# P7→NS1/RNS1 缺失项 #5:"我的常客"的展示字段 ## 简要结论 - 状态:✅ 已解决 - 风险等级:🟡 低 - 后端已在 PERF-1 响应中返回常客列表,包含 P7 AC4 要求的次数、小时数、收入合计三个核心字段。前端已完整展示。Schema 中 `RegularCustomer` 模型字段齐全。 ## 详细审查 ### 审查范围 - `apps/backend/app/services/performance_service.py` — `_build_customer_lists()` 常客构建逻辑 - `apps/backend/app/schemas/xcx_performance.py` — `RegularCustomer` 模型 - `apps/miniprogram/miniprogram/pages/performance/performance.wxml` — 常客列表展示 ### 发现 1. **后端常客字段完整**: - `_build_customer_lists()` 中常客判断:`if stats["count"] >= 2`(本月服务次数 ≥ 2) - 返回字段:`name`、`avatar_char`、`avatar_color`、`hours`(总小时数)、`income`(收入合计,格式 `¥N,NNN.NN`)、`count`(服务次数) - 按收入倒序排列 2. **Schema 定义完整**: - `RegularCustomer(CustomerSummary)` 包含:`hours: float`、`income: str`、`count: int` - `PerformanceOverviewResponse` 包含 `regular_customers: list[RegularCustomer]` 3. **前端展示完整**: - WXML:`{{item.count}}次 · {{fmt.hours(item.hours)}} · {{fmt.safe(item.income)}}` - 展示格式:`3次 · 4.5h · ¥1,200` - 支持展开/收起(默认显示 5 条,可展开至 20 条) 4. **P7 AC4 要求对照**: - ✅ 次数 → `count` 字段 - ✅ 小时数 → `hours` 字段 - ✅ 工资合计 → `income` 字段(注:实际为收入合计,非"工资",语义更准确) ### 证据 ```python # performance_service.py — 常客构建 if stats["count"] >= 2: regular_customers.append({ "name": name, "avatar_char": char, "avatar_color": color, "hours": round(stats["total_hours"], 2), "income": f"¥{stats['total_income']:,.2f}", "count": stats["count"], }) # 按收入倒序 regular_customers.sort( key=lambda x: float(x.get("income", "¥0").replace("¥", "").replace(",", "")), reverse=True, ) ``` ```python # xcx_performance.py — Schema class RegularCustomer(CustomerSummary): """常客。""" hours: float income: str count: int ``` ```xml {{item.count}}次 · {{fmt.hours(item.hours)}} · {{fmt.safe(item.income)}} ``` ### 建议(微调项) - 常客阈值 `count >= 2` 当前硬编码,可考虑从配置表读取(遵循 feiqiu-data-rules 规则 6) - `income` 字段在后端格式化为字符串(`¥N,NNN.NN`),与 DISPLAY-STANDARDS.md 的金额规范(`¥N,NNN` 无小数)略有差异,建议统一