fix: load authenticated product archive images
This commit is contained in:
@@ -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">
|
||||
|
||||
@@ -3687,6 +3687,16 @@ body.resizing .studio-panel {
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
.product-archive-image-empty {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--text-muted);
|
||||
font-size: 11px;
|
||||
text-align: center;
|
||||
}
|
||||
.product-archive-thumb-empty,
|
||||
.product-archive-cover-empty {
|
||||
padding: 4px;
|
||||
|
||||
Reference in New Issue
Block a user