|
|
@@ -0,0 +1,198 @@
|
|
|
+# 顾客详情页 AI 模拟结果卡片流设计
|
|
|
+
|
|
|
+## 目标
|
|
|
+
|
|
|
+在顾客详情页的“过往照片和AI发型模拟”区块中,替换当前未开发占位卡片,展示该顾客历史 AI 发型模拟生成结果。每一张生成图对应一张卡片,按创建时间倒序展示,点击卡片进入对应任务详情页。
|
|
|
+
|
|
|
+## 背景
|
|
|
+
|
|
|
+- 当前顾客详情页中,“过往照片和AI发型模拟”区块仍是静态占位,不承载真实业务结果。
|
|
|
+- AI 发型模拟主流程已经具备创建任务、查询任务详情、展示子任务结果图的能力。
|
|
|
+- 用户要求在顾客详情页直接看到“刚刚任务的结果”,并明确要求:
|
|
|
+ - 一个图片就是一个任务卡片
|
|
|
+ - 按时间顺序全部展示
|
|
|
+ - 点击图片卡片进入对应任务详情页
|
|
|
+ - 排序采用最新在前
|
|
|
+
|
|
|
+## 范围
|
|
|
+
|
|
|
+### 本次包含
|
|
|
+
|
|
|
+- 新增顾客维度的 AI 模拟结果卡片列表接口
|
|
|
+- 顾客详情页接入真实结果卡片流
|
|
|
+- 每张生成图展开为一张独立卡片
|
|
|
+- 点击卡片跳转到对应模拟任务详情页
|
|
|
+- 空状态展示
|
|
|
+
|
|
|
+### 本次不包含
|
|
|
+
|
|
|
+- 分页
|
|
|
+- 筛选
|
|
|
+- 失败任务和处理中任务的卡片展示
|
|
|
+- 在顾客详情页直接轮询任务状态
|
|
|
+- 任务详情页结构变更
|
|
|
+
|
|
|
+## 交互设计
|
|
|
+
|
|
|
+### 区块位置
|
|
|
+
|
|
|
+继续使用顾客详情页现有“过往照片和AI发型模拟”区块,不改变整体页面骨架、标题和右上角“AI发型模拟”入口按钮位置。
|
|
|
+
|
|
|
+### 卡片规则
|
|
|
+
|
|
|
+- 一张生成图展开为一张卡片
|
|
|
+- 一个任务下如果有多张生成图,则展开成多张卡片
|
|
|
+- 同一个 `simulationId` 下出现多张卡片属于预期行为
|
|
|
+- 卡片至少展示:
|
|
|
+ - 生成图
|
|
|
+ - 模板名称
|
|
|
+ - 生成时间
|
|
|
+
|
|
|
+### 点击行为
|
|
|
+
|
|
|
+- 点击任意卡片,跳转至 `/:locale/simulation/result/:simulationId`
|
|
|
+- 不跳到子任务维度页面,继续复用现有任务详情页
|
|
|
+
|
|
|
+### 排序
|
|
|
+
|
|
|
+- 按模拟任务创建时间倒序排列
|
|
|
+- 最新的结果卡片排在最前面
|
|
|
+
|
|
|
+### 空状态
|
|
|
+
|
|
|
+- 当顾客还没有任何成功生成的 AI 模拟结果时,不显示假卡片
|
|
|
+- 使用清晰的空状态文案提示当前暂无 AI 模拟结果
|
|
|
+
|
|
|
+## 后端设计
|
|
|
+
|
|
|
+### 新接口
|
|
|
+
|
|
|
+- 路由:`GET /api/v1/simulations/customer/:customerId/gallery`
|
|
|
+- 权限:仅允许当前登录发型师查看自己名下顾客的数据
|
|
|
+
|
|
|
+### 返回结构
|
|
|
+
|
|
|
+返回扁平化卡片列表,而不是主任务嵌套结构。每条记录代表一张生成图卡片。
|
|
|
+
|
|
|
+建议 DTO:
|
|
|
+
|
|
|
+```ts
|
|
|
+export type CustomerSimulationGalleryItemDto = {
|
|
|
+ simulationId: string;
|
|
|
+ taskId: string;
|
|
|
+ imageUrl: string;
|
|
|
+ templateName: string;
|
|
|
+ createdAt: string;
|
|
|
+ taskStatus: 'SUCCESSES';
|
|
|
+};
|
|
|
+```
|
|
|
+
|
|
|
+响应示例:
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "items": [
|
|
|
+ {
|
|
|
+ "simulationId": "91",
|
|
|
+ "taskId": "task-11",
|
|
|
+ "imageUrl": "https://cdn.example.com/result-1.png",
|
|
|
+ "templateName": "Layer Bob",
|
|
|
+ "createdAt": "2026-06-28T09:00:00.000Z",
|
|
|
+ "taskStatus": "SUCCESSES"
|
|
|
+ }
|
|
|
+ ]
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 查询规则
|
|
|
+
|
|
|
+- 只查询当前发型师名下的顾客
|
|
|
+- 只查询该顾客关联的 `ai_hair_simulation`
|
|
|
+- 只展开 `ai_hair_simulation_task` 中 `task_status = 'SUCCESSES'` 的任务
|
|
|
+- 从 `result_images` 中展开真实图片列表
|
|
|
+- 每张图片映射为一条扁平记录
|
|
|
+- 按所属模拟任务 `create_time` 倒序输出
|
|
|
+
|
|
|
+### 数据来源
|
|
|
+
|
|
|
+- 主表:`ai_hair_simulation`
|
|
|
+- 子表:`ai_hair_simulation_task`
|
|
|
+- 模板名来自 `hair_template.template_name`
|
|
|
+
|
|
|
+### 安全约束
|
|
|
+
|
|
|
+- 必须校验 `customerId` 属于当前发型师
|
|
|
+- 不允许跨发型师读取顾客结果
|
|
|
+
|
|
|
+## 前端设计
|
|
|
+
|
|
|
+### API 层
|
|
|
+
|
|
|
+在 `frontend/src/services/api/simulations.ts` 中新增顾客详情页所需的 gallery 查询方法,并在 `contracts.ts` 中补齐对应类型。
|
|
|
+
|
|
|
+建议签名:
|
|
|
+
|
|
|
+```ts
|
|
|
+export async function listCustomerSimulationGallery(
|
|
|
+ customerId: string,
|
|
|
+): Promise<{ items: CustomerSimulationGalleryItem[] }>
|
|
|
+```
|
|
|
+
|
|
|
+### 顾客详情页
|
|
|
+
|
|
|
+在 `CustomerDetailPage.tsx` 中替换原有 `photoPlaceholders` 占位卡片渲染逻辑:
|
|
|
+
|
|
|
+- 页面加载后并行请求:
|
|
|
+ - 顾客详情
|
|
|
+ - 顾客 AI 模拟结果卡片列表
|
|
|
+- 卡片区改为真实图片网格
|
|
|
+- 每张卡片使用 `Link`
|
|
|
+- 跳转目标为 `path(\`/simulation/result/${simulationId}\`)`
|
|
|
+
|
|
|
+### 展示字段
|
|
|
+
|
|
|
+每张卡片展示:
|
|
|
+
|
|
|
+- 主图:`imageUrl`
|
|
|
+- 标题:`templateName`
|
|
|
+- 辅助时间:`createdAt` 的格式化日期时间
|
|
|
+
|
|
|
+## 边界与异常
|
|
|
+
|
|
|
+- 如果接口失败:
|
|
|
+ - 顾客详情主体仍按现有策略处理
|
|
|
+ - AI 模拟图片区块显示错误或空状态,而不是整页崩溃
|
|
|
+- 如果某个成功任务的 `result_images` 为空数组:
|
|
|
+ - 该任务不生成卡片
|
|
|
+- 如果模板被删除:
|
|
|
+ - 模板名称允许回退为默认文案,但不阻塞图片展示
|
|
|
+
|
|
|
+## 测试策略
|
|
|
+
|
|
|
+### 后端
|
|
|
+
|
|
|
+- service 单测:
|
|
|
+ - 顾客归属校验
|
|
|
+ - 仅展开成功任务
|
|
|
+ - 一个任务多图展开为多条记录
|
|
|
+ - 倒序输出
|
|
|
+- e2e:
|
|
|
+ - 返回当前顾客 gallery
|
|
|
+ - 非本人顾客不可访问
|
|
|
+
|
|
|
+### 前端
|
|
|
+
|
|
|
+- API 测试:
|
|
|
+ - 请求路径正确
|
|
|
+- 页面测试:
|
|
|
+ - 成功渲染真实卡片
|
|
|
+ - 空状态渲染
|
|
|
+ - 点击卡片跳转到结果详情页
|
|
|
+
|
|
|
+## 验收标准
|
|
|
+
|
|
|
+- 顾客详情页“过往照片和AI发型模拟”区块展示真实 AI 模拟结果卡片
|
|
|
+- 一张生成图对应一张卡片
|
|
|
+- 最新结果排在最前
|
|
|
+- 点击卡片进入对应任务详情页
|
|
|
+- 页面整体 UI 骨架不被破坏
|