# SPEC: 财务看板 Phase 2 — 144 组合全量验证 > 创建日期:2026-03-28 > 前置 SPEC:`board-finance-phase2`(已完成 T1-T6 + bugfix) > 状态:已完成 ✅(2026-03-28) > 优先级:P1 --- ## 一、目标 遍历财务看板全部 144 种筛选组合(8 时间 × 9 区域 × 2 环比),验证后端 API 返回数据与前端 `page.data` 一致性。 ## 二、组合矩阵 ### 时间筛选(8 种) | 枚举值 | 显示 | 当期范围 | 上期范围 | |--------|------|---------|---------| | month | 本月 | 月首~今天 | 上月首~上月同日 | | lastMonth | 上月 | 上月首~上月末 | 再上月首~再上月末 | | week | 本周 | 周一~今天 | 上周一~上周同天 | | lastWeek | 上周 | 上周一~上周日 | 再上周一~再上周日 | | quarter3 | 前3个月 | 往前3月首~上月末 | 再往前等长 | | quarter | 本季度 | 季首~今天 | 上季首~上季同天 | | lastQuarter | 上季度 | 上季首~上季末 | 再上季首~再上季末 | | half6 | 最近6个月 | 往前6月首~上月末 | 再往前等长 | ### 区域筛选(9 种) | 枚举值 | 显示 | 影响板块 | |--------|------|---------| | all | 全部区域 | 6 板块全显示 | | hall | 大厅 | 隐藏:预收资产/现金流出/助教分析 | | hallA | A区 | 同上 | | hallB | B区 | 同上 | | hallC | C区 | 同上 | | vip | 台球包厢 | 同上 | | snooker | 斯诺克 | 同上 | | mahjong | 麻将房 | 同上 | | ktv | 团建房 | 同上 | ### 环比开关(2 种) | 值 | 说明 | |----|------| | 0 | 关闭,环比字段为空 | | 1 | 开启,环比字段有值 | ## 三、验证项清单 每种组合需验证以下字段(共 6 板块): ### 3.1 经营一览(overview)— 始终显示 | # | 字段 | 验证规则 | |---|------|---------| | O1 | occurrence | ≥0,数字类型 | | O2 | discount | ≥0,数字类型 | | O3 | discountRate | 0~1 之间 | | O4 | confirmedRevenue | = occurrence - discount | | O5 | cashIn | ≥0 | | O6 | cashOut | ≥0 | | O7 | cashBalance | = cashIn - cashOut | | O8 | balanceRate | cashIn>0 时 = cashBalance/cashIn | | O9 | area≠all 时 | occurrence/discount/confirmedRevenue 应与 revenue 板块一致 | | O10 | compare=1 时 | 8 个 xxxCompare 字段非空,格式为 "X.X%" / "持平" / "新增" | | O11 | compare=0 时 | 8 个 xxxCompare 字段为空/null | ### 3.2 预收资产(recharge)— 仅 area=all 时返回 | # | 字段 | 验证规则 | |---|------|---------| | R1 | area≠all 时 | recharge 为 null | | R2 | actualIncome | ≥0 | | R3 | firstCharge + renewCharge | ≈ actualIncome | | R4 | cardBalance | ≥0(快照值) | | R5 | allCardBalance | ≥ cardBalance | | R6 | giftRows | 长度 3(新增/消费/余额) | | R7 | compare=1 时 | allCardBalanceCompare 非空 | ### 3.3 应计收入确认(revenue)— 始终显示 | # | 字段 | 验证规则 | |---|------|---------| | V1 | structureRows | 长度 ≥ 3(至少有主行+助教+食品) | | V2 | area≠all 时 | structureRows 只含对应区域 | | V3 | totalOccurrence | = SUM(structureRows 非 isSub 行的 amount) | | V4 | discountTotal | = SUM(discountItems 的 amount) | | V5 | confirmedTotal | = totalOccurrence - discountTotal | | V6 | discountItems | 长度 5(团购/会员折扣/手动调整/赠送卡/其他) | | V7 | channelItems | 长度 3 | | V8 | priceItems | 长度 3 | | V9 | structureRows 优惠列 | 主行 discount = discountTotal,子行按占比分摊 | | V10 | compare=1 时 | totalOccurrenceCompare/confirmedTotalCompare 非空 | | V11 | compare=1 时 | structureRows 各行 bookedCompare 非空 | ### 3.4 现金流入(cashflow)— 始终显示 | # | 字段 | 验证规则 | |---|------|---------| | C1 | consumeItems | 长度 2-3(纸币/线上/团购 或 合并项/团购) | | C2 | rechargeItems | 长度 1 | | C3 | total | = SUM(consumeItems) + SUM(rechargeItems) | | C4 | consumeItems 各项 | desc 非空(柜台现金收款等) | | C5 | compare=1 时 | totalCompare 非空,各项 compare 非空 | ### 3.5 现金流出(expense)— 仅 area=all 时显示 | # | 字段 | 验证规则 | |---|------|---------| | E1 | operationItems | 长度 ≥ 3 | | E2 | fixedItems | 长度 ≥ 4 | | E3 | coachItems | 长度 ≥ 4 | | E4 | platformItems | 长度 ≥ 3 | | E5 | total | = SUM(所有 items) | ### 3.6 助教分析(coachAnalysis)— 仅 area=all 时显示 | # | 字段 | 验证规则 | |---|------|---------| | A1 | basic.rows | 长度 1-4(初/中/高/星) | | A2 | basic.totalPay | = SUM(rows.pay) | | A3 | basic.totalShare | = SUM(rows.share) | | A4 | basic.avgHourly | 13~28 范围(基础课) | | A5 | incentive.rows | 长度 0-4 | | A6 | compare=1 时 | basic/incentive 各行 payCompare/shareCompare 非空 | ## 四、执行方案 ### 4.1 后端 API 验证(Python 脚本) 写 `scripts/ops/validate_board_finance.py`,遍历 144 种组合: 1. 登录获取 token(dev-login) 2. 循环调用 `GET /api/xcx/board/finance?time=X&area=Y&compare=Z` 3. 对每个响应按验证项清单检查 4. 输出问题清单到 `export/board-finance-validation.md` ### 4.2 前端 page.data 验证(微信开发者工具) 对后端验证发现问题的组合,用 `evaluate_script` 验证: 1. 连接开发者工具(ws://127.0.0.1:9420) 2. `page.setData({ selectedTime, selectedArea, compareEnabled })` + `page._loadData()` 3. 等待 5 秒后读取 `page.data` 4. 对比后端 API 返回值与 `page.data` 是否一致 ### 4.3 优化策略 144 种组合中,很多是等价的: - area=all 时 6 板块全显示,area≠all 时只有 3 板块(overview/revenue/cashflow) - compare=0 时不需要验证环比字段 - 不同区域的验证逻辑相同,只是数据不同 可以分层验证: 1. 第一层:8 时间 × 2 环比 × area=all = 16 种(全板块) 2. 第二层:8 时间 × 1 区域(hallA 代表)× 2 环比 = 16 种(验证区域过滤) 3. 第三层:对剩余 7 个区域,只验证 month × compare=0 = 7 种(验证区域数据差异) 4. 总计:16 + 16 + 7 = 39 种(覆盖所有逻辑分支) ## 五、执行环境 - 后端:`cd apps/backend && uvicorn app.main:app --reload` - 微信开发者工具:端口 9420 - 数据库:pg-etl-test(test_etl_feiqiu) - 脚本 cwd:项目根目录 ## 六、产出物 - `scripts/ops/validate_board_finance.py` — 验证脚本 - `export/board-finance-validation.md` — 验证报告(问题清单) - 如有问题,修复后重跑验证直到全部通过