fix: 平台套图工作台 YYX 测试清单一轮修复(13 条)
- 平台改单选;结果分组/标签名对应所选平台 - 工作台结果区按当前商品隔离(productBatches) - 平台套图去掉「详情排版」,只出平台头图 - 部分失败给失败占位 +「重跑这张」单张重跑;部分成功批次恢复加入资产库 - 提示词框加大;生图模型选择移入框内作胶囊靠左置底 - 去掉生成按钮下方说明文字 - 工作台「新建商品」改弹抽屉(复用 ProductCreateDrawer),不再跳商品库 - 右上搜索恒显全部平台、改为筛选结果图(按提示词) - 结果卡参考即梦:显示提示词/平台/张数 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -762,7 +762,6 @@ export function ImageWorkbenchPage({
|
||||
(mode !== "model" || (!!product?.id && pickedIds.length > 0)) &&
|
||||
// 平台套图:必须选商品 + 至少一个平台(P0③ 多选)
|
||||
(mode !== "cover" || (!!product?.id && pickedIds.length > 0));
|
||||
const anyGenerating = batches.some((b) => b.status === "generating");
|
||||
|
||||
/* 多批次本地持久化(行33):用 ai-tools 私有 key,不与 App 的单批 `airshelf:imgwb:{mode}` 抢同一槽。
|
||||
已出图的批次直接回显;App 不可改,故"刷新时仍在跑"的批次只能尽力恢复(见回报)。 */
|
||||
@@ -1291,16 +1290,11 @@ export function ImageWorkbenchPage({
|
||||
原右上「1 批·比例」与「N×」徽标系重复信息,已剔除 */}
|
||||
<div className="iw-pv-h">
|
||||
<Quote className="quote-icon" />
|
||||
{/* YYX#13:参考即梦 —— 显示用户输入的提示词 / 选择的平台 / 生成的张数 */}
|
||||
<div className="pv-line">
|
||||
<span className="k">商品</span>
|
||||
<span className="v">{batchProductTitle(batch)}</span>
|
||||
<span className="k">提示词</span>
|
||||
<span className="v pv-prompt">{batch.prompt || "—"}</span>
|
||||
</div>
|
||||
{mode === "model" && batch.modelName && (
|
||||
<div className="pv-line">
|
||||
<span className="k">模特</span>
|
||||
<span className="v">{batch.modelName}</span>
|
||||
</div>
|
||||
)}
|
||||
{mode === "cover" && (
|
||||
<div className="pv-line">
|
||||
<span className="k">平台</span>
|
||||
@@ -1313,8 +1307,14 @@ export function ImageWorkbenchPage({
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{mode === "model" && batch.modelName && (
|
||||
<div className="pv-line">
|
||||
<span className="k">模特</span>
|
||||
<span className="v">{batch.modelName}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="pv-line">
|
||||
<span className="k">结果</span>
|
||||
<span className="k">张数</span>
|
||||
<span className="v">
|
||||
{batch.count} 张 · {batch.ratio} · {generating ? "生成中" : failed ? "失败" : "已完成"}
|
||||
{!generating && !failed && batch.results.some((a) => a.in_library)
|
||||
@@ -1902,12 +1902,31 @@ export function ImageWorkbenchPage({
|
||||
)}
|
||||
<div className="iw-sub">
|
||||
<div className="iw-sub-h">// 提示词 · 描述你想要的画面</div>
|
||||
<textarea
|
||||
className="textarea"
|
||||
value={prompt}
|
||||
onChange={(event) => setPrompt(event.target.value)}
|
||||
placeholder={`例如:${meta.promptTemplate(product?.title || "商品")}`}
|
||||
/>
|
||||
{/* YYX#7:提示词框加大;YYX#10:生图模型选择作胶囊嵌在框内靠左置底 */}
|
||||
<div className="iw-prompt-box">
|
||||
<textarea
|
||||
className="textarea iw-prompt-text"
|
||||
value={prompt}
|
||||
onChange={(event) => setPrompt(event.target.value)}
|
||||
placeholder={`例如:${meta.promptTemplate(product?.title || "商品")}`}
|
||||
/>
|
||||
<div className="iw-prompt-bar">
|
||||
<div className={`chip-wrap iw-model-pill${genModelOpen ? " open" : ""}`} data-filter="genmodel">
|
||||
<button className="chip" type="button" title="生图模型" onClick={() => setGenModelOpen((v) => !v)}>
|
||||
<Sparkles size={12} />
|
||||
<span className="chip-label">{GEN_MODEL_OPTIONS.find((o) => o.value === genModel)?.label || "火山 Seedream"}</span>
|
||||
<svg className="caret" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><path d="M4 6l4 4 4-4" /></svg>
|
||||
</button>
|
||||
<div className="chip-menu">
|
||||
{GEN_MODEL_OPTIONS.map((o) => (
|
||||
<div className={`mi${genModel === o.value ? " selected" : ""}`} key={o.value} role="button" tabIndex={0} onClick={() => { setGenModel(o.value); setGenModelOpen(false); }}>
|
||||
<svg className="mi-check" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2"><path d="M3 8l3.5 3.5L13 5" /></svg>{o.label}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1917,7 +1936,7 @@ export function ImageWorkbenchPage({
|
||||
<WandSparkles size={13} />
|
||||
立即生成 (预估 ¥{(candidateCount * (mode === "model" ? 0.3 : 0.5)).toFixed(2)})
|
||||
</button>
|
||||
<div className="iw-cta-hint">// 生成即扣费 · 生成的图先在工作台 · 点「加入资产库」才进资产库列表{anyGenerating ? " · 有批次生成中,可继续提交" : ""}</div>
|
||||
{/* YYX#9:去掉生成按钮下方那行说明文字 */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@ import { SkeletonRows } from "../components/loading";
|
||||
import { money, stageMeta, statusPill } from "./stage-config";
|
||||
import { Progress } from "../components/pipeline-stage";
|
||||
import { IconKitSvg } from "../components/IconKitSvg";
|
||||
import { ProductCreateDrawer, type ProductCreatePayload } from "../components/product-create-drawer";
|
||||
|
||||
export function Dashboard({ products, projects, productTotal, projectTotal, billing, userName, loading = false, navigate }: {
|
||||
export function Dashboard({ products, projects, productTotal, projectTotal, billing, userName, loading = false, navigate, onCreateProduct }: {
|
||||
products: Product[];
|
||||
projects: Project[];
|
||||
productTotal?: number; // 后端真实总数(分页 count),用于「N 个/SKU」展示
|
||||
@@ -16,7 +17,11 @@ export function Dashboard({ products, projects, productTotal, projectTotal, bill
|
||||
userName?: string;
|
||||
loading?: boolean;
|
||||
navigate: (page: Page) => void;
|
||||
// YYX#11:工作台点「新建商品」直接弹抽屉(复用商品库同一组件),而非跳商品库
|
||||
onCreateProduct?: (payload: ProductCreatePayload) => Promise<Product | null | undefined> | void;
|
||||
}) {
|
||||
// YYX#11:新建商品抽屉开关
|
||||
const [createDrawer, setCreateDrawer] = useState(false);
|
||||
const projCount = projectTotal ?? projects.length;
|
||||
const prodCount = productTotal ?? products.length;
|
||||
// 资产总数:走轻量 summary 接口(各 tab 计数之和),不再吃全局 assets 全量数组
|
||||
@@ -58,7 +63,7 @@ export function Dashboard({ products, projects, productTotal, projectTotal, bill
|
||||
<div className="sub"><span className="mono">// {dateMono}</span><span>·</span><span>你有 <b>{running} 个项目</b> 正在进行中</span></div>
|
||||
</div>
|
||||
<div className="actions">
|
||||
<button className="btn" type="button" onClick={() => navigate("products")}>
|
||||
<button className="btn" type="button" onClick={() => (onCreateProduct ? setCreateDrawer(true) : navigate("products"))}>
|
||||
<IconKitSvg name="productPlus" size={16} />
|
||||
新建商品
|
||||
</button>
|
||||
@@ -70,6 +75,15 @@ export function Dashboard({ products, projects, productTotal, projectTotal, bill
|
||||
</div>
|
||||
<div className="stats with-corners"><span className="corner-tr">+</span><span className="corner-bl">+</span><KpiStat label="总项目" badge="ALL" value={projCount} delta={totalDelta} /><KpiStat label="进行中" badge="WIP" value={running} /><KpiStat label="成片" badge="DONE" value={completed} /><button className="stat" type="button" onClick={() => navigate("account")}><div className="lbl">余额 <span className="badge">¥</span></div><div className="v">{money(billing?.account.balance)}</div><div className="bar"><span style={{ width: `${reservedPct}%` }} /></div><div className="sub">冻结 {money(reservedNum)} / 共 {money(fundsTotal)}</div></button></div>
|
||||
<div className="dash-grid"><div><div className="section-h"><h2>最近项目</h2><button className="more" type="button" onClick={() => navigate("projects")}>[ ALL · {projCount} ] →</button></div><div className="card-hard">{loading && projects.length === 0 ? <SkeletonRows count={4} /> : projects.slice(0, 6).map((project) => <button className="recent-row" key={project.id} type="button" onClick={() => navigate("pipeline")}><div className="placeholder thumb"><span className="ph-frame">9:16</span></div><div className="recent-meta"><div className="name">{project.name}</div><div className="sub">{[productTitle(project.product), "AI 全生", project.video_segment_count ? `${project.video_segment_count} 镜` : null].filter(Boolean).join(" / ")}</div></div><Progress status={project.current_stage} /><span className={`pill ${statusPill(project.status)}`}><span className="dot" />{stageMeta[project.current_stage]?.label || project.current_stage}</span><span className="btn btn-sm">继续</span></button>)}</div></div><div style={{ display: "flex", flexDirection: "column", gap: 24 }}><div><div className="section-h"><h2>快捷入口</h2><span className="more">[ /shortcuts ]</span></div><div className="shortcuts"><Shortcut name="package" title="商品库" desc={`${prodCount} SKU`} onClick={() => navigate("products")} /><Shortcut name="images" title="资产库" desc={`${assetCount ?? "…"} 资产`} onClick={() => navigate("library")} /><Shortcut name="creditCard" title="充值" desc={money(billing?.account.balance)} onClick={() => navigate("account")} /><Shortcut name="clapperboard" title="所有项目" desc={`${projCount} 个`} onClick={() => navigate("projects")} /></div></div><div><div className="section-h"><h2>提示</h2><span className="more">[ FAQ ]</span></div><div className="tip"><strong>扣费规则</strong>生成失败、超时、用户重跑 — 均不扣费。仅在你点 <span className="mono">[ 确认通过 ]</span> 时按 token 实际结算。</div></div></div></div>
|
||||
{/* YYX#11:新建商品抽屉 · 复用商品库同一组件,创建成功后跳商品库看新商品 */}
|
||||
{onCreateProduct && (
|
||||
<ProductCreateDrawer
|
||||
open={createDrawer}
|
||||
close={() => setCreateDrawer(false)}
|
||||
onCreate={onCreateProduct}
|
||||
onCreated={() => { setCreateDrawer(false); navigate("products"); }}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user