# 变更审计记录:助教详情页设计稿对齐 + 数据格式化修复 | 字段 | 值 | |------|-----| | 日期 | 2026-03-29 09:16:43 | | Prompt-ID | P20260329-090937 | | Session-ID | 96ce2a05 | | Session 路径 | docs/audit/session_logs/2026-03/29/29_abf3b322_085456 | ## 操作摘要 修复助教详情页与设计稿的多项显示差异:后端金额/数量字段从预格式化字符串改为返回原始数字(避免前端 WXS 格式化 NaN),收入 color 从 hex 值改为 CSS 类名,服务记录 table 从 table_id 改为 table_name,WXML 模板统一使用 `fmt.safe()` / `fmt.money()` / `fmt.hours()` WXS 函数格式化。同时将 coach-detail 和 customer-detail 页面的自定义加载组件替换为小程序原生 `wx.showLoading`。 ## 根因分析 后端 `_format_currency()` 预格式化金额为字符串(如 "¥25,447"),前端 WXML 中 WXS `money()` 函数对字符串输入返回 NaN。违反了"TS 与 WXS 格式化互斥"规范(`frontend-backend-integration.md`)。 ## 本次对话文件变更 ### 新增文件 - `docs/audit/prompt_logs/prompt_log_20260329_090937.md` - `docs/audit/session_logs/2026-03/29/29_abf3b322_085456/main_01_96ce2a05.md` ## 改动注解 ### `apps/backend/app/schemas/xcx_coaches.py` - 变更类型:修改 - 原始原因:前端 WXS `money()` 函数对已格式化的字符串(如 "¥25,447")调用数值方法返回 NaN,需要后端返回原始数字 - 思路分析:将 `TopCustomer.balance/consume` 从 `str` → `float`,`CoachServiceRecord.income` 从 `str` → `float`,`HistoryMonth.customers` 从 `str` → `int`、`hours/salary` 从 `str` → `float`。遵循"TS 与 WXS 格式化互斥"规范,后端只返回原始数值,格式化交给前端 WXS - 修改结果:Schema 类型与 service 层返回值对齐,Pydantic 验证通过,前端 WXS 可正确格式化数值 ### `apps/backend/app/services/coach_service.py` - 变更类型:修改 - 原始原因:多处与设计稿不一致:color 用 hex 值而非 CSS 类名、金额预格式化导致前端 NaN、table 显示 id 而非名称、TASK_TYPE_MAP 缺少 relationship_building - 思路分析:(1) `_build_income` 中 color 从 hex(`#42A5F5` 等)改为 CSS 类名(`primary/success/warning/purple`),符合"后端值拼接 WXSS 类名时必须是合法 CSS 标识符"规范;(2) `_build_top_customers` 中 `balance/consume` 从 `_format_currency()` 改为返回原始 float;(3) `_build_service_records` 中 `income` 改为原始 float,`table` 从 `table_id` 改为 `table_name`;(4) `_build_history_months` 中 `customers/hours/salary` 改为原始数字;(5) TASK_TYPE_MAP 新增 `relationship_building` → "关系维护";(6) `_build_notes` 中 `ai_score` → `score` 对齐 Schema;(7) 添加 `@trace_service` 装饰器 - 修改结果:所有数值字段返回原始类型,前端 WXS 可正确格式化;color 值为合法 CSS 类名;table 显示人类可读名称 ### `apps/backend/app/services/fdw_queries.py` - 变更类型:修改 - 原始原因:`get_assistant_info` 的 hire_date 带时区后缀、`get_coach_top_customers` 未过滤散客、`get_coach_service_records` 缺少 table_name - 思路分析:(1) `get_assistant_info` 中 hire_date 从 `str(row[3])` 改为 `.strftime("%Y-%m-%d")`,去除时区信息;(2) `get_coach_top_customers` 添加 `tenant_member_id > 0` 过滤散客(散客 member_id ≤ 0,符合飞球数据规范);(3) `get_coach_service_records` LEFT JOIN `v_dim_table` 获取 `table_name`,返回 `table_name` 字段替代 `table_id` - 修改结果:hire_date 格式统一为 YYYY-MM-DD;TOP 客户列表不再包含散客;服务记录显示台桌名称而非 ID ### `apps/miniprogram/miniprogram/pages/coach-detail/coach-detail.wxml` - 变更类型:修改 - 原始原因:(1) 使用自定义加载组件(`g-toast-loading` + `t-loading`),需改为原生 `wx.showLoading`;(2) 数据展示未使用 WXS 格式化函数;(3) 更多信息表格 hours 格式化从 `fmt.hours` 改为 `fmt.hoursH`("小时"→"h") - 思路分析:移除自定义加载 DOM,引入 `format.wxs`,所有数据绑定统一使用 `fmt.safe()` / `fmt.money()` / `fmt.hours()` WXS 函数,确保 null/undefined 值安全显示 - 修改结果:页面加载使用原生遮罩,数据展示统一通过 WXS 格式化,避免 NaN 和 undefined 显示 ### `apps/miniprogram/miniprogram/pages/customer-detail/customer-detail.wxml` - 变更类型:修改 - 原始原因:使用自定义加载组件,需改为原生 `wx.showLoading`;数据展示未统一使用 WXS 格式化 - 思路分析:与 coach-detail 同步改造,移除自定义加载 DOM,统一使用 `fmt.safe()` / `fmt.money()` / `fmt.hours()` WXS 函数格式化所有数据绑定 - 修改结果:页面加载使用原生遮罩,金额/时长/文本统一通过 WXS 格式化 ### `apps/miniprogram/miniprogram/pages/customer-records/customer-records.wxml` - 变更类型:修改 - 原始原因:消费记录页面数据展示未统一使用 WXS 格式化,金额直接拼接 `¥` 前缀 - 思路分析:所有金额字段改用 `fmt.money()` 格式化,文本字段用 `fmt.safe()` 防护,时长用 `fmt.hours()` 格式化 - 修改结果:消费记录页面数据展示统一通过 WXS 格式化,与其他页面保持一致 ## 合规检查 | 检查项 | 状态 | |--------|------| | 新增迁移 SQL | 无 | | DDL 基线 | N/A | | BD 手册 | N/A(无 DB schema 变更) | | ⚠️ OpenAPI spec | 接口返回类型已变更但 spec 未同步。自动导出失败(`dashscope` 模块缺失),需手动在后端 venv 中执行 `python scripts/ops/_export_openapi.py` | ## 风险评估 - 影响范围:助教详情页(COACH-1)、客户详情页、消费记录页 - 前后端契约变更:`TopCustomer.balance/consume`、`CoachServiceRecord.income`、`HistoryMonth.customers/hours/salary` 类型从 str 变为数值类型,前端已同步适配 WXS 格式化 - 向后兼容:前端已同步修改,无兼容性问题