Files
zt-closet-wxmini-frontend/.codebuddy/plans/前端同步后端AI穿搭待保存改造_7e01cff1.md
2026-09-15 23:04:38 +08:00

206 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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 视觉零漂移