This commit is contained in:
parent
04335f3269
commit
553014cc79
@ -249,7 +249,7 @@
|
||||
<div class="export-wrap" style="flex:1; position:relative;">
|
||||
<button class="btn btn-ghost btn-lg" id="export-trigger" type="button" style="width:100%;">
|
||||
导出账单
|
||||
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-left:6px; vertical-align:-1px;"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="margin-left:6px; vertical-align:-1px;"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</button>
|
||||
<div class="export-menu" id="export-menu" hidden>
|
||||
<button type="button" data-fmt="csv"><span class="ic">⌥</span><span class="t">CSV<span class="d">// 全部明细 · Excel 兼容</span></span></button>
|
||||
@ -479,7 +479,7 @@
|
||||
<span class="corner-tr" aria-hidden></span><span class="corner-bl" aria-hidden></span>
|
||||
<div class="modal-h">
|
||||
<div class="ic-m">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v10M9 10h4a1.5 1.5 0 0 1 0 3h-3a1.5 1.5 0 0 0 0 3h4"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v10M9 10h4a1.5 1.5 0 0 1 0 3h-3a1.5 1.5 0 0 0 0 3h4"/></svg>
|
||||
</div>
|
||||
<div class="ti">扫码支付<span id="topup-channel-label">// 微信支付</span></div>
|
||||
</div>
|
||||
|
||||
@ -167,6 +167,7 @@ img, svg, video { display: block; max-width: 100%; }
|
||||
.muted-2 { color: var(--black-alpha-48); }
|
||||
.spacer { flex: 1; }
|
||||
.hstack { display: flex; align-items: center; gap: 8px; }
|
||||
.hstack[hidden], .vstack[hidden] { display: none; }
|
||||
.vstack { display: flex; flex-direction: column; gap: 8px; }
|
||||
.divider { height: 1px; background: var(--border-faint); margin: 16px 0; }
|
||||
|
||||
@ -374,6 +375,7 @@ main { position: relative; background: var(--background-base); min-width: 0; }
|
||||
transition: background var(--t-base), border-color var(--t-base);
|
||||
}
|
||||
.queue-chip:hover { background: var(--black-alpha-4); border-color: var(--black-alpha-24); }
|
||||
.queue-chip[hidden] { display: none; }
|
||||
.queue-chip svg { width: 14px; height: 14px; color: var(--black-alpha-56); }
|
||||
.queue-chip .count {
|
||||
display: inline-flex; align-items: center; justify-content: center;
|
||||
@ -481,6 +483,7 @@ main { position: relative; background: var(--background-base); min-width: 0; }
|
||||
border-color: var(--black-alpha-12);
|
||||
}
|
||||
.btn svg { width: 13px; height: 13px; }
|
||||
.btn[hidden] { display: none; }
|
||||
|
||||
.btn-primary {
|
||||
background: var(--heat);
|
||||
|
||||
@ -93,12 +93,12 @@ window.Shell = {
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="9"/><path d="M12 7v10M9 10h4a1.5 1.5 0 0 1 0 3h-3a1.5 1.5 0 0 0 0 3h4"/></svg>
|
||||
余额 <strong>${balance}</strong>
|
||||
</span>
|
||||
<button class="queue-chip" onclick="Shell.toast('任务队列', '3 个进行中')">
|
||||
<button class="queue-chip" onclick="Shell.toast('任务队列', '3 个进行中')" hidden>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18M3 12h18M3 18h18"/></svg>
|
||||
任务队列
|
||||
<span class="count">3</span>
|
||||
</button>
|
||||
<button class="icon-btn" onclick="Shell.toast('通知中心', '12 条未读')">
|
||||
<button class="icon-btn" onclick="location.href='messages.html'" title="消息中心">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9M10 21a2 2 0 0 0 4 0"/></svg>
|
||||
<span class="count-noti">12</span>
|
||||
</button>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
426
电商AI平台/design.md
426
电商AI平台/design.md
@ -542,10 +542,436 @@ Disabled: 底 `--black-alpha-5` + 边 `--black-alpha-12` + 半透明。
|
||||
|
||||
**颜色:** 默认 `--black-alpha-56` / hover `--accent-black` / active `--heat` / disabled `--black-alpha-12` / 在主 CTA 内 `#fff`。
|
||||
|
||||
### §4.13 AI 对话面板(编辑器型页面专用)
|
||||
|
||||
> **使用范围:** AI 图片创作 / 流水线 AI 助手 / 商品 AI 优化 / 镜头脚本编辑。3 个编辑器页(pipeline / model-photo / image-optimize)定义一致 — 已成事实组件,该抽到 restraint.css。
|
||||
|
||||
#### HTML 结构
|
||||
|
||||
```html
|
||||
<div class="pane chat-pane">
|
||||
<div class="pane-h">
|
||||
<span class="ic-box"><svg>...</svg></span>
|
||||
<span class="ti">AI 助手</span>
|
||||
<span class="mono" style="margin-left:auto">// chat /v2</span>
|
||||
</div>
|
||||
<div class="chat-body">
|
||||
<div class="msg ai">
|
||||
<div class="bubble">你好,我来帮你优化这张图...</div>
|
||||
<div class="mono ts">// 14:32</div>
|
||||
</div>
|
||||
<div class="msg user">
|
||||
<div class="bubble">请把背景换成咖啡厅</div>
|
||||
</div>
|
||||
<div class="msg ai">
|
||||
<div class="ai-thinking"><span class="dots"><span></span><span></span><span></span></span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-input">
|
||||
<div class="chat-input-card">
|
||||
<textarea placeholder="@AI 帮我..."></textarea>
|
||||
<div class="chat-input-actions">
|
||||
<button class="btn btn-sm btn-ghost">附件</button>
|
||||
<button class="btn btn-sm btn-primary">发送 →</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### 关键 CSS
|
||||
|
||||
| 类 | 关键属性 |
|
||||
| -- | -------- |
|
||||
| `.chat-pane` | `flex column / 高度填充父容器` |
|
||||
| `.chat-body` | `flex 1 / overflow-y auto / padding 16 18 / gap 14 / flex column / max-height 460(可选)` |
|
||||
| `.chat-input` | `padding 14 18 18 / border-top 1px var(--border-faint)` |
|
||||
| `.chat-input-card` | `bg --background-base / border 1px --border-faint / radius 8 / padding 12 14 10` · `:focus-within` 边变 `--accent-black` + ring `0 0 0 3px rgba(0,0,0,.04)` |
|
||||
|
||||
#### 消息气泡(`.msg.ai` / `.msg.user`)
|
||||
|
||||
| 类型 | 对齐 | 气泡背景 | 气泡边框 | 字色 |
|
||||
| ---- | ---- | -------- | -------- | ---- |
|
||||
| `.msg.ai` | 左对齐(默认) | `--surface` 白 | `--border-faint` | `--accent-black` |
|
||||
| `.msg.user` | 右对齐(`align-items: flex-end`) | `--heat-12` 浅橙 | `--heat-20` | `--accent-black` |
|
||||
|
||||
所有气泡共享:`max-width 90% / padding 10 14 / font-size 13 / line-height 1.6 / radius 8`。
|
||||
时间戳放气泡下:mono 11 px / `--black-alpha-48` / 格式 `// 14:32`。
|
||||
|
||||
#### 打字指示器(`.ai-thinking`)
|
||||
|
||||
3 个 6×6 圆点 · 1.2 s 交替闪烁:
|
||||
|
||||
```css
|
||||
.ai-thinking .dots { display: inline-flex; gap: 3px; }
|
||||
.ai-thinking .dots span {
|
||||
width: 6px; height: 6px; background: var(--black-alpha-32);
|
||||
border-radius: 50%;
|
||||
animation: thinking 1.2s ease-in-out infinite;
|
||||
}
|
||||
.ai-thinking .dots span:nth-child(2) { animation-delay: .15s; }
|
||||
.ai-thinking .dots span:nth-child(3) { animation-delay: .30s; }
|
||||
@keyframes thinking {
|
||||
0%, 80%, 100% { opacity: .25; }
|
||||
40% { opacity: 1; }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### §4.14 商品 / 资产卡片体系(3 种形态)
|
||||
|
||||
> **核心原则:** 商品 + 资产 + 人物 + 场景共用**一套**卡片体系,按"使用场景"选形态。**不要为每种内容类型做新类。**
|
||||
|
||||
#### 三种形态总览
|
||||
|
||||
| 形态 | 类名(建议统一) | 缩图比 | 缩图宽度 | 使用场景 |
|
||||
| ---- | -------------- | ------ | -------- | -------- |
|
||||
| **网格主卡** | `.product-card` | 1.4:1(商品)· 1:1(资产/场景)· 3:4(人物) | 自适应宽 | 商品库 / 资产库 / 团队页主网格 |
|
||||
| **行卡(列表)** | `.prod-row` 或 `.mp-prod-item` | 1:1 | 28–36 px | 表单内已选行 / 侧栏列表 |
|
||||
| **选择器卡** | `.pl-card` / `.opt-card` / `.model-card` | 1:1 或 3:4 | 100–160 px | Modal 内多选 picker |
|
||||
|
||||
#### 4.14.1 网格主卡(`.product-card`)
|
||||
|
||||
```html
|
||||
<div class="product-card">
|
||||
<div class="product-thumb placeholder">9:16</div>
|
||||
<div class="product-body">
|
||||
<div class="product-name">夏季新款蕾丝连衣裙</div>
|
||||
<div class="product-cat mono">// 女装 · 蓝色</div>
|
||||
</div>
|
||||
<div class="product-footer">
|
||||
<span class="stat">素材 <b>124</b></span>
|
||||
<span class="sep">·</span>
|
||||
<span class="stat">视频 <b>36</b></span>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
关键 CSS:
|
||||
- 容器:`bg --surface / border 1px --border-faint / radius 8 / display flex column / overflow hidden / cursor pointer`
|
||||
- hover:`bg --background-lighter / border --black-alpha-48`
|
||||
- 缩图:`aspect-ratio` 按内容类型选 — 商品 `1.4/1` · 资产 `1/1` · 人物 `3/4`
|
||||
- body:`padding 14 14 12 / flex 1`
|
||||
- name:`14 / 600 / --accent-black / 单行省略`
|
||||
- cat(分类):mono 11 / `--black-alpha-48`
|
||||
- footer:`grid 1fr auto 1fr / padding 10 12 / border-top 1px --border-faint / bg --background-base / font 11.5 / 字 --black-alpha-56`
|
||||
|
||||
**变体:**
|
||||
- `.product-card.with-action` — footer 右侧加一个小按钮(用于流水线 stage 2 资产库的"AI 生成"入口)
|
||||
- `.product-card` 默认支持 selectable 模式:加 `.card-check` 22×22 圆形 checkbox(左上 hover 显示)+ 选中态 border 加深
|
||||
|
||||
#### 4.14.2 行卡(`.prod-row` / `.mp-prod-item`)
|
||||
|
||||
```html
|
||||
<div class="prod-row">
|
||||
<div class="thumb placeholder">9:16</div>
|
||||
<div class="nm">夏季新款蕾丝连衣裙</div>
|
||||
<button class="row-swap"><svg>swap</svg></button>
|
||||
<button class="row-x"><svg>×</svg></button>
|
||||
</div>
|
||||
```
|
||||
|
||||
紧凑行卡:`flex align-center / gap 10 / padding 8 10 / bg --background-lighter / border 1px --border-faint / radius 6 / 28-36 px 缩图 + 单行文本`。
|
||||
|
||||
**用法:**
|
||||
- 表单里"已选商品"列表(可删可换)
|
||||
- 侧栏商品/演员列表(`.mp-prod-item` · 36×36 缩图)
|
||||
- 流水线 stage 选中态
|
||||
|
||||
#### 4.14.3 选择器卡(`.pl-card`)
|
||||
|
||||
```html
|
||||
<div class="pl-card selected">
|
||||
<div class="pl-thumb placeholder">3:4</div>
|
||||
<div class="pl-name">夏季新款蕾丝连衣裙</div>
|
||||
<div class="pl-check"><svg>✓</svg></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Modal 内多选 picker:`bg --background-lighter / padding 10 / display flex column / gap 6 / cursor pointer`。
|
||||
|
||||
3 种状态:
|
||||
|
||||
| 状态 | 视觉 |
|
||||
| ---- | ---- |
|
||||
| 默认 | `bg --background-lighter / border 1px --border-faint` |
|
||||
| hover | `bg --surface`(变白) |
|
||||
| **selected ★** | `border var(--heat) / bg var(--heat-12)` + 右上角橙色勾 SVG |
|
||||
|
||||
---
|
||||
|
||||
### §4.15 人物 / 演员 / 模特卡片(`.model-card`)
|
||||
|
||||
> **本质:** 选择器卡的"人物 3:4 竖图"特例。**复用 `.pl-card` 的选中态逻辑**,只换缩图比例。
|
||||
|
||||
```html
|
||||
<div class="model-card selected">
|
||||
<div class="m-thumb placeholder">3:4</div>
|
||||
<div class="m-name">林夏 · 25 岁</div>
|
||||
<div class="m-meta mono">// 165cm · 都市风</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
| 元素 | 样式 |
|
||||
| ---- | ---- |
|
||||
| 缩图 | `aspect-ratio: 3/4`(人物竖图标准) |
|
||||
| name | 12.5 / 500 / `--accent-black` |
|
||||
| meta | mono 11 / `--black-alpha-48` |
|
||||
| 选中态 | 同 `.pl-card`(橙边 + 橙底 + 右上勾) |
|
||||
|
||||
**与 `.pl-card` 的关系:** 同一基类,仅缩图比例不同 — 商品 1:1 / 人物 3:4。
|
||||
**建议实现:** `.model-card` 继承 `.pl-card` 基类 + 覆盖 `.pl-thumb` 的 `aspect-ratio`。
|
||||
|
||||
---
|
||||
|
||||
### §4.16 场景卡片(复用 `.asset-card-2`)
|
||||
|
||||
> 场景卡 = 资产卡的"1:1 通用"形态。**不要做新类**,只语义命名。
|
||||
|
||||
```html
|
||||
<div class="asset-card-2 scene-card">
|
||||
<div class="thumb-2 placeholder">1:1</div>
|
||||
<div class="body-2">
|
||||
<div class="ti">咖啡厅 · 暖光</div>
|
||||
<div class="sub mono">// indoor · warm</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
`.asset-card-2`(通用资产卡基础):
|
||||
- `bg --surface / border 1px --border-faint / radius 8 / overflow hidden / display flex column`
|
||||
- hover:`border --heat-40 / box-shadow 0 1 3 rgba(0,0,0,.04)`
|
||||
- 缩图:`aspect-ratio 1` 正方形 · 通常宽 240 px(flex shrink 0)
|
||||
- body:`padding 12 14`
|
||||
- ti:14 / 500 / `--accent-black` · sub:mono 11 / `--black-alpha-48`
|
||||
|
||||
**派生类只做语义命名:** `.scene-card` / `.person-card` / `.background-card` — 样式继承 `.asset-card-2`,**不要重新写规则**。
|
||||
|
||||
---
|
||||
|
||||
### §4.17 其他高频复用组件
|
||||
|
||||
以下组件已在 2-5 个页面重复定义,需要尽快抽到 restraint.css。规范在此先记录。
|
||||
|
||||
#### 4.17.1 流程步骤条(`.stepper` / `.stage-step`)
|
||||
|
||||
```html
|
||||
<div class="stepper">
|
||||
<div class="stage-step done"><span class="num">1</span><span class="lbl">商品</span></div>
|
||||
<div class="stage-step active"><span class="num">2</span><span class="lbl">故事板</span></div>
|
||||
<div class="stage-step"><span class="num">3</span><span class="lbl">镜头</span></div>
|
||||
<div class="stage-step"><span class="num">4</span><span class="lbl">生成</span></div>
|
||||
<div class="stage-step"><span class="num">5</span><span class="lbl">投放</span></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
| 元素 | 样式 |
|
||||
| ---- | ---- |
|
||||
| 容器 | `flex align-center / padding 14 18 / bg --surface / border 1px --border-faint / radius 8` |
|
||||
| `.num` 编号 | 26×26 / mono 12 / 600 / radius 4 / 默认 `bg --surface + border 1px --border-faint + 字 --black-alpha-48` |
|
||||
| `.done .num` | `bg --accent-black + 字 --accent-white`(已完成 · 黑) |
|
||||
| **`.active .num`** | `bg --heat + 字 --accent-white`(进行中 · 橙) |
|
||||
| 步间连接线 | 1 px / `--border-faint` / 高 1 px / 长度自适应 |
|
||||
|
||||
**与 `.prog` 区别:** `.prog` 是 5 段进度条徽标(横放在卡片角落),`.stepper` 是大尺寸主流程步骤条(放在 page-head 之下)。
|
||||
|
||||
#### 4.17.2 分页(`.pagination`)
|
||||
|
||||
```html
|
||||
<div class="pagination">
|
||||
<span class="total">共 <b>12</b> 条</span>
|
||||
<button class="page-size">12 条/页</button>
|
||||
<span class="pages">
|
||||
<button>1</button>
|
||||
<button class="active">2</button>
|
||||
<button>3</button>
|
||||
</span>
|
||||
<span class="jump">跳至 <input type="number"> 页</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
| 元素 | 样式 |
|
||||
| ---- | ---- |
|
||||
| 容器 | sticky bottom / `flex gap 16 / padding 14 0 / border-top 1px --border-faint / bg --background-base / font 12.5 / 字 --black-alpha-56` |
|
||||
| 页码按钮 | 30×30 / radius 4 · 4 px 不是 8(密集场景小圆角不破节奏) |
|
||||
| 默认页 | `bg --surface / border 1px --border-faint / 字 --black-alpha-72` |
|
||||
| **激活页 ★** | `bg --heat / 字 --accent-white / 600 字重` |
|
||||
|
||||
#### 4.17.3 视图切换(`.view-toggle`)
|
||||
|
||||
```html
|
||||
<div class="view-toggle">
|
||||
<button class="active"><svg>grid</svg></button>
|
||||
<button><svg>list</svg></button>
|
||||
</div>
|
||||
```
|
||||
|
||||
| 元素 | 样式 |
|
||||
| ---- | ---- |
|
||||
| 容器 | `inline-flex / bg --surface / border 1px --border-faint / radius 4 / padding 2`(外壳 4,因子按钮 4) |
|
||||
| 按钮 | 30×28 / radius 4 / transparent / 字 `--black-alpha-48` |
|
||||
| hover | `bg --black-alpha-4 / 字 --accent-black` |
|
||||
| **激活 ★** | `bg --accent-black / 字 --accent-white`(**注意:不是橙**) |
|
||||
|
||||
> **为何用黑不用橙:** 视图切换是"显示模式开关",不是 CTA。黑表达"激活态"又不抢主橙的舞台。**同理:任何"模式切换"按钮组都用黑激活,不用橙。**
|
||||
|
||||
#### 4.17.4 操作型胶囊(`.pill-tip`)
|
||||
|
||||
```html
|
||||
<button class="pill-tip">→ 去商品库</button>
|
||||
```
|
||||
|
||||
- 高 28 / padding 0 14 / radius 999 / font 12 / weight 500
|
||||
- 默认:`bg --heat-12 / border 1px --heat-20 / 字 --heat`
|
||||
- hover:`bg --heat / 字 --accent-white / box-shadow var(--shadow-cta)`
|
||||
|
||||
**与 `.pill.info` 区别:** `.pill.info` 是状态徽标(静态展示),`.pill-tip` 是可点击操作(动态橙底反馈 · hover 升级到主 CTA 视觉)。
|
||||
|
||||
#### 4.17.5 卖点 / 编辑式列表(`.bullet-list`)
|
||||
|
||||
```html
|
||||
<ul class="bullet-list">
|
||||
<li class="bl-item">
|
||||
<span class="num">1</span>
|
||||
<span class="bl-text">100% 棉麻 · 透气吸汗</span>
|
||||
<button class="bl-x">×</button>
|
||||
</li>
|
||||
<li class="bl-item">
|
||||
<span class="num">2</span>
|
||||
<span class="bl-text">独家设计 · 限量 200 件</span>
|
||||
<button class="bl-x">×</button>
|
||||
</li>
|
||||
<li class="bl-add">
|
||||
<span class="num">+</span>
|
||||
<input class="bl-input" placeholder="添加卖点(Enter 确认)">
|
||||
</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
| 元素 | 样式 |
|
||||
| ---- | ---- |
|
||||
| 行 `.bl-item` | `flex gap 10 / padding 8 12 / bg --background-lighter / border 1px --border-faint / radius 8 / mb 6` |
|
||||
| 序号 `.num` | 22×22 / mono 11 / 700 / 字 `--heat` / `bg --surface / border 1px --border-faint / radius 4` |
|
||||
| `.bl-text` | 13.5 / `--accent-black` / `flex 1` |
|
||||
| `.bl-x` 删除 | 22×22 / 圆 · hover 时显示(默认 `opacity 0`)· hover 变红 |
|
||||
| **`.bl-add` 添加行 ★** | 同 `.bl-item` 但 `border-style: dashed / bg transparent` |
|
||||
| `.bl-add .num` | `bg transparent / border 1px dashed --heat-40 / 字 --heat`(显示 `+`) |
|
||||
| `.bl-input` | `height 24 / border 0 / bg transparent / outline none / 字 13` |
|
||||
|
||||
---
|
||||
|
||||
### §4.18 AI 生成结果卡(`.gen-card`)
|
||||
|
||||
> **来源:** AI 图片创作 / 视频创作 / 任何"输入提示词 → 多候选输出"场景。
|
||||
> **三个可变接口:** ① 图片比例 ② 悬浮按钮的功能 ③ 底部按钮的功能。**其他全部复用。**
|
||||
|
||||
#### 组件骨架
|
||||
|
||||
```html
|
||||
<div class="gen-card">
|
||||
<!-- ① Prompt 提示词行 -->
|
||||
<div class="gen-prompt">
|
||||
<svg class="quote"><!-- 16px " 引号 --></svg>
|
||||
<span class="text">一只穿着宇航服的橘猫,漂浮在霓虹色星云中,赛博朋克风</span>
|
||||
</div>
|
||||
|
||||
<!-- ② Meta chip 行(竖线分隔) -->
|
||||
<div class="gen-meta">
|
||||
<span class="m-item">流·Studio v2</span>
|
||||
<span class="m-sep">|</span>
|
||||
<span class="m-item">1:1</span>
|
||||
<span class="m-sep">|</span>
|
||||
<span class="m-item">1K · 2 天前</span>
|
||||
</div>
|
||||
|
||||
<!-- ③ 图片网格(N 张候选 · 比例由 --ratio 控制) -->
|
||||
<div class="gen-images" style="--cols:4; --ratio: 1/1">
|
||||
<div class="gen-image">
|
||||
<div class="placeholder"><span class="ph-frame">1:1 · #1</span></div>
|
||||
<!-- hover 浮层 · 右上按钮组 -->
|
||||
<div class="gen-image-actions">
|
||||
<button class="gen-img-btn" data-act="regen"><svg><!-- ↻ --></svg></button>
|
||||
<button class="gen-img-btn" data-act="dl"><svg><!-- ↓ --></svg></button>
|
||||
<button class="gen-img-btn" data-act="more"><svg><!-- ··· --></svg></button>
|
||||
</div>
|
||||
<!-- 点击反馈 · 中央 toast(默认 opacity 0) -->
|
||||
<div class="gen-image-feedback">
|
||||
<svg><!-- ✓ --></svg>
|
||||
<span>已添加到剪贴板</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- × N -->
|
||||
</div>
|
||||
|
||||
<!-- ④ 底部操作按钮行 -->
|
||||
<div class="gen-card-actions">
|
||||
<button class="btn btn-sm"><svg></svg>重新编辑</button>
|
||||
<button class="btn btn-sm"><svg></svg>再次生成</button>
|
||||
<button class="btn btn-sm btn-ghost"><svg></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### 关键 CSS
|
||||
|
||||
| 区域 | 样式 |
|
||||
| ---- | ---- |
|
||||
| 容器 `.gen-card` | `bg --surface / border 1px --border-faint / radius 8 / padding 16 / display flex column / gap 14` |
|
||||
| 选中态 `.gen-card.selected` | `border-color --heat`(可选 modifier) |
|
||||
| Prompt `.gen-prompt` | `flex align-start / gap 10 / padding 0 4` |
|
||||
| Prompt 引号 `svg.quote` | 16×16 / `--black-alpha-32` / margin-top 2 |
|
||||
| Prompt 文本 `.text` | 14 / 500 / `--accent-black` |
|
||||
| Meta 行 `.gen-meta` | `flex align-center / gap 8 / padding 0 4 / font 11.5 mono / 字 --black-alpha-48 / letter-spacing .04em` |
|
||||
| Meta 分隔 `.m-sep` | `--black-alpha-24`(直接用 `\|` 字符) |
|
||||
| 图片网格 `.gen-images` | `display grid / grid-template-columns repeat(var(--cols), 1fr) / gap 10` |
|
||||
| 单张图 `.gen-image` | `position relative / aspect-ratio var(--ratio) / radius 8 / overflow hidden / cursor pointer` |
|
||||
| 浮层按钮组 `.gen-image-actions` | `absolute / top 8 right 8 / flex gap 2 / bg --surface / border 1px --border-faint / radius 8 / padding 2 / opacity 0 / z-index 2 / shadow 0 2 8 rgba(0,0,0,.08)` · hover `.gen-image` 时 `opacity 1` |
|
||||
| 浮层按钮 `.gen-img-btn` | `28×28 / radius 6 / bg transparent / 字 --black-alpha-56 / border 0 / cursor pointer` · hover `bg --black-alpha-4 / 字 --accent-black` |
|
||||
| 中央反馈 `.gen-image-feedback` | `absolute / inset 0 / flex column center / gap 8 / bg rgba(38,38,38,.88) / 字 --accent-white / radius 8 / opacity 0 / transition opacity .2s / pointer-events none` |
|
||||
| 反馈触发态 `.gen-image.show-feedback .gen-image-feedback` | `opacity 1`(1.5 s 后 JS 移除) |
|
||||
| 反馈 icon | 20×20 / 白 SVG ✓ |
|
||||
| 反馈文字 | 12.5 / 500 / 白 |
|
||||
| 底部按钮行 `.gen-card-actions` | `flex gap 8 / padding-top 4` |
|
||||
|
||||
#### 三个可变接口
|
||||
|
||||
| 维度 | 怎么变 |
|
||||
| ---- | ------ |
|
||||
| **① 图片比例** | 改 `style="--ratio: 1/1"` 为 `9/16` `16/9` `4/5` `3/4` 等 · 同时可改 `--cols` 控制列数(4 张方图 4 列 / 2 张竖图 2 列) |
|
||||
| **② 悬浮按钮功能** | 改 `<button data-act="X">` 的 act 名 + icon SVG · 数量 1–4 个(超过 4 个合并到 ··· 弹出菜单) |
|
||||
| **③ 底部按钮功能** | `.gen-card-actions` 内放 `.btn.btn-sm` · 通常 1-2 个二级 + 1 个三级 ghost ··· · **不放主橙**(避免抢 prompt 视觉) |
|
||||
|
||||
#### 反馈 toast 触发 JS
|
||||
|
||||
```js
|
||||
img.addEventListener('click', () => {
|
||||
img.classList.add('show-feedback');
|
||||
setTimeout(() => img.classList.remove('show-feedback'), 1500);
|
||||
});
|
||||
```
|
||||
|
||||
#### 适用场景
|
||||
|
||||
- AI 图片创作(2-8 张候选图 · 1:1 或 9:16)
|
||||
- AI 视频创作(1-4 段候选视频 · 16:9 或 9:16 · 缩图用 video poster)
|
||||
- 模板生成结果(批量预览选择)
|
||||
- 任何"prompt 输入 → 多候选输出"流程
|
||||
|
||||
#### Don't
|
||||
|
||||
- ❌ **给每个图片单独写卡样式** — 用 `.gen-image` 通用
|
||||
- ❌ **悬浮按钮组放图片底部** — 永远右上(避免遮挡图片主体)
|
||||
- ❌ **用全局 toast 通知"已复制"** — 用本组件内的 `.gen-image-feedback`(就地反馈,用户不必转头看屏幕角落)
|
||||
- ❌ **把 prompt 文字截断省略** — 完整显示(它就是用户的输入 · 要看清)
|
||||
- ❌ **底部按钮做成主橙 primary** — 抢了 prompt 的视觉重心,用二级 `.btn` 即可
|
||||
|
||||
---
|
||||
|
||||
## §5 · Mono 装饰元素(品牌签名 · 不能丢)
|
||||
|
||||
> 方括号标签 / 双斜杠注释 / 中点连接 —— 这些是流·Studio 独有的"调试视图感",Firecrawl 没有,绝对保留。
|
||||
|
||||
| 用法 | 示例 |
|
||||
| ---- | ---- |
|
||||
| 方括号标签 | `[ 200 OK ]` `[ /v2 ]` `[ .MP4 · 9:16 ]` `[ STUDIO ]` `[ ALL · 12 ] →` |
|
||||
|
||||
@ -678,16 +678,16 @@
|
||||
<aside class="io-side">
|
||||
<div class="io-side-h">
|
||||
<button class="back-pill" type="button" onclick="history.length > 1 ? history.back() : location.href='asset-factory.html'" title="返回">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M15 18l-6-6 6-6"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15 18l-6-6 6-6"/></svg>
|
||||
<span>返回</span>
|
||||
</button>
|
||||
<button class="fold" type="button" title="折叠侧栏">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M9 3v18"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M9 3v18"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button class="io-new-conv" type="button" id="io-new-conv">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 113 3L7 19l-4 1 1-4z"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 113 3L7 19l-4 1 1-4z"/></svg>
|
||||
新对话
|
||||
</button>
|
||||
|
||||
@ -695,7 +695,7 @@
|
||||
<div class="io-conv-list" style="flex: 0 0 auto;">
|
||||
<div class="io-conv-item default active" data-default>
|
||||
<div class="thumb">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 16l5-5 4 4 3-3 6 6"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 16l5-5 4 4 3-3 6 6"/></svg>
|
||||
</div>
|
||||
<span class="nm">默认创作</span>
|
||||
</div>
|
||||
@ -713,7 +713,7 @@
|
||||
<div class="io-toolbar">
|
||||
<span class="spacer"></span>
|
||||
<button class="search-btn" type="button" title="搜索">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
</button>
|
||||
<button class="tb-chip" type="button">
|
||||
时间
|
||||
@ -737,7 +737,7 @@
|
||||
|
||||
<button class="io-jump-bottom" type="button" id="io-jump-bottom">
|
||||
回到底部
|
||||
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M4 6l4 4 4-4"/></svg>
|
||||
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 6l4 4 4-4"/></svg>
|
||||
</button>
|
||||
|
||||
<!-- 底部输入栏 -->
|
||||
@ -747,7 +747,7 @@
|
||||
<div class="io-input-top">
|
||||
<div class="io-input-refs" id="io-input-refs"></div>
|
||||
<button class="add-btn" type="button" id="io-add-btn" title="上传参考图">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg>
|
||||
</button>
|
||||
<input type="file" id="io-file-input" accept="image/*" multiple>
|
||||
</div>
|
||||
@ -803,7 +803,7 @@
|
||||
<div class="io-dup-modal">
|
||||
<div class="dh">
|
||||
<div class="ic">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 8v4M12 16h.01"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 8v4M12 16h.01"/></svg>
|
||||
</div>
|
||||
<div class="ti">
|
||||
<strong id="io-dup-title">图片已在资产库</strong>
|
||||
@ -1021,11 +1021,11 @@ Shell.render({
|
||||
convList.innerHTML = state.convs.map(c => `
|
||||
<div class="io-conv-item${state.activeConvId === c.id ? ' active' : ''}" data-id="${c.id}">
|
||||
<div class="thumb"${c.thumb ? ` style="background-image:url(${c.thumb})"` : ''}>
|
||||
${c.thumb ? '' : '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="M21 15l-5-5-9 9"/></svg>'}
|
||||
${c.thumb ? '' : '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="M21 15l-5-5-9 9"/></svg>'}
|
||||
</div>
|
||||
<span class="nm">${esc(c.title)}</span>
|
||||
<button class="del" type="button" data-del="${c.id}" title="删除">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
`).join('');
|
||||
@ -1078,7 +1078,7 @@ Shell.render({
|
||||
streamInner.innerHTML = `
|
||||
<div class="io-empty">
|
||||
<div class="ic">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3l1.7 4.6L18 9l-4.3 1.4L12 15l-1.7-4.6L6 9l4.3-1.4L12 3z"/><path d="M19 16l.85 2.3L22 19l-2.15.7L19 22l-.85-2.3L16 19l2.15-.7L19 16z"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3l1.7 4.6L18 9l-4.3 1.4L12 15l-1.7-4.6L6 9l4.3-1.4L12 3z"/><path d="M19 16l.85 2.3L22 19l-2.15.7L19 22l-.85-2.3L16 19l2.15-.7L19 16z"/></svg>
|
||||
</div>
|
||||
<div class="badge">// IMAGE STUDIO</div>
|
||||
<h2>开始你的创作</h2>
|
||||
@ -1113,18 +1113,18 @@ Shell.render({
|
||||
${r.status === 'ok' ? `
|
||||
<div class="cell-ops">
|
||||
<button type="button" data-act="cell-rerun" title="再次生成">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 11-3-6.7L21 8M21 3v5h-5"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 11-3-6.7L21 8M21 3v5h-5"/></svg>
|
||||
</button>
|
||||
<button type="button" data-act="dl" title="下载">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
|
||||
</button>
|
||||
<div class="cell-more-wrap">
|
||||
<button type="button" data-act="more" title="更多">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="5" cy="12" r="1.2"/><circle cx="12" cy="12" r="1.2"/><circle cx="19" cy="12" r="1.2"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="5" cy="12" r="1.2"/><circle cx="12" cy="12" r="1.2"/><circle cx="19" cy="12" r="1.2"/></svg>
|
||||
</button>
|
||||
<div class="cell-more-menu">
|
||||
<button type="button" data-act="save-lib"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21l-7-5-7 5V5a2 2 0 012-2h10a2 2 0 012 2z"/></svg>加入资产库</button>
|
||||
<button type="button" class="danger" data-act="cell-del"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>删除</button>
|
||||
<button type="button" data-act="save-lib"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21l-7-5-7 5V5a2 2 0 012-2h10a2 2 0 012 2z"/></svg>加入资产库</button>
|
||||
<button type="button" class="danger" data-act="cell-del"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>删除</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1156,24 +1156,24 @@ Shell.render({
|
||||
<div class="io-msg-grid">${cellsHTML}</div>
|
||||
<div class="io-msg-ops">
|
||||
<button type="button" data-act="edit" data-id="${m.id}">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 113 3L7 19l-4 1 1-4z"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 113 3L7 19l-4 1 1-4z"/></svg>
|
||||
重新编辑
|
||||
</button>
|
||||
<button type="button" data-act="rerun" data-id="${m.id}">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 11-3-6.7L21 8M21 3v5h-5"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 11-3-6.7L21 8M21 3v5h-5"/></svg>
|
||||
再次生成
|
||||
</button>
|
||||
<div class="msg-more-wrap">
|
||||
<button type="button" class="icon" data-act="msg-more" data-id="${m.id}" title="更多">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="5" cy="12" r="1.2"/><circle cx="12" cy="12" r="1.2"/><circle cx="19" cy="12" r="1.2"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="5" cy="12" r="1.2"/><circle cx="12" cy="12" r="1.2"/><circle cx="19" cy="12" r="1.2"/></svg>
|
||||
</button>
|
||||
<div class="msg-more-menu" role="menu">
|
||||
<button type="button" data-act="msg-save-all" data-id="${m.id}">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21H5a2 2 0 01-2-2V5a2 2 0 012-2h11l5 5v11a2 2 0 01-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21H5a2 2 0 01-2-2V5a2 2 0 012-2h11l5 5v11a2 2 0 01-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>
|
||||
全部加入资产库
|
||||
</button>
|
||||
<button type="button" class="danger" data-act="msg-del" data-id="${m.id}">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>
|
||||
删除该批结果
|
||||
</button>
|
||||
</div>
|
||||
@ -1500,7 +1500,7 @@ Shell.render({
|
||||
inputRefs.innerHTML = state.refImages.map(r => `
|
||||
<div class="io-input-ref" data-id="${r.id}">
|
||||
<img src="${r.dataUrl}" alt="">
|
||||
<button class="x" type="button"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 4l8 8M12 4l-8 8"/></svg></button>
|
||||
<button class="x" type="button"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M4 4l8 8M12 4l-8 8"/></svg></button>
|
||||
</div>
|
||||
`).join('');
|
||||
inputRefs.querySelectorAll('.x').forEach(b => {
|
||||
|
||||
@ -398,7 +398,7 @@
|
||||
<div class="asset-grid" data-tab="people" id="grid-people">
|
||||
<div class="asset-card" data-name="林夕" data-gender="女" data-age="青年" data-role="都市白领" data-source="AI 生成" data-used="4" data-added="20260513" onclick="Shell.toast('查看资产', '林夕')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">林夕 · 都市白领</span></div>
|
||||
<div class="asset-body">
|
||||
<div class="asset-name">林夕</div>
|
||||
@ -407,7 +407,7 @@
|
||||
</div>
|
||||
<div class="asset-card" data-name="阿楠" data-gender="女" data-age="青年" data-role="都市白领" data-source="AI 生成" data-used="2" data-added="20260507" onclick="Shell.toast('查看资产', '阿楠')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">阿楠 · 同事女</span></div>
|
||||
<div class="asset-body">
|
||||
<div class="asset-name">阿楠</div>
|
||||
@ -416,7 +416,7 @@
|
||||
</div>
|
||||
<div class="asset-card" data-name="小七" data-gender="女" data-age="青年" data-role="学生" data-source="AI 生成" data-used="3" data-added="20260512" onclick="Shell.toast('查看资产', '小七')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">小七 · 学生女</span></div>
|
||||
<div class="asset-body">
|
||||
<div class="asset-name">小七</div>
|
||||
@ -425,7 +425,7 @@
|
||||
</div>
|
||||
<div class="asset-card" data-name="阿杰" data-gender="男" data-age="青年" data-role="都市白领" data-source="AI 生成" data-used="2" data-added="20260428" onclick="Shell.toast('查看资产', '阿杰')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">阿杰 · 通勤男</span></div>
|
||||
<div class="asset-body">
|
||||
<div class="asset-name">阿杰</div>
|
||||
@ -434,14 +434,14 @@
|
||||
</div>
|
||||
<div class="asset-card" data-name="妈妈 · 王姐" data-gender="女" data-age="中年" data-role="居家" data-source="手动上传" data-triview="0" data-used="1" data-added="20260415" onclick="Shell.toast('查看资产', '王姐')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb">
|
||||
<span class="tri-missing-badge" tabindex="0" role="button" aria-label="缺三视图,查看说明">
|
||||
<span class="ico" aria-hidden="true"></span>
|
||||
<span class="lbl-mono">缺三视图</span>
|
||||
<span class="tri-missing-pop" role="tooltip">
|
||||
<span class="pop-h">
|
||||
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M12 9v4M12 17h.01"/><path d="M10.3 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/></svg>
|
||||
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 9v4M12 17h.01"/><path d="M10.3 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/></svg>
|
||||
MISSING TRI-VIEW
|
||||
</span>
|
||||
<span class="pop-body">手动上传的人物未生成 <b>正 / 侧 / 背</b> 三视图。直接进入图片或视频生成,人脸/服饰一致性可能下降。</span>
|
||||
@ -457,7 +457,7 @@
|
||||
</div>
|
||||
<div class="asset-card" data-name="阿强" data-gender="男" data-age="青年" data-role="健身" data-source="AI 生成" data-used="2" data-added="20260508" onclick="Shell.toast('查看资产', '阿强')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">阿强 · 健身男</span></div>
|
||||
<div class="asset-body">
|
||||
<div class="asset-name">阿强</div>
|
||||
@ -466,7 +466,7 @@
|
||||
</div>
|
||||
<div class="asset-card" data-name="小苏" data-gender="女" data-age="青年" data-role="文艺" data-source="AI 生成" data-used="1" data-added="20260420" onclick="Shell.toast('查看资产', '小苏')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">小苏 · 文艺女</span></div>
|
||||
<div class="asset-body">
|
||||
<div class="asset-name">小苏</div>
|
||||
@ -475,7 +475,7 @@
|
||||
</div>
|
||||
<div class="asset-card" data-name="闺蜜组合" data-gender="女" data-age="青年" data-role="都市白领" data-source="AI 生成" data-used="1" data-added="20260511" onclick="Shell.toast('查看资产', '闺蜜组合')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">闺蜜组合 · 双人</span></div>
|
||||
<div class="asset-body">
|
||||
<div class="asset-name">闺蜜组合</div>
|
||||
@ -484,7 +484,7 @@
|
||||
</div>
|
||||
<div class="asset-card" data-name="豆豆" data-gender="女" data-age="幼年" data-role="居家" data-source="AI 生成" data-used="2" data-added="20260509" onclick="Shell.toast('查看资产', '豆豆')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">豆豆 · 幼儿</span></div>
|
||||
<div class="asset-body">
|
||||
<div class="asset-name">豆豆</div>
|
||||
@ -493,7 +493,7 @@
|
||||
</div>
|
||||
<div class="asset-card" data-name="小宇" data-gender="男" data-age="少年" data-role="学生" data-source="AI 生成" data-used="1" data-added="20260502" onclick="Shell.toast('查看资产', '小宇')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">小宇 · 中学生</span></div>
|
||||
<div class="asset-body">
|
||||
<div class="asset-name">小宇</div>
|
||||
@ -502,14 +502,14 @@
|
||||
</div>
|
||||
<div class="asset-card" data-name="李爷爷" data-gender="男" data-age="老年" data-role="居家" data-source="手动上传" data-triview="0" data-used="1" data-added="20260418" onclick="Shell.toast('查看资产', '李爷爷')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb">
|
||||
<span class="tri-missing-badge" tabindex="0" role="button" aria-label="缺三视图,查看说明">
|
||||
<span class="ico" aria-hidden="true"></span>
|
||||
<span class="lbl-mono">缺三视图</span>
|
||||
<span class="tri-missing-pop" role="tooltip">
|
||||
<span class="pop-h">
|
||||
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M12 9v4M12 17h.01"/><path d="M10.3 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/></svg>
|
||||
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 9v4M12 17h.01"/><path d="M10.3 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/></svg>
|
||||
MISSING TRI-VIEW
|
||||
</span>
|
||||
<span class="pop-body">手动上传的人物未生成 <b>正 / 侧 / 背</b> 三视图。直接进入图片或视频生成,人脸/服饰一致性可能下降。</span>
|
||||
@ -529,73 +529,73 @@
|
||||
<div class="asset-grid" data-tab="scenes" id="grid-scenes" hidden>
|
||||
<div class="asset-card" data-name="卧室·暖光" data-scene-type="卧室" data-source="AI 生成" data-used="6" data-added="20260513" onclick="Shell.toast('查看资产', '卧室·暖光')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">卧室 · 暖光</span></div>
|
||||
<div class="asset-body"><div class="asset-name">卧室·暖光</div><div class="asset-meta">卧室 · AI 生成 · 用过 6 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="卧室·冷调" data-scene-type="卧室" data-source="AI 生成" data-used="3" data-added="20260507" onclick="Shell.toast('查看资产', '卧室·冷调')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">卧室 · 冷调</span></div>
|
||||
<div class="asset-body"><div class="asset-name">卧室·冷调</div><div class="asset-meta">卧室 · AI 生成 · 用过 3 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="浴室·梳妆台" data-scene-type="浴室" data-source="AI 生成" data-used="4" data-added="20260510" onclick="Shell.toast('查看资产', '浴室·梳妆台')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">浴室 · 梳妆台</span></div>
|
||||
<div class="asset-body"><div class="asset-name">浴室·梳妆台</div><div class="asset-meta">浴室 · AI 生成 · 用过 4 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="客厅·北欧" data-scene-type="客厅" data-source="AI 生成" data-used="5" data-added="20260512" onclick="Shell.toast('查看资产', '客厅·北欧')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">客厅 · 北欧</span></div>
|
||||
<div class="asset-body"><div class="asset-name">客厅·北欧</div><div class="asset-meta">客厅 · AI 生成 · 用过 5 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="客厅·中古" data-scene-type="客厅" data-source="手动上传" data-used="1" data-added="20260418" onclick="Shell.toast('查看资产', '客厅·中古')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">客厅 · 中古</span></div>
|
||||
<div class="asset-body"><div class="asset-name">客厅·中古</div><div class="asset-meta">客厅 · 手动上传 · 用过 1 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="厨房·中岛" data-scene-type="厨房" data-source="AI 生成" data-used="3" data-added="20260509" onclick="Shell.toast('查看资产', '厨房·中岛')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">厨房 · 中岛</span></div>
|
||||
<div class="asset-body"><div class="asset-name">厨房·中岛</div><div class="asset-meta">厨房 · AI 生成 · 用过 3 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="办公室·开放" data-scene-type="办公室" data-source="AI 生成" data-used="2" data-added="20260506" onclick="Shell.toast('查看资产', '办公室·开放')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">办公室 · 开放</span></div>
|
||||
<div class="asset-body"><div class="asset-name">办公室·开放</div><div class="asset-meta">办公室 · AI 生成 · 用过 2 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="办公室·会议室" data-scene-type="办公室" data-source="AI 生成" data-used="1" data-added="20260425" onclick="Shell.toast('查看资产', '办公室·会议室')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">办公室 · 会议室</span></div>
|
||||
<div class="asset-body"><div class="asset-name">办公室·会议室</div><div class="asset-meta">办公室 · AI 生成 · 用过 1 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="咖啡店·窗边" data-scene-type="咖啡店" data-source="AI 生成" data-used="4" data-added="20260511" onclick="Shell.toast('查看资产', '咖啡店·窗边')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">咖啡店 · 窗边</span></div>
|
||||
<div class="asset-body"><div class="asset-name">咖啡店·窗边</div><div class="asset-meta">咖啡店 · AI 生成 · 用过 4 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="街景·夜" data-scene-type="街景" data-source="AI 生成" data-used="2" data-added="20260430" onclick="Shell.toast('查看资产', '街景·夜')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">街景 · 夜</span></div>
|
||||
<div class="asset-body"><div class="asset-name">街景·夜</div><div class="asset-meta">街景 · AI 生成 · 用过 2 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="健身房·器械" data-scene-type="健身房" data-source="AI 生成" data-used="3" data-added="20260508" onclick="Shell.toast('查看资产', '健身房·器械')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">健身房 · 器械</span></div>
|
||||
<div class="asset-body"><div class="asset-name">健身房·器械</div><div class="asset-meta">健身房 · AI 生成 · 用过 3 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="街景·日" data-scene-type="街景" data-source="手动上传" data-used="1" data-added="20260422" onclick="Shell.toast('查看资产', '街景·日')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">街景 · 日</span></div>
|
||||
<div class="asset-body"><div class="asset-name">街景·日</div><div class="asset-meta">街景 · 手动上传 · 用过 1 次</div></div>
|
||||
</div>
|
||||
@ -605,73 +605,73 @@
|
||||
<div class="asset-grid" data-tab="products" id="grid-products" hidden>
|
||||
<div class="asset-card" data-name="补水面膜 · 主图" data-product="透真补水面膜" data-source="商品库引用" data-used="5" data-added="20260513" onclick="Shell.toast('查看资产', '补水面膜 主图')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">补水面膜 · 主图</span></div>
|
||||
<div class="asset-body"><div class="asset-name">补水面膜 · 主图</div><div class="asset-meta">透真补水面膜 · 库引用 · 用过 5 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="补水面膜 · AI 优化" data-product="透真补水面膜" data-source="AI 优化" data-used="3" data-added="20260513" onclick="Shell.toast('查看资产', '补水面膜 AI 优化')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">补水面膜 · AI 优化</span></div>
|
||||
<div class="asset-body"><div class="asset-name">补水面膜 · AI 优化</div><div class="asset-meta">透真补水面膜 · AI 优化 · 用过 3 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="蓝牙耳机 · 主图" data-product="南卡 Lite Pro" data-source="商品库引用" data-used="4" data-added="20260507" onclick="Shell.toast('查看资产', '蓝牙耳机 主图')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">蓝牙耳机 · 主图</span></div>
|
||||
<div class="asset-body"><div class="asset-name">蓝牙耳机 · 主图</div><div class="asset-meta">南卡 Lite Pro · 库引用 · 用过 4 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="蓝牙耳机 · 场景图" data-product="南卡 Lite Pro" data-source="手动上传" data-used="1" data-added="20260507" onclick="Shell.toast('查看资产', '蓝牙耳机 场景')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">蓝牙耳机 · 场景</span></div>
|
||||
<div class="asset-body"><div class="asset-name">蓝牙耳机 · 场景图</div><div class="asset-meta">南卡 Lite Pro · 手动上传 · 用过 1 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="速食面 · 主图" data-product="滋啦速食" data-source="商品库引用" data-used="3" data-added="20260512" onclick="Shell.toast('查看资产', '速食面 主图')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">速食面 · 主图</span></div>
|
||||
<div class="asset-body"><div class="asset-name">速食面 · 主图</div><div class="asset-meta">滋啦速食 · 库引用 · 用过 3 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="速食面 · 加汤" data-product="滋啦速食" data-source="AI 优化" data-used="2" data-added="20260512" onclick="Shell.toast('查看资产', '速食面 加汤')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">速食面 · 加汤</span></div>
|
||||
<div class="asset-body"><div class="asset-name">速食面 · 加汤</div><div class="asset-meta">滋啦速食 · AI 优化 · 用过 2 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="防晒霜 · 主图" data-product="透真防晒霜" data-source="商品库引用" data-used="4" data-added="20260510" onclick="Shell.toast('查看资产', '防晒霜 主图')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">防晒霜 · 主图</span></div>
|
||||
<div class="asset-body"><div class="asset-name">防晒霜 · 主图</div><div class="asset-meta">透真防晒霜 · 库引用 · 用过 4 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="防晒霜 · AI 优化" data-product="透真防晒霜" data-source="AI 优化" data-used="3" data-added="20260510" onclick="Shell.toast('查看资产', '防晒霜 优化')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">防晒霜 · AI 优化</span></div>
|
||||
<div class="asset-body"><div class="asset-name">防晒霜 · AI 优化</div><div class="asset-meta">透真防晒霜 · AI 优化 · 用过 3 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="咖啡冻干 · 主图" data-product="三顿半同款" data-source="商品库引用" data-used="3" data-added="20260509" onclick="Shell.toast('查看资产', '咖啡冻干 主图')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">咖啡冻干 · 主图</span></div>
|
||||
<div class="asset-body"><div class="asset-name">咖啡冻干 · 主图</div><div class="asset-meta">三顿半同款 · 库引用 · 用过 3 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="咖啡冻干 · 24 颗" data-product="三顿半同款" data-source="商品库引用" data-used="2" data-added="20260509" onclick="Shell.toast('查看资产', '咖啡冻干 24 颗')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">咖啡冻干 · 24 颗</span></div>
|
||||
<div class="asset-body"><div class="asset-name">咖啡冻干 · 24 颗</div><div class="asset-meta">三顿半同款 · 库引用 · 用过 2 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="空气炸锅 · 主图" data-product="小熊 4L 空气炸锅" data-source="商品库引用" data-used="2" data-added="20260504" onclick="Shell.toast('查看资产', '空气炸锅 主图')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">空气炸锅 · 主图</span></div>
|
||||
<div class="asset-body"><div class="asset-name">空气炸锅 · 主图</div><div class="asset-meta">小熊 4L · 库引用 · 用过 2 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="瑜伽裤 · 模特图" data-product="露露同款瑜伽裤" data-source="手动上传" data-used="3" data-added="20260506" onclick="Shell.toast('查看资产', '瑜伽裤 模特')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">瑜伽裤 · 模特</span></div>
|
||||
<div class="asset-body"><div class="asset-name">瑜伽裤 · 模特图</div><div class="asset-meta">露露同款瑜伽裤 · 手动上传 · 用过 3 次</div></div>
|
||||
</div>
|
||||
@ -681,49 +681,49 @@
|
||||
<div class="asset-grid video-grid" data-tab="finals" id="grid-finals" hidden>
|
||||
<div class="asset-card video" data-name="蓝牙耳机 · 开箱测评" data-project="蓝牙耳机 · 开箱测评" data-duration="60s" data-used="3" data-added="20260507" onclick="Shell.toast('打开成片', '蓝牙耳机 · 开箱测评')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">9:16 · 60s</span></div>
|
||||
<div class="asset-body"><div class="asset-name">蓝牙耳机 · 开箱测评</div><div class="asset-meta">南卡 Lite Pro · 60s · 5 月 7 日</div></div>
|
||||
</div>
|
||||
<div class="asset-card video" data-name="瑜伽裤 · 通勤穿搭" data-project="瑜伽裤 · 通勤穿搭" data-duration="45s" data-used="2" data-added="20260506" onclick="Shell.toast('打开成片', '瑜伽裤 · 通勤穿搭')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">9:16 · 45s</span></div>
|
||||
<div class="asset-body"><div class="asset-name">瑜伽裤 · 通勤穿搭</div><div class="asset-meta">露露同款 · 45s · 5 月 6 日</div></div>
|
||||
</div>
|
||||
<div class="asset-card video" data-name="空气炸锅 · 小户型" data-project="空气炸锅 · 小户型" data-duration="30s" data-used="2" data-added="20260504" onclick="Shell.toast('打开成片', '空气炸锅 · 小户型')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">9:16 · 30s</span></div>
|
||||
<div class="asset-body"><div class="asset-name">空气炸锅 · 小户型</div><div class="asset-meta">小熊 4L · 30s · 5 月 4 日</div></div>
|
||||
</div>
|
||||
<div class="asset-card video" data-name="补水面膜 · 痛点种草 v1" data-project="补水面膜 · 痛点种草 v1" data-duration="60s" data-used="2" data-added="20260428" onclick="Shell.toast('打开成片', '补水面膜 v1')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">9:16 · 60s</span></div>
|
||||
<div class="asset-body"><div class="asset-name">补水面膜 · 痛点种草 v1</div><div class="asset-meta">透真补水面膜 · 60s · 4 月 28 日</div></div>
|
||||
</div>
|
||||
<div class="asset-card video" data-name="防晒霜 · 通勤对比" data-project="防晒霜 · 通勤对比" data-duration="60s" data-used="1" data-added="20260425" onclick="Shell.toast('打开成片', '防晒霜 · 通勤对比')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">9:16 · 60s</span></div>
|
||||
<div class="asset-body"><div class="asset-name">防晒霜 · 通勤对比</div><div class="asset-meta">透真防晒霜 · 60s · 4 月 25 日</div></div>
|
||||
</div>
|
||||
<div class="asset-card video" data-name="速食面 · 加班治愈" data-project="速食面 · 加班治愈" data-duration="30s" data-used="1" data-added="20260420" onclick="Shell.toast('打开成片', '速食面 · 加班治愈')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">9:16 · 30s</span></div>
|
||||
<div class="asset-body"><div class="asset-name">速食面 · 加班治愈</div><div class="asset-meta">滋啦速食 · 30s · 4 月 20 日</div></div>
|
||||
</div>
|
||||
<div class="asset-card video" data-name="咖啡 · 早八剧情" data-project="咖啡 · 早八剧情" data-duration="45s" data-used="2" data-added="20260418" onclick="Shell.toast('打开成片', '咖啡 · 早八剧情')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">9:16 · 45s</span></div>
|
||||
<div class="asset-body"><div class="asset-name">咖啡 · 早八剧情</div><div class="asset-meta">三顿半同款 · 45s · 4 月 18 日</div></div>
|
||||
</div>
|
||||
<div class="asset-card video" data-name="收纳 · 北欧" data-project="收纳 · 北欧" data-duration="15s" data-used="1" data-added="20260410" onclick="Shell.toast('打开成片', '收纳 · 北欧')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">9:16 · 15s</span></div>
|
||||
<div class="asset-body"><div class="asset-name">收纳 · 北欧</div><div class="asset-meta">家居好物 · 15s · 4 月 10 日</div></div>
|
||||
</div>
|
||||
@ -733,19 +733,19 @@
|
||||
<div class="asset-grid" data-tab="uploads" id="grid-uploads" hidden>
|
||||
<div class="asset-card" data-name="林夕 · 主播照" data-kind="人物" data-source="手动上传" data-used="4" data-added="20260513" onclick="Shell.toast('查看资产', '林夕 · 主播照')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">林夕 · 主播照</span></div>
|
||||
<div class="asset-body"><div class="asset-name">林夕 · 主播照</div><div class="asset-meta">人物 · 手动上传 · 用过 4 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="卧室 · 实拍" data-kind="场景" data-source="手动上传" data-used="2" data-added="20260510" onclick="Shell.toast('查看资产', '卧室 · 实拍')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">卧室 · 实拍</span></div>
|
||||
<div class="asset-body"><div class="asset-name">卧室 · 实拍</div><div class="asset-meta">场景 · 手动上传 · 用过 2 次</div></div>
|
||||
</div>
|
||||
<div class="asset-card" data-name="防晒霜 · 官方图" data-kind="商品" data-source="手动上传" data-used="3" data-added="20260507" onclick="Shell.toast('查看资产', '防晒霜 · 官方图')">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">防晒霜 · 官方图</span></div>
|
||||
<div class="asset-body"><div class="asset-name">防晒霜 · 官方图</div><div class="asset-meta">商品 · 手动上传 · 用过 3 次</div></div>
|
||||
</div>
|
||||
@ -814,7 +814,7 @@
|
||||
<img id="upload-preview-img" alt="预览">
|
||||
<video id="upload-preview-video" controls hidden></video>
|
||||
<button class="preview-x" type="button" id="upload-preview-x" aria-label="移除">
|
||||
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 4l8 8M12 4l-8 8"/></svg>
|
||||
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M4 4l8 8M12 4l-8 8"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -904,7 +904,7 @@
|
||||
<span class="corner-bl" aria-hidden></span>
|
||||
<div class="modal-h">
|
||||
<div class="ic-m" style="background:var(--crimson-bg,#fdebea);color:var(--accent-crimson,#c43d3d)">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>
|
||||
</div>
|
||||
<div class="ti">确认删除资产<span>// CONFIRM DELETE</span></div>
|
||||
</div>
|
||||
@ -912,7 +912,7 @@
|
||||
<div class="modal-f" id="del-confirm-foot">
|
||||
<button class="btn" type="button" id="del-confirm-cancel">取消</button>
|
||||
<button class="btn" type="button" id="del-confirm-ok" style="background:var(--accent-crimson,#c43d3d);color:var(--accent-white);border-color:var(--accent-crimson,#c43d3d)">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/></svg>
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/></svg>
|
||||
确认删除
|
||||
</button>
|
||||
</div>
|
||||
@ -925,14 +925,14 @@
|
||||
<button class="clear-sel" type="button" id="bulk-clear">清空</button>
|
||||
<span class="sep"></span>
|
||||
<button class="danger" type="button" id="bulk-del">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>
|
||||
删除所选
|
||||
</button>
|
||||
<div class="move-wrap">
|
||||
<button type="button" id="bulk-move">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/><path d="M3 12h12"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18l6-6-6-6"/><path d="M3 12h12"/></svg>
|
||||
移动到
|
||||
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" style="margin-left:2px"><path d="M4 10l4-4 4 4"/></svg>
|
||||
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="margin-left:2px"><path d="M4 10l4-4 4 4"/></svg>
|
||||
</button>
|
||||
<div class="move-menu" id="bulk-move-menu"></div>
|
||||
</div>
|
||||
@ -945,7 +945,7 @@ Shell.render({ active: 'library', crumbs: [{ label: '工作台', href: 'index.ht
|
||||
|
||||
/* ─── 给所有资产卡注入下载按钮 · PRD §6.5 所有中间产物可下载 ─── */
|
||||
(function injectDownloadBtns() {
|
||||
const dlSvg = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>';
|
||||
const dlSvg = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>';
|
||||
document.querySelectorAll('.asset-card').forEach(card => {
|
||||
if (card.querySelector('.card-dl-btn')) return;
|
||||
const btn = document.createElement('button');
|
||||
@ -995,7 +995,7 @@ const TAB_KEYS = ['people', 'scenes', 'products', 'finals', 'uploads', 'unclassi
|
||||
card.dataset.libId = it.id || '';
|
||||
card.innerHTML = `
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除资产" onclick="event.stopPropagation();" data-action="delete-asset"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder asset-thumb"><span class="ph-frame">${esc(it.name || '未命名')}</span></div>
|
||||
<div class="asset-body">
|
||||
<div class="asset-name">${esc(it.name || '未命名')}</div>
|
||||
@ -1262,14 +1262,14 @@ function renderPagination(totalVisible, totalPages) {
|
||||
const list = document.getElementById('page-list');
|
||||
const items = pageNumberList(state.page, totalPages);
|
||||
let html = `<button type="button" data-page="prev" ${state.page <= 1 ? 'disabled' : ''} aria-label="上一页">
|
||||
<svg width="11" height="11" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M10 12L6 8l4-4"/></svg>
|
||||
<svg width="11" height="11" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10 12L6 8l4-4"/></svg>
|
||||
</button>`;
|
||||
items.forEach(p => {
|
||||
if (p === '…') html += `<span class="ellipsis">…</span>`;
|
||||
else html += `<button type="button" data-page="${p}" ${p === state.page ? 'class="active"' : ''}>${p}</button>`;
|
||||
});
|
||||
html += `<button type="button" data-page="next" ${state.page >= totalPages ? 'disabled' : ''} aria-label="下一页">
|
||||
<svg width="11" height="11" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M6 4l4 4-4 4"/></svg>
|
||||
<svg width="11" height="11" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 4l4 4-4 4"/></svg>
|
||||
</button>`;
|
||||
list.innerHTML = html;
|
||||
}
|
||||
@ -1894,7 +1894,7 @@ function renderMoveMenu() {
|
||||
bulkMoveMenu.innerHTML = TAB_KEYS
|
||||
.filter(t => t !== cur)
|
||||
.map(t => `<button class="mv-item" type="button" data-target="${t}">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
|
||||
移到「${TAB_NAMES[t]}」
|
||||
</button>`).join('');
|
||||
bulkMoveMenu.querySelectorAll('.mv-item').forEach(btn => {
|
||||
@ -1988,9 +1988,13 @@ document.querySelectorAll('.asset-card').forEach(card => {
|
||||
.asset-detail-lead { display: flex; flex-direction: column; gap: 10px; }
|
||||
.asset-detail-lead .ad-lead-wrap { position: relative; }
|
||||
.asset-detail-lead .placeholder.ad-lead-img { aspect-ratio: 3/4; border-radius: var(--r-md); }
|
||||
.asset-detail-lead .ad-zoom-btn { position: absolute; right: 10px; bottom: 10px; height: 28px; padding: 0 12px; background: rgba(21,20,15,.7); color: #fff; border: 0; border-radius: var(--r-pill); display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px; font-family: inherit; cursor: pointer; }
|
||||
.asset-detail-lead .ad-zoom-btn:hover { background: rgba(21,20,15,.9); }
|
||||
.asset-detail-lead .ad-zoom-btn svg { width: 12px; height: 12px; }
|
||||
/* 查看大图 icon · 悬浮容器才显示 · 32×32 icon-only */
|
||||
.ad-zoom-btn { position: absolute; right: 8px; bottom: 8px; width: 32px; height: 32px; padding: 0; background: rgba(21,20,15,.7); color: #fff; border: 0; border-radius: var(--r-sm); display: grid; place-items: center; cursor: pointer; backdrop-filter: blur(4px); opacity: 0; transition: opacity var(--t-base), background var(--t-base); z-index: 3; }
|
||||
.ad-zoom-btn:hover { background: rgba(21,20,15,.92); }
|
||||
.ad-zoom-btn svg { width: 14px; height: 14px; }
|
||||
.asset-detail-lead .ad-lead-wrap:hover .ad-zoom-btn,
|
||||
.asset-detail-tri-row .placeholder:hover .ad-zoom-btn { opacity: 1; }
|
||||
.asset-detail-tri-row .placeholder { position: relative; }
|
||||
.asset-detail-lead .ad-thumbs { display: flex; gap: 8px; }
|
||||
.asset-detail-lead .ad-thumbs .thumb { flex: 0 0 64px; aspect-ratio: 3/4; border-radius: var(--r-sm); border: 1px solid var(--border-faint); cursor: pointer; overflow: hidden; }
|
||||
.asset-detail-lead .ad-thumbs .thumb:hover { border-color: var(--heat-40); }
|
||||
@ -2019,13 +2023,38 @@ document.querySelectorAll('.asset-card').forEach(card => {
|
||||
.ad-props .ad-prop .v { color: var(--accent-black); font-weight: 500; word-break: break-all; }
|
||||
.asset-detail-tip { margin-top: 10px; padding: 10px 12px; background: var(--heat-12); border: 1px solid var(--heat-20); border-radius: var(--r-sm); font-size: 12px; color: var(--accent-black); display: flex; align-items: center; gap: 8px; line-height: 1.5; }
|
||||
.asset-detail-tip svg { width: 14px; height: 14px; color: var(--heat); flex-shrink: 0; }
|
||||
.asset-detail-tip .ai-gen-btn { margin-left: auto; height: 26px; padding: 0 10px; background: var(--heat); color: #fff; border: 1px solid var(--heat); border-radius: var(--r-sm); font-size: 11.5px; cursor: pointer; font-family: inherit; flex-shrink: 0; }
|
||||
.asset-detail-tip .ai-gen-btn { margin-left: auto; height: 26px; padding: 0 10px; background: var(--heat); color: #fff; border: 1px solid var(--heat); border-radius: var(--r-sm); font-size: 11.5px; cursor: pointer; font-family: inherit; flex-shrink: 0; display: inline-flex; align-items: center; }
|
||||
.asset-detail-tip .ai-gen-btn:disabled { opacity: .55; cursor: not-allowed; }
|
||||
.asset-detail-tip.is-loading svg { animation: ad-spin 1s linear infinite; }
|
||||
@keyframes ad-spin { to { transform: rotate(360deg); } }
|
||||
.asset-detail-history { margin-top: 10px; padding: 10px 12px; background: var(--background-lighter); border: 1px solid var(--border-faint); border-radius: var(--r-sm); }
|
||||
.asset-detail-history .adh-h { font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-56); margin-bottom: 8px; letter-spacing: .02em; }
|
||||
.asset-detail-history .adh-h .adh-cur { color: var(--heat); }
|
||||
.asset-detail-history .adh-row { display: flex; gap: 8px; flex-wrap: wrap; }
|
||||
.asset-detail-history .adh-thumb { width: 64px; height: 36px; border-radius: var(--r-sm); background: var(--background-base); border: 1px solid var(--border-faint); display: grid; place-items: center; font-family: var(--font-mono); font-size: 11px; color: var(--black-alpha-72); cursor: pointer; position: relative; transition: border-color var(--t-base), color var(--t-base); }
|
||||
.asset-detail-history .adh-thumb:hover { border-color: var(--heat-40); color: var(--heat); }
|
||||
.asset-detail-history .adh-thumb.active { border-color: var(--heat); color: var(--heat); background: var(--heat-12); }
|
||||
.asset-detail-history .adh-thumb.active::after { content: ""; position: absolute; top: -3px; right: -3px; width: 8px; height: 8px; background: var(--heat); border: 2px solid var(--surface); border-radius: 50%; }
|
||||
.asset-modal-f { padding: 14px 20px; border-top: 1px solid var(--border-faint); display: flex; align-items: center; gap: 8px; }
|
||||
.asset-modal-f .ad-foot-stats { display: flex; gap: 6px; margin-right: auto; }
|
||||
.asset-modal-f .ad-stat-btn { height: 32px; padding: 0 12px; display: inline-flex; align-items: center; gap: 6px; background: transparent; border: 1px solid var(--border-faint); border-radius: var(--r-sm); color: var(--black-alpha-72); font-size: 12.5px; font-family: inherit; cursor: pointer; }
|
||||
.asset-modal-f .ad-stat-btn:hover { background: var(--background-lighter); color: var(--accent-black); border-color: var(--black-alpha-24); }
|
||||
.asset-modal-f .ad-stat-btn svg { width: 13px; height: 13px; }
|
||||
.asset-modal-f .ad-stat-btn b { color: var(--accent-black); font-weight: 600; }
|
||||
/* ── 缺保存 · 二次确认弹窗(模仿 model-photo .mc-leave) ── */
|
||||
.lib-confirm-bg { position: fixed; inset: 0; z-index: 1300; background: rgba(21,20,15,.42); display: none; align-items: center; justify-content: center; padding: 40px; }
|
||||
.lib-confirm-bg.show { display: flex; }
|
||||
.lib-confirm { background: var(--surface); border: 1px solid var(--border-faint); border-radius: var(--r-md); width: 440px; max-width: 92vw; box-shadow: 0 24px 64px rgba(0,0,0,.16); overflow: hidden; }
|
||||
.lib-confirm .lc-h { display: flex; align-items: center; gap: 10px; padding: 14px 20px 10px; }
|
||||
.lib-confirm .lc-h .ic { width: 28px; height: 28px; display: grid; place-items: center; background: var(--heat-12); color: var(--heat); border-radius: var(--r-sm); flex-shrink: 0; }
|
||||
.lib-confirm .lc-h .ic svg { width: 16px; height: 16px; }
|
||||
.lib-confirm .lc-h h3 { font-size: 15px; font-weight: 600; color: var(--accent-black); margin: 0; }
|
||||
.lib-confirm .lc-h .mono { margin-left: auto; font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); letter-spacing: .04em; }
|
||||
.lib-confirm .lc-b { padding: 4px 20px 18px; font-size: 13px; line-height: 1.65; color: var(--black-alpha-72); }
|
||||
.lib-confirm .lc-b b { color: var(--accent-black); font-weight: 600; }
|
||||
.lib-confirm .lc-f { display: flex; align-items: center; gap: 8px; padding: 12px 20px; border-top: 1px solid var(--border-faint); background: var(--background-lighter); }
|
||||
.lib-confirm .lc-f .spacer { flex: 1; }
|
||||
.lib-confirm .lc-f .btn { height: 34px; padding: 0 14px; font-size: 13px; }
|
||||
`;
|
||||
const style = document.createElement('style');
|
||||
style.textContent = css;
|
||||
@ -2044,9 +2073,8 @@ document.querySelectorAll('.asset-card').forEach(card => {
|
||||
<div class="asset-detail-lead">
|
||||
<div class="ad-lead-wrap">
|
||||
<div class="placeholder ad-lead-img" id="lib-detail-lead-img"><span class="ph-frame">立绘 / 主图</span></div>
|
||||
<button class="ad-zoom-btn" type="button">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 8V3h5M16 3h5v5M21 16v5h-5M8 21H3v-5"/></svg>
|
||||
查看大图
|
||||
<button class="ad-zoom-btn" type="button" id="lib-detail-lead-zoom" aria-label="查看大图" title="查看大图">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 8V3h5M16 3h5v5M21 16v5h-5M8 21H3v-5"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="ad-thumbs" id="lib-detail-thumbs"></div>
|
||||
@ -2054,23 +2082,30 @@ document.querySelectorAll('.asset-card').forEach(card => {
|
||||
<div class="asset-detail-right">
|
||||
<div class="ad-section" id="lib-detail-tri-section">
|
||||
<div class="asset-detail-section-h">
|
||||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg></span>
|
||||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg></span>
|
||||
<span class="t">三视图</span>
|
||||
<span class="ad-ratio-chip" id="lib-detail-ratio">16:9</span>
|
||||
<button class="ad-icon-btn" type="button" title="下载"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg></button>
|
||||
<button class="ad-icon-btn" type="button" title="下载"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg></button>
|
||||
</div>
|
||||
<div class="asset-detail-tri-row" id="lib-detail-tri">
|
||||
<div class="placeholder"><span class="ph-frame">正 / 侧 / 背 · 三视图</span></div>
|
||||
</div>
|
||||
<div class="asset-detail-tip" id="lib-detail-tip" style="display:none;">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 8v4M12 16h.01"/></svg>
|
||||
<span>暂无三视图,建议用 AI 生成以保证多角度一致性</span>
|
||||
<button class="ai-gen-btn" type="button" id="lib-detail-aigen">AI 生成三视图</button>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 8v4M12 16h.01"/></svg>
|
||||
<span id="lib-detail-tip-text">暂无三视图,建议用 AI 生成以保证多角度一致性</span>
|
||||
<button class="ai-gen-btn" type="button" id="lib-detail-aigen">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="width:11px;height:11px;display:inline-block;vertical-align:-1px;margin-right:3px;"><path d="M12 3l1.8 4.2L18 9l-4.2 1.8L12 15l-1.8-4.2L6 9l4.2-1.8L12 3z"/></svg>
|
||||
<span id="lib-detail-aigen-label">AI 生成三视图</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="asset-detail-history" id="lib-detail-history" style="display:none;">
|
||||
<div class="adh-h">// 三视图版本 · <span class="adh-ct" id="lib-detail-history-count">0</span> 版 · <span class="adh-cur" id="lib-detail-history-cur">v1</span></div>
|
||||
<div class="adh-row" id="lib-detail-history-row"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ad-section">
|
||||
<div class="asset-detail-section-h">
|
||||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 6h16M4 12h16M4 18h10"/></svg></span>
|
||||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 6h16M4 12h16M4 18h10"/></svg></span>
|
||||
<span class="t">简介</span>
|
||||
</div>
|
||||
<p class="ad-intro" id="lib-detail-intro"></p>
|
||||
@ -2083,11 +2118,30 @@ document.querySelectorAll('.asset-card').forEach(card => {
|
||||
<div class="asset-modal-f">
|
||||
<div class="ad-foot-stats">
|
||||
<button class="ad-stat-btn" type="button">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
|
||||
下载
|
||||
</button>
|
||||
</div>
|
||||
<button class="btn btn-primary" type="button" id="lib-detail-apply">使用该资产</button>
|
||||
<button class="btn btn-primary" type="button" id="lib-detail-apply">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lib-confirm-bg" id="lib-confirm-bg" aria-hidden="true">
|
||||
<div class="lib-confirm" role="dialog" aria-modal="true" aria-labelledby="lib-confirm-title">
|
||||
<div class="lc-h">
|
||||
<span class="ic">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 9v4M12 17h.01M10.3 3.86l-8.18 14.18A2 2 0 0 0 3.84 21h16.32a2 2 0 0 0 1.72-2.96L13.7 3.86a2 2 0 0 0-3.4 0z"/></svg>
|
||||
</span>
|
||||
<h3 id="lib-confirm-title">三视图尚未保存</h3>
|
||||
<span class="mono">// UNSAVED</span>
|
||||
</div>
|
||||
<div class="lc-b" id="lib-confirm-body">
|
||||
已生成 <b id="lib-confirm-count">1</b> 版三视图但<b>尚未保存</b>。直接退出会丢失这些版本,且当前资产仍标记为「<b>缺三视图</b>」。
|
||||
</div>
|
||||
<div class="lc-f">
|
||||
<span class="spacer"></span>
|
||||
<button class="btn" type="button" id="lib-confirm-discard">退出</button>
|
||||
<button class="btn btn-primary" type="button" id="lib-confirm-save">保存并退出</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
@ -2105,6 +2159,86 @@ document.querySelectorAll('.asset-card').forEach(card => {
|
||||
const tagsEl = document.getElementById('lib-detail-tags');
|
||||
const propsEl = document.getElementById('lib-detail-props');
|
||||
const tipEl = document.getElementById('lib-detail-tip');
|
||||
const tipTextEl = document.getElementById('lib-detail-tip-text');
|
||||
const aigenBtn = document.getElementById('lib-detail-aigen');
|
||||
const aigenLabel = document.getElementById('lib-detail-aigen-label');
|
||||
const historyEl = document.getElementById('lib-detail-history');
|
||||
const historyRowEl = document.getElementById('lib-detail-history-row');
|
||||
const historyCountEl = document.getElementById('lib-detail-history-count');
|
||||
const historyCurEl = document.getElementById('lib-detail-history-cur');
|
||||
const applyBtn = document.getElementById('lib-detail-apply');
|
||||
|
||||
// 当前打开资产的状态(仅 isActor + missing tri 时启用)
|
||||
let _curCard = null;
|
||||
let _curName = '';
|
||||
let _versions = []; // [{ ts, label }]
|
||||
let _curIdx = -1;
|
||||
let _dirty = false; // 已生成但未保存
|
||||
let _generating = false;
|
||||
let _allowGen = false; // 是否启用生成入口(missing tri-view 才启用)
|
||||
|
||||
function _renderHistory() {
|
||||
if (!_versions.length) { historyEl.style.display = 'none'; return; }
|
||||
historyEl.style.display = 'block';
|
||||
historyCountEl.textContent = _versions.length;
|
||||
historyCurEl.textContent = _versions[_curIdx]?.label || '';
|
||||
historyRowEl.innerHTML = _versions.map((v, i) =>
|
||||
'<div class="adh-thumb' + (i === _curIdx ? ' active' : '') + '" data-idx="' + i + '" title="' + v.label + ' · ' + v.ts + '">' + v.label + '</div>'
|
||||
).join('');
|
||||
historyRowEl.querySelectorAll('.adh-thumb').forEach(el => {
|
||||
el.addEventListener('click', () => {
|
||||
const i = Number(el.dataset.idx);
|
||||
if (i === _curIdx) return;
|
||||
_curIdx = i;
|
||||
_renderTriPreview();
|
||||
_renderHistory();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function _renderTriPreview() {
|
||||
if (_curIdx < 0) return;
|
||||
const ver = _versions[_curIdx];
|
||||
triEl.innerHTML = '<div class="placeholder"><span class="ph-frame">' + _curName + ' · 三视图(正/侧/背)· ' + ver.label + '</span><button class="ad-zoom-btn" type="button" data-zoom-tri aria-label="查看大图" title="查看大图"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 8V3h5M16 3h5v5M21 16v5h-5M8 21H3v-5"/></svg></button></div>';
|
||||
triEl.querySelector('[data-zoom-tri]')?.addEventListener('click', e => {
|
||||
e.stopPropagation();
|
||||
if (window.Shell?._openLightbox) Shell._openLightbox('', _curName + ' · 三视图 · ' + ver.label);
|
||||
});
|
||||
}
|
||||
|
||||
function _renderTriLoading() {
|
||||
triEl.innerHTML = '<div class="placeholder" style="display:grid;place-items:center;gap:6px;"><div class="spinner" style="width:22px;height:22px;border:2px solid var(--border-faint);border-top-color:var(--heat);border-radius:50%;animation:ad-spin 1s linear infinite;"></div><span class="ph-frame" style="font-size:10.5px;">生成中 · 约 12s</span></div>';
|
||||
}
|
||||
|
||||
function _setAigenLabel(text, loading) {
|
||||
aigenLabel.textContent = text;
|
||||
aigenBtn.disabled = !!loading;
|
||||
tipEl.classList.toggle('is-loading', !!loading);
|
||||
}
|
||||
|
||||
function _startGenerate() {
|
||||
if (!_allowGen || _generating) return;
|
||||
_generating = true;
|
||||
_setAigenLabel(_versions.length ? '生成中…' : '生成中…', true);
|
||||
_renderTriLoading();
|
||||
setTimeout(() => {
|
||||
_generating = false;
|
||||
const now = new Date();
|
||||
const ts = String(now.getHours()).padStart(2,'0') + ':' + String(now.getMinutes()).padStart(2,'0');
|
||||
_versions.push({ ts, label: 'v' + (_versions.length + 1) });
|
||||
_curIdx = _versions.length - 1;
|
||||
_dirty = true;
|
||||
_renderTriPreview();
|
||||
_renderHistory();
|
||||
// 第一次生成后,按钮文案 → 再次生成;并隐藏 tip 文案,只留按钮在右侧
|
||||
tipEl.style.display = 'flex';
|
||||
tipTextEl.textContent = '已生成 ' + _versions.length + ' 版三视图 · 不满意可重跑,保存后写入资产';
|
||||
_setAigenLabel('再次生成', false);
|
||||
if (window.Shell?.toast) {
|
||||
Shell.toast('三视图已生成', _curName + ' · ' + _versions[_curIdx].label + ' · 满意请点「保存」');
|
||||
}
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
function _hash(s) { let h = 0; for (let i = 0; i < s.length; i++) h = ((h << 5) - h + s.charCodeAt(i)) | 0; return Math.abs(h); }
|
||||
function _fmtAssetId(name, k) { return 'ASSET-20240520-' + (k === 'person' ? 'M' : k === 'scene' ? 'S' : 'P') + String(_hash(name) % 1000).padStart(3, '0'); }
|
||||
@ -2113,7 +2247,19 @@ document.querySelectorAll('.asset-card').forEach(card => {
|
||||
function _fmtDl(name) { const n = 200 + _hash(name) % 1800; return n >= 1000 ? (n / 1000).toFixed(1) + 'k' : String(n); }
|
||||
|
||||
function open(card) {
|
||||
// 重置本次打开的状态
|
||||
_curCard = card;
|
||||
_versions = [];
|
||||
_curIdx = -1;
|
||||
_dirty = false;
|
||||
_generating = false;
|
||||
_allowGen = false;
|
||||
historyEl.style.display = 'none';
|
||||
tipEl.classList.remove('is-loading');
|
||||
_setAigenLabel('AI 生成三视图', false);
|
||||
|
||||
const name = card.dataset.name || '资产';
|
||||
_curName = name;
|
||||
const used = card.dataset.used || '0';
|
||||
const source = card.dataset.source || '平台预设';
|
||||
let tagText = 'AI 素材', intro = '', tags = [], props = [], hasTri = false, isActor = false;
|
||||
@ -2163,51 +2309,142 @@ document.querySelectorAll('.asset-card').forEach(card => {
|
||||
titleEl.textContent = name;
|
||||
kindEl.textContent = '/ ' + tagText;
|
||||
leadImg.innerHTML = '<span class="ph-frame">' + name + '</span>';
|
||||
// 立绘 zoom 按钮(单次绑定 · 通过 name 闭包始终读最新 _curName)
|
||||
const _leadZoomBtn = document.getElementById('lib-detail-lead-zoom');
|
||||
if (_leadZoomBtn && !_leadZoomBtn.dataset.bound) {
|
||||
_leadZoomBtn.dataset.bound = '1';
|
||||
_leadZoomBtn.addEventListener('click', e => {
|
||||
e.stopPropagation();
|
||||
if (window.Shell?._openLightbox) Shell._openLightbox('', _curName || titleEl.textContent);
|
||||
});
|
||||
}
|
||||
|
||||
thumbsEl.innerHTML = ['v1','v2','v3'].map((t, i) => `<div class="thumb placeholder${i === 0 ? ' active' : ''}"><span class="ph-frame">${t}</span></div>`).join('');
|
||||
thumbsEl.querySelectorAll('.thumb').forEach(t => t.addEventListener('click', () => {
|
||||
thumbsEl.querySelectorAll('.thumb').forEach(x => x.classList.remove('active'));
|
||||
t.classList.add('active');
|
||||
}));
|
||||
// 平台预设资产 · 仅 1 张缩略图(用户上传多张的场景在 pipeline 工作台详情中处理)
|
||||
const _thumbLabel = card.dataset.sceneType ? '场景' : (isActor ? '立绘' : '主图');
|
||||
thumbsEl.innerHTML = `<div class="thumb placeholder active"><span class="ph-frame">${_thumbLabel}</span></div>`;
|
||||
|
||||
// 卡片是否标注「缺三视图」(data-triview="0")
|
||||
const cardMissingTri = card.dataset.triview === '0';
|
||||
|
||||
if (card.dataset.sceneType) {
|
||||
triSection.style.display = 'none';
|
||||
} else if (isActor) {
|
||||
triSection.style.display = '';
|
||||
triEl.classList.remove('actor');
|
||||
triEl.innerHTML = '<div class="placeholder"><span class="ph-frame">' + name + ' · 三视图 (正/侧/背)</span></div>';
|
||||
ratioChip.textContent = '16:9';
|
||||
tipEl.style.display = 'none';
|
||||
if (cardMissingTri) {
|
||||
// 人物 · 缺三视图 → 显示生成入口
|
||||
_allowGen = true;
|
||||
triEl.innerHTML = '<div class="placeholder missing" data-tri="0"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 8v4M12 16h.01"/></svg><span>暂未生成三视图 · 点击右侧按钮 AI 生成</span></div>';
|
||||
tipTextEl.textContent = '暂无三视图,建议用 AI 生成以保证多角度一致性';
|
||||
_setAigenLabel('AI 生成三视图', false);
|
||||
tipEl.style.display = 'flex';
|
||||
} else {
|
||||
triEl.innerHTML = '<div class="placeholder"><span class="ph-frame">' + name + ' · 三视图 (正/侧/背)</span><button class="ad-zoom-btn" type="button" data-zoom-tri aria-label="查看大图" title="查看大图"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 8V3h5M16 3h5v5M21 16v5h-5M8 21H3v-5"/></svg></button></div>';
|
||||
tipEl.style.display = 'none';
|
||||
}
|
||||
} else {
|
||||
triSection.style.display = '';
|
||||
triEl.classList.remove('actor');
|
||||
ratioChip.textContent = '16:9';
|
||||
if (hasTri) {
|
||||
triEl.innerHTML = '<div class="placeholder"><span class="ph-frame">' + name + ' · 三视图</span></div>';
|
||||
if (hasTri && !cardMissingTri) {
|
||||
triEl.innerHTML = '<div class="placeholder"><span class="ph-frame">' + name + ' · 三视图</span><button class="ad-zoom-btn" type="button" data-zoom-tri aria-label="查看大图" title="查看大图"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 8V3h5M16 3h5v5M21 16v5h-5M8 21H3v-5"/></svg></button></div>';
|
||||
tipEl.style.display = 'none';
|
||||
} else {
|
||||
// 商品/其他 · 缺三视图 → 同样启用生成入口
|
||||
_allowGen = true;
|
||||
triEl.innerHTML = '<div class="placeholder missing" data-tri="0"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 8v4M12 16h.01"/></svg><span>暂未生成三视图(16:9 单图)</span></div>';
|
||||
tipTextEl.textContent = '暂无三视图,建议用 AI 生成以保证多角度一致性';
|
||||
_setAigenLabel('AI 生成三视图', false);
|
||||
tipEl.style.display = 'flex';
|
||||
}
|
||||
}
|
||||
|
||||
// 三视图 zoom 按钮 click
|
||||
triEl.querySelector('[data-zoom-tri]')?.addEventListener('click', e => {
|
||||
e.stopPropagation();
|
||||
if (window.Shell?._openLightbox) Shell._openLightbox('', name + ' · 三视图');
|
||||
});
|
||||
|
||||
introEl.textContent = intro || '暂无简介';
|
||||
tagsEl.innerHTML = tags.map(t => '<span class="ad-tag-chip">' + t + '</span>').join('') +
|
||||
'<button class="ad-tag-add" type="button" title="添加标签"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M8 3v10M3 8h10"/></svg></button>';
|
||||
'<button class="ad-tag-add" type="button" title="添加标签"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M8 3v10M3 8h10"/></svg></button>';
|
||||
propsEl.innerHTML = props.map(([k, v]) => '<div class="ad-prop"><span class="k">' + k + '</span><span class="v">' + v + '</span></div>').join('');
|
||||
|
||||
bg.classList.add('show');
|
||||
}
|
||||
function close() { bg.classList.remove('show'); }
|
||||
// ── 二次确认弹窗 ──
|
||||
const confirmBg = document.getElementById('lib-confirm-bg');
|
||||
const confirmCountEl = document.getElementById('lib-confirm-count');
|
||||
const confirmSaveBtn = document.getElementById('lib-confirm-save');
|
||||
const confirmDiscardBtn = document.getElementById('lib-confirm-discard');
|
||||
function _openConfirm() {
|
||||
confirmCountEl.textContent = _versions.length;
|
||||
confirmBg.classList.add('show');
|
||||
confirmBg.setAttribute('aria-hidden', 'false');
|
||||
}
|
||||
function _closeConfirm() {
|
||||
confirmBg.classList.remove('show');
|
||||
confirmBg.setAttribute('aria-hidden', 'true');
|
||||
}
|
||||
confirmBg.addEventListener('click', e => { if (e.target === confirmBg) _closeConfirm(); });
|
||||
|
||||
function _doSave() {
|
||||
if (_curCard) {
|
||||
const badge = _curCard.querySelector('.tri-missing-badge');
|
||||
if (badge) badge.remove();
|
||||
_curCard.dataset.triview = '1';
|
||||
}
|
||||
_dirty = false;
|
||||
Shell.toast('已保存', _curName + ' · 三视图(' + _versions[_curIdx].label + ')已写入资产');
|
||||
}
|
||||
|
||||
function close(force) {
|
||||
if (!force && _dirty) {
|
||||
_openConfirm();
|
||||
return;
|
||||
}
|
||||
bg.classList.remove('show');
|
||||
_dirty = false;
|
||||
}
|
||||
|
||||
bg.addEventListener('click', e => { if (e.target === bg) close(); });
|
||||
document.getElementById('lib-detail-x').addEventListener('click', close);
|
||||
document.getElementById('lib-detail-apply').addEventListener('click', () => {
|
||||
Shell.toast('已应用「' + titleEl.textContent + '」', '已加入当前项目');
|
||||
close();
|
||||
document.getElementById('lib-detail-x').addEventListener('click', () => close());
|
||||
|
||||
applyBtn.addEventListener('click', () => {
|
||||
if (_allowGen && _versions.length) {
|
||||
_doSave();
|
||||
close(true);
|
||||
return;
|
||||
}
|
||||
if (_allowGen && !_versions.length) {
|
||||
Shell.toast('请先生成三视图', '点击「AI 生成三视图」开始');
|
||||
return;
|
||||
}
|
||||
Shell.toast('已保存', _curName);
|
||||
close(true);
|
||||
});
|
||||
document.getElementById('lib-detail-aigen').addEventListener('click', () => {
|
||||
Shell.toast('AI 生成三视图中', '约 12s · POST /assets/tri-view');
|
||||
|
||||
// 弹窗按钮 · 主按钮「保存并退出」/ 次按钮「退出」
|
||||
confirmSaveBtn.addEventListener('click', () => {
|
||||
if (_versions.length) _doSave();
|
||||
_closeConfirm();
|
||||
close(true);
|
||||
});
|
||||
confirmDiscardBtn.addEventListener('click', () => {
|
||||
_dirty = false;
|
||||
_closeConfirm();
|
||||
close(true);
|
||||
});
|
||||
|
||||
aigenBtn.addEventListener('click', _startGenerate);
|
||||
|
||||
// Esc · 若确认弹窗开着,先关确认;否则尝试关详情(经过 dirty 检查)
|
||||
document.addEventListener('keydown', e => {
|
||||
if (e.key !== 'Escape') return;
|
||||
if (confirmBg.classList.contains('show')) { _closeConfirm(); return; }
|
||||
if (!bg.classList.contains('show')) return;
|
||||
close();
|
||||
});
|
||||
|
||||
// 把所有 .asset-card 的旧 onclick="Shell.toast(...)" 清掉,改成 open(card)
|
||||
|
||||
@ -107,7 +107,7 @@
|
||||
<!-- 左:品牌 -->
|
||||
<aside class="auth-brand">
|
||||
<div class="logo">
|
||||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 L19 7 V17 L12 22 L5 17 V7 Z"/><path d="M12 2 V22"/><path d="M5 7 L19 17"/></svg></span>
|
||||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 L19 7 V17 L12 22 L5 17 V7 Z"/><path d="M12 2 V22"/><path d="M5 7 L19 17"/></svg></span>
|
||||
<span>流·Studio</span>
|
||||
</div>
|
||||
<div class="tag">// SHORT-VIDEO COMMERCE PLATFORM</div>
|
||||
@ -145,7 +145,7 @@
|
||||
<div class="field">
|
||||
<label class="field-label" for="auth-email">邮箱 <span class="req">*</span></label>
|
||||
<div class="field-input-wrap">
|
||||
<svg class="ic-l" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z"/><path d="m22 6-10 7L2 6"/></svg>
|
||||
<svg class="ic-l" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z"/><path d="m22 6-10 7L2 6"/></svg>
|
||||
<input type="email" id="auth-email" placeholder="name@company.com" value="li@shop.com" required>
|
||||
</div>
|
||||
</div>
|
||||
@ -153,17 +153,17 @@
|
||||
<div class="field">
|
||||
<label class="field-label" for="auth-pwd">密码 <span class="req">*</span></label>
|
||||
<div class="field-input-wrap">
|
||||
<svg class="ic-l" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
|
||||
<svg class="ic-l" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
|
||||
<input type="password" id="auth-pwd" placeholder="••••••••" value="demo-1234" required>
|
||||
<button type="button" class="toggle-pwd" aria-label="切换密码可见" onclick="togglePwd()">
|
||||
<svg id="pwd-eye" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/></svg>
|
||||
<svg id="pwd-eye" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-between">
|
||||
<label><input type="checkbox" checked> 记住我 7 天</label>
|
||||
<a href="#" onclick="event.preventDefault();alert('演示稿 · 真实流程为重置密码邮件');">忘记密码?</a>
|
||||
<a href="#" onclick="event.preventDefault();_loginToast('已发送重置邮件','请到 li@shop.com 收件箱查看 · 链接 30 分钟有效');">忘记密码?</a>
|
||||
</div>
|
||||
|
||||
<button class="btn-cta" type="submit">
|
||||
@ -174,11 +174,11 @@
|
||||
<div class="divider"><span class="line"></span><span class="txt">OR</span><span class="line"></span></div>
|
||||
|
||||
<div class="sso-row">
|
||||
<button type="button" class="sso-btn" onclick="alert('演示稿 · 微信扫码登录占位');">
|
||||
<button type="button" class="sso-btn" onclick="_loginToast('微信扫码','请在 60s 内用微信扫一扫完成授权 · 内测中,以邮箱登录为准');">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M9 4C5 4 2 6.5 2 9.5c0 1.7 1 3.2 2.5 4.2L4 16l2.2-1.1c.7.2 1.5.3 2.3.3-.3-.5-.5-1.1-.5-1.7 0-2.8 2.9-5 6.5-5h.5C14.6 6 12 4 9 4zm-2 3.5c.6 0 1 .4 1 1s-.4 1-1 1-1-.4-1-1 .4-1 1-1zm4 0c.6 0 1 .4 1 1s-.4 1-1 1-1-.4-1-1 .4-1 1-1zM15 9c-3.3 0-6 2.2-6 5s2.7 5 6 5c.7 0 1.4-.1 2-.3L19 20l-.4-1.7c1.4-.9 2.4-2.3 2.4-3.8 0-2.8-2.7-5-6-5zm-2 2.5c.6 0 1 .4 1 1s-.4 1-1 1-1-.4-1-1 .4-1 1-1zm4 0c.6 0 1 .4 1 1s-.4 1-1 1-1-.4-1-1 .4-1 1-1z"/></svg>
|
||||
微信扫码
|
||||
</button>
|
||||
<button type="button" class="sso-btn" onclick="alert('演示稿 · 飞书 SSO 占位');">
|
||||
<button type="button" class="sso-btn" onclick="_loginToast('飞书 SSO','即将打开企业飞书登录授权页 · 内测中,以邮箱登录为准');">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor"><rect x="3" y="3" width="18" height="18" rx="3"/></svg>
|
||||
飞书 SSO
|
||||
</button>
|
||||
@ -202,6 +202,20 @@
|
||||
btn.disabled = true;
|
||||
setTimeout(() => { location.href = 'index.html'; }, 700);
|
||||
}
|
||||
// 轻量 toast(不依赖 shell.js,免登录页拉重)
|
||||
function _loginToast(t, sub) {
|
||||
let el = document.getElementById('__login-toast');
|
||||
if (!el) {
|
||||
el = document.createElement('div');
|
||||
el.id = '__login-toast';
|
||||
el.style.cssText = 'position:fixed;left:50%;bottom:36px;transform:translateX(-50%) translateY(20px);background:#fff;border:1px solid #e0e0e0;border-radius:8px;padding:12px 18px;box-shadow:0 8px 24px rgba(0,0,0,.12);display:flex;flex-direction:column;gap:2px;opacity:0;transition:opacity .2s,transform .2s;z-index:9999;font-family:inherit;max-width:360px;';
|
||||
document.body.appendChild(el);
|
||||
}
|
||||
el.innerHTML = '<div style="font-size:13.5px;font-weight:600;color:#262626;">' + t + '</div>' + (sub ? '<div style="font-size:11.5px;color:rgba(0,0,0,.56);font-family:\'JetBrains Mono\',monospace;letter-spacing:.02em;">// ' + sub + '</div>' : '');
|
||||
requestAnimationFrame(() => { el.style.opacity = '1'; el.style.transform = 'translateX(-50%) translateY(0)'; });
|
||||
clearTimeout(el._t);
|
||||
el._t = setTimeout(() => { el.style.opacity = '0'; el.style.transform = 'translateX(-50%) translateY(20px)'; }, 2800);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
769
电商AI平台/messages.html
Normal file
769
电商AI平台/messages.html
Normal file
@ -0,0 +1,769 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>消息中心 · 流·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?v=202605211643">
|
||||
<style>
|
||||
#page-content { flex: 1; min-height: 0; display: flex; flex-direction: column; }
|
||||
#page { display: flex; flex-direction: column; height: 100%; min-height: 0; }
|
||||
|
||||
/* ─── 页头 ─── */
|
||||
.page-head { margin-bottom: 18px; }
|
||||
.page-head h1 .ct { font-family: var(--font-mono); font-size: 12px; color: var(--black-alpha-48); margin-left: 8px; font-weight: 400; letter-spacing: .04em; }
|
||||
|
||||
/* ─── 顶部工具栏:tabs + 搜索 + 操作 ─── */
|
||||
.ms-toolbar {
|
||||
display: flex; align-items: center; gap: 14px;
|
||||
padding: 10px 14px;
|
||||
background: var(--surface); border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-md);
|
||||
margin-bottom: 14px; flex-wrap: wrap;
|
||||
}
|
||||
.ms-tabs { display: inline-flex; gap: 4px; }
|
||||
.ms-tab {
|
||||
height: 30px; padding: 0 14px;
|
||||
display: inline-flex; align-items: center; gap: 6px;
|
||||
background: transparent; border: 1px solid transparent;
|
||||
border-radius: var(--r-pill);
|
||||
font-family: inherit; font-size: 12.5px; color: var(--black-alpha-72);
|
||||
cursor: pointer;
|
||||
transition: background var(--t-base), color var(--t-base), border-color var(--t-base);
|
||||
}
|
||||
.ms-tab:hover { color: var(--accent-black); background: var(--background-lighter); }
|
||||
.ms-tab.active { background: var(--heat-12); color: var(--heat); border-color: var(--heat-20); font-weight: 600; }
|
||||
.ms-tab .ct {
|
||||
font-family: var(--font-mono); font-size: 10.5px;
|
||||
background: var(--black-alpha-7); color: var(--black-alpha-72);
|
||||
padding: 1px 6px; border-radius: var(--r-pill);
|
||||
min-width: 18px; text-align: center;
|
||||
}
|
||||
.ms-tab.active .ct { background: var(--heat); color: var(--accent-white); }
|
||||
|
||||
.ms-search {
|
||||
flex: 1; min-width: 200px; max-width: 320px;
|
||||
position: relative; display: inline-flex; align-items: center;
|
||||
}
|
||||
.ms-search svg {
|
||||
position: absolute; left: 10px; width: 13px; height: 13px;
|
||||
color: var(--black-alpha-40); pointer-events: none;
|
||||
}
|
||||
.ms-search input {
|
||||
width: 100%; height: 32px; padding: 0 12px 0 30px;
|
||||
background: var(--background-lighter); border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-sm); font-family: inherit; font-size: 12.5px;
|
||||
color: var(--accent-black); outline: none;
|
||||
}
|
||||
.ms-search input:focus { border-color: var(--heat-40); background: var(--surface); }
|
||||
|
||||
.ms-toggle {
|
||||
height: 30px; padding: 0 12px;
|
||||
display: inline-flex; align-items: center; gap: 6px;
|
||||
background: var(--background-lighter); border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-pill);
|
||||
font-family: inherit; font-size: 12px; color: var(--black-alpha-72);
|
||||
cursor: pointer; transition: background var(--t-base), color var(--t-base), border-color var(--t-base);
|
||||
}
|
||||
.ms-toggle:hover { color: var(--accent-black); border-color: var(--black-alpha-24); }
|
||||
.ms-toggle.on { background: var(--heat-12); border-color: var(--heat-20); color: var(--heat); font-weight: 600; }
|
||||
.ms-toggle .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
|
||||
|
||||
.ms-actions { margin-left: auto; display: inline-flex; gap: 8px; }
|
||||
.ms-actions .btn { height: 30px; padding: 0 12px; font-size: 12px; }
|
||||
|
||||
/* ─── 主体:左侧列表 + 右侧详情 ─── */
|
||||
.ms-body {
|
||||
flex: 1; min-height: 0;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(340px, 420px) 1fr;
|
||||
gap: 14px;
|
||||
}
|
||||
@media (max-width: 980px) { .ms-body { grid-template-columns: 1fr; } }
|
||||
|
||||
/* 左:列表卡片 */
|
||||
.ms-list-pane {
|
||||
background: var(--surface); border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-md);
|
||||
display: flex; flex-direction: column;
|
||||
overflow: hidden; min-height: 0;
|
||||
}
|
||||
.ms-list-h {
|
||||
padding: 12px 16px; border-bottom: 1px solid var(--border-faint);
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ms-list-h .mono { font-family: var(--font-mono); font-size: 11px; color: var(--black-alpha-48); letter-spacing: .04em; }
|
||||
.ms-list-h .group-toggle {
|
||||
margin-left: auto;
|
||||
background: transparent; border: 0; cursor: pointer;
|
||||
font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-56);
|
||||
letter-spacing: .04em; padding: 2px 6px; border-radius: var(--r-sm);
|
||||
}
|
||||
.ms-list-h .group-toggle:hover { background: var(--background-lighter); color: var(--accent-black); }
|
||||
|
||||
.ms-list { flex: 1; min-height: 0; overflow-y: auto; }
|
||||
.ms-group-h {
|
||||
padding: 8px 16px 6px;
|
||||
font-family: var(--font-mono); font-size: 10.5px;
|
||||
color: var(--black-alpha-48); letter-spacing: .06em; text-transform: uppercase;
|
||||
background: var(--background-base);
|
||||
position: sticky; top: 0; z-index: 1;
|
||||
}
|
||||
.ms-item {
|
||||
position: relative;
|
||||
display: grid; grid-template-columns: 28px 1fr; gap: 10px;
|
||||
padding: 14px 16px;
|
||||
border-bottom: 1px solid var(--border-faint);
|
||||
cursor: pointer;
|
||||
transition: background var(--t-base);
|
||||
}
|
||||
.ms-item:hover { background: var(--background-lighter); }
|
||||
.ms-item.active { background: var(--heat-12); }
|
||||
.ms-item.active::before {
|
||||
content: ''; position: absolute; left: 0; top: 0; bottom: 0;
|
||||
width: 3px; background: var(--heat);
|
||||
}
|
||||
.ms-item.read .ms-item-title { color: var(--black-alpha-56); font-weight: 400; }
|
||||
.ms-item.read .ms-item-icon { opacity: .55; }
|
||||
|
||||
.ms-item-icon {
|
||||
width: 28px; height: 28px;
|
||||
display: grid; place-items: center;
|
||||
border-radius: var(--r-sm);
|
||||
background: var(--background-lighter); border: 1px solid var(--border-faint);
|
||||
color: var(--black-alpha-72);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ms-item-icon svg { width: 14px; height: 14px; }
|
||||
.ms-item-icon.task { background: var(--heat-12); border-color: var(--heat-20); color: var(--heat); }
|
||||
.ms-item-icon.team { background: rgba(76,134,255,.10); border-color: rgba(76,134,255,.24); color: #3a6dd1; }
|
||||
.ms-item-icon.system { background: var(--black-alpha-7); border-color: var(--border-faint); color: var(--black-alpha-72); }
|
||||
.ms-item-icon.billing { background: rgba(241,176,29,.12); border-color: rgba(241,176,29,.28); color: #b5860d; }
|
||||
.ms-item-icon.success { background: var(--forest-bg); border-color: var(--forest-bd); color: var(--accent-forest); }
|
||||
.ms-item-icon.error { background: var(--crimson-bg); border-color: var(--crimson-bd); color: var(--accent-crimson); }
|
||||
|
||||
.ms-item-main { min-width: 0; }
|
||||
.ms-item-row1 { display: flex; align-items: center; gap: 8px; }
|
||||
.ms-item-title { font-size: 13px; font-weight: 600; color: var(--accent-black); flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.ms-item-ts { font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); letter-spacing: .02em; flex-shrink: 0; }
|
||||
.ms-item-unread {
|
||||
width: 7px; height: 7px; border-radius: 50%;
|
||||
background: var(--heat); flex-shrink: 0;
|
||||
}
|
||||
.ms-item.read .ms-item-unread { display: none; }
|
||||
.ms-item-body {
|
||||
font-size: 12px; color: var(--black-alpha-56);
|
||||
line-height: 1.5; margin-top: 3px;
|
||||
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
.ms-item-tag {
|
||||
display: inline-block; margin-top: 6px;
|
||||
padding: 1px 6px;
|
||||
font-family: var(--font-mono); font-size: 10px; letter-spacing: .02em;
|
||||
background: var(--background-lighter); border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-sm); color: var(--black-alpha-56);
|
||||
}
|
||||
.ms-item-tag.crit { background: var(--crimson-bg); border-color: var(--crimson-bd); color: var(--accent-crimson); }
|
||||
.ms-item-tag.warn { background: rgba(241,176,29,.14); border-color: rgba(241,176,29,.32); color: #b5860d; }
|
||||
.ms-item-tag.ok { background: var(--forest-bg); border-color: var(--forest-bd); color: var(--accent-forest); }
|
||||
.ms-item-tag.info { background: var(--heat-12); border-color: var(--heat-20); color: var(--heat); }
|
||||
|
||||
.ms-list-empty {
|
||||
padding: 60px 24px;
|
||||
display: flex; flex-direction: column; align-items: center; gap: 10px;
|
||||
color: var(--black-alpha-48); font-size: 13px;
|
||||
}
|
||||
.ms-list-empty .ic {
|
||||
width: 44px; height: 44px;
|
||||
display: grid; place-items: center;
|
||||
background: var(--background-lighter); border: 1px solid var(--border-faint);
|
||||
border-radius: 50%; color: var(--black-alpha-40);
|
||||
}
|
||||
.ms-list-empty .mono { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .04em; }
|
||||
|
||||
/* 右:详情 pane */
|
||||
.ms-detail-pane {
|
||||
background: var(--surface); border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-md);
|
||||
display: flex; flex-direction: column;
|
||||
overflow: hidden; min-height: 0;
|
||||
}
|
||||
.ms-detail-empty {
|
||||
flex: 1; display: grid; place-items: center;
|
||||
color: var(--black-alpha-40); font-size: 13px;
|
||||
flex-direction: column; gap: 8px;
|
||||
}
|
||||
.ms-detail-empty .ic {
|
||||
width: 48px; height: 48px;
|
||||
display: grid; place-items: center;
|
||||
background: var(--background-lighter); border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-md); color: var(--black-alpha-40);
|
||||
}
|
||||
.ms-detail-empty .ic svg { width: 22px; height: 22px; }
|
||||
.ms-detail-empty .mono { font-family: var(--font-mono); font-size: 10.5px; color: var(--black-alpha-48); letter-spacing: .04em; }
|
||||
|
||||
.ms-detail-h {
|
||||
padding: 18px 24px 14px;
|
||||
border-bottom: 1px solid var(--border-faint);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ms-detail-h .row1 { display: flex; align-items: center; gap: 10px; }
|
||||
.ms-detail-h .kind-tag {
|
||||
font-family: var(--font-mono); font-size: 10.5px;
|
||||
padding: 2px 8px; border-radius: var(--r-sm);
|
||||
background: var(--background-lighter); border: 1px solid var(--border-faint);
|
||||
color: var(--black-alpha-56); letter-spacing: .04em; text-transform: uppercase;
|
||||
}
|
||||
.ms-detail-h .kind-tag.task { background: var(--heat-12); color: var(--heat); border-color: var(--heat-20); }
|
||||
.ms-detail-h .kind-tag.team { background: rgba(76,134,255,.10); color: #3a6dd1; border-color: rgba(76,134,255,.24); }
|
||||
.ms-detail-h .kind-tag.system { background: var(--black-alpha-7); color: var(--black-alpha-72); }
|
||||
.ms-detail-h .kind-tag.billing { background: rgba(241,176,29,.12); color: #b5860d; border-color: rgba(241,176,29,.28); }
|
||||
.ms-detail-h .x {
|
||||
margin-left: auto; width: 28px; height: 28px;
|
||||
background: transparent; border: 0; border-radius: var(--r-sm);
|
||||
color: var(--black-alpha-56); cursor: pointer;
|
||||
display: grid; place-items: center;
|
||||
}
|
||||
.ms-detail-h .x:hover { background: var(--background-lighter); color: var(--accent-black); }
|
||||
.ms-detail-h .x svg { width: 14px; height: 14px; }
|
||||
.ms-detail-h h2 { font-size: 18px; font-weight: 600; letter-spacing: -.012em; color: var(--accent-black); margin: 12px 0 6px; }
|
||||
.ms-detail-h .meta { display: flex; align-items: center; gap: 14px; font-family: var(--font-mono); font-size: 11px; color: var(--black-alpha-48); letter-spacing: .02em; }
|
||||
.ms-detail-h .meta .from { color: var(--accent-black); font-weight: 600; }
|
||||
.ms-detail-h .meta .dot { width: 3px; height: 3px; border-radius: 50%; background: var(--black-alpha-24); }
|
||||
|
||||
.ms-detail-b {
|
||||
flex: 1; min-height: 0; overflow-y: auto;
|
||||
padding: 18px 24px 20px;
|
||||
}
|
||||
.ms-detail-b p { font-size: 13.5px; line-height: 1.7; color: var(--accent-black); margin: 0 0 12px; }
|
||||
.ms-detail-b .quote {
|
||||
border-left: 3px solid var(--heat);
|
||||
padding: 8px 14px;
|
||||
background: var(--heat-12);
|
||||
border-radius: 0 var(--r-sm) var(--r-sm) 0;
|
||||
font-size: 13px; line-height: 1.65; color: var(--accent-black);
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
/* 详情属性表 */
|
||||
.ms-props {
|
||||
display: grid; grid-template-columns: 110px 1fr;
|
||||
row-gap: 10px; column-gap: 16px;
|
||||
margin: 14px 0 6px;
|
||||
padding: 12px 16px;
|
||||
background: var(--background-lighter); border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-sm);
|
||||
}
|
||||
.ms-props .k {
|
||||
font-family: var(--font-mono); font-size: 11px;
|
||||
color: var(--black-alpha-48); letter-spacing: .04em; text-transform: uppercase;
|
||||
}
|
||||
.ms-props .v { font-size: 12.5px; color: var(--accent-black); word-break: break-all; }
|
||||
.ms-props .v.mono { font-family: var(--font-mono); }
|
||||
.ms-props .v a { color: var(--heat); }
|
||||
.ms-props .v a:hover { text-decoration: underline; }
|
||||
|
||||
.ms-detail-f {
|
||||
padding: 12px 20px;
|
||||
border-top: 1px solid var(--border-faint);
|
||||
background: var(--background-lighter);
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
flex-shrink: 0; flex-wrap: wrap;
|
||||
}
|
||||
.ms-detail-f .spacer { flex: 1; }
|
||||
.ms-detail-f .btn { height: 32px; padding: 0 14px; font-size: 12.5px; }
|
||||
|
||||
/* 设置入口卡(底部) */
|
||||
.ms-foot-hint {
|
||||
margin-top: 14px;
|
||||
padding: 10px 14px;
|
||||
background: var(--background-lighter); border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-md);
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
font-size: 12px; color: var(--black-alpha-56);
|
||||
}
|
||||
.ms-foot-hint svg { width: 14px; height: 14px; color: var(--heat); flex-shrink: 0; }
|
||||
.ms-foot-hint a { color: var(--heat); margin-left: auto; font-weight: 600; }
|
||||
.ms-foot-hint a:hover { text-decoration: underline; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="page">
|
||||
|
||||
<div class="page-head">
|
||||
<div>
|
||||
<h1>消息中心<span class="ct" id="ms-head-ct">// 0 条未读 · 0 条总计</span></h1>
|
||||
<div class="sub"><span class="mono">// 任务 · 团队 · 系统 · 计费 四类事件流</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 顶部工具栏 -->
|
||||
<div class="ms-toolbar">
|
||||
<div class="ms-tabs" id="ms-tabs">
|
||||
<button class="ms-tab active" type="button" data-tab="all">全部 <span class="ct" data-ct="all">0</span></button>
|
||||
<button class="ms-tab" type="button" data-tab="task">任务 <span class="ct" data-ct="task">0</span></button>
|
||||
<button class="ms-tab" type="button" data-tab="team">团队 <span class="ct" data-ct="team">0</span></button>
|
||||
<button class="ms-tab" type="button" data-tab="system">系统 <span class="ct" data-ct="system">0</span></button>
|
||||
<button class="ms-tab" type="button" data-tab="billing">计费 <span class="ct" data-ct="billing">0</span></button>
|
||||
</div>
|
||||
<button class="ms-toggle" type="button" id="ms-only-unread"><span class="dot"></span>仅看未读</button>
|
||||
<div class="ms-search">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<input type="text" id="ms-search-input" placeholder="搜索消息内容 / 来源 / 项目…">
|
||||
</div>
|
||||
<div class="ms-actions">
|
||||
<button class="btn" type="button" id="ms-mark-all">全部标已读</button>
|
||||
<button class="btn btn-ghost" type="button" id="ms-settings">通知设置</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 列表 + 详情 -->
|
||||
<div class="ms-body">
|
||||
<!-- 左 · 列表 -->
|
||||
<div class="ms-list-pane">
|
||||
<div class="ms-list-h">
|
||||
<span class="mono" id="ms-list-ct">// 显示 0 条</span>
|
||||
<button class="group-toggle" type="button" id="ms-group-toggle">按时间分组 ▾</button>
|
||||
</div>
|
||||
<div class="ms-list" id="ms-list"></div>
|
||||
</div>
|
||||
|
||||
<!-- 右 · 详情 -->
|
||||
<div class="ms-detail-pane" id="ms-detail-pane">
|
||||
<div class="ms-detail-empty" id="ms-detail-empty">
|
||||
<div class="ic">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9M10 21a2 2 0 0 0 4 0"/></svg>
|
||||
</div>
|
||||
<div>从左侧选择一条消息查看详情</div>
|
||||
<div class="mono">// 点击列表项 · 自动标为已读</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ms-foot-hint">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 8v4M12 16h.01"/></svg>
|
||||
消息默认保留 90 天,任务类消息可在「通知设置」中按类别静音或转发到团队邮箱。
|
||||
<a href="settings.html">前往设置 →</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script src="assets/shell.js?v=202605211643"></script>
|
||||
<script>
|
||||
Shell.render({ active: '', crumbs: [{ label: '工作台', href: 'index.html' }, { label: '消息中心' }] });
|
||||
|
||||
/* ─── Mock 数据 · 12 条,贴合 PRD 与项目当前内容 ─── */
|
||||
const NOW = new Date('2026-05-25T15:18:00');
|
||||
function _ago(min) {
|
||||
const d = new Date(NOW.getTime() - min * 60000);
|
||||
return d;
|
||||
}
|
||||
function _fmt(d) {
|
||||
const today = new Date(NOW.getFullYear(), NOW.getMonth(), NOW.getDate());
|
||||
const dDay = new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
||||
const diff = (today - dDay) / (24 * 3600 * 1000);
|
||||
const hh = String(d.getHours()).padStart(2, '0'), mm = String(d.getMinutes()).padStart(2, '0');
|
||||
if (diff === 0) return '今天 ' + hh + ':' + mm;
|
||||
if (diff === 1) return '昨天 ' + hh + ':' + mm;
|
||||
if (diff < 7) return diff + ' 天前';
|
||||
return (d.getMonth() + 1) + '.' + d.getDate() + ' ' + hh + ':' + mm;
|
||||
}
|
||||
function _fmtFull(d) {
|
||||
return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0')
|
||||
+ ' ' + String(d.getHours()).padStart(2, '0') + ':' + String(d.getMinutes()).padStart(2, '0');
|
||||
}
|
||||
|
||||
const ICONS = {
|
||||
taskOk: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.1V12a10 10 0 1 1-5.93-9.14"/><path d="m9 11 3 3L22 4"/></svg>',
|
||||
taskFail: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M15 9l-6 6M9 9l6 6"/></svg>',
|
||||
taskRun: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>',
|
||||
team: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="8" r="3.5"/><path d="M3 20c0-3 2.7-5 6-5s6 2 6 5"/><circle cx="17" cy="9" r="2.5"/><path d="M14 20c.5-2.4 2.4-4 5-4"/></svg>',
|
||||
comment: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 11.5a8.4 8.4 0 0 1-8.5 8.5 8.5 8.5 0 0 1-4.5-1.3L3 20l1.3-5a8.5 8.5 0 0 1-1.3-4.5A8.4 8.4 0 0 1 11.5 2 8.5 8.5 0 0 1 21 11.5z"/></svg>',
|
||||
system: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 8v4M12 16h.01"/></svg>',
|
||||
billing: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="6" width="18" height="13" rx="2"/><path d="M3 10h18M16 14h2"/></svg>',
|
||||
shield: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="m9 12 2 2 4-4"/></svg>',
|
||||
pipeline: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16"/><path d="M7 4v16M16 4v16M3 9h18M3 15h18"/></svg>',
|
||||
};
|
||||
|
||||
const MESSAGES = [
|
||||
// ─ 任务类(5) ─
|
||||
{
|
||||
id: 'm-001', type: 'task', icon: 'taskOk', severity: 'ok',
|
||||
title: '视频已完成 · 补水面膜 · 痛点种草 v3',
|
||||
body: '7 镜 · 40 秒成片渲染完成,余额已扣除 ¥18.40。点 [✓ 通过] 进入投放阶段,或 [↻ 重跑] 调整脚本。',
|
||||
ts: _ago(8), from: '系统', tag: '通过', tagKind: 'ok',
|
||||
project: '补水面膜', stage: 'Stage 5 · 投放',
|
||||
target: { type: 'project', href: 'pipeline.html?product=' + encodeURIComponent('补水面膜'), name: '补水面膜 · 痛点种草' },
|
||||
actions: [
|
||||
{ label: '进入项目', primary: true, action: 'goto' },
|
||||
{ label: '查看成片', action: 'preview' },
|
||||
{ label: '再次生成', action: 'rerun' },
|
||||
],
|
||||
unread: true,
|
||||
},
|
||||
{
|
||||
id: 'm-002', type: 'task', icon: 'taskOk', severity: 'ok',
|
||||
title: '4 张模特上身图已生成 · 祛痘精华',
|
||||
body: '阿楠 · 通勤白领 · 室内自然光 · 3:4。预估 ¥3.20,可在「资产库 / 我的上传」直接调用或加入新项目。',
|
||||
ts: _ago(42), from: '系统', tag: '通过', tagKind: 'ok',
|
||||
project: '祛痘精华', stage: '图片生成 · 模特上身图',
|
||||
target: { type: 'asset-factory', href: 'asset-factory.html', name: '图片生成 · 模特上身图' },
|
||||
actions: [
|
||||
{ label: '查看素材', primary: true, action: 'goto' },
|
||||
{ label: '加入项目', action: 'attach' },
|
||||
],
|
||||
unread: true,
|
||||
},
|
||||
{
|
||||
id: 'm-003', type: 'task', icon: 'taskOk', severity: 'ok',
|
||||
title: '演员「林夕」三视图已就绪',
|
||||
body: '正/侧/背 三视图生成完成,共 ¥0.30。该演员现已具备多角度一致性,可放心进入视频生成。',
|
||||
ts: _ago(95), from: '系统', tag: '资产更新', tagKind: 'info',
|
||||
project: '资产库', stage: '演员库 · 我的上传',
|
||||
target: { type: 'library', href: 'library.html#person', name: '资产库 / 人物 / 林夕' },
|
||||
actions: [
|
||||
{ label: '查看演员', primary: true, action: 'goto' },
|
||||
{ label: '在项目中使用', action: 'attach' },
|
||||
],
|
||||
unread: true,
|
||||
},
|
||||
{
|
||||
id: 'm-004', type: 'task', icon: 'taskFail', severity: 'err',
|
||||
title: '脚本生成失败 · 618 大促',
|
||||
body: '上下文超长(prompt > 8k tokens),AI 脚本服务返回 413。系统已自动截断 30% 内容并重试,本次失败不扣费。',
|
||||
ts: _ago(180), from: '系统', tag: '失败 · 免费重试', tagKind: 'crit',
|
||||
project: '618 大促', stage: 'Stage 1 · 脚本',
|
||||
target: { type: 'project', href: 'pipeline.html?product=' + encodeURIComponent('618 大促'), name: '618 大促 · Stage 1' },
|
||||
actions: [
|
||||
{ label: '重试生成', primary: true, action: 'rerun' },
|
||||
{ label: '查看错误日志', action: 'log' },
|
||||
],
|
||||
unread: true,
|
||||
},
|
||||
{
|
||||
id: 'm-005', type: 'task', icon: 'taskRun', severity: 'warn',
|
||||
title: '图片优化任务已超时,自动重跑',
|
||||
body: '原任务 12:45 提交,> 10 分钟未完成。已按 PRD §10.3 自动重跑,如再次失败将退还本次预估额度。',
|
||||
ts: _ago(220), from: '系统', tag: '超时 · 已重跑', tagKind: 'warn',
|
||||
project: '资产库', stage: '图片优化 · 队列',
|
||||
target: { type: 'queue', href: 'index.html', name: '工作台 · 任务队列' },
|
||||
actions: [
|
||||
{ label: '查看队列', primary: true, action: 'goto' },
|
||||
],
|
||||
unread: true,
|
||||
},
|
||||
|
||||
// ─ 团队类(4) ─
|
||||
{
|
||||
id: 'm-006', type: 'team', icon: 'team',
|
||||
title: '@王芳 已加入团队 · 角色 运营',
|
||||
body: '由超管 李 邀请。月限额 ¥800 · 资产可读可写。如需调整权限请前往团队设置。',
|
||||
ts: _ago(265), from: '@李(超管)', tag: '团队', tagKind: 'info',
|
||||
project: '团队', stage: '成员管理',
|
||||
target: { type: 'team', href: 'team.html', name: '团队 / 成员' },
|
||||
actions: [
|
||||
{ label: '查看团队', primary: true, action: 'goto' },
|
||||
{ label: '调整权限', action: 'edit' },
|
||||
],
|
||||
unread: true,
|
||||
},
|
||||
{
|
||||
id: 'm-007', type: 'team', icon: 'team',
|
||||
title: '@张磊 由「运营」升级为「主管」',
|
||||
body: '权限范围:可管理本人 + 下属团员的项目、资产、额度。变更生效于今天 13:22。',
|
||||
ts: _ago(310), from: '@李(超管)', tag: '权限变更', tagKind: 'info',
|
||||
project: '团队', stage: '权限管理',
|
||||
target: { type: 'team', href: 'team.html', name: '团队 / 角色' },
|
||||
actions: [
|
||||
{ label: '查看团队', primary: true, action: 'goto' },
|
||||
],
|
||||
unread: false,
|
||||
},
|
||||
{
|
||||
id: 'm-008', type: 'team', icon: 'team',
|
||||
title: '@李 创建了模特「小七 · 学生女」',
|
||||
body: '团队资产已同步 · 你可立即在「资产库 / 人物」中调用,免重复生成。',
|
||||
ts: _ago(420), from: '@李', tag: '资产共用', tagKind: 'ok',
|
||||
project: '资产库', stage: '人物 · 我的上传',
|
||||
target: { type: 'library', href: 'library.html#person', name: '资产库 / 人物 / 小七' },
|
||||
actions: [
|
||||
{ label: '查看资产', primary: true, action: 'goto' },
|
||||
],
|
||||
unread: false,
|
||||
},
|
||||
{
|
||||
id: 'm-009', type: 'team', icon: 'comment',
|
||||
title: '@刘 在「补水面膜」镜头 3 留下了评论',
|
||||
body: '"开头节奏可以更紧凑,前 2 秒建议直接进痛点。可以让 AI 把镜头 1 缩到 3 秒吗?"',
|
||||
ts: _ago(540), from: '@刘(运营)', tag: '评论', tagKind: 'info',
|
||||
project: '补水面膜', stage: 'Stage 3 · 镜头',
|
||||
target: { type: 'project', href: 'pipeline.html?product=' + encodeURIComponent('补水面膜') + '#sh3', name: '补水面膜 / 镜头 3' },
|
||||
actions: [
|
||||
{ label: '查看镜头', primary: true, action: 'goto' },
|
||||
{ label: '回复', action: 'reply' },
|
||||
],
|
||||
unread: true,
|
||||
},
|
||||
|
||||
// ─ 系统/计费类(3) ─
|
||||
{
|
||||
id: 'm-010', type: 'billing', icon: 'billing', severity: 'warn',
|
||||
title: '团队余额低于 ¥100',
|
||||
body: '当前余额 ¥87.20,按本周消耗速度估算可支撑 4-5 个视频项目。建议尽早充值以免任务中断。',
|
||||
ts: _ago(660), from: '系统', tag: '余额预警', tagKind: 'warn',
|
||||
project: '计费', stage: '余额监控',
|
||||
target: { type: 'account', href: 'account.html', name: '消费 / 充值' },
|
||||
actions: [
|
||||
{ label: '前往充值', primary: true, action: 'goto' },
|
||||
{ label: '设置预警阈值', action: 'edit' },
|
||||
],
|
||||
unread: false,
|
||||
},
|
||||
{
|
||||
id: 'm-011', type: 'system', icon: 'system',
|
||||
title: '5/25 23:00 - 5/26 01:00 · 视频生成服务例行维护',
|
||||
body: '本次维护涉及视频生成 + 三视图生成两项服务,期间提交的任务会自动延迟到维护结束后开始处理,已生成任务不受影响。',
|
||||
ts: _ago(720), from: '流·Studio 运维', tag: '公告', tagKind: 'info',
|
||||
project: '系统', stage: '维护公告',
|
||||
target: null,
|
||||
actions: [
|
||||
{ label: '我已了解', primary: true, action: 'ack' },
|
||||
],
|
||||
unread: false,
|
||||
},
|
||||
{
|
||||
id: 'm-012', type: 'system', icon: 'shield',
|
||||
title: '「祛痘精华」首版投放素材已通过平台审核',
|
||||
body: '审核耗时 1h 12min,通过 4 张图 / 2 条视频,可直接进入「投放」阶段。',
|
||||
ts: _ago(1380), from: '审核中台', tag: '审核通过', tagKind: 'ok',
|
||||
project: '祛痘精华', stage: 'Stage 5 · 投放',
|
||||
target: { type: 'project', href: 'pipeline.html?product=' + encodeURIComponent('祛痘精华'), name: '祛痘精华 · 投放' },
|
||||
actions: [
|
||||
{ label: '进入投放', primary: true, action: 'goto' },
|
||||
],
|
||||
unread: false,
|
||||
},
|
||||
];
|
||||
|
||||
/* ─── 状态 + 渲染 ─── */
|
||||
const state = { tab: 'all', onlyUnread: false, q: '', selectedId: null };
|
||||
|
||||
function _filter() {
|
||||
return MESSAGES.filter(m => {
|
||||
if (state.tab !== 'all' && m.type !== state.tab) return false;
|
||||
if (state.onlyUnread && !m.unread) return false;
|
||||
if (state.q) {
|
||||
const q = state.q.toLowerCase();
|
||||
const hay = (m.title + ' ' + m.body + ' ' + (m.project || '') + ' ' + (m.from || '')).toLowerCase();
|
||||
if (!hay.includes(q)) return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function _groupByTs(items) {
|
||||
const groups = { '今天': [], '昨天': [], '更早': [] };
|
||||
const today = new Date(NOW.getFullYear(), NOW.getMonth(), NOW.getDate());
|
||||
items.forEach(m => {
|
||||
const dDay = new Date(m.ts.getFullYear(), m.ts.getMonth(), m.ts.getDate());
|
||||
const diff = (today - dDay) / (24 * 3600 * 1000);
|
||||
if (diff === 0) groups['今天'].push(m);
|
||||
else if (diff === 1) groups['昨天'].push(m);
|
||||
else groups['更早'].push(m);
|
||||
});
|
||||
return groups;
|
||||
}
|
||||
|
||||
function _renderTabs() {
|
||||
const counts = { all: 0, task: 0, team: 0, system: 0, billing: 0 };
|
||||
MESSAGES.forEach(m => {
|
||||
if (m.unread) {
|
||||
counts.all++;
|
||||
if (counts[m.type] !== undefined) counts[m.type]++;
|
||||
}
|
||||
});
|
||||
// 显示总数(不只是未读) — 与 tabs 自身含义一致
|
||||
const tot = { all: MESSAGES.length, task: 0, team: 0, system: 0, billing: 0 };
|
||||
MESSAGES.forEach(m => { if (tot[m.type] !== undefined) tot[m.type]++; });
|
||||
document.querySelectorAll('#ms-tabs .ms-tab').forEach(btn => {
|
||||
const k = btn.dataset.tab;
|
||||
const ct = btn.querySelector('[data-ct]');
|
||||
ct.textContent = tot[k];
|
||||
btn.classList.toggle('active', k === state.tab);
|
||||
});
|
||||
const totalUnread = counts.all;
|
||||
document.getElementById('ms-head-ct').textContent = '// ' + totalUnread + ' 条未读 · ' + MESSAGES.length + ' 条总计';
|
||||
}
|
||||
|
||||
function _renderList() {
|
||||
const list = _filter();
|
||||
const listEl = document.getElementById('ms-list');
|
||||
document.getElementById('ms-list-ct').textContent = '// 显示 ' + list.length + ' 条';
|
||||
if (!list.length) {
|
||||
listEl.innerHTML = `
|
||||
<div class="ms-list-empty">
|
||||
<div class="ic"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.1V12a10 10 0 1 1-5.93-9.14"/><path d="m9 11 3 3L22 4"/></svg></div>
|
||||
<div>没有符合条件的消息</div>
|
||||
<div class="mono">// 试试切换分类 / 关闭「仅看未读」</div>
|
||||
</div>`;
|
||||
return;
|
||||
}
|
||||
const groups = _groupByTs(list);
|
||||
let html = '';
|
||||
['今天', '昨天', '更早'].forEach(g => {
|
||||
if (!groups[g].length) return;
|
||||
html += `<div class="ms-group-h">${g} · ${groups[g].length}</div>`;
|
||||
html += groups[g].map(m => _itemHtml(m)).join('');
|
||||
});
|
||||
listEl.innerHTML = html;
|
||||
listEl.querySelectorAll('.ms-item').forEach(el => {
|
||||
el.addEventListener('click', () => _select(el.dataset.id));
|
||||
});
|
||||
}
|
||||
|
||||
function _itemHtml(m) {
|
||||
const iconClass = m.severity === 'err' ? 'error' : (m.severity === 'ok' ? 'success' : m.type);
|
||||
return `
|
||||
<div class="ms-item ${m.unread ? '' : 'read'} ${state.selectedId === m.id ? 'active' : ''}" data-id="${m.id}">
|
||||
<div class="ms-item-icon ${iconClass}">${ICONS[m.icon] || ICONS.system}</div>
|
||||
<div class="ms-item-main">
|
||||
<div class="ms-item-row1">
|
||||
<span class="ms-item-unread"></span>
|
||||
<span class="ms-item-title">${m.title}</span>
|
||||
<span class="ms-item-ts">${_fmt(m.ts)}</span>
|
||||
</div>
|
||||
<div class="ms-item-body">${m.body}</div>
|
||||
${m.tag ? `<span class="ms-item-tag ${m.tagKind || ''}">${m.tag}</span>` : ''}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function _select(id) {
|
||||
const m = MESSAGES.find(x => x.id === id);
|
||||
if (!m) return;
|
||||
state.selectedId = id;
|
||||
if (m.unread) {
|
||||
m.unread = false;
|
||||
_renderTabs();
|
||||
_renderList();
|
||||
} else {
|
||||
document.querySelectorAll('#ms-list .ms-item').forEach(el => {
|
||||
el.classList.toggle('active', el.dataset.id === id);
|
||||
});
|
||||
}
|
||||
_renderDetail(m);
|
||||
}
|
||||
|
||||
function _renderDetail(m) {
|
||||
const pane = document.getElementById('ms-detail-pane');
|
||||
const propsHtml = [
|
||||
['来源', m.from || '系统'],
|
||||
['类别', { task: '任务', team: '团队', system: '系统', billing: '计费' }[m.type] || '系统'],
|
||||
['项目', m.project || '-'],
|
||||
['阶段', m.stage || '-'],
|
||||
['时间', _fmtFull(m.ts)],
|
||||
...(m.target ? [['关联资源', `<a href="${m.target.href}">${m.target.name} →</a>`]] : []),
|
||||
].map(([k, v]) => `<div class="k">${k}</div><div class="v">${v}</div>`).join('');
|
||||
|
||||
const actionsHtml = (m.actions || []).map(a => {
|
||||
const cls = a.primary ? 'btn btn-primary' : 'btn';
|
||||
return `<button class="${cls}" type="button" data-act="${a.action}">${a.label}</button>`;
|
||||
}).join('');
|
||||
|
||||
pane.innerHTML = `
|
||||
<div class="ms-detail-h">
|
||||
<div class="row1">
|
||||
<span class="kind-tag ${m.type}">${ { task: '任务', team: '团队', system: '系统', billing: '计费' }[m.type] || '系统' }</span>
|
||||
${m.tag ? `<span class="ms-item-tag ${m.tagKind || ''}" style="margin: 0;">${m.tag}</span>` : ''}
|
||||
<button class="x" type="button" id="ms-detail-close" title="关闭"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><path d="M6 6l12 12M6 18L18 6"/></svg></button>
|
||||
</div>
|
||||
<h2>${m.title}</h2>
|
||||
<div class="meta">
|
||||
<span class="from">${m.from || '系统'}</span>
|
||||
<span class="dot"></span>
|
||||
<span>${_fmtFull(m.ts)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ms-detail-b">
|
||||
<p>${m.body}</p>
|
||||
${m.quote ? `<div class="quote">${m.quote}</div>` : ''}
|
||||
<div class="ms-props">${propsHtml}</div>
|
||||
</div>
|
||||
<div class="ms-detail-f">
|
||||
<button class="btn btn-ghost" type="button" id="ms-detail-del">删除</button>
|
||||
<button class="btn btn-ghost" type="button" id="ms-detail-mute">不再接收同类</button>
|
||||
<span class="spacer"></span>
|
||||
${actionsHtml}
|
||||
</div>`;
|
||||
document.getElementById('ms-detail-close').addEventListener('click', () => {
|
||||
state.selectedId = null;
|
||||
pane.innerHTML = `
|
||||
<div class="ms-detail-empty">
|
||||
<div class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9M10 21a2 2 0 0 0 4 0"/></svg></div>
|
||||
<div>从左侧选择一条消息查看详情</div>
|
||||
<div class="mono">// 点击列表项 · 自动标为已读</div>
|
||||
</div>`;
|
||||
_renderList();
|
||||
});
|
||||
document.getElementById('ms-detail-del').addEventListener('click', () => {
|
||||
const i = MESSAGES.findIndex(x => x.id === m.id);
|
||||
if (i >= 0) MESSAGES.splice(i, 1);
|
||||
state.selectedId = null;
|
||||
Shell.toast('已删除', m.title);
|
||||
_renderTabs(); _renderList();
|
||||
document.getElementById('ms-detail-close').click();
|
||||
});
|
||||
document.getElementById('ms-detail-mute').addEventListener('click', () => {
|
||||
Shell.toast('已静音同类消息', `不再接收「${ { task: '任务', team: '团队', system: '系统', billing: '计费' }[m.type] }」类提醒 · 可在通知设置中恢复`);
|
||||
});
|
||||
pane.querySelectorAll('.ms-detail-f .btn-primary, .ms-detail-f [data-act]').forEach(btn => {
|
||||
btn.addEventListener('click', e => {
|
||||
const act = btn.dataset.act;
|
||||
if (act === 'goto' && m.target?.href) { location.href = m.target.href; return; }
|
||||
if (act === 'rerun') { Shell.toast('已发起重试', m.project + ' · 任务已重新排队'); return; }
|
||||
if (act === 'preview') { Shell.toast('打开预览', m.project + ' · 视频成片'); return; }
|
||||
if (act === 'attach') { Shell.toast('已加入项目', '请到工作台选择目标项目'); return; }
|
||||
if (act === 'log') { Shell.toast('错误日志', 'prompt=tokens 8124 / max=8000 · type=413'); return; }
|
||||
if (act === 'reply') { Shell.toast('打开评论', '可在镜头详情页直接回复'); return; }
|
||||
if (act === 'ack') { Shell.toast('已确认'); return; }
|
||||
if (act === 'edit') { Shell.toast('打开设置', '权限 / 阈值 · 可在设置中调整'); return; }
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* ─── 事件绑定 ─── */
|
||||
document.querySelectorAll('#ms-tabs .ms-tab').forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
state.tab = btn.dataset.tab;
|
||||
_renderTabs(); _renderList();
|
||||
});
|
||||
});
|
||||
const ouBtn = document.getElementById('ms-only-unread');
|
||||
ouBtn.addEventListener('click', () => {
|
||||
state.onlyUnread = !state.onlyUnread;
|
||||
ouBtn.classList.toggle('on', state.onlyUnread);
|
||||
_renderList();
|
||||
});
|
||||
document.getElementById('ms-search-input').addEventListener('input', e => {
|
||||
state.q = e.target.value.trim();
|
||||
_renderList();
|
||||
});
|
||||
document.getElementById('ms-mark-all').addEventListener('click', () => {
|
||||
MESSAGES.forEach(m => { m.unread = false; });
|
||||
Shell.toast('已全部标为已读', MESSAGES.length + ' 条');
|
||||
_renderTabs(); _renderList();
|
||||
});
|
||||
document.getElementById('ms-settings').addEventListener('click', () => {
|
||||
location.href = 'settings.html';
|
||||
});
|
||||
document.getElementById('ms-group-toggle').addEventListener('click', () => {
|
||||
Shell.toast('排序', '当前按时间分组 · 后续支持按项目分组');
|
||||
});
|
||||
|
||||
/* 首次渲染 */
|
||||
_renderTabs();
|
||||
_renderList();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -386,12 +386,12 @@
|
||||
<div class="ti-row">
|
||||
<span class="ti">商品空间</span>
|
||||
<button class="add" type="button" title="新建商品">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Q1-A · 搜索框 -->
|
||||
<div class="dma-search">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<input type="text" placeholder="搜索商品 / 分类">
|
||||
</div>
|
||||
</div>
|
||||
@ -444,10 +444,10 @@
|
||||
|
||||
<!-- Q1-B · 全部商品入口(贴底) -->
|
||||
<button class="dma-all" type="button">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 9h18M9 4v16"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 9h18M9 4v16"/></svg>
|
||||
全部商品
|
||||
<span class="ct">24 个</span>
|
||||
<svg style="margin-left:4px" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
|
||||
<svg style="margin-left:4px" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
|
||||
</button>
|
||||
</aside>
|
||||
|
||||
@ -538,7 +538,7 @@
|
||||
<span>余额 ¥327.40</span>
|
||||
</div>
|
||||
<button class="dma-gen" type="button">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3l1.7 4.6L18 9l-4.3 1.4L12 15l-1.7-4.6L6 9l4.3-1.4L12 3z"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3l1.7 4.6L18 9l-4.3 1.4L12 15l-1.7-4.6L6 9l4.3-1.4L12 3z"/></svg>
|
||||
立即生成 · 透真补水面膜 × Ava
|
||||
</button>
|
||||
</div>
|
||||
@ -560,9 +560,9 @@
|
||||
<div class="info">透真补水面膜 <span class="sep">·</span> 3:4 <span class="sep">·</span> 3 分钟前 <span class="sep">·</span> ¥1.20</div>
|
||||
</div>
|
||||
<div class="ops">
|
||||
<button type="button" title="全部重跑"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 11-3-6.7L21 8M21 3v5h-5"/></svg></button>
|
||||
<button type="button" title="全部下载"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg></button>
|
||||
<button type="button" title="加入资产库"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21l-7-5-7 5V5a2 2 0 012-2h10a2 2 0 012 2z"/></svg></button>
|
||||
<button type="button" title="全部重跑"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 11-3-6.7L21 8M21 3v5h-5"/></svg></button>
|
||||
<button type="button" title="全部下载"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg></button>
|
||||
<button type="button" title="加入资产库"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21l-7-5-7 5V5a2 2 0 012-2h10a2 2 0 012 2z"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dma-batch-grid">
|
||||
@ -582,9 +582,9 @@
|
||||
<div class="info">透真补水面膜 <span class="sep">·</span> 3:4 <span class="sep">·</span> 12 分钟前 <span class="sep">·</span> ¥1.20</div>
|
||||
</div>
|
||||
<div class="ops">
|
||||
<button type="button" title="全部重跑"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 11-3-6.7L21 8M21 3v5h-5"/></svg></button>
|
||||
<button type="button" title="全部下载"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg></button>
|
||||
<button type="button" title="加入资产库"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21l-7-5-7 5V5a2 2 0 012-2h10a2 2 0 012 2z"/></svg></button>
|
||||
<button type="button" title="全部重跑"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 11-3-6.7L21 8M21 3v5h-5"/></svg></button>
|
||||
<button type="button" title="全部下载"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg></button>
|
||||
<button type="button" title="加入资产库"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21l-7-5-7 5V5a2 2 0 012-2h10a2 2 0 012 2z"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dma-batch-grid">
|
||||
@ -604,7 +604,7 @@
|
||||
<div class="info">透真补水面膜 <span class="sep">·</span> 3:4 <span class="sep">·</span> 刚刚 <span class="sep">·</span> 生成中</div>
|
||||
</div>
|
||||
<div class="ops">
|
||||
<button type="button" title="取消"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M6 6l12 12M6 18L18 6"/></svg></button>
|
||||
<button type="button" title="取消"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 6l12 12M6 18L18 6"/></svg></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dma-batch-grid">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
2602
电商AI平台/pipeline.html
2602
电商AI平台/pipeline.html
File diff suppressed because one or more lines are too long
@ -890,28 +890,51 @@
|
||||
color: var(--accent-crimson, #c43d3d);
|
||||
background: rgba(196, 61, 61, .05);
|
||||
}
|
||||
/* 右上 hover 操作组 */
|
||||
/* 右上 hover 操作组 · 同 spec §4.18 .gen-image-actions */
|
||||
.pv-platform-section .ps-grid .mp-result .cell-ops {
|
||||
position: absolute; top: 6px; right: 6px;
|
||||
display: flex; gap: 4px;
|
||||
position: absolute; top: 8px; right: 8px;
|
||||
display: flex; gap: 2px;
|
||||
padding: 2px;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-md);
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,.08);
|
||||
opacity: 0;
|
||||
transition: opacity var(--t-base);
|
||||
z-index: 2;
|
||||
}
|
||||
.pv-platform-section .ps-grid .mp-result:hover .cell-ops { opacity: 1; }
|
||||
.pv-platform-section .ps-grid .mp-result .cell-ops button {
|
||||
width: 26px; height: 26px;
|
||||
background: rgba(255, 255, 255, .92);
|
||||
border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-sm);
|
||||
color: var(--accent-black);
|
||||
width: 28px; height: 28px;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 6px;
|
||||
color: var(--black-alpha-56);
|
||||
cursor: pointer;
|
||||
display: grid; place-items: center;
|
||||
backdrop-filter: blur(4px);
|
||||
transition: border-color var(--t-base), color var(--t-base);
|
||||
transition: background var(--t-base), color var(--t-base);
|
||||
}
|
||||
.pv-platform-section .ps-grid .mp-result .cell-ops button:hover { border-color: var(--heat); color: var(--heat); }
|
||||
.pv-platform-section .ps-grid .mp-result .cell-ops button svg { width: 12px; height: 12px; }
|
||||
.pv-platform-section .ps-grid .mp-result .cell-ops button:hover {
|
||||
background: var(--black-alpha-4);
|
||||
color: var(--accent-black);
|
||||
}
|
||||
.pv-platform-section .ps-grid .mp-result .cell-ops button svg { width: 14px; height: 14px; }
|
||||
.pv-platform-section .ps-grid .mp-result.adopted .cell-ops .r-check { display: none; }
|
||||
/* 中央反馈 toast · 同 spec §4.18 .gen-image-feedback */
|
||||
.pv-platform-section .ps-grid .mp-result .cell-feedback {
|
||||
position: absolute; inset: 0;
|
||||
display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
|
||||
background: rgba(38, 38, 38, .88);
|
||||
color: var(--accent-white);
|
||||
border-radius: var(--r-md);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity .2s var(--t-base, ease);
|
||||
z-index: 3;
|
||||
}
|
||||
.pv-platform-section .ps-grid .mp-result.show-feedback .cell-feedback { opacity: 1; }
|
||||
.pv-platform-section .ps-grid .mp-result .cell-feedback svg { width: 20px; height: 20px; }
|
||||
.pv-platform-section .ps-grid .mp-result .cell-feedback span { font-size: 12.5px; font-weight: 500; letter-spacing: .02em; }
|
||||
.pv-platform-section .ps-grid .mp-result .cell-more-wrap { position: relative; }
|
||||
.pv-platform-section .ps-grid .mp-result .cell-more-menu {
|
||||
position: absolute; top: calc(100% + 4px); right: 0;
|
||||
@ -1008,25 +1031,24 @@
|
||||
color: var(--black-alpha-48); letter-spacing: .02em;
|
||||
}
|
||||
.pc-pv-batch .summary b { color: var(--heat); font-weight: 700; }
|
||||
/* 底栏按钮 · 同 spec §4.18 + image-optimize .io-msg-ops button */
|
||||
.pc-pv-batch .pill-btn {
|
||||
height: 34px;
|
||||
padding: 0 18px;
|
||||
height: 30px;
|
||||
padding: 0 12px;
|
||||
display: inline-flex; align-items: center; gap: 6px;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--black-alpha-12);
|
||||
border-radius: var(--r-pill);
|
||||
border: 1px solid var(--border-faint);
|
||||
border-radius: var(--r-md);
|
||||
color: var(--accent-black);
|
||||
font-family: inherit; font-size: 12.5px;
|
||||
cursor: pointer;
|
||||
transition: background var(--t-base), border-color var(--t-base), color var(--t-base);
|
||||
}
|
||||
.pc-pv-batch .pill-btn:hover { background: var(--background-lighter); border-color: var(--black-alpha-24); }
|
||||
.pc-pv-batch .pill-btn.primary {
|
||||
background: var(--heat); color: #fff; border-color: var(--heat);
|
||||
.pc-pv-batch .pill-btn:hover {
|
||||
border-color: var(--heat-20); color: var(--heat); background: var(--heat-12);
|
||||
}
|
||||
.pc-pv-batch .pill-btn.primary:hover { filter: brightness(.94); }
|
||||
.pc-pv-batch .pill-btn svg { width: 13px; height: 13px; }
|
||||
.pc-pv-batch .pill-btn.icon { width: 34px; padding: 0; justify-content: center; }
|
||||
.pc-pv-batch .pill-btn.icon { width: 30px; padding: 0; justify-content: center; }
|
||||
/* 批次更多气泡 */
|
||||
.pc-pv-batch .batch-more-wrap { position: relative; display: inline-flex; }
|
||||
.pc-pv-batch .batch-more-menu {
|
||||
@ -1102,16 +1124,16 @@
|
||||
<!-- 顶部 · 返回 + 折叠 (跟图片创作风格一致) -->
|
||||
<div class="pc-side-top">
|
||||
<button class="back-pill" type="button" onclick="history.length > 1 ? history.back() : location.href='asset-factory.html'" title="返回">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M15 18l-6-6 6-6"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15 18l-6-6 6-6"/></svg>
|
||||
<span>返回</span>
|
||||
</button>
|
||||
<button class="fold" type="button" title="折叠侧栏" style="margin-left:auto">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M9 3v18"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M9 3v18"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="pc-ps-h">
|
||||
<div class="pc-ps-search">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<input type="text" id="ps-search-input" placeholder="搜索商品 / 分类">
|
||||
</div>
|
||||
</div>
|
||||
@ -1125,10 +1147,10 @@
|
||||
</div>
|
||||
<div class="pc-ps-list" id="ps-list"></div>
|
||||
<button class="pc-ps-all" type="button" id="ps-all-btn">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 9h18M9 4v16"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 9h18M9 4v16"/></svg>
|
||||
<span>全部商品</span>
|
||||
<span class="ct" id="ps-all-ct">0 个</span>
|
||||
<svg style="margin-left:0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
|
||||
<svg style="margin-left:0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
|
||||
</button>
|
||||
</aside>
|
||||
|
||||
@ -1144,7 +1166,7 @@
|
||||
<span class="spacer"></span>
|
||||
<div class="tb-search-wrap" id="pc-search-wrap">
|
||||
<button class="search-btn" type="button" title="搜索批次/平台" id="pc-search-toggle">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
</button>
|
||||
<input type="text" class="tb-search-input" id="pc-search-input" placeholder="搜索批次/平台…" autocomplete="off">
|
||||
</div>
|
||||
@ -1373,11 +1395,11 @@
|
||||
<div class="pl-main">
|
||||
<div class="pl-toolbar">
|
||||
<div class="search">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<input type="text" id="pl-search-input" placeholder="搜索商品名">
|
||||
</div>
|
||||
<button class="btn-new" type="button" id="pl-new-btn">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg>
|
||||
新建商品
|
||||
</button>
|
||||
</div>
|
||||
@ -1518,10 +1540,10 @@ function renderProdLib() {
|
||||
<div class="pl-card${_plDraft === p.id ? ' selected' : ''}" data-id="${p.id}">
|
||||
<div class="pl-card-actions">
|
||||
<button class="pl-act" type="button" data-edit="${p.id}" title="编辑商品" aria-label="编辑">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 013 3L7 19l-4 1 1-4 12.5-12.5z"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 013 3L7 19l-4 1 1-4 12.5-12.5z"/></svg>
|
||||
</button>
|
||||
<button class="pl-act danger" type="button" data-del="${p.id}" title="删除商品" aria-label="删除">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="pl-check"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></div>
|
||||
@ -1584,9 +1606,9 @@ function renderProdImgs(n) {
|
||||
if (ct) ct.textContent = n;
|
||||
let html = '';
|
||||
for (let i = 0; i < n; i++) {
|
||||
html += `<div class="thumb"><span class="ph-frame">1:1</span><button class="rm" type="button" title="删除" data-idx="${i}"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M6 6l12 12M6 18L18 6"/></svg></button></div>`;
|
||||
html += `<div class="thumb"><span class="ph-frame">1:1</span><button class="rm" type="button" title="删除" data-idx="${i}"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M6 6l12 12M6 18L18 6"/></svg></button></div>`;
|
||||
}
|
||||
html += `<div class="img-upload" id="pcf-img-add" title="上传图片"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg></div>`;
|
||||
html += `<div class="img-upload" id="pcf-img-add" title="上传图片"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg></div>`;
|
||||
grid.innerHTML = html;
|
||||
grid.querySelectorAll('.thumb .rm').forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
@ -1621,7 +1643,7 @@ function openEditProductDrawer(id) {
|
||||
li.innerHTML = `
|
||||
<span class="num">${i + 1}</span>
|
||||
<input value="${b.replace(/"/g, '"')}">
|
||||
<button class="rm" type="button" aria-label="删除"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6 6l12 12M6 18L18 6"/></svg></button>
|
||||
<button class="rm" type="button" aria-label="删除"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 6l12 12M6 18L18 6"/></svg></button>
|
||||
`;
|
||||
ul.insertBefore(li, addLi);
|
||||
li.querySelector('.rm').addEventListener('click', () => { li.remove(); renumberBullets(); });
|
||||
@ -1654,7 +1676,7 @@ document.getElementById('pcf-add-input').addEventListener('keydown', e => {
|
||||
li.innerHTML = `
|
||||
<span class="num">0</span>
|
||||
<input value="${v.replace(/"/g, '"')}">
|
||||
<button class="rm" type="button" aria-label="删除"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6 6l12 12M6 18L18 6"/></svg></button>
|
||||
<button class="rm" type="button" aria-label="删除"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 6l12 12M6 18L18 6"/></svg></button>
|
||||
`;
|
||||
ul.insertBefore(li, addLi);
|
||||
li.querySelector('.rm').addEventListener('click', () => { li.remove(); renumberBullets(); });
|
||||
@ -1855,13 +1877,14 @@ function renderPreviewSections() {
|
||||
}
|
||||
|
||||
// 渲染生成结果 (点立即生成时调,带 hover overlay + 批量 bar)
|
||||
const RERUN_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>';
|
||||
const RERUN_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>';
|
||||
const ADOPT_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>';
|
||||
const CELL_RERUN_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 11-3-6.7L21 8M21 3v5h-5"/></svg>';
|
||||
const CELL_DL_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>';
|
||||
const CELL_MORE_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="5" cy="12" r="1.2"/><circle cx="12" cy="12" r="1.2"/><circle cx="19" cy="12" r="1.2"/></svg>';
|
||||
const CELL_ADOPT_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21l-7-5-7 5V5a2 2 0 012-2h10a2 2 0 012 2z"/></svg>';
|
||||
const CELL_DEL_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>';
|
||||
const CELL_RERUN_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 11-3-6.7L21 8M21 3v5h-5"/></svg>';
|
||||
const CELL_DL_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>';
|
||||
const CELL_MORE_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="5" cy="12" r="1.2"/><circle cx="12" cy="12" r="1.2"/><circle cx="19" cy="12" r="1.2"/></svg>';
|
||||
const CELL_ADOPT_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21l-7-5-7 5V5a2 2 0 012-2h10a2 2 0 012 2z"/></svg>';
|
||||
const CELL_DEL_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>';
|
||||
const CELL_EDIT_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 113 3L7 19l-4 1 1-4z"/></svg>';
|
||||
|
||||
let _batchSeq = 0;
|
||||
function appendBatch(n, kind) {
|
||||
@ -1893,6 +1916,10 @@ function appendBatch(n, kind) {
|
||||
<div class="mp-result gen" data-idx="${i}">
|
||||
<div class="mp-r-thumb"><span class="ph-frame">${c.dataset.name}</span></div>
|
||||
<span class="adopt-badge">已采用</span>
|
||||
<div class="cell-feedback" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
|
||||
<span>已采用</span>
|
||||
</div>
|
||||
<div class="cell-ops">
|
||||
<button class="r-rerun" type="button" title="再次生成" aria-label="再次生成">${CELL_RERUN_SVG}</button>
|
||||
<button class="r-dl" type="button" title="下载" aria-label="下载">${CELL_DL_SVG}</button>
|
||||
@ -1908,14 +1935,14 @@ function appendBatch(n, kind) {
|
||||
`).join('')}
|
||||
</div>
|
||||
<div class="pc-pv-batch batch-foot">
|
||||
<button class="pill-btn edit-batch" type="button" title="重新编辑">
|
||||
${CELL_EDIT_SVG}
|
||||
<span>重新编辑</span>
|
||||
</button>
|
||||
<button class="pill-btn rerun-batch" type="button" title="再次生成这一批">
|
||||
${CELL_RERUN_SVG}
|
||||
<span>再次生成</span>
|
||||
</button>
|
||||
<button class="pill-btn primary adopt-batch" type="button" title="采用这一批">
|
||||
${ADOPT_SVG}
|
||||
<span>全部采用 · <span class="adopted">0</span>/<span class="total">${n}</span></span>
|
||||
</button>
|
||||
<div class="batch-more-wrap">
|
||||
<button class="pill-btn icon batch-more" type="button" title="更多" aria-label="更多">${CELL_MORE_SVG}</button>
|
||||
<div class="batch-more-menu" role="menu">
|
||||
@ -1962,17 +1989,22 @@ function appendBatch(n, kind) {
|
||||
else updateBatchSummary();
|
||||
Shell.toast('已删除');
|
||||
}));
|
||||
section.querySelector('.edit-batch').addEventListener('click', () => {
|
||||
const form = document.querySelector('.pc-form');
|
||||
if (form) form.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
Shell.toast('重新编辑', '请在左侧调整平台 / 张数后再生成');
|
||||
});
|
||||
section.querySelector('.rerun-batch').addEventListener('click', () => {
|
||||
appendBatch(n, 'rerun-all');
|
||||
Shell.toast('再次生成', n + ' 张图重新生成中 · 新批次已追加');
|
||||
});
|
||||
section.querySelector('.adopt-batch').addEventListener('click', () => {
|
||||
const _adoptAll = () => {
|
||||
const cards = section.querySelectorAll('.mp-result:not(.adopted)');
|
||||
if (!cards.length) { Shell.toast('该批次已全部采用'); return; }
|
||||
cards.forEach(c => { c.classList.remove('gen'); c.classList.add('adopted'); });
|
||||
updateBatchSummary();
|
||||
Shell.toast('已全部采用', cards.length + ' 张图入对应商品的 AI 素材 · 扣 ¥' + (cards.length * UNIT_PRICE).toFixed(2));
|
||||
});
|
||||
Shell.toast('已全部加入资产库', cards.length + ' 张图入对应商品的 AI 素材 · 扣 ¥' + (cards.length * UNIT_PRICE).toFixed(2));
|
||||
};
|
||||
// 批次「更多」按钮 → 开/合 menu
|
||||
const _bMoreBtn = section.querySelector('.batch-more');
|
||||
const _bMoreWrap = section.querySelector('.batch-more-wrap');
|
||||
@ -1987,7 +2019,7 @@ function appendBatch(n, kind) {
|
||||
section.querySelector('.batch-save-all').addEventListener('click', e => {
|
||||
e.stopPropagation();
|
||||
if (_bMoreWrap) _bMoreWrap.classList.remove('open');
|
||||
section.querySelector('.adopt-batch').click();
|
||||
_adoptAll();
|
||||
});
|
||||
section.querySelector('.batch-del').addEventListener('click', e => {
|
||||
e.stopPropagation();
|
||||
@ -2016,7 +2048,9 @@ function adoptOne(card) {
|
||||
if (!card || card.classList.contains('adopted')) return;
|
||||
card.classList.remove('gen');
|
||||
card.classList.add('adopted');
|
||||
Shell.toast('已加入资产库', '入对应商品的 AI 素材 · 扣 ¥' + UNIT_PRICE.toFixed(2));
|
||||
// spec §4.18 · 就地中央反馈
|
||||
card.classList.add('show-feedback');
|
||||
setTimeout(() => card.classList.remove('show-feedback'), 1500);
|
||||
updateBatchSummary();
|
||||
}
|
||||
// 点击页面其它位置 → 关闭单图/批次 more menu
|
||||
|
||||
@ -306,7 +306,7 @@ function renderPhotos() {
|
||||
<span class="slot-label">${SLOT_LABELS[i]}</span>
|
||||
${i === 0 ? '<span class="slot-main">MAIN</span>' : ''}
|
||||
<button class="slot-x" type="button" data-i="${i}" aria-label="移除">
|
||||
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 4l8 8M12 4l-8 8"/></svg>
|
||||
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M4 4l8 8M12 4l-8 8"/></svg>
|
||||
</button>
|
||||
`;
|
||||
} else if (i === photos.length) {
|
||||
|
||||
@ -442,9 +442,13 @@
|
||||
}
|
||||
.ov-images-sub .thumb img { width: 100%; height: 100%; object-fit: cover; }
|
||||
|
||||
/* 快速操作 · 2 段:图片生成(3 等比 CTA)+ 视频生成(1 CTA) */
|
||||
/* 快速操作 · 2 段:图片生成(3 等比 CTA)+ 视频生成(1 CTA) · 两段等高填充容器 */
|
||||
.ov-actions { display: flex; flex-direction: column; }
|
||||
.ov-actions .qa-section { margin-bottom: 14px; }
|
||||
.ov-actions .qa-section {
|
||||
margin-bottom: 14px;
|
||||
display: flex; flex-direction: column;
|
||||
flex: 1 1 0; min-height: 0;
|
||||
}
|
||||
.ov-actions .qa-section:last-child { margin-bottom: 0; }
|
||||
.ov-actions .qa-section-h {
|
||||
font-family: var(--font-mono);
|
||||
@ -458,10 +462,16 @@
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 8px;
|
||||
flex: 1 1 0; min-height: 0;
|
||||
}
|
||||
.ov-actions .qa-row-1 {
|
||||
display: flex;
|
||||
flex: 1 1 0; min-height: 0;
|
||||
}
|
||||
.ov-actions .qa-row-1 .qa-item { width: 100%; }
|
||||
.qa-item {
|
||||
display: flex; flex-direction: column; align-items: center; gap: 8px;
|
||||
display: flex; flex-direction: column;
|
||||
align-items: center; justify-content: center; gap: 8px;
|
||||
padding: 14px 10px;
|
||||
background: var(--background-lighter);
|
||||
border: 1px solid var(--border-faint);
|
||||
@ -925,7 +935,7 @@
|
||||
<!-- AI 生成三视图 · 按钮 + 弹出 panel(view 模式可见) -->
|
||||
<div class="ov-tri-wrap">
|
||||
<button class="ov-edit ov-tri-trigger" type="button" id="ov-tri-btn" title="AI 生成商品三视图" aria-haspopup="dialog" aria-expanded="false">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3l1.8 4.2L18 9l-4.2 1.8L12 15l-1.8-4.2L6 9l4.2-1.8L12 3z"/><path d="M19 14l.9 2.1L22 17l-2.1.9L19 20l-.9-2.1L16 17l2.1-.9L19 14z"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3l1.8 4.2L18 9l-4.2 1.8L12 15l-1.8-4.2L6 9l4.2-1.8L12 3z"/><path d="M19 14l.9 2.1L22 17l-2.1.9L19 20l-.9-2.1L16 17l2.1-.9L19 14z"/></svg>
|
||||
AI 生成三视图
|
||||
</button>
|
||||
<div class="ov-tri-pop" id="ov-tri-pop" role="dialog" aria-label="AI 生成三视图">
|
||||
@ -950,13 +960,13 @@
|
||||
</div>
|
||||
<!-- view 模式: 单个 [编辑信息] -->
|
||||
<button class="ov-edit ov-edit-single" type="button" id="ov-edit-btn" title="编辑商品信息">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 013 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 013 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>
|
||||
编辑信息
|
||||
</button>
|
||||
<!-- edit 模式: [重置] [取消] [保存] -->
|
||||
<div class="ov-edit-group">
|
||||
<button class="ov-edit" type="button" id="ov-reset-btn" title="重置为修改前">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 4v5h5"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 4v5h5"/></svg>
|
||||
重置
|
||||
</button>
|
||||
<button class="ov-edit" type="button" id="ov-cancel-btn">取消</button>
|
||||
@ -1043,15 +1053,15 @@
|
||||
<div class="qa-section-h">// 图片生成</div>
|
||||
<div class="qa-row-3">
|
||||
<div class="qa-item" data-go="model-photo" role="button" tabindex="0">
|
||||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="8" r="4"/><path d="M4 21v-2a4 4 0 014-4h8a4 4 0 014 4v2"/></svg></span>
|
||||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="8" r="4"/><path d="M4 21v-2a4 4 0 014-4h8a4 4 0 014 4v2"/></svg></span>
|
||||
模特上身图
|
||||
</div>
|
||||
<div class="qa-item" data-go="platform-cover" role="button" tabindex="0">
|
||||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 3v18"/></svg></span>
|
||||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 3v18"/></svg></span>
|
||||
平台套图
|
||||
</div>
|
||||
<div class="qa-item" data-go="image-optimize" role="button" tabindex="0">
|
||||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v18M3 12h18M5 5l14 14M5 19l14-14"/></svg></span>
|
||||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v18M3 12h18M5 5l14 14M5 19l14-14"/></svg></span>
|
||||
图片创作
|
||||
</div>
|
||||
</div>
|
||||
@ -1060,7 +1070,7 @@
|
||||
<div class="qa-section-h">// 视频生成</div>
|
||||
<div class="qa-row-1">
|
||||
<div class="qa-item primary" data-go="projects-new" role="button" tabindex="0">
|
||||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="M16 10l6-3v10l-6-3z"/></svg></span>
|
||||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="M16 10l6-3v10l-6-3z"/></svg></span>
|
||||
生成视频
|
||||
</div>
|
||||
</div>
|
||||
@ -1092,10 +1102,10 @@
|
||||
<div class="right">
|
||||
<div class="view-tog">
|
||||
<button type="button" class="active" title="网格视图">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/></svg>
|
||||
</button>
|
||||
<button type="button" title="列表视图">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M3 6h18M3 12h18M3 18h18"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M3 6h18M3 12h18M3 18h18"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
<button class="filter" type="button" data-key="sort">
|
||||
@ -1944,7 +1954,7 @@
|
||||
: `${ver.label} · 预览中(未采用)`;
|
||||
foot.innerHTML = `
|
||||
<button class="ov-edit" type="button" id="ov-tri-rerun" style="height:28px;">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 4v5h5"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 4v5h5"/></svg>
|
||||
重跑
|
||||
</button>
|
||||
<button class="ov-edit ${isAdopted ? '' : 'primary'}" type="button" id="ov-tri-adopt" style="height:28px;" ${isAdopted ? 'disabled title="此版本已采用"' : 'title="将此版本设为唯一通过版本,其他版本变为不通过"'}>
|
||||
|
||||
@ -520,7 +520,7 @@
|
||||
<div class="name">透真玻尿酸补水面膜</div>
|
||||
<div class="meta">[ 美妆个护 ] · ¥39.9 · 22-32 岁女性</div>
|
||||
</div>
|
||||
<button class="edit" onclick="alert('行内编辑商品信息 · demo')">
|
||||
<button class="edit" onclick="Shell.toast('打开编辑面板','跳转至 product-detail.html · 行内编辑商品信息');setTimeout(()=>location.href='product-detail.html',600);">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
|
||||
编辑
|
||||
</button>
|
||||
@ -549,7 +549,7 @@
|
||||
</div>
|
||||
<div class="ov-photo" style="background-image: linear-gradient(135deg,#dceafe 0%, #c3e0fe 100%);" title="包装"></div>
|
||||
<div class="ov-photo" style="background-image: linear-gradient(135deg,#e7e3d5 0%, #d6d1c0 100%);" title="质地"></div>
|
||||
<div class="ov-photo add" onclick="alert('上传新图 · demo')" title="添加">
|
||||
<div class="ov-photo add" onclick="document.getElementById('__ov-photo-input').click()" title="添加"><input type="file" id="__ov-photo-input" accept="image/*" multiple hidden onchange="if(this.files.length)Shell.toast('已上传 '+this.files.length+' 张','补充图已加入商品图册')">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M12 5v14M5 12h14"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
@ -863,7 +863,7 @@ function renderAssets() {
|
||||
</div>
|
||||
${a.skeleton ? '' : `
|
||||
<div class="a-actions">
|
||||
<button title="预览" onclick="event.stopPropagation();alert('预览 · demo')">
|
||||
<button title="预览" onclick="event.stopPropagation();(window.Shell&&Shell._openLightbox?Shell._openLightbox('','${a.id} · 预览'):Shell.toast('打开预览','${a.id}'))">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
</button>
|
||||
<button title="重跑" onclick="event.stopPropagation();regen('${a.id}')">
|
||||
|
||||
@ -664,10 +664,10 @@
|
||||
<span>// 显示 <span class="count">7</span> / 7 个商品</span>
|
||||
<div class="view-tog" style="margin-left:auto" id="view-tog">
|
||||
<button type="button" class="active" data-view="grid" title="网格视图">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/></svg>
|
||||
</button>
|
||||
<button type="button" data-view="list" title="列表视图">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><path d="M3 6h18M3 12h18M3 18h18"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M3 6h18M3 12h18M3 18h18"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -677,7 +677,7 @@
|
||||
<div class="product-grid" id="product-grid">
|
||||
<div class="product-card" data-cat="美妆个护" data-name="透真玻尿酸补水面膜" data-tags="熬夜党 敏感肌" data-added="1" data-assets="124" data-videos="36" data-date="2026-05-15" onclick="location.href='product-detail.html?t='+Date.now()">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除商品" onclick="event.stopPropagation();" data-action="delete-product"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除商品" onclick="event.stopPropagation();" data-action="delete-product"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder product-thumb"><span class="ph-frame">补水面膜 · 1200×800</span></div>
|
||||
<div class="product-body">
|
||||
<div class="product-name">透真玻尿酸补水面膜</div>
|
||||
@ -686,12 +686,12 @@
|
||||
</div>
|
||||
<div class="product-footer">
|
||||
<span class="stat">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="10" r="2"/><path d="M21 17l-5-5-9 9"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="10" r="2"/><path d="M21 17l-5-5-9 9"/></svg>
|
||||
素材 <b>124</b>
|
||||
</span>
|
||||
<span class="sep">·</span>
|
||||
<span class="stat">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="M16 10l6-3v10l-6-3z"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="M16 10l6-3v10l-6-3z"/></svg>
|
||||
视频 <b>36</b>
|
||||
</span>
|
||||
|
||||
@ -700,7 +700,7 @@
|
||||
|
||||
<div class="product-card" data-cat="数码 3C" data-name="南卡 Lite Pro 蓝牙耳机" data-tags="通勤 运动" data-added="2" data-assets="96" data-videos="28" data-date="2026-05-12" onclick="location.href='product-detail.html?t='+Date.now()">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除商品" onclick="event.stopPropagation();" data-action="delete-product"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除商品" onclick="event.stopPropagation();" data-action="delete-product"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder product-thumb"><span class="ph-frame">蓝牙耳机 · 1200×800</span></div>
|
||||
<div class="product-body">
|
||||
<div class="product-name">南卡 Lite Pro 蓝牙耳机</div>
|
||||
@ -709,12 +709,12 @@
|
||||
</div>
|
||||
<div class="product-footer">
|
||||
<span class="stat">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="10" r="2"/><path d="M21 17l-5-5-9 9"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="10" r="2"/><path d="M21 17l-5-5-9 9"/></svg>
|
||||
素材 <b>96</b>
|
||||
</span>
|
||||
<span class="sep">·</span>
|
||||
<span class="stat">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="M16 10l6-3v10l-6-3z"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="M16 10l6-3v10l-6-3z"/></svg>
|
||||
视频 <b>28</b>
|
||||
</span>
|
||||
|
||||
@ -723,7 +723,7 @@
|
||||
|
||||
<div class="product-card" data-cat="食品饮料" data-name="滋啦速食牛肉面 6 桶装" data-tags="加班 独居" data-added="3" data-assets="96" data-videos="24" data-date="2026-05-10" onclick="location.href='product-detail.html?t='+Date.now()">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除商品" onclick="event.stopPropagation();" data-action="delete-product"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除商品" onclick="event.stopPropagation();" data-action="delete-product"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder product-thumb"><span class="ph-frame">速食牛肉面 · 1200×800</span></div>
|
||||
<div class="product-body">
|
||||
<div class="product-name">滋啦速食牛肉面 · 6 桶装</div>
|
||||
@ -732,12 +732,12 @@
|
||||
</div>
|
||||
<div class="product-footer">
|
||||
<span class="stat">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="10" r="2"/><path d="M21 17l-5-5-9 9"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="10" r="2"/><path d="M21 17l-5-5-9 9"/></svg>
|
||||
素材 <b>96</b>
|
||||
</span>
|
||||
<span class="sep">·</span>
|
||||
<span class="stat">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="M16 10l6-3v10l-6-3z"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="M16 10l6-3v10l-6-3z"/></svg>
|
||||
视频 <b>24</b>
|
||||
</span>
|
||||
|
||||
@ -746,7 +746,7 @@
|
||||
|
||||
<div class="product-card" data-cat="美妆个护" data-name="透真清透物理防晒霜" data-tags="SPF50 通勤" data-added="4" data-assets="76" data-videos="18" data-date="2026-05-08" onclick="location.href='product-detail.html?t='+Date.now()">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除商品" onclick="event.stopPropagation();" data-action="delete-product"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除商品" onclick="event.stopPropagation();" data-action="delete-product"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder product-thumb"><span class="ph-frame">防晒霜 · 1200×800</span></div>
|
||||
<div class="product-body">
|
||||
<div class="product-name">透真清透物理防晒霜</div>
|
||||
@ -755,12 +755,12 @@
|
||||
</div>
|
||||
<div class="product-footer">
|
||||
<span class="stat">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="10" r="2"/><path d="M21 17l-5-5-9 9"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="10" r="2"/><path d="M21 17l-5-5-9 9"/></svg>
|
||||
素材 <b>76</b>
|
||||
</span>
|
||||
<span class="sep">·</span>
|
||||
<span class="stat">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="M16 10l6-3v10l-6-3z"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="M16 10l6-3v10l-6-3z"/></svg>
|
||||
视频 <b>18</b>
|
||||
</span>
|
||||
|
||||
@ -769,7 +769,7 @@
|
||||
|
||||
<div class="product-card" data-cat="食品饮料" data-name="三顿半同款冻干咖啡粉" data-tags="提神 早八" data-added="5" data-assets="68" data-videos="21" data-date="2026-05-05" onclick="location.href='product-detail.html?t='+Date.now()">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除商品" onclick="event.stopPropagation();" data-action="delete-product"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除商品" onclick="event.stopPropagation();" data-action="delete-product"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder product-thumb"><span class="ph-frame">咖啡冻干粉 · 1200×800</span></div>
|
||||
<div class="product-body">
|
||||
<div class="product-name">三顿半同款冻干咖啡粉</div>
|
||||
@ -778,12 +778,12 @@
|
||||
</div>
|
||||
<div class="product-footer">
|
||||
<span class="stat">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="10" r="2"/><path d="M21 17l-5-5-9 9"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="10" r="2"/><path d="M21 17l-5-5-9 9"/></svg>
|
||||
素材 <b>68</b>
|
||||
</span>
|
||||
<span class="sep">·</span>
|
||||
<span class="stat">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="M16 10l6-3v10l-6-3z"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="M16 10l6-3v10l-6-3z"/></svg>
|
||||
视频 <b>21</b>
|
||||
</span>
|
||||
|
||||
@ -792,7 +792,7 @@
|
||||
|
||||
<div class="product-card" data-cat="家居家电" data-name="小熊 4L 可视空气炸锅" data-tags="小户型 健康" data-added="6" data-assets="54" data-videos="16" data-date="2026-05-03" onclick="location.href='product-detail.html?t='+Date.now()">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除商品" onclick="event.stopPropagation();" data-action="delete-product"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除商品" onclick="event.stopPropagation();" data-action="delete-product"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder product-thumb"><span class="ph-frame">空气炸锅 · 1200×800</span></div>
|
||||
<div class="product-body">
|
||||
<div class="product-name">小熊 4L 可视空气炸锅</div>
|
||||
@ -801,12 +801,12 @@
|
||||
</div>
|
||||
<div class="product-footer">
|
||||
<span class="stat">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="10" r="2"/><path d="M21 17l-5-5-9 9"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="10" r="2"/><path d="M21 17l-5-5-9 9"/></svg>
|
||||
素材 <b>54</b>
|
||||
</span>
|
||||
<span class="sep">·</span>
|
||||
<span class="stat">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="M16 10l6-3v10l-6-3z"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="M16 10l6-3v10l-6-3z"/></svg>
|
||||
视频 <b>16</b>
|
||||
</span>
|
||||
|
||||
@ -815,7 +815,7 @@
|
||||
|
||||
<div class="product-card" data-cat="运动户外" data-name="露露同款裸感瑜伽裤" data-tags="健身房 通勤" data-added="7" data-assets="42" data-videos="12" data-date="2026-04-30" onclick="location.href='product-detail.html?t='+Date.now()">
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除商品" onclick="event.stopPropagation();" data-action="delete-product"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除商品" onclick="event.stopPropagation();" data-action="delete-product"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder product-thumb"><span class="ph-frame">瑜伽裤 · 1200×800</span></div>
|
||||
<div class="product-body">
|
||||
<div class="product-name">露露同款裸感瑜伽裤</div>
|
||||
@ -824,12 +824,12 @@
|
||||
</div>
|
||||
<div class="product-footer">
|
||||
<span class="stat">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="10" r="2"/><path d="M21 17l-5-5-9 9"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="10" r="2"/><path d="M21 17l-5-5-9 9"/></svg>
|
||||
素材 <b>42</b>
|
||||
</span>
|
||||
<span class="sep">·</span>
|
||||
<span class="stat">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="M16 10l6-3v10l-6-3z"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="M16 10l6-3v10l-6-3z"/></svg>
|
||||
视频 <b>12</b>
|
||||
</span>
|
||||
|
||||
@ -914,9 +914,9 @@
|
||||
<div class="pf-example">
|
||||
<div class="ex-h">示例图</div>
|
||||
<div class="ex-grid">
|
||||
<div class="ex-thumb"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><path d="M7 4h10l1 4v12H6V8l1-4z"/><path d="M9 4v3M15 4v3M9 11h6M9 14h6"/></svg></div>
|
||||
<div class="ex-thumb"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="5" width="12" height="15" rx="2"/><path d="M9 9h6M9 12h6M9 15h4"/></svg></div>
|
||||
<div class="ex-thumb"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3h8l1 5v12H7V8l1-5z"/><circle cx="12" cy="13" r="2.5"/></svg></div>
|
||||
<div class="ex-thumb"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M7 4h10l1 4v12H6V8l1-4z"/><path d="M9 4v3M15 4v3M9 11h6M9 14h6"/></svg></div>
|
||||
<div class="ex-thumb"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="5" width="12" height="15" rx="2"/><path d="M9 9h6M9 12h6M9 15h4"/></svg></div>
|
||||
<div class="ex-thumb"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3h8l1 5v12H7V8l1-5z"/><circle cx="12" cy="13" r="2.5"/></svg></div>
|
||||
</div>
|
||||
<div class="ex-d">优质的商品图有助于生成更好的素材效果</div>
|
||||
</div>
|
||||
@ -935,7 +935,7 @@
|
||||
|
||||
<div class="drawer-f">
|
||||
<button class="btn-guide" type="button" onclick="Shell.toast('使用指南', '点击查看完整填写指南')">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M9.5 9a2.5 2.5 0 015 0c0 1.5-2.5 2-2.5 4M12 17h.01"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M9.5 9a2.5 2.5 0 015 0c0 1.5-2.5 2-2.5 4M12 17h.01"/></svg>
|
||||
使用指南
|
||||
</button>
|
||||
<button class="btn" type="button" id="pc-cancel-btn">取消</button>
|
||||
@ -953,7 +953,7 @@
|
||||
<span class="corner-bl" aria-hidden></span>
|
||||
<div class="modal-h">
|
||||
<div class="ic-m" style="background:var(--heat-12);color:var(--heat)">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83"/></svg>
|
||||
</div>
|
||||
<div class="ti" id="gen-choice-ti"><span id="gen-choice-target">—</span><span>// PICK ONE</span></div>
|
||||
</div>
|
||||
@ -988,7 +988,7 @@
|
||||
<span class="corner-bl" aria-hidden></span>
|
||||
<div class="modal-h">
|
||||
<div class="ic-m" style="background:var(--crimson-bg,#fdebea);color:var(--accent-crimson,#c43d3d)">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>
|
||||
</div>
|
||||
<div class="ti" id="del-confirm-ti">确认删除商品<span>// CONFIRM DELETE</span></div>
|
||||
</div>
|
||||
@ -996,7 +996,7 @@
|
||||
<div class="modal-f" id="del-confirm-foot">
|
||||
<button class="btn" type="button" id="del-confirm-cancel">取消</button>
|
||||
<button class="btn" type="button" id="del-confirm-ok" style="background:var(--accent-crimson,#c43d3d);color:var(--accent-white);border-color:var(--accent-crimson,#c43d3d)">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
|
||||
确认删除
|
||||
</button>
|
||||
</div>
|
||||
@ -1009,7 +1009,7 @@
|
||||
<button class="clear-sel" type="button" id="bulk-clear">清空</button>
|
||||
<span class="sep"></span>
|
||||
<button class="danger" type="button" id="bulk-del">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>
|
||||
删除所选
|
||||
</button>
|
||||
<button type="button" id="bulk-exit">完成</button>
|
||||
@ -1049,14 +1049,14 @@ Shell.render({ active: 'products', crumbs: [{ label: '工作台', href: 'index.h
|
||||
card.dataset.triview = '0';
|
||||
card.innerHTML = `
|
||||
<span class="card-check" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 8 7 12 13 4"/></svg></span>
|
||||
<button class="card-del-btn" type="button" title="删除商品" onclick="event.stopPropagation();" data-action="delete-product"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<button class="card-del-btn" type="button" title="删除商品" onclick="event.stopPropagation();" data-action="delete-product"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg></button>
|
||||
<div class="placeholder product-thumb">
|
||||
<span class="tri-missing-badge" tabindex="0" role="button" aria-label="缺三视图,查看说明">
|
||||
<span class="ico" aria-hidden="true"></span>
|
||||
<span class="lbl-mono">缺三视图</span>
|
||||
<span class="tri-missing-pop" role="tooltip">
|
||||
<span class="pop-h">
|
||||
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M12 9v4M12 17h.01"/><path d="M10.3 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/></svg>
|
||||
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 9v4M12 17h.01"/><path d="M10.3 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/></svg>
|
||||
MISSING TRI-VIEW
|
||||
</span>
|
||||
<span class="pop-body">该商品还未生成 <b>正 / 侧 / 背</b> 三视图。直接生成图片或视频,模型缺少多角度参考,角色一致性、姿态稳定性可能下降。</span>
|
||||
@ -1072,12 +1072,12 @@ Shell.render({ active: 'products', crumbs: [{ label: '工作台', href: 'index.h
|
||||
</div>
|
||||
<div class="product-footer">
|
||||
<span class="stat">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="10" r="2"/><path d="M21 17l-5-5-9 9"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="10" r="2"/><path d="M21 17l-5-5-9 9"/></svg>
|
||||
素材 <b>${p.assets || 0}</b>
|
||||
</span>
|
||||
<span class="sep">·</span>
|
||||
<span class="stat">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="M16 10l6-3v10l-6-3z"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="14" height="12" rx="2"/><path d="M16 10l6-3v10l-6-3z"/></svg>
|
||||
视频 <b>${p.videos || 0}</b>
|
||||
</span>
|
||||
</div>
|
||||
@ -1537,14 +1537,14 @@ function renderPagination(totalVisible, totalPages) {
|
||||
const list = document.getElementById('page-list');
|
||||
const items = pageNumberList(state.page, totalPages);
|
||||
let html = `<button type="button" data-page="prev" ${state.page <= 1 ? 'disabled' : ''} aria-label="上一页">
|
||||
<svg width="11" height="11" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M10 12L6 8l4-4"/></svg>
|
||||
<svg width="11" height="11" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10 12L6 8l4-4"/></svg>
|
||||
</button>`;
|
||||
items.forEach(p => {
|
||||
if (p === '…') html += `<span class="ellipsis">…</span>`;
|
||||
else html += `<button type="button" data-page="${p}" ${p === state.page ? 'class="active"' : ''}>${p}</button>`;
|
||||
});
|
||||
html += `<button type="button" data-page="next" ${state.page >= totalPages ? 'disabled' : ''} aria-label="下一页">
|
||||
<svg width="11" height="11" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M6 4l4 4-4 4"/></svg>
|
||||
<svg width="11" height="11" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M6 4l4 4-4 4"/></svg>
|
||||
</button>`;
|
||||
list.innerHTML = html;
|
||||
}
|
||||
@ -1667,7 +1667,7 @@ function pfRender() {
|
||||
<div class="pf-thumb" data-id="${u.id}">
|
||||
<img src="${u.dataUrl}" alt="${pfEsc(u.name)}">
|
||||
<button class="pf-x" type="button" title="删除">
|
||||
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 4l8 8M12 4l-8 8"/></svg>
|
||||
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M4 4l8 8M12 4l-8 8"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
@ -585,11 +585,11 @@
|
||||
<div class="pl-main">
|
||||
<div class="pl-toolbar">
|
||||
<div class="search">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
|
||||
<input type="text" id="pl-search-input" placeholder="搜索商品名">
|
||||
</div>
|
||||
<button class="btn-new" type="button" id="pl-new-btn">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg>
|
||||
新建商品
|
||||
</button>
|
||||
</div>
|
||||
@ -769,12 +769,12 @@
|
||||
|
||||
const ICONS = {
|
||||
check: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12l5 5L20 6"/></svg>',
|
||||
search: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>',
|
||||
plus: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg>',
|
||||
search: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>',
|
||||
plus: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg>',
|
||||
x: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 5l14 14M19 5L5 19"/></svg>',
|
||||
bulb: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18h6"/><path d="M10 22h4"/><path d="M15.09 14c.18-.98.65-1.74 1.41-2.5A4.65 4.65 0 0 0 18 8 6 6 0 0 0 6 8c0 1 .23 2.23 1.5 3.5A4.61 4.61 0 0 1 8.91 14"/></svg>',
|
||||
arrow: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg>',
|
||||
wallet: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="6" width="18" height="13" rx="2"/><path d="M3 10h18M16 14h2"/></svg>',
|
||||
wallet: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="6" width="18" height="13" rx="2"/><path d="M3 10h18M16 14h2"/></svg>',
|
||||
};
|
||||
|
||||
/* ---------- actions ---------- */
|
||||
@ -1115,7 +1115,7 @@
|
||||
|
||||
const cards = pageList.map(productCardHTML).join('');
|
||||
const createCard = `<div class="pp-create-card" onclick="_wiz.openNewProduct()">
|
||||
<div class="pc-plus"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg></div>
|
||||
<div class="pc-plus"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14M5 12h14"/></svg></div>
|
||||
<div class="pc-t">创建新商品</div>
|
||||
<div class="pc-d">// 在此添加一个新商品</div>
|
||||
</div>`;
|
||||
@ -1154,7 +1154,7 @@
|
||||
${total > pageSize ? pickerPagerHTML(total) : ''}
|
||||
|
||||
<div class="pp-bottom-tip">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 8v5M12 16h.01"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 8v5M12 16h.01"/></svg>
|
||||
<span>找不到想要的商品?可<a onclick="_wiz.openNewProduct()">创建新商品</a>,或前往 <a href="products.html">商品库 · 管理商品</a></span>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
@ -536,6 +536,40 @@
|
||||
<p>// 试试切换 tab 或修改搜索词</p>
|
||||
</div>
|
||||
|
||||
<!-- ===== 删除确认 modal (必须在 <script> 之前 · 否则 getElementById 取 null 导致脚本崩) ===== -->
|
||||
<div class="modal-bg" id="del-confirm-bg">
|
||||
<div class="modal" role="dialog">
|
||||
<span class="corner-tr" aria-hidden></span>
|
||||
<span class="corner-bl" aria-hidden></span>
|
||||
<div class="modal-h">
|
||||
<div class="ic-m" style="background:var(--crimson-bg,#fdebea);color:var(--accent-crimson,#c43d3d)">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>
|
||||
</div>
|
||||
<div class="ti">确认删除项目<span>// CONFIRM DELETE</span></div>
|
||||
</div>
|
||||
<div class="modal-b" id="del-confirm-body">即将删除项目。</div>
|
||||
<div class="modal-f">
|
||||
<button class="btn" type="button" id="del-confirm-cancel">取消</button>
|
||||
<button class="btn" type="button" id="del-confirm-ok" style="background:var(--accent-crimson);color:var(--accent-white);border-color:var(--accent-crimson)">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/></svg>
|
||||
确认删除
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===== bulk-bar (必须在 <script> 之前) ===== -->
|
||||
<div class="bulk-bar" id="bulk-bar">
|
||||
<span class="ct">已选 <b id="bulk-count">0</b> 项</span>
|
||||
<button class="clear-sel" type="button" id="bulk-clear">清空</button>
|
||||
<span class="sep"></span>
|
||||
<button class="danger" type="button" id="bulk-del">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>
|
||||
删除所选
|
||||
</button>
|
||||
<button type="button" id="bulk-exit">完成</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script src="assets/shell.js?v=202605211643"></script>
|
||||
<script>
|
||||
@ -1042,39 +1076,5 @@ document.querySelectorAll('#list-tbody tr').forEach(tr => {
|
||||
}, true);
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- ===== 删除确认 modal ===== -->
|
||||
<div class="modal-bg" id="del-confirm-bg">
|
||||
<div class="modal" role="dialog">
|
||||
<span class="corner-tr" aria-hidden></span>
|
||||
<span class="corner-bl" aria-hidden></span>
|
||||
<div class="modal-h">
|
||||
<div class="ic-m" style="background:var(--crimson-bg,#fdebea);color:var(--accent-crimson,#c43d3d)">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>
|
||||
</div>
|
||||
<div class="ti">确认删除项目<span>// CONFIRM DELETE</span></div>
|
||||
</div>
|
||||
<div class="modal-b" id="del-confirm-body">即将删除项目。</div>
|
||||
<div class="modal-f">
|
||||
<button class="btn" type="button" id="del-confirm-cancel">取消</button>
|
||||
<button class="btn" type="button" id="del-confirm-ok" style="background:var(--accent-crimson);color:var(--accent-white);border-color:var(--accent-crimson)">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/></svg>
|
||||
确认删除
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===== bulk-bar ===== -->
|
||||
<div class="bulk-bar" id="bulk-bar">
|
||||
<span class="ct">已选 <b id="bulk-count">0</b> 项</span>
|
||||
<button class="clear-sel" type="button" id="bulk-clear">清空</button>
|
||||
<span class="sep"></span>
|
||||
<button class="danger" type="button" id="bulk-del">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6"/></svg>
|
||||
删除所选
|
||||
</button>
|
||||
<button type="button" id="bulk-exit">完成</button>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -101,7 +101,7 @@
|
||||
|
||||
<aside class="auth-brand">
|
||||
<div class="logo">
|
||||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 L19 7 V17 L12 22 L5 17 V7 Z"/><path d="M12 2 V22"/><path d="M5 7 L19 17"/></svg></span>
|
||||
<span class="ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 L19 7 V17 L12 22 L5 17 V7 Z"/><path d="M12 2 V22"/><path d="M5 7 L19 17"/></svg></span>
|
||||
<span>流·Studio</span>
|
||||
</div>
|
||||
<div class="tag">// SHORT-VIDEO COMMERCE PLATFORM</div>
|
||||
@ -149,7 +149,7 @@
|
||||
<div class="field">
|
||||
<label class="field-label" for="reg-team">团队名 <span class="req">*</span></label>
|
||||
<div class="field-input-wrap">
|
||||
<svg class="ic-l" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><path d="M9 22V12h6v10"/></svg>
|
||||
<svg class="ic-l" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><path d="M9 22V12h6v10"/></svg>
|
||||
<input type="text" id="reg-team" placeholder="例: 小李的店 / XX 文化传媒" required>
|
||||
</div>
|
||||
</div>
|
||||
@ -157,7 +157,7 @@
|
||||
<div class="field">
|
||||
<label class="field-label" for="reg-email">超管邮箱 <span class="req">*</span><span class="hint">用于成员邀请 + 找回密码</span></label>
|
||||
<div class="field-input-wrap">
|
||||
<svg class="ic-l" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z"/><path d="m22 6-10 7L2 6"/></svg>
|
||||
<svg class="ic-l" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z"/><path d="m22 6-10 7L2 6"/></svg>
|
||||
<input type="email" id="reg-email" placeholder="name@company.com" required>
|
||||
</div>
|
||||
</div>
|
||||
@ -166,20 +166,20 @@
|
||||
<div class="field">
|
||||
<label class="field-label" for="reg-pwd">密码 <span class="req">*</span></label>
|
||||
<div class="field-input-wrap">
|
||||
<svg class="ic-l" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
|
||||
<svg class="ic-l" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
|
||||
<input type="password" id="reg-pwd" placeholder="至少 8 位" required>
|
||||
<button type="button" class="toggle-pwd" onclick="togglePwd('reg-pwd')">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="field-label" for="reg-pwd2">确认密码 <span class="req">*</span></label>
|
||||
<div class="field-input-wrap">
|
||||
<svg class="ic-l" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
|
||||
<svg class="ic-l" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
|
||||
<input type="password" id="reg-pwd2" placeholder="再输一次" required>
|
||||
<button type="button" class="toggle-pwd" onclick="togglePwd('reg-pwd2')">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -188,14 +188,14 @@
|
||||
<div class="field">
|
||||
<label class="field-label" for="reg-invite">邀请码 <span class="hint">可选 · 团队邀请才需要</span></label>
|
||||
<div class="field-input-wrap">
|
||||
<svg class="ic-l" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/></svg>
|
||||
<svg class="ic-l" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/></svg>
|
||||
<input type="text" id="reg-invite" placeholder="例: TEAM-XXXX-XXXX">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label class="agree">
|
||||
<input type="checkbox" id="reg-agree" checked>
|
||||
<span>我已阅读并同意 <a href="#" onclick="event.preventDefault()">用户协议</a> 与 <a href="#" onclick="event.preventDefault()">隐私政策</a>,知悉「失败不扣费 · 确认后扣」的扣费规则。</span>
|
||||
<span>我已阅读并同意 <a href="#" onclick="event.preventDefault();_regToast('用户协议','含数据处理 / 内容生成版权 / 计费规则三章 · 完整文本将在正式版接入');">用户协议</a> 与 <a href="#" onclick="event.preventDefault();_regToast('隐私政策','遵循《个人信息保护法》· 团队数据存中国境内 · 默认不用于模型训练');">隐私政策</a>,知悉「失败不扣费 · 确认后扣」的扣费规则。</span>
|
||||
</label>
|
||||
|
||||
<button class="btn-cta" type="submit" id="reg-submit">
|
||||
@ -230,6 +230,20 @@
|
||||
btn.disabled = true;
|
||||
setTimeout(() => { location.href = 'index.html'; }, 900);
|
||||
}
|
||||
// 轻量 toast(不依赖 shell.js)
|
||||
function _regToast(t, sub) {
|
||||
let el = document.getElementById('__reg-toast');
|
||||
if (!el) {
|
||||
el = document.createElement('div');
|
||||
el.id = '__reg-toast';
|
||||
el.style.cssText = 'position:fixed;left:50%;bottom:36px;transform:translateX(-50%) translateY(20px);background:#fff;border:1px solid #e0e0e0;border-radius:8px;padding:12px 18px;box-shadow:0 8px 24px rgba(0,0,0,.12);display:flex;flex-direction:column;gap:2px;opacity:0;transition:opacity .2s,transform .2s;z-index:9999;font-family:inherit;max-width:380px;';
|
||||
document.body.appendChild(el);
|
||||
}
|
||||
el.innerHTML = '<div style="font-size:13.5px;font-weight:600;color:#262626;">' + t + '</div>' + (sub ? '<div style="font-size:11.5px;color:rgba(0,0,0,.56);font-family:\'JetBrains Mono\',monospace;letter-spacing:.02em;">// ' + sub + '</div>' : '');
|
||||
requestAnimationFrame(() => { el.style.opacity = '1'; el.style.transform = 'translateX(-50%) translateY(0)'; });
|
||||
clearTimeout(el._t);
|
||||
el._t = setTimeout(() => { el.style.opacity = '0'; el.style.transform = 'translateX(-50%) translateY(20px)'; }, 3000);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -421,7 +421,7 @@
|
||||
<div class="lbl">退出登录</div>
|
||||
<div class="val">
|
||||
<span class="static mono" style="font-size: 11.5px; color: var(--black-alpha-56);">// 仅退出当前设备,数据保留</span>
|
||||
<button class="btn btn-sm" style="margin-left: auto; color: var(--accent-crimson); border-color: var(--accent-crimson);" onclick="if(confirm('确定退出登录?')) Shell.toast('已退出', '正在跳转登录页')">退出登录</button>
|
||||
<button class="btn btn-sm" style="margin-left: auto; color: var(--accent-crimson); border-color: var(--accent-crimson);" onclick="if(confirm('确定退出登录?')){Shell.toast('已退出','正在跳转登录页');setTimeout(()=>location.href='login.html',600);}">退出登录</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
|
||||
@ -489,7 +489,7 @@
|
||||
<span>// MCN · 老张</span>
|
||||
</div>
|
||||
<button class="ws-new-btn" id="ws-new-btn">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M12 5v14M5 12h14"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M12 5v14M5 12h14"/></svg>
|
||||
新建商品
|
||||
</button>
|
||||
<div class="ws-search">
|
||||
@ -912,7 +912,7 @@ function renderPhotos(p, isEdit) {
|
||||
if (ph) {
|
||||
slots += `<div class="ov-photo" style="background:${ph.bg};background-size:cover;background-position:center;">
|
||||
${i===0?'<span class="pmain">MAIN</span>':''}
|
||||
<button class="photo-x" data-i="${i}" type="button"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 4l8 8M12 4l-8 8"/></svg></button>
|
||||
<button class="photo-x" data-i="${i}" type="button"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M4 4l8 8M12 4l-8 8"/></svg></button>
|
||||
</div>`;
|
||||
} else if (i === p.photos.length) {
|
||||
slots += `<div class="ov-photo empty-slot add-active" data-add-photo>+ 上传</div>`;
|
||||
|
||||
@ -667,7 +667,7 @@
|
||||
<span>// MCN · 老张的店</span>
|
||||
</div>
|
||||
<button class="ws-new-btn" id="ws-new-btn">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M12 5v14M5 12h14"/></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M12 5v14M5 12h14"/></svg>
|
||||
新建商品
|
||||
</button>
|
||||
<div class="ws-search">
|
||||
@ -1246,7 +1246,7 @@ function renderPhotosBlock(p) {
|
||||
if (ph) {
|
||||
slots += `<div class="ov-photo" style="background:${ph.bg};background-size:cover;background-position:center;">
|
||||
${i===0?'<span class="pmain">MAIN</span>':''}
|
||||
<button class="photo-x" data-i="${i}" type="button"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 4l8 8M12 4l-8 8"/></svg></button>
|
||||
<button class="photo-x" data-i="${i}" type="button"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M4 4l8 8M12 4l-8 8"/></svg></button>
|
||||
</div>`;
|
||||
} else if (i === p.photos.length) {
|
||||
slots += `<div class="ov-photo empty-slot add-active" data-add-photo>+ 上传</div>`;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user