fix(core): 资产详情大图随数据显示,缩略图已出大图不再卡转圈

- 三视图/立绘大图改为跟数据(url)走,出图完成即显示,不再被在途轮询的
  busy 标志挡住——根治「小缩略图已出、大图一直转圈」
- 一并带上工作区其余改动(script_agent / services / tests / ai-tools / actor-library / App)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
zyc
2026-06-18 10:57:02 +08:00
co-authored by Claude Opus 4.8
parent fe38d3a512
commit 326c34ecd1
7 changed files with 200 additions and 47 deletions
+8 -6
View File
@@ -66,7 +66,7 @@ const crumbLabels: Partial<Record<Page, string>> = {
/* 图片生成工作台·跨刷新持久化:把在跑的任务 id + 已出结果按 mode 存本地,
刷新后可恢复"生成中"占位并继续轮询(worker 在后台出图,任务永不丢)。 */
const imgwbKey = (mode?: string) => `airshelf:imgwb:${mode || "image"}`;
type ImgwbSaved = { pending?: string[]; results?: Asset[]; count?: number; ts?: number };
type ImgwbSaved = { pending?: string[]; results?: Asset[]; count?: number; ts?: number; productId?: string; productTitle?: string };
function loadImgwb(mode?: string): ImgwbSaved | null {
try {
const raw = localStorage.getItem(imgwbKey(mode));
@@ -410,7 +410,9 @@ export function App() {
const ids = tasks.map((t) => t.id);
if (ids.length === 0) throw new Error("未能提交生成任务");
// 提交成功即落盘:刷新页面也能恢复"生成中"并继续轮询(任务在 worker 里跑,关掉浏览器也不丢)
saveImgwb(payload.mode, { pending: ids, results: [], count: payload.count });
// 记下本批所属商品(id+名),恢复在途批次时用它当导航头,而不是用「当前选中商品」(切走再回会显示错名)
const batchProduct = products.find((p) => p.id === payload.product_id);
saveImgwb(payload.mode, { pending: ids, results: [], count: payload.count, productId: payload.product_id, productTitle: batchProduct?.title });
return pollImageTasks(payload.mode, ids);
}, "图片已生成");
}
@@ -686,11 +688,11 @@ export function App() {
case "assetFactory":
return <AssetFactoryPage navigate={navigate} />;
case "imageOptimize":
return <ImageWorkbenchPage mode="image" products={products} modelConfigs={modelConfigs} initialProductId={activeProductId} onBack={() => navigate("assetFactory")} navigate={navigate} onGenerate={generateImages} onResume={resumeImages} />;
return <ImageWorkbenchPage mode="image" products={products} modelConfigs={modelConfigs} initialProductId={activeProductId} onProductChange={setActiveProductId} onBack={() => navigate("assetFactory")} navigate={navigate} onGenerate={generateImages} onResume={resumeImages} />;
case "modelPhoto":
return <ImageWorkbenchPage mode="model" products={products} modelConfigs={modelConfigs} initialProductId={activeProductId} onBack={() => navigate("assetFactory")} navigate={navigate} onGenerate={generateImages} onResume={resumeImages} />;
return <ImageWorkbenchPage mode="model" products={products} modelConfigs={modelConfigs} initialProductId={activeProductId} onProductChange={setActiveProductId} onBack={() => navigate("assetFactory")} navigate={navigate} onGenerate={generateImages} onResume={resumeImages} />;
case "platformCover":
return <ImageWorkbenchPage mode="cover" products={products} modelConfigs={modelConfigs} initialProductId={activeProductId} onBack={() => navigate("assetFactory")} navigate={navigate} onGenerate={generateImages} onResume={resumeImages} />;
return <ImageWorkbenchPage mode="cover" products={products} modelConfigs={modelConfigs} initialProductId={activeProductId} onProductChange={setActiveProductId} onBack={() => navigate("assetFactory")} navigate={navigate} onGenerate={generateImages} onResume={resumeImages} />;
case "modelPhotoDemoA":
return <ModelPhotoDemoPage variant="A" products={products} onBack={() => navigate("modelPhoto")} navigate={navigate} />;
case "modelPhotoDemoB":
@@ -750,7 +752,7 @@ export function App() {
avatarChar={avatarChar}
logout={logout} onAdoptScript={(scriptId) => action(() => api.adoptScript(pipelineProject.id, scriptId), "脚本已采用")}
onUpdateShot={(payload) => action(() => api.updateScriptSegment(pipelineProject.id, payload), "分镜已更新")}
onAddShot={(afterSegmentId) => action(() => api.addScriptSegment(pipelineProject.id, { after_segment_id: afterSegmentId }), "分镜已添加")}
onAddShot={(afterSegmentId, content) => action(() => api.addScriptSegment(pipelineProject.id, { after_segment_id: afterSegmentId, ...content }), "分镜已添加")}
onDeleteShot={(segmentId) => action(() => api.deleteScriptSegment(pipelineProject.id, { segment_id: segmentId }), "分镜已删除")}
onRerunShot={(segmentId, instruction) => action(() => api.rerunScriptSegment(pipelineProject.id, { segment_id: segmentId, instruction }), "分镜已重跑")}
onSaveProjectMeta={(meta) =>