|
|
@@ -0,0 +1,564 @@
|
|
|
+# 顾客详情页恢复与表单统一设计
|
|
|
+
|
|
|
+## 背景
|
|
|
+
|
|
|
+顾客模块上一轮实现为了严格收口 case 范围,已经把顾客详情页和编辑页从当前主线代码中移除,只保留了:
|
|
|
+
|
|
|
+- 顾客列表页
|
|
|
+- 新建顾客页
|
|
|
+- 顾客汇总接口
|
|
|
+
|
|
|
+但本次新 case 的目标已经变化,用户明确要求:
|
|
|
+
|
|
|
+- 顾客列表中的“详情”按钮恢复可用,并优化其 UI 表现
|
|
|
+- 顾客详情页恢复出来,优先复用之前那版详情页的页面结构
|
|
|
+- 新增页与编辑页不再分裂维护,而是统一为一个共享表单页面
|
|
|
+- 详情页中的“施术历史”“过往照片”“AI 发型模拟”“发送提醒”等能力,本次明确标记为未开发,不做伪功能
|
|
|
+- “到店频率”需要依赖 `customer_treatment_record` 做推断,而不是继续沿用旧字段模型中的静态字段
|
|
|
+
|
|
|
+当前仓库中虽然已经删除了 `CustomerDetailPage`,但通过 git 历史可以确认:
|
|
|
+
|
|
|
+- `frontend/src/pages/dashboard/customers/CustomerDetailPage.tsx` 曾经存在
|
|
|
+- 旧版详情页提供了可复用的页面骨架
|
|
|
+- 旧版字段模型与当前已对齐数据库设计的顾客模型不一致,因此不能原样恢复
|
|
|
+
|
|
|
+因此,本次正确方向不是“直接把旧文件拷回来”,而是:
|
|
|
+
|
|
|
+- 恢复旧版详情页的结构和信息层级
|
|
|
+- 用当前数据库对齐后的字段语义重新映射页面内容
|
|
|
+- 同时把新增和编辑统一到同一套表单页中
|
|
|
+
|
|
|
+## 目标
|
|
|
+
|
|
|
+- 恢复顾客详情链路:列表 -> 详情 -> 编辑。
|
|
|
+- 保持本 case 的边界清晰,只补齐真实需要的顾客详情能力。
|
|
|
+- 详情页复用旧版页面结构,但完全基于当前 `customer` 表字段重建展示语义。
|
|
|
+- 新增和编辑共用 `CustomerFormPage`,以当前较完整的表单布局为统一基线。
|
|
|
+- 新增页和编辑页都必须包含“提醒时间”和“下次到店”两个字段输入。
|
|
|
+- 详情页中尚未进入本 case 的业务能力,统一呈现为明确的未开发占位。
|
|
|
+- 到店频率由后端按施术历史记录推导,避免引入新的冗余数据库字段。
|
|
|
+
|
|
|
+## 非目标
|
|
|
+
|
|
|
+- 本次不实现施术历史真实列表接口。
|
|
|
+- 本次不实现过往照片真实聚合接口。
|
|
|
+- 本次不实现 AI 发型模拟历史聚合接口。
|
|
|
+- 本次不实现提醒发送接口。
|
|
|
+- 本次不实现新的工作台聚合能力。
|
|
|
+- 本次不扩展顾客主表字段,不引入新的顾客冗余展示字段。
|
|
|
+
|
|
|
+## 设计原则
|
|
|
+
|
|
|
+### 1. 优先复用旧页面结构,不复活旧错误字段
|
|
|
+
|
|
|
+旧版详情页中可复用的是布局骨架和区块组织方式,不可复用的是字段语义。
|
|
|
+
|
|
|
+可复用的结构包括:
|
|
|
+
|
|
|
+- 顶部 Hero 区
|
|
|
+- 基础信息区
|
|
|
+- 历史区块
|
|
|
+- 照片区块
|
|
|
+- 页面底部 CTA 区
|
|
|
+
|
|
|
+不可继续沿用的旧字段包括但不限于:
|
|
|
+
|
|
|
+- `image`
|
|
|
+- `summary`
|
|
|
+- `nextVisit`
|
|
|
+- `visitCycle`
|
|
|
+- `hairCondition`
|
|
|
+- `formulaNote`
|
|
|
+- `followMessage`
|
|
|
+- `lineStatus`
|
|
|
+
|
|
|
+这些字段已经不符合当前以 `customer` 表为唯一事实来源的顾客模型,不应在本次恢复时被重新带回主线代码。
|
|
|
+
|
|
|
+### 2. 新增与编辑只维护一套表单布局
|
|
|
+
|
|
|
+当前 `CustomerFormPage` 已经是完整度较高的表单骨架,因此本次不重新做独立编辑页布局,而是:
|
|
|
+
|
|
|
+- 继续以 `CustomerFormPage` 作为唯一顾客表单页
|
|
|
+- 通过路由参数和加载逻辑区分 `new` / `edit` 模式
|
|
|
+- 仅通过 copy、按钮文案、返回路径和提交逻辑体现模式差异
|
|
|
+
|
|
|
+这样可以避免新建和编辑页面继续发生结构漂移。
|
|
|
+
|
|
|
+### 3. 未开发模块必须显式可感知
|
|
|
+
|
|
|
+用户已经明确指出:
|
|
|
+
|
|
|
+- 施术历史先标记为未开发
|
|
|
+- 过往照片和 AI 发型模拟先标记为未开发
|
|
|
+- 发送提醒按钮也先标记为未开发
|
|
|
+
|
|
|
+因此本次不做假数据、不做空跳转、不做点击后 toast 提示,而是:
|
|
|
+
|
|
|
+- 保留区块标题和结构
|
|
|
+- 明确显示“当前版本暂未开发”
|
|
|
+- 对未开发按钮使用禁用态或不可点击态
|
|
|
+
|
|
|
+### 4. 计算类展示信息由后端推导,不回写数据库
|
|
|
+
|
|
|
+“到店频率”本质上是基于顾客施术记录的派生信息。
|
|
|
+
|
|
|
+因此本次采用:
|
|
|
+
|
|
|
+- 后端详情接口临时计算 `visitFrequencyLabel`
|
|
|
+- 前端只展示该派生值
|
|
|
+- 不在 `customer` 表中新增存储列
|
|
|
+
|
|
|
+## 现状分析
|
|
|
+
|
|
|
+### 1. 当前前端现状
|
|
|
+
|
|
|
+当前前端主线中已经具备:
|
|
|
+
|
|
|
+- 顾客列表页 `CustomerListPage`
|
|
|
+- 顾客新建页 `CustomerFormPage`
|
|
|
+- 顾客 API:列表、创建、汇总
|
|
|
+- 顾客表单映射工具 `shared/customerForm.ts`
|
|
|
+
|
|
|
+当前缺失:
|
|
|
+
|
|
|
+- 顾客详情路由
|
|
|
+- 顾客详情页组件
|
|
|
+- 顾客编辑路由
|
|
|
+- 顾客详情接口
|
|
|
+- 顾客更新接口
|
|
|
+
|
|
|
+同时,当前 `CustomerFormPage` 已经包含以下字段:
|
|
|
+
|
|
|
+- `nextFollowDate`
|
|
|
+- `recommendVisitDate`
|
|
|
+
|
|
|
+这意味着“新增页缺少提醒/下次到店输入”的问题,在当前主线代码里已经部分补齐,但还没有与编辑模式统一收口。
|
|
|
+
|
|
|
+### 2. 当前后端现状
|
|
|
+
|
|
|
+当前后端已经具备:
|
|
|
+
|
|
|
+- `POST /api/v1/customers`
|
|
|
+- `GET /api/v1/customers`
|
|
|
+- `GET /api/v1/customers/summary`
|
|
|
+
|
|
|
+且数据模型已经与 [数据库设计.md](file:///Users/yuchen/Documents/hairstylist/backend/docs/数据库设计.md#L16-L54) 对齐。
|
|
|
+
|
|
|
+当前缺失:
|
|
|
+
|
|
|
+- `GET /api/v1/customers/:id`
|
|
|
+- `PATCH /api/v1/customers/:id`
|
|
|
+- 基于 `customer_treatment_record` 的到店频率推导
|
|
|
+
|
|
|
+### 3. 旧详情页的可复用价值
|
|
|
+
|
|
|
+通过 git 历史可以确认旧版 `CustomerDetailPage` 具备以下价值:
|
|
|
+
|
|
|
+- 页面层次完整
|
|
|
+- 顶部 Hero 区适合承接头像、姓名、下次到店信息
|
|
|
+- 卡片式信息区适合继续复用到当前顾客详情
|
|
|
+- 未开发区块可直接复用旧页面中的“历史/照片/CTA”视觉结构
|
|
|
+
|
|
|
+但旧详情页曾依赖旧字段模型,因此恢复时必须做一次结构保留、字段重映射。
|
|
|
+
|
|
|
+## 方案选择
|
|
|
+
|
|
|
+本次采用以下方案:
|
|
|
+
|
|
|
+- 恢复旧版详情页的页面结构
|
|
|
+- 按当前数据库字段和真实 API 重建详情页数据模型
|
|
|
+- 将 `CustomerFormPage` 改造为 `new` / `edit` 共用页面
|
|
|
+- 只补充顾客详情与顾客更新接口,不扩展未开发模块的真实后端能力
|
|
|
+
|
|
|
+不采用以下方案:
|
|
|
+
|
|
|
+- **直接恢复旧文件**:会重新引入旧错误字段模型
|
|
|
+- **重新完全改写详情页结构**:偏离“优先用之前的详情页面”的用户要求
|
|
|
+- **本次连施术历史、照片、提醒接口一起做完**:会把当前 case 做胖,超出确认范围
|
|
|
+
|
|
|
+## 路由设计
|
|
|
+
|
|
|
+本次顾客模块路由收口为:
|
|
|
+
|
|
|
+- `/:locale/customers`:顾客列表页
|
|
|
+- `/:locale/customers/new`:顾客新建页
|
|
|
+- `/:locale/customers/:customerId`:顾客详情页
|
|
|
+- `/:locale/customers/:customerId/edit`:顾客编辑页
|
|
|
+
|
|
|
+其中:
|
|
|
+
|
|
|
+- `CustomerListPage` 负责进入详情页
|
|
|
+- `CustomerDetailPage` 负责进入编辑页
|
|
|
+- `CustomerFormPage` 同时处理 `new` 与 `edit`
|
|
|
+
|
|
|
+## 页面设计
|
|
|
+
|
|
|
+## 1. 顾客列表页
|
|
|
+
|
|
|
+### 1.1 详情按钮 UI
|
|
|
+
|
|
|
+当前列表页没有独立操作列,详情入口的视觉层级也不够明确。
|
|
|
+
|
|
|
+本次调整为:
|
|
|
+
|
|
|
+- 在列表每行增加独立操作列
|
|
|
+- 详情入口使用次级按钮样式
|
|
|
+- 按钮文案继续使用当前双语 copy 中的“详情 / 詳細”
|
|
|
+- 按钮点击进入 `/customers/:customerId`
|
|
|
+
|
|
|
+设计意图:
|
|
|
+
|
|
|
+- 保持操作入口清晰
|
|
|
+- 避免“详情”按钮和顾客信息、状态标签混在一起
|
|
|
+- 不在本 case 中额外加入更多行内动作,保持单一目标
|
|
|
+
|
|
|
+### 1.2 列表项字段
|
|
|
+
|
|
|
+列表页继续只展示当前必要字段:
|
|
|
+
|
|
|
+- 头像
|
|
|
+- 姓名
|
|
|
+- 电话
|
|
|
+- 发长
|
|
|
+- 到店计划 `planDate`
|
|
|
+- 烦恼 `trouble`
|
|
|
+- 跟进状态 `followState`
|
|
|
+- 操作按钮
|
|
|
+
|
|
|
+## 2. 顾客详情页
|
|
|
+
|
|
|
+详情页基于旧版页面结构恢复,但展示内容按当前字段语义重构。
|
|
|
+
|
|
|
+### 2.1 顶部 Hero 区
|
|
|
+
|
|
|
+Hero 区展示:
|
|
|
+
|
|
|
+- 顾客头像
|
|
|
+- 顾客姓名
|
|
|
+- 姓名读音
|
|
|
+- 电话
|
|
|
+- 期望联系渠道
|
|
|
+- 下次到店日期 `recommendVisitDate`
|
|
|
+- 提醒时间 `nextFollowDate`
|
|
|
+
|
|
|
+右上角操作区保留:
|
|
|
+
|
|
|
+- 返回列表
|
|
|
+- 进入编辑
|
|
|
+
|
|
|
+旧版中的“开始模拟”入口本次不作为主操作恢复到详情页 Hero 中,原因如下:
|
|
|
+
|
|
|
+- 用户已经要求 AI 发型模拟在详情页中标记为未开发
|
|
|
+- 若在 Hero 中保留可点击模拟入口,会造成和未开发状态冲突
|
|
|
+
|
|
|
+### 2.2 基础信息区
|
|
|
+
|
|
|
+基础信息区展示以下字段:
|
|
|
+
|
|
|
+- 手机号 `phone`
|
|
|
+- 邮箱 `email`
|
|
|
+- 生日 `birthday`
|
|
|
+- 期望联系渠道 `expectContact`
|
|
|
+- 到店频率 `visitFrequencyLabel`
|
|
|
+
|
|
|
+当 `visitFrequencyLabel` 无法计算时,显示:
|
|
|
+
|
|
|
+- `未记录`
|
|
|
+
|
|
|
+### 2.3 咨询信息区
|
|
|
+
|
|
|
+展示以下字段:
|
|
|
+
|
|
|
+- 到店计划 `planDate`
|
|
|
+- 来店目的 `visitPurpose`
|
|
|
+- 烦恼 `trouble`
|
|
|
+- 咨询内容 `consultContent`
|
|
|
+- 期待造型 `expectLook`
|
|
|
+
|
|
|
+### 2.4 头发信息区
|
|
|
+
|
|
|
+展示以下字段:
|
|
|
+
|
|
|
+- 发长 `hairLength`
|
|
|
+- 发质 `hairTexture`
|
|
|
+- 注意事项 `notice`
|
|
|
+- 过敏备注 `allergy`
|
|
|
+- 内部备注 `innerRemark`
|
|
|
+
|
|
|
+### 2.5 下次到店区
|
|
|
+
|
|
|
+单独展示:
|
|
|
+
|
|
|
+- 下次到店 `recommendVisitDate`
|
|
|
+- 提醒时间 `nextFollowDate`
|
|
|
+
|
|
|
+并保留一个“发送提醒”按钮,但本次处理为:
|
|
|
+
|
|
|
+- 禁用态按钮
|
|
|
+- 明确显示“未开发”
|
|
|
+
|
|
|
+### 2.6 施术历史区
|
|
|
+
|
|
|
+施术历史区保留标题与卡片结构,但内容统一为未开发态:
|
|
|
+
|
|
|
+- 标题存在
|
|
|
+- 内容显示“当前版本暂未开发”
|
|
|
+- 不渲染伪造历史记录列表
|
|
|
+
|
|
|
+### 2.7 过往照片区
|
|
|
+
|
|
|
+过往照片区保留旧版图片区块视觉结构,但内容统一为未开发态:
|
|
|
+
|
|
|
+- 标题存在
|
|
|
+- 网格区显示空占位
|
|
|
+- 辅助说明“当前版本暂未开发”
|
|
|
+
|
|
|
+### 2.8 AI 发型模拟区
|
|
|
+
|
|
|
+AI 发型模拟区单独保留为一个未开发卡片或 CTA 区:
|
|
|
+
|
|
|
+- 标题存在
|
|
|
+- 主按钮存在但禁用
|
|
|
+- 文案明确为未开发
|
|
|
+
|
|
|
+这样可以延续旧版详情页的页面节奏,但不会误导为可用能力。
|
|
|
+
|
|
|
+## 3. 顾客表单页
|
|
|
+
|
|
|
+### 3.1 页面定位
|
|
|
+
|
|
|
+`CustomerFormPage` 是本次唯一的顾客表单页面。
|
|
|
+
|
|
|
+它承载两种模式:
|
|
|
+
|
|
|
+- `new`
|
|
|
+- `edit`
|
|
|
+
|
|
|
+### 3.2 模式判定
|
|
|
+
|
|
|
+模式判定规则:
|
|
|
+
|
|
|
+- 无 `customerId` 时为 `new`
|
|
|
+- 有 `customerId` 时为 `edit`
|
|
|
+
|
|
|
+### 3.3 `new` 模式
|
|
|
+
|
|
|
+行为:
|
|
|
+
|
|
|
+- 使用 `emptyCustomerForm()`
|
|
|
+- 提交到 `createCustomer()`
|
|
|
+- 成功后返回顾客列表页
|
|
|
+
|
|
|
+### 3.4 `edit` 模式
|
|
|
+
|
|
|
+行为:
|
|
|
+
|
|
|
+- 页面初始化请求顾客详情
|
|
|
+- 通过 `customerToFormValues()` 回填表单
|
|
|
+- 提交到 `updateCustomer()`
|
|
|
+- 成功后返回对应顾客详情页
|
|
|
+
|
|
|
+### 3.5 统一字段集合
|
|
|
+
|
|
|
+新增与编辑必须共享同一套字段:
|
|
|
+
|
|
|
+- 基础信息
|
|
|
+- 头像
|
|
|
+- 咨询信息
|
|
|
+- 头发信息
|
|
|
+- 跟进信息
|
|
|
+
|
|
|
+尤其要确保以下字段在 `new` 和 `edit` 都存在:
|
|
|
+
|
|
|
+- `nextFollowDate`
|
|
|
+- `recommendVisitDate`
|
|
|
+
|
|
|
+### 3.6 copy 策略
|
|
|
+
|
|
|
+本次不新建第二套布局 copy,而是对现有 copy 做模式化扩展:
|
|
|
+
|
|
|
+- 标题
|
|
|
+- 页面描述
|
|
|
+- badge
|
|
|
+- 返回按钮
|
|
|
+- 提交按钮
|
|
|
+- 底部说明文案
|
|
|
+
|
|
|
+这些文案按 `new` / `edit` 分别定义。
|
|
|
+
|
|
|
+## API 设计
|
|
|
+
|
|
|
+## 1. 获取顾客详情
|
|
|
+
|
|
|
+接口:
|
|
|
+
|
|
|
+`GET /api/v1/customers/:id`
|
|
|
+
|
|
|
+返回字段以当前顾客实体为主,并额外附加:
|
|
|
+
|
|
|
+```ts
|
|
|
+type CustomerDetailResponse = CustomerEntity & {
|
|
|
+ visitFrequencyLabel: string
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+规则:
|
|
|
+
|
|
|
+- 仅允许访问当前登录发型师名下顾客
|
|
|
+- 若顾客不存在或不属于当前发型师,返回 `404`
|
|
|
+- 未开发区块所需内容不从该接口额外扩展复杂嵌套结构
|
|
|
+
|
|
|
+## 2. 更新顾客
|
|
|
+
|
|
|
+接口:
|
|
|
+
|
|
|
+`PATCH /api/v1/customers/:id`
|
|
|
+
|
|
|
+请求体与创建顾客使用同一字段模型:
|
|
|
+
|
|
|
+```ts
|
|
|
+type UpdateCustomerRequest = CustomerUpsertInput
|
|
|
+```
|
|
|
+
|
|
|
+规则:
|
|
|
+
|
|
|
+- 仅允许更新当前登录发型师名下顾客
|
|
|
+- 不允许修改 `hairstylist_id`
|
|
|
+- 不允许前端传 `isFirstRegister` 作为编辑开关
|
|
|
+- 依旧沿用当前数据库字段模型,不引入旧字段兼容
|
|
|
+
|
|
|
+## 到店频率计算规则
|
|
|
+
|
|
|
+“到店频率”基于 `customer_treatment_record` 计算。
|
|
|
+
|
|
|
+### 1. 数据来源
|
|
|
+
|
|
|
+查询条件:
|
|
|
+
|
|
|
+- `customer_id = 当前顾客`
|
|
|
+- `hairstylist_id = 当前登录发型师`
|
|
|
+- `is_deleted = 0`
|
|
|
+
|
|
|
+按 `treatment_time` 升序排序。
|
|
|
+
|
|
|
+### 2. 空态
|
|
|
+
|
|
|
+若有效施术记录少于 2 条,则返回:
|
|
|
+
|
|
|
+- `未记录`
|
|
|
+
|
|
|
+### 3. 计算方法
|
|
|
+
|
|
|
+若有效施术记录不少于 2 条:
|
|
|
+
|
|
|
+- 计算相邻施术时间的天数差
|
|
|
+- 求平均值
|
|
|
+- 按区间映射为展示文案
|
|
|
+
|
|
|
+### 4. 文案映射
|
|
|
+
|
|
|
+- `<= 45 天`:`约 1.5 个月`
|
|
|
+- `46 - 75 天`:`约 2 个月`
|
|
|
+- `76 - 105 天`:`约 3 个月`
|
|
|
+- `> 105 天`:`约 3 个月以上`
|
|
|
+
|
|
|
+该值只用于详情页展示,不回写顾客表。
|
|
|
+
|
|
|
+## 前端数据模型调整
|
|
|
+
|
|
|
+本次前端 API 层需要新增:
|
|
|
+
|
|
|
+- `getCustomerById(customerId)`
|
|
|
+- `updateCustomer(customerId, input)`
|
|
|
+
|
|
|
+`contracts.ts` 中需要扩展顾客详情返回结构,以承接:
|
|
|
+
|
|
|
+- `visitFrequencyLabel`
|
|
|
+
|
|
|
+`shared/customerForm.ts` 继续作为创建与编辑的统一映射层,不新增第二套编辑专用映射逻辑。
|
|
|
+
|
|
|
+## 未开发占位策略
|
|
|
+
|
|
|
+本次统一采用“结构保留 + 能力禁用”的未开发策略:
|
|
|
+
|
|
|
+- 施术历史:区块保留,内容未开发
|
|
|
+- 过往照片:区块保留,内容未开发
|
|
|
+- AI 发型模拟:区块保留,按钮禁用
|
|
|
+- 发送提醒:按钮禁用
|
|
|
+
|
|
|
+原因:
|
|
|
+
|
|
|
+- 便于后续 case 继续在既有结构上填充真实能力
|
|
|
+- 避免出现“没有页面结构,后续又要重搭布局”的返工
|
|
|
+- 同时满足本 case 不扩展功能边界的要求
|
|
|
+
|
|
|
+## 测试策略
|
|
|
+
|
|
|
+### 1. 后端单测
|
|
|
+
|
|
|
+至少覆盖:
|
|
|
+
|
|
|
+1. `getById()` 仅能读取当前发型师的顾客
|
|
|
+2. `update()` 仅能更新当前发型师的顾客
|
|
|
+3. 施术记录不足 2 条时返回 `未记录`
|
|
|
+4. 施术记录达到 2 条以上时返回正确的频率区间文案
|
|
|
+
|
|
|
+### 2. 后端 e2e
|
|
|
+
|
|
|
+至少覆盖:
|
|
|
+
|
|
|
+1. 未登录访问详情返回 `401`
|
|
|
+2. 获取详情成功
|
|
|
+3. 编辑顾客成功
|
|
|
+4. 非所属发型师访问顾客详情返回 `404`
|
|
|
+
|
|
|
+### 3. 前端测试
|
|
|
+
|
|
|
+至少覆盖:
|
|
|
+
|
|
|
+1. 列表页详情按钮跳转到详情页
|
|
|
+2. 详情页正确渲染顾客字段
|
|
|
+3. 详情页未开发模块占位可见
|
|
|
+4. `CustomerFormPage` 在 `new` / `edit` 模式下显示不同文案
|
|
|
+5. `CustomerFormPage` 在 `edit` 模式下会回填顾客数据
|
|
|
+6. `CustomerFormPage` 在 `edit` 模式下提交更新接口
|
|
|
+
|
|
|
+## 风险与约束
|
|
|
+
|
|
|
+### 1. 旧版详情页字段模型已经失效
|
|
|
+
|
|
|
+实施时要警惕直接复制旧代码,避免把旧字段名重新带回当前主线。
|
|
|
+
|
|
|
+### 2. 当前 copy 结构可能不足以承载 `edit` 模式
|
|
|
+
|
|
|
+本次需要扩充文案配置,但仍应以当前 copy 结构延展为主,避免另起一套页面文案模型。
|
|
|
+
|
|
|
+### 3. `customer_treatment_record` 当前未接入前端
|
|
|
+
|
|
|
+这正是本次将施术历史区块标记为未开发的原因。后端只需要为“到店频率”做最小计算,不需要同步开放完整历史接口。
|
|
|
+
|
|
|
+### 4. 详情页恢复后会重新打开此前被删除的路由
|
|
|
+
|
|
|
+因此需要同步更新现有 `App` 路由测试,移除“已删除详情页会重定向”的断言,改为新的可访问行为验证。
|
|
|
+
|
|
|
+## 验收标准
|
|
|
+
|
|
|
+- 顾客列表页中的“详情”按钮具有清晰可点击的按钮样式,并可进入详情页。
|
|
|
+- 顾客详情页成功恢复,且页面结构沿用旧版详情页的大框架。
|
|
|
+- 顾客详情页展示字段完全基于当前数据库对齐后的顾客模型。
|
|
|
+- “到店频率”由后端基于施术记录推断,无记录时显示 `未记录`。
|
|
|
+- 施术历史、过往照片、AI 发型模拟、发送提醒均明确显示为未开发。
|
|
|
+- `CustomerFormPage` 同时支持新建和编辑两种模式。
|
|
|
+- 新建和编辑页面共享同一套布局和字段集合。
|
|
|
+- 新建和编辑均包含提醒时间与下次到店字段。
|
|
|
+- 详情页、编辑页只允许访问当前登录发型师名下顾客。
|
|
|
+
|
|
|
+## 最终结论
|
|
|
+
|
|
|
+本次 case 的正确完成定义为:
|
|
|
+
|
|
|
+1. 顾客详情页重新回到主线代码中,但以当前数据库字段语义为准,而不是复活旧模型。
|
|
|
+2. 新增与编辑统一为一个共享表单页面,不再维护两套布局。
|
|
|
+3. 到店频率由后端按 `customer_treatment_record` 推导,不新增冗余存储字段。
|
|
|
+4. 施术历史、过往照片、AI 发型模拟与发送提醒全部明确标记为未开发。
|
|
|
+5. 列表 -> 详情 -> 编辑链路可用,但 case 范围不扩展到完整历史、照片和提醒系统。
|