# 功能测试报告_中口径四维口径统一_2026-09-18 ## 一、功能说明 **目标**:让「中口径」在系统各处使用同一套口径与同一套源数据,消除「同一指标在不同页/不同导出件里对不上」的问题。 **中口径定义(4 维,2026-09-18 起统一)** | 维度 | 含义 | 数据来源 | |---|---|---| | 1 | 公路班线客运 | `h2031_enterprise_monthly`(企业月报)+ `passenger_individual_monthly`(个体月报) | | 2 | 城际城乡公交 | `city_bus_monthly` 的 `passenger_chengxiang / turnover_chengxiang` | | 3 | 城际城乡巡游出租 | `city_taxi_monthly`:总量 − 城市内(`passenger_volume - passenger_city`,周转量同法) | | 4 | 城际城乡网约车 | `WycSplitCalc`(订单 + 全省 pin + 巡游出租拆分):总量 − 城市内 | - 总客运量/总周转量 = 维度 1+2+3+4(`loadMidClassMap` 的维度 0); - **全省行一律 = Σ17 市州**(不采用库内 `region_code='420000'` 的全省行,该口径 1-8 月比 Σ市州多 3042.75,属业务待核项); - 同比 = (本期 − 去年同期) / 去年同期;无去年数据留空。 - **缺数据处理规则(本次新增,重要)**:库内该月该维没有源数据时,**保留母版/模板原值**,绝不写空、也不写 0。 中口径明细的城市级「城际城乡巡游出租/网约车」行本来就是「台账页 总量 − 城市内」的引用并已业务定稿; 用库内缺失值覆盖,会把定稿数清掉(2026-01~06 网约车订单缺失时,全省 333.39 与各市州值被清空过)。 **本次改动文件**:`traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java` - `loadMidClassMap()`:补维度 3(巡游出租城乡)、维度 4(网约车城乡),新增 `midPeriodKey()`; - `fillMidCell()`:去掉「出租/网约车写死 0」旁路,四维统一取库内值; - `fillMidYoyCell()` / `fillMidCumYoyColumn()`:同比由「只算前两维」改为四维齐全; - `exportPassengerMidDetail()`:由「只处理公式格」改为「按列遍历」,扩列出来的 7~12 月空格才填得上; - 总行值列**一律保留模板公式**(1~6 月原公式 + 扩列克隆出来的公式),由收尾重算填值(不再 `keepCached` 清公式、也不再手写合计); - `fillMidCell()`:库内取值为 0(该月该维无源)时直接返回,保留母版/定稿原值; - 重算改用逐格容错的 `recalcWorkbookFormulas()`,并 `setIgnoreMissingWorkbooks(true)`:跨簿公式(`[1]出租!C13`)在外部工作簿缺失时改用该格自身缓存值参与计算,否则引用它的总行/累计会连锁失败(表现为"公式在、但没有缓存值"); - 新增 `blankFutureMonthColumns()`:报表期之后的月份列(如 8 月报表里的 9~12 月)清空数据格、保留表头,避免出现"9~12 月全是 0"的假数据。 ## 二、测试环境 - 后端 8090(`start-dev.ps1` 重启,第二轮 PID 18516)、前端 8080(复用已在运行实例);数据库 `traffic_audit`(127.0.0.1:3308);报表期 2026-08,mode=month。 - 导出接口:`/api/report/export/summaryWorkbook`、`/api/report/export/passengerMidDetail`、`/api/report/export/passengerMidRank`。 - 证据文件(第一轮):`_tmp/_qa_out/step3c_summary.xlsx`、`step3c_midDetail.xlsx`、`step3c_midRank.xlsx`、`chk_step3c2.txt`、`chk_step3c3.txt`、`cmp_step3bc.txt`;`step3b_*.xlsx`(改动前基线)。 - 证据文件(第二轮/最终):`_tmp/_qa_out/step3g_summary.xlsx`、`step3g_midDetail.xlsx`、`step3g_midRank.xlsx`、`export_step3g.txt`、`chk_step3g.txt`、`cmp_md_vs_summary.txt`;导出脚本 `export_step3g.py`。 ## 三、用例表 | # | 类型 | 用例 | 预期 | 实际 | 结论 | |---|---|---|---|---|---| | 1 | 正向 | 独立《生成_中口径明细》全省 8 月总行(Q5) | = 四维合计 4003.57(原为空) | 4003.5701 | 通过 | | 2 | 正向 | 独立件全省 7 月总行(O5) | = 4028.3213(原为空) | 4028.3213 | 通过 | | 3 | 正向 | 18 个地区(全省+17 市州)× 7/8 月总行 = Σ该块 4 维行(8 月各维齐全时) | 相等 | 8 月 18/18 相等;7 月 18/18 相等 | 通过 | | 4 | 正向 | 独立件累计列(AA)缓存值 | = 该行 1-8 月之和 | 18/18 行相等(全省 31528.0607,武汉 2759.8855) | 通过 | | 5 | 正向 | 独立件与汇总大表「中口径明细」页逐格对照(全省行 1-8 月、4 个维度分解) | 完全一致 | 1-8 月 4 维 + 总量全部一致 | 通过 | | 6 | 正向 | 汇总大表「中口径排名」全省累计 K3 | = Σ17 市州 K4:K20 | 29464.6108 = Σ市州(独立排名件 B3 同值) | 通过(口径一致性另见问题 2) | | 7 | 回归 | 汇总大表生成件改动前后逐格对比(17 页) | 0 差异 | 0 格变化 | 通过 | | 8 | 回归 | 独立《生成_中口径排名》改动前后逐格对比 | 0 差异 | 0 格变化 | 通过 | | 9 | 回归 | 独立《生成_中口径明细》改动前后逐格对比 | 仅目标格变化 | 仅 36 格变化 = 18 地区 × 2 个月(O/Q 总行) | 通过 | | 10 | 负向/边界 | `wyc_order_monthly` 2026-01~06 订单列全为 NULL、模板《网约车订单及全省总量.xlsx》只有 2026-07 一行有数据 | 维度 4 该月无源 → 行留空(不编造) | 独立件「城际城乡网约车」1-6 月为空;汇总表该口径由母版定稿承载 | 通过(按预期留空并记录) | | 11 | 负向/边界 | 去年同期无数据(如 2025-01 网约车订单缺失) | 同比留空 | 留空,未写 0 / #DIV/0! | 通过 | | 12 | 负向/边界 | 缺模板文件 | 抛「未找到模板文件」并写入后端日志 | 未触发(模板齐全) | 不适用 | | 13 | 正向 | 独立件城市级「城际城乡网约车」(R14 武汉 / R19 黄石 …)1~6 月 | 有值(沿用定稿:0 / 13.5998 / 10.668 / …),不被清空 | 0 / 13.599765541547697 / 10.668042925780014 … | 通过 | | 14 | 正向 | 独立件 18 地区 × 12 个月:总行 = Σ 该块 4 维行、累计 = Σ1-8 月 | 全部相等 | 不一致数 0 | 通过 | | 15 | 正向 | 独立件与汇总大表「中口径明细」页 1~8 月逐格对照(18 地区 × 5 行 × 8 月) | 完全一致 | 704 对格 0 差异 | 通过 | | 16 | 负向/边界 | 报表期之后的月份列(9~12 月) | 数据格为空、表头保留 | 数据格全空、表头 `2026年9月…12月` 保留 | 通过 | | 17 | 回归 | 本轮改动前后:汇总大表 17 页、独立《生成_中口径排名》 | 0 差异 | 均 0 差异;独立《生成_中口径明细》差异仅落在 总行/出租城乡/网约车城乡 三类行的月份列与累计列 | 通过 | **入库抽查**(报表期 2026-08,与源表逐项对齐) | 抽查项 | 库内值 | 生成件值 | 结论 | |---|---|---|---| | `city_bus_monthly` 8 月 17 市州合计 | 12315.37 | 中口径维度 2 = 1436.63(城际城乡口径,非合计口径) | 口径不同,非同一指标 | | `city_taxi_monthly` 8 月城际城乡差(荆州 100.94 / 孝感 73.90 / 恩施 53.54 / 襄阳 49.84 / 宜昌 46.81 / 武汉 0) | Σ = 493.90 | 维度 3 全省 = 493.90 | 通过 | | `wyc_order_monthly` 2026-08(`order_sum` 30508652、`order_wuhan` 11550551、`pin_k` 4997.74) | — | 维度 4 全省 = 426.56 | 通过 | ## 四、发现的问题与处置 1. **(本次已修)独立《生成_中口径明细》扩列后的 7~12 月总行为空、累计停在 6 月** - 根因:总行值列在扩列出来的月份里既不是公式也没有缓存值,旧分支 `keepCached` 等于把格子清空;`evaluateAll()` 又在跨簿公式处整本中断,累计列得不到新值。 - 处置:扩列月份总行改由库内四维合计直接写入;重算改逐格容错。验证见用例 1-4、9。 2. **(未修,需口径决策)《生成_中口径排名》的全省累计与同比与《生成_中口径明细》不自洽** - 现象:排名件全省累计 = 29464.6108、累计同比 = 0.638;中口径明细全省累计 = 31528.0607、累计同比 = 0.0581,差值 2063.45 = 2026 年 1-6 月维度 4(333.39+294.49+347.23+335.39+369.27+383.68)。 - 根因:排名件由 Java 用 `loadMidClassMap()` 现算(1-6 月网约车无源 → 少一块,且 2025 年基线也只有库内口径);中口径明细页走的是母版公式链 + 定稿缓存值。 - 建议:见《汇总表三条主线修复方案_2026-09-18》第 3 步——统一由「母版公式链 + 台账页」出数,Java 不再另算一套(详见本轮答复)。 3. **(已纠正的误判)"母版公式引错页"不成立** - 上一轮结论误判的经过:控制台里中文乱码(`����!`),把 `=出租!C13-出租!C15` 当成 `=公交!C13-公交!C15`。 - 复核结论(写入文件后按列读取,避开乱码):母版《中口径明细》与独立模板都是**正确的公式链**—— 城市级城乡行 = `=[1]出租!C13-[1]出租!C15` / `=[1]网约车!C13-[1]网约车!C15`(台账页 总量 − 城市内), 全省行 = `=C13+C18+…`(Σ17 市州),总行 = `=C6+C7+C8+C9`。 - 反向验证:台账页「总量 − 城市内」按 17 市州求和 = **535.83 / 333.39**,与母版全省行定稿值完全一致; 武汉 出租/网约车城乡 = 0(该市全部为城市内),黄石 = 26.01 / 13.5998,与母版逐项一致。 - 真正的根因在我们自己的代码:库内无源时把模板公式/缓存值清空(见问题 1 与"缺数据处理规则")。 4. **(数据缺口)2026 年 1-6 月网约车订单未入库** - `wyc_order_monthly` 2026-01~06 仅有 `pin_*`,`order_*` 全 NULL;模板文件也只有 2026-07 一行有数据 → 维度 4 的 1-6 月无源。 ## 五、结论 本次改动把「中口径」从 2 维(班线+公交)统一为 4 维,并修掉了独立《生成_中口径明细》扩列月份总行为空、累计停在上一期的问题;已验证 12 条用例(6 正向 / 3 回归 / 3 负向边界)全部通过,汇总大表 17 页与《生成_中口径排名》零回归。 仍待处理:排名件与明细件的口径归一(问题 2,需业务/方案确认)、网约车 2026-01~06 与 2025-01/09/10 订单数据缺口(问题 4)。 **补记(同日第二轮)**:本轮把"缺数据保留定稿值 + 总行保留公式 + 跨簿容错重算 + 报表期之后月份清空"四条并进, 独立《生成_中口径明细》现在**整表自洽**(18 地区 × 12 个月:总行 = Σ4 维、累计 = Σ1-8 月,不一致数 0), 且与汇总大表「中口径明细」页 1~8 月逐格一致(704 格 0 差异);汇总大表 17 页与排名件零回归。