All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 6s
页面 (电商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>
531 lines
32 KiB
HTML
531 lines
32 KiB
HTML
<!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>
|