# 汇总大表(道路运输量汇总表)问题交接说明 > 交接日期:2026-09-21 交接人:郑玉洁 接手人:待定 > 范围:报表生成 → 汇总大表(`生成_道路运输量汇总表.xlsx`,19 个页签)一键生成功能及其全部遗留问题 > 本文只写「接手人动手前必须知道的事」,功能全貌见第 1 节列的前置文档。 ## 0. 一句话现状 8 月汇总大表已能做到「导入基础数据 → 一键生成」,与人工母版逐格比对基本一致。但有两个高危遗留: 1. ~~**历史同期(2025 年)列在两套口径之间没有统一** —— 「中口径排名」页与「中口径明细」页的累计同比对不上(黄冈 7.74% vs 7.64%),**这是第一优先问题**。~~ **已于 2026-09-21 按方案 A 解决,见第 4 章。** 2. **每月要人工准备一份新母版**,程序不会自己扩列,9 月及以后不解决就会卡住出表。 ## 1. 前置阅读(先看这 5 份,约 30 分钟建立概念) | 文档 | 作用 | | --- | --- | | `docs/生成汇总大表/输入输出与逻辑关系总表_2026-09-03.md` | 每个页签的输入、输出、取数来源 | | `docs/生成汇总大表/页签逻辑关系说明.md` | 页签之间的公式依赖关系 | | `docs/汇总大表数据驱动改造方案_2026-09-07.md` | 数据驱动改造的整体设计 | | `docs/问题汇总/汇总表问题汇总_2026-09-17.md` | 第一批(8 月空白/排名不对)的问题与根因 | | `docs/问题汇总/汇总表三条主线修复方案_2026-09-18.md` | 「公式不重算」主线的修复方案 | 对外/对同事解释用:`D:\桌面\报表生成原理说明_2026-09-20.md`、`D:\桌面\系统实现汇总说明_2026-09-20.md`。 ## 2. 生成原理速览(6 步) 入口:前端 `traffic-audit-web/src/views/ReportExport.vue`(报表生成页勾选「汇总大表」)→ 后端 `ReportExportController` → `ReportExportTaskService`(异步任务 + 进度 + 10 分钟内存缓存)→ `ReportExportService.exportSummaryWorkbook()`(`ReportExportService.java:3522`)。 1. **找母版**:`resolveSummaryMother()`(:4464)在 `docs/生成汇总大表/` 下按文件名 `{yyyy}年{M}月道路运输量汇总表.xlsx` **精确查找**,找不到直接报「未找到模板文件」。母版**不入库、不随程序分发**。 2. **回填台账页当月值**:`SummaryWorkbookFiller.fillMonthlyLedger()`(`SummaryWorkbookFiller.java:54`)回填 6 张台账页 —— 班线包车/公交/出租(`fillCityRows()`,写 1~当月全月)、轨道轮渡、货运、网约车(后两者**只写当月**,历史月沿用母版)。 3. **补齐公式**:`ensureMonthFormulas()`(:432)+ `ensureMonthYoyFormulas()`(:549)按月把「当月值/同比/累计」公式右移;`repairCumulativeYoyFormulas()`(:777)修累计同比分母。 4. **现算成品页**:`refreshSummaryCumulativeSheets()`(:3984)重算 城市汇总 / 城市分市州 / 中口径分析 / 道路运输周转量 四页。 5. **搬值排名页**:`refreshSummaryRankSheets()`(:3753)→ `copyRankValues()`(:3766)把 `exportFreightRank / exportTurnoverRank / exportPassengerMidRank` 三个独立生成器的结果拷进 货运量排名 / 货运周转量排名 / 中口径排名。 6. **收尾**:`applyTwoDecimalFormat()`(全精度存储 + 显示两位小数)→ `recalcWorkbookFormulas()`(:3601,`evaluateAll` 写回缓存值)→ `fullCalcOnLoad=true` → 输出。 > **关键认知**:母版本身就是公式驱动的。全省行 = Σ17 市州;城市客运 / 中口径明细 = 跨表引用(如 `城市客运!C9 = =公交!C16+出租!C16+网约车!C16+'轨道、轮渡'!C9`)。所以这两页**不需要单独写数**,只要公式按月补齐 + 重算即可。 ## 3. 问题总览 | 编号 | 问题 | 状态 | 优先级 | | --- | --- | --- | --- | | P0-1 | 历史同比基数「双轨制」:中口径排名 vs 中口径明细 累计同比全市州不一致 | **已解决(2026-09-21,方案 A)** | 高 | | P0-2 | 母版依赖:每月要人工准备新母版,程序不会自己扩列 | **未解决** | 高 | | P1-1 | 城市客运页 AJ 列(2025年1-7月累计)残留在生成表 | 已修复 09-20 | - | | P1-2 | 中口径排名周转量口径与人工列不一致 | 已修复 09-19 | - | | P1-3 | 中口径排名同比与城市客运列错位 | 已修复 09-18 | - | | P1-4 | 公式写了但无缓存值,预览/二次处理看到旧值 | 已修复 09-18 | - | | P2-1 | 导出前基数体检 + 弹窗 +《数据缺失清单》页(B4) | 待排期 | 中 | | P2-2 | 增速排名措辞(D 组) | 待排期 | 低 | | P2-3 | 中口径明细 4 格 `#DIV/0!`(2025 年 8 月基数为 0) | 待业务确认 | 低 | | P2-4 | 缺母版提示未实测;部署包内是带 AJ 列的旧母版 | 待处理 | 低 | ## 4. P0-1 历史同比基数「双轨制」(本次交接重点) > **状态更新(2026-09-21):用户采用方案 A,已实施并回归通过。** 排名页的 2025 累计基数改读母版《中口径明细》静态列;黄冈 1-8 月累计同比由 7.744917% 修正为 7.641733%,与明细页一致。 ### 4.1 现象 `D:\桌面\生成数据\生成_道路运输量汇总表 (3).xlsx`(2026-09-20 14:42 生成): - 「中口径排名」M13 黄冈 1-8 月累计同比 = **7.744917%** - 「中口径明细」T55 同一格 = **7.641733%** - 两页当月累计值完全相同(`3480.930066022`),差的只是**去年同期基数**:排名页 `3230.713965` vs 明细页 `3233.810859`,差 `3.096894`。 ### 4.2 根因:两页的去年同期基数来源不同 | 页签 | 去年同期(2025)怎么来的 | 代码位置 | | --- | --- | --- | | 中口径排名 | **查库现算**,四个维度全部现算(含网约车拆分) | `loadMidClassMap()` `ReportExportService.java:2441`;网约车维度 :2531;同比 `midCumYoy()` :2404 | | 中口径明细 | 2025 列在母版里是**写死的静态数值(无公式)**,程序不重算 | 生成件「中口径明细」V/X/Z…AJ 列;`fillMonthlyLedger()` 不写 2025 列 | ### 4.3 差异定位(已逐层验证到单元格) 1. 四个维度分别比对 2025 年 1-8 月:班线+个体、城际城乡公交、城际城乡巡游出租 **全部逐位一致**;只有**城际城乡网约车**一维不同。 2. 该维只有 **2025 年 3、4 月**不同(其余 6 个月逐位一致): | | 母版静态值 | 库现算 | 差 | | --- | --- | --- | --- | | 2025-03 黄冈 | 5.203089147 | 3.938965484 | 1.264123663 | | 2025-04 黄冈 | 6.585331252 | 4.752560757 | 1.832770495 | | 合计 | 56.317159454 | 53.220265295 | **3.096894158** | 与两页基数差 `3.096894` 完全吻合。 3. 用**母版自己的出租列**(与库逐格一致)+ 订单 + pin 套现算法复算:**1/2/5/6/7/8 月逐位复现(偏差 0.000000000)**,3/4 月复现不出来 → 算法没问题,是那两格另有来源。 ### 4.4 那两格到底是什么(重要,避免接手后走弯路) - 母版(含 **9/8 程序尚未改动前的原始母版** `docs/生成汇总大表/_bak_202608母版修改前_20260916/2026年8月道路运输量汇总表.xlsx`)里,这两格**本来就是** `5.203089147` / `6.585331252` —— 不是程序算出来的,是省里提供的模板自带的。 - **不是 9/16 出租补录导致的**:9/8 原始母版的出租列(417.01/404.51、410.7/398.38)就已经和现在库里一模一样。 - 反推这两格隐含的输入(前提已验证:母版 17 市州「城市内」加总 = `2504.28` = 全省 pin 城市内,分毫不差,武汉自留 → **分摊规则与现算法完全相同**): | 市州 | 现库出租城市内 | 反推当时值 | 差 | | --- | --- | --- | --- | | 荆州 | 755.90 | 714.52 | -41.38 | | 恩施 | 496.19 | 461.54 | -34.65 | | **黄冈** | **404.51** | **378.38** | **-26.13** | | 十堰 | 339.59 | 319.28 | -20.31 | | 宜昌 | 649.59 | 651.86 | +2.27 | (2025-04 同量级:荆州 -43.71、黄冈 -28.11、恩施 -27.20…) - **结论**:母版 2025 年 3、4 月的网约车拆分,是用**另一份「巡游出租城市内客运量」**(16 个市州里 15 个都比现在低)算出来的,而母版/库里同一张表的出租列却是调整后的值 —— **母版这两列自相矛盾**。9/16 出租入库后,排名页一现算,矛盾才第一次显性化。 ### 4.5 影响面 - **不只黄冈**:除武汉(网约车城市内占比 = 100%,不参与分摊)外,**16 个市州全都有差**。 | 市州 | 同比差(百分点) | 市州 | 同比差(百分点) | | --- | --- | --- | --- | | 宜昌 | +0.5476 | 荆州 | -0.3187 | | 十堰 | -0.3529 | 鄂州 | -0.2986 | | 黄冈 | -0.1032 | 荆门 | -0.2524 | | 恩施 | -0.1342 | 黄石 | +0.0914 | | 孝感 | -0.0662 | 咸宁 | -0.0526 | | 随州 | -0.0349 | 襄阳 | -0.0352 | | 仙桃 | -0.0020 | 潜江 | -0.0174 | | 天门 | -0.0236 | 神农架 | -0.0031 | - **全省行两页完全一致**(31528.0607 / 5.810558%),因为这是**市州之间的分摊差异**,全省加总相互抵消。 ### 4.6 处置方案(2026-09-21:方案 A 已实施) **实施结果**:`exportPassengerMidRank()` 在汇总导出中复用内存母版,在独立排名表导出中打开对应母版,按表头读取《中口径明细》2025 年「总客运量」「总旅客周转量」1..N 月静态值;全省基数由 17 市州求和。静态列不完整时自动回退原库内现算并写 WARN 日志。 回归证据:2026-08 汇总大表黄冈客运量累计同比排名/明细均为 `7.641733%`;17 市州 × 客运量/周转量的累计值与累计同比共 68 个数值对全部一致,最大绝对差 `2.91e-11`;当月同比 34 个数值对最大差 `5.48e-15`。详见《功能测试报告_中口径排名同比基数方案A_2026-09-21.md》。 - **方案 A(推荐,改动小)**:让 `exportPassengerMidRank()` 取「去年同期累计」时,改用母版那份 2025 静态列(与中口径明细同源)。 - 理由:对外发布的同比,基数本该用去年定稿值;只动排名页 `midCumYoy/midCumClass` 的取数来源,2026 当月值不受影响。 - 要点:把母版 2025 列读成内存映射(按「市州+指标+月」)供排名页取用;或直接让排名页同比格改成引用中口径明细页的公式。 - **方案 B**:把中口径明细 2025 列也改成库内现算,两页都用库。 - 代价:会改动**所有已定稿的 2025 基数**,必须省局确认。 - **附带建议**:加一条导出校验 —— 两页同城同月基数不一致就写进 `problems`(B4 体检已有框架,见 P2-1)。 ### 4.7 回归验证方法(改完必须跑) 1. 生成 2026-08 汇总表; 2. 对 17 市州 × 客运量/周转量,逐格比对「中口径排名」与「中口径明细」的累计同比,要求**全部一致**; 3. 反向校验全省行仍等于 Σ17 市州、且全省同比两页一致; 4. 顺带确认 2026 年 1-8 月各月当月同比两页仍一致(当前是一致的,别改坏)。 ## 5. P0-2 母版依赖与「每月换母版」 ### 5.1 现状机制 - 母版目录 `docs/生成汇总大表/`,合法文件名只有 `{yyyy}年{M}月道路运输量汇总表.xlsx` 一种(`resolveSummaryMother()` :4464)。 - 程序**只按文件名精确匹配**,找不到即报「未找到模板文件」,**不会自己建模板**。 - 另有 `_备份_` 前缀的历史同期母版还原逻辑(`resolveSummaryDonor`)和一批 `_bak_` 备份文件,**别乱删**。 ### 5.2 痛点 - 要出 9 月表,就必须人工先做一份《2026年9月道路运输量汇总表.xlsx》放进母版目录;用户明确表示「这样很麻烦」。 - 每加一个月要动的地方(经核实只有 3 处): 1. 新月份列的同比公式(`=Q{row}/AJ{row}-1` 这类,右移 2 列); 2. 累计列的枚举要补当月(如 `SUM(V,X,Z,AB,AD,AF,AH,AJ)` → 再补 AL); 3. **插列右侧的 2025/2024/2023 三块历史区及其几千条公式引用需要 +2** —— POI 不会像 Excel 那样自动改写引用,必须程序显式平移。 ### 5.3 方案(待拍板) - **方案 A(程序自动扩列)**:预计 2-3 天。第一步只做「扩列器 + 用 7 月母版扩出 8 月、与真实 8 月母版逐格 diff」的验证报告,证明扩列器可靠后再做整链。 - **方案 B(本机 Excel 小工具一键扩列)**:预计 1 天。用 Excel COM 插列(引用由 Excel 自动调整,省掉第 3 处平移),生成新母版。 - 建议:先 B 应急(保证 9 月出表),再 A 做长效。 ### 5.4 验证方法 用 7 月母版扩列出 8 月结构,与 `docs/生成汇总大表/2026年8月道路运输量汇总表.xlsx`(已人工删过 AJ 列)逐格 diff,差异必须为 0 或全部可解释。 ## 6. 已修复但必须知悉的历史坑(避免改回去) 1. **城市客运页 AJ 列**(09-20):8 月母版城市客运页多了一列「2025年1-7月累计」,把 2025 年 8 月列挤到 AK,导致 8 月同比变成「8月 ÷ 1-7月累计」、累计同比漏计。已用 Excel COM 整列删除 AJ 并还原 36 处被 `#REF!` 的公式;备份 `_bak_202608母版删除AJ列前_20260920.xlsx`。**注意:用户当时删的是 7 月母版,而 8 月导出用的是 8 月母版 —— 母版有两本,改之前先确认改对哪本。** 2. **列号 0 基/1 基**(09-20):`colIndexOf()` 曾返回 1 基列号,POI 要 0 基,导致公式右移 2 列变成自引用、360 格循环引用。已修,新写列号换算时务必复测。 3. **`setCellFormula` 不接受带 `=` 前缀**(09-20):异常又被 `catch (Exception ignore)` 吞掉,导致累计同比分母修正静默失效。已改成 WARN 日志,**接手后新写公式时不要再吞异常**。 4. **公式必须重算写缓存值**(09-18):POI 写文件不算公式,Excel 打开靠 `fullCalcOnLoad` 会算,但系统预览、二次处理、部分 WPS 看不到。现已在收尾统一 `evaluateAll`(`recalcWorkbookFormulas()` :3601)。 5. **中口径排名周转量口径统一**(09-19):城际城乡一律用「总量 - 城市内」现算(`ReportExportService.java:2504` 附近注释),原「字段值优先」会在个别企业行差 ±0.01。 6. **`setValOrBlank()` 遇到公式单元格直接 return**(`ReportExportService.java:2740`):所以中口径排名全省行的 `SUM` 公式不会被覆盖,别试图用写值去改它。 ## 7. P2 其他待办 - **B4 导出前基数体检**:导出前检查各页签基数/期次是否齐备,缺失就弹窗 + 生成《数据缺失清单》页。已有 `midIssues`(:2435)和 `dbProblems` 两个问题清单可挂。 - **D 组 增速排名措辞**:待排期。 - **中口径明细 4 格 `#DIV/0!`**:2025 年 8 月基数为 0,不可比,是否改空白待业务口径确认。 - **缺母版提示(T08)未实测**。 - **部署包母版是旧版**(`deploy/traffic-audit-deploy-20260913/backend/docs/生成汇总大表/`、`_deploytest/`):用户 09-20 明确「部署包先不管」,发包前需同步。 - 同期存在的其他线:天门物流源文件缺失、荆州/黄石「规划内/规划外」口径待确认。 ## 8. 关键代码地图 | 文件 | 位置 | 职责 | | --- | --- | --- | | `reportexport/service/ReportExportService.java` | :139 | `checkExportReady()` 导出就绪校验 | | | :285 | `reportPreview()` 预览 | | | :2209 | `exportPassengerMidDetail()` 中口径明细独立生成器 | | | :2441 | `loadMidClassMap()` 中口径五维(0 总量 / 1 班线+个体 / 2 城际城乡公交 / 3 城际城乡巡游出租 / 4 城际城乡网约车)—— **全部查库现算** | | | :2531 | 维度 4 网约车 = `WycSplitCalc.calc()` | | | :2683 | `exportPassengerMidRank()` 中口径排名独立生成器 | | | :3522 | `exportSummaryWorkbook()` 汇总大表主入口 | | | :3753 / :3766 | `refreshSummaryRankSheets()` / `copyRankValues()` 排名页搬值 | | | :3984 | `refreshSummaryCumulativeSheets()` 四页成品页现算 | | | :4464 | `resolveSummaryMother()` 母版定位 | | | :4476 | `exportWycSplit()` 网约车拆分 | | `reportexport/calc/SummaryWorkbookFiller.java` | :54 | `fillMonthlyLedger()` 六张台账页回填 | | | :432 / :549 / :777 | `ensureMonthFormulas()` / `ensureMonthYoyFormulas()` / `repairCumulativeYoyFormulas()` 公式按月补齐与修分母 | | | :586 / :589 | `isMonthLedgerSheet()` / `isFilledLedgerSheet()` **页范围判断,曾因两者不一致出 bug** | | | :864 | `monthColumnCapacity()` 母版能容纳的月份列数 | | `reportexport/calc/WycSplitCalc.java` | :93 | `calc()` 网约车拆分(订单占比 × 全省 pin;城市内用巡游出租「城市内占比」代理,武汉自留、其余按剩余占比重分摊) | | | :201 / :241 | `loadMonthlyInput()` 取数:**先查库 `wyc_order_monthly`,库里没有才回落到 `docs/城市客运/网约车订单及全省总量.xlsx`** | | `reportexport/service/ReportExportTaskService.java` | - | 异步导出任务 + 进度 + 10 分钟内存缓存 + 数据版本守卫(`import_batch.id` 变化即失效) | | `traffic-audit-web/src/views/ReportExport.vue` | - | 报表生成页(预览/下载/进度弹窗/缓存提示) | ## 9. 数据与环境 - 后端 Spring Boot 端口 `8090`;前端 Vue2 + ElementUI 端口 `8080`(`/api` 代理到 8090)。 - 一键启停:`start-dev.ps1`(项目根目录),**必须在沙箱外运行**。 - 数据库:MySQL 8.0 `127.0.0.1:3308/traffic_audit`(root/123456);客户端 `D:\mysql\mysql-5.7.41-winx64\bin\mysql.exe`。 - 汇总大表用到的表: | 表 | 用途 | | --- | --- | | `h2031_enterprise_monthly` | 公路客运企业月报(班线/包车,中口径维度 1) | | `passenger_individual_monthly` | 个体客运(并入维度 1) | | `city_bus_monthly` | 城市公交(维度 2 = 总量 - 城市内) | | `city_taxi_monthly` | 巡游出租(维度 3 = 总量 - 城市内;也是网约车拆分的代理输入) | | `wyc_order_monthly` / `wyc_total_monthly` | 网约车订单占比与全省 pin(维度 4) | | `h2032_enterprise_monthly` | 货运量与周转量 | - 母版目录:`docs/生成汇总大表/`(含 `_bak_`/`_备份_` 历史件,**未经同意不要删**)。 - 单位约定:库内为原始单位,写入表格时 ÷10000 得「万人 / 万吨 / 万人公里」;**全精度写入,显示两位小数**(`applyTwoDecimalFormat()`)。 ## 10. 本次排查产生的证据文件(在项目根目录,尚未清理) | 文件 | 内容 | | --- | --- | | `_chk_mid.txt`、`_chk_hg*.txt` | 中口径明细/排名页黄冈数据与公式 dump | | `_chk_wyc.txt` ~ `_chk_wyc7.txt` | 网约车拆分逐市逐月复算与母版比对 | | `_chk_taxidiff.txt` | 出租页 vs 库出租逐格比对 | | `_chk_lineage.txt`、`_chk_lineage2.txt` | 母版历史版本血缘(7 份母版的 2025-03/04 值) | | `_chk_backsolve.txt` | 由母版网约车反推当时的出租输入 | | `_chk_rule.txt` | 候选分摊公式拟合结果(排除法) | | `_chk_orig.txt` | 9/8 原始母版关键格 | | `_chk_all_pref.txt` | 17 市州两页同比差异清单 | | `_chk_code*.txt`、`_chk_wyccalc.txt`、`_chk_wycdb.txt`、`_chk_filler.txt`、`_chk_freight.txt` | 相关代码段摘录 | > 说明(2026-09-27):上表中的 `_chk_*` 证据件为当时的临时文本 dump,已随历史临时文件一并清理(本地不再保留);如需复现,按本章方法重跑(数据源与步骤见上)。 ## 11. 待用户/业务确认清单(接手人先别自己拍) 1. ~~P0-1 走方案 A 还是 B?(建议 A)~~ 用户已选择方案 A,2026-09-21 已实施并回归通过。 2. P0-2 走方案 A(程序自动扩列)还是 B(Excel 小工具)?9 月是否先用 B 应急? 3. 中口径明细 4 格 `#DIV/0!` 是否改空白? 4. B4 基数体检的触发时机与弹窗文案。 ## 12. 建议的接手顺序 1. 跑通环境 + 生成一次 2026-08 汇总大表,确认能复现本文所有现象(半天)。 2. ~~处理 P0-1 方案 A(1 天,含回归)。~~ 已于 2026-09-21 完成。 3. 处理 P0-2 方案 B 出 9 月母版(1 天),随后排 A。 4. 补 B4 基数体检(1-2 天)。