206 lines
15 KiB
Markdown
206 lines
15 KiB
Markdown
---
|
||
name: 前端同步后端AI穿搭待保存改造
|
||
overview: 跟进后端本轮改动:穿搭对象新增 status(1正常/2封禁/3待保存)、未保存 AI 穿搭 7 天自动清理、任务快照 15 分钟。前端新增 pages/ai-pending 管理页(待保存/已保存分段,支持保存、删除、重新生成、查看详情),我的穿搭只保留手工创建(source=1)并在顶部加入口,同步统一 status 展示口径与超期/清理兜底文案。
|
||
design:
|
||
styleKeywords:
|
||
- 零彩色灰阶
|
||
- 杂志排版
|
||
- 发丝线分层
|
||
- 毛玻璃悬浮层
|
||
- 极简克制
|
||
fontSystem:
|
||
fontFamily: Songti-SC, PingFang-SC
|
||
heading:
|
||
size: 68rpx
|
||
weight: 400
|
||
subheading:
|
||
size: 34rpx
|
||
weight: 600
|
||
body:
|
||
size: 30rpx
|
||
weight: 400
|
||
colorSystem:
|
||
primary:
|
||
- "#0A0A0A"
|
||
- "#1C1C1E"
|
||
- "#6E6E73"
|
||
background:
|
||
- "#FFFFFF"
|
||
- "#F7F7F5"
|
||
- "#EFEFED"
|
||
text:
|
||
- "#0A0A0A"
|
||
- "#6E6E73"
|
||
- "#AEAEB2"
|
||
functional:
|
||
- "#C9C9CE"
|
||
- "#B9B9BE"
|
||
- "#D2D2D7"
|
||
todos:
|
||
- id: status-contract
|
||
content: 补 OutfitItem.status 类型,新增 utils/outfit-status.ts 与 utils/outfit-cover.ts 收敛状态口径与封面组装
|
||
status: completed
|
||
- id: my-outfits-entry
|
||
content: 我的穿搭改为只取 source=1,改用统一状态胶囊并新增 AI 穿搭入口卡片与待保存角标
|
||
status: completed
|
||
dependencies:
|
||
- status-contract
|
||
- id: pending-page
|
||
content: 新增 pages/ai-pending 页面:待保存/已保存分段、保存/删除/重新生成/详情与 7 天清理提示
|
||
status: completed
|
||
dependencies:
|
||
- status-contract
|
||
- id: ai-recommend-entry
|
||
content: AI 推荐页接入 AI 穿搭入口,90402 文案改为引导并补换一套时的未保存提示
|
||
status: completed
|
||
- id: detail-status
|
||
content: 穿搭详情页支持待保存直接保存、封禁态只读并隐藏管理操作
|
||
status: completed
|
||
dependencies:
|
||
- status-contract
|
||
- id: qa-verify
|
||
content: 用 [subagent:code-explorer] 与 [skill:lsp-code-analysis] 核对引用点,用 [skill:playwright-cli] 对照参考稿,跑 tsc 与静态审计并输出真机验收清单
|
||
status: completed
|
||
dependencies:
|
||
- my-outfits-entry
|
||
- pending-page
|
||
- ai-recommend-entry
|
||
- detail-status
|
||
---
|
||
|
||
## 产品概述
|
||
|
||
后端已完成 AI 推荐异步化与穿搭状态体系改造(穿搭对象带 `status`:正常 / 封禁 / 待保存,且超过 7 天未保存的 AI 推荐由后端自动清理)。前端本轮跟进:把 AI 生成的穿搭从「我的穿搭」中完全独立出来,收进新页面「AI 穿搭」统一管理,让用户可随时找回、保存或清理 AI 生成结果。
|
||
|
||
## 核心功能
|
||
|
||
- **新增「AI 穿搭」页**:分「待保存 / 已保存」两段;待保存项支持 保存到我的穿搭、查看详情、删除、重新生成;已保存项仅查看(删除走详情页既有入口)
|
||
- **待保存说明与超期兜底**:页面顶部说明「保存后进入「我的穿搭」;超过 7 天未保存将自动清理」;保存时若已被清理,给出「这套搭配已被清理,请重新生成」的明确提示并移出列表
|
||
- **我的穿搭只留手工创建**:列表请求按来源过滤,AI 穿搭不再混入;顶部新增「AI 穿搭」入口卡片,存在待保存项时显示数量角标
|
||
- **AI 推荐页打通入口**:「场景抽屉」底部可进入「AI 穿搭」;生成结果过期提示里引导用户去「AI 穿搭」查看是否已生成;重新生成前提示上一套未保存的推荐去哪找
|
||
- **穿搭详情页状态化**:待保存的 AI 穿搭在详情页可直接保存;已封禁的穿搭只读展示,隐藏全部管理操作
|
||
- **删除二次确认**:删除 AI 生成结果前弹玻璃确认层,说明该操作不可恢复
|
||
|
||
## 视觉效果
|
||
|
||
延续现有零彩色灰阶杂志风:衬线大标题 + 小字号大写 eyebrow、下划线式文字分段、发丝线分隔、直角卡片配无缝拼图封面、悬浮玻璃操作条与玻璃弹层。新的操作行以「实心黑主按钮 + 无衬线文字按钮」排布,待保存用实心黑胶囊、已封禁以降透明度呈现,保持全站只有白与灰阶。
|
||
|
||
## 技术栈
|
||
|
||
- 原生微信小程序(TypeScript + WXML + WXSS),无构建脚本,沿用 `miniprogram-api-typings`
|
||
- 复用现有 v2 设计系统:`app.wxss` 令牌与通用类、`styles/icons.wxss`(CSS mask 单色图标)、`components/{navigation-bar, empty-state, v2-overlay}`
|
||
- 复用现有请求与工具层:`utils/request`、`utils/logger`、`utils/paged`(`normalizePaged / mergePaged / hasMorePaged`)、`utils/nav`(`navScroll`)、`utils/tabbar`
|
||
|
||
## 实现方案
|
||
|
||
### 契约对齐(与后端已确认的真实行为)
|
||
|
||
- `GET /outfit` 请求参数为 `{ page, page_size, is_public?, source? }` —— **只支持 source 过滤,没有 status 过滤**;DAO 不会过滤 `status=3 / status=2`
|
||
- `OutfitCreateResponse` 已带 `status`(`1` 正常 / `2` 封禁 / `3` 待保存),列表、详情、创建响应都有
|
||
- `GET /outfit/community` 固定 `is_public=2 AND audit_status=2 AND status=1`,社区天然不含待保存与封禁
|
||
- `POST /ai-recommend/save`:`status=3` → 置 `1`;已为 `1` → 幂等返回 nil;已被清理 → `40000`;封禁 → `40003`
|
||
- `DELETE /outfit/:uuid` 可用(事务删明细 + 主表)
|
||
- 待保存 AI 穿搭 7 天后由后端每小时清理一次(软删除,列表与详情立即不可见)
|
||
|
||
### 关键决策
|
||
|
||
1. **我的穿搭用服务端过滤**:请求带 `source=1`(后端现成参数),分页 `total` 正确、无需客户端剔除,彻底避免「客户端过滤导致某页全被剔除、列表越翻越空」的分页塌陷问题。
|
||
2. **AI 穿搭页用单分页流 + 客户端拆段**:一次 `source=2` 的累积数组,渲染时派生成「待保存(status=3)/ 已保存(status=1)」两段;`hasMore` 只看原始分页是否满额(`hasMorePaged(all, total, pageSize)`)。保存成功后**本地迁移**(把该项从待保存段移入已保存段并置本地 status=1),不重新请求,避免闪屏与流量。
|
||
3. **状态口径收敛为单一事实来源**:新增 `utils/outfit-status.ts`,输出胶囊文案 + 类名、以及 `isPendingSave / isBanned` 判定,供 outfit / ai-pending / outfit-detail 三处共用,杜绝同一条语义在三个文件各写一遍 if-else。
|
||
4. **复用优先、最小改面**:新页面结构直接套用已上线验证的 outfit 页模式(`.head / .segbar / 骨架 / empty-state / 卡片 / float-duo`);把两页共用的无缝拼图封面(`.collage` 系列样式 + 封面组装函数)上提为共享资产,避免复制粘贴后视觉分叉。
|
||
5. **入口计数不追求全量准确**:我的穿搭页 `onShow` 静默拉一页 `source=2&page_size=20` 统计 `status===3` 数量用于角标引导;请求失败或超页则只显示入口不显示数字,避免为角标做 N 次翻页。
|
||
6. **口径提示(需在实现中保持一致)**:按已确认口径,所有 `source=2` 穿搭只在「AI 穿搭」页查看,因此「保存到我的穿搭」按钮语义为「保存为正式穿搭(status 3→1)」,保存后该项进入 AI 穿搭页的「已保存」段而**不进入「我的穿搭」列表**;若后续希望保存后的 AI 穿搭回流,只需把 `source=1` 过滤改为「source=1 或 (source=2 且 status=1)」,改动集中在一处。
|
||
|
||
### 状态流转
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
A[AI 推荐生成] --> B[落库 status=3 待保存]
|
||
B --> C[AI 穿搭页 · 待保存段]
|
||
C -->|POST /ai-recommend/save| D[status=1 已保存]
|
||
D --> E[AI 穿搭页 · 已保存段]
|
||
C -->|DELETE /outfit/:uuid| F[本地移除]
|
||
C -.->|超过 7 天被后端清理后 save| G[40000 提示已被清理]
|
||
```
|
||
|
||
### 性能与可靠性
|
||
|
||
- 列表渲染只对累积数组做一次 `filter`,复杂度 O(n),n 为已加载条数(每页 20),无额外遍历
|
||
- 待保存计数为单次静默请求(失败降级不打扰用户),不阻塞首屏
|
||
- 保存/删除均加 loading 防抖,避免重复提交;定时器与请求回调统一由 `reqSeq` 防串页
|
||
- 所有错误路径必须有可见出口:`40000`(已被清理)、`40002`(删除失败)、网络异常,均弹层或 toast 明示,禁止静默
|
||
|
||
## 目录结构(仅列受影响文件)
|
||
|
||
```
|
||
miniprogram/
|
||
├── app.json # [MODIFY] pages 数组末尾注册 pages/ai-pending/ai-pending
|
||
├── app.wxss # [MODIFY] 上移共用「无缝拼图封面」样式(.collage/.cg/.pic/.ph/.cg-more/.cg-badge),供穿搭页与 AI 穿搭页共用
|
||
├── types/models.ts # [MODIFY] OutfitItem 补 status: number(1 正常 2 封禁 3 待保存),与后端 OutfitCreateResponse 对齐
|
||
├── utils/outfit-status.ts # [NEW] 状态口径单一事实来源:胶囊文案+类名、isPendingSave/isBanned
|
||
├── utils/outfit-cover.ts # [NEW] 拼图封面组装:由 items 取前 4 件图片、生成 4/3/2/1 分格类名与 +N 角标、空数据补线稿格
|
||
├── pages/ai-pending/ai-pending.json # [NEW] usingComponents 声明 navigation-bar / empty-state / v2-overlay(相对路径 ../../components/...)
|
||
├── pages/ai-pending/ai-pending.wxml # [NEW] 页头 + 下划线分段(待保存/已保存)+ 说明行 + 卡片列表(封面/名称/场景胶囊/件数/时间)+ 操作行 + 骨架 + 空态 + 删除确认弹层
|
||
├── pages/ai-pending/ai-pending.wxss # [NEW] 页面级样式:入口说明行、卡片操作行(ink 主按钮 + 文字按钮)、角标;拼图卡与全局类一律复用 app.wxss
|
||
├── pages/ai-pending/ai-pending.ts # [NEW] 分页拉取 source=2 + 按 status 拆段 + 保存/删除/重新生成/详情 + 下拉刷新与触底加载
|
||
├── pages/outfit/outfit.ts # [MODIFY] 我的穿搭请求带 source=1;getStatusText 收敛到共享口径;新增待保存计数与跳转 AI 穿搭页
|
||
├── pages/outfit/outfit.wxml # [MODIFY] 我的穿搭分段下新增「AI 穿搭」入口卡片(含待保存角标)
|
||
├── pages/outfit/outfit.wxss # [MODIFY] 入口卡片样式;删除已上移到 app.wxss 的拼图封面重复定义
|
||
├── pages/ai-recommend/ai-recommend.ts # [MODIFY] 新增进入 AI 穿搭页;90402 文案引导 + 弹层加「去看看」;换一套确认文案补未保存提示
|
||
├── pages/ai-recommend/ai-recommend.wxml # [MODIFY] 场景抽屉底部新增「查看我的 AI 穿搭」文字入口
|
||
├── pages/outfit-detail/outfit-detail.ts # [MODIFY] 待保存态保存逻辑(含防抖与 40000 兜底)
|
||
└── pages/outfit-detail/outfit-detail.wxml # [MODIFY] 待保存显示「保存到我的穿搭」并隐藏公开;封禁态只读、隐藏更多入口与状态提示行
|
||
```
|
||
|
||
## 关键结构(供三个模块共用的状态口径)
|
||
|
||
```ts
|
||
export type OutfitStatusPill = { text: string; cls: string }
|
||
export type OutfitStatusLike = { status?: number; source?: number; is_public?: number }
|
||
|
||
// 待保存(3) 优先于来源判定;封禁(2) 降透明度;AI 已保存(1 且 source=2) 用实心黑胶囊
|
||
export function outfitStatusPill(o: OutfitStatusLike): OutfitStatusPill
|
||
export function isPendingSave(o: OutfitStatusLike): boolean
|
||
export function isBanned(o: OutfitStatusLike): boolean
|
||
```
|
||
|
||
## 实现要点(执行注意)
|
||
|
||
- 单位统一 rpx(v2 的 px×2);只允许使用 `app.wxss` 令牌与既有通用类,禁止新增色值(零彩色审计会拦截)
|
||
- `empty-state` / `v2-overlay` 等组件为 `styleIsolation: apply-shared`,页面样式不要反向覆盖组件内部类
|
||
- 日志统一 `logger` + 模块名常量(新页 `LOG = 'ai-pending'`),失败一律 warn 级并带 `code`,不打日志敏感信息
|
||
- 工作区已有未提交改动(outfit / ai-recommend / outfit-detail / clothes-detail 等),本轮改动必须叠加在其之上,不回溯、不重构无关逻辑
|
||
- 本环境无法启动微信开发者工具,视觉只做静态核对,最终以真机预览为准
|
||
|
||
## 设计说明
|
||
|
||
新增页面严格沿用既有 v2 零彩色灰阶杂志风设计系统,不引入任何新风格要素:颜色只取灰阶令牌,衬线字体用于大标题与数字,无衬线用于正文与按钮,0.5px 发丝线替代边框,仅胶囊/抽屉/小控件使用圆角,统一 `cubic-bezier(.32,.72,0,1)` 动效与 `scale(.97)` 按压反馈。
|
||
|
||
## 页面区块设计(AI 穿搭页,自上而下)
|
||
|
||
1. **顶部导航**:透明起点为 34px 左对齐衬线大标题,向下滚动收缩为居中玻璃小标题,右侧无操作项。
|
||
2. **页头**:10px 大写字距 eyebrow「AI Styling」+ 衬线 display「AI 穿搭」,左右 20px 内边距。
|
||
3. **下划线式文字分段**:待保存 / 已保存,选中项黑色加粗 + 2px 实心黑下划线,未选中为中性灰,左右滑动不折行。
|
||
4. **待保存段**:首行 13px 中性灰说明「保存后进入「我的穿搭」;超过 7 天未保存将自动清理」;卡片为直角无缝拼图封面(4/3/2/1 分格,超出显示 +N 角标,件数胶囊叠右下),下方名称(17px/600)+ 场景描边胶囊 + 生成时间;卡片底部操作行:实心黑主按钮「保存到我的穿搭」占满剩余宽度,「重新生成」「删除」为 14px 中性灰文字按钮。
|
||
5. **已保存段**:同款卡片但仅展示与点击进入详情,无内联操作按钮,保持信息密度一致。
|
||
6. **状态视图**:骨架为灰阶占位条 + 图片块;空态用线稿图标 + 标题 + 说明 + 主按钮;触底显示「没有更多了」小字。
|
||
7. **玻璃弹层**:删除使用居中玻璃 modal(标题 + 说明「删除后不可恢复」+ 取消 / 确认删除),点击遮罩取消,主按钮为实心黑。
|
||
8. **动效与响应**:列表项入场 40ms 递进淡入上移,分段切换 320ms 交叉淡入,按钮按压 `scale(.97)` 并降至 60% 透明度;375px 基准宽度自适应,底部预留安全区与 64px 触底间距。
|
||
|
||
## Agent Extensions
|
||
|
||
### SubAgent
|
||
|
||
- **code-explorer**
|
||
- Purpose: 跨文件盘点状态口径相关的全部引用点(`OutfitItem` / `getStatusText` / `source` 判定 / `outfit-status` 使用处)与旧口径残留,确保「我的穿搭只显示手工创建」与状态胶囊改造无遗漏、无死代码
|
||
- Expected outcome: 给出引用点清单与残留清单,作为状态口径收敛与最终走查的核对依据
|
||
|
||
### Skill
|
||
|
||
- **lsp-code-analysis**
|
||
- Purpose: 用语义分析确认 `OutfitItem`、`OutfitSource`、新增 `utils/outfit-status` 的定义与全部引用关系(含类型错误定位),避免仅靠文本搜索漏掉动态引用与类型不匹配
|
||
- Expected outcome: 得到准确的引用/定义清单与类型诊断,确认 `status` 字段补齐后无类型错误、无未使用符号
|
||
|
||
- **playwright-cli**
|
||
- Purpose: 打开 `stitch_ai_ui_v2/index.html` 的穿搭相关参考屏(outfit / outfit-detail / spec 规范页),抓取分段条、卡片、胶囊、发丝线、间距与字号的真实样式值,与新页面 WXSS 逐项核对
|
||
- Expected outcome: 输出一份「参考稿样式值 vs 新页面实现值」的逐项对照结论,修正偏差项,保证新页面与既有 v2 视觉零漂移 |