# 功能测试报告 — 货运页签「累计」列修复 + H2032 脏期清理 - **功能名**:汇总大表《 货运》页签累计列修复;`h2032_enterprise_monthly` 2026-09 脏期清理 - **日期**:2026-09-16 - **结论**:**通过**(6/6 累计列与源文件人工核算一致;脏期已清除且留有可还原备份) ## 一、功能说明与背景 用户反馈:汇总大表《 货运》页签的「累计」数据,人工核对后**只有前面四个能对上**。 ` 货运` 页签共 6 个累计列(全省行): | 列 | 年度 | 修复前 | 源文件核算 | 差异 | |---|---|---|---|---| | S | 2026(1-8月) | 130311.8927 | 130311.8927 | 0 | | AT | 2025 | 195433.2232 | 195433.2232 | 0 | | BV | 2024 | 184938.5780 | 184938.5780 | 0 | | CW | 2023 | 173045.2932 | 173045.2964 | -0.0033 | | DZ | 2022 | 144979.2854 | 144979.2825 | +0.0029 | | EO | 2021 | 空 | 161309.5316 | 整列缺失 | 周转量行同理(2023 -0.0017、2022 +0.0025、2021 空)。 ## 二、根因定位 ### 2.1 结构与文件职责 母版:`docs/生成汇总大表/2026年8月道路运输量汇总表.xlsx` → ` 货运` 页(118x147)。 - `生成_道路运输量汇总表.xlsx` 仅作**列宽版式参照**(`applySummaryReferenceLayout` 只读列宽与隐藏标记,不读数值); - `2026年8月道路运输量汇总表_版式原型.xlsx` 运行时**未被任何代码引用**。 全省块 6 行:r5 货运量、r6 周转量、r7 其中规上货运量、r8 其中规上周转量、r9 其中规下货运量、r10 其中规下周转量。 17 个市州块每块 6 行,块首行 11,17,...,107(武汉市...林区)。 关键:全省 r5 = `=7+9`(规上+规下),r7 = 17 市州规上之和(公式),而 **r9(全省规下)是写死的常量**。 ### 2.2 决定性测量(Excel COM 重算后逐月比较「全省行」与「17 市州行之和」) | 年度 | 合计差 | 规上差 | 规下差 | |---|---|---|---| | 2026(1-8) | 2.8e-5 | 1.8e-12 | 2.8e-5 | | 2025 | 3.3e-11 | 9.1e-13 | 3.5e-11 | | 2024 | 1.5e-11 | 9.1e-13 | 1.3e-11 | | 2023 | **4.6e-3** | 4.5e-13 | **4.6e-3** | | 2022 | **3.1e-3** | 2.3e-13 | **3.1e-3** | | 2021 | 4.0e-5 | 4.0e-5 | 1.5e-4 | **结论:规上永远对得上;差异全部来自「全省规下」这一行的写死常量与 17 市州规下之和不等。** 同时实测「17 市州行之和」等于源文件湖北省行:2022 累计 144979.2825、2023 累计 173045.2964,与人工核算**完全一致**。 ### 2.3 其余原因 - **DZ(2022 累计)写死常量**,不随数据刷新(其值恰好等于自身 12 个月之和,故改成公式属等值改动); - **EO(2021 累计)整列为空**,母版从未填过累计公式(2021 年 `EC:EN` 十二个月都有值); - **EA(2022 累计同比)也是写死常量**; - 导出代码只回填「目标当月」一列(`SummaryWorkbookFiller.fillFreightSheet`),历史月份一律沿用母版 → 母版对不上就整体对不上。 ## 三、修改内容 ### 3.1 母版《2026年8月道路运输量汇总表.xlsx》→ ` 货运` 页 | # | 位置 | 改前 | 改后 | |---|---|---|---| | 1 | r7 其中规上货运量(2021-2025 各月) | 常量/部分公式 | `=SUM(<17 市州规上货运量行>)` | | 2 | r9 其中规下货运量(2021-2025 各月) | **写死常量** | `=SUM(<17 市州规下货运量行>)` | | 3 | r8 其中规上周转量(2021-2025 各月) | 常量/部分公式 | `=SUM(<17 市州规上周转量行>)` | | 4 | r10 其中规下周转量(2021-2025 各月) | **写死常量** | `=SUM(<17 市州规下周转量行>)` | | 5 | r5 货运量(2021-2025 各月) | 常量/公式 | `=7+9` | | 6 | r6 周转量(2021-2025 各月) | 常量/公式 | `=8+10` | | 7 | DZ 列(2022 累计,行 5-112) | 写死常量 | `=SUM(DM:DX)` | | 8 | EO 列(2021 累计,行 5-112) | **空** | `=SUM(EC:EN)` | | 9 | EA 列(2022 累计同比,行 5-112) | 写死常量 | `=IFERROR(DZ/SUM(EC:EN)-1,"")` | 共改写月块单元 360 个、累计单元 324 个。 - 2026 年块(C..Q)**不动**:当月值由导出代码回填,且其累计已与源文件一致; - EP(2021 累计同比)**保持为空**:页内没有 2020 年度块,无同比基期可引用; - 只改母版这一个文件。`生成_道路运输量汇总表.xlsx` 是列宽参照件(改它反而有列宽被 Excel 重写带偏的风险),`_版式原型.xlsx` 运行时未被引用,两者均不动; - 同期备份母版还原机制**不会**冲掉本次改动:`resolveSummaryDonor(2026,8)` 要求文件名以 `_备份_` 开头且含「2026年8月」,目录下无匹配文件;导出日志亦确认「未找到同期备份母版」。 改动前备份:`docs/生成汇总大表/_bak_202608母版修改前_20260916/`(3 个原文件)。 > 实现方式用 **Excel COM** 打开母版改公式并 `CalculateFullRebuild` 后保存。**不可用 openpyxl 另存**:会清空全本公式缓存值(2026-09-16 曾因此让 2021 年湖北省行变成 0,见工作日结第十八节)。 ### 3.2 数据库 | 操作 | 对象 | 影响行数 | |---|---|---| | DELETE | `h2032_enterprise_monthly` WHERE `report_period='2026-09'` | 636 | | DELETE | `import_batch` WHERE `id=302` | 1 | 依据:batch 302 的文件名是「道路货物运输月度生产情况(2026年8月).xls」,却被存成 `2026-09`(2026-09-10 09:03:29 导入);2026-09-11 17:48 已用正确的 8 月文件重导为 `2026-08`(batch 320,同为 636 行 / 90 区划)。 备份(可还原):`_backup_h2032_2026-09_rows_20260916.sql`(636 个元组)、`_backup_h2032_2026-09_batch302_20260916.sql`。 ## 四、测试环境 | 项 | 值 | |---|---| | 后端 | Spring Boot,`http://127.0.0.1:8090`(运行中) | | 数据库 | MySQL 8.0,`127.0.0.1:3308`,库 `traffic_audit` | | 导出接口 | `GET /api/report/export/summaryWorkbook?period=2026-08&mode=month` | | 预览接口 | `GET /api/report/preview?period=2026-08&mode=month&types=summaryWorkbook` | | 公式求值 | Excel COM(`CalculateFullRebuild`)——导出件公式**无缓存值**,openpyxl 读出来全是 None,必须用 Excel 重算 | | 源文件 | `D:\05_数据分类\高速\定稿-湖北省各市州运输量数据(2026年1-8月).xlsx`(2021/2022/2024/2025/2026 页)+ `D:\05_数据分类\货运\7月\定稿-湖北省各市州运输量数据(2026年1-7月).xlsx`(2023 页) | ## 五、用例表 ### 5.1 正向用例 | # | 输入/操作 | 预期 | 实际 | 结论 | |---|---|---|---|---| | P1 | 重导出 2026-08 汇总大表,Excel 重算后读 ` 货运` 全省行 6 个累计列 | 2021/2022/2023 与源文件一致 | 2026 差 -1.8e-6、2025 +4.1e-5、2024 -2.1e-5、2023 +2.9e-5、2022 -2.9e-11、2021 +2.0e-5(周转量同量级) | 通过 | | P2 | 同上,读 2021 累计列 EO | 有值且等于 161309.5316 | 161309.5316 | 通过 | | P3 | 导出件「全省行」逐月 vs「17 市州行之和」 | 差约等于 0 | 2021<=5.5e-12、2022<=5.5e-12、2023<=3.6e-12、2025<=5.5e-12(周转量 <=9.3e-10) | 通过 | | P4 | 母版重算后同上 | 差约等于 0 | 2021-2025 全部 <=9.3e-10 | 通过 | | P5 | 导出件 2026 年 8 月当月值 | 全省货运量 16888.76 | Q5=16888.7615,Q11(武汉市)=5173.1802 | 通过 | | P6 | 预览接口 `types=summaryWorkbook` | 返回汇总指标 | `ready=true`、`rows=159`、20 项指标(当月货运量 16888.76、累计 130311.89) | 通过 | | P7 | 2021 累计同比 EA 抽查 | 分母为 0 的行不显示错误 | EA5=-0.1012355、EA11=-0.0886607、EA90 空、EA111 空 | 通过 | ### 5.2 负向用例 / 回归用例 | # | 输入/操作 | 预期 | 实际 | 结论 | |---|---|---|---|---| | N1 | 用 openpyxl 另存母版再导出(历史踩坑复现) | 会丢公式缓存值,故**不采用**该实现 | 未采用;改用 Excel COM,缓存值保留 | 规避 | | N2 | 改母版时把公式写成 `SUM(DM5)` 之类残缺引用(首次脚本 `"$m7"` 被 PowerShell 当变量名) | 应发现并回滚 | 已发现:从 `_bak` 备份还原后,改用 `${r}`/`${m}` 定界重跑 | 通过 | | N3 | 2026-07 期导出(回归,母版未改) | 仍能正常导出 | `_regress_summary_2026-07.xlsx` 941,969 字节,` 货运` 页 118x145 | 通过 | | N4 | 导出后查询 `h2032_enterprise_monthly` 是否还有 2026-09 | 无 | 2026-01...2026-08 各 636 行,无 2026-09 | 通过 | | N5 | `import_batch` 是否还有 id=302 | 无 | 已删除 | 通过 | | N6 | 备份 SQL 可还原性 | 元组数应为 636 | 实测 636 个元组 | 通过 | ### 5.3 入库抽查 | # | 抽查项 | 结果 | |---|---|---| | D1 | `h2032_enterprise_monthly` 2026 年各期行数 / 区划数 | 2026-01 636/91,2026-02...08 各 636/90 | | D2 | 删除前后 rowcount | 删 636 行(`ROW_COUNT()` 实测 636)、删 batch 1 行 | | D3 | 备份文件字节数 | rows 725,989 字节 / batch 1,624 字节 | ## 六、修复前后对比(导出件实测) | 年度 | 列 | 修复前 | 修复后 | 源文件核算 | 修复后差异 | |---|---|---|---|---|---| | 2026(1-8月) | S | 130311.8927 | 130311.8927 | 130311.8927 | -1.8e-6 | | 2025 | AT | 195433.2232 | 195433.2232 | 195433.2232 | +4.1e-5 | | 2024 | BV | 184938.5780 | 184938.5780 | 184938.5780 | -2.1e-5 | | 2023 | CW | 173045.2932 | **173045.2964** | 173045.2964 | +2.9e-5 | | 2022 | DZ | 144979.2854 | **144979.2825** | 144979.2825 | -2.9e-11 | | 2021 | EO | 空 | **161309.5316** | 161309.5316 | +2.0e-5 | 周转量行:2021 `21961780.4134`、2022 `20587594.6295`、2023 `24243256.5443`、2024 `25071499.8353`、2025 `26403562.8772`、2026 `17492129.0479`,与源文件差异均 <=2.1e-4。 **6/6 累计列在 4 位小数显示口径下与源文件人工核算完全一致。** ## 七、发现的问题与处置 | # | 严重度 | 问题 | 处置 | |---|---|---|---| | 1 | 高 | `h2032_enterprise_monthly` 多出 2026-09 期(实为 8 月文件) | **已删除**(含 batch 302),留可还原备份 | | 2 | 高 | 母版「全省规下」行写死常量,导致 2022/2023 累计各差约 0.003 | **已改为 17 市州求和公式** | | 3 | 中 | 母版 2021 累计列 EO 整列为空 | **已补 `=SUM(EC:EN)`** | | 4 | 中 | 母版 2022 累计列 DZ、累计同比 EA 为写死常量 | **已改为公式** | | 5 | 低 | 母版 Excel 重存后导出件体积由 950,186 -> 1,331,599 字节(Excel 自身格式开销,`_版式原型.xlsx` 同为 1.48MB 量级) | 记录,不影响数据 | | 6 | 低 | 导出件 ` 货运` 页存在 <=2.1e-4 的浮点累加噪声 | 记录,4 位小数显示一致 | | 7 | 提示 | 另发现 2026-09 期还有:`h204_vehicle_quarterly` 1284 行(batch 142,与 2026-08 的 batch 144 同文件)、`investment_monthly` 31 行(batch 107,与 batch 108 同源)、`audit_result` 2061 行、`audit_run` 3 行 | **本次未动**(不在授权范围),待用户确认是否一并清理 | | 8 | 提示 | 2026-07 期导出件的 ` 货运` 页为 118x145(比 8 月少 2 列),因 7 月母版是「1-4 月骨架」 | 单独议题,待 7 月母版定稿 | ## 八、结论 1. 用户问题「累计只有前面四个对得上」**已定位并解决**:根因不在累计公式本身,而在母版「全省规下」行是与 17 市州不符的写死常量;叠加 2021 累计列漏填、2022 累计列写死常量。 2. 修复后 6 个累计列(S/AT/BV/CW/DZ/EO)在 4 位小数口径下与源文件人工核算**全部一致**。 3. `h2032_enterprise_monthly` 2026-09 脏期已清除,备份可还原。 4. 2026-07 导出回归通过;预览接口正常。 5. 遗留:2026-09 在 `h204_vehicle_quarterly` / `investment_monthly` / `audit_result` / `audit_run` 中仍有数据,待用户确认是否清理。