AirShelf/v1/mockups/mockup-C-step3.html
iye f420af2069
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 6s
chore: 全量推送 · 累积页面改动 + Next.js 工程骨架 + v1/ 归档 + 文档
页面 (电商AI平台/)
- account / team / settings / index / products / projects: 累积迭代
- restraint.css: 设计 token 补充
- login.html / register.html: 新增登录注册页
- _ARCHIVE.md: 归档说明

Next.js 工程骨架
- app/ + components/: 新一代 SPA 雏形 (page / layout / sidebar / topbar / GridBg / Icon)
- package.json / package-lock.json / next.config.mjs / tsconfig.json / postcss.config.mjs / next-env.d.ts

历史归档 / 文档
- v1/: 原 V1 静态稿镜像 (含 mockup-A/B/C)
- PRD.md / deployment-guide.md / _check.html
- ui参考/ / screenshots/

杂项
- .gitignore 调整
- 删除根 README.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 21:16:46 +08:00

531 lines
32 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>方案 3 · 子步骤分屏 · 模特挑选 · 流·Studio</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<link rel="stylesheet" href="../assets/restraint.css">
<style>
body { background: var(--bg); }
.demo-bar { padding: 16px 24px; background: var(--card); border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 16px; font-family: 'Inter', sans-serif; }
.demo-bar .ti { font-weight: 700; font-size: 15px; }
.demo-bar .desc { font-family: 'JetBrains Mono', monospace; font-size: 12px; color: var(--ink-3); }
.wb { height: calc(100vh - 60px); display: grid; grid-template-rows: 56px 1fr; background: var(--bg); }
.wb-top { padding: 0 24px; background: var(--card); border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 18px; }
.wb-top .ti { font-size: 15px; font-weight: 700; }
.wb-top .ti span { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--orange); background: var(--orange-tint); border: 1px solid var(--orange-soft); padding: 2px 6px; margin-left: 8px; letter-spacing: .04em; }
.wb-top .meta-line { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--ink-3); letter-spacing: .04em; }
.wb-top .right { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.wb-top .x { width: 32px; height: 32px; display: grid; place-items: center; cursor: pointer; color: var(--ink-2); border: 1px solid var(--border); }
.wb-top .x:hover { color: var(--orange); border-color: var(--orange); }
.wb-main { display: grid; grid-template-columns: 280px 1fr 360px; min-height: 0; }
/* Sidebar - 4 steps with sub-items */
.wb-side { border-right: 1px solid var(--border); background: var(--bg); overflow-y: auto; padding: 18px 0; }
.step-item { padding: 14px 20px; display: flex; align-items: flex-start; gap: 12px; cursor: pointer; border-left: 3px solid transparent; position: relative; }
.step-item:hover { background: var(--bg-soft); }
.step-item.active { background: var(--orange-tint); border-left-color: var(--orange); }
.step-item .num { width: 24px; height: 24px; border: 1px solid var(--border); background: var(--card); color: var(--ink-3); font-family: 'JetBrains Mono', monospace; font-size: 11px; font-weight: 700; display: grid; place-items: center; flex-shrink: 0; }
.step-item.done .num { background: var(--ink); color: #FFF; border-color: var(--ink); }
.step-item.active .num { background: var(--orange); color: #FFF; border-color: var(--orange); }
.step-item .info { flex: 1; min-width: 0; }
.step-item .ti2 { font-size: 13.5px; font-weight: 600; color: var(--ink-2); }
.step-item.active .ti2 { color: var(--ink); }
.step-item .sub { font-size: 11px; color: var(--ink-3); margin-top: 3px; font-family: 'JetBrains Mono', monospace; letter-spacing: .02em; }
/* Sub items under active step */
.substep-list { padding: 4px 20px 8px 56px; }
.substep-item {
display: flex; align-items: center; gap: 10px;
padding: 7px 10px;
cursor: pointer;
font-size: 12px; color: var(--ink-3);
border-left: 2px solid var(--border);
margin-left: -4px;
}
.substep-item:hover { color: var(--ink-2); border-left-color: var(--ink-3); }
.substep-item.active { color: var(--orange); border-left-color: var(--orange); font-weight: 600; }
.substep-item.done { color: var(--ink-2); }
.substep-item .num-mini {
width: 16px; height: 16px;
border: 1px solid currentColor;
font-family: 'JetBrains Mono', monospace; font-size: 9px; font-weight: 700;
display: grid; place-items: center;
flex-shrink: 0;
}
.substep-item.active .num-mini, .substep-item.done .num-mini { background: currentColor; color: #FFF; }
.substep-item.done .num-mini { background: var(--ink); border-color: var(--ink); }
.side-divider { height: 1px; background: var(--border); margin: 14px 20px; }
.side-section-h { padding: 4px 20px 8px; font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: var(--ink-3); letter-spacing: .08em; text-transform: uppercase; font-weight: 600; }
/* Center canvas */
.wb-canvas { background: var(--bg); overflow-y: auto; padding: 0; display: flex; flex-direction: column; min-width: 0; }
/* Sub-tab strip on top */
.subtab-strip {
padding: 0 32px;
border-bottom: 1px solid var(--border);
background: var(--card);
display: flex; align-items: center; gap: 0;
position: sticky; top: 0; z-index: 5;
}
.subtab {
padding: 14px 18px;
font-size: 13px; font-weight: 500;
color: var(--ink-2);
border-bottom: 2px solid transparent;
margin-bottom: -1px;
cursor: pointer;
display: flex; align-items: center; gap: 8px;
}
.subtab:hover { color: var(--ink); }
.subtab.active { color: var(--orange); border-bottom-color: var(--orange); font-weight: 600; }
.subtab.disabled { color: var(--ink-3); cursor: not-allowed; opacity: .55; }
.subtab .num-circ {
width: 20px; height: 20px;
border: 1px solid currentColor;
border-radius: 50%;
font-family: 'JetBrains Mono', monospace; font-size: 10px; font-weight: 700;
display: grid; place-items: center;
}
.subtab.done .num-circ { background: var(--ink); color: #FFF; border-color: var(--ink); }
.subtab.active .num-circ { background: var(--orange); color: #FFF; border-color: var(--orange); }
.subtab .arrow { color: var(--ink-3); margin: 0 4px; }
.subtab-meta { margin-left: auto; font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: var(--ink-3); letter-spacing: .04em; }
/* Canvas inner */
.canvas-inner { padding: 24px 32px 40px; flex: 1; }
.canvas-h { margin-bottom: 18px; display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.canvas-h h2 { font-size: 22px; font-weight: 700; letter-spacing: -.012em; }
.canvas-h p { font-size: 13px; color: var(--ink-2); margin-top: 4px; }
.canvas-h .step-tag { font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: var(--ink-3); padding: 3px 8px; background: var(--bg-soft); border: 1px solid var(--border-soft); letter-spacing: .04em; flex-shrink: 0; }
.filter-bar { display: flex; align-items: center; gap: 10px; margin-bottom: 18px; flex-wrap: wrap; }
.search-input { position: relative; width: 280px; }
.search-input svg { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: var(--ink-3); width: 14px; height: 14px; }
.search-input input { padding-left: 32px; height: 30px; font-size: 12.5px; background: var(--card); border: 1px solid var(--border); color: var(--ink); outline: none; width: 100%; }
.filter-chip { height: 30px; padding: 0 10px; border: 1px solid var(--border); background: var(--card); font-size: 12px; color: var(--ink-2); display: inline-flex; align-items: center; gap: 4px; cursor: pointer; font-family: inherit; }
.filter-chip:hover { background: var(--bg-soft); }
.filter-chip.active { border-color: var(--orange); color: var(--orange); background: var(--orange-tint); font-weight: 600; }
.filter-chip svg { width: 11px; height: 11px; }
.results-meta { margin-left: auto; font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--ink-3); letter-spacing: .04em; }
.model-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 12px; }
@media (max-width: 1400px) { .model-grid { grid-template-columns: repeat(5, 1fr); } }
@media (max-width: 1200px) { .model-grid { grid-template-columns: repeat(4, 1fr); } }
.model-card { aspect-ratio: 3/4; background: var(--card); border: 1px solid var(--border); cursor: pointer; position: relative; overflow: hidden; }
.model-card:hover { border-color: var(--ink-3); }
.model-card.selected { border: 2px solid var(--orange); }
.model-card.selected::after { content: '✓'; position: absolute; top: 6px; right: 6px; width: 22px; height: 22px; background: var(--orange); color: #FFF; display: grid; place-items: center; font-weight: 700; font-size: 12px; z-index: 2; }
.model-card .placeholder { width: 100%; height: 100%; }
.model-card .lbl-bottom { position: absolute; bottom: 0; left: 0; right: 0; background: rgba(255,255,255,.95); border-top: 1px solid var(--border); padding: 6px 8px; display: flex; flex-direction: column; gap: 2px; }
.model-card .lbl-bottom .nm { font-size: 12px; font-weight: 600; color: var(--ink); }
.model-card .lbl-bottom .tags { font-family: 'JetBrains Mono', monospace; font-size: 9.5px; color: var(--ink-3); letter-spacing: .02em; }
.model-card .pose-tag { position: absolute; top: 6px; left: 6px; background: rgba(0,0,0,.55); color: #FFF; font-family: 'JetBrains Mono', monospace; font-size: 9px; padding: 1px 5px; letter-spacing: .04em; z-index: 1; }
/* Wear (sub-tab 2) */
.wear-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; max-width: 760px; }
.wear-card { aspect-ratio: 1; background: var(--card); border: 1px solid var(--border); cursor: pointer; position: relative; overflow: hidden; }
.wear-card:hover { border-color: var(--ink-3); }
.wear-card .placeholder { width: 100%; height: 100%; }
.wear-card.selected { border: 3px solid var(--orange); }
.wear-card.selected::after { content: '✓'; position: absolute; top: 12px; right: 12px; width: 32px; height: 32px; background: var(--orange); color: #FFF; display: grid; place-items: center; font-weight: 700; font-size: 16px; }
.wear-card .corner-info { position: absolute; bottom: 12px; left: 12px; background: rgba(255,255,255,.94); border: 1px solid var(--border); padding: 4px 10px; font-family: 'JetBrains Mono', monospace; font-size: 11px; letter-spacing: .04em; color: var(--ink-2); }
/* Right panel */
.wb-controls { border-left: 1px solid var(--border); background: var(--bg); overflow-y: auto; padding: 22px 22px 100px; display: flex; flex-direction: column; position: relative; }
.ctrl-section { margin-bottom: 22px; }
.ctrl-section h3 { font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: var(--ink-3); letter-spacing: .08em; text-transform: uppercase; font-weight: 600; margin-bottom: 10px; }
.hover-detail { background: var(--card); border: 1px solid var(--border); padding: 14px; }
.hover-detail .hd-name { font-size: 15px; font-weight: 700; }
.hover-detail .hd-tags { display: flex; gap: 4px; flex-wrap: wrap; margin-top: 6px; }
.hover-detail .hd-tags span { font-family: 'JetBrains Mono', monospace; font-size: 10px; color: var(--ink-2); background: var(--bg-soft); border: 1px solid var(--border-soft); padding: 1px 5px; letter-spacing: .02em; }
.hover-detail .hd-views { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; margin-top: 12px; }
.hover-detail .hd-views .placeholder { aspect-ratio: 3/4; }
.hover-detail .hd-meta { display: flex; flex-direction: column; gap: 6px; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); font-size: 11.5px; color: var(--ink-2); }
.hover-detail .hd-meta div { display: flex; gap: 8px; }
.hover-detail .hd-meta .k { font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: var(--ink-3); width: 56px; letter-spacing: .04em; }
.selected-list { display: flex; flex-direction: column; gap: 6px; }
.sel-row { display: flex; align-items: center; gap: 8px; padding: 6px 8px; background: var(--card); border: 1px solid var(--border); }
.sel-row .placeholder { width: 28px; height: 36px; flex-shrink: 0; }
.sel-row .nm { flex: 1; font-size: 12px; font-weight: 600; }
.sel-row .x-btn { width: 18px; height: 18px; display: grid; place-items: center; cursor: pointer; color: var(--ink-3); }
.sel-row .x-btn:hover { color: var(--red); }
.tip-mini { padding: 10px 12px; background: var(--orange-tint); border: 1px solid var(--orange-soft); font-size: 11.5px; color: var(--ink-2); line-height: 1.5; }
.tip-mini strong { color: var(--orange); display: block; font-family: 'JetBrains Mono', monospace; font-size: 10px; letter-spacing: .04em; margin-bottom: 4px; }
.wb-bottom { position: absolute; left: 0; right: 0; bottom: 0; padding: 14px 22px; background: var(--card); border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: 10px; }
.wb-bottom .row1 { display: flex; align-items: center; justify-content: space-between; }
.cost-info { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--ink-3); letter-spacing: .04em; }
.cost-info .price { color: var(--orange); font-weight: 700; }
/* Step pane switching */
.sub-pane { display: none; }
.sub-pane.active { display: block; animation: fade .2s ease; }
@keyframes fade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } }
</style>
</head>
<body>
<div class="demo-bar">
<a href="index.html" class="btn btn-ghost btn-sm">← 返回方案对比</a>
<span class="ti">方案 3 · 子步骤分屏(4 步主流程,Step 3 内部 2 个子 Tab)</span>
<span class="desc">// 顶部子 Tab 切换:挑选模特 → 生成上身图 · 在同一步骤内递进</span>
</div>
<div class="wb">
<header class="wb-top">
<div class="ti">透真玻尿酸补水面膜 <span>[ AI 生成模式 ]</span></div>
<div class="meta-line">// 美妆个护 · ¥39.9 · 已选头图 A · WHITE-BG</div>
<div class="right">
<button class="btn btn-sm">保存草稿</button>
<div class="x"><svg width="14" height="14" viewBox="0 0 16 16"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg></div>
</div>
</header>
<div class="wb-main">
<!-- Left: 4 main steps + sub items under step 3 -->
<aside class="wb-side">
<div class="side-section-h">// CREATE FLOW · 4 STEPS</div>
<div class="step-item done"><div class="num"></div><div class="info"><div class="ti2">商品信息</div><div class="sub">名称、品类、价格、卖点</div></div></div>
<div class="step-item done"><div class="num"></div><div class="info"><div class="ti2">生成头图</div><div class="sub">已选 1 / 4 · 候选 A</div></div></div>
<div class="step-item active">
<div class="num">3</div>
<div class="info"><div class="ti2">模特上身图</div><div class="sub">// 子流程 · ① 挑模特 → ② 生上身</div></div>
</div>
<div class="substep-list" id="sub-nav">
<div class="substep-item active" data-sub="1">
<span class="num-mini"></span>
<span>挑选模特</span>
<span style="margin-left:auto; font-family:'JetBrains Mono',monospace; font-size:10px; opacity:.7;">2 / 50+</span>
</div>
<div class="substep-item" data-sub="2">
<span class="num-mini"></span>
<span>生成上身图</span>
<span style="margin-left:auto; font-family:'JetBrains Mono',monospace; font-size:10px; opacity:.6;">待开始</span>
</div>
</div>
<div class="step-item"><div class="num">4</div><div class="info"><div class="ti2">完成创建</div><div class="sub">// 预览 · 提交</div></div></div>
<div class="side-divider"></div>
<div class="side-section-h">// SELECTED ASSETS</div>
<div style="padding: 0 20px;">
<div style="font-size:11.5px; color:var(--ink-3); margin-bottom:6px; font-family:'JetBrains Mono',monospace; letter-spacing:.02em;">原图 · 1 张</div>
<div class="placeholder" style="width:100%; aspect-ratio: 4/5; margin-bottom:12px;"><span class="ph-frame">补水面膜<br>1200×1500</span></div>
<div style="font-size:11.5px; color:var(--ink-3); margin-bottom:6px; font-family:'JetBrains Mono',monospace; letter-spacing:.02em;">头图 · 候选 A</div>
<div class="placeholder" style="width:100%; aspect-ratio: 1; margin-bottom:12px;"><span class="ph-frame">A · 白底简约</span></div>
</div>
</aside>
<!-- Center canvas: with sub-tab strip on top -->
<main class="wb-canvas">
<!-- Sub-tab strip -->
<div class="subtab-strip">
<div class="subtab active" data-sub="1">
<span class="num-circ"></span>
挑选模特
</div>
<span class="arrow" style="color:var(--ink-3); padding: 0 6px;"></span>
<div class="subtab disabled" data-sub="2">
<span class="num-circ"></span>
生成上身图
</div>
<span class="subtab-meta" id="subtab-meta">// SUB-STEP 1 / 2 · 已选模特 <span style="color:var(--orange); font-weight:700;" id="meta-count">2</span></span>
</div>
<div class="canvas-inner">
<!-- ============= SUB 1 · 挑选模特 ============= -->
<section class="sub-pane active" data-pane="1">
<div class="canvas-h">
<div>
<h2>挑选模特 · 子步骤 ①</h2>
<p>从 AI 模特库选 1 个或多个,统一白 T + 白短裤立绘。选好后点右下「下一步 → 生成上身图」自动跳到 ②。</p>
</div>
<span class="step-tag">// STEP 3 / 4 · SUB 1</span>
</div>
<div class="filter-bar">
<div class="search-input">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
<input type="text" placeholder="搜索模特名称、风格…">
</div>
<button class="filter-chip active">全部 <span style="font-family:'JetBrains Mono',monospace; opacity:.7;">52</span></button>
<button class="filter-chip">女性</button>
<button class="filter-chip">男性</button>
<button class="filter-chip">25-30 岁</button>
<button class="filter-chip">都市白领</button>
<button class="filter-chip">学生</button>
<button class="filter-chip">居家</button>
<button class="filter-chip">+ 更多筛选 <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M4 6l4 4 4-4"/></svg></button>
<span class="results-meta">// 12 / 52 · 已选 <span id="sel-count" style="color:var(--orange); font-weight:700;">2</span></span>
</div>
<div class="model-grid" id="model-grid">
<div class="model-card selected" data-id="m1" onmouseenter="hoverModel('林夕','女 · 25-30','都市白领',['温柔','日常','OL','通勤'])">
<span class="pose-tag">[ 立绘 · 肩上 ]</span>
<div class="placeholder"><span class="ph-frame">林夕 · 都市女</span></div>
<div class="lbl-bottom"><div class="nm">林夕</div><div class="tags">女 · 25-30 · 都市白领</div></div>
</div>
<div class="model-card" data-id="m2" onmouseenter="hoverModel('阿楠','女 · 25-30','姐妹/同事',['精致','干练','短发'])">
<span class="pose-tag">[ 立绘 · 肩上 ]</span>
<div class="placeholder"><span class="ph-frame">阿楠</span></div>
<div class="lbl-bottom"><div class="nm">阿楠</div><div class="tags">女 · 25-30 · 同事</div></div>
</div>
<div class="model-card selected" data-id="m3" onmouseenter="hoverModel('小七','女 · 18-22','学生/Z世代',['青春','元气','校园'])">
<span class="pose-tag">[ 立绘 · 肩上 ]</span>
<div class="placeholder"><span class="ph-frame">小七 · 学生</span></div>
<div class="lbl-bottom"><div class="nm">小七</div><div class="tags">女 · 18-22 · 学生</div></div>
</div>
<div class="model-card" data-id="m4" onmouseenter="hoverModel('王姐','女 · 38-45','妈妈/居家',['亲和','成熟','温暖'])">
<span class="pose-tag">[ 立绘 · 肩上 ]</span>
<div class="placeholder"><span class="ph-frame">王姐 · 居家</span></div>
<div class="lbl-bottom"><div class="nm">王姐</div><div class="tags">女 · 38-45 · 妈妈</div></div>
</div>
<div class="model-card" data-id="m5" onmouseenter="hoverModel('阿杰','男 · 28-35','通勤男',['商务','干练','西装'])">
<span class="pose-tag">[ 立绘 · 肩上 ]</span>
<div class="placeholder"><span class="ph-frame">阿杰 · 通勤男</span></div>
<div class="lbl-bottom"><div class="nm">阿杰</div><div class="tags">男 · 28-35 · 通勤</div></div>
</div>
<div class="model-card" data-id="m6" onmouseenter="hoverModel('阿强','男 · 22-28','健身男',['阳光','运动','肌肉'])">
<span class="pose-tag">[ 立绘 · 肩上 ]</span>
<div class="placeholder"><span class="ph-frame">阿强 · 健身男</span></div>
<div class="lbl-bottom"><div class="nm">阿强</div><div class="tags">男 · 22-28 · 健身</div></div>
</div>
<div class="model-card" data-id="m7" onmouseenter="hoverModel('小苏','女 · 22-26','文艺研究生',['书卷气','静谧','文艺'])">
<span class="pose-tag">[ 立绘 · 肩上 ]</span>
<div class="placeholder"><span class="ph-frame">小苏 · 文艺女</span></div>
<div class="lbl-bottom"><div class="nm">小苏</div><div class="tags">女 · 22-26 · 文艺</div></div>
</div>
<div class="model-card" data-id="m8" onmouseenter="hoverModel('文文','女 · 30-38','母亲',['温柔','母性','温暖'])">
<span class="pose-tag">[ 立绘 · 肩上 ]</span>
<div class="placeholder"><span class="ph-frame">文文 · 母亲</span></div>
<div class="lbl-bottom"><div class="nm">文文</div><div class="tags">女 · 30-38 · 母亲</div></div>
</div>
<div class="model-card" data-id="m9" onmouseenter="hoverModel('老王','男 · 45-55','大叔',['沉稳','成熟','商务'])">
<span class="pose-tag">[ 立绘 · 肩上 ]</span>
<div class="placeholder"><span class="ph-frame">老王 · 大叔</span></div>
<div class="lbl-bottom"><div class="nm">老王</div><div class="tags">男 · 45-55 · 大叔</div></div>
</div>
<div class="model-card" data-id="m10" onmouseenter="hoverModel('萌萌','女 · 18-22','Z世代',['可爱','潮流','二次元'])">
<span class="pose-tag">[ 立绘 · 肩上 ]</span>
<div class="placeholder"><span class="ph-frame">萌萌 · Z世代</span></div>
<div class="lbl-bottom"><div class="nm">萌萌</div><div class="tags">女 · 18-22 · Z 世代</div></div>
</div>
<div class="model-card" data-id="m11" onmouseenter="hoverModel('Leo','男 · 30-38','健身教练',['专业','力量','健身房'])">
<span class="pose-tag">[ 立绘 · 肩上 ]</span>
<div class="placeholder"><span class="ph-frame">Leo · 教练</span></div>
<div class="lbl-bottom"><div class="nm">Leo</div><div class="tags">男 · 30-38 · 教练</div></div>
</div>
<div class="model-card" data-id="m12" onmouseenter="hoverModel('双人组合','双人 · 25-30','闺蜜',['亲密','日常','搭档'])">
<span class="pose-tag">[ 立绘 · 双人 ]</span>
<div class="placeholder"><span class="ph-frame">闺蜜双人</span></div>
<div class="lbl-bottom"><div class="nm">闺蜜组合</div><div class="tags">双人 · 25-30</div></div>
</div>
</div>
<div style="margin-top: 18px; padding: 12px 16px; background: var(--card); border: 1px dashed var(--border); text-align: center; font-family: 'JetBrains Mono', monospace; font-size: 11.5px; color: var(--ink-3); letter-spacing: .02em;">
// 还有 40 个模特 · 滚动加载 / 用上方筛选缩小范围
</div>
</section>
<!-- ============= SUB 2 · 生成上身图 ============= -->
<section class="sub-pane" data-pane="2">
<div class="canvas-h">
<div>
<h2>生成上身图 · 子步骤 ②</h2>
<p>已为你选的每个模特生成 4 张上身图,可多选保留。可点 ← 回到「① 挑选模特」改人。</p>
</div>
<span class="step-tag">// STEP 3 / 4 · SUB 2</span>
</div>
<div style="display:flex; align-items:center; gap:8px; margin-bottom:14px; padding:10px 14px; background: var(--card); border: 1px solid var(--border);">
<span style="font-family:'JetBrains Mono',monospace; font-size:11px; color:var(--ink-3); letter-spacing:.02em;">// 当前模特:</span>
<button class="filter-chip active" style="height: 26px;">林夕 · 都市白领</button>
<button class="filter-chip" style="height: 26px;">小七 · 学生</button>
<span style="margin-left:auto; font-family:'JetBrains Mono',monospace; font-size:11px; color:var(--ink-3); letter-spacing:.02em;">// 切换模特看不同上身效果</span>
</div>
<div class="wear-grid">
<div class="wear-card selected"><div class="placeholder"><span class="ph-frame">上身 A · 持物半身</span></div><span class="corner-info">[ A · 持物半身 ]</span></div>
<div class="wear-card"><div class="placeholder"><span class="ph-frame">上身 B · 敷面膜中</span></div><span class="corner-info">[ B · 敷面膜中 ]</span></div>
<div class="wear-card selected"><div class="placeholder"><span class="ph-frame">上身 C · 镜前自拍</span></div><span class="corner-info">[ C · 镜前自拍 ]</span></div>
<div class="wear-card"><div class="placeholder"><span class="ph-frame">上身 D · 床边特写</span></div><span class="corner-info">[ D · 床边特写 ]</span></div>
</div>
<div style="margin-top: 18px; display: flex; align-items: center; gap: 12px;">
<button class="btn btn-sm">↻ 全部重新生成(¥0.40)</button>
<span style="font-family:'JetBrains Mono',monospace; font-size:11px; color:var(--ink-3); letter-spacing:.02em;">// 不满意不扣费 · 已选 2 / 4 张</span>
</div>
</section>
</div>
</main>
<!-- Right controls -->
<aside class="wb-controls">
<div class="ctrl-section">
<h3>// 当前悬浮 · DETAIL</h3>
<div class="hover-detail" id="hover-detail">
<div class="hd-name">林夕</div>
<div class="hd-tags">
<span></span><span>25-30</span><span>都市白领</span><span>温柔</span><span>OL</span><span>通勤</span>
</div>
<div class="hd-views">
<div class="placeholder"><span class="ph-frame">正面</span></div>
<div class="placeholder"><span class="ph-frame">侧面</span></div>
<div class="placeholder"><span class="ph-frame">背面</span></div>
</div>
<div class="hd-meta">
<div><span class="k">// 服装</span><span>白 T + 白短裤(默认立绘)</span></div>
<div><span class="k">// 年龄</span><span>25-30 岁 · 可微调 ±3</span></div>
<div><span class="k">// 身材</span><span>普通女 · 165cm / 50kg</span></div>
<div><span class="k">// 用过</span><span>4 个项目 · 平均评分 4.5</span></div>
</div>
</div>
</div>
<div class="ctrl-section">
<h3>// 已选模特 · <span style="color:var(--orange); font-weight:700;" id="sel-count-3">2</span></h3>
<div class="selected-list" id="selected-list">
<div class="sel-row" data-id="m1">
<div class="placeholder"><span class="ph-frame"></span></div>
<div class="nm">林夕 · 都市白领</div>
<div class="x-btn" title="移除"></div>
</div>
<div class="sel-row" data-id="m3">
<div class="placeholder"><span class="ph-frame"></span></div>
<div class="nm">小七 · 学生</div>
<div class="x-btn" title="移除"></div>
</div>
</div>
</div>
<div class="ctrl-section">
<h3>// TIP</h3>
<div class="tip-mini">
<strong>子步骤的好处</strong>
挑模特 → 生上身在同一个 Step 内推进,左侧 sidebar 不变多。Sub Tab 可来回切换不丢已选。
</div>
</div>
<div class="wb-bottom">
<div class="row1">
<span class="cost-info">// 预计 <span class="price">¥0.80</span> / 8 张</span>
<span class="cost-info" id="bottom-meta">SUB 1 / 2</span>
</div>
<div class="hstack">
<button class="btn" style="flex:1;" id="btn-prev-sub">← 上一步</button>
<button class="btn btn-primary" style="flex:1;" id="btn-next-sub">下一步 → 生成上身</button>
</div>
</div>
</aside>
</div>
</div>
<script>
let curSub = 1;
function switchSub(n) {
curSub = n;
document.querySelectorAll('.sub-pane').forEach(p => p.classList.remove('active'));
document.querySelector(`[data-pane="${n}"]`).classList.add('active');
// sub tabs in canvas
document.querySelectorAll('.subtab').forEach(t => {
t.classList.remove('active', 'done', 'disabled');
const tn = +t.dataset.sub;
if (tn < n) t.classList.add('done');
else if (tn === n) t.classList.add('active');
});
// sub items in sidebar
document.querySelectorAll('.substep-item').forEach(t => {
t.classList.remove('active', 'done');
const tn = +t.dataset.sub;
if (tn < n) t.classList.add('done');
else if (tn === n) t.classList.add('active');
});
document.getElementById('subtab-meta').innerHTML = n === 1
? '// SUB-STEP 1 / 2 · 已选模特 <span style="color:var(--orange); font-weight:700;">2</span>'
: '// SUB-STEP 2 / 2 · 上身图 4 选 N';
document.getElementById('bottom-meta').textContent = `SUB ${n} / 2`;
document.getElementById('btn-next-sub').textContent = n === 1 ? '下一步 → 生成上身' : '下一步 → 完成创建';
document.querySelector('.wb-canvas').scrollTop = 0;
}
document.querySelectorAll('.subtab').forEach(t => {
t.onclick = () => {
if (t.classList.contains('disabled')) {
const n = +t.dataset.sub;
// allow click after step 1 satisfied
switchSub(n);
} else {
switchSub(+t.dataset.sub);
}
};
});
document.querySelectorAll('.substep-item').forEach(t => {
t.onclick = () => switchSub(+t.dataset.sub);
});
document.getElementById('btn-next-sub').onclick = () => {
if (curSub === 1) switchSub(2);
else alert('→ 进入 Step 4 完成创建');
};
document.getElementById('btn-prev-sub').onclick = () => {
if (curSub === 2) switchSub(1);
else alert('← 返回 Step 2 头图');
};
// multi select
document.querySelectorAll('.model-card').forEach(c => {
c.onclick = () => {
c.classList.toggle('selected');
updateCount();
};
});
function updateCount() {
const n = document.querySelectorAll('.model-card.selected').length;
document.getElementById('sel-count').textContent = n;
document.getElementById('sel-count-3').textContent = n;
document.getElementById('meta-count').textContent = n;
}
function hoverModel(name, base, role, tags) {
const hd = document.getElementById('hover-detail');
hd.querySelector('.hd-name').textContent = name;
hd.querySelector('.hd-tags').innerHTML = (base.split(' · ')).concat([role]).concat(tags).map(t => `<span>${t}</span>`).join('');
}
// wear cards multi select
document.querySelectorAll('.wear-card').forEach(c => {
c.onclick = () => c.classList.toggle('selected');
});
document.querySelectorAll('.x-btn').forEach(b => {
b.onclick = (e) => {
e.stopPropagation();
const row = b.closest('.sel-row');
const id = row.dataset.id;
document.querySelector(`.model-card[data-id="${id}"]`)?.classList.remove('selected');
row.remove();
updateCount();
};
});
</script>
</body>
</html>