diff --git a/core/frontend/src/routes/products.tsx b/core/frontend/src/routes/products.tsx index cceb70d..2bc3487 100644 --- a/core/frontend/src/routes/products.tsx +++ b/core/frontend/src/routes/products.tsx @@ -675,15 +675,19 @@ export function ProductDetailPage({ product, projects, initialTab = "assets", na return () => { alive = false; }; }, [product?.id, assetReload]); - // ZWQ#row24/三视图同步:该商品已存在的三视图资产(在【视频项目】基础资产阶段生成、 - // 或此前在商品库生成并落库的 tri_view)回填到三视图面板,避免「明明已生成却显示尚未生成」。 - // 判定与后端 is_triview 对齐:category=tri_view / metadata.view=three_view / 名字含三视图。 + // ZWQ#row25/三视图同步:该商品已存在的「商品三视图」资产(在【视频项目】基础资产阶段生成、 + // 或此前在商品库生成并落库)回填到三视图面板,避免「明明已生成却显示尚未生成」。 + // ⚠️ row28:必须只取「商品」三视图,排除「角色/人物三视图」——二者 category 都是 tri_view、名字都含「三视图」, + // 唯一可靠区分是 metadata.triview_of(角色三视图指向其立绘 asset id;商品三视图没有)+ kind=person。 + // 漏掉这层过滤就会把角色三视图塞进商品三视图面板(row28「商品三视图显示成角色三视图」)。 useEffect(() => { - const triAssets = productAssets.filter( - (a) => a.category === "tri_view" || a.asset_type === "tri_view" - || (a.metadata as { view?: string } | undefined)?.view === "three_view" - || (a.name || "").includes("三视图") - ); + const triAssets = productAssets.filter((a) => { + const m = (a.metadata as { triview_of?: unknown; kind?: string; view?: string } | undefined) || {}; + if (m.triview_of) return false; // 角色/人物/模特三视图:绝不进商品三视图面板 + if (m.kind === "person" || m.kind === "scene") return false; + return a.category === "tri_view" || a.asset_type === "tri_view" + || m.view === "three_view" || (a.name || "").includes("商品三视图"); + }); if (!triAssets.length) return; const serverVersions: TriVersion[] = triAssets .map((a) => ({ id: a.id, url: a.files?.[0]?.preview_url || "", asset: a, createdAt: a.created_at || "" }))