fix: 测试清单(8) 新一轮 — ZWQ/PMC/设置/团队 多项修复
视频/工作台/商品库(ZWQ): - row19 视频阶段移除已取消的【上传视频】按钮 (pipeline.tsx) - row20 工作台统计栏(总项目/进行中/成片)点击跳转视频项目对应 tab (dashboard/projects/route-config/App) - row21 最新项目跳转改用真实 projectId, 不再跳到最近打开项目 (dashboard.tsx) - row22+PMC28 网格/列表视图模式持久化(localStorage), 跨菜单记住用户选择 (projects/ai-tools + 新 hook use-view-mode.ts) - row24 已有三视图的演员/模特直接复用, 不再强制点AI生成三视图 (pipeline.tsx) 图片生成/设置(PMC): - row27 任务中心: 6个进行中状态补全归类, 不再把生成中误判为失败栏 (stage-config.ts) - row29 头像上传500: avatar_url 存公读直链替代超长预签名URL(URLField max_length=200溢出) (accounts/views.py, 需部署) - row30 显示名保存后回显: 改读 first_name 回退 username, 修刷新仍旧名 (settings.tsx) - row31/32 隐藏【创作默认】【显示】两个设置模块 (settings.tsx) 平台套图(YYX): - row3 图片预览铺满占位 (ai-tools-page.css) 团队: - PMC25 充值/邀请成员/设置月限额三弹窗禁止点遮罩误关 (team.tsx) 含平台套图线上提示词优化(services.py/views.py/api.ts, 前序会话遗留一并提交) 构建: tsc --noEmit=0, npm run build=0 (1755模块); 后端 py_compile OK 注: row29 头像/后端项需部署生效 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,7 @@ import { ActorLibrary } from "../components/actor-library";
|
||||
import { SkeletonRows } from "../components/loading";
|
||||
import { MediaLightbox } from "../components/overlays";
|
||||
import { Pager } from "../components/pager";
|
||||
import { useViewMode } from "../components/use-view-mode";
|
||||
import type { Page } from "./route-config";
|
||||
import { statusPill } from "./stage-config";
|
||||
import { productMockCoverUrl } from "./products";
|
||||
@@ -182,7 +183,7 @@ export function AssetFactoryPage({ navigate }: { navigate: (page: Page) => void
|
||||
const [query, setQuery] = useState("");
|
||||
const [timeFilter, setTimeFilter] = useState<"all" | "1" | "7" | "30">("all");
|
||||
const [typeFilter, setTypeFilter] = useState("");
|
||||
const [view, setView] = useState<"grid" | "list">("grid");
|
||||
const [view, setView] = useViewMode<"grid" | "list">("viewmode:tasks", "grid");
|
||||
const [openChip, setOpenChip] = useState<"" | "time" | "type">("");
|
||||
// 任务中心分页:每页 10 条,筛选/搜索变化时回第 1 页
|
||||
const TASKS_PER_PAGE = 10;
|
||||
@@ -514,10 +515,11 @@ const MODE_META: Record<
|
||||
cover: {
|
||||
title: "平台套图",
|
||||
tag: "[ PLATFORM · KIT ]",
|
||||
desc: "选择平台模板,一键生成电商平台头图 / 主图。",
|
||||
ratio: "4:5",
|
||||
desc: "选择平台模板,一键生成平台商品头图。",
|
||||
// 优化版:商品上架主图默认 1:1(原 4:5 会 fallback 成方图致比例错乱);竖图按平台/类目再选
|
||||
ratio: "1:1",
|
||||
// YYX#4:只出平台头图,去掉「详情排版」
|
||||
promptTemplate: (title) => `${title},电商平台头图,统一视觉,主图特写`
|
||||
promptTemplate: (title) => `${title},平台商品头图,统一视觉,商品主体清晰`
|
||||
}
|
||||
};
|
||||
|
||||
@@ -565,6 +567,12 @@ const PLATFORM_OPTIONS = [
|
||||
{ id: "al", name: "1688", logo: "阿", img: "/assets/svg/icon-platform-1688.svg" }
|
||||
];
|
||||
|
||||
/* 前端平台 id(dy/tb…) → 后端规范化 platform_id(优化版:后端按此 key 注入平台版式块)。 */
|
||||
const PLATFORM_ID_MAP: Record<string, string> = {
|
||||
dy: "douyin", tb: "taobao", tm: "tmall", jd: "jd", pdd: "pdd",
|
||||
xhs: "xhs", ks: "kuaishou", sph: "wechat", amz: "amazon", al: "1688"
|
||||
};
|
||||
|
||||
/* YYX#row10:平台 logo —— 优先真 logo 图(public/assets/svg),加载失败回退到品牌色块+字符。
|
||||
className 默认 p-logo(平台卡/筛选弹窗),分组头传 cg-logo。 */
|
||||
function PlatformLogo({ p, className }: { p: { id: string; name: string; logo: string; img?: string }; className?: string }) {
|
||||
@@ -623,7 +631,7 @@ export function ImageWorkbenchPage({
|
||||
modelConfigs: ModelConfig[];
|
||||
onBack: () => void;
|
||||
navigate?: (page: Page) => void;
|
||||
onGenerate: (payload: { prompt: string; mode?: "image" | "model" | "cover"; count?: number; product_id?: string; model_id?: string; ratio?: string; image_model?: string; conversation_id?: string; reference_image_ids?: string[]; onSubmitted?: (taskIds: string[]) => void }) => Promise<{ assets: Asset[]; conversation_id?: string } | null>;
|
||||
onGenerate: (payload: { prompt: string; mode?: "image" | "model" | "cover"; count?: number; product_id?: string; model_id?: string; ratio?: string; image_model?: string; platform_id?: string; conversation_id?: string; reference_image_ids?: string[]; onSubmitted?: (taskIds: string[]) => void }) => Promise<{ assets: Asset[]; conversation_id?: string } | null>;
|
||||
onResume?: (mode: "image" | "model" | "cover", ids: string[]) => Promise<{ assets: Asset[] } | null>;
|
||||
/** 行19:从商品页带入的初始商品 id(可选);未传则回退到第一个商品 */
|
||||
initialProductId?: string;
|
||||
@@ -963,6 +971,8 @@ export function ImageWorkbenchPage({
|
||||
modelId?: string;
|
||||
modelName?: string;
|
||||
platformIds?: string[];
|
||||
/** 优化版:规范化平台 id(douyin/taobao…),透传给后端注入平台版式块 */
|
||||
platformId?: string;
|
||||
/** 图片创作:本批要参考的上传图(含 file 用于上传;已是 asset 的可只给 id) */
|
||||
refs?: { name: string; url: string; file?: File; assetId?: string }[];
|
||||
/** PMC#25:原地重跑——复位这张已有批次卡(清旧结果、重新生成),不新开任务卡 */
|
||||
@@ -1027,7 +1037,7 @@ export function ImageWorkbenchPage({
|
||||
}
|
||||
// 带上当前对话 id(空则后端自动开一条并回传);conversation_id 用 ref 取最新值,避免闭包旧值
|
||||
// onSubmitted:提交成功拿到任务 id 即把本批 pendingIds 落盘 → 切走再回来本批能各自续轮询(PMC#5/#10)
|
||||
const result = await onGenerate({ prompt: opts.prompt, mode, count: opts.count, product_id: opts.productId, model_id: opts.modelId, ratio: opts.ratio, image_model: genModel, conversation_id: activeConvRef.current || undefined, reference_image_ids: referenceImageIds,
|
||||
const result = await onGenerate({ prompt: opts.prompt, mode, count: opts.count, product_id: opts.productId, model_id: opts.modelId, ratio: opts.ratio, image_model: genModel, platform_id: opts.platformId, conversation_id: activeConvRef.current || undefined, reference_image_ids: referenceImageIds,
|
||||
onSubmitted: (taskIds) => setBatches((prev) => { const next = prev.map((b) => (b.id === batchId ? { ...b, pendingIds: taskIds } : b)); persistBatches(next); return next; }) });
|
||||
// 首发新对话:把后端建的对话登记进左栏并设为 active;刷新列表拿到真标题/计数
|
||||
const convId = result?.conversation_id;
|
||||
@@ -1083,10 +1093,9 @@ export function ImageWorkbenchPage({
|
||||
};
|
||||
if (mode === "cover") {
|
||||
// P0③:每个选中平台各起一批 → 右侧自然形成多平台分组 section;
|
||||
// 平台名拼进提示词,让各平台套图按其版式倾向出图(后端无 platform 字段,靠 prompt 表达)
|
||||
// 优化版:不再把平台名拼进 prompt,改传规范化 platform_id 给后端注入平台版式块(平台调性/版式/负面约束)
|
||||
for (const pid of pickedIds) {
|
||||
const platName = PLATFORM_OPTIONS.find((p) => p.id === pid)?.name;
|
||||
void startBatch({ ...base, prompt: platName ? `${base.prompt},${platName}平台头图版式` : base.prompt, platformIds: [pid] });
|
||||
void startBatch({ ...base, platformId: PLATFORM_ID_MAP[pid], platformIds: [pid] });
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1116,6 +1125,7 @@ export function ImageWorkbenchPage({
|
||||
modelId: src.modelId,
|
||||
modelName: src.modelName,
|
||||
platformIds: src.platformIds,
|
||||
platformId: src.platformIds?.[0] ? PLATFORM_ID_MAP[src.platformIds[0]] : undefined,
|
||||
reuseBatchId: src.id
|
||||
});
|
||||
}
|
||||
@@ -1196,6 +1206,7 @@ export function ImageWorkbenchPage({
|
||||
modelId: src.modelId,
|
||||
modelName: src.modelName,
|
||||
platformIds: src.platformIds,
|
||||
platformId: src.platformIds?.[0] ? PLATFORM_ID_MAP[src.platformIds[0]] : undefined,
|
||||
appendToBatchId: src.id
|
||||
});
|
||||
}
|
||||
@@ -2114,7 +2125,7 @@ export function ImageWorkbenchPage({
|
||||
for (const pid of plDraft.slice(1)) {
|
||||
const p = products.find((x) => x.id === pid);
|
||||
if (mode === "cover") {
|
||||
for (const platId of pickedIds) void startBatch({ prompt: prompt.trim(), ratio, count: candidateCount, productId: pid, productTitle: p?.title, platformIds: [platId] });
|
||||
for (const platId of pickedIds) void startBatch({ prompt: prompt.trim(), ratio, count: candidateCount, productId: pid, productTitle: p?.title, platformId: PLATFORM_ID_MAP[platId], platformIds: [platId] });
|
||||
} else {
|
||||
void startBatch({ prompt: prompt.trim(), ratio, count: candidateCount, productId: pid, productTitle: p?.title, modelId: mode === "model" ? pickedIds[0] : undefined, modelName: mode === "model" ? pickedModelName : undefined });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user