fix(projects+assets): 项目封面引用真实商品图 + 资产库排除软删资产
- 项目卡封面:废弃「项目名关键词→静态 mock 假图」映射(与真实数据脱节,导致全是假面膜图), 改用后端 cover_preview_url(取商品 cover_asset 主图);无商品图 → 干净占位 - 资产库 queryset/summary/facets 补 is_deleted=False:软删资产不再出现在资产库与 tab 计数 (此前 is_deleted 字段在资产库未生效,软删无效) - 单测 AssetSoftDeleteTests:列表 + 计数均排除软删 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
c6e9c7e77b
commit
9e791a4db9
@@ -396,20 +396,9 @@ function projShotMeta(project: Project): string {
|
||||
const dur = projDurationLabel(project);
|
||||
return dur ? `${shots} 镜 · ${dur}` : `${shots} 镜`;
|
||||
}
|
||||
// 复刻 mock-media coverFor:按项目名关键词映射封面图(无匹配 → 占位)
|
||||
function projCover(name: string): string {
|
||||
const t = name.replace(/\s+/g, "");
|
||||
if (/蓝牙|耳机|南卡/.test(t)) return "cover-earbuds.png";
|
||||
if (/速食|牛肉面|泡面|面条/.test(t)) return "cover-noodle.png";
|
||||
if (/防晒/.test(t)) return "cover-sunscreen.png";
|
||||
if (/咖啡|冻干/.test(t)) return "cover-coffee.png";
|
||||
if (/空气炸锅|小熊/.test(t)) return "cover-air-fryer.png";
|
||||
if (/瑜伽裤|露露/.test(t)) return "cover-yoga.png";
|
||||
if (/v1|final|已完成|成片|敷面膜|化妆台/.test(t)) return "cover-mask-final.png";
|
||||
if (/面膜|补水|玻尿酸|透真/.test(t)) return "cover-mask-v3.png";
|
||||
return "";
|
||||
}
|
||||
const projMock = (file: string): CSSProperties => ({ ["--mock-media-url"]: `url(/exact/assets/mock/${file})` } as CSSProperties);
|
||||
// 项目卡封面 = 该项目商品的主图(后端 cover_preview_url,取商品 cover_asset)。无图 → 占位。
|
||||
// (原先按项目名关键词映射静态 mock 假图,与真实数据脱节,已废弃。)
|
||||
const coverStyle = (url: string): CSSProperties => ({ ["--mock-media-url"]: `url(${url})` } as CSSProperties);
|
||||
|
||||
const PROJ_TABS: Array<{ filter: "all" | "wip" | "done" | "fail"; label: string }> = [
|
||||
{ filter: "all", label: "全部" }, { filter: "wip", label: "进行中" }, { filter: "done", label: "已完成" }, { filter: "fail", label: "失败" }
|
||||
@@ -638,7 +627,7 @@ export function ProjectsPage({ products, projects, loading = false, navigate, op
|
||||
<tbody id="list-tbody">
|
||||
{pageItems.map((project) => {
|
||||
const no = projStageNo(project);
|
||||
const cover = projCover(project.name);
|
||||
const cover = project.cover_preview_url || "";
|
||||
const isSel = selected.has(project.id);
|
||||
return (
|
||||
<tr key={project.id} data-status={projBucket(project)} data-name={project.name} className={editMode && isSel ? "row-selected" : undefined} onClick={() => (editMode ? toggleSelect(project.id) : openPipeline(project.id))}>
|
||||
@@ -647,7 +636,7 @@ export function ProjectsPage({ products, projects, loading = false, navigate, op
|
||||
{editMode && (
|
||||
<span className={`row-check${isSel ? " on" : ""}`} aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="3 8 7 12 13 4" /></svg></span>
|
||||
)}
|
||||
<div className={`placeholder proj-thumb${cover ? " has-mock-media" : ""}`} style={cover ? projMock(cover) : undefined}><span className="ph-frame">9:16</span></div>
|
||||
<div className={`placeholder proj-thumb${cover ? " has-mock-media" : ""}`} style={cover ? coverStyle(cover) : undefined}><span className="ph-frame">9:16</span></div>
|
||||
<div><div className="proj-name">{project.name}</div><div className="proj-sub">{projShotMeta(project)}</div></div>
|
||||
</div>
|
||||
</td>
|
||||
@@ -681,13 +670,13 @@ export function ProjectsPage({ products, projects, loading = false, navigate, op
|
||||
</div>
|
||||
) : (
|
||||
<div className="proj-grid">{pageItems.map((project) => {
|
||||
const cover = projCover(project.name);
|
||||
const cover = project.cover_preview_url || "";
|
||||
const no = projStageNo(project);
|
||||
const isSel = selected.has(project.id);
|
||||
return (
|
||||
<article className={`proj-card${editMode && isSel ? " selected" : ""}`} key={project.id} onClick={() => (editMode ? toggleSelect(project.id) : openPipeline(project.id))}>
|
||||
<span className="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="3 8 7 12 13 4" /></svg></span>
|
||||
<div className={`placeholder card-thumb${cover ? " has-mock-media" : ""}`} style={cover ? projMock(cover) : undefined}><span className="ph-frame">9:16</span></div>
|
||||
<div className={`placeholder card-thumb${cover ? " has-mock-media" : ""}`} style={cover ? coverStyle(cover) : undefined}><span className="ph-frame">9:16</span></div>
|
||||
<div className="card-body">
|
||||
<div>
|
||||
<div className="card-name">{project.name}</div>
|
||||
|
||||
Reference in New Issue
Block a user