编辑 | blame | 历史 | 原始文档

汇总大表(道路运输量汇总表)问题交接说明

交接日期:2026-09-21 交接人:郑玉洁 接手人:待定
范围:报表生成 → 汇总大表(生成_道路运输量汇总表.xlsx,19 个页签)一键生成功能及其全部遗留问题
本文只写「接手人动手前必须知道的事」,功能全貌见第 1 节列的前置文档。

0. 一句话现状

8 月汇总大表已能做到「导入基础数据 → 一键生成」,与人工母版逐格比对基本一致。但有两个高危遗留:

  1. 历史同期(2025 年)列在两套口径之间没有统一 —— 「中口径排名」页与「中口径明细」页的累计同比对不上(黄冈 7.74% vs 7.64%),**这是第一优先问题**。
  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 中口径明细 累计同比全市州不一致 未解决 高
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 历史同比基数「双轨制」(本次交接重点)

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 完全吻合。

  1. 用**母版自己的出租列**(与库逐格一致)+ 订单 + 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 处置方案(待拍板,尚未实施)

  • 方案 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 相关代码段摘录

11. 待用户/业务确认清单(接手人先别自己拍)

  1. P0-1 走方案 A 还是 B?(建议 A)
  2. P0-2 走方案 A(程序自动扩列)还是 B(Excel 小工具)?9 月是否先用 B 应急?
  3. 中口径明细 4 格 #DIV/0! 是否改空白?
  4. B4 基数体检的触发时机与弹窗文案。

12. 建议的接手顺序

  1. 跑通环境 + 生成一次 2026-08 汇总大表,确认能复现本文所有现象(半天)。
  2. 处理 P0-1 方案 A(1 天,含回归)。
  3. 处理 P0-2 方案 B 出 9 月母版(1 天),随后排 A。
  4. 补 B4 基数体检(1-2 天)。