perf(*): 创作工作台 - 优化首页按需加载与画布交互并修复历史迁移冲突
This commit is contained in:
@@ -589,7 +589,7 @@ function reconcileTaskSummaries(current: GenerationTask[], next: GenerationTask[
|
||||
let changed = false;
|
||||
const reconciled = next.map((task) => {
|
||||
const previous = currentById.get(task.id);
|
||||
if (previous?.updatedAt === task.updatedAt && previous.previewUrl === task.previewUrl && previous.billing?.status === task.billing?.status && previous.billing?.amountMicrocredits === task.billing?.amountMicrocredits) return previous;
|
||||
if (previous?.updatedAt === task.updatedAt && previous.previewUrl === task.previewUrl && previous.previewPosterUrl === task.previewPosterUrl && previous.billing?.status === task.billing?.status && previous.billing?.amountMicrocredits === task.billing?.amountMicrocredits) return previous;
|
||||
changed = true;
|
||||
return task;
|
||||
});
|
||||
|
||||
@@ -11,13 +11,16 @@ export function TaskGridCard({ task, actingId, onOpen, onRetry }: { task: Genera
|
||||
const isActive = task.status === "queued" || task.status === "running";
|
||||
const isFailed = isTaskFailed(task);
|
||||
const isVideo = task.previewKind === "video";
|
||||
const thumbnailUrl = isVideo ? task.previewPosterUrl : task.previewUrl;
|
||||
const fallbackVideo = task.type.includes("video");
|
||||
const Icon = fallbackVideo ? Video : task.type.includes("image") ? ImageIcon : FileText;
|
||||
return (
|
||||
<article className={`task-grid-card${isFailed ? " is-attention" : ""}`}>
|
||||
<div className="task-grid-thumb">
|
||||
{task.previewUrl ? (
|
||||
<MediaPreview src={task.previewUrl} kind={isVideo ? "video" : "image"} loading="lazy" className="h-full w-full object-cover" />
|
||||
{thumbnailUrl ? (
|
||||
<MediaPreview src={thumbnailUrl} kind="image" loading="lazy" className="h-full w-full object-cover" />
|
||||
) : isVideo && task.previewUrl ? (
|
||||
<span className="task-video-poster-placeholder"><Video /><small>视频预览</small></span>
|
||||
) : (
|
||||
<Icon />
|
||||
)}
|
||||
|
||||
@@ -101,7 +101,8 @@ function TaskPreviewThumbnail({ task, onOpen }: { task: GenerationTask; onOpen:
|
||||
const isVideo = task.previewKind === "video";
|
||||
const fallbackVideo = task.type.includes("video");
|
||||
const [unavailableUrl, setUnavailableUrl] = useState("");
|
||||
const previewUnavailable = Boolean(task.previewUrl && unavailableUrl === task.previewUrl);
|
||||
const thumbnailUrl = isVideo ? task.previewPosterUrl : task.previewUrl;
|
||||
const previewUnavailable = Boolean(thumbnailUrl && unavailableUrl === thumbnailUrl);
|
||||
if (!task.previewUrl) {
|
||||
const Icon = fallbackVideo ? Video : task.type.includes("image") ? ImageIcon : FileText;
|
||||
return (
|
||||
@@ -119,7 +120,7 @@ function TaskPreviewThumbnail({ task, onOpen }: { task: GenerationTask; onOpen:
|
||||
aria-label={previewUnavailable ? "预览不可用,素材可能已删除" : isVideo ? "放大预览生成视频" : "放大预览生成图片"}
|
||||
title={previewUnavailable ? "预览不可用,素材可能已删除" : undefined}
|
||||
>
|
||||
<MediaPreview src={task.previewUrl} kind={isVideo ? "video" : "image"} width={68} height={48} loading="lazy" className="h-full w-full object-cover" fallbackLabel="预览不可用" onUnavailable={() => setUnavailableUrl(task.previewUrl || "")} />
|
||||
{thumbnailUrl ? <MediaPreview src={thumbnailUrl} kind="image" width={68} height={48} loading="lazy" className="h-full w-full object-cover" fallbackLabel="预览不可用" onUnavailable={() => setUnavailableUrl(thumbnailUrl)} /> : <span className="task-video-poster-placeholder"><Video className="size-4" /><small>视频</small></span>}
|
||||
{!previewUnavailable ? (
|
||||
<span className="absolute inset-0 grid place-items-center bg-black/0 text-white opacity-0 transition-[background-color,opacity] duration-150 group-hover:bg-black/30 group-hover:opacity-100 group-focus-visible:bg-black/30 group-focus-visible:opacity-100">
|
||||
{isVideo ? <Play className="size-4 fill-current" /> : <Eye className="size-4" />}
|
||||
|
||||
Reference in New Issue
Block a user