fix: load authenticated product archive images

This commit is contained in:
2026-09-12 18:37:56 +08:00
parent 4fd6d66c0e
commit 7e275798e7
2 changed files with 68 additions and 3 deletions
+58 -3
View File
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import type { FormEvent } from 'react';
import AppSettingsWindow, { type ThemeMode } from '../components/AppSettingsWindow';
import { ensureOk } from '../lib/api';
import { apiUrl, ensureOk } from '../lib/api';
import { IconArchive, IconGrid, IconHelp, IconLock, IconRefresh, IconTrash } from '../components/Icons';
import {
deleteProduct,
@@ -57,6 +57,51 @@ function formatDateTime(value: string): string {
});
}
function AuthenticatedImage({
token,
imageUrl,
alt,
emptyLabel,
}: {
token: string;
imageUrl: string;
alt: string;
emptyLabel: string;
}) {
const [objectUrl, setObjectUrl] = useState('');
useEffect(() => {
let cancelled = false;
let createdUrl = '';
const load = async () => {
try {
const res = await fetch(apiUrl(imageUrl), {
headers: { Authorization: `Bearer ${token}` },
});
await ensureOk(res, '预览图读取失败');
const blob = await res.blob();
createdUrl = URL.createObjectURL(blob);
if (!cancelled) setObjectUrl(createdUrl);
} catch {
if (!cancelled) setObjectUrl('');
}
};
void load();
return () => {
cancelled = true;
if (createdUrl) URL.revokeObjectURL(createdUrl);
};
}, [imageUrl, token]);
if (!objectUrl) {
return <div className="product-archive-image-empty">{emptyLabel}</div>;
}
return <img src={objectUrl} alt={alt} loading="lazy" decoding="async" />;
}
export default function ProductArchivePage({
themeMode,
systemTheme,
@@ -286,7 +331,12 @@ export default function ProductArchivePage({
>
<span className="product-archive-thumb">
{coverUrl
? <img src={coverUrl} alt={product.name} />
? <AuthenticatedImage
token={token}
imageUrl={coverUrl}
alt={product.name}
emptyLabel="暂无预览图"
/>
: <span className="product-archive-thumb-empty"></span>}
</span>
<span className="product-archive-row-body">
@@ -352,7 +402,12 @@ export default function ProductArchivePage({
<div className="product-archive-detail">
<div className="product-archive-cover">
{previewUrl
? <img src={previewUrl} alt={`${selected.name} 预览图`} />
? <AuthenticatedImage
token={token}
imageUrl={previewUrl}
alt={`${selected.name} 预览图`}
emptyLabel="暂无预览图"
/>
: <div className="product-archive-cover-empty"></div>}
</div>
<div className="product-archive-detail-body">