顾客模块上一轮实现为了严格收口 case 范围,已经把顾客详情页和编辑页从当前主线代码中移除,只保留了:
但本次新 case 的目标已经变化,用户明确要求:
customer_treatment_record 做推断,而不是继续沿用旧字段模型中的静态字段当前仓库中虽然已经删除了 CustomerDetailPage,但通过 git 历史可以确认:
frontend/src/pages/dashboard/customers/CustomerDetailPage.tsx 曾经存在因此,本次正确方向不是“直接把旧文件拷回来”,而是:
customer 表字段重建展示语义。CustomerFormPage,以当前较完整的表单布局为统一基线。旧版详情页中可复用的是布局骨架和区块组织方式,不可复用的是字段语义。
可复用的结构包括:
不可继续沿用的旧字段包括但不限于:
imagesummarynextVisitvisitCyclehairConditionformulaNotefollowMessagelineStatus这些字段已经不符合当前以 customer 表为唯一事实来源的顾客模型,不应在本次恢复时被重新带回主线代码。
当前 CustomerFormPage 已经是完整度较高的表单骨架,因此本次不重新做独立编辑页布局,而是:
CustomerFormPage 作为唯一顾客表单页new / edit 模式这样可以避免新建和编辑页面继续发生结构漂移。
用户已经明确指出:
因此本次不做假数据、不做空跳转、不做点击后 toast 提示,而是:
“到店频率”本质上是基于顾客施术记录的派生信息。
因此本次采用:
visitFrequencyLabelcustomer 表中新增存储列当前前端主线中已经具备:
CustomerListPageCustomerFormPageshared/customerForm.ts当前缺失:
同时,当前 CustomerFormPage 已经包含以下字段:
nextFollowDaterecommendVisitDate这意味着“新增页缺少提醒/下次到店输入”的问题,在当前主线代码里已经部分补齐,但还没有与编辑模式统一收口。
当前后端已经具备:
POST /api/v1/customersGET /api/v1/customersGET /api/v1/customers/summary且数据模型已经与 数据库设计.md 对齐。
当前缺失:
GET /api/v1/customers/:idPATCH /api/v1/customers/:idcustomer_treatment_record 的到店频率推导通过 git 历史可以确认旧版 CustomerDetailPage 具备以下价值:
但旧详情页曾依赖旧字段模型,因此恢复时必须做一次结构保留、字段重映射。
本次采用以下方案:
CustomerFormPage 改造为 new / edit 共用页面不采用以下方案:
本次顾客模块路由收口为:
/:locale/customers:顾客列表页/:locale/customers/new:顾客新建页/:locale/customers/:customerId:顾客详情页/:locale/customers/:customerId/edit:顾客编辑页其中:
CustomerListPage 负责进入详情页CustomerDetailPage 负责进入编辑页CustomerFormPage 同时处理 new 与 edit当前列表页没有独立操作列,详情入口的视觉层级也不够明确。
本次调整为:
/customers/:customerId设计意图:
列表页继续只展示当前必要字段:
planDatetroublefollowState详情页基于旧版页面结构恢复,但展示内容按当前字段语义重构。
Hero 区展示:
recommendVisitDatenextFollowDate右上角操作区保留:
旧版中的“开始模拟”入口本次不作为主操作恢复到详情页 Hero 中,原因如下:
基础信息区展示以下字段:
phoneemailbirthdayexpectContactvisitFrequencyLabel当 visitFrequencyLabel 无法计算时,显示:
未记录展示以下字段:
planDatevisitPurposetroubleconsultContentexpectLook展示以下字段:
hairLengthhairTexturenoticeallergyinnerRemark单独展示:
recommendVisitDatenextFollowDate并保留一个“发送提醒”按钮,但本次处理为:
施术历史区保留标题与卡片结构,但内容统一为未开发态:
过往照片区保留旧版图片区块视觉结构,但内容统一为未开发态:
AI 发型模拟区单独保留为一个未开发卡片或 CTA 区:
这样可以延续旧版详情页的页面节奏,但不会误导为可用能力。
CustomerFormPage 是本次唯一的顾客表单页面。
它承载两种模式:
newedit模式判定规则:
customerId 时为 newcustomerId 时为 editnew 模式行为:
emptyCustomerForm()createCustomer()edit 模式行为:
customerToFormValues() 回填表单updateCustomer()新增与编辑必须共享同一套字段:
尤其要确保以下字段在 new 和 edit 都存在:
nextFollowDaterecommendVisitDate本次不新建第二套布局 copy,而是对现有 copy 做模式化扩展:
这些文案按 new / edit 分别定义。
接口:
GET /api/v1/customers/:id
返回字段以当前顾客实体为主,并额外附加:
type CustomerDetailResponse = CustomerEntity & {
visitFrequencyLabel: string
}
规则:
404接口:
PATCH /api/v1/customers/:id
请求体与创建顾客使用同一字段模型:
type UpdateCustomerRequest = CustomerUpsertInput
规则:
hairstylist_idisFirstRegister 作为编辑开关“到店频率”基于 customer_treatment_record 计算。
查询条件:
customer_id = 当前顾客hairstylist_id = 当前登录发型师is_deleted = 0按 treatment_time 升序排序。
若有效施术记录少于 2 条,则返回:
未记录若有效施术记录不少于 2 条:
<= 45 天:约 1.5 个月46 - 75 天:约 2 个月76 - 105 天:约 3 个月> 105 天:约 3 个月以上该值只用于详情页展示,不回写顾客表。
本次前端 API 层需要新增:
getCustomerById(customerId)updateCustomer(customerId, input)contracts.ts 中需要扩展顾客详情返回结构,以承接:
visitFrequencyLabelshared/customerForm.ts 继续作为创建与编辑的统一映射层,不新增第二套编辑专用映射逻辑。
本次统一采用“结构保留 + 能力禁用”的未开发策略:
原因:
至少覆盖:
getById() 仅能读取当前发型师的顾客update() 仅能更新当前发型师的顾客未记录至少覆盖:
401404至少覆盖:
CustomerFormPage 在 new / edit 模式下显示不同文案CustomerFormPage 在 edit 模式下会回填顾客数据CustomerFormPage 在 edit 模式下提交更新接口实施时要警惕直接复制旧代码,避免把旧字段名重新带回当前主线。
edit 模式本次需要扩充文案配置,但仍应以当前 copy 结构延展为主,避免另起一套页面文案模型。
customer_treatment_record 当前未接入前端这正是本次将施术历史区块标记为未开发的原因。后端只需要为“到店频率”做最小计算,不需要同步开放完整历史接口。
因此需要同步更新现有 App 路由测试,移除“已删除详情页会重定向”的断言,改为新的可访问行为验证。
未记录。CustomerFormPage 同时支持新建和编辑两种模式。本次 case 的正确完成定义为:
customer_treatment_record 推导,不新增冗余存储字段。