fix(summary): 修 2026-07 导出件「Excel 打不开」+ 补齐 7 月母版 2021/2022/2023 累计列

根因(P0):
- 7 月母版由 openpyxl 写出(文本用 <is> 存储),而 7 月存在 _备份_* 备份母版,
restoreSummaryMonthlyBlocks 整格回填时只改 t/<v>、不清旧 <is>,
产出 <c t="n"><v>67.0</v><is><t>67.00</t></is></c> 这类模式非法格,
Excel 直接判定「无法读取的内容」拒开(COM 报「不能取得类 Workbooks 的 Open 属性」)。
- leave-one-out 定位:sheet9《公交》17 格 + sheet12《轨道、轮渡》2 格,共 19 格。

修复:
- exportSummaryWorkbook 落盘前新增 normalizeStaleInlineStrings(),清掉所有
「非 inlineStr 却残留 <is>」的格子(幂等 + warn 日志)。
- restoreSummaryMonthlyBlocks 新增 skipFreightHistoryBlocks:《 货运》页 T 列及以后
(2025..2021 年度块 + 各年累计/累计同比列)永不从备份母版回填,防「生成又复活」。

母版补齐(Excel COM,与 8 月母版口径对齐):
- docs/生成汇总大表/2026年7月道路运输量汇总表.xlsx
2025..2021 五个年度块 360 格(r7/r9/r8/r10 = SUM(17 市州)、r5=r7+r9、r6=r8+r10)
+ 324 个累计格(DX=SUM(DK:DV)、EM=SUM(EA:EL)、DY=IFERROR(DX/SUM(EA:EL)-1,""))。
- 实测:7 月 DX5/EM5/CU5 与 8 月 DZ5/EO5/CW5 完全相等;
2022 累计由旧常量 144979.285376043 修正为 144979.2825(差 0.0029 = 全省规下常量与 17 市州之和的差)。

测试:docs/功能测试报告/功能测试报告_2026-07母版补齐与导出件打不开修复_2026-09-16.md
(2026-07/08 导出件均可被 Excel 打开,各 19 页;非法格复扫 0;2026-09 残留复核全 0)
4个文件已修改
1个文件已添加
226 ■■■■■ 已修改文件
docs/功能测试报告/功能测试报告_2026-07母版补齐与导出件打不开修复_2026-09-16.md 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/工作日结/工作日结_2026-09-16.md 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/生成汇总大表/2026年7月道路运输量汇总表.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/问题汇总/问题与注意事项汇总_2026-09-16.md 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/¹¦ÄܲâÊÔ±¨¸æ/¹¦ÄܲâÊÔ±¨¸æ_2026-07ĸ°æ²¹ÆëÓëµ¼³ö¼þ´ò²»¿ªÐÞ¸´_2026-09-16.md
New file
@@ -0,0 +1,86 @@
# åŠŸèƒ½æµ‹è¯•æŠ¥å‘Š â€” 2026-07 æ¯ç‰ˆè¡¥é½ & å¯¼å‡ºä»¶ã€ŒExcel æ‰“不开」修复
- æ—¥æœŸï¼š2026-09-16
- èŒƒå›´ï¼šæ±‡æ€»å¤§è¡¨ï¼ˆ`/api/report/export/summaryWorkbook`)2026-07 / 2026-08 å¯¼å‡ºï¼›`docs/生成汇总大表/2026å¹´7月道路运输量汇总表.xlsx` æ¯ç‰ˆè¡¥é½
- å…³è”:`docs/问题汇总/问题与注意事项汇总_2026-09-16.md` ç¬¬åä¸‰èŠ‚
## ä¸€ã€èƒŒæ™¯
《 è´§è¿ã€‹é¡µã€Œç´¯è®¡ã€åˆ—口径在 2026-09-16 å·²åœ¨ **8 æœˆæ¯ç‰ˆ** è½åœ°ï¼ˆè§ç¬¬åäºŒèŠ‚ï¼‰ã€‚ç”¨æˆ·ç¡®è®¤ã€Œå¯ä»¥è¡¥é½ã€ï¼Œè¦æ±‚æŠŠåŒä¸€å£å¾„è¡¥åˆ° **7 æœˆæ¯ç‰ˆ**,并解决 7 æœˆå¯¼å‡ºä»¶æ— æ³•用 Excel æ‰“开的问题。
## äºŒã€æµ‹è¯•环境
| é¡¹ | å€¼ |
|---|---|
| åŽç«¯ | Spring Boot,8090(修复后已重启) |
| å‰ç«¯ | Vue,8080 |
| æ•°æ®åº“ | MySQL 127.0.0.1:3308 / traffic_audit |
| Excel åˆ¤æ® | Excel COM `Workbooks.Open`(每例独立实例,测后强杀孤儿进程) |
| ç»“构判据 | Python `zipfile` + `xml.etree` é€éƒ¨ä»¶æ ¡éªŒã€é€æ ¼ `<c>` è§£æž |
## ä¸‰ã€å‘现的根因(两处,均为本次修复对象)
### 3.1 å¯¼å‡ºä»¶æ‰“不开:残留 `<is>` çš„非法单元格
坏件里存在 19 ä¸ª**模式非法**的格子:
```
<c r="E15" s="111" t="n"><v>67.0</v><is><t>67.00</t></is></c>
```
`<is>`(inlineStr)只允许出现在 `t="inlineStr"` çš„æ ¼é‡Œï¼›`t="n"` å´å¸¦ `<is>` å±žäºŽéžæ³•,Excel ç›´æŽ¥åˆ¤å®šã€Œæ— æ³•读取的内容」拒绝打开(COM è¡¨çŽ°ä¸ºã€Œä¸èƒ½å–å¾—ç±» Workbooks çš„ Open å±žæ€§ã€ï¼Œè¿žä¿®å¤æ¨¡å¼ `CorruptLoad=1` ä¹Ÿæ‰“不开)。
**成因**:7 æœˆæ¯ç‰ˆç”± **openpyxl** å†™å‡ºï¼ˆ`docProps/app.xml` = `Microsoft Excel Compatible / Openpyxl 3.1.5`,文本用 `<is>` å­˜å‚¨ï¼‰ã€‚导出时别的写入路径只改 `t`/`<v>`,**不清旧 `<is>`**;而 8 æœˆæ¯ç‰ˆæ˜¯ Excel åŽŸç”Ÿï¼ˆæ–‡æœ¬èµ° sharedStrings),所以同样代码下 8 æœˆä»¶æ­£å¸¸ã€7 æœˆä»¶åã€‚
**为什么只有 7 æœˆå**:7 æœˆå­˜åœ¨åŒæœŸå¤‡ä»½æ¯ç‰ˆ `_备份_2026å¹´7月道路运输量汇总表_清理前_20260904.xlsx`,`restoreSummaryMonthlyBlocks` ä¼šæ•´æ ¼å›žå¡«ï¼›å›žå¡«å†™å…¥ inlineStr æ¯ç‰ˆæ ¼æ—¶ç•™ä¸‹æ—§ `<is>`。8 æœˆæ²¡æœ‰è¯¥ `_备份_*` æ–‡ä»¶ï¼Œä¸èµ°å›žå¡«ï¼Œå› æ­¤ä¸è§¦å‘。
**定位方法**(可复用):坏件与好件除 worksheets/styles/sharedStrings å¤–**全部部件逐字节相同** â†’ ç”¨ zip æ‚交 + Excel é€ä¸€å¼€æ¡£åš leave-one-out,定位到 **sheet9《公交》(17 æ ¼) + sheet12《轨道、轮渡》(2 æ ¼)**。
### 3.2 æ¯ç‰ˆè¡¥é½è¢«å¤‡ä»½æ¯ç‰ˆã€Œç”Ÿæˆåˆå¤æ´»ã€
补好 7 æœˆæ¯ç‰ˆåŽå¯¼å‡ºï¼Œ`货运` é¡µ 2022/2021 ç´¯è®¡**又变回旧写死常量** â€”— å› ä¸º `restoreSummaryMonthlyBlocks` æŠŠå¤‡ä»½æ¯ç‰ˆï¼ˆæ¸…理前、仍是旧常量)整格回填覆盖了母版的新公式。
## å››ã€ä¿®å¤å†…容
| # | ä½ç½® | æ”¹åЍ |
|---|---|---|
| 1 | `ReportExportService.exportSummaryWorkbook` | è½ç›˜å‰æ–°å¢ž `normalizeStaleInlineStrings(wb)`:把所有「非 inlineStr å´æ®‹ç•™ `<is>`」的格子清掉(幂等),并打 warn æ—¥å¿— |
| 2 | `ReportExportService.restoreSummaryMonthlyBlocks` | æ–°å¢ž `skipFreightHistoryBlocks`:《 è´§è¿ã€‹é¡µ **T åˆ—及以后**(2025/2024/2023/2022/2021 å¹´åº¦å— + å„年累计/累计同比列)永不从备份母版回填,避免“生成又复活”(与既有「中口径排名」左块保护同一思路) |
| 3 | `docs/生成汇总大表/2026å¹´7月道路运输量汇总表.xlsx` | Excel COM è¡¥é½ï¼š2025/2024/2023/2022/2021 äº”个年度块共 **360** ä¸ªå—内格(`r7/r9/r8/r10 = SUM(17 å¸‚å·ž)`、`r5=r7+r9`、`r6=r8+r10`)+ **324** ä¸ªç´¯è®¡æ ¼ï¼ˆ`DX=SUM(DK:DV)`、`EM=SUM(EA:EL)`、`DY=IFERROR(DX/SUM(EA:EL)-1,"")`),`CalculateFullRebuild` åŽä¿å­˜ |
> å¤‡ä»½ï¼š`docs/生成汇总大表/_bak_2026å¹´7月道路运输量汇总表_补齐前_20260916.xlsx`(**故意不用 `_备份_` å‰ç¼€**,否则会被 `resolveSummaryDonor` å½“成 donor å›žå¡«ï¼‰ã€‚
## äº”、用例表
| # | ç”¨ä¾‹ | è¾“å…¥ | é¢„期 | å®žé™… | ç»“论 |
|---|---|---|---|---|---|
| 1 | åä»¶å¤çް | 2026-07 å¯¼å‡ºï¼ˆä¿®å¤å‰ï¼‰ | å¯æ‰“å¼€ | Excel æŠ¥ã€Œä¸èƒ½å–å¾—ç±» Workbooks çš„ Open å±žæ€§ã€ï¼Œé‡è¯• 2 æ¬¡ä»å¤±è´¥ | å¤çް |
| 2 | çŽ¯å¢ƒæŽ’é™¤ | 10KB å°ä»¶ / 8 æœˆæ¯ç‰ˆ / 7 æœˆæ¯ç‰ˆ / 09-08 æ—§ 7 æœˆå¯¼å‡º | â€” | å…¨éƒ¨å¯æ‰“开;仅新 7 æœˆå¯¼å‡ºå¤±è´¥ | ç¡®è®¤éžçŽ¯å¢ƒé—®é¢˜ |
| 3 | è·¯å¾„排除 | åä»¶å¤åˆ¶åˆ°å¦ä¸€ç›®å½•改名 | ä»å¤±è´¥ | ä»å¤±è´¥ | ç¡®è®¤æ˜¯æ–‡ä»¶å†…容问题 |
| 4 | éƒ¨ä»¶çº§æ‚交 | åä»¶ + å¥½ä»¶çš„ styles/sharedStrings/worksheets | å®šä½åéƒ¨ä»¶ | åä»¶ styles + åä»¶ sst + **好件全部 sheets** â†’ å¯æ‰“å¼€ | å®šä½åˆ° worksheets |
| 5 | leave-one-out | 19 ä¸ª sheet é€ä¸ªæ¢æˆåä»¶ç‰ˆ | æ‰¾å‡ºå sheet | ä»… **sheet9《公交》/ sheet12《轨道、轮渡》** å¤±è´¥ | å®šä½åˆ° 2 é¡µ |
| 6 | è´Ÿå‘:非法格计数 | ä¿®å¤å‰å¯¼å‡ºä»¶ | â€” | 19 ä¸ª `t="n"` å¸¦ `<is>` | å‘½ä¸­æ ¹å›  |
| 7 | æ­£å‘:修复后 2026-07 | é‡å¯åŽç«¯åŽå¯¼å‡º | å¯æ‰“开、19 é¡µã€ç´¯è®¡å¯¹ | OK sheets=19;`DX5=144979.2825`(`=SUM(DK5:DV5)`)、`DY5=-0.101235487797891`、`EM5=161309.53162`、`CU5=173045.296428512` | é€šè¿‡ |
| 8 | æ­£å‘:修复后 2026-08 | åŒä¸Š | å¯æ‰“开、累计不变 | OK sheets=19;`DZ5=144979.2825`、`EO5=161309.53162`、`CW5=173045.296428512`、`S5=130311.892698249` | é€šè¿‡ |
| 9 | è·¨æœˆä¸€è‡´æ€§ | 7 æœˆ vs 8 æœˆåŒå£å¾„格子 | å®Œå…¨ç›¸ç­‰ | 2022 ç´¯è®¡ / 2021 ç´¯è®¡ / 2023 ç´¯è®¡ ä¸‰ä¸ªæœˆåº¦ â†’ ä¸‰ä¸ªå€¼**完全相等** | é€šè¿‡ |
| 10 | éžæ³•格复扫 | ä¿®å¤åŽ 7 æœˆå¯¼å‡º | 0 ä¸ª | 0 ä¸ª | é€šè¿‡ |
| 11 | æ¯ç‰ˆå¯æ‰“å¼€ | è¡¥é½åŽç”¨ Excel æ‰“å¼€ 7 æœˆæ¯ç‰ˆ | å¯æ‰“å¼€ | å¯æ‰“å¼€ | é€šè¿‡ |
| 12 | æ®‹ç•™æ•°æ®å¤æ ¸ | `2026-09` äº”张表计数 | å…¨ 0 | å…¨ 0(h204 / investment_monthly / h2032 / audit_result / import_batch) | é€šè¿‡ |
## å…­ã€å‘现的问题与处置
1. **7 æœˆå¯¼å‡ºä»¶æ‰“不开**(P0):`normalizeStaleInlineStrings` æ ¹æ²»ï¼›å¯¼å‡ºä»¶ä»Ž 941,960 å­—节(坏)→ 1,310,693 å­—节(好)。
2. **备份母版回填让补齐失效**(P0):`skipFreightHistoryBlocks` ä¿æŠ¤ `货运` T åˆ—及以后。
3. **Excel COM ä¼šç•™å­¤å„¿è¿›ç¨‹**:每例测完必须强杀本次新建的 `EXCEL` è¿›ç¨‹ï¼Œå¦åˆ™åŽç»­ `Workbooks.Open` ä¼š**间歇性假报**同样的错(本次排查初期被此干扰过)。属排查工具坑,已记入问题汇总。
4. **注意**:本次**未**改动 8 æœˆæ¯ç‰ˆä¸Žä»»ä½•入库数据。
## ä¸ƒã€ç»“论
- 2026-07 / 2026-08 ä¸¤ä¸ªå¯¼å‡ºä»¶å‡å¯è¢« Excel æ­£å¸¸æ‰“开(各 19 é¡µï¼‰ï¼Œä¸”《 è´§è¿ã€‹é¡µ 2021/2022/2023 ç´¯è®¡åˆ—口径**完全一致**。
- 7 æœˆæ¯ç‰ˆå·²æŒ‰ 8 æœˆæ¯ç‰ˆå£å¾„补齐(年度块 360 æ ¼ + ç´¯è®¡ 324 æ ¼ï¼‰ï¼Œå¹¶ä»Ž openpyxl è¡€ç¼˜è½¬ä¸º Excel åŽŸç”Ÿã€‚
- ç”¨æˆ·è¦æ±‚的「残留数据全部清除」经复核为 0 æ®‹ç•™ã€‚
## å…«ã€é—ç•™
- 2026-06 / 2026-09 æ— æ¯ç‰ˆ â†’ é¢„览返回 `ready=False`「未找到模板文件」,需新建母版才能出数(用户第 5 é—®çš„延伸)。
- ä»“库根目录 `_*.*` ä¸´æ—¶æŽ’查文件(含本次 `_hyb_*` / `_loo_*` / `_v2_*` / `_final_*`)未删,待用户同意。
docs/¹¤×÷ÈÕ½á/¹¤×÷ÈÕ½á_2026-09-16.md
@@ -309,3 +309,66 @@
- 2026-07 æœŸå¯¼å‡ºä»¶ã€Œ è´§è¿ã€é¡µä¸º 118x145(比 8 æœˆå°‘ 2 åˆ—),因 7 æœˆæ¯ç‰ˆæ˜¯ã€Œ1-4 æœˆéª¨æž¶ã€ã€‚
详见《功能测试报告/功能测试报告_货运页签累计列修复与脏期清理_2026-09-16.md》。
---
## äºŒåä¸€ã€2026-07 æ¯ç‰ˆè¡¥é½ + å¯¼å‡ºä»¶ã€ŒExcel æ‰“不开」根因修复
日期:2026-09-16(第 9 è½®ï¼ŒæŽ¥äºŒåèŠ‚ï¼‰
### 21.1 ä»Šå¤©åšäº†ä»€ä¹ˆ
| # | äº‹é¡¹ | ç»“æžœ |
|---|---|---|
| 1 | æ¸…理 2026-09 æ®‹ç•™æ•°æ®ï¼ˆç”¨æˆ·ç¬¬ 1 æ¡ï¼‰ | **完成**:h204_vehicle_quarterly 1284 / investment_monthly 31 / audit_result 2061 / audit_run 3 / import_batch 5 / h2032 636,全部复核为 0 æ®‹ç•™ï¼›å·²ç•™å¯è¿˜åŽŸ SQL å¤‡ä»½ `_backup_2026-09_residual_all_20260916.sql` |
| 2 | ä¿® 2026-07 å¯¼å‡ºä»¶ã€ŒExcel æ‰“不开」 | **完成**(P0,见 21.2) |
| 3 | è¡¥é½ 2026-07 æ¯ç‰ˆï¼ˆç”¨æˆ·ç¬¬ 3 æ¡ã€Œå¯ä»¥è¡¥é½ã€ï¼‰ | **完成**(见 21.3) |
| 4 | ä¿®å¤‡ä»½æ¯ç‰ˆå›žå¡«æŠŠè¡¥é½ã€Œæ‰“回原形」 | **完成**(见 21.4) |
### 21.2 æ ¹å› ï¼šopenpyxl æ¯ç‰ˆ + å¤‡ä»½å›žå¡« â†’ æ®‹ç•™ <is> éžæ³•æ ¼
- åä»¶é‡Œ 19 ä¸ªæ ¼å­å½¢å¦‚ `<c r="E15" s="111" t="n"><v>67.0</v><is><t>67.00</t></is></c>`:`t="n"` å´å¸¦ `<is>`,模式非法,Excel ç›´æŽ¥æ‹’开(COM æŠ¥ã€Œä¸èƒ½å–å¾—ç±» Workbooks çš„ Open å±žæ€§ã€ï¼Œè¿žä¿®å¤æ¨¡å¼ `CorruptLoad=1` ä¹Ÿæ‰“不开)。
- 7 æœˆæ¯ç‰ˆæ˜¯ **openpyxl å†™å‡º**(文本存 `<is>`),8 æœˆæ¯ç‰ˆæ˜¯ **Excel åŽŸç”Ÿ**(文本走 sharedStrings)→ åŒä»£ç ä¸‹åªæœ‰ 7 æœˆåã€‚
- è§¦å‘者是 `restoreSummaryMonthlyBlocks`:7 æœˆæœ‰ `_备份_2026å¹´7月…清理前…xlsx`,整格回填时往 inlineStr æ ¼é‡Œå†™å€¼ï¼Œç•™ä¸‹æ—§ `<is>`;8 æœˆæ²¡æœ‰ `_备份_*`,不走回填,所以一直是好的。
- å®šä½æ‰‹æ³•(值得记住):坏件/好件**除 worksheets/styles/sharedStrings å¤–全部部件逐字节相同** â†’ zip æ‚交 + Excel é€ä¸€å¼€æ¡£ leave-one-out â†’ é”å®š **sheet9《公交》17 æ ¼ + sheet12《轨道、轮渡》2 æ ¼**。
### 21.3 ä¿®å¤
1. `ReportExportService.exportSummaryWorkbook`:落盘前新增 `normalizeStaleInlineStrings(wb)`,清掉所有「非 inlineStr å´æ®‹ç•™ `<is>`」的格子(幂等 + warn æ—¥å¿—)。
2. `ReportExportService.restoreSummaryMonthlyBlocks`:新增 `skipFreightHistoryBlocks`,《 è´§è¿ã€‹é¡µ **T åˆ—及以后**(2025..2021 äº”个年度块 + å„年累计列)永不从备份母版回填 â€”— ä¸Žæ—¢æœ‰ã€Œä¸­å£å¾„排名左块」保护同一思路,防「生成又复活」。
### 21.4 7 æœˆæ¯ç‰ˆè¡¥é½ï¼ˆExcel COM,360 + 324 æ ¼ï¼‰
按 `_fix_mother.ps1`(8 æœˆæ¯ç‰ˆé‚£ç‰ˆï¼‰**整体左移 2 åˆ—**改写:
- å¹´åº¦å—:2025 `T,V,X,Z,AB,AD,AF,AH,AJ,AL,AN,AP`;2024 `AV..BR` éš”列;2023 `BW..CS` éš”列;2022 `DK..DV` è¿žç»­ï¼›2021 `EA..EL` è¿žç»­ï¼›æ¯åˆ—写 `r7/r9/r8/r10 = SUM(17 å¸‚å·ž)`、`r5=r7+r9`、`r6=r8+r10` â†’ **360 æ ¼**;
- ç´¯è®¡åˆ—:`DX=SUM(DK:DV)`、`EM=SUM(EA:EL)`、`DY=IFERROR(DX/SUM(EA:EL)-1,"")`,行 5..112 â†’ **324 æ ¼**;
- `CalculateFullRebuild` åŽä¿å­˜ã€‚母版 921,559 â†’ 1,440,038 å­—节(转 Excel åŽŸç”Ÿï¼‰ã€‚
### 21.5 æµ‹è¯•结果摘要
| ç”¨ä¾‹ | ç»“æžœ |
|---|---|
| 2026-07 å¯¼å‡ºï¼ˆä¿®å¤å‰ï¼‰ | FAIL(复现) |
| çŽ¯å¢ƒ/路径排除(小件、两本母版、09-08 æ—§å¯¼å‡ºã€æ”¹åå¤åˆ¶ï¼‰ | å…¨éƒ¨ OK,确认非环境问题 |
| ä¿®å¤åŽ 2026-07 å¯¼å‡º | **OK sheets=19**,`DX5=144979.2825`、`DY5=-0.101235487797891`、`EM5=161309.53162`、`CU5=173045.296428512` |
| ä¿®å¤åŽ 2026-08 å¯¼å‡º | **OK sheets=19**,`DZ5=144979.2825`、`EO5=161309.53162`、`CW5=173045.296428512` |
| è·¨æœˆä¸€è‡´æ€§ | 7 æœˆä¸Ž 8 æœˆçš„ 2022/2021/2023 ç´¯è®¡**完全相等** |
| éžæ³•格复扫 | 0 ä¸ª |
| 2026-09 æ®‹ç•™å¤æ ¸ | 5 å¼ è¡¨å…¨ 0 |
> æ³¨ï¼š8 æœˆæ¯ç‰ˆè®¡ç®—后 `DZ5` ç”±æ—§çš„写死常量 `144979.285376043` å˜ä¸º `144979.2825`,差 0.0029 â€”— æ­£æ˜¯ç¬¬åäºŒèŠ‚è®°å½•çš„ã€Œå…¨çœè§„ä¸‹å¸¸é‡ â‰  17 å¸‚州之和」那笔差额,属**修正**而非回退。
### 21.6 è¸©å‘
1. **Excel COM å­¤å„¿è¿›ç¨‹ä¼šè®© `Workbooks.Open` é—´æ­‡æ€§å‡æŠ¥åŒä¸€ä¸ªé”™**:每例测完必须强杀本次新建的 `EXCEL` è¿›ç¨‹ã€‚排查初期就因孤儿进程误判「8 æœˆä»¶ä¹Ÿæ‰“不开」,浪费了一轮。
2. `CTWorksheet` **没有** `isSetSheetData()`(sheetData æ˜¯å¿…填),要用 `getSheetData() != null`。
3. æ¯ç‰ˆè¡¥é½çš„备份文件**不能**用 `_备份_` å‰ç¼€ï¼ˆä¼šè¢« `resolveSummaryDonor` å½“ donor å›žå¡«ï¼‰ï¼Œæœ¬æ¬¡ç”¨ `_bak_2026å¹´7月道路运输量汇总表_补齐前_20260916.xlsx`。
### 21.7 é—ç•™
- 2026-06 / 2026-09 æ— æ¯ç‰ˆ â†’ é¢„览 `ready=False`「未找到模板文件」,需先建母版。
- ç¬¬ 8 æ£’遗留未动:`h2031` ç¼º 2025-01、`passenger_individual_monthly` 2026-08 ç¼ºé»„冈、`PASSENGER_AUTH` 11 æœŸå…¨ 0。
- ä»“库根 `_*.*`(含本次 `_hyb_*` / `_loo_*` / `_v2_*` / `_final_*` / `_fixed_*` / `_t7_*` / `_poijar`)未删,待用户同意。
详见《功能测试报告/功能测试报告_2026-07母版补齐与导出件打不开修复_2026-09-16.md》。
docs/Éú³É»ã×Ü´ó±í/2026Äê7ÔµÀ·ÔËÊäÁ¿»ã×ܱí.xlsx
Binary files differ
docs/ÎÊÌâ»ã×Ü/ÎÊÌâÓë×¢ÒâÊÂÏî»ã×Ü_2026-09-16.md
@@ -243,3 +243,47 @@
| 12 | æ¯ç‰ˆç» Excel é‡å­˜åŽä½“积 959,706 -> 1,492,121 å­—节(导出件 950,186 -> 1,331,599) | çº¯æ ¼å¼å¼€é”€ï¼Œæ•°æ®æ— å½±å“ | è®°å½• |
详见《功能测试报告/功能测试报告_货运页签累计列修复与脏期清理_2026-09-16.md》。
---
## åä¸‰ã€2026-09-16 è¡¥å……:2026-07 æ¯ç‰ˆè¡¥é½ & å¯¼å‡ºä»¶ã€ŒExcel æ‰“不开」根因(P0)
### 13.1 ç—‡çŠ¶ä¸Žæ ¹å› 
| é¡¹ | å†…容 |
|---|---|
| ç—‡çж | `GET /api/report/export/summaryWorkbook?period=2026-07&mode=month` ç”Ÿæˆçš„ xlsx,**Excel æ‰“不开**(COM æŠ¥ã€Œä¸èƒ½å–å¾—ç±» Workbooks çš„ Open å±žæ€§ã€ï¼›`CorruptLoad=1` ä¿®å¤æ¨¡å¼åŒæ ·æ‰“不开);2026-08 åŒæŽ¥å£æ­£å¸¸ |
| ç›´æŽ¥åŽŸå›  | å¯¼å‡ºä»¶é‡Œæœ‰ **19 ä¸ªæ¨¡å¼éžæ³•æ ¼**:`<c r="E15" s="111" t="n"><v>67.0</v><is><t>67.00</t></is></c>` â€”— `t="n"` ä¸å…è®¸å¸¦ `<is>`(inlineStr ä¸“用) |
| æ·±å±‚原因 | 7 æœˆæ¯ç‰ˆç”± **openpyxl** å†™å‡ºï¼ˆ`docProps/app.xml` = `Microsoft Excel Compatible / Openpyxl 3.1.5`,文本存 `<is>`);8 æœˆæ¯ç‰ˆæ˜¯ **Excel åŽŸç”Ÿ**(文本走 sharedStrings)。POI çš„部分写入路径只改 `t`/`<v>`、不清旧 `<is>` |
| è§¦å‘路径 | 7 æœˆå­˜åœ¨ `_备份_2026å¹´7月道路运输量汇总表_清理前_20260904.xlsx` â†’ `restoreSummaryMonthlyBlocks` æ•´æ ¼å›žå¡« â†’ å¾€ inlineStr æ ¼é‡Œå†™å€¼ç•™ä¸‹æ—§ `<is>`。8 æœˆæ—  `_备份_*`,不走回填,故正常 |
| å‘½ä¸­ä½ç½® | leave-one-out å®šä½åˆ° **sheet9《公交》17 æ ¼ + sheet12《轨道、轮渡》2 æ ¼** |
### 13.2 ä¿®å¤ï¼ˆ`traffic-audit-server`)
1. **`exportSummaryWorkbook` æ–°å¢ž `normalizeStaleInlineStrings(wb)`**:落盘前清掉所有「非 `inlineStr` å´æ®‹ç•™ `<is>`」的格子(幂等),命中即打 warn æ—¥å¿—。
2. **`restoreSummaryMonthlyBlocks` æ–°å¢ž `skipFreightHistoryBlocks`**:《 è´§è¿ã€‹é¡µ **T åˆ—及以后**(2025/2024/2023/2022/2021 å¹´åº¦å— + å„年累计/累计同比列)**永不从备份母版回填** â€”— ä¸Žæ—¢æœ‰ã€Œä¸­å£å¾„排名左块永不回填」同一思路,避免补齐被「生成又复活」。
### 13.3 2026-07 æ¯ç‰ˆè¡¥é½ï¼ˆå£å¾„与 8 æœˆæ¯ç‰ˆå¯¹é½ï¼‰
- å¹´åº¦å—(每列):`r7/r9/r8/r10 = SUM(17 å¸‚州对应行)`、`r5 = r7+r9`、`r6 = r8+r10` â†’ 360 æ ¼ï¼›
- ç´¯è®¡åˆ—:`DX = SUM(DK:DV)`(2022)、`EM = SUM(EA:EL)`(2021,原**整列为空**)、`DY = IFERROR(DX/SUM(EA:EL)-1,"")`(2022 ç´¯è®¡åŒæ¯”,原为**写死常量**)→ 324 æ ¼ï¼›
- 2023 ç´¯è®¡ `CU = BW+BY+…+CS` æœ¬æ¥å°±æ­£ç¡®ï¼Œæœªæ”¹ï¼›`EN`(2021 ç´¯è®¡åŒæ¯”)按口径保持为空。
- ä¸€æ‰‹è¯æ®ï¼šæ¯ç‰ˆ `DX5=144979.2825`(旧常量 `144979.285376043`,差 0.0029 = å…¨çœè§„下常量与 17 å¸‚州之和的差)、`EM5=161309.53162`、`CU5=173045.296428512`,与 8 æœˆæ¯ç‰ˆ `DZ5/EO5/CW5` **完全相等**。
- å¤‡ä»½ï¼š`docs/生成汇总大表/_bak_2026å¹´7月道路运输量汇总表_补齐前_20260916.xlsx`。**切勿改名为 `_备份_` å¼€å¤´**,否则会被 `resolveSummaryDonor` å½“ donor å›žå¡«ã€‚
### 13.4 æœ¬æ¬¡æ–°å¢žçš„æŽ’查坑
| é—®é¢˜ | åŽŸå›  | å¤„ç½® |
|---|---|---|
| Excel COM **间歇性**报同一个错,导致误判「8 æœˆä»¶ä¹Ÿæ‰“不开」 | æ¯æ¬¡ `New-Object -ComObject Excel.Application` ç•™ä¸‹çš„**孤儿 EXCEL è¿›ç¨‹**会污染后续实例 | æ¯ä¾‹æµ‹å®ŒæŠŠã€Œæœ¬æ¬¡æ–°å»ºçš„ EXCEL è¿›ç¨‹ã€å¼ºæ€å†æµ‹ä¸‹ä¸€ä¾‹ï¼›`Quit()`+`ReleaseComObject` å¹¶ä¸å¤Ÿ |
| ç¼–译报「找不到 isSetSheetData()」 | `CTWorksheet.sheetData` æ˜¯ XSD **必填**元素,不生成 `isSetXxx` | æ”¹ç”¨ `ctw.getSheetData() != null` |
| éƒ¨ä»¶çº§ diff å¤ªå¤§è·‘不动 | å¯¹ 519KB çš„ `styles.xml` ç›´æŽ¥ `difflib` æ˜¯ O(n²) | å…ˆæŒ‰éƒ¨ä»¶æ¯”字节尺寸/是否相等,只在必要的小部件上做 diff |
### 13.5 é—留问题增量
| # | é—®é¢˜ | å½±å“ | çŠ¶æ€ |
|---|---|---|---|
| 13 | 2026-06 / 2026-09 æ— æ¯ç‰ˆ | é¢„览 `ready=False`「未找到模板文件」,无法出数 | éœ€å…ˆå»ºæ¯ç‰ˆï¼ˆç”¨æˆ·ç¬¬ 5 é—®çš„延伸) |
| 14 | ä»“库根 `_*.*` ä¸´æ—¶æ–‡ä»¶ç»§ç»­å¢žå¤šï¼ˆ`_hyb_*` / `_loo_*` / `_v2_*` / `_final_*` / `_fixed_*` / `_t7_*` / `_poijar`) | ä½“积/可读性 | ç»ç”¨æˆ·åŒæ„åŽå†æ¸…理 |
> ç¬¬ 10 é¡¹ï¼ˆ2026-07 å¯¼å‡ºä»¶å°‘ 2 åˆ— / 7 æœˆæ¯ç‰ˆæ˜¯ã€Œ1-4 æœˆéª¨æž¶ã€ï¼‰æœ¬èŠ‚å·²å¤„ç†ï¼šå¯¼å‡ºç«¯ä¼š**自动补出 5/6/7 æœˆè¡¨å¤´ä¸Žå…¬å¼**并重算累计公式,母版已补齐 2021/2022/2023 ç´¯è®¡åˆ—,故关闭该项。
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java
@@ -3360,12 +3360,41 @@
                    + "按《生成_道路运输量汇总表》对齐列宽列数={},缺数提示={}",
                    dbFilled, yoyFilled, monthFormulaFilled, rankRefreshed, cumulativeRefreshed, widthApplied, dbProblems);
            applyTwoDecimalFormat(wb); // æ•°å€¼æ˜¾ç¤ºä¸¤ä½å°æ•°ï¼ˆä¿ç•™å…¨ç²¾åº¦ï¼‰ï¼›% / æ—¥æœŸç­‰æ—¢æœ‰æ ·å¼ä¸æ”¹å˜
            int inlineFixed = normalizeStaleInlineStrings(wb); // æ¸…掉「非 inlineStr å´æ®‹ç•™ <is>」的非法格,否则 Excel æ‹’绝打开
            if (inlineFixed > 0) log.warn("汇总工作簿清掉残留 inlineStr éžæ³•æ ¼ {} ä¸ªï¼ˆæ¯ç‰ˆç”± openpyxl å†™å‡ºæ—¶çš„典型问题)", inlineFixed);
            if (!wb.getCTWorkbook().isSetCalcPr()) wb.getCTWorkbook().addNewCalcPr();
            wb.getCTWorkbook().getCalcPr().setFullCalcOnLoad(true); // è¿˜åŽŸ/改写公式后打开即重算
            return toBytes(wb);
        } finally {
            ZipSecureFile.setMinInflateRatio(savedZipRatio);
        }
    }
    /**
     * æ¸…掉「非 inlineStr å´æ®‹ç•™ &lt;is&gt;」的非法单元格。
     *
     * æ¯ç‰ˆè‹¥ç”± openpyxl å†™å‡ºï¼Œæ–‡æœ¬å•元格用 &lt;is&gt;(inlineStr)存储;POI çš„ setCellValue åªæ”¹å†™ t ä¸Ž &lt;v&gt;,
     * ä¸ä¼šæ¸…掉旧 &lt;is&gt;,于是产出 &lt;c t="n"&gt;&lt;v&gt;67.0&lt;/v&gt;&lt;is&gt;&lt;t&gt;67.00&lt;/t&gt;&lt;/is&gt;&lt;/c&gt; è¿™ç§éžæ³•格,
     * Excel åˆ¤å®šä¸ºã€Œæ— æ³•读取的内容」而直接拒绝打开(COM è¡¨çŽ°ä¸ºã€Œä¸èƒ½å–å¾—ç±» Workbooks çš„ Open å±žæ€§ã€ï¼‰ã€‚
     * 2026-07 å¯¼å‡ºä»¶å³å› æ­¤æ‰“不开(《公交》17 æ ¼ +《轨道、轮渡》2 æ ¼ï¼‰ã€‚落盘前统一清理,幂等。
     */
    private int normalizeStaleInlineStrings(XSSFWorkbook wb) {
        int fixed = 0;
        for (int i = 0; i < wb.getNumberOfSheets(); i++) {
            org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet ctw = wb.getSheetAt(i).getCTWorksheet();
            if (ctw == null || ctw.getSheetData() == null) continue;
            for (org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow row : ctw.getSheetData().getRowArray()) {
                for (org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell c : row.getCArray()) {
                    if (!c.isSetIs()) continue;
                    STCellType.Enum t = c.getT();
                    if (t == null || !STCellType.INLINE_STR.equals(t)) {
                        c.unsetIs();
                        fixed++;
                    }
                }
            }
        }
        return fixed;
    }
    /**
@@ -4454,6 +4483,9 @@
            if (bs == null) continue;
            // ä¸­å£å¾„排名页 A..H é™ˆæ—§å·¦å—已于 2026-09-09 æ‹æ¿æ•´å—删除:该区域永不从备份母版回填,避免“生成又复活”
            boolean skipMidRankLeftBlock = "中口径排名".equals(ds.getSheetName());
            // ã€Š è´§è¿ã€‹é¡µ 2025..2021 å¹´åº¦å—(T åˆ—起,含各年累计/累计同比列)在母版里是「市州派生公式」,
            // å¤‡ä»½æ¯ç‰ˆåŒåŒºä»æ˜¯æ—§çš„写死常量(全省规下等),回填会让 2021/2022/2023 ç´¯è®¡åˆå¯¹ä¸ä¸Šï¼ˆâ€œç”Ÿæˆåˆå¤æ´»â€ï¼‰ï¼Œæ•…该区不回填。
            boolean skipFreightHistoryBlocks = " è´§è¿".equals(ds.getSheetName());
            for (int r = ds.getFirstRowNum(); r <= ds.getLastRowNum(); r++) {
                Row dr = ds.getRow(r);
                if (dr == null) continue;
@@ -4461,6 +4493,7 @@
                for (Cell dc : dr) {
                    if (dc == null) continue;
                    if (skipMidRankLeftBlock && dc.getColumnIndex() < 8) continue;
                    if (skipFreightHistoryBlocks && dc.getColumnIndex() >= 19) continue; // T åˆ—及以后 = 2025..2021 å¹´åº¦å—
                    CellType t = dc.getCellType();
                    if (t == CellType.BLANK) continue;
                    String dtx = summaryCellText(dc);