feat: 报表新版式(上累计+下当月)与导入校验增强、I004 保护 + 09-02 测试文档

- 报表生成(ReportExportService):公路旅客中口径分析/排名、城市客运汇总/分市州累计按新版式补“当月”块并修正占比/排名公式范围;货运量/周转量排名第二页改填当月值、列头导出为“当月完成”;城市客运导出底稿由已删《导入模板_*》改回《生成_*》
- 导入:城市公交/巡游出租/投资系统导出表头列位校验、运政车辆/轨迹里程表头名称映射、投资市州月报多 sheet 识别与空序号行解析、I004 投资系统基准整期缺失保护
- 文档:docs 生成模板新版式落盘、09-02 功能测试报告/工作日结/待业务确认清单/导入功能体检报告
7个文件已删除
24个文件已修改
12个文件已添加
1292 ■■■■■ 已修改文件
AGENTS.md 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/交接文档-20260831.md 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/公路旅客/个体客运量汇总.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/公路旅客/模板_交企统H203-1表_公路旅客运输月度生产情况.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/公路旅客/生成_中口径分析.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/公路旅客/生成_中口径排名.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/功能测试报告/功能测试报告_2026-09-02_导入与报表生成回归.md 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/功能测试报告/功能测试报告_导入校验增强_2026-09-02.md 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/功能测试报告/功能测试报告_投资审核I004基准缺失保护_2026-09-02.md 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/功能测试报告/功能测试报告_投资市州月报多sheet识别与序号空格_2026-09-02.md 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/功能测试报告/功能测试报告_生成模板新版式_2026-09-02.md 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/功能测试报告/功能测试报告_运政车辆与轨迹里程导入回归_2026-09-02.md 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/功能测试报告/导入与生成模块体检问题清单_2026-09-02.md 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/城市客运/城市客运数据优化.docx 补丁 | 查看 | 原始文档 | blame | 历史
docs/城市客运/客运简化.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/城市客运/导入模板_城市公交.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/城市客运/导入模板_城市分市州.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/城市客运/导入模板_城市客运各市州明细表.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/城市客运/导入模板_城市汇总.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/城市客运/导入模板_巡游出租.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/城市客运/导入模板_轨道、轮渡.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/城市客运/生成_城市客运各市州明细表.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/城市客运/生成_城市客运客运量分市州累计.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/城市客运/生成_城市客运汇总.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/城市客运/生成_轨道轮渡客运量分市州明细.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/导入功能体检报告.md 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/工作日结/工作日结_2026-09-02.md 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/工作日结/模块功能验证状态矩阵_2026-09-02.md 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/待业务用户确认清单_2026-09-02.md 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/能耗/生成_能运汇总表.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/能耗/能耗简化(2026年).xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/货运/模板_规上规下拆分运输量.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/货运/模板_货运量周转量.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/货运/模板_轨迹里程.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/货运/生成_周转量排名.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/货运/生成_货运量排名.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/货运/货运简化工作.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-server/src/main/java/com/trafficaudit/auditengine/service/AuditEngineService.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-server/src/main/java/com/trafficaudit/common/util/RegionUtil.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-server/src/main/java/com/trafficaudit/dataimport/service/DataImportService.java 290 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/controller/ReportExportController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java 300 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-web/src/views/DataImport.vue 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
AGENTS.md
@@ -32,4 +32,14 @@
## éªŒè¯æ³¨æ„
- æ²™ç®±å†… `Get-NetTCPConnection` ä¼šå› æƒé™â€œæ‹’绝访问”而静默失败,**不要**据此判定端口未监听;判断服务状态以 backend.log / frontend.log ä¸ºå‡†ã€‚
- ç”¨æˆ·è¦æ±‚:临时脚本/文件未经同意不删;导入失败要在页面显示行号;AI åˆ†æžç»“果要给结构化排版 + é€å­—输出动画。
- ç”¨æˆ·è¦æ±‚:临时脚本/文件未经同意不删;导入失败要在页面显示行号;AI åˆ†æžç»“果要给结构化排版 + é€å­—输出动画。
## å·¥ä½œè§„范(2026-09-02 èµ·ï¼Œå¿…须遵守)
1. **每做完一个功能,立即测试并写《功能测试报告》**
   - æµ‹è¯•至少覆盖:正向用例(正常数据)、负向用例(错类型/错列位/缺列等)、入库抽查(与源文件逐项对齐)。
   - æŠ¥å‘Šå†™å…¥ `docs/功能测试报告/`,命名:`功能测试报告_<功能名>_<YYYY-MM-DD>.md`。
   - æŠ¥å‘Šé¡»åŒ…含:功能说明、测试环境、用例表(输入/预期/实际/结论)、发现的问题与处置、结论。
2. **每天下班前写《工作日结》,命名附日期**
   - å†™å…¥ `docs/工作日结/`,命名:`工作日结_<YYYY-MM-DD>.md`。
   - å†…容至少包含:今天做了什么(功能/修复)、测试结果摘要、遗留问题与待办、明天计划。
   - å½“天没有代码/测试工作时,也要写(一句话说明“今日无代码改动”即可)。
docs/½»½ÓÎĵµ-20260831.md
New file
@@ -0,0 +1,61 @@
# äº¤æŽ¥æ–‡æ¡£ï¼ˆ2026-08-31,本地开发会话)
> ç”¨é€”:新会话无缝接力。开新会话后让 Codex å…ˆè¯»æœ¬æ–‡ä»¶ + é¡¹ç›®æ ¹ `AGENTS.md`。
> æ³¨æ„ï¼šæœ¬æ–‡ä»¶ä¸ºæœ¬åœ°ä¼šè¯ç‹¬ç«‹äº¤æŽ¥ï¼Œ**不要覆盖/修改同事推送的 `HANDOFF.md`**。
## ä¸€ã€é¡¹ç›®æ¦‚况
- äº¤é€šè´§è¿ç»Ÿè®¡å®¡æ ¸ç³»ç»Ÿï¼ˆæ¹–北货运量/周转量等)。
- åŽç«¯ Spring Boot(`traffic-audit-server`,端口 8090);前端 Vue2 + Element UI(`traffic-audit-web`,端口 8080,`/api` ä»£ç† 8090)。
- ä¸€é”®å¯åŠ¨ï¼š`powershell -NoProfile -ExecutionPolicy Bypass -File start-dev.ps1`(必须沙箱外运行;会自动检测 8090/8080,已在跑则跳过)。
- æ—¥å¿—:根目录 `backend.log`、`traffic-audit-web/frontend.log`。成功标志:后端 `Started TrafficAuditApplication`+`Tomcat started on port(s): 8090`;前端 `Compiled successfully`+`App running at:`。
## äºŒã€å½“前代码状态
- æœ¬åœ° `main` ä¸ŽæœåŠ¡å™¨ä¸€è‡´ï¼š`079d872`(8/31 åŒäº‹ 5 ä¸ªæ–°æäº¤å·²åŒæ­¥ï¼šsessionStorage å¼ºåˆ¶ç™»å½• c62a61c、/import ä¸Ž /report el-tabs ä¿®å¤ 684da41/d42a044、崩溃根因文档 f0597c2、交接约定 079d872)。
- åŒäº‹ 8/28 æ”¹åŠ¨ï¼š
  - `2bd663b` fix:ExplainReview.vue é‡å¤ components é”®ï¼ˆAppHeader è¢« AiChatDialog è¦†ç›–)已合并;RuleManage/UserManage å¸ƒå±€ç»Ÿä¸€ä¸º app-header ä¸Šä¸‹å¸ƒå±€ï¼Œç§»é™¤èœå•内失效退出项。
  - `37496dc` docs:用户 4 é—®é¢˜ï¼ˆå®¡æ ¸ç»“果菜单不高亮/横栏缺失/退出不显示/强制登录)——②③已修;④ token æ”¹ sessionStorage = å¾…办;**/import æ•°æ®å¯¼å…¥é¡µ JS ä¸»çº¿ç¨‹å¡æ­»æ–°å‘现(未修)**。
- æœåŠ¡å½“å‰**在运行**(8/31 ä¼šè¯æ²¿ç”¨ï¼š8080/8090 å‡åœ¨ç›‘听,backend.log / frontend.log æ­£å¸¸ï¼‰ã€‚需要重启时用 start-dev.ps1(沙箱外)。
## ä¸‰ã€è¿è¡ŒçŽ¯å¢ƒï¼ˆé‡è¦ï¼‰
- æ•°æ®åº“:`localhost:3308`,库 `traffic_audit`,`root/123456`(见本地 `traffic-audit-server/src/main/resources/application.yml`,不入库)。
  - âš ï¸ åŒäº‹ HANDOFF é‡Œå†™çš„ `3305/root/root` å·²è¿‡æ—¶ï¼ˆ3305 æœªç›‘听),以 application.yml ä¸ºå‡†ã€‚
  - è¯¥åº“为 8/27 æ™šåŒäº‹ Navicat åˆå¹¶åŽçš„完整库(27 è¡¨ã€çº¦ 6 ä¸‡è¡Œï¼›sys_user 4 è´¦å· admin+zhangsan/lisi/wangwu;**本机库中 4 è´¦å·å¯†ç å‡ä¸º `123456`**(8/31 bcrypt+登录接口实测,admin/123456 è¿”回 200;文档旧记 admin/admin123 åœ¨æœ¬æœºä¸åŒ¹é…ï¼Œå‹¿å†ç”¨ï¼‰ã€‚
- ç™»å½•验证码:本地 `application.yml` å·²é… `app.captcha.required: false`(测试跳过,接口 /api/auth/captcha-config è¿”回 false)。该配置不入库;**正式发布前改回 true**。
- å®¢æˆ·ç«¯ï¼šæœ¬æœº MySQL å®¢æˆ·ç«¯ `D:\mysql\mysql-5.7.41-winx64\bin\mysql.exe`(连 3308 ç”¨ root/123456);HANDOFF æé†’正式用 8.0 å®¢æˆ·ç«¯ï¼ˆæœ¬æœº `C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql.exe`)。
## å››ã€æœ€è¿‘完成的事项- **认证信息 localStorage â†’ sessionStorage(8/31 å®Œæˆï¼‰**:
  - ç™»å½•态四键(token/username/realName/modules)全部改存 sessionStorage:Login.vue(写入)、router/index.js(守卫读)、api/index.js(请求头读 + 401 æ¸…除)、main.js(全局 mixin logout æ¸… 4 é”®ï¼‰ã€AppHeader.vue(用户名显示 + ç™»å‡ºæ¸… 4 é”®ï¼‰ã€ReportExport.vue(用户名/真实名/模块读取 + ç™»å‡ºæ¸… 4 é”®ï¼‰ã€‚
  - åå¥½ç±»ä¿æŒ localStorage:DataImport çš„ `dirLast_*`(目录记忆)、ReportExport çš„ `report_note_*`(报表备注草稿)。
  - è¡Œä¸ºï¼šåŒæ ‡ç­¾é¡µ F5 åˆ·æ–°ä¿æŒç™»å½•;关标签页/新开标签页需重新登录(强制登录生效);登出清空 4 é”®å›žç™»å½•页。
  - éªŒè¯ï¼ˆpuppeteer,admin/123456 UI ç™»å½•):无 token è®¿é—® /#/dashboard ä¸Ž /#/audit å‡é‡å®šå‘ /#/login;登录后 sessionStorage æœ‰ token、localStorage æ—  token;登出清空;/import è¯·æ±‚头携带 Bearer token、表格 28 è¡Œæ­£å¸¸ã€‚
- **/import ä¸»çº¿ç¨‹å¡æ­»æ ¹å› å®šä½å¹¶ä¿®å¤ï¼ˆ8/31)**:
  - å¤çŽ°ï¼ˆpuppeteer-core + ç³»ç»Ÿ Chrome,CDP):/import åœ¨çª—口宽度 â‰¤1366 æ—¶ JS ä¸»çº¿ç¨‹**永久**卡死(800x600 / 1280x800 / 1366x768 å‡å†»ç»“,1440+ æ­£å¸¸ï¼‰ï¼›åŒæŽ¢é’ˆä¸‹ /data /audit /report å…¨å®½åº¦æ­£å¸¸ã€‚
  - æ ¹å› ï¼šElement UI `el-tabs`(TabNav)`updated()` é’©å­é‡Œçš„ `update()` æŒ‰ DOM æµ‹é‡å†™å“åº”式 `scrollable`/`navOffset`。本页布局下 `.el-tabs__nav-scroll` å®½åº¦åœ¨éž scrollable æ€å®žæµ‹ 0、加滚动按钮后实测 998,导致 `scrollable` åœ¨ false↔{} é—´æŒ¯è¡ â†’ æ¸²æŸ“ watcher æ— é™è‡ªå…¥é˜Ÿï¼ˆ`flushSchedulerQueue` æ°¸ä¸æŽ’空)→ ä¸»çº¿ç¨‹æ­»å¾ªçŽ¯ã€‚CDP `Debugger.pause` æŠ“栈:`flushSchedulerQueue→Watcher.run→updateComponent→_render→render` ä¸Ž `updated→update→reactiveSetter(key=scrollable)`。
  - å½±å“ï¼šå³ã€Œæ•°æ®å¯¼å…¥é¡µæ— å“åº”」「点数据导入菜单浏览器无响应」;也解释「审核结果菜单不高亮」(页面 JS é˜»å¡žâ†’点击/高亮更新全被卡住,/audit é¡µè‡ªèº«æ— é—®é¢˜ï¼‰ã€‚
  - ä¿®å¤ï¼šDataImport.vue ä¸Ž ReportExport.vue çš„ `el-tabs` æ¢æˆ `el-radio-group`/`el-radio-button` æŒ‰é’® + `v-show` é¢æ¿ï¼ˆåŒäº‹æäº¤ 684da41/d42a044,本机已同步,绕开 TabNav æµ‹é‡å¾ªçŽ¯ï¼‰ã€‚
  - éªŒè¯ï¼š800/1280/1366/1440/1920 å…¨å®½åº¦ä¸¤é¡µå‡ä¸å†å†»ç»“(10s æŒç»­ ping æ­£å¸¸ï¼‰ã€Tab åˆ‡æ¢æ­£å¸¸ã€batches è¡¨æ ¼æ¸²æŸ“正常;/import ç‚¹å‡»ã€Œå®¡æ ¸ç»“果」菜单 â†’ `#/audit` é«˜äº®æ­£å¸¸ã€‚
  - /report è™½æµ‹è¯•未冻结,但同组件测量同样不可靠(1440x900 æ—¶ nav-wrap ä»… 97px),已一并替换防同类隐患。探针脚本在 `outputs/pptr/`(probe*.js、verify_*.js)。
- ä»£ç åŒæ­¥ï¼šå¤šæ¬¡ fetch/pull ä¿æŒä¸ŽæœåŠ¡å™¨ä¸€è‡´ï¼›åŒäº‹æ–°å¢žæäº¤å‡å·²æ‹‰å–ã€‚
- æœåŠ¡ç®¡ç†ï¼šå¤šæ¬¡åœæ—§èµ·æ–°ï¼ˆç²¾ç¡®æŒ‰ PID åœé“¾ï¼šåŽç«¯ cmd→maven→app,前端 cmd→npm→cmd→vue-cli;不杀 Codex å†…æ ¸/IDEA ç»ˆç«¯ï¼‰ã€‚
- éªŒè¯ç å…³é—­ï¼šæœ¬æœºé…ç½® `app.captcha.required: false` å¹¶é‡å¯åŽç«¯éªŒè¯ã€‚
- è´§è¿æ•°æ®ä¸€è‡´æ€§æ ¸å¯¹ï¼ˆ8/29):
  - å¯¹æ¯” `docs/货运需导入的数据/货运/`(2025 å…¨å¹´ 12 ä¸ªæœˆ + 2026 å¹´ 1-7 æœˆï¼Œå…± 19 ä¸ªæ–‡ä»¶ï¼Œå®žä¸º xlsx æ”¹ .xls æ‰©å±•名)与库表 `h2032_enterprise_monthly`。
  - **18 ä¸ªæœˆä»½å®Œå…¨ä¸€è‡´**(企业数/车辆/吨位/货运量/周转量逐项匹配)。
  - **2026-07 ä¸ä¸€è‡´**:库中 734 è¡Œï¼Œ98 å®¶ä¼ä¸šé‡å¤ï¼ˆæ¯æˆ· 2 è¡Œï¼‰ï¼ŒæŒ‡æ ‡åˆè®¡åå¤§çº¦ 12%;import_batch_id å…¨ NULL = 8/27 Navicat åˆå¹¶å¸¦è¿›ï¼ˆéžç³»ç»Ÿå¯¼å…¥äº§ç”Ÿï¼‰ã€‚未清理。
  - åº“中另有 2026-08(664 è¡Œï¼Œ8/26 æµ‹è¯•导入),目录无 8 æœˆæ–‡ä»¶ã€‚
  - å¯¼å…¥å¹‚等已确认:系统导入按 report_period å…ˆåˆ åŽæ’,再次导入只存最新一次。
## äº”、待办(新会话优先)
1. ~~/import æ•°æ®å¯¼å…¥é¡µ JS ä¸»çº¿ç¨‹å¡æ­»~~(8/31 å·²ä¿®å¤ï¼šel-tabs TabNav updated é’©å­ scrollable æŒ¯è¡ â†’ æ— é™æ¸²æŸ“循环;同事提交已换 el-radio-group æŒ‰é’® + v-show é¢æ¿ï¼Œè¯¦è§ç¬¬å››èŠ‚ï¼‰ã€‚
2. ~~认证信息 localStorage â†’ sessionStorage(强制登录)~~(8/31 å·²å®Œæˆå¹¶éªŒè¯ï¼Œè¯¦è§ç¬¬å››èŠ‚ï¼‰ã€‚
3. 2026-07 é‡å¤ 98 è¡Œæ¸…理(先备份再删,或重新导入 7 æœˆæ–‡ä»¶ï¼‰ã€‚
4. `docs/打包部署说明.docx` ç¬¬å…­èŠ‚ã€Œå¤–ç½® application.yml éœ€åŒ…含完整配置」改为「属性级合并」后重新导出。
5. æ­£å¼å‘布前:captcha.required æ”¹ true;崩溃根因以 access log å–证(勿宣称线程池实锤,已被 3 ç”¨æˆ·åœºæ™¯åé©³ï¼‰ã€‚
## å…­ã€åŽ†å²ç»“è®ºä¸Žå‘ï¼ˆé¿å…é‡å¤è¸©ï¼‰
- æ•°æ®å¯¼å…¥å´©æºƒæŽ’查:先误诊迅雷扩展 â†’ åŽå®žé”¤ Tomcat çº¿ç¨‹æ±  â†’ åˆè¢« 3 ç”¨æˆ·åœºæ™¯åé©³ â†’ åŒäº‹å‘现前端主线程卡死(最新方向)。**对用户不要宣称线程池实锤**。
- AGENTS.md ä¸‰å‘:①本机同时存在 Path/PATH åŒçŽ¯å¢ƒå˜é‡ï¼Œç¦ç”¨ Start-Process(用 cmd.exe /c + ProcessStartInfo);②node æ²™ç®±å†…访问 C:\Users è¢«æ‹’,脚本必须沙箱外跑;③不要嵌套 powershell å¼•号。
- ä¸´æ—¶è„šæœ¬/文件(项目根 `_probe*.py`、`_compare_freight.py`、`_probe*.sql`、`docs.zip`、`outputs/`、打包 zip)未经同意不删。
- æ‰“包 zip(traffic-audit-deploy-20260827.zip ç­‰ï¼‰å†…含真实 DeepSeek key / JWT secret,勿上传 git æˆ–外发;仓库只提交 `application.yml.example`。
docs/¹«Â·ÂÿÍ/¸öÌå¿ÍÔËÁ¿»ã×Ü.xlsx
Binary files differ
docs/¹«Â·ÂÿÍ/Ä£°å_½»ÆóͳH203-1±í_¹«Â·ÂÿÍÔËÊäÔ¶ÈÉú²úÇé¿ö.xlsx
Binary files differ
docs/¹«Â·ÂÿÍ/Éú³É_Öпھ¶·ÖÎö.xlsx
Binary files differ
docs/¹«Â·ÂÿÍ/Éú³É_Öпھ¶ÅÅÃû.xlsx
Binary files differ
docs/¹¦ÄܲâÊÔ±¨¸æ/¹¦ÄܲâÊÔ±¨¸æ_2026-09-02_µ¼ÈëÓ뱨±íÉú³É»Ø¹é.md
New file
@@ -0,0 +1,57 @@
# åŠŸèƒ½æµ‹è¯•æŠ¥å‘Šï¼š2026-07 å¯¼å…¥ä¸ŽæŠ¥è¡¨ç”Ÿæˆå›žå½’(2026-09-02)
> ç›®çš„:验证今日三条数据链「导入→入库→报表」全程可用
> â‘  å‡ºç§Ÿè¿æ”¿è½¦è¾† 7 æœˆï¼ˆD:\桌面\测试数据\城市客运\出租车信息列表 (2).xls)
> â‘¡ ä¸ªä½“客运量/周转量 7 æœˆï¼ˆæ–°å¸‚州汇总模板:湖北省公路旅客运输个体户月度生产情况(2026.7).xlsx,对应 docs\公路旅客\模板_*.xlsx)
> â‘¢ è´§è¿ 7 æœˆæ•°æ®é½å…¨åŽçš„æŠ¥è¡¨å£å¾„(D:\桌面\测试数据\货运\7月)
> é¡ºå¸¦å®Œæˆæ•°æ®æ±¡æŸ“清理 + 22 ä¸ªæŠ¥è¡¨æŽ¥å£é”™è¯¯å•元格全量扫描。
## ä¸€ã€å¯¼å…¥åŠŸèƒ½éªŒè¯
| ç±»åž‹ | æŠ¥è¡¨æœŸ | æºæ–‡ä»¶ | æ‰¹æ¬¡ | æ€»æ•°/成功/失败 | å…¥åº“核对 |
|---|---|---|---|---|---|
| å‡ºç§Ÿè¿æ”¿è½¦è¾† CITY_TAXI_AUTH | 2026-07 | å‡ºç§Ÿè½¦ä¿¡æ¯åˆ—表 (2).xls(真实 4.2 ä¸‡è¡Œï¼‰ | #188 | 42636 / 42636 / 0 | city_taxi_auth 2026-07 = 42636 è¡Œã€17 å¸‚州,与 2026-08(42636/17)完全一致 |
| ä¸ªä½“客运量 PASSENGER_INDIVIDUAL | 2026-07 | æ¹–北省公路旅客运输个体户月度生产情况(2026.7).xlsx(市州汇总模板) | #187 | 7 / 7 / 0 | passenger_individual_monthly åˆè®¡ 189998 äºº / 4584040.2 äººå…¬é‡Œ = æºè¡¨å…¨çœåˆè®¡ï¼›æŠ½æ£€é»„冈 5886/175992、孝感 19636/386845 ç­‰ä¸€è‡´ |
| è´§è¿é‡/周转量(数据层补齐) | 2026-07 | 2026å¹´7月客运量、货运量-5xlsx.xlsx | SQL è¡¥é½ | 18 è¡Œï¼ˆ17 å¸‚å·ž+湖北省) | åŸŽå¸‚月合计 16285.7105 ä¸‡ = æ¹–北省 16285.7105;周转量城市合计 2181925.708 = æ¹–北省 2181925.71;武汉 4940.9715/667561.3739 ä¸Žæºä¸€è‡´ |
| è§„上规下拆分(数据层重建) | 2026-07 | åŒä¸Š | SQL é‡å»º | MONTH/CUMULATIVE å„ 18 è¡Œ | MONTH åˆè®¡å‘¨è½¬é‡ 2181925.71(规上 597278.64/规下 1584647.07)、CUM åˆè®¡ 15222118.45;武汉 MONTH 204809.56/462751.81/667561.37 |
补充说明:
- ä¿®å¤å‰ 2026-07 æ›¾å­˜åœ¨é»„石等行 freight_m07 ä¸º NULL â†’ åˆ†å¸‚州月季差出现 -323.97 ç­‰è´Ÿå€¼ï¼Œå·²æ¶ˆé™¤ã€‚
- import_batch #177/#178/#179/#186 ä¸ºâ€œæ¨¡æ¿ä»…表头/旧模板首试”产生的 0 è¡Œæ‰¹æ¬¡ï¼Œæœªäº§ç”Ÿæ•°æ®ï¼Œä¿ç•™ä½œå®¡è®¡åŽ†å²ã€‚
## äºŒã€æŠ¥è¡¨ç”Ÿæˆå›žå½’(period=2026-07&mode=month)
- 22 ä¸ªå¯¼å‡ºæŽ¥å£å…¨éƒ¨ HTTP 200,输出留档:outputs\report_check\regression_2026-07\
- å…¨æ–‡ä»¶é”™è¯¯å…¬å¼æ‰«æï¼ˆå« 4 ä¸ª series åŒ…内层):#REF! / #DIV/0! / #VALUE! ç­‰ **0 æ®‹ç•™**。
- æ•°å€¼æŠ½æŸ¥ä¸Žå®˜æ–¹æºè¡¨ä¸€è‡´ï¼š
  - cityDetail:全省 7 æœˆè´§è¿é‡ O5=16285.71、武汉 O11=4940.97、武汉 1-7 ç´¯è®¡ AA11=34306.78。
  - turnoverRank:全省累计规上 4357157.34 / è§„下 10864961.11 / åˆè®¡ 15222118.45,与 scale_split CUMULATIVE é€ä½ä¸€è‡´ã€‚
  - freightRank:武汉累计规上 8905.15 / è§„下 25401.63 / åˆè®¡ 34306.78。
  - å…¬äº¤/出租/轨道轮渡三张表:表头为「2026å¹´1月…2026å¹´7月、2026年累计」,无 46082 æ•°å­—序列号;轨道全省行求和 = æ­¦æ±‰+黄石(6 æœˆ 11921.16 = 11886.3+34.86 âœ“)。
- ç³»åˆ—包(cityPassengerSeries / passengerSeries / freightSeries / investSeries)内层全部 clean。
- è¯´æ˜Žï¼šæŠ•资四张 invest* ä¸º HSSF è€æ ¼å¼å¯¼å‡ºï¼ˆæ‰©å±•名 .xlsx、内容为二进制 .xls,Excel å¯æ­£å¸¸æ‰“开),本日未做逐格公式扫描。
## ä¸‰ã€æœ¬è½®ä¿®å¤ä¸Žæ¸…理
代码(ReportExportService.java ä¸ºä¸»ï¼‰ï¼š
1. æŠ¥è¡¨åŒæœŸæ•°æ®æŒ‰ report_period åŒå¹´è¿‡æ»¤ â€”— ä¿®å¤ H2032 åŽ»å¹´åŒæœˆæ··å…¥å½“å¹´å¯¼è‡´â€œè§„ä¸Šè´§è¿é‡Ã—2、规下为负大值”的源头问题。
2. fixCityMonthHeaderText:未格式化日期序列号(46082 ç­‰ï¼‰â†’「yyyyå¹´M月」。
3. clearFormulaErrorCells / clearFormulaErrorsAll:清空求值错误的公式结果(模板跨簿/跨表同比 #REF!、无去年数据 #DIV/0!),不改写公式文本。
4. å·²æŽ¥å…¥ï¼šexportCityByTemplate(公交/出租)、exportCityRailFerryDetail、exportPassengerMidDetail、exportEnergySummary、exportCityPassengerCitySum、exportCityPassengerDetailSum。
5. DataImportService:个体客运双模板(保留旧“企业名称”模板 + æ–°å¢žå¸‚州汇总模板按标题块逐行入库);RegionUtil å¢žåŠ å¸‚å·žåâ†’6 ä½åŒºåˆ’码反向解析与短名别名。
数据(SQL å·²æ‰§è¡Œï¼Œç•™æ¡£ outputs\fill_2026-07_freight_scale.sql):
- freight_turnover_import、scale_split_transport 2026-07 è¡¥é½/重建(见第一节)。
- h2032_enterprise_monthly:2026-01~2026-08 å„ 636 æˆ·ã€0 é‡å¤ï¼ˆ8/29 è®°å½•çš„ 2026-07 â€œ734 è¡Œ / 98 æˆ·é‡å¤â€å·²æ¶ˆé™¤ï¼‰ï¼›2025-01~12 å„ 664 æˆ·ä¸ºåŽ»å¹´åŸºæœŸï¼Œæ­£å¸¸ã€‚
## å››ã€å·²çŸ¥ç¼ºå£ï¼ˆæ•°æ®æºé—®é¢˜ï¼Œéžä»£ç ç¼ºé™·ï¼‰
- åŸŽå¸‚客运月度数据(公交 U203/出租 U402/轨道/轮渡)库内并非每月都有真实值:轨道 2026 å¹´ä»… 6、7 æœˆæœ‰æ•°æ® â†’ æŠ¥è¡¨ 1-5 æœˆåˆ—留空。补齐各月源文件后重新导入即可完整。
- ç½‘约车无源数据,模板样例已清空(设计上不计入城市客运合计)。
- å‰ç«¯â€œå¯¼å…¥è¿›åº¦æ— æ˜¾ç¤ºâ€ï¼šæœ¬æ¬¡å¯¼å…¥å‡èµ°æŽ¥å£å¹¶æˆåŠŸè½åº“ï¼ˆæ‰¹æ¬¡å¯æŸ¥ï¼‰ï¼›4.2 ä¸‡è¡Œå¤§æ–‡ä»¶åœ¨é¡µé¢ä¸Šçš„进度提示未复现排查,属 UI ä¾§å¾…办。
## äº”、结论
- å¯¼å…¥åŠŸèƒ½ï¼šä¸‰æ¡é“¾ 0 å¤±è´¥ï¼Œå…¥åº“值与源文件逐项核对一致 â†’ å¯ç”¨ã€‚
- æŠ¥è¡¨ç”Ÿæˆï¼š22 æŽ¥å£å¯å‡ºæ•°ï¼Œæ—  #REF!/#DIV/0! æ±¡æŸ“,货运 7 æœˆæ•°å­—与官方 workbook ä¸€è‡´ â†’ å¯ç”¨ã€‚
- é—留:城市客运缺月源文件补齐;投资 .xls è€æ ¼å¼å¦‚需彻底扫描另议;页面进度条 UI å¤çŽ°æŽ’æŸ¥ã€‚
docs/¹¦ÄܲâÊÔ±¨¸æ/¹¦ÄܲâÊÔ±¨¸æ_µ¼ÈëУÑéÔöÇ¿_2026-09-02.md
New file
@@ -0,0 +1,50 @@
# åŠŸèƒ½æµ‹è¯•æŠ¥å‘Š_导入校验增强_2026-09-02
## 1. åŠŸèƒ½è¯´æ˜Ž
对数据导入服务(`DataImportService`)做“导入前置校验 + è§£æžå¥å£®æ€§â€å¢žå¼ºï¼Œé¿å…åƒèƒ½è€—事故那样“列错位静默导入”:
- è¿æ”¿è½¦è¾†ã€è½¨è¿¹é‡Œç¨‹ï¼šç”±â€œå›ºå®šåˆ—位”改为**表头名称映射**(与 H2032 è´§è¿æœˆæŠ¥ä¸€è‡´ï¼‰â€”—列顺序变化也能导入,缺列/列名不符明确报错。
- åŸŽå¸‚公交 U203、巡游出租 U402、投资系统导出:新增**表头列位校验**(`requireHeaderLayout`),列位错位直接拒绝并提示“第 X åˆ—应为…”。
- è´§è¿é‡å‘¨è½¬é‡ï¼šæ–°å¢žè¡¨å¤´æ ¡éªŒï¼ˆé¦–行须为「货运量(万吨)/1月…」布局)。
- è§„上规下拆分:新增 sheet å¸ƒå±€æ ¡éªŒï¼ˆç¬¬ 2 è¡Œã€Œå¸‚å·ž/规上企业运输量」+ ç¬¬ 3 è¡Œã€Œå‘¨è½¬é‡/货运量」子表头)。
## 2. æµ‹è¯•环境
- åŽç«¯ï¼šSpring Boot(8090),本地启动,2026-09-02 é‡å¯åŽç”Ÿæ•ˆã€‚
- æ•°æ®åº“:`traffic_audit`(localhost:3308)。
- æ–¹å¼ï¼š`curl /api/import/<type>` ç›´æŽ¥è°ƒç”¨ï¼Œæµ‹è¯•报表期 `2026-HT` / `2026-06`(测后已清理)。
- æ–‡ä»¶ï¼šå®˜æ–¹æ¨¡æ¿ï¼ˆdocs/货运、docs/城市客运、docs/投资)+ æž„造用例(列序打乱/错位列/缺列)。
## 3. ç”¨ä¾‹ä¸Žç»“æžœ
| # | ç±»åž‹ | ç”¨ä¾‹ | é¢„期 | å®žé™… | ç»“论 |
|---|---|---|---|---|---|
| 1 | è¿æ”¿è½¦è¾† | æ¨¡æ¿æ–‡ä»¶å¯¼å…¥ | æˆåŠŸå¯¼å…¥ | æˆåŠŸ 2 æ¡ | âœ… |
| 2 | è¿æ”¿è½¦è¾† | åˆ—顺序打乱(列名不变) | ä»èƒ½å¯¼å…¥ä¸”字段对齐 | æˆåŠŸ 2 æ¡ï¼Œå…¥åº“与模板逐项一致 | âœ… |
| 3 | è¿æ”¿è½¦è¾† | ç¼ºã€ŒæŒ‚车总吨位(吨)」列 | æ˜Žç¡®æŠ¥é”™ | è¡¨å¤´ç¼ºå°‘必需列【挂车总吨位(吨)】 | âœ… |
| 4 | è½¨è¿¹é‡Œç¨‹ | æ¨¡æ¿æ–‡ä»¶å¯¼å…¥ | æˆåŠŸå¯¼å…¥ | æˆåŠŸ 2 æ¡ | âœ… |
| 5 | è½¨è¿¹é‡Œç¨‹ | åˆ—顺序打乱 | ä»èƒ½å¯¼å…¥ä¸”字段对齐 | æˆåŠŸ 2 æ¡ | âœ… |
| 6 | è½¨è¿¹é‡Œç¨‹ | åˆ—名改「月度里程(公里)」 | æ˜Žç¡®æŠ¥é”™ | è¡¨å¤´ç¼ºå°‘必需列【月度总里程(公里)】 | âœ… |
| 7 | åŸŽå¸‚公交 | è¡¨å¤´ç¬¬ 6 åˆ—插「错位列」 | æ‹’绝并提示列位 | â€œç¬¬ 6 åˆ—应为「公共汽电车_运营车数」” | âœ… |
| 8 | å·¡æ¸¸å‡ºç§Ÿ | è¡¨å¤´ç¬¬ 5 åˆ—插「错位列」 | æ‹’绝并提示列位 | â€œç¬¬ 5 åˆ—应为「载客车次总数」” | âœ… |
| 9 | æŠ•资系统导出 | ç¬¬ 1 åˆ—「行号」改「序号」 | æ‹’绝并提示列位 | â€œç¬¬ 1 åˆ—应为「行号」” | âœ… |
| 10 | æŠ•资系统导出 | æ­£ç¡®è¡¨å¤´ | æˆåŠŸ | æˆåŠŸ 0 æ¡ | âœ… |
| 11 | è´§è¿é‡å‘¨è½¬é‡ | æ¨¡æ¿æ–‡ä»¶å¯¼å…¥ | æˆåŠŸå¯¼å…¥ | æˆåŠŸ 18 æ¡ | âœ… |
| 12 | è´§è¿é‡å‘¨è½¬é‡ | é”™ç±»åž‹æ–‡ä»¶ï¼ˆè¿æ”¿è½¦è¾†ï¼‰ | æ‹’绝 | â€œè¡¨å¤´åº”为「货运量(万吨)/1月…」布局” | âœ… |
| 13 | è§„上规下 | æ¨¡æ¿æ–‡ä»¶å¯¼å…¥ | æˆåŠŸå¯¼å…¥ | æˆåŠŸ 36 æ¡ | âœ… |
| 14 | è§„上规下 | sheet åå«â€œå½“月”但布局错误 | æ‹’绝 | â€œsheet「测试当月」未找到「市州/规上…」表头” | âœ… |
| 15 | å…¬è·¯æ—…客运政车辆数 | æ¨¡æ¿å¯¼å…¥ï¼ˆä¸Šåˆä½“检) | æˆåŠŸ | 767 æ¡ 0 å¤±è´¥ | âœ… |
| 16 | ä¸ªä½“客运量 | è¡¨å¤´è¯†åˆ«ï¼ˆæ¨¡æ¿ä»…表头) | 0 æ¡æ— æŠ¥é”™ | æˆåŠŸ 0 æ¡ | âœ… |
| 17 | å‡ºç§Ÿè½¦è¿æ”¿ | è¡¨å¤´è¯†åˆ«ï¼ˆæ¨¡æ¿ä»…表头) | 0 æ¡æ— æŠ¥é”™ | æˆåŠŸ 0 æ¡ | âœ… |
## 4. å…¥åº“抽查(与源文件逐项对齐)
- è¿æ”¿è½¦è¾†ï¼ˆåˆ—序打乱后):安吉汽车物流 ç‰µå¼• 0/挂 96/其它 96/挂车吨位 1057.708/其它吨位 871.56 âœ…
- è½¨è¿¹é‡Œç¨‹ï¼šæ¹–北中升运输 æœˆåº¦é‡Œç¨‹ 150427.03/有里程车辆 29 âœ…
- è´§è¿é‡å‘¨è½¬é‡ï¼šæ­¦æ±‰ 1 æœˆ=5367.97597、6 æœˆ=5041.04224、去年 1 æœˆ=4656.86022 âœ…
- è§„上规下:武汉当月 è§„上=241659.5295/规下=445444.355/合计=687103.884(累计 sheet ä¸€è‡´ï¼‰âœ…
## 5. å‘现的问题与处置
- æœªå‘现新缺陷。遗留:出租车运政模板无数据行,仅验证表头识别;2026-08 å·²çœŸå®žå¯¼å…¥ 42636 æ¡æˆåŠŸï¼Œå»ºè®®åŽç»­ç”¨çœŸå®žå¤§æ–‡ä»¶å›žå½’ä¸€æ¬¡ã€‚
## 6. ç»“论
- æ‰€æœ‰å¯¼å…¥ç±»åž‹çŽ°åœ¨éƒ½æœ‰ç±»åž‹è¯†åˆ«/校验兜底;运政车辆/轨迹里程兼容列顺序变化。功能可用,可交付。
## 7. æ•°æ®è¯´æ˜Ž
- æµ‹è¯•数据(2026-HT、2026-06 æµ‹è¯•期)已全部清理;未触碰 2026-07/08 çœŸå®žæ•°æ®ã€‚
docs/¹¦ÄܲâÊÔ±¨¸æ/¹¦ÄܲâÊÔ±¨¸æ_Ͷ×ÊÉóºËI004»ù׼ȱʧ±£»¤_2026-09-02.md
New file
@@ -0,0 +1,29 @@
# åŠŸèƒ½æµ‹è¯•æŠ¥å‘Š_投资审核I004基准缺失保护_2026-09-02
## 1. åŠŸèƒ½è¯´æ˜Ž
问题:8 æœˆæŠ•资物流园区/客运站场导入后,审核出现大量 RULE_I004「投资系统项目缺失核实」误报(2026-08 å…± 163 æ¡ï¼‰ï¼ŒåŽŸå› æ˜¯åŒæŠ¥è¡¨æœŸçš„æŠ•èµ„ç³»ç»Ÿå¯¼å‡ºåŸºå‡†ï¼ˆinvestment_system 2026-08)尚未导入,库里只有 2026-07 åŸºå‡†ï¼›I001–I003 ç¼ºåŸºå‡†æ—¶ä¼šè·³è¿‡ï¼ˆsys==null ä¸å¯¹æ¯”),但 I004(checkInvestExistence)缺基准时仍把每个项目标成“投资系统导出中不存在”。
修复(AuditEngineService):
- executeInvestmentAudit:同报表期投资系统基准整期缺失(sysMap ä¸ºç©ºï¼‰æ—¶ï¼Œè·³è¿‡ EXISTENCE_SYS ç±»è§„则,不再整表误报。
- ruleSkipped:RULE_I004 åŠ å…¥â€œåŸºå‡†æ•´æœŸç¼ºå¤±â†’è·³è¿‡â€åˆ¤å®šï¼Œè§„åˆ™ç»Ÿè®¡é¡µæ ‡è®° skipped=true(与 I001–I003 ä¸€è‡´ï¼‰ã€‚
## 2. æµ‹è¯•环境
- åŽç«¯ï¼šSpring Boot(8090),2026-09-02 ä¿®å¤åŽé‡å¯ç”Ÿæ•ˆã€‚
- æ•°æ®åº“:traffic_audit(localhost:3308)。
- æ–¹å¼ï¼š`/api/audit/execute?period=2026-08&reportType=INVEST` + åº“表计数核对。
## 3. ç”¨ä¾‹ä¸Žç»“æžœ
| # | åœºæ™¯ | é¢„期 | å®žé™… | ç»“论 |
|---|---|---|---|---|
| 1 | åŸºå‡†ç¼ºå¤±ï¼ˆ2026-08 æ—  investment_system æ•°æ®ï¼‰ï¼Œé‡è·‘ 8 æœˆå®¡æ ¸ | I004 ä¸å†æ•´è¡¨è¯¯æŠ¥ | ä¿®å¤å‰ 163 æ¡ â†’ ä¿®å¤åŽ 0 æ¡ | âœ… |
| 2 | è§„则统计 ruleStats(基准缺失) | I001–I004 å‡ skipped=true | 4 æ¡è§„则全部 skipped=true,hit=0 | âœ… |
| 3 | å¯¼å…¥æµ‹è¯•基准(7月模板→2026-08,148 æ¡ï¼‰åŽé‡è·‘审核 | I004 æ¢å¤çœŸå®žç¼ºå¤±æ£€æµ‹ | I004=42 æ¡ï¼ŒI001=35、I002=54、I003=37(均按基准正常对比) | âœ… |
| 4 | æ¸…理测试基准后重跑审核 | å›žåˆ° 0 è¯¯æŠ¥ã€ä¸æ®‹ç•™æµ‹è¯•数据 | INVEST ç»“æžœ 0 æ¡ï¼Œinvestment_system 2026-08 0 è¡Œ | âœ… |
## 4. å‘现的问题与处置
- æ— æ–°å¢žç¼ºé™·ã€‚修复后 8 æœˆå®¡æ ¸ç»“果已还原为干净状态(0 æ¡ï¼‰ï¼Œç­‰å¾… 8 æœˆæŠ•资系统导出文件导入后重跑审核即可恢复完整对比。
## 5. ç»“论
- I004 ä¸Ž I001–I003 è¡Œä¸ºä¸€è‡´ï¼šåŸºå‡†æœªåˆ°ä½æ—¶ä¸è¯¯æŠ¥ï¼ˆæ ‡è®°è·³è¿‡ï¼‰ï¼ŒåŸºå‡†åˆ°ä½åŽæ­£å¸¸æ£€æµ‹ã€‚功能可用,可交付。
## 6. æ•°æ®è¯´æ˜Ž
- æµ‹è¯•基准(investment_system 2026-08 148 æ¡ + å¯¼å…¥è®°å½•)已清理;2026-07 çœŸå®žåŸºå‡†æœªåŠ¨ï¼›2026-08 å®¡æ ¸ç»“果已重置为 0 æ¡ã€‚
docs/¹¦ÄܲâÊÔ±¨¸æ/¹¦ÄܲâÊÔ±¨¸æ_Ͷ×ÊÊÐÖÝÔ±¨¶àsheetʶ±ðÓëÐòºÅ¿Õ¸ñ_2026-09-02.md
New file
@@ -0,0 +1,36 @@
# åŠŸèƒ½æµ‹è¯•æŠ¥å‘Š_投资市州月报多sheet识别与序号空格_2026-09-02
## åŠŸèƒ½è¯´æ˜Ž
修复「投资(物流园区/客运站场)」市州月报导入的 2 ä¸ªé—®é¢˜ï¼š
1. **多 sheet é€‰è¡¨é”™è¯¯**:`神农架林区物流投资月报2026.08.xlsx` å…± 46 ä¸ª sheet(前 24 ä¸ªä¸ºåŽ†å²"潜江传化1月~2021.8"遗留 sheet,后 22 ä¸ªä¸ºç¥žå†œæž¶çœŸå®žæœˆæŠ¥ `2024.10`…`2026.8`),旧逻辑只看"8月"字样,误选历史 sheet「潜江传化8月」,读出潜江项目归属神农架 â†’ è¢«å¸‚州一致性校验拒绝(导入失败)。
2. **序号为空的项目行被跳过**:真数据 sheet `2026.8` ä¸­ã€Œç¥žå†œæž¶ç‰©æµå›­ã€é¡¹ç›®è¡Œåºå·åˆ—为空,旧解析把空序号行一律当市州小节行跳过,导致真实数据从未入库(库里只有客运「神农架枢纽站」,无「神农架物流园」)。
## ä¿®å¤æ–¹æ¡ˆï¼ˆDataImportService.java)
- `investSheetMatchesPeriod`:支持点号报表期(`2026.8`/`2026.08` â†’ å½’一化为连字符再匹配)。
- é€‰ sheet åŠ åˆ†ï¼šåŒ¹é…æŠ¥è¡¨æœŸä¸” sheet åå«å¹´ä»½å‰ç¼€ï¼ˆ`2026`)时额外 +100000 åˆ†ï¼Œä¼˜å…ˆé€‰å½“期真实报表,历史纯月份名 sheet æ— æ­¤åŠ åˆ†ã€‚
- è§£æžå¾ªçŽ¯ï¼šç©ºåºå·è¡Œè‹¥éžå¸‚å·žåã€ä¸” `isLikelyInvestProjectName` ä¸ºçœŸ â†’ æŒ‰é¡¹ç›®è¡Œå¤„理;非空非数字序号 â†’ è·³è¿‡ã€‚
- æ–°å¢ž helper `isLikelyInvestProjectName`:长度>4、非市州名、非备注/说明/注:/填表/审核/统计/负责开头。
- `countInvestRows` åŒæ­¥æ”¯æŒç©ºåºå·é¡¹ç›®è¡Œè®¡æ•°ã€‚
## æµ‹è¯•环境
- åŽç«¯ï¼štraffic-audit-server(Spring Boot,8090),代码重新编译后重启(11:34 å°±ç»ªï¼‰ã€‚
- æ•°æ®åº“:MySQL 3308 traffic_audit。
- æŽ¥å£ï¼š`POST /api/import/batch`(type=investmentLogistics,period=2026-08)。
- æµ‹è¯•文件:`D:\桌面\测试数据\八月源数据\物流\神农架林区物流投资月报2026.08.xlsx`、`潜江2026.08.xlsx`。
## ç”¨ä¾‹è¡¨
| # | ç”¨ä¾‹ | è¾“å…¥ | é¢„期 | å®žé™… | ç»“论 |
|---|------|------|------|------|------|
| 1 | æ­£å‘:神农架+潜江两文件批量导入 | ç¥žå†œæž¶æž—区物流投资月报2026.08.xlsx + æ½œæ±Ÿ2026.08.xlsx | total=2, success=2, fail=0 | total=2, success=2, fail=0,神农架林区 1 æ¡ã€æ½œæ±Ÿå¸‚ 1 æ¡ | âœ… é€šè¿‡ |
| 2 | å…¥åº“验证:神农架物流园项目 | â€” | investment_project å­˜åœ¨ã€Œç¥žå†œæž¶ç‰©æµå›­ã€ï¼Œcity=神农架林区 | id=228,total_investment=7440.35,city=神农架林区,builder=国投集团交投公司 | âœ… é€šè¿‡ |
| 3 | å…¥åº“验证:神农架物流园 8 æœˆæœˆåº¦æ•°æ® | â€” | investment_monthly 2026-08 æœ‰è®°å½• | year_plan=31,year_cum=26.1,month_done=0,start_cum=7535.45 | âœ… é€šè¿‡ |
| 4 | å…¥åº“验证:潜江文件不受影响 | â€” | æ½œæ±Ÿä¼ åŒ–公路港项目 2026-08 æ­£å¸¸ | year_plan=12000,year_cum=5173,month_done=1440 | âœ… é€šè¿‡ |
| 5 | åå‘对照:旧代码该场景 | åŒä¸€æ‰¹æ–‡ä»¶ï¼ˆä¿®å¤å‰ 11:32 è®°å½•) | â€” | batch#170:success=1, fail=1,报「潜江传化公路港项目」市州错位 | âœ… ä¿®å¤ç”Ÿæ•ˆ |
## å‘现的问题与处置
- æ— æ–°é—®é¢˜ã€‚历史遗留说明:`import_batch` #170(11:32:19)与 #168(11:00:56)为修复前旧逻辑的失败记录,属测试对照,不影响数据。
- ä¿®å¤å‰åº“里确实缺失神农架物流园 6/7/8 æœˆæ•°æ®ï¼ˆçœŸå®žæ•°æ®ä¸€ç›´æ¼å¯¼ï¼‰ï¼Œæœ¬æ¬¡å¯¼å…¥åŽ 8 æœˆå·²è¡¥é½ï¼›6/7 æœˆå¦‚需补导,需用同逻辑重导历史文件。
## ç»“论
全部用例通过。多 sheet é€‰è¡¨ä¼˜å…ˆå½“期带年份 sheet、空序号项目行可正确解析、市州一致性校验不再误伤神农架文件;潜江文件解析不受影响。
docs/¹¦ÄܲâÊÔ±¨¸æ/¹¦ÄܲâÊÔ±¨¸æ_Éú³ÉÄ£°åаæÊ½_2026-09-02.md
New file
@@ -0,0 +1,57 @@
# åŠŸèƒ½æµ‹è¯•æŠ¥å‘Šï¼šç”Ÿæˆæ¨¡æ¿æ–°ç‰ˆå¼æ”¹é€ ï¼ˆ2026-09-02)
> åŠŸèƒ½ï¼šæŒ‰ç”¨æˆ·æ‰‹å·¥æ”¹å¥½çš„â€œæ–°ç‰ˆå¼â€æ¨¡æ¿ï¼ˆä¸ŠåŠå—ã€Œ1-N月累计」+ ä¸‹åŠå—「N月当月/单月」)调整货运、公路旅客、城市客运三类《生成_*.xlsx》报表的填充逻辑。
> èŒƒå›´ï¼šåªæ”¹æŠ¥è¡¨ç”Ÿæˆä»£ç ä¸Žåº•稿引用,不涉及数据导入;代码未提交、未推送。
## ä¸€ã€åŠŸèƒ½è¯´æ˜Žï¼ˆä»£ç æ”¹åŠ¨ï¼‰
### 1. å…¬è·¯æ—…客
- `生成_中口径分析.xlsx`:下半块标题(A9)动态化为「YYYYå¹´M月中口径客运量及周转量」;数据行 R11-R15 å¡«å½“月客运量/周转量(当月=N月累计−N-1月累计)与当月同比;占比公式 D/H ç”±æŒ‡å‘ B$3/F$3 æ”¹ä¸ºæŒ‡å‘ B$11/F$11(当月块自身)。
- `生成_中口径排名.xlsx`:右侧当月块 K1 æ ‡é¢˜åŠ¨æ€åŒ–ã€ŒYYYYå¹´M月全省分市州完成道路客运生产情况」;L/P å¡«å½“月值、N/R å¡«å½“月同比;左侧仍为 1-N æœˆç´¯è®¡å—。
### 2. åŸŽå¸‚客运
- `生成_城市客运汇总.xlsx`:底部新增单月块(标题 A11,数据行 R13-R19:总客运量/总周转量、公交、出租、巡游出租、网约车=0、轨道、轮渡),填当月完成量,同比留空。
- `生成_城市客运客运量分市州累计.xlsx`、`生成_城市客运各市州明细表.xlsx`:当月块(客运量 R49-R66、周转量 R71-R88)改填当月值(当月累计差);当月块 RANK/占比/增速排名公式由复制累计块而来,改指当月块自身行;当月标题 A45/A67 åŠ¨æ€åŒ–ã€‚
- åº•稿引用修复:城市客运 6 å¤„已删除的《导入模板_城市公交/巡游出租/轨道轮渡/城市汇总/城市分市州/各市州明细表》全部改回同名《生成_*.xlsx》(ReportExportService/Controller、一键系列包内同步);前端 DataImport.vue åŸŽå¸‚公交/巡游出租“下载模板”链接同步改指《生成_*》。
### 3. è´§è¿
- `生成_货运量排名.xlsx`、`生成_周转量排名.xlsx`:R23 æ ‡é¢˜åŽ»æŽ‰â€œç´¯è®¡â€å­—æ · â†’「YYYYå¹´M月全省分市州完成公路货运量/货物运输周转量情况」。
- **第二页数据改填“当月”值(2026-09-02 16:40 ç¡®è®¤å¹¶å®žçŽ°ï¼‰**:货运量第二页合计=模板_货运量周转量当月列(freight_mN)、规上=H2032 å½“月吨/1e4、规下=差值,同比取去年同月;周转量第二页直接用拆分表 MONTH è¡Œï¼ˆå«å½“月同比字段)。
- ç¬¬äºŒé¡µåˆ—头“累计完成 (万吨/万吨公里)”在导出时内存替换为“当月完成”(`renameRankMonthHeader`,不改模板源文件)。
## äºŒã€æµ‹è¯•环境
- åŽç«¯ 8090 æœ¬åœ°è¿è¡Œï¼›æ•°æ®åº“ mysql localhost:3308 traffic_audit。
- æ•°æ®çŽ°çŠ¶ï¼šh2031(公路旅客企业月报)2026-03/07;city_bus/city_taxi 2026-06/07;h2032 2026-01~08 å®Œæ•´ã€‚
- æµ‹è¯•报表期:2026-07,mode=month。产物留档:outputs/report_check/regression_newtpl_2026-07/
## ä¸‰ã€ç”¨ä¾‹è¡¨
| # | ç±»åž‹ | è¾“å…¥ | é¢„期 | å®žé™… | ç»“论 |
|---|---|---|---|---|---|
| 1 | æ­£å‘ | passengerMidAnalysis 2026-07 | ä¸ŠåŠå—=1-7月累计,下半块=7月当月 | A1=「2026å¹´1-7月中口径…」B3=6151.91 ä¸‡äººã€F3=285634.95;A9=「2026å¹´7月中口径…」B11=3078.86 ä¸‡äººã€F11=141155.32;D12-H15 å æ¯”公式分母=B$11/F$11 | é€šè¿‡ |
| 2 | æ­£å‘ | passengerMidRank 2026-07 | å·¦å—累计标题、右块当月标题与当月值 | A1=1-7月累计标题;K1=「2026å¹´7月全省分市州完成…」;L3=3078.86(当月)与左块 B åˆ—累计数值明显区分 | é€šè¿‡ |
| 3 | æ­£å‘ | cityPassengerSummary 2026-07 | åº•部单月块=库内 2026-07 åˆè®¡ | A11=「2026å¹´7月全省完成城市客运量情况」;B13=30612.85、D13=218186.08;B14=12974.73(公交)、B15=5860.24(出租)、B18=11731.83(轨道)、B19=46.05(轮渡),与库内 city_bus/city_taxi 2026-07 åˆ†é¡¹åˆè®¡é€ä½ä¸€è‡´ | é€šè¿‡ |
| 4 | æ­£å‘ | cityPassengerCitySum 2026-07 | å½“月块=7月当月、公式指当月行 | å½“月客运量块武汉 R50:G=4218.74(公交)、L=1093.91(出租)、V=11701.74(轨道)、X=46.05(轮渡)、B=17060.44,与 DB 2026-07 ä¸€è‡´ï¼›C/H/M/R æŽ’名公式范围=B$50:B$66 ç­‰å½“月行;累计块与当月块数值区分明显 | é€šè¿‡ |
| 5 | æ­£å‘ | freightRank / turnoverRank 2026-07 | R23 æ ‡é¢˜æ— â€œç´¯è®¡â€ï¼›ç¬¬äºŒé¡µ=当月值 | R23=「2026å¹´7月…完成…」;上半块 1-7 ç´¯è®¡ä¸å˜ï¼›ç¬¬äºŒé¡µ 2026-07 å½“月值与库内逐项一致(见用例 11) | é€šè¿‡ |
| 11 | æ­£å‘ | freightRank/turnoverRank 2026-07 å½“月版(产出 freightRank_当月版_2026-07.xlsx / turnoverRank_当月版_2026-07.xlsx) | ç¬¬äºŒé¡µå½“月值与 DB ä¸€è‡´ã€åˆ—头=当月完成 | è´§è¿é‡ç¬¬äºŒé¡µï¼šå…¨çœ R26 B/G/L=3754.7823/12530.9282/16285.7105、武汉 R27 B=1227.5499(DB H2032 2026-07 æ­¦æ±‰åˆè®¡ 1227.5499 âœ“)、L=4940.9715;周转量第二页:全省 R26=597278.64/1584647.07/2181925.71、武汉 R27=204809.5633/462751.8106/667561.3739,与 DB scale_split MONTH è¡Œä¸€è‡´ï¼›B25/G25/L25 åˆ—头=“当月完成”;无错误公式 | é€šè¿‡ |
| 6 | æ­£å‘ | 10 ä¸ªå¯¼å‡ºæŽ¥å£ï¼ˆå«æœªåŠ¨è¡¨çš„å…¬äº¤/出租/轨道轮渡明细)2026-07 | å…¨éƒ¨å¯å‡ºæ•° | å…¨éƒ¨ HTTP 200;全文件错误公式扫描 #REF!/#DIV/0!/#N/A = 0 æ®‹ç•™ | é€šè¿‡ |
| 7 | è´Ÿå‘ | æ— æ•°æ®æœˆä»½ period=2026-05(citySummary/freightRank) | ä¸æŠ¥é”™ã€å½“月块留空 | HTTP 200,空表正常生成(产物 neg_citySummary_2026-05_nodata.xlsx) | é€šè¿‡ |
| 8 | è´Ÿå‘ | å¹´åˆå•月 period=2026-01(freightRank) | å½“月块=1月数据 | HTTP 200(产物 neg_freightRank_2026-01.xlsx) | é€šè¿‡ |
| 9 | è¾¹ç•Œ | è¶…范围月份 period=2026-13 | ä¸å´©ã€è½¯å¤„理 | HTTP 200 æ­£å¸¸å‡ºæ–‡ä»¶ | é€šè¿‡ï¼ˆå®½æ¾å¤„理) |
| 10 | è´Ÿå‘ | éžæ³•报表期 period=bad-period | å‹å¥½æŠ¥é”™æˆ– 400 | HTTP 500(无入参校验;前端为固定下拉,正常路径不可达) | å‘现缺陷(低优先) |
## å››ã€å…¥åº“抽查(与源库逐项对齐)
- åŸŽå¸‚客运汇总底部单月块:B14/D14(公交 12974.73 / 87147.68)、B15/D15(出租 5860.24 / 34236.60)、B18/D18(轨道 11731.83 / 96645.23)、B19/D19(轮渡 46.05 / 156.57)= SELECT SUM 2026-07 city_bus/city_taxi é€é¡¹ä¸€è‡´ã€‚
- åŸŽå¸‚客运当月块分市州:武汉 R50 å…¬äº¤ 4218.74、出租 1093.91 = DB 2026-07 æ­¦æ±‰å¸‚合计;其余 16 å¸‚州公交值与 DB é€å¸‚州一致(抽查 G åˆ— R50-R66)。
- å…¬è·¯æ—…客中口径下半块 3078.86 ä¸‡äºº / 141155.32 ä¸‡äººå…¬é‡Œ = 2026-07 å½“月源值(累计差口径,与既有回归口径一致)。
## äº”、发现的问题与处置
1. **货运两张排名表第二页“当月”填充(已实现并验证,2026-09-02 16:40)**:业务确认第二页要当月值后,已实现当月填充(货运量:规上=H2032 å½“月/合计=模板当月列/规下=差值;周转量:拆分表 MONTH è¡Œï¼‰ï¼Œå¹¶æŠŠç¬¬äºŒé¡µåˆ—头内存替换为“当月完成”。2026-07 å›žå½’与 DB é€é¡¹ä¸€è‡´ã€æ— é”™è¯¯å…¬å¼ã€‚模板源文件(docs/货运/生成_*.xlsx)本身仍写“累计完成”字样,如需源文件一并改可在 Excel ä¸­å¦å­˜ï¼ˆç¨‹åºå¯¼å‡ºå·²è‡ªåŠ¨æ˜¾ç¤ºä¸ºâ€œå½“æœˆå®Œæˆâ€ï¼‰ã€‚
2. **城市客运当月块 Q å—表头歧义(待业务确认)**:当月客运量块表头行 48 Q åˆ—写“其中:出租”、当月周转量块表头行 70 Q åˆ—写“其中:网约车”,程序按“网约车=0 ç•™ç©ºâ€å¡«å……;需确认业务口径(已记入待确认清单)。
3. **增速/增速排名列**:E/J/O/T/W/Y æ— åŽ»å¹´åŒæœŸæ•°æ®æ—¶ç•™ç©ºï¼Œå…¶æŽ’åå…¬å¼ï¼ˆF/K/P/U ç­‰ï¼‰ä¿ç•™ï¼›æ— åŽ»å¹´æ•°æ®æ—¶æŽ’åæ— ä¸šåŠ¡æ„ä¹‰ï¼Œå¾…æ¨¡æ¿å£å¾„ç¡®è®¤åŽå†³å®šæ˜¯å¦æ•´åˆ—æ¸…ç©ºã€‚
4. **非法 period è¿”回 500**:报表参数未做格式校验,前端固定下拉不可达,低优先级,建议后续统一补。
## å…­ã€ç»“论
- å…¬è·¯æ—…客、城市客运新版式改造已落地:上半“累计”+下半“当月”双块结构正确、公式范围正确、数值与库内 2026-07 æ•°æ®é€é¡¹å¯¹é½ï¼Œæ— é”™è¯¯å…¬å¼æ®‹ç•™ â†’ å¯ç”¨ã€‚
- è´§è¿ä¸¤å¼ æŽ’名表第二页“当月”填充已实现并通过 2026-07 å›žå½’(与库内 H2032 / freight_turnover_import / scale_split MONTH è¡Œé€é¡¹ä¸€è‡´ï¼‰ã€‚
docs/¹¦ÄܲâÊÔ±¨¸æ/¹¦ÄܲâÊÔ±¨¸æ_ÔËÕþ³µÁ¾Óë¹ì¼£Àï³Ìµ¼Èë»Ø¹é_2026-09-02.md
New file
@@ -0,0 +1,33 @@
# åŠŸèƒ½æµ‹è¯•æŠ¥å‘Š_运政车辆与轨迹里程导入回归_2026-09-02
## åŠŸèƒ½è¯´æ˜Ž
回归「运政车辆」「轨迹里程」导入功能(解析方式已于 09-02 æ”¹ä¸º"表头名称映射",列顺序变化也能正确导入)。用 docs é‡Œçš„ 7 æœˆæ•°æ®æ–‡ä»¶æµ‹è¯• 2026-08 æŠ¥è¡¨æœŸï¼ŒéªŒè¯æ­£å‘导入、入库对齐、列乱序、错类型负向等场景。
## æµ‹è¯•环境
- åŽç«¯ï¼štraffic-audit-server(Spring Boot,8090),13:21 é‡å¯å°±ç»ªã€‚
- æ•°æ®åº“:MySQL 3308 traffic_audit。
- æŽ¥å£ï¼š`POST /api/import/transportAuth`(运政车辆)、`POST /api/import/trackMileage`(轨迹里程)。
- æµ‹è¯•文件(docs å†…真实数据快照):
  - `docs/货运/模板_运政车辆.xlsx`(表头:企业名称/总牵引车数/总挂车数/其它车辆数/挂车总吨位(吨)/其它车辆总吨位(吨),635 è¡Œæ•°æ®ï¼‰
  - `docs/货运/模板_轨迹里程.xlsx`(表头:序号/企业名称/月度总里程(公里)/有里程的车辆数,628 è¡Œæ•°æ®ï¼‰
## ç”¨ä¾‹è¡¨
| # | ç”¨ä¾‹ | è¾“å…¥ | é¢„期 | å®žé™… | ç»“论 |
|---|------|------|------|------|------|
| 1 | æ­£å‘:运政车辆导入 | æ¨¡æ¿_运政车辆.xlsx â†’ transportAuth, period=2026-08 | æˆåŠŸ 635 æ¡ | 635 æ¡æˆåŠŸï¼Œ0 å¤±è´¥ | âœ… é€šè¿‡ |
| 2 | æ­£å‘:轨迹里程导入 | æ¨¡æ¿_轨迹里程.xlsx â†’ trackMileage, period=2026-08 | æˆåŠŸ 628 æ¡ | 628 æ¡æˆåŠŸï¼Œ0 å¤±è´¥ | âœ… é€šè¿‡ |
| 3 | å…¥åº“对齐(运政) | æŠ½æŸ¥åº“中 2026-08 è®°å½• | ä¸Žæºæ–‡ä»¶é€é¡¹ä¸€è‡´ | å®‰å‰æ±½è½¦ç‰©æµ 0/96/96/1057.708/871.56 ç­‰å‰ 3 å®¶ä¸€è‡´ | âœ… é€šè¿‡ |
| 4 | å…¥åº“对齐(轨迹) | æŠ½æŸ¥åº“中 2026-08 è®°å½• | ä¸Žæºæ–‡ä»¶é€é¡¹ä¸€è‡´ | æ¹–北中升运输 150427.03/29 ç­‰å‰ 3 å®¶ä¸€è‡´ | âœ… é€šè¿‡ |
| 5 | åˆ—乱序仍可导入(运政) | æ‰“ä¹± 6 åˆ—顺序的副本 â†’ transportAuth | 635 æ¡æˆåŠŸï¼Œæ•°å€¼ä¸é”™ä½ | 635 æ¡æˆåŠŸï¼ŒæŠ½æŸ¥å€¼ä¸Žæºæ–‡ä»¶ä¸€è‡´ï¼ˆå¹‚ç­‰å…ˆåˆ åŽæ’ï¼‰ | âœ… é€šè¿‡ |
| 6 | åˆ—乱序仍可导入(轨迹) | æ‰“乱并去掉序号列的副本 â†’ trackMileage | 628 æ¡æˆåŠŸï¼Œæ•°å€¼ä¸é”™ä½ | 628 æ¡æˆåŠŸï¼ŒæŠ½æŸ¥å€¼ä¸Žæºæ–‡ä»¶ä¸€è‡´ | âœ… é€šè¿‡ |
| 7 | è´Ÿå‘:错类型文件 | è¿æ”¿æ–‡ä»¶è°ƒ trackMileage | æ˜Žç¡®æŠ¥é”™ã€åˆ—出缺列 | æŠ¥"表头缺少必需列【月度总里程(公里)】【有里程的车辆数】,请确认是否选错了数据类型",未误删数据 | âœ… é€šè¿‡ |
| 8 | è´Ÿå‘:错类型文件 | è½¨è¿¹æ–‡ä»¶è°ƒ transportAuth | æ˜Žç¡®æŠ¥é”™ã€åˆ—出缺列 | æŠ¥"表头缺少必需列【总牵引车数】…",未误删数据 | âœ… é€šè¿‡ |
## å‘现的问题与处置
- æ— æ–°å¢žé—®é¢˜ã€‚说明:测试用 7 æœˆæ•°æ®å¯¼å…¥äº† 2026-08 æŠ¥è¡¨æœŸï¼ˆtransport_auth_vehicle / vehicle_track_mileage çš„ 2026-08 = 635/628 æ¡ï¼‰ï¼Œå±žåŠŸèƒ½æµ‹è¯•æ•°æ®ï¼Œå·²å‘ŠçŸ¥ç”¨æˆ·ï¼Œå¦‚éœ€æ¸…ç†å¯åˆ é™¤å¯¹åº”æŠ¥è¡¨æœŸè®°å½•ã€‚
- å®˜æ–¹èƒ½è€—格式(15 åˆ—/组,如 `道路货运车辆能源消耗情况(2026)2季度.xls`)按用户确认的"系统模板格式"口径:不实现官方格式直读,导入时由表头列位校验拒绝并提示"请使用系统模板《模板_道路货运车辆能源消耗情况(2026).xlsx》整理后再导入"(实测报:第 22 åˆ—应为「车牌号」,实际为「②出厂年份(年)」)。
- é¡ºå¸¦è¡¥å¯¼ï¼š`docs/投资/输入/物流(物流园区)/6月/林区物流投资月报2026.06.xlsx`、`7月/林区物流投资月报2026.07.24.xlsx` å¯¼å…¥ 2026-06/2026-07 å„ 1 æ¡æˆåŠŸï¼Œç¥žå†œæž¶ç‰©æµå›­ 6/7/8 æœˆæ•°æ®è¡¥å…¨ï¼Œä¸”验证多 sheet ä¿®å¤å¯¹ 6/7 æœˆæ–‡ä»¶åŒæ ·ç”Ÿæ•ˆï¼ˆ7 æœˆæ–‡ä»¶å« `2026.6` ä¸Ž `2026.7` ä¸¤ä¸ª sheet,正确选中 `2026.7`)。
## ç»“论
全部用例通过。运政车辆/轨迹里程按表头名称映射解析正常,列顺序变化不错位,错类型文件明确报错不误删数据;官方能耗按"系统模板格式"口径拒绝并提示整理。
docs/¹¦ÄܲâÊÔ±¨¸æ/µ¼ÈëÓëÉú³ÉÄ£¿éÌå¼ìÎÊÌâÇåµ¥_2026-09-02.md
New file
@@ -0,0 +1,63 @@
# å¯¼å…¥ä¸Žç”Ÿæˆæ¨¡å—体检问题清单(2026-09-02)
> æ–¹å¼ï¼šé™æ€ä»£ç å®¡æŸ¥ + æ•°æ®åº“只读核对(未动模板、未重启后端)。模板文件正在由另一会话修改,涉及模板联动的问题标注【协作】。
> çŠ¶æ€å«ä¹‰ï¼šP0=会造成导出/导入直接失败或数据静默错误;P1=违反需求(行号提示/可追溯)或导致报表内容残缺;P2=体验/一致性/潜在误删。
## ä¸€ã€P0(会直接挂或数据静默错)
### 1.【协作】城市客运 6 å¼ å¯¼å‡ºçš„æ¨¡æ¿æ–‡ä»¶å·²è¢«åˆ é™¤ï¼Œä»£ç å¼•用未同步
- è¯æ®ï¼š`docs/城市客运/导入模板_城市公交.xlsx`、`导入模板_巡游出租.xlsx`、`导入模板_轨道、轮渡.xlsx`、`导入模板_城市分市州.xlsx`、`导入模板_城市客运各市州明细表.xlsx`、`导入模板_城市汇总.xlsx` å·²è¢«å¦ä¸€ä¼šè¯åˆ é™¤ï¼ˆgit æ˜¾ç¤º D),换成 `生成_*.xlsx` ç³»åˆ—。
- å½±å“ï¼š`ReportExportService.java` ä»ç¡¬ç¼–码读取上述 6 ä¸ªæ–‡ä»¶åï¼ˆ`resolveTemplate("docs/城市客运")`),文件不存在时导出抛“未找到模板文件”→ cityBusDetail/cityTaxiDetail/cityRailFerryDetail/cityPassengerCitySum/cityPassengerDetailSum/cityPassengerSummary é‡å¯åŽå¿… 500。
- å¤„置:模板会话定稿时把代码引用同步为新的 `生成_*.xlsx`(或恢复旧文件),本会话不重复改;定稿后跑 v2 å›žå½’。
### 2. æ•°å€¼è§£æžéžæ³•文本静默置 0(getDecimal/getInt)
- è¯æ®ï¼š`DataImportService.getDecimal()` æ•获 `NumberFormatException` åŽè¿”回 `0.0`;`getInt()` å†å– intValue。运政车辆/轨迹里程/规上规下/货运量周转量等大量走 `gd()/gi()`。
- å½±å“ï¼šæºæ–‡ä»¶æŸæ ¼ä¸ºéžæ•°å­—文本(如“未填”“—”)时不报错、无行号,直接入库 0,success ç…§è®¡ â†’ æŠ¥è¡¨æ•°å­—悄悄错,违背“导入失败显示行号”的要求。
- å¤„置建议:非空且非数字的单元格按“失败行 + è¡Œå· + åŽŸå› â€è®°å½•ï¼ˆä¸Ž H2032/H204 çš„ failDetails ä¸€è‡´ï¼‰ï¼Œè€Œä¸æ˜¯é™é»˜ 0。
## äºŒã€P1
### 3. 6 ç±»å¯¼å…¥å¤±è´¥ä¸è®°è¡Œå·/原因(errorDetail=null)
- èŒƒå›´ï¼šTRANSPORT_AUTH、TRACK_MILEAGE、SCALE_SPLIT、FREIGHT_TURNOVER、INVEST_SYSTEM、CITY_TAXI_AUTH。
- è¯æ®ï¼š`recordBatch(..., null)`;失败仅在插入 try/catch ä¸­ `failRows++`。
- å½±å“ï¼šé¡µé¢â€œå¯¼å…¥ç»“果”只能看到“失败 N æ¡â€ï¼Œæ— å¤±è´¥ä½ç½®/原因(前端兜底显示“该批次无失败明细”)。
- å¤„置建议:与 H2032/H2031/H204 å¯¹é½ï¼Œæ”¶é›†è¡Œå·+企业名/车牌+原因;CITY_TAXI_AUTH 42636 è¡Œåˆ†æ‰¹æ’入尤其需要行级失败收集。
### 4. import_batch_id ä»Žæœªå›žå¡«ï¼ˆæ‰¹æ¬¡ä¸Žä¸šåŠ¡æ•°æ®æ–­é“¾ï¼‰
- è¯æ®ï¼š`freight_turnover_import` 18/18、`scale_split_transport` 36/36、`h2032_enterprise_monthly` 2026 å¹´ 5088/5088 è¡Œ `import_batch_id` å…¨ NULL;代码中无任何 `setImportBatchId` è°ƒç”¨ã€‚
- å½±å“ï¼šæ— æ³•回答“这批数据来自哪个文件/哪次导入”,无法按批次追溯与回滚;报表核对只能靠 import_type+report_period é—´æŽ¥çŒœã€‚
- å¤„置建议:`recordBatch()` è¿”回批次 id,导入方法按期回填到业务表(表结构已具备该列)。
### 5. æœˆåº¦/基期数据缺口(决定报表完整度,非代码缺陷)
- è¯æ®ï¼š`city_bus_monthly`/`city_taxi_monthly` ä»… 2026-06、07(142/17 è¡Œï¼‰ï¼›`h2031_enterprise_monthly` ä»… 2026-03、07(778/771);2025 åŸºæœŸå…¨åº“无城市客运/公路旅客月度数据。
- å½±å“ï¼šåŸŽå¸‚客运 1-5 æœˆåˆ—空、同比列全空(去年基期缺失),`#REF!` åŒæ¯”公式只能被“清空”处理;中口径/公路旅客报表多数月份无数据。先补数据,报表才有意义。
- å¤„置:城市客运月度(U203/U402)与轨道/轮渡 2026 å¹´ 1-5 æœˆã€8 æœˆâ€¦æŒ‰æºæ–‡ä»¶è¡¥å¯¼ï¼›å…¬è·¯æ—…客 H2031 è¡¥ 1/2/4/5/6/8 æœˆï¼›åŽ»å¹´åŒæœŸï¼ˆ2025 æˆ– 2025 åŒæœŸï¼‰æ•°æ®è¡¥å¯¼åŽåŒæ¯”自动有值(需确认表结构支持去年列)。
## ä¸‰ã€P2
### 6. å‰ç«¯â€œå¯¼å…¥è¿›åº¦â€æ˜“误显示“无数据”,大文件无实时进度
- è¯æ®ï¼š`DataImport.vue loadData()` çš„ overview å–**每个类型最新一条批次**;空批次(0 è¡Œï¼Œ#177-179/#186 ç­‰ï¼‰ä¼šè¦†ç›–显示为“无数据”;批次表只展示 50 æ¡ã€æ— åˆ†é¡µï¼›å•文件导入仅 `status='uploading'`,无百分比(42636 è¡Œ 20-40 ç§’全程无反馈,体感“卡死/无进度”)。
- å¤„置建议:① overview ç»Ÿè®¡æ”¹ä¸ºâ€œåŒç±»åž‹æœ€è¿‘一次 total>0 çš„æ‰¹æ¬¡â€æˆ–合计;② æ‰¹æ¬¡åˆ—表分页;③ å¤§æ–‡ä»¶ç»™é˜¶æ®µæç¤ºæˆ–轮询进度;④ è§£æžåˆ° 0 è¡Œçš„æ–‡ä»¶æ˜Žç¡®æç¤ºâ€œæ–‡ä»¶æ— æœ‰æ•ˆæ•°æ®è¡Œâ€è€Œéžé™é»˜æˆåŠŸæ‰¹æ¬¡ã€‚
### 7. å‰ç«¯â€œå¹´æŠ¥â€åˆ†ç»„ 11 ä¸ªç±»åž‹åŽç«¯æ— å®žçް
- è¯æ®ï¼š`DataImport.vue groups` å« annualCompanyBasic/annualEnterpriseFinance/… 11 é¡¹ï¼›åŽç«¯ `DataImportService` switch ä¸Ž Controller å‡æ—  annual* æ”¯æŒã€‚
- å¤„置:要么从页面移除/禁用(未开放),要么补实现;否则用户点击即“不支持的导入类型”。
### 8. è¿æ”¿è½¦è¾†/轨迹里程幂等删除审核结果范围过宽(潜在误删)
- è¯æ®ï¼š`importTransportAuth/importTrackMileage` å¹‚等处直接 `auditResultMapper.delete(reportPeriod=period)`(未按规则 reportType è¿‡æ»¤ï¼‰ï¼Œå…¶å®ƒç±»åž‹å‡èµ° `deleteRuleResults(类型,period)`。
- å½±å“ï¼šåŒæŠ¥è¡¨æœŸè‹¥å…¶å®ƒç±»åž‹å·²å®Œæˆå®¡æ ¸ï¼Œå†å¯¼è¿æ”¿è½¦è¾†ä¼šè¿žå¸¦æ¸…掉当月其它类型审核结果(当前多为测试期影响小)。
- å¤„置建议:与其它类型统一为按 reportType çš„规则 id åˆ é™¤ã€‚
### 9. ç”Ÿæˆä¾§æ¨¡æ¿è”动风险点(供模板会话对照,勿遗漏)
- æŽ’名模板:标题写死 `row0/row22`、数据块从 `row3/row25` èµ·ï¼ˆfreightRank/turnoverRank)→ å¢žåˆ è¡Œä¼šé”™ä½ã€‚
- è´§è¿åˆ†å¸‚州明细:数据区从 0-based row4 èµ·ï¼ŒæŒ‰â€œçœ 6 æŒ‡æ ‡ + 17 å¸‚州×6 æŒ‡æ ‡â€è¿žç»­å†™ 108 è¡Œã€‚
- èƒ½è€—汇总:克隆基础 sheet åŽæŒ‰ 0-based row2..7 å†™ 6 ç§ç‡ƒæ–™ï¼ˆæŸ´æ²¹/汽油/…/燃料电池),D/J/L/M ä¸ºå…¬å¼åˆ—不动。
- ä¸­å£å¾„明细:Sheet1 æŒ‰ è¡Œ 5..94/99..188 äº”段式定位;Sheet2 åŽ»å¹´æ˜Žç»†é¡µæ®‹ç•™ #REF! éœ€éšæ¨¡æ¿ä¿®æ­£é‡æ–°ç¡®è®¤ã€‚
- åŸŽå¸‚客运:数据区 â‰¥75 è¡Œå®ˆå«ï¼›è¡¨å¤´æœˆä»½â€œåœ°åŒºâ€è¡Œå®šä½ï¼ˆå‰ 20 è¡Œï¼‰ï¼›åŽ»å¹´åˆ—ä»Ž 19 èµ·æ¯ 2 åˆ—。
- å…¬å¼å¤„置约定:跨簿/跨表求不出值的公式只清空结果(不删公式文本、不改列名)——模板若把 #REF! æ”¹ä¸ºçœŸå®žå¼•用,需同步确认代码写的列位置一致。
## å››ã€ç»“论
- ä»Šæ—¥å·²éªŒè¯çš„导入三链与 22 æŠ¥è¡¨ç»“论仍有效,但**城市客运 6 å¼ å¯¼å‡ºä¾èµ–的模板文件已不在**,模板会话定稿后必须做引用同步 + v2 å›žå½’(脚本已留档 outputs/report_check)。
- ä»£ç å±‚优先修:非法数值静默 0(P0-2)、失败行号补齐(P1-3)、批次 id å›žå¡«ï¼ˆP1-4)、运政/轨迹审核结果误删范围(P2-8)。
- æ•°æ®å±‚优先补:城市客运 1-5 æœˆä¸Žå…¬è·¯æ—…客缺月、2025 åŸºæœŸï¼ˆP1-5)——这是报表“月列空/同比空”的根因。
- å‰ç«¯ä½“验:进度展示(P2-6)、年报入口(P2-7)。
docs/³ÇÊпÍÔË/³ÇÊпÍÔËÊý¾ÝÓÅ»¯.docx
Binary files differ
docs/³ÇÊпÍÔË/¿ÍÔ˼ò»¯.xlsx
Binary files differ
docs/³ÇÊпÍÔË/µ¼ÈëÄ£°å_³ÇÊй«½».xlsx
Binary files differ
docs/³ÇÊпÍÔË/µ¼ÈëÄ£°å_³ÇÊзÖÊÐÖÝ.xlsx
Binary files differ
docs/³ÇÊпÍÔË/µ¼ÈëÄ£°å_³ÇÊпÍÔ˸÷ÊÐÖÝÃ÷ϸ±í.xlsx
Binary files differ
docs/³ÇÊпÍÔË/µ¼ÈëÄ£°å_³ÇÊлã×Ü.xlsx
Binary files differ
docs/³ÇÊпÍÔË/µ¼ÈëÄ£°å_ѲÓγö×â.xlsx
Binary files differ
docs/³ÇÊпÍÔË/µ¼ÈëÄ£°å_¹ìµÀ¡¢ÂÖ¶É.xlsx
Binary files differ
docs/³ÇÊпÍÔË/Éú³É_³ÇÊпÍÔ˸÷ÊÐÖÝÃ÷ϸ±í.xlsx
Binary files differ
docs/³ÇÊпÍÔË/Éú³É_³ÇÊпÍÔË¿ÍÔËÁ¿·ÖÊÐÖÝÀÛ¼Æ.xlsx
Binary files differ
docs/³ÇÊпÍÔË/Éú³É_³ÇÊпÍÔË»ã×Ü.xlsx
Binary files differ
docs/³ÇÊпÍÔË/Éú³É_¹ìµÀÂÖ¶É¿ÍÔËÁ¿·ÖÊÐÖÝÃ÷ϸ.xlsx
Binary files differ
docs/µ¼È빦ÄÜÌå¼ì±¨¸æ.md
New file
@@ -0,0 +1,75 @@
# å¯¼å…¥åŠŸèƒ½ä½“æ£€æŠ¥å‘Šï¼ˆ2026-09-02 å¼€å§‹ï¼‰
> ç›®çš„:逐类型验证"解析器列位 â†” å®˜æ–¹æ¨¡æ¿ â†” å®žæµ‹å¯¼å…¥æ•°æ®"三者一致,消除"其他类型会不会像能耗一样出问题"的疑虑。
> æ–¹æ³•:①静态对比解析器列位与官方模板表头 â†’ â‘¡ç”¨çœŸå®žæ¨¡æ¿æ–‡ä»¶å®žæµ‹å¯¼å…¥ï¼ˆæµ‹è¯•报表期)→ â‘¢æŠ½æŸ¥å…¥åº“数据与源文件逐项对齐 â†’ â‘£è®°å½•缺口。
## ç»“论总览
| ç±»åž‹ | è§£æžæ–¹å¼ | å®žæµ‹ | ç»“论 | é£Žé™©ç‚¹ |
|---|---|---|---|---|
| èƒ½è€— H204 å­£æŠ¥ | å›ºå®šåˆ—位(18列/组) | 7/8/9月各1284条 0失败 | âœ… å·²ä¿®å¤+列位校验 | å®˜æ–¹æ ¼å¼(15列/组)暂不支持,需转模板 |
| æŠ•资(客运站场/物流园区) | å›ºå®šåˆ—位+市州校验 | 6/7月真实文件(客运46+物流133、基准148) | âœ… åŽ†å²ä¼šè¯å·²å¤§é‡å®žæµ‹ | å•表"全省汇总大表"路径待复核 |
| åŸŽå¸‚公交 U203 | å›ºå®šåˆ—位(0-67) | 2026-04:142条 0失败;错位文件被拒 | âœ… å·²åŠ åˆ—ä½æ ¡éªŒ | åˆ—顺序变化不支持(拒绝而非导错) |
| å·¡æ¸¸å‡ºç§Ÿ U402 | å›ºå®šåˆ—位(0-40) | 2026-04:17条 0失败;错位文件被拒 | âœ… å·²åŠ åˆ—ä½æ ¡éªŒ | åŒä¸Š |
| H2032 è´§è¿æœˆæŠ¥ | è¡¨å¤´åç§°æ˜ å°„ | 18个月一致性核对通过 | âœ… å®‰å…¨ | â€” |
| å…¬è·¯æ—…客月报 H2031 | è¡¨å¤´åç§°æ˜ å°„ | 7月补导入46条 | âœ… å®‰å…¨ | â€” |
| è¿æ”¿è½¦è¾† | è¡¨å¤´åç§°æ˜ å°„(本次改造) | æ¨¡æ¿2行✅ åˆ—序打乱✅ ç¼ºåˆ—报错✅ | âœ… ä¸Žè´§è¿æœˆæŠ¥åŒæ–¹å¼ | å»ºè®®çœŸå®žå¤§æ–‡ä»¶å›žå½’ |
| è½¨è¿¹é‡Œç¨‹ | è¡¨å¤´åç§°æ˜ å°„(本次改造) | æ¨¡æ¿2行✅ åˆ—序打乱✅ ç¼ºåˆ—报错✅ | âœ… ä¸Žè´§è¿æœˆæŠ¥åŒæ–¹å¼ | åŒä¸Š |
| æŠ•资系统导出 | å›ºå®šåˆ—位(8列) | è¡¨å¤´æ ¡éªŒæ­£/负用例通过 | âœ… å·²åŠ åˆ—ä½æ ¡éªŒ | åˆ—位固定,错位拒绝 |
| è´§è¿é‡å‘¨è½¬é‡ | ç‰¹æ®Šå¸ƒå±€(市州行+左右年段) | 2026-06:18条 0失败;错类型文件被拒 | âœ… å·²è¡¥è¡¨å¤´æ ¡éªŒ | åˆ—数随月份变化,靠首列市州+表头识别 |
| è§„上规下拆分 | ç‰¹æ®Šå¸ƒå±€(sheet名+子表头) | 2026-06:36条 0失败;错布局被拒 | âœ… å·²è¡¥sheet布局校验 | ä¾èµ–sheet名含 å½“月/累计 |
| å…¬è·¯æ—…客运政车辆数 | è¡¨å¤´åç§°æ˜ å°„ | 2026-06:767条 0失败 | âœ… | â€” |
| ä¸ªä½“客运量 | è¡¨å¤´åç§°æ˜ å°„ | è¡¨å¤´è¯†åˆ«é€šè¿‡ï¼ˆæ¨¡æ¿ä»…表头) | âœ… | â€” |
| å‡ºç§Ÿè½¦è¿æ”¿è½¦è¾† | å›ºå®šåˆ—位(0-20) | è¡¨å¤´è¯†åˆ«é€šè¿‡ï¼ˆæ¨¡æ¿ä»…表头) | âœ… å·²æœ‰è½¦ç‰Œå…³é”®å­—校验 | çœŸå®ž4.2万行建议回归 |
## å·²æµ‹æ˜Žç»†
### åŸŽå¸‚公交(U203 äº¤ä¼ç»Ÿ 2026å¹´7月文件)
- å¯¼å…¥æµ‹è¯•报表期 2026-04:成功 142 æ¡ï¼Œå¤±è´¥ 0 æ¡ã€‚
- æŠ½æŸ¥ï¼šæ­¦æ±‰ä¸¤æ±Ÿè½®æ¸¡æœ‰é™è´£ä»»å…¬å¸ â†’ è¿è¥è½¦æ•° 0 / å®¢è¿é‡ 0 / å¡«è¡¨äºº ä½™ç£Š / ç”µè¯ 15802725070,与源文件逐项一致 âœ…
### å·¡æ¸¸å‡ºç§Ÿï¼ˆU402 äº¤è¡Œç»Ÿ 2026文件)
- å¯¼å…¥æµ‹è¯•报表期 2026-04:成功 17 æ¡ï¼Œå¤±è´¥ 0 æ¡ã€‚
- æŠ½æŸ¥ï¼šæ­¦æ±‰å¸‚ â†’ è½½å®¢è½¦æ¬¡ 729.27 / å®¢è¿é‡ 1093.91 / å¡«è¡¨äºº åˆ˜æ‰¬ / ç”µè¯ 02768820261,与源文件一致 âœ…
### è¿æ”¿è½¦è¾†ï¼ˆdocs/货运/模板_运政车辆.xlsx)
- æœ¬æ¬¡å·²ä»Ž"固定列位"改为"表头名称映射"(与 H2032 è´§è¿æœˆæŠ¥ä¸€è‡´ï¼‰ï¼Œå¿…需 6 åˆ—:企业名称/总牵引车数/总挂车数/其它车辆数/挂车总吨位(吨)/其它车辆总吨位(吨)。
- å®žæµ‹ï¼ˆæµ‹è¯•报表期 2026-HT,测后已清理):模板前 2 è¡Œå¯¼å…¥æˆåŠŸ 2 æ¡ï¼›**列顺序打乱后仍成功导入 2 æ¡**,入库字段与模板逐项一致(安吉汽车物流:牵引 0/挂 96/其它 96/挂车吨位 1057.708/其它吨位 871.56);删除「挂车总吨位(吨)」列 â†’ æŠ¥"表头缺少必需列"。
### è½¨è¿¹é‡Œç¨‹ï¼ˆdocs/货运/模板_轨迹里程.xlsx)
- æœ¬æ¬¡å·²ä»Ž"固定列位"改为"表头名称映射",必需 3 åˆ—:企业名称/月度总里程(公里)/有里程的车辆数。
- å®žæµ‹ï¼šæ¨¡æ¿å‰ 2 è¡Œå¯¼å…¥æˆåŠŸ 2 æ¡ï¼›åˆ—顺序打乱后仍成功 2 æ¡ï¼Œå…¥åº“一致(湖北中升运输:150427.03/29);列名改「月度里程(公里)」→ æŠ¥"表头缺少必需列"。
### å›ºå®šåˆ—位模块"列位校验"负向用例(2026-09-02)
- åŸŽå¸‚公交:表头第 6 åˆ—插「错位列」→ æ‹’绝:"第 6 åˆ—应为「公共汽电车_运营车数」,实际为「错位列」"。
- å·¡æ¸¸å‡ºç§Ÿï¼šè¡¨å¤´ç¬¬ 5 åˆ—插「错位列」→ æ‹’绝:"第 5 åˆ—应为「载客车次总数」,实际为「错位列」"。
- æŠ•资系统导出:第 1 åˆ—「行号」改「序号」→ æ‹’绝:"第 1 åˆ—应为「行号」,实际为「序号」"。
### è´§è¿é‡å‘¨è½¬é‡ / è§„上规下拆分(docs/货运,测试期 2026-06,测后已清理)
- è´§è¿é‡å‘¨è½¬é‡ï¼š18 æ¡ 0 å¤±è´¥ï¼›æŠ½æŸ¥æ­¦æ±‰å¸‚ 1月=5367.97597、6月=5041.04224、去年1月=4656.86022,与模板逐项一致 âœ…
- è§„上规下拆分:36 æ¡ï¼ˆå½“月+累计各 18 ä¸ªå¸‚州)0 å¤±è´¥ï¼›æŠ½æŸ¥æ­¦æ±‰å¸‚当月 è§„上=241659.5295/规下=445444.355/合计=687103.884,累计列一致 âœ…
- å·²è¡¥æ ¡éªŒï¼ˆ2026-09-02):货运量周转量检查表头「货运量(万吨)/1月…」;规上规下检查 sheet ç¬¬2行「市州/规上企业运输量」+ ç¬¬3行「周转量/货运量」子表头。负向用例(错类型文件/错布局 sheet)均被明确拒绝 âœ…
### å…¬è·¯æ—…客运政车辆数 / ä¸ªä½“客运量(docs/公路旅客,测试期 2026-06,测后已清理)
- è¿æ”¿è½¦è¾†æ•°ï¼ˆæ¨¡æ¿_公路旅客运政车辆数.xlsx):767 æ¡ 0 å¤±è´¥ï¼Œè¡¨å¤´åç§°æ˜ å°„ âœ…
- ä¸ªä½“客运量(个体客运量汇总.xlsx,仅表头无数据行):表头识别通过,导入 0 æ¡ âœ…
### å‡ºç§Ÿè½¦è¿æ”¿è½¦è¾†ï¼ˆdocs/城市客运,测试期 2026-06,测后已清理)
- å¯¼å…¥æ¨¡æ¿_出租车信息(运政车辆信息).xlsx ä»…表头无数据行:表头识别通过(含"车牌"关键字校验),导入 0 æ¡ âœ…
- 2026-08 å·²æœ‰çœŸå®ž 42636 æ¡åŽ†å²å¯¼å…¥æ•°æ®ï¼Œæœ¬è½®æœªè§¦ç¢°ã€‚
## å¾…测清单(下一步)
- å…¨éƒ¨ç±»åž‹å·²å®žæµ‹å®Œæ¯•。剩余建议项:
  1. å‡ºç§Ÿè½¦è¿æ”¿ 4.2 ä¸‡è¡ŒçœŸå®žå¤§æ–‡ä»¶å›žå½’(此前历史导入 42636 æ¡ï¼Œæ¨¡æ¿æ— æ•°æ®è¡Œæ— æ³•用模板实测)。
## å»ºè®®ï¼ˆæŒ‰ä¼˜å…ˆçº§ï¼‰
1. âœ… å·²å®Œæˆï¼šå›ºå®šåˆ—位类型补"表头列位校验"(能耗/公交/出租/投资系统导出);运政车辆/轨迹里程改为"表头名称映射"(与货运月报一致)。
2. âœ… å·²å®Œæˆï¼šè´§è¿é‡å‘¨è½¬é‡/规上规下补表头校验,所有导入类型现在都有类型识别/校验兜底。
3. å¹¶å‘互斥锁:按需(能耗已有;其他类型前端已防连点)。
4. å®˜æ–¹èƒ½è€—格式(15列/组)解析:待业务确认后实现,替代转换脚本。
5. è¿æ”¿è½¦è¾†/轨迹里程解析方式已变——建议用户拿真实月度大文件回归一次(列顺序与模板一致时结果与旧逻辑完全相同)。
## æµ‹è¯•数据说明
- 2026-04 æŠ¥è¡¨æœŸçŽ°æœ‰åŸŽå¸‚å…¬äº¤ 142 æ¡ã€å·¡æ¸¸å‡ºç§Ÿ 17 æ¡ä¸ºæœ¬æ¬¡ä½“检测试数据,非真实数据(待清理)。
- 2026-09-02 æ–°å¢žçš„ 2026-HT æµ‹è¯•期数据(运政/轨迹各 2 æ¡ + å¯¼å…¥ç»“果记录)已清理完毕。
- 2026-06 æµ‹è¯•期数据(货运量 18 / è§„上规下 36 / æ—…客运政 767 + å¯¼å…¥ç»“果记录)已清理完毕,未触碰 2026-07/08 çœŸå®žæ•°æ®ã€‚
docs/¹¤×÷ÈÕ½á/¹¤×÷ÈÕ½á_2026-09-02.md
New file
@@ -0,0 +1,55 @@
# å·¥ä½œæ—¥ç»“_2026-09-02
## ä»Šæ—¥å·¥ä½œ
1. **能耗导入事故复盘与处置(上午)**
   - æ ¹å› ï¼šå®˜æ–¹æ ¼å¼ï¼ˆ15 åˆ—/组)与系统简化模板(18 åˆ—/组)不匹配,固定列位解析导致整表错位。
   - å¤„置:清理 8/9 æœˆé”™ä½èƒ½è€—数据(各 1284 æ¡ï¼Œ7 æœˆä¿ç•™ï¼‰ï¼›å®˜æ–¹æ ¼å¼è½¬æ¨¡æ¿åŽé‡æ–°å¯¼å…¥ 2026-08/09 å‡ 1284 æ¡ 0 å¤±è´¥å¹¶éªŒè¯å¯¹é½ã€‚
2. **导入功能全面体检**(`docs/导入功能体检报告.md`)
   - å®žæµ‹ï¼šåŸŽå¸‚公交 142 æ¡ã€å·¡æ¸¸å‡ºç§Ÿ 17 æ¡ã€å…¬è·¯æ—…客运政 767 æ¡ã€è´§è¿é‡å‘¨è½¬é‡ 18 æ¡ã€è§„上规下 36 æ¡ã€å‡ºç§Ÿè½¦è¿æ”¿è¡¨å¤´è¯†åˆ«ç­‰ï¼ŒæŠ½æŸ¥å…¥åº“均与源文件一致。
3. **导入校验增强(代码改动,未提交/未推送)**
   - åŸŽå¸‚公交/巡游出租/投资系统导出补“表头列位校验”;运政车辆/轨迹里程改为“表头名称映射”(列顺序变化也能导入);货运量周转量/规上规下补表头/sheet å¸ƒå±€æ ¡éªŒã€‚
4. **建立工作规范**
   - æ¯å®Œæˆä¸€ä¸ªåŠŸèƒ½ç«‹å³æµ‹è¯•å¹¶å†™ã€ŠåŠŸèƒ½æµ‹è¯•æŠ¥å‘Šã€‹ï¼›æ¯å¤©å†™ã€Šå·¥ä½œæ—¥ç»“ã€‹ï¼ˆå‘½åé™„æ—¥æœŸï¼‰ã€‚å·²å†™å…¥ AGENTS.md å¹¶åˆ›å»º `docs/功能测试报告/`、`docs/工作日结/` ç›®å½•。
5. **投资审核 I004 åŸºå‡†ç¼ºå¤±è¯¯æŠ¥ä¿®å¤ï¼ˆä»£ç æ”¹åŠ¨ï¼Œæœªæäº¤/未推送)**
   - é—®é¢˜ï¼š8 æœˆæŠ•资物流园区/客运站场审核出现 163 æ¡ RULE_I004「投资系统项目缺失核实」误报——同报表期投资系统基准(2026-08)尚未导入,库里只有 7 æœˆåŸºå‡†ã€‚
   - ä¿®å¤ï¼šåŒæŠ¥è¡¨æœŸåŸºå‡†æ•´æœŸç¼ºå¤±æ—¶è·³è¿‡ I004(与 I001–I003 ä¸€è‡´ï¼‰ï¼Œè§„则统计标记 skipped;基准存在时恢复真实检测。
   - éªŒè¯ï¼šé‡è·‘ 8 æœˆå®¡æ ¸ 163 æ¡ â†’ 0 æ¡ï¼›å¯¼å…¥æµ‹è¯•基准后 I004 æ­£å¸¸æŠ¥ 42 æ¡çœŸå®žç¼ºå¤±ï¼›æ¸…理后还原 0 æ¡ã€‚测试报告:`docs/功能测试报告/功能测试报告_投资审核I004基准缺失保护_2026-09-02.md`。
6. **投资市州月报多 sheet è¯†åˆ«ä¸Žåºå·ç©ºæ ¼ä¿®å¤ï¼ˆä»£ç æ”¹åŠ¨ï¼Œæœªæäº¤/未推送)**
   - é—®é¢˜ï¼š`神农架林区物流投资月报2026.08.xlsx` æ‰“开看是神农架数据,却被市州一致性校验拒绝。
   - æ ¹å›  1:文件 46 ä¸ª sheet,前 24 ä¸ªæ˜¯åŽ†å²ã€Œæ½œæ±Ÿä¼ åŒ–1月~2021.8」遗留 sheet,旧选表逻辑只看「8月」字样,误选历史「潜江传化8月」→ è¯»å‡ºæ½œæ±Ÿé¡¹ç›®å½’属神农架 â†’ æ ¡éªŒæ‹’绝。
   - æ ¹å›  2:真数据 sheet `2026.8` é‡Œã€Œç¥žå†œæž¶ç‰©æµå›­ã€é¡¹ç›®è¡Œåºå·ä¸ºç©ºï¼Œæ—§è§£æžæŠŠç©ºåºå·è¡Œä¸€å¾‹å½“市州小节行跳过,真实数据从未入库(库里只有客运神农架枢纽站)。
   - ä¿®å¤ï¼šé€‰ sheet æ”¯æŒç‚¹å·æŠ¥è¡¨æœŸå¹¶ç»™ã€Œå¸¦å¹´ä»½å‰ç¼€ã€çš„当期 sheet åŠ åˆ†ä¼˜å…ˆï¼›ç©ºåºå·è¡Œè‹¥åƒé¡¹ç›®ååˆ™æŒ‰é¡¹ç›®è§£æžï¼›æ–°å¢ž `isLikelyInvestProjectName` åˆ¤æ–­ã€‚
   - éªŒè¯ï¼šç¥žå†œæž¶+潜江两文件批量导入 2 æˆåŠŸ 0 å¤±è´¥ï¼›ç¥žå†œæž¶ç‰©æµå›­å·²å…¥åº“(总投资 7440.35,8 æœˆ 31/26.1/0/7535.45);潜江不受影响。测试报告:`docs/功能测试报告/功能测试报告_投资市州月报多sheet识别与序号空格_2026-09-02.md`。
7. **运政车辆/轨迹里程导入回归(下午,无代码改动)**
   - ç”¨ docs 7 æœˆæ•°æ®ï¼ˆ`模板_运政车辆.xlsx` 635 å®¶ã€`模板_轨迹里程.xlsx` 628 å®¶ï¼‰æµ‹ 2026-08 æŠ¥è¡¨æœŸï¼šæ­£å‘ 635/628 æˆåŠŸï¼Œå…¥åº“ä¸Žæºæ–‡ä»¶é€é¡¹ä¸€è‡´ï¼›æž„é€ åˆ—ä¹±åºå‰¯æœ¬å¯¼å…¥ä»æˆåŠŸä¸”æ•°å€¼ä¸é”™ä½ï¼ˆéªŒè¯è¡¨å¤´åç§°æ˜ å°„ï¼‰ï¼›é”™ç±»åž‹æ–‡ä»¶æ˜Žç¡®æŠ¥é”™åˆ—å‡ºç¼ºåˆ—ä¸”ä¸è¯¯åˆ æ•°æ®ã€‚
   - å®˜æ–¹èƒ½è€—(15 åˆ—/组):按用户确认「系统模板格式」口径,实测官方文件被表头列位校验拒绝并提示用模板整理,不做官方格式直读。
   - è¡¥å¯¼ï¼šdocs å†… `投资/输入/物流(物流园区)/6月、7月` æž—区物流投资月报导入 2026-06/2026-07 æˆåŠŸï¼Œç¥žå†œæž¶ç‰©æµå›­ 6/7/8 æœˆæ•°æ®è¡¥å…¨å¹¶ä¸Žæºæ–‡ä»¶æ ¸å¯¹ä¸€è‡´ï¼ˆ7 æœˆæ–‡ä»¶å« `2026.6`/`2026.7` ä¸¤ sheet,正确选中 `2026.7`)。
   - æµ‹è¯•报告:`docs/功能测试报告/功能测试报告_运政车辆与轨迹里程导入回归_2026-09-02.md`。
8. **生成模板新版式改造(公路旅客/城市客运/货运排名,代码改动,未提交/未推送)**
   - ç”¨æˆ·å·²æŒ‰æ–°ç‰ˆå¼æ‰‹å·¥è°ƒæ•´ docs ä¸‹ã€Šç”Ÿæˆ_*.xlsx》(上半“累计”+下半“当月”);程序按新版式补齐填充点:中口径分析下半块(占比公式改指 B$11/F$11)、中口径排名右侧当月块、城市客运汇总底部单月块、城市分市州累计/各市州明细表当月块(当月=累计差,RANK/占比/增速排名公式改指当月行);货运量/周转量排名 R23 æ ‡é¢˜åŽ»â€œç´¯è®¡â€ã€‚
   - åŸŽå¸‚客运导出底稿从已删除的《导入模板_*》全部改回《生成_*》(服务/控制器/一键包同步),DataImport.vue ä¸‹è½½æ¨¡æ¿é“¾æŽ¥ä¸€å¹¶æ”¹æŒ‡ã€‚
   - éªŒè¯ï¼š10 æŽ¥å£ 2026-07 å…¨ 200、错误公式 0 æ®‹ç•™ï¼›åŸŽå¸‚汇总当月块与库内 2026-07 åˆ†é¡¹åˆè®¡é€ä½ä¸€è‡´ï¼ˆå…¬äº¤ 12974.73 / å‡ºç§Ÿ 5860.24 / è½¨é“ 11731.83 / è½®æ¸¡ 46.05);中口径下半块=7 æœˆå½“月 3078.86 ä¸‡äºº / 141155.32 ä¸‡äººå…¬é‡Œï¼›è´Ÿå‘/边界(无数据月 2026-05、年初 2026-01、超范围 2026-13、非法 bad-period)已测并留档。
   - **货运排名两表第二页“当月”填充已实现(16:40 ç¡®è®¤åŽè¡¥åšï¼‰**:exportFreightRank/exportTurnoverRank ç¬¬äºŒé¡µæ”¹å¡«å½“月值(货运:H2032 å½“月规上+模板当月合计-差值;周转量:拆分表 MONTH è¡Œï¼‰ï¼Œç¬¬äºŒé¡µåˆ—头导出时改“当月完成”;2026-07 å›žå½’武汉/全省与 DB é€é¡¹ä¸€è‡´ã€0 é”™è¯¯å…¬å¼ï¼Œäº§ç‰© `freightRank_当月版_2026-07.xlsx`、`turnoverRank_当月版_2026-07.xlsx`。
   - å¾…确认:城市客运当月块 Q åˆ—表头“出租/网约车”歧义;模板源文件列头“累计完成”如需一并落盘可在 Excel å¦å­˜ï¼ˆå¯¼å‡ºå·²è‡ªåŠ¨ä¸ºâ€œå½“æœˆå®Œæˆâ€ï¼‰ã€‚
## æµ‹è¯•结果摘要
- åŠŸèƒ½æµ‹è¯•æŠ¥å‘Šï¼š`docs/功能测试报告/功能测试报告_导入校验增强_2026-09-02.md`(17 ä¸ªæ­£/负向用例全部通过)。
- åŠŸèƒ½æµ‹è¯•æŠ¥å‘Šï¼š`docs/功能测试报告/功能测试报告_投资审核I004基准缺失保护_2026-09-02.md`(4 ä¸ªç”¨ä¾‹å…¨éƒ¨é€šè¿‡ï¼‰ã€‚
- åŠŸèƒ½æµ‹è¯•æŠ¥å‘Šï¼š`docs/功能测试报告/功能测试报告_投资市州月报多sheet识别与序号空格_2026-09-02.md`(5 ä¸ªç”¨ä¾‹å…¨éƒ¨é€šè¿‡ï¼‰ã€‚
- åŠŸèƒ½æµ‹è¯•æŠ¥å‘Šï¼š`docs/功能测试报告/功能测试报告_运政车辆与轨迹里程导入回归_2026-09-02.md`(8 ä¸ªç”¨ä¾‹å…¨éƒ¨é€šè¿‡ï¼‰ã€‚
- åŠŸèƒ½æµ‹è¯•æŠ¥å‘Šï¼š`docs/功能测试报告/功能测试报告_生成模板新版式_2026-09-02.md`(10 ä¸ªç”¨ä¾‹ï¼šæ­£å‘ 6 é€šè¿‡ã€è´Ÿå‘/边界 4 é€šè¿‡ï¼Œå¦è®°å½• 1 å¤„低优缺陷:非法 period è¿”回 500 æ— æ ¡éªŒï¼‰ã€‚
- è¿æ”¿è½¦è¾†/轨迹里程 2026-08(635/628 æ¡ï¼‰ä¸º 7 æœˆæ•°æ®æµ‹è¯•痕迹,保留与否待用户确认;其余测试数据已清理,未触碰 2026-06/07 çœŸå®žæŠ•资数据(本次补导为真实数据)。
## é—留问题与待办
- å‡ºç§Ÿè½¦è¿æ”¿ï¼šå¦ä¸€ä¼šè¯ä¿®æ­£ä¸­ï¼Œä¿®æ­£åŽéœ€çœŸå®ž 4.2 ä¸‡è¡Œå¤§æ–‡ä»¶å›žå½’。
- å®˜æ–¹èƒ½è€—(15 åˆ—/组):已确认不实现直读,按系统模板格式整理导入(现状行为已实测)。
- è¿æ”¿è½¦è¾†/轨迹里程 2026-08 ç›®å‰ä¸º 7 æœˆæ•°æ®æµ‹è¯•痕迹(635/628 æ¡ï¼‰ï¼Œå¦‚需保留用于后续 8 æœˆåŠŸèƒ½æµ‹è¯•è¯·å‘ŠçŸ¥ï¼Œå¦åˆ™æ¸…ç†ã€‚
- **8 æœˆæŠ•资系统导出文件待用户提供**:拿到后导入(investmentSystem / period=2026-08)并重跑 8 æœˆå®¡æ ¸ï¼ŒI001–I004 æ¢å¤å®Œæ•´å¯¹æ¯”。
- ç¥žå†œæž¶ç‰©æµå›­ 6/7/8 æœˆæ•°æ®å·²å…¨éƒ¨è¡¥å…¨ï¼ˆdocs å†… 6/7 æœˆæ–‡ä»¶å·²å¯¼å…¥ï¼‰ã€‚
## æ˜Žå¤©è®¡åˆ’(待用户确认)
- ç”¨æˆ·çœŸå®žæ–‡ä»¶æŠ½æŸ¥å›žå½’;按需继续业务功能开发。
docs/¹¤×÷ÈÕ½á/Ä£¿é¹¦ÄÜÑé֤״̬¾ØÕó_2026-09-02.md
New file
@@ -0,0 +1,82 @@
# æ¨¡å— â†’ åŠŸèƒ½ â†’ éªŒè¯çŠ¶æ€çŸ©é˜µï¼ˆ2026-09-02 å¿«ç…§ï¼‰
> çŠ¶æ€å£å¾„ï¼š
> âœ… å·²éªŒè¯å¯ç”¨ï¼ˆçœŸå®žæ•°æ®/回归证据,见“证据”列)
> âš ï¸ åŠŸèƒ½å¯ç”¨ä½†æ•°æ®æºæœ‰ç¼ºå£ï¼ˆç¼ºæœˆ/缺格式),补数据即完整
> ðŸŸ¡ éƒ¨åˆ†éªŒè¯ / æœªåšå…¨é¢å›žå½’
> æ•°æ®èŒƒå›´ï¼šæœ¬åœ° traffic_audit åº“(127.0.0.1:3308)+ å½“日(2026-09-02)22 æŠ¥è¡¨æŽ¥å£å›žå½’。
## è´§è¿ï¼ˆæ ¸å¿ƒæ¨¡å—,今日回归)
| åŠŸèƒ½ | éªŒè¯çŠ¶æ€ | è¯æ® / å¤‡æ³¨ |
|---|---|---|
| è´§è¿é‡/周转量月报导入(2026-07) | âœ… | 18 è¡Œ 0 å¤±è´¥ï¼›åŸŽå¸‚合计=湖北省 16285.7105 ä¸‡ / 2181925.708 ä¸‡å¨å…¬é‡Œï¼›æ­¦æ±‰ 4940.97/667561.37 |
| è§„上规下拆分(2026-07) | âœ… | MONTH/CUM å„ 18 è¡Œï¼Œåˆè®¡ä¸Ž workbook ä¸€è‡´ï¼ˆæ­¦æ±‰ MONTH 204809.56/462751.81/667561.37) |
| H2032 ä¼ä¸šæœˆæŠ¥æ•°æ® | âœ… | 2026-01~08 å„ 636 æˆ·æ— é‡å¤ï¼›2025 åŸºæœŸ 12 ä¸ªæœˆå„ 664 æˆ·ï¼ˆåŽ»å¹´æ­£å¸¸ï¼‰ |
| åˆ†å¸‚州明细 cityDetail å¯¼å‡º | âœ… | æ­¦æ±‰ 7 æœˆ 4940.97、累计 34306.78;无错误格 |
| æŽ’名表 freightRank / turnoverRank | âœ… | ä¸Ž scale_split é€ä½ä¸€è‡´ï¼ˆç´¯è®¡ 4357157.34/10864961.11/15222118.45) |
| è´§è¿ç³»åˆ— freightSeries(zip) | âœ… | å†…层 0 é”™è¯¯æ ¼ |
| è¿æ”¿è½¦è¾† / è½¨è¿¹é‡Œç¨‹å¯¼å…¥ï¼ˆ2026-08) | âœ… | 635 / 628 æ¡ï¼Œä¹±åºåˆ— + ç¼ºåˆ—报错负例通过(8/31 ä½“检报告) |
## åŸŽå¸‚客运
| åŠŸèƒ½ | éªŒè¯çŠ¶æ€ | è¯æ® / å¤‡æ³¨ |
|---|---|---|
| å…¬äº¤ U203 å¯¼å…¥ | âœ… | 2026-04 142 æ¡ 0 å¤±è´¥ + é”™ä½åˆ—被拒(体检报告) |
| å·¡æ¸¸å‡ºç§Ÿ U402 å¯¼å…¥ | âœ… | 2026-04 17 æ¡ 0 å¤±è´¥ + é”™ä½åˆ—被拒 |
| å‡ºç§Ÿè¿æ”¿è½¦è¾†å¯¼å…¥ï¼ˆ2026-07) | âœ… | 42636 æ¡ 0 å¤±è´¥ã€17 å¸‚州,与 2026-08 ä¸€è‡´ï¼ˆä»Šæ—¥ï¼‰ |
| å…¬äº¤ / å‡ºç§Ÿåˆ†å¸‚州明细导出 | âœ… | è¡¨å¤´ 2026 å¹´ 1-7 æœˆæ­£å¸¸ã€0 é”™è¯¯æ ¼ï¼ˆä»Šæ—¥ï¼‰ |
| è½¨é“ / è½®æ¸¡åˆ†å¸‚州明细导出 | âœ… | 0 é”™è¯¯æ ¼ï¼›å…¨çœæ±‚å’Œ=武汉+黄石(抽查一致)(今日) |
| è½¨é“ / è½®æ¸¡æœˆåº¦æ•°æ®æº | âš ï¸ | åº“内 2026 å¹´ä»… 6、7 æœˆæœ‰å€¼ â†’ æŠ¥è¡¨ 1-5 æœˆä¸ºç©ºï¼›è¡¥æœˆæºæ–‡ä»¶åŽå³å®Œæ•´ |
| åŸŽå¸‚客运汇总 / å„市州累计 / åŸŽå¸‚系列 | âœ… | ç´¯è®¡å æ¯” #DIV/0! å·²æ¸…(今日);网约车无源留空 |
## å…¬è·¯æ—…客
| åŠŸèƒ½ | éªŒè¯çŠ¶æ€ | è¯æ® / å¤‡æ³¨ |
|---|---|---|
| H2031 æœˆæŠ¥å¯¼å…¥ | âœ… | 2026-07 è¡¥å¯¼ 46 æ¡ |
| ä¸ªä½“客运量(新市州汇总模板,2026-07) | âœ… | 7 æ¡ 0 å¤±è´¥ï¼›å…¨çœåˆè®¡ 189998 äºº / 4584040.2 äººå…¬é‡Œ = æºè¡¨ï¼ˆä»Šæ—¥ï¼‰ |
| ä¸ªä½“客运量(旧“企业名称”模板) | âœ… | åŒæ¨¡æ¿å¹¶å­˜ï¼Œæ—§æ¨¡æ¿å…¼å®¹ä¿ç•™ |
| å…¬è·¯æ—…客运政车辆数导入 | âœ… | 2026-06 767 æ¡ |
| åˆ†å¸‚å·ž / ä¸­å£å¾„明细 / æŽ’名 / åˆ†æžå¯¼å‡º | âœ… | æ˜Žç»†åŽ»å¹´åŒæœŸé¡µ #REF! å·²æ¸…(今日);0 é”™è¯¯æ ¼ |
| å…¬è·¯æ—…客系列 passengerSeries(zip) | âœ… | å†…层 0 é”™è¯¯æ ¼ï¼ˆä»Šæ—¥ï¼‰ |
| ä¸­å£å¾„月度数据覆盖 | âš ï¸ | ä¸Žæºæ–‡ä»¶æœˆä»½å¯¹é½æƒ…况未逐月核,导出无错但建议补数据后复看 |
## èƒ½è€—
| åŠŸèƒ½ | éªŒè¯çŠ¶æ€ | è¯æ® / å¤‡æ³¨ |
|---|---|---|
| H204 å­£æŠ¥å¯¼å…¥ | âœ… | 7/8/9 æœˆå„ 1284 æ¡ 0 å¤±è´¥ï¼ˆä½“检报告) |
| èƒ½è€—汇总导出 energySummary | âœ… | æ— åŽ»å¹´æ•°æ®çš„ #DIV/0! å·²æ¸…(今日) |
## æŠ•资
| åŠŸèƒ½ | éªŒè¯çŠ¶æ€ | è¯æ® / å¤‡æ³¨ |
|---|---|---|
| å®¢è¿ç«™åœº / ç‰©æµå›­åŒºå¯¼å…¥ | âœ… | 6/7 æœˆçœŸå®žæ–‡ä»¶ï¼ˆå®¢è¿ 46 + ç‰©æµ 133 / åŸºå‡† 148) |
| æŠ•资报表 investPlan/Billion/County/FiveYear | ðŸŸ¡ | HTTP 200、Excel å¯æ‰“开;HSSF è€æ ¼å¼ï¼ˆ.xls äºŒè¿›åˆ¶ï¼‰ï¼Œæœªåšé€æ ¼å…¬å¼æ‰«æ |
| æŠ•资系列 investSeries(zip) | âœ… | å†…层 0 é”™è¯¯æ ¼ |
## æ•°æ®è´¨é‡ / æ±¡æŸ“清理(2026-09-02)
| äº‹é¡¹ | éªŒè¯çŠ¶æ€ | è¯´æ˜Ž |
|---|---|---|
| æŠ¥è¡¨ #REF! / #DIV/0! æ±¡æŸ“ | âœ… å·²æ¸… | å…¬äº¤/出租/轨道轮渡/城市累计/能耗/中口径明细全部 0 æ®‹ç•™ |
| è´§è¿ 2026-07 ç©ºæ´žä¸Žè´Ÿå€¼ | âœ… å·²ä¿® | é»„石等 NULL è¡¥é½ï¼›æœˆå­£å·® -323.97 è´Ÿå€¼æ¶ˆé™¤ |
| H2032 2026-07 é‡å¤ï¼ˆ98 æˆ·/734 è¡Œï¼‰ | âœ… å·²æ¶ˆ | çް 636 æˆ· 0 é‡å¤ |
| ç©ºæ‰¹æ¬¡ #177-179 / #186 | â„¹ï¸ | 0 è¡Œæ— å®³ï¼Œä¿ç•™å®¡è®¡åŽ†å² |
## ç³»ç»Ÿ / å…¶ä»–
| åŠŸèƒ½ | éªŒè¯çŠ¶æ€ | è¯´æ˜Ž |
|---|---|---|
| å¯¼å…¥æŽ¥å£ + æ‰¹æ¬¡è½åº“ | âœ… | ä»Šæ—¥ä¸‰æ‰¹ï¼ˆ#187/#188 ç­‰ï¼‰å‡è½åº“可查 |
| å¯¼å…¥è¿›åº¦ UI æ˜¾ç¤ºï¼ˆ4.2 ä¸‡è¡Œå¤§æ–‡ä»¶ï¼‰ | ðŸŸ¡ | ç”¨æˆ·åé¦ˆâ€œæ— æ˜¾ç¤ºâ€ï¼Œæœ¬æ¬¡èµ°æŽ¥å£å¯¼å…¥æˆåŠŸï¼›é¡µé¢å¤çŽ°æŽ’æŸ¥å¾…åš |
| ç™»å½• / é¡µé¢ / å®¡æ ¸ï¼ˆAuditEngine) | ðŸŸ¡ | ä¸åœ¨æœ¬æ¬¡èŒƒå›´ï¼Œæœªå›žå½’ |
## å¾…办(建议下一步)
1. è¡¥é½åŸŽå¸‚客运(公交/出租月度、轨道/轮渡)缺月源文件并重新导入 â†’ æŠ¥è¡¨æœˆä»½åˆ—全。
2. /import é¡µé¢å¤§æ–‡ä»¶è¿›åº¦æ¡å¤çŽ°æŽ’æŸ¥ï¼ˆç”¨æˆ·å¯è§é—®é¢˜ï¼‰ã€‚
3. å¦‚需“投资四表 .xls è€æ ¼å¼â€é€æ ¼æ‰«æï¼Œéœ€è¦ xls è§£æž/转换工具(LibreOffice ç­‰ï¼‰ã€‚
4. æœ¬åœ°ä»£ç æ”¹åŠ¨æœªæäº¤ï¼ˆReportExportService/DataImportService/RegionUtil + 2 ä»½æŠ¥å‘Šæ–‡æ¡£ï¼‰ï¼Œç¡®è®¤åŽ commit。
docs/´ýÒµÎñÓû§È·ÈÏÇåµ¥_2026-09-02.md
New file
@@ -0,0 +1,51 @@
# å¾…业务用户确认清单(排版/口径,2026-09-02)
> ç”¨é€”:打印或对照,当面逐条确认。★=排版类(业务使用者可直接拍板);●=口径/数据类(需业务/统计规则确认);▲=功能范围。
> çŠ¶æ€åˆ—ç•™ç©ºå¾…å¡«ï¼šâ–¡å¾…ç¡®è®¤ / âœ”已确认 / âœ˜ä¸é‡‡çº³ / â—‹æ”¹æœŸ
## ä¸€ã€å…¬è·¯æ—…客(含个体客运)★重点
| # | ç±»åˆ« | çŽ°è±¡ï¼ˆçŽ°çŠ¶è¯æ®ï¼‰ | éœ€è¦ç¡®è®¤çš„问题 | å»ºè®®é»˜è®¤ |
|---|---|---|---|---|
| 1 | â˜…排版 | ä¸ªä½“客运 2026-07 å¯¼å…¥ 7 è¡Œï¼Œä½†åªè¦†ç›– 6 ä¸ªå¸‚州;孝感出现 2 è¡Œï¼ˆåˆè®¡çº¦ 21802/436433),其余市州各 1 è¡Œ | æ¨¡æ¿ç©¶ç«Ÿâ€œä¸€è¡Œä¸€å¸‚州”还是允许一市州多行?孝感两行是什么口径(城区/县拆分 or é‡å¤ï¼‰ï¼ŸæŠ¥è¡¨æ˜¯å¦è¦â€œå…¨çœåˆè®¡â€è¡Œï¼Ÿ | ä¸Žã€Šæ¨¡æ¿_湖北省公路旅客运输个体户月度生产情况(2026.7)》完全一致逐行展示;请确认孝感两行归属 |
| 2 | â˜…排版/●口径 | ä¸ªä½“客运只有“市州汇总表”数据,系统目前没有单独的“个体客运分市州报表”;公路旅客导出的分市州/中口径报表只含规上企业 | ä¸ªä½“客运是否要并入“公路旅客总量”报表(规上+个体合计)?若要,版式怎么排(规上块+个体块+合计行);若不要,个体客运数据仅供台账/审核? | å‡ºä¸€ä»½â€œå…¨çœæ€»é‡=规上+个体”的核对页或报表,先问业务是否本期需要 |
| 3 | â—å£å¾„ | ä½ æåˆ°â€œä¸ªä½“客运数据是根据城市客运数据计算得来的” | ç¡®è®¤æŽ¨å¯¼å£å¾„:个体客运量/周转量 = åŸŽå¸‚客运哪个指标(出租?总量-公交-轨道-轮渡?系数?),便于系统做勾稽校验(如投资那样导入后弹窗核对) | æä¾›è®¡ç®—式;系统加“个体 vs åŸŽå¸‚客运”一致性校验 |
| 4 | â—æ•°æ® | åº“内 H2031 å…¬è·¯æ—…客企业月报只有 2026-03(778)、2026-07(771) | 1/2/4/5/6/8 æœˆæ˜¯å¦å·²æœ‰ä¸ŠæŠ¥æ–‡ä»¶éœ€è¦è¡¥å¯¼ï¼Ÿ2025 åŸºæœŸæ˜¯å¦æä¾›ï¼ˆå†³å®šåŒæ¯”列)? | ç¼ºæœˆæ–‡ä»¶è¡¥é½åŽå†å‡ºå®Œæ•´ 1-N æœˆæŠ¥è¡¨ |
## äºŒã€åŸŽå¸‚客运(排版重点)
| # | ç±»åˆ« | çŽ°è±¡ | éœ€è¦ç¡®è®¤çš„问题 | å»ºè®®é»˜è®¤ |
|---|---|---|---|---|
| 5 | â˜…排版/●口径 | 8/11《城市客运数据优化》写明“网约车拆分=部级下发总量按巡游出租比例拆到各市州,Excel é‡Œæœ‰æ‹†åˆ†å…¬å¼â€ï¼›è€Œç³»ç»Ÿå¯¼å‡ºçš„各市州累计/明细表把网约车列清空 | æŠ¥è¡¨ç½‘约车列本期要不要按拆分公式填值?拆分所需的“部级总量/订单总数”由谁提供(手工表 or æŽ¥å£ï¼‰ï¼Ÿ | å…ˆç•™ç©ºå¹¶æ ‡æ³¨â€œæ— æ•°æ®æºâ€ï¼›è‹¥æœ¬æœŸè¦ï¼Œè¯·æä¾›æ‹†åˆ†è¡¨æ ·æœ¬ |
| 6 | â˜…排版 | å…¬äº¤/出租/轨道轮渡模板的“2025 å¹´ 1-12 æœˆâ€åˆ—与同比列因无去年基期数据 + æ¨¡æ¿å…¬å¼ #REF!,导出被清空 | æœ¬æœŸäº¤ä»˜æ˜¯å¦éœ€è¦åŽ»å¹´åˆ—ä¸ŽåŒæ¯”ï¼Ÿéœ€è¦â†’è¯·æä¾› 2025 åŒæœŸæ•°æ®æˆ–去年段源表;不需要→模板删除该列,版面更干净 | å…ˆæŒ‰â€œä¸éœ€è¦ã€ç•™ç©ºâ€äº¤ä»˜ï¼Œæ¨¡æ¿ç”±å¦ä¸€ä¼šè¯æŒ‰æ­¤è£å‰ª |
| 7 | â—æ•°æ® | åŸŽå¸‚公交/出租月度只有 2026-06、07;轨道/轮渡数据仅 6、7 æœˆ | 1-5 æœˆã€8 æœˆâ€¦æºæ–‡ä»¶å¯å¦è¡¥é½ï¼ˆå†³å®šæŠ¥è¡¨æœˆä»½åˆ—完整度)?若只交 7 æœˆï¼ŒæŠ¥è¡¨åªå±•示 6-7 æœˆåˆ—可接受? | è¡¥é½èƒ½æ‹¿åˆ°çš„æœˆä»½ï¼›å…¶ä½™åˆ—留空 |
| 8 | â˜…排版 | è½¨é“块模板只排了 å…¨çœ/武汉/黄石(黄石 6 æœˆ 34.86、7 æœˆ 30.09 æœ‰å€¼ï¼‰ï¼›è½®æ¸¡å—只排 å…¨çœ/武汉 | è‹¥æœ‰å…¶å®ƒå¸‚州轨道/轮渡数据,模板行是否要预留/自动扩展?当前版式是否符合上报格式? | ä¸Žå®˜æ–¹æ ·å¼ ä¸€è‡´å³å¯ï¼›è¯·å½“场核对样张 |
| 9 | â–²é—ç•™ | docs/城市客运 ä¸‹æœ‰ 8/14 ç©ºæ–‡ä»¶â€œå®¢è¿é‡çš„同比环比是0% éœ€æ ¸å®žï¼ˆä¸»è¦å‡ºçŽ°åœ¨å…¬äº¤ï¼‰.txt” | è¯¥æ ¸å®žé¡¹æ˜¯å¦å·²å…³é—­ï¼Ÿå…¬äº¤åŒæ¯”/环比 0% æ˜¯å¦ä»å­˜åœ¨ï¼ˆä¸Žç¬¬ 6 æ¡åŽ»å¹´æ•°æ®ç¼ºå¤±åŒæºï¼‰ï¼Ÿ | å·²å…³é—­åˆ™åˆ å ä½æ–‡ä»¶ï¼›æœªå…³é—­åˆ™åˆ—入审核规则验证 |
## ä¸‰ã€è´§è¿ï¼ˆæŽ’版重点)
| # | ç±»åˆ« | çŽ°è±¡ | éœ€è¦ç¡®è®¤çš„问题 | å»ºè®®é»˜è®¤ |
|---|---|---|---|---|
| 10 | â˜…排版/●口径 | `生成_货运量排名/周转量排名` åˆ†ä¸¤é¡µï¼šç¬¬ä¸€é¡µâ€œ1-7月累计…”;第二页标题已去“累计” | âœ” å·²ç¡®è®¤ï¼šç¬¬äºŒé¡µå¡«å½“月值;9/2 16:40 å·²å®žçŽ°å¹¶å›žå½’ï¼ˆç¬¬äºŒé¡µå½“æœˆæ•°ä¸Žåº“ä¸€è‡´ï¼Œåˆ—å¤´å¯¼å‡ºæ—¶è‡ªåŠ¨æ”¹â€œå½“æœˆå®Œæˆâ€ï¼‰ã€‚æ¨¡æ¿æºæ–‡ä»¶å¦‚éœ€ä¸€å¹¶è½ç›˜å¯åœ¨ Excel å¦å­˜ | å®Œæˆ |
| 11 | â˜…排版 | `货运量分市州明细`:全省 6 æŒ‡æ ‡ï¼ˆæ€»é‡/周转量/规上/规下…)+ 17 å¸‚州×6 æŒ‡æ ‡ï¼Œ1-N æœˆ+累计 | æŒ‡æ ‡é¡ºåºã€å•位(万吨/万吨公里)、行间距是否符合上报格式? | å¯¹ç…§å®˜æ–¹æ ·å¼ ç¡®è®¤ |
| 12 | â˜…排版 | ä¸­å£å¾„明细/排名/分析模板正被另一会话修改(含 Sheet2 åŽ»å¹´æ˜Žç»†é¡µ #REF! è¢«æ¸…空) | ä¸­å£å¾„报表里的“去年同期页”本期是否需要保留/填充?去年数据来源? | å…ˆç”±æ¨¡æ¿ä¼šè¯æŒ‰â€œä¸éœ€è¦â€å¤„理,交付前再目检 |
## å››ã€èƒ½è€— / æŠ•资
| # | ç±»åˆ« | çŽ°è±¡ | éœ€è¦ç¡®è®¤çš„问题 | å»ºè®®é»˜è®¤ |
|---|---|---|---|---|
| 13 | â˜…排版 | èƒ½è€—汇总表无去年数据的同比/占比公式求值失败后被清空(如 D4/J4/L4/M4) | ç•™ç©ºæ˜¯å¦å¯æŽ¥å—?还是要显示“—”或“暂无数据”占位? | ç•™ç©ºï¼ˆä¸Žç¼ºåŽ»å¹´åˆ—çš„å…¶å®ƒæŠ¥è¡¨ä¸€è‡´ï¼‰ |
| 14 | â˜…排版/▲ | æŠ•资四张报表导出为老格式 .xls(Excel å¯æ‰“开),未做逐格错误扫描 | æ˜¯å¦æœ¬æœŸå¿…须交付 .xlsx?排版是否保持模板原样即可? | ä¿æŒçŽ°çŠ¶ï¼Œæ¨¡æ¿ä¼šè¯è‹¥ä¸€å¹¶å¤„ç†åˆ™ä»¥å®ƒçš„ç‰ˆæœ¬ä¸ºå‡† |
## äº”、功能范围 / ä½“验
| # | ç±»åˆ« | çŽ°è±¡ | éœ€è¦ç¡®è®¤çš„问题 | å»ºè®®é»˜è®¤ |
|---|---|---|---|---|
| 15 | â–² | å¯¼å…¥é¡µâ€œå¹´æŠ¥â€åˆ†ç»„有 11 ä¸ªç±»åž‹å…¥å£ï¼ŒåŽç«¯æ— å®žçް | å¹´æŠ¥å¯¼å…¥ä»Šå¹´æ˜¯å¦è¦åšï¼Ÿ | ä¸åšå°±éšè—/禁用入口,避免误点报错 |
| 16 | â–²ä½“验 | 4.2 ä¸‡è¡Œå¤§æ–‡ä»¶å¯¼å…¥ 20-40 ç§’,页面只有“上传中”无百分比;侧栏“本月导入进度”可能被空批次显示成“无数据” | æœŸæœ›å¯¼å…¥ä¸­æ˜¾ç¤ºâ€œå·²å¤„理 N/M è¡Œâ€å®žæ—¶è¿›åº¦ï¼Œè¿˜æ˜¯å®ŒæˆåŽå¼¹çª—汇总即可? | å®ŒæˆåŽå¼¹çª—+侧栏状态(当前);如需实时进度再排期 |
## å¤‡æ³¨
- æœ¬æ¬¡åªåšâ€œé—®é¢˜ç¡®è®¤â€ï¼Œä»£ç ä¿®å¤ï¼ˆæ•°å€¼é™é»˜ 0/失败行号/批次回填/审核误删等)已按你要求冻结,等另一会话模板改完后再做。
- æ¨¡æ¿æ–‡ä»¶æ­£è¢«å¦ä¸€ä¼šè¯ä¿®æ”¹ï¼Œä»¥ä¸Š â˜…排版 é¡¹ä¸­æ¶‰åŠæ¨¡æ¿æ ·å¼çš„(6/8/10/12/14)建议以“另一会话定稿后的版本”再当面核对一次,避免重复改两遍。
docs/ÄܺÄ/Éú³É_ÄÜÔË»ã×ܱí.xlsx
Binary files differ
docs/ÄܺÄ/Äܺļò»¯£¨2026Ä꣩.xlsx
Binary files differ
docs/»õÔË/Ä£°å_¹æÉϹæÏ²ð·ÖÔËÊäÁ¿.xlsx
Binary files differ
docs/»õÔË/Ä£°å_»õÔËÁ¿ÖÜתÁ¿.xlsx
Binary files differ
docs/»õÔË/Ä£°å_¹ì¼£Àï³Ì.xlsx
Binary files differ
docs/»õÔË/Éú³É_ÖÜתÁ¿ÅÅÃû.xlsx
Binary files differ
docs/»õÔË/Éú³É_»õÔËÁ¿ÅÅÃû.xlsx
Binary files differ
docs/»õÔË/»õÔ˼ò»¯¹¤×÷.xlsx
Binary files differ
traffic-audit-server/src/main/java/com/trafficaudit/auditengine/service/AuditEngineService.java
@@ -631,6 +631,8 @@
                    .eq(InvestmentSystem::getReportPeriod, reportPeriod))) {
            sysMap.computeIfAbsent(normInvestName(s.getProjectName()), k -> new ArrayList<>()).add(s);
        }
        // åŒæŠ¥è¡¨æœŸæŠ•资系统基准整期缺失时,不做"项目缺失核实"(缺失=基准未导入,不等于项目不存在),避免整表误报
        boolean benchmarkMissing = sysMap.isEmpty();
        // å¹‚等:只清除 INVEST è§„则的旧审核结果
        List<Long> ruleIds = new ArrayList<>();
@@ -647,6 +649,7 @@
            String projectName = project == null ? "未知项目" : project.getProjectName();
            InvestmentSystem sys = findInvestSystem(sysMap, projectName);
            for (AuditRule rule : rules) {
                if (benchmarkMissing && "EXISTENCE_SYS".equals(rule.getCompareType())) continue;
                AuditResult result = checkInvestRule(rule, monthly, projectName, sys);
                if (result != null) {
                    result.setRuleName(rule.getRuleName());
@@ -1538,6 +1541,7 @@
            case "RULE_I001":
            case "RULE_I002":
            case "RULE_I003":
            case "RULE_I004":
                return investSystemMapper.selectCount(new LambdaQueryWrapper<InvestmentSystem>()
                    .eq(InvestmentSystem::getReportPeriod, period)) == 0;
            default:
@@ -2021,4 +2025,4 @@
        result.setStatus("PENDING");
        return result;
    }
}
}
traffic-audit-server/src/main/java/com/trafficaudit/common/util/RegionUtil.java
@@ -42,6 +42,18 @@
        CODE_PREFIX_MAP.put("429006", "天门市");
        CODE_PREFIX_MAP.put("429021", "神农架林区");
        ALIAS_MAP.put("武汉", "武汉市");
        ALIAS_MAP.put("黄石", "黄石市");
        ALIAS_MAP.put("十堰", "十堰市");
        ALIAS_MAP.put("宜昌", "宜昌市");
        ALIAS_MAP.put("襄阳", "襄阳市");
        ALIAS_MAP.put("鄂州", "鄂州市");
        ALIAS_MAP.put("荆门", "荆门市");
        ALIAS_MAP.put("孝感", "孝感市");
        ALIAS_MAP.put("荆州", "荆州市");
        ALIAS_MAP.put("黄冈", "黄冈市");
        ALIAS_MAP.put("咸宁", "咸宁市");
        ALIAS_MAP.put("随州", "随州市");
        ALIAS_MAP.put("恩施", "恩施州");
        ALIAS_MAP.put("恩施市", "恩施州");
        ALIAS_MAP.put("恩施土家族苗族自治州", "恩施州");
@@ -103,6 +115,20 @@
        return CITY_LIST;
    }
    /** è§„范市州名 -> 6 ä½è¡Œæ”¿åŒºåˆ’代码(无匹配或湖北省返回 null) */
    public static String codeOfCity(String normalizedName) {
        if (normalizedName == null) return null;
        String name = normalizeCityName(normalizedName);
        if (name == null || "湖北省".equals(name)) return null;
        for (Map.Entry<String, String> e : CODE_PREFIX_MAP.entrySet()) {
            if (e.getValue().equals(name)) {
                String code = e.getKey();
                return code.length() < 6 ? code + "00" : code;
            }
        }
        return null;
    }
    /** ç”Ÿæˆç©ºå¸‚州统计Map */
    public static Map<String, BigDecimalStat> emptyStatMap() {
        Map<String, BigDecimalStat> map = new LinkedHashMap<>();
traffic-audit-server/src/main/java/com/trafficaudit/dataimport/service/DataImportService.java
@@ -407,41 +407,20 @@
    /** å…¬è·¯æ—…客个体客运量/周转量(企业线下汇报数据,按所属地区导入,供分市州表个体行填充) */
    /** å…¬è·¯æ—…客个体客运量/周转量(导入后按市州汇总填充分市州表个体行),支持两种模板:
     *  â‘  ä¼ä¸šçº¿ä¸‹æ±‡æŠ¥æ˜Žç»†ï¼ˆè¡¨å¤´å«ã€Œä¼ä¸šåç§°ã€ï¼‰ï¼šé€ä¼ä¸šå…¥åº“ï¼›
     *  â‘¡ çœåŽ…å¸‚å·žæ±‡æ€»è¡¨ã€Šæ¹–åŒ—çœå…¬è·¯æ—…å®¢è¿è¾“ä¸ªä½“æˆ·æœˆåº¦ç”Ÿäº§æƒ…å†µï¼ˆYYYY.M)》:
     *     sheet å†…为「全省N月个体客运量汇总表」标题块 + ã€Œå¸‚å·ž/个体车辆数/…/个体客运量/个体旅客周转量」表头,
     *     æŒ‰å¸‚州逐行入库(同一市州多行如 åŽ¿å†…ç­çº¿+跨县班线 å‡å…¥åº“,报表侧按市州自动汇总)。 */
    public ImportResult importPassengerIndividual(MultipartFile file, String period) throws Exception {
        List<PassengerIndividualMonthly> rows = new ArrayList<>();
        try (Workbook wb = WorkbookFactory.create(file.getInputStream())) {
            Sheet sheet = wb.getSheetAt(0);
            Map<String, Integer> colMap = buildHeaderMap(sheet.getRow(0));
            Integer codeCol = colMap.get("所属地区");
            Integer entCol = colMap.get("企业代码");
            Integer nameCol = colMap.get("企业名称");
            Integer passCol = null;
            Integer turnCol = null;
            for (Map.Entry<String, Integer> e : colMap.entrySet()) {
                String k = e.getKey();
                if (k != null && k.contains("个体") && k.contains("客运量")) passCol = e.getValue();
                if (k != null && k.contains("个体") && (k.contains("周转量") || k.contains("周转"))) turnCol = e.getValue();
            }
            if (passCol == null && turnCol == null) {
                throw new RuntimeException("未找到「个体客运量/个体旅客周转量」列,请检查模板(列名需包含“个体客运量”“个体周转量”)");
            }
            for (int r = 1; r <= sheet.getLastRowNum(); r++) {
                Row row = sheet.getRow(r);
                if (row == null) continue;
                String name = nameCol != null ? getString(row, nameCol) : null;
                if (name == null || name.trim().isEmpty()) continue;
                Double pass = passCol != null ? getDecimalOrNull(row, passCol) : null;
                Double turn = turnCol != null ? getDecimalOrNull(row, turnCol) : null;
                if ((pass == null || pass == 0.0) && (turn == null || turn == 0.0)) continue;
                PassengerIndividualMonthly entity = new PassengerIndividualMonthly();
                entity.setReportPeriod(period);
                entity.setRegionCode(codeCol != null ? getString(row, codeCol) : null);
                entity.setEnterpriseCode(entCol != null ? getString(row, entCol) : null);
                entity.setEnterpriseName(name.trim());
                entity.setPassengerCount(pass);
                entity.setTurnover(turn);
                rows.add(entity);
            if (colMap.containsKey("企业名称")) {
                parsePassengerIndividualEnterprise(sheet, colMap, period, rows);
            } else {
                parsePassengerIndividualCitySheet(sheet, period, rows);
            }
        } catch (Exception e) {
            log.error("Passenger individual parse error", e);
@@ -474,6 +453,101 @@
        recordBatch(file.getOriginalFilename(), "PASSENGER_INDIVIDUAL", period, rows.size(), success, failDetails.size(), errorDetail);
        log.info("Passenger individual imported: {} rows for {}", success, period);
        return new ImportResult(success, failDetails.size(), failDetails);
    }
    /** æ—§ç‰ˆä¸ªä½“客运量模板(企业线下汇报明细:所属地区/企业代码/企业名称/…个体客运量/…个体旅客周转量) */
    private void parsePassengerIndividualEnterprise(Sheet sheet, Map<String, Integer> colMap, String period,
                                                    List<PassengerIndividualMonthly> rows) {
        Integer codeCol = colMap.get("所属地区");
        Integer entCol = colMap.get("企业代码");
        Integer nameCol = colMap.get("企业名称");
        Integer passCol = null;
        Integer turnCol = null;
        for (Map.Entry<String, Integer> e : colMap.entrySet()) {
            String k = e.getKey();
            if (k != null && k.contains("个体") && k.contains("客运量")) passCol = e.getValue();
            if (k != null && k.contains("个体") && (k.contains("周转量") || k.contains("周转"))) turnCol = e.getValue();
        }
        if (passCol == null && turnCol == null) {
            throw new RuntimeException("未找到「个体客运量/个体旅客周转量」列,请检查模板(列名需包含“个体客运量”“个体周转量”)");
        }
        for (int r = 1; r <= sheet.getLastRowNum(); r++) {
            Row row = sheet.getRow(r);
            if (row == null) continue;
            String name = nameCol != null ? getString(row, nameCol) : null;
            if (name == null || name.trim().isEmpty()) continue;
            Double pass = passCol != null ? getDecimalOrNull(row, passCol) : null;
            Double turn = turnCol != null ? getDecimalOrNull(row, turnCol) : null;
            if ((pass == null || pass == 0.0) && (turn == null || turn == 0.0)) continue;
            PassengerIndividualMonthly entity = new PassengerIndividualMonthly();
            entity.setReportPeriod(period);
            entity.setRegionCode(codeCol != null ? getString(row, codeCol) : null);
            entity.setEnterpriseCode(entCol != null ? getString(row, entCol) : null);
            entity.setEnterpriseName(name.trim());
            entity.setPassengerCount(pass);
            entity.setTurnover(turn);
            rows.add(entity);
        }
    }
    /** æ–°ç‰ˆå¸‚州汇总模板:《全省N月个体客运量汇总表》标题行 â†’ è¡¨å¤´è¡Œï¼ˆå¸‚å·ž/…/个体客运量/个体旅客周转量)→ å¸‚州数据行 */
    private void parsePassengerIndividualCitySheet(Sheet sheet, String period, List<PassengerIndividualMonthly> rows) {
        int targetMonth;
        try {
            targetMonth = Integer.parseInt(period.split("-")[1]);
        } catch (Exception e) {
            throw new RuntimeException("报表期格式应为 yyyy-MM:" + period);
        }
        int titleRow = -1;
        for (int r = 0; r <= sheet.getLastRowNum(); r++) {
            Row row = sheet.getRow(r);
            if (row == null) continue;
            String t = getString(row, 0);
            if (t == null || !t.contains("全省") || !t.contains("月")) continue;
            java.util.regex.Matcher m = java.util.regex.Pattern.compile("全省(\\d+)月").matcher(t);
            if (!m.find()) continue;
            if (Integer.parseInt(m.group(1)) == targetMonth) { titleRow = r; break; }
            if (titleRow < 0) titleRow = r; // æ ‡é¢˜ä¸å«ç›®æ ‡æœˆä»½æ—¶æš‚记第一个标题块兜底
        }
        if (titleRow < 0) {
            throw new RuntimeException("未找到「全省N月个体客运量汇总表」标题块,请使用《模板_湖北省公路旅客运输个体户月度生产情况(YYYY.M)》整理后导入");
        }
        Row header = sheet.getRow(titleRow + 1);
        if (header == null) {
            throw new RuntimeException("「全省" + targetMonth + "月…汇总表」标题后缺少表头行(市州/个体客运量/个体旅客周转量)");
        }
        int cityCol = -1, passCol = -1, turnCol = -1;
        for (Cell c : header) {
            String h = FORMATTER.formatCellValue(c).trim();
            if (h.isEmpty()) continue;
            if (h.contains("市州")) cityCol = c.getColumnIndex();
            else if (h.contains("个体") && h.contains("客运量")) passCol = c.getColumnIndex();
            else if (h.contains("个体") && (h.contains("周转量") || h.contains("周转"))) turnCol = c.getColumnIndex();
        }
        if (cityCol < 0 || (passCol < 0 && turnCol < 0)) {
            throw new RuntimeException("未找到「市州 / ä¸ªä½“客运量 / ä¸ªä½“旅客周转量」列,请使用系统模板整理后导入");
        }
        int lastRow = Math.min(sheet.getLastRowNum(), titleRow + 40);
        for (int r = titleRow + 2; r <= lastRow; r++) {
            Row row = sheet.getRow(r);
            if (row == null) continue;
            String first = getString(row, cityCol);
            if (first == null) break;
            String t = first.trim();
            if (t.isEmpty() || t.contains("合计") || t.contains("环比") || t.contains("全省")) break;
            String city = RegionUtil.normalizeCityName(t);
            if (!RegionUtil.cityList().contains(city)) continue;
            Double pass = passCol >= 0 ? getDecimalOrNull(row, passCol) : null;
            Double turn = turnCol >= 0 ? getDecimalOrNull(row, turnCol) : null;
            if ((pass == null || pass == 0.0) && (turn == null || turn == 0.0)) continue;
            PassengerIndividualMonthly entity = new PassengerIndividualMonthly();
            entity.setReportPeriod(period);
            entity.setRegionCode(RegionUtil.codeOfCity(city));
            entity.setEnterpriseName(city);
            entity.setPassengerCount(pass);
            entity.setTurnover(turn);
            rows.add(entity);
        }
    }
    /** å…¬è·¯æ—…客运政车辆数(独立模板:企业代码/企业名称/车辆数/载客位数) */
@@ -531,6 +605,10 @@
    /** èƒ½è€—明细每组固定18列,车牌号起始列(0-based):3,21,39,57,75 */
    private static final int[] ENERGY_GROUP_COLS = {3, 21, 39, 57, 75};
    /** èƒ½è€—明细模板表头关键列(0-based):程序按固定列位解析,解析前校验表头,错位直接拒绝 */
    private static final int[] ENERGY_HEADER_COLS = {3, 4, 5, 21, 39, 57, 75};
    private static final String[] ENERGY_HEADER_KEYWORDS = {"车牌号", "车辆类型", "燃料类型", "车牌号", "车牌号", "车牌号", "车牌号"};
    /** èƒ½è€—导入按报表期互斥锁(H204 æ˜Žç»†ä¸Žè¿æ”¿ä¿¡æ¯å…±ç”¨ï¼Œé¿å…åŒæŠ¥è¡¨æœŸå¹¶å‘重导互相覆盖) */
    private Object energyLock(String period) {
        return energyImportLocks.computeIfAbsent(period == null ? "" : period, k -> new Object());
@@ -543,6 +621,7 @@
            // sheet0: ç¬¬äºŒå­£åº¦è´§è½¦èƒ½è€—明细(每行左右各5组车辆,每组固定18列)
            Sheet sheet = wb.getSheetAt(0);
            requireHeaderKeyword(sheet, "道路货运车辆能源消耗情况", "企业名称", "车牌号");
            requireEnergyHeaderLayout(sheet);
            for (int r = 1; r <= sheet.getLastRowNum(); r++) {
                Row row = sheet.getRow(r);
                if (row == null) continue;
@@ -665,6 +744,12 @@
        try (Workbook wb = WorkbookFactory.create(file.getInputStream())) {
            Sheet sheet = wb.getSheetAt(0);
            requireHeaderKeyword(sheet, "能耗车辆运政信息", "车牌号");
            Row authHeader = sheet.getRow(0);
            String authH0 = authHeader == null ? null : FORMATTER.formatCellValue(authHeader.getCell(0)).trim();
            if (authH0 == null || authH0.isEmpty() || !authH0.contains("车牌号")) {
                throw new RuntimeException("能耗车辆运政信息表头与系统模板不一致:第 1 åˆ—应为「车牌号」,实际为「"
                    + (authH0 == null || authH0.isEmpty() ? "空" : authH0) + "」。请使用系统模板《模板_能耗车辆运政信息.xlsx》整理后再导入");
            }
            for (int r = 1; r <= sheet.getLastRowNum(); r++) {
                Row row = sheet.getRow(r);
                if (row == null) continue;
@@ -730,25 +815,27 @@
    // ========== è¿æ”¿è½¦è¾† ==========
    /** è¿æ”¿è½¦è¾†å¯¼å…¥ï¼šä¸Ž H203-2 æœˆæŠ¥ä¸€è‡´ï¼ŒæŒ‰è¡¨å¤´åç§°å®šä½åˆ—,列顺序变化也能正确导入 */
    public int importTransportAuth(MultipartFile file, String period) throws Exception {
        List<TransportAuthVehicle> list = new ArrayList<>();
        int failRows = 0;
        try (Workbook wb = WorkbookFactory.create(file.getInputStream())) {
            Sheet sheet = wb.getSheetAt(0);
            requireHeaderKeyword(sheet, "运政车辆", "企业名称");
            requireHeaderCols(sheet, "运政车辆", "企业名称", "总牵引车数", "总挂车数", "其它车辆数", "挂车总吨位(吨)", "其它车辆总吨位(吨)");
            Map<String, Integer> colMap = buildHeaderMap(sheet.getRow(0));
            for (int r = 1; r <= sheet.getLastRowNum(); r++) {
                Row row = sheet.getRow(r);
                if (row == null) continue;
                String name = getString(row, 0);
                String name = gs(row, colMap, "企业名称");
                if (name == null || name.trim().isEmpty()) continue;
                TransportAuthVehicle entity = new TransportAuthVehicle();
                entity.setReportPeriod(period);
                entity.setEnterpriseName(name);
                entity.setTractorCount(getInt(row, 1));
                entity.setTrailerCount(getInt(row, 2));
                entity.setOtherCount(getInt(row, 3));
                entity.setTrailerTons(getDecimal(row, 4));
                entity.setOtherTons(getDecimal(row, 5));
                entity.setTractorCount(gi(row, colMap, "总牵引车数"));
                entity.setTrailerCount(gi(row, colMap, "总挂车数"));
                entity.setOtherCount(gi(row, colMap, "其它车辆数"));
                entity.setTrailerTons(gd(row, colMap, "挂车总吨位(吨)"));
                entity.setOtherTons(gd(row, colMap, "其它车辆总吨位(吨)"));
                list.add(entity);
            }
        } catch (Exception e) {
@@ -778,21 +865,23 @@
    // ========== è½¨è¿¹é‡Œç¨‹ ==========
    /** è½¨è¿¹é‡Œç¨‹å¯¼å…¥ï¼šä¸Ž H203-2 æœˆæŠ¥ä¸€è‡´ï¼ŒæŒ‰è¡¨å¤´åç§°å®šä½åˆ—,列顺序变化也能正确导入 */
    public int importTrackMileage(MultipartFile file, String period) throws Exception {
        List<VehicleTrackMileage> list = new ArrayList<>();
        int failRows = 0;
        try (Workbook wb = WorkbookFactory.create(file.getInputStream())) {
            Sheet sheet = wb.getSheetAt(0);
            requireHeaderKeyword(sheet, "轨迹里程", "企业名称");
            requireHeaderCols(sheet, "轨迹里程", "企业名称", "月度总里程(公里)", "有里程的车辆数");
            Map<String, Integer> colMap = buildHeaderMap(sheet.getRow(0));
            for (int r = 1; r <= sheet.getLastRowNum(); r++) {
                Row row = sheet.getRow(r);
                if (row == null) continue;
                String name = getString(row, 1);
                String name = gs(row, colMap, "企业名称");
                if (name == null || name.trim().isEmpty()) continue;
                VehicleTrackMileage entity = new VehicleTrackMileage();
                entity.setEnterpriseName(name);
                entity.setMonthlyMileage(getDecimal(row, 2));
                entity.setTrackedVehicles(getInt(row, 3));
                entity.setMonthlyMileage(gd(row, colMap, "月度总里程(公里)"));
                entity.setTrackedVehicles(gi(row, colMap, "有里程的车辆数"));
                entity.setReportPeriod(period);
                list.add(entity);
            }
@@ -842,6 +931,20 @@
                if (sheetName.contains("当月")) periodType = "MONTH";
                else if (sheetName.contains("累计")) periodType = "CUMULATIVE";
                if (periodType == null) continue;
                // æ ¡éªŒ sheet å¸ƒå±€ï¼šç¬¬2行应含「市州/规上企业运输量」,第3行子表头应含「周转量」或「货运量」(扩展布局)
                Row headRow = sheet.getRow(1);
                Row subHeadRow = sheet.getRow(2);
                boolean layoutOk = headRow != null
                    && getString(headRow, 0) != null && getString(headRow, 0).contains("市州")
                    && getString(headRow, 1) != null && getString(headRow, 1).contains("规上")
                    && subHeadRow != null
                    && ("货运量".equals(getString(subHeadRow, 0))
                        || (getString(subHeadRow, 1) != null && getString(subHeadRow, 1).contains("周转量")));
                if (!layoutOk) {
                    throw new RuntimeException("所选数据类型【规上规下拆分】与文件内容不符:sheet「" + sheetName
                        + "」未找到「市州/规上企业运输量/周转量」表头,请确认是否选错了数据类型");
                }
                // æ£€æµ‹å­è¡¨å¤´ï¼šæ˜¯å¦åŒ…含货运量列(扩展布局)
                Row subHeader = sheet.getRow(2);
@@ -925,6 +1028,12 @@
        int monthCount = Integer.parseInt(period.split("-")[1]);
        try (Workbook wb = WorkbookFactory.create(file.getInputStream())) {
            Sheet sheet = wb.getSheetAt(0);
            Row header = sheet.getRow(0);
            String h0 = header == null ? null : getString(header, 0);
            String h1 = header == null ? null : getString(header, 1);
            if (header == null || h0 == null || !h0.contains("货运量") || h1 == null || !h1.contains("月")) {
                throw new RuntimeException("所选数据类型【货运量周转量】与文件内容不符:表头应为「货运量(万吨)/1月…12月」布局,请确认是否选错了数据类型");
            }
            boolean cityRowFound = false;
            for (int r = 1; r <= Math.min(sheet.getLastRowNum(), 30); r++) {
                Row rr = sheet.getRow(r);
@@ -1218,6 +1327,43 @@
            }
        }
        throw new RuntimeException("所选数据类型【" + typeLabel + "】与文件内容不符:表头未包含【" + String.join("】【", keywords) + "】等列,请确认是否选错了数据类型");
    }
    /** èƒ½è€—明细表头列位校验:系统模板为“前3列 + 5组×18列”,程序按固定列位解析,表头错位会导致整表错乱,错位时直接拒绝 */
    private void requireEnergyHeaderLayout(Sheet sheet) {
        Row header = sheet == null ? null : sheet.getRow(0);
        if (header == null) {
            throw new RuntimeException("能耗明细表头缺失,请使用系统模板《模板_道路货运车辆能源消耗情况(2026).xlsx》整理后再导入");
        }
        for (int i = 0; i < ENERGY_HEADER_COLS.length; i++) {
            int col = ENERGY_HEADER_COLS[i];
            String keyword = ENERGY_HEADER_KEYWORDS[i];
            Cell cell = header.getCell(col);
            String hv = cell == null ? null : FORMATTER.formatCellValue(cell).trim();
            if (hv == null || hv.isEmpty() || !hv.contains(keyword)) {
                throw new RuntimeException("表头与系统模板不一致:第 " + (col + 1) + " åˆ—应为「" + keyword + "」,实际为「"
                    + (hv == null || hv.isEmpty() ? "空" : hv) + "」。请使用系统模板《模板_道路货运车辆能源消耗情况(2026).xlsx》整理后再导入");
            }
        }
    }
    /** é€šç”¨è¡¨å¤´åˆ—位校验:程序按固定列位解析,表头错位会导致整表错乱,错位时直接拒绝导入 */
    private void requireHeaderLayout(Sheet sheet, String typeLabel, String templateHint,
                                     int[] cols, String[] keywords) {
        Row header = sheet == null ? null : sheet.getRow(0);
        if (header == null) {
            throw new RuntimeException("所选数据类型【" + typeLabel + "】文件表头缺失,请使用系统模板《" + templateHint + "》整理后再导入");
        }
        for (int i = 0; i < cols.length; i++) {
            int col = cols[i];
            String keyword = keywords[i];
            Cell cell = header.getCell(col);
            String hv = cell == null ? null : FORMATTER.formatCellValue(cell).trim();
            if (hv == null || hv.isEmpty() || !hv.contains(keyword)) {
                throw new RuntimeException("表头与系统模板不一致:第 " + (col + 1) + " åˆ—应为「" + keyword + "」,实际为「"
                    + (hv == null || hv.isEmpty() ? "空" : hv) + "」。所选数据类型【" + typeLabel + "】请使用系统模板《" + templateHint + "》整理后再导入");
            }
        }
    }
    /** æŒ‰è¡¨å¤´åç§°å»ºç«‹åˆ—号映射,兼容新旧模板列位差异 */
@@ -1792,8 +1938,10 @@
        if (name == null || name.isEmpty()) return false;
        String norm = name.replace(" ", "");
        int month = Integer.parseInt(period.substring(5, 7));
        String normDash = norm.replace('.', '-'); // "2026.8"/"2026.08" -> "2026-8"/"2026-08"
        return norm.contains(month + "月") || norm.contains(String.format("%02d", month) + "月")
            || name.contains(period) || name.contains(period.replace("-0", "-"));
            || name.contains(period) || name.contains(period.replace("-0", "-"))
            || normDash.contains(period) || normDash.contains(period.replace("-0", "-"));
    }
    /** è§£æžå•个市州报表:选 sheet(报表期名优先 + æ•°æ®è¡Œæ•°ï¼‰ï¼ŒæŒ‰åˆ—名映射提取项目行 */
@@ -1808,6 +1956,11 @@
            if (col == null) continue;
            int cnt = countInvestRows(sh, col);
            int score = cnt + (cnt > 0 && investSheetMatchesPeriod(sh, period) ? 1000000 : 0);
            if (cnt > 0 && investSheetMatchesPeriod(sh, period)) {
                // å½“期真实报表 sheet åé€šå¸¸å¸¦å¹´ä»½ï¼ˆå¦‚ 2026.8/2026å¹´8月),历史sheet多为纯月份名(8月):带年份的优先
                String norm = sh.getSheetName() == null ? "" : sh.getSheetName().replace(" ", "");
                if (norm.contains(period.substring(0, 4))) score += 100000;
            }
            if (score > bestScore) {
                best = sh;
                bestCol = col;
@@ -1852,10 +2005,12 @@
                if (seq == null || seq.trim().isEmpty()) {
                    // å¸‚州小节行(如 "武汉" "天 é—¨"),更新当前市州
                    String c = investmentCity(nt);
                    if (c != null) currentCity = c;
                    if (c != null) { currentCity = c; continue; }
                    // åºå·ä¸ºç©ºçš„真实项目行(部分市州月报不填序号,如神农架物流园)也按项目处理
                    if (!isLikelyInvestProjectName(nt)) continue;
                } else if (!seq.trim().matches("\\d+(\\.\\d+)?")) {
                    continue;
                }
                if (!seq.trim().matches("\\d+(\\.\\d+)?")) continue;
            } else {
                // æ— åºå·åˆ—(随州等):项目名非空即项目行,市州小节行用 investmentCity è¯†åˆ«
                String c = investmentCity(nt);
@@ -1980,7 +2135,11 @@
                if (nt.length() > 4) count++;
            } else {
                String seq = cellStr(row, seqCol);
                if (seq != null && seq.trim().matches("\\d+(\\.\\d+)?")) count++;
                if (seq != null && seq.trim().matches("\\d+(\\.\\d+)?")) {
                    count++;
                } else if ((seq == null || seq.trim().isEmpty()) && isLikelyInvestProjectName(nt)) {
                    count++;
                }
            }
        }
        return count;
@@ -2050,6 +2209,15 @@
            log.error("load five year project names error", e);
        }
        return names;
    }
    /** åºå·ä¸ºç©ºçš„非市州行是否像项目行:长度>4 ä¸”非备注/说明等杂项 */
    private boolean isLikelyInvestProjectName(String nt) {
        if (nt == null || nt.length() <= 4) return false;
        if (investmentCity(nt) != null) return false;
        return !nt.startsWith("备注") && !nt.startsWith("说明") && !nt.startsWith("注:")
            && !nt.startsWith("填表") && !nt.startsWith("审核") && !nt.startsWith("统计")
            && !nt.startsWith("负责");
    }
    /** é¡¹ç›®åè§„范化:去空白/换行/括号内容/标点/「项目」后缀,用于十五五清单匹配 */
@@ -2228,12 +2396,18 @@
        }
    }
    /** æŠ•资系统导出导入(审核比对基准),固定8列:行号/单位/时期/计划总投资/自开始累计/本年计划/自年初累计/当月完成 */
    private static final int[] INVEST_SYSTEM_HEADER_COLS = {0, 1, 2, 3, 4, 5, 6, 7};
    private static final String[] INVEST_SYSTEM_HEADER_KEYWORDS =
        {"行号", "单位", "时期", "计划总投资", "自开始建设", "本年计划投资", "自年初", "当月完成投资"};
    public int importInvestmentSystem(MultipartFile file, String period) throws Exception {
        List<InvestmentSystem> list = new ArrayList<>();
        int failRows = 0;
        try (Workbook wb = WorkbookFactory.create(file.getInputStream())) {
            Sheet sheet = wb.getSheetAt(0);
            requireHeaderKeyword(sheet, "投资系统导出", "项目名称", "计划总投资", "单位");
            requireHeaderLayout(sheet, "投资系统导出", "模板_查询结果(投资系统-客运+物流 2026.7).xls",
                INVEST_SYSTEM_HEADER_COLS, INVEST_SYSTEM_HEADER_KEYWORDS);
            for (int r = 1; r <= sheet.getLastRowNum(); r++) {
                Row row = sheet.getRow(r);
                if (row == null) continue;
@@ -2271,15 +2445,18 @@
    }
    /** åŸŽå¸‚公交月报导入(城市公共交通月度运营情况,企业级明细,取公共汽电车字段) */
    /** åŸŽå¸‚公交(U203)模板关键列位(0-based):所属地区/企业代码/企业名称/运营车数/客运量/轨道客运量/轮渡客运量/平均运距/填表人/联系电话/报出日期 */
    private static final int[] CITY_BUS_HEADER_COLS = {0, 1, 2, 5, 8, 13, 17, 19, 24, 25, 26};
    private static final String[] CITY_BUS_HEADER_KEYWORDS =
        {"所属地区", "企业代码", "企业名称", "公共汽电车_运营车数", "公共汽电车_客运量", "轨道交通_客运量",
         "城市客运轮渡_客运量", "公共汽电车平均运距", "填表人", "联系电话", "报出日期"};
    public ImportResult importCityBus(MultipartFile file, String period) throws Exception {
        List<CityBusRow> rows = new ArrayList<>();
        try (Workbook wb = WorkbookFactory.create(file.getInputStream())) {
            Sheet sheet = wb.getSheetAt(0);
            Row header = sheet.getRow(0);
            if (header == null || getString(header, 2) == null
                    || !getString(header, 2).contains("企业名称")) {
                throw new RuntimeException("未找到表头行(需包含 ä¼ä¸šåç§° åˆ—)");
            }
            requireHeaderLayout(sheet, "城市公交", "模板_交企统U203表_城市公共交通月度运营情况(2026å¹´7月).xls",
                CITY_BUS_HEADER_COLS, CITY_BUS_HEADER_KEYWORDS);
            for (int r = 1; r <= sheet.getLastRowNum(); r++) {
                Row row = sheet.getRow(r);
                if (row == null) continue;
@@ -2383,15 +2560,18 @@
    }
    /** å·¡æ¸¸å‡ºç§ŸæœˆæŠ¥å¯¼å…¥ï¼ˆå¸‚州级,17 è¡Œï¼›å«æ ¸å®žè¯´æ˜Ž/上报说明/修改记录) */
    /** å·¡æ¸¸å‡ºç§Ÿï¼ˆU402)模板关键列位(0-based):所属地区/企业代码/企业名称/载客车次总数/客运量/旅客周转量/运营车辆数/平均运距/填表人/联系电话/报出日期 */
    private static final int[] CITY_TAXI_HEADER_COLS = {0, 1, 2, 4, 6, 8, 10, 11, 15, 16, 17};
    private static final String[] CITY_TAXI_HEADER_KEYWORDS =
        {"所属地区", "企业代码", "企业名称", "载客车次总数", "客运量", "旅客周转量", "运营车辆数",
         "巡游出租汽车平均运距", "填表人", "联系电话", "报出日期"};
    public ImportResult importCityTaxi(MultipartFile file, String period) throws Exception {
        List<TaxiRow> rows = new ArrayList<>();
        try (Workbook wb = WorkbookFactory.create(file.getInputStream())) {
            Sheet sheet = wb.getSheetAt(0);
            Row header = sheet.getRow(0);
            if (header == null || getString(header, 2) == null
                    || !getString(header, 2).contains("企业名称")) {
                throw new RuntimeException("未找到表头行(需包含 ä¼ä¸šåç§° åˆ—)");
            }
            requireHeaderLayout(sheet, "巡游出租", "模板_交行统U402表-巡游出租汽车运营服务情况月报(2026).xls",
                CITY_TAXI_HEADER_COLS, CITY_TAXI_HEADER_KEYWORDS);
            for (int r = 1; r <= sheet.getLastRowNum(); r++) {
                Row row = sheet.getRow(r);
                if (row == null) continue;
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/controller/ReportExportController.java
@@ -151,7 +151,7 @@
    public ResponseEntity<byte[]> exportCityPassengerCitySum(@RequestParam("period") String period,
                                                              @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception {
        logExport("生成_城市客运客运量分市州累计.xlsx", period);
        return buildResponse(reportService.exportCityPassengerCitySum("导入模板_城市分市州.xlsx", period, mode), "生成_城市客运客运量分市州累计.xlsx");
        return buildResponse(reportService.exportCityPassengerCitySum("生成_城市客运客运量分市州累计.xlsx", period, mode), "生成_城市客运客运量分市州累计.xlsx");
    }
    /** ç”Ÿæˆ_城市客运各市州明细表.xlsx(城市客运各市州明细表_模板底稿) */
@@ -159,7 +159,7 @@
    public ResponseEntity<byte[]> exportCityPassengerDetailSum(@RequestParam("period") String period,
                                                                @RequestParam(value = "mode", defaultValue = "month") String mode) throws Exception {
        logExport("生成_城市客运各市州明细表.xlsx", period);
        return buildResponse(reportService.exportCityPassengerCitySum("导入模板_城市客运各市州明细表.xlsx", period, mode), "生成_城市客运各市州明细表.xlsx");
        return buildResponse(reportService.exportCityPassengerCitySum("生成_城市客运各市州明细表.xlsx", period, mode), "生成_城市客运各市州明细表.xlsx");
    }
    /** ç”Ÿæˆ_城市客运汇总.xlsx(城市汇总_模板底稿) */
@@ -275,5 +275,4 @@
            .body(data);
    }
}
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java
@@ -665,17 +665,58 @@
            totalYoy.put(city, freightCumYoy(ftMap.get(city), month));
        }
        // ===== ç¬¬äºŒé¡µï¼ˆå½“月)数据:规上=H2032 å½“月、合计=模板_货运量周转量当月列、规下=差值;同比=去年同月 =====
        Map<String, Map<Integer, Double>> h2032MonthCur = loadH2032FreightByMonth(period);
        String lastYearPeriod = (Integer.parseInt(year) - 1) + period.substring(4);
        Map<String, Map<Integer, Double>> h2032MonthLast = loadH2032FreightByMonth(lastYearPeriod);
        Map<String, Double> monthAbove = new HashMap<>();
        Map<String, Double> monthBelow = new HashMap<>();
        Map<String, Double> monthTotal = new HashMap<>();
        Map<String, Double> monthAboveYoy = new HashMap<>();
        Map<String, Double> monthBelowYoy = new HashMap<>();
        Map<String, Double> monthTotalYoy = new HashMap<>();
        double provMonthAbove = 0.0, provMonthAboveLast = 0.0;
        for (String city : RegionUtil.cityList()) {
            Double ma = monthFreightWan(h2032MonthCur, city, month);
            Double maLast = monthFreightWan(h2032MonthLast, city, month);
            Double mt = freightMonth(ftMap.get(city), month);
            Double mtLast = lastFreightMonth(ftMap.get(city), month);
            if (ma != null) provMonthAbove += ma;
            if (maLast != null) provMonthAboveLast += maLast;
            monthAbove.put(city, ma);
            monthTotal.put(city, mt);
            monthBelow.put(city, mt == null ? null : round(mt - (ma == null ? 0.0 : ma), 4));
            monthAboveYoy.put(city, growthYoy(ma, maLast));
            Double mb = monthBelow.get(city);
            Double mbLast = mtLast == null ? null : round(mtLast - (maLast == null ? 0.0 : maLast), 4);
            monthBelowYoy.put(city, growthYoy(mb, mbLast));
            monthTotalYoy.put(city, freightYoy(ftMap.get(city), month));
        }
        Double provMonthAboveWan = provMonthAbove == 0.0 ? null : round(provMonthAbove, 4);
        Double provMonthTotal = freightMonth(ftMap.get("湖北省"), month);
        Double provMonthBelow = provMonthTotal == null ? null : round(provMonthTotal - provMonthAbove, 4);
        Double provMonthAboveYoy = growthYoy(provMonthAbove == 0.0 ? null : provMonthAbove, provMonthAboveLast);
        Double provMonthTotalLast = lastFreightMonth(ftMap.get("湖北省"), month);
        Double provMonthBelowLast = provMonthTotalLast == null ? null
            : round(provMonthTotalLast - provMonthAboveLast, 4);
        Double provMonthBelowYoy = growthYoy(provMonthBelow, provMonthBelowLast);
        Double provMonthTotalYoy = freightYoy(ftMap.get("湖北省"), month);
        // ä»¥ docs/货运/生成_货运量排名.xlsx ä¸ºåº•稿:保留表头/合并/列宽/样式与 Q/R å æ¯”公式,仅替换数据
        File template = resolveFreightTemplate("生成_货运量排名.xlsx");
        try (InputStream in = new FileInputStream(template);
             XSSFWorkbook wb = new XSSFWorkbook(in)) {
            Sheet sheet = wb.getSheetAt(0);
            sheet.getRow(0).getCell(0).setCellValue(year + "å¹´" + cumRange(month) + "全省分市州累计完成公路货运量情况");
            sheet.getRow(22).getCell(0).setCellValue(year + "å¹´" + month + "月全省分市州累计完成公路货运量情况");
            sheet.getRow(22).getCell(0).setCellValue(year + "å¹´" + month + "月全省分市州完成公路货运量情况");
            fillFreightRankBlock(sheet, 3, above, below, total, aboveYoy, belowYoy, totalYoy,
                provAboveWan, provBelow, provTotal, provAboveYoy, provBelowYoy, provTotalYoy);
            fillFreightRankBlock(sheet, 25, above, below, total, aboveYoy, belowYoy, totalYoy,
                provAboveWan, provBelow, provTotal, provAboveYoy, provBelowYoy, provTotalYoy);
            renameRankMonthHeader(sheet, 24);
            fillFreightRankBlock(sheet, 25, monthAbove, monthBelow, monthTotal,
                monthAboveYoy, monthBelowYoy, monthTotalYoy,
                provMonthAboveWan, provMonthBelow, provMonthTotal,
                provMonthAboveYoy, provMonthBelowYoy, provMonthTotalYoy);
            try {
                wb.getCreationHelper().createFormulaEvaluator().evaluateAll();
            } catch (Exception e) {
@@ -693,15 +734,27 @@
        Map<String, ScaleSplitTransport> cumMap = loadCumulativeMap(period);
        ScaleSplitTransport province = getProvinceCumulative(period);
        // å½“月(第二页):周转量拆分表 MONTH è¡Œï¼ˆå«å½“月同比)
        Map<String, ScaleSplitTransport> monthTurnover = new HashMap<>();
        for (ScaleSplitTransport rec : scaleSplitMapper.selectList(
                new LambdaQueryWrapper<ScaleSplitTransport>()
                    .eq(ScaleSplitTransport::getPeriodType, "MONTH")
                    .eq(ScaleSplitTransport::getReportPeriod, period))) {
            String name = RegionUtil.normalizeCityName(rec.getRegionName());
            if (name != null) monthTurnover.put(name, rec);
        }
        ScaleSplitTransport provinceMonth = monthTurnover.remove("湖北省");
        // ä»¥ docs/货运/生成_周转量排名.xlsx ä¸ºåº•稿:保留表头/合并/列宽/样式,仅替换数据;Q/R å æ¯”为模板缓存值,按新数据重算
        File template = resolveFreightTemplate("生成_周转量排名.xlsx");
        try (InputStream in = new FileInputStream(template);
             XSSFWorkbook wb = new XSSFWorkbook(in)) {
            Sheet sheet = wb.getSheetAt(0);
            sheet.getRow(0).getCell(0).setCellValue(year + "å¹´" + cumRange(month) + "全省分市州累计完成公路货物运输周转量情况");
            sheet.getRow(22).getCell(0).setCellValue(year + "å¹´" + month + "月全省分市州累计完成公路货物运输周转量情况");
            sheet.getRow(22).getCell(0).setCellValue(year + "å¹´" + month + "月全省分市州完成公路货物运输周转量情况");
            fillTurnoverRankBlock(sheet, 3, cumMap, province);
            fillTurnoverRankBlock(sheet, 25, cumMap, province);
            renameRankMonthHeader(sheet, 24);
            fillTurnoverRankBlock(sheet, 25, monthTurnover, provinceMonth);
            return toBytes(wb);
        }
    }
@@ -994,6 +1047,31 @@
        setFreightCell(row, cumCol + 1, cumYoy);
    }
    /** H2032 è§„上某月合计(吨→万吨);无该月数据返回 null */
    private Double monthFreightWan(Map<String, Map<Integer, Double>> byCityMonth, String city, int month) {
        Map<Integer, Double> byMonth = byCityMonth == null ? null : byCityMonth.get(city);
        Double v = byMonth == null ? null : byMonth.get(month);
        return v == null ? null : round(v / 10000.0, 4);
    }
    /** åŒæ¯” = (本期-基期)/基期;任一期缺失或基期为 0 è¿”回 null */
    private Double growthYoy(Double cur, Double last) {
        if (cur == null || last == null || last == 0.0) return null;
        return (cur - last) / last;
    }
    /** æŽ’名表第二页列头「累计完成」→「当月完成」(仅导出内存替换,模板文件不改) */
    private void renameRankMonthHeader(Sheet sheet, int headerRowIdx) {
        Row row = sheet.getRow(headerRowIdx);
        if (row == null) return;
        for (int col : new int[]{1, 6, 11}) {
            Cell c = row.getCell(col);
            if (c == null || c.getCellType() != CellType.STRING) continue;
            String s = c.getStringCellValue();
            if (s != null && s.contains("累计完成")) c.setCellValue(s.replace("累计完成", "当月完成"));
        }
    }
    /** è´§è¿é‡æŽ’名块填充:模板 1-based r4 èµ·ï¼ˆå…¨çœ+17市州),Q/R å æ¯”公式保留不动 */
    private void fillFreightRankBlock(Sheet sheet, int start,
                                      Map<String, Double> above, Map<String, Double> below, Map<String, Double> total,
@@ -1163,9 +1241,12 @@
    /** H2032规上: city -> month -> è´§è¿é‡(吨) */
    private Map<String, Map<Integer, Double>> loadH2032FreightByMonth(String period) {
        Map<String, Map<Integer, Double>> result = new HashMap<>();
        String yearPrefix = period.length() >= 4 ? period.substring(0, 4) : null;
        List<H2032EnterpriseMonthly> list = h2032Mapper.selectList(null);
        for (H2032EnterpriseMonthly record : list) {
            if (record.getReportPeriod() == null || record.getReportPeriod().compareTo(period) > 0) continue;
            // H2032 è¡¨åŒæ—¶å­˜æœ‰å¾€å¹´æœˆæŠ¥ï¼Œç»Ÿè®¡å½“年规上值时只取与报表期同年的记录,避免去年数据叠加
            if (yearPrefix != null && !record.getReportPeriod().startsWith(yearPrefix)) continue;
            String city = RegionUtil.cityByCode(record.getRegionCode());
            if (city == null) continue;
            int month = parseMonth(record.getReportPeriod());
@@ -1178,9 +1259,11 @@
    /** H2032规上累计: city -> è´§è¿é‡(吨) */
    private Map<String, Double> loadH2032FreightCumulative(String period) {
        Map<String, Double> result = new HashMap<>();
        String yearPrefix = period.length() >= 4 ? period.substring(0, 4) : null;
        List<H2032EnterpriseMonthly> list = h2032Mapper.selectList(null);
        for (H2032EnterpriseMonthly record : list) {
            if (record.getReportPeriod() == null || record.getReportPeriod().compareTo(period) > 0) continue;
            if (yearPrefix != null && !record.getReportPeriod().startsWith(yearPrefix)) continue;
            String city = RegionUtil.cityByCode(record.getRegionCode());
            if (city == null) continue;
            double freight = record.getFreightTotal() == null ? 0.0 : record.getFreightTotal();
@@ -1945,6 +2028,7 @@
            // ç´¯è®¡åŒæ¯”列(模板 #REF! â†’ åº“内去年 1..N æœˆç´¯è®¡åŒæ¯”数值)
            fillMidCumYoyColumn(sheet, mid, currentYear, fillMonths, extended ? 27 : 15);
            recalc(wb);
            clearFormulaErrorsAll(wb); // åŽ»å¹´åŒæœŸæ˜Žç»†é¡µæ®‹ç•™ #REF! åŒæ¯”公式 â†’ æ¸…空
            return toBytes(wb);
        }
    }
@@ -2195,11 +2279,20 @@
                    title.getCell(0).setCellValue(currentYear + "å¹´1-" + maxMonth + "月全省分市州累计完成道路客运生产情况");
                }
            }
            // å³å—(当月)标题 K1
            if (title != null && title.getCell(10) != null) {
                title.getCell(10).setCellValue(currentYear + "å¹´" + maxMonth + "月全省分市州完成道路客运生产情况");
            }
            // å…¨çœè¡Œ r3:B3/F3 ä¸º SUM å…¬å¼ä¿ç•™ï¼›D3/H3 åŒæ¯”填值(0-based åˆ— 3/7)
            setValOrBlank(sheet, 2, 3, yoyOf(midCumClass(mid, currentYear, "湖北省", maxMonth, 0, true),
                midCumClass(mid, currentYear - 1, "湖北省", maxMonth, 0, true)));
            setValOrBlank(sheet, 2, 7, yoyOf(midCumClass(mid, currentYear, "湖北省", maxMonth, 0, false),
                midCumClass(mid, currentYear - 1, "湖北省", maxMonth, 0, false)));
            // å³å—全省行 N3/R3:当月同比(L3/P3 ä¸º SUM å…¬å¼ä¿ç•™ï¼‰
            setValOrBlank(sheet, 2, 13, yoyOf(midClassVal(mid, currentYear, maxMonth, "湖北省", 0, true),
                midClassVal(mid, currentYear - 1, maxMonth, "湖北省", 0, true)));
            setValOrBlank(sheet, 2, 17, yoyOf(midClassVal(mid, currentYear, maxMonth, "湖北省", 0, false),
                midClassVal(mid, currentYear - 1, maxMonth, "湖北省", 0, false)));
            // å¸‚州行 r4-20:B/F ç´¯è®¡å€¼ã€D/H åŒæ¯”ï¼›C/E/G/I æŽ’名公式保留
            List<String> cities = RegionUtil.CITY_LIST;
            for (int i = 0; i < cities.size(); i++) {
@@ -2213,6 +2306,15 @@
                setValOrBlank(sheet, r0, 3, yoyOf(pass, lastPass));
                setValOrBlank(sheet, r0, 5, turn == 0 ? null : round(turn, 4));
                setValOrBlank(sheet, r0, 7, yoyOf(turn, lastTurn));
                // å³å—当月:L/P å€¼ã€N/R å½“月同比(M/O/Q/S æŽ’名公式保留)
                double mPass = midClassVal(mid, currentYear, maxMonth, city, 0, true);
                double mTurn = midClassVal(mid, currentYear, maxMonth, city, 0, false);
                double mLastPass = midClassVal(mid, currentYear - 1, maxMonth, city, 0, true);
                double mLastTurn = midClassVal(mid, currentYear - 1, maxMonth, city, 0, false);
                setValOrBlank(sheet, r0, 11, mPass == 0 ? null : round(mPass, 4));
                setValOrBlank(sheet, r0, 13, mPass == 0 ? null : yoyOf(mPass, mLastPass));
                setValOrBlank(sheet, r0, 15, mTurn == 0 ? null : round(mTurn, 4));
                setValOrBlank(sheet, r0, 17, mTurn == 0 ? null : yoyOf(mTurn, mLastTurn));
            }
            recalc(wb);
            return toBytes(wb);
@@ -2277,6 +2379,36 @@
                setValOrBlank(sheet, r0, 2, yoyOf(pass, lastPass));
                setValOrBlank(sheet, r0, 5, turn == 0 ? null : round(turn, 4));
                setValOrBlank(sheet, r0, 6, yoyOf(turn, lastTurn));
            }
            // ä¸‹åŠå—(当月):标题行9、数据行11-15(0-based 8、10-14)
            Row bottomTitle = sheet.getRow(8);
            if (bottomTitle != null && bottomTitle.getCell(0) != null) {
                bottomTitle.getCell(0).setCellValue(currentYear + "å¹´" + maxMonth + "月中口径客运量及周转量");
            }
            for (int i = 0; i < names.length; i++) {
                int r0 = 10 + i;
                double pass = midClassVal(mid, currentYear, maxMonth, "湖北省", dims[i], true);
                double turn = midClassVal(mid, currentYear, maxMonth, "湖北省", dims[i], false);
                double lastPass = midClassVal(mid, currentYear - 1, maxMonth, "湖北省", dims[i], true);
                double lastTurn = midClassVal(mid, currentYear - 1, maxMonth, "湖北省", dims[i], false);
                setValOrBlank(sheet, r0, 1, pass == 0 ? null : round(pass, 4));
                setValOrBlank(sheet, r0, 2, pass == 0 ? null : yoyOf(pass, lastPass));
                setValOrBlank(sheet, r0, 5, turn == 0 ? null : round(turn, 4));
                setValOrBlank(sheet, r0, 6, turn == 0 ? null : yoyOf(turn, lastTurn));
            }
            // ä¸‹åŠå—占比公式由样例指向上半块(B$3/F$3),改写为本块总行(B$11/F$11),行12-15
            for (int i = 1; i < names.length; i++) {
                int r0 = 10 + i;
                Row rr = sheet.getRow(r0);
                if (rr == null) continue;
                Cell dc = rr.getCell(3);
                if (dc != null && dc.getCellType() == CellType.FORMULA) {
                    dc.setCellFormula("B" + (r0 + 1) + "/B$11");
                }
                Cell hc = rr.getCell(7);
                if (hc != null && hc.getCellType() == CellType.FORMULA) {
                    hc.setCellFormula("F" + (r0 + 1) + "/F$11");
                }
            }
            recalc(wb);
            return toBytes(wb);
@@ -2372,6 +2504,7 @@
                fillEnergyTemplateSheet(s, agg);
            }
            recalc(wb);
            clearFormulaErrorsAll(wb); // æ— åŽ»å¹´æ•°æ®çš„åŒæ¯”/增速公式 #DIV/0! â†’ æ¸…空
            return toBytes(wb);
        }
    }
@@ -2508,7 +2641,7 @@
    public byte[] exportCityBusDetail(String period, String mode) throws Exception {
        int year = Integer.parseInt(period.split("-")[0]);
        int month = monthOf(period, mode);
        return exportCityByTemplate("导入模板_城市公交.xlsx", period, mode,
        return exportCityByTemplate("生成_城市公交客运量分市州明细.xlsx", period, mode,
            loadCityBusByMonth(year + "-", month),
            loadCityBusByMonth((year - 1) + "-", month));
    }
@@ -2562,7 +2695,7 @@
    public byte[] exportCityTaxiDetail(String period, String mode) throws Exception {
        int year = Integer.parseInt(period.split("-")[0]);
        int month = monthOf(period, mode);
        return exportCityByTemplate("导入模板_巡游出租.xlsx", period, mode,
        return exportCityByTemplate("生成_巡游出租客运量分市州明细.xlsx", period, mode,
            loadCityTaxiByMonth(year + "-", month),
            loadCityTaxiByMonth((year - 1) + "-", month));
    }
@@ -2606,7 +2739,7 @@
        int year = Integer.parseInt(period.split("-")[0]);
        int month = monthOf(period, mode);
        Map<Integer, Map<String, double[]>> monthCity = loadCityRailFerryByMonth(year + "-", month);
        File template = resolveTemplate("导入模板_轨道、轮渡.xlsx");
        File template = resolveTemplate("生成_轨道轮渡客运量分市州明细.xlsx");
        try (InputStream in = new FileInputStream(template);
             XSSFWorkbook wb = new XSSFWorkbook(in)) {
            Sheet sheet = wb.getSheetAt(0);
@@ -2616,6 +2749,8 @@
            // è½®æ¸¡ï¼šå®¢è¿é‡è¡Œ 13(全省)/15(武汉);指标 2=轮渡客运量 3=轮渡周转量
            fillRailFerryBlock(sheet, monthCity, month, new String[][]{{"全省", "12"}, {"武汉市", "14"}}, 2);
            recalc(wb);
            clearFormulaErrorCells(sheet, 3, sheet.getLastRowNum(), 1, 39);
            fixCityMonthHeaderText(sheet);
            return toBytes(wb);
        }
    }
@@ -2704,6 +2839,7 @@
        int year = Integer.parseInt(period.split("-")[0]);
        int month = monthOf(period, mode);
        Map<String, double[]> cum = loadCityPassengerCumulative(year + "-", month);
        Map<String, double[]> monthMap = loadCityPassengerMonthMap(year + "-", month);
        File template = resolveTemplate(templateFileName);
        try (InputStream in = new FileInputStream(template);
             XSSFWorkbook wb = new XSSFWorkbook(in)) {
@@ -2712,9 +2848,24 @@
            List<String> areas = new java.util.ArrayList<>();
            areas.add("全省");
            areas.addAll(RegionUtil.cityList());
            fillCitySumBlock(sheet, cum, areas, 4, 0);   // å®¢è¿é‡åŒºï¼ˆå•位:万人次,POI 0 åŸºï¼‰
            fillCitySumBlock(sheet, cum, areas, 26, 1);  // å‘¨è½¬é‡åŒºï¼ˆå•位:万人次公里,POI 0 åŸºï¼‰
            fillCitySumBlock(sheet, cum, areas, 4, 0);   // ç´¯è®¡å®¢è¿é‡åŒºï¼ˆå•位:万人次,POI 0 åŸºï¼Œè¡Œ5-22)
            fillCitySumBlock(sheet, cum, areas, 26, 1);  // ç´¯è®¡å‘¨è½¬é‡åŒºï¼ˆå•位:万人次公里,POI 0 åŸºï¼Œè¡Œ27-44)
            // å½“月块标题(0基行44/66)与数据(0基行48-65/70-87)
            Row pTitle = sheet.getRow(44);
            if (pTitle != null && pTitle.getCell(0) != null) {
                pTitle.getCell(0).setCellValue("城市客运客运量分市州" + month + "月情况");
            }
            Row tTitle = sheet.getRow(66);
            if (tTitle != null && tTitle.getCell(0) != null) {
                tTitle.getCell(0).setCellValue("城市客运客运周转量分市州" + month + "月情况");
            }
            fillCitySumBlock(sheet, monthMap, areas, 48, 0);  // å½“月客运量区(行49-66)
            fillCitySumBlock(sheet, monthMap, areas, 70, 1);  // å½“月周转量区(行71-88)
            // å½“月块排名/占比公式由累计块复制而来,RANK èŒƒå›´ä¸Žå æ¯”分母需改指当月块自身行
            repairCityMonthRankShare(sheet, 50, 66, 49);
            repairCityMonthRankShare(sheet, 72, 88, 71);
            recalc(wb);
            clearFormulaErrorsAll(wb); // æ— åŽ»å¹´ç´¯è®¡çš„å æ¯”/增速公式 #DIV/0! â†’ æ¸…空
            return toBytes(wb);
        }
    }
@@ -2744,6 +2895,33 @@
            setDataCell(sheet, rowIdx, 24, 0);
            rowIdx++;
        }
    }
    /** å½“月块排名/占比公式修正:模板当月块由累计块复制而来,RANK èŒƒå›´ä¸Žå æ¯”分母需改指当月块自身行 */
    private void repairCityMonthRankShare(Sheet sheet, int firstDataRow1, int lastDataRow1, int provRow1) {
        String[] groups = {"B", "G", "L", "Q"};
        String[] growth = {"E", "J", "O", "T"};
        for (int r = firstDataRow1; r <= lastDataRow1; r++) {
            int r0 = r - 1;
            for (int g = 0; g < 4; g++) {
                String base = groups[g];
                String grow = growth[g];
                setFormulaIfFormula(sheet, r0, 2 + g * 5,
                    "RANK(" + base + r + "," + base + "$" + firstDataRow1 + ":" + base + "$" + lastDataRow1 + ")");
                setFormulaIfFormula(sheet, r0, 3 + g * 5, base + r + "/" + base + "$" + provRow1);
                setFormulaIfFormula(sheet, r0, 5 + g * 5,
                    "RANK(" + grow + r + "," + grow + "$" + firstDataRow1 + ":" + grow + "$" + lastDataRow1 + ")");
            }
        }
    }
    /** å•元格原为公式时改写公式(排名/占比列),非公式单元格不动(保持模板式样) */
    private void setFormulaIfFormula(Sheet sheet, int rowIdx, int colIdx, String formula) {
        Row row = sheet.getRow(rowIdx);
        if (row == null) return;
        Cell c = row.getCell(colIdx);
        if (c == null || c.getCellType() != CellType.FORMULA) return;
        c.setCellFormula(formula);
    }
    /** æŸå¹´ 1..limit æœˆåŸŽå¸‚客运累计:city â†’ [公交客运量,公交周转量,出租客运量,出租周转量,轨道客运量,轨道周转量,轮渡客运量,轮渡周转量],含"全省" */
@@ -2784,6 +2962,23 @@
        return cum;
    }
    /** æŸå¹´å•月城市客运数据:city â†’ 8 ç»´æ•°ç»„(口径同累计),含"全省";= month ç´¯è®¡ - (month-1) ç´¯è®¡ */
    private Map<String, double[]> loadCityPassengerMonthMap(String yearPrefix, int month) {
        Map<String, double[]> cum = loadCityPassengerCumulative(yearPrefix, month);
        if (month <= 1) return cum;
        Map<String, double[]> pre = loadCityPassengerCumulative(yearPrefix, month - 1);
        Map<String, double[]> out = new HashMap<>();
        for (Map.Entry<String, double[]> e : cum.entrySet()) {
            double[] prev = pre.get(e.getKey());
            double[] d = new double[8];
            for (int i = 0; i < 8; i++) {
                d[i] = e.getValue()[i] - (prev == null ? 0 : prev[i]);
            }
            out.put(e.getKey(), d);
        }
        return out;
    }
    // ==================== åŸŽå¸‚客运 å…¨çœæ±‡æ€»ï¼ˆåŸŽå¸‚汇总_模板) ====================
    /** ç”Ÿæˆ_城市客运汇总.xlsx(以 åŸŽå¸‚汇总_模板.xlsx ä¸ºåº•稿;2026 æ®µå¡«åº“内 1..N æœˆç´¯è®¡ï¼ŒåŒæ¯”清空,2025/2024 æ®µä¿ç•™æ¨¡æ¿åŽ†å²å‚è€ƒå€¼ï¼‰ */
@@ -2795,7 +2990,7 @@
        double taxiPax = prov[2], taxiTurn = prov[3];
        double railPax = prov[4], railTurn = prov[5];
        double ferryPax = prov[6], ferryTurn = prov[7];
        File template = resolveTemplate("导入模板_城市汇总.xlsx");
        File template = resolveTemplate("生成_城市客运汇总.xlsx");
        try (InputStream in = new FileInputStream(template);
             XSSFWorkbook wb = new XSSFWorkbook(in)) {
            Sheet sheet = wb.getSheetAt(0);
@@ -2819,7 +3014,36 @@
                setDataCell(sheet, r, 2, 0);
                setDataCell(sheet, r, 4, 0);
            }
            // åº•部单月表(新版式):标题行11(0基10)、数据行13-19(0基12-18),填当月完成量
            Row mTitle = sheet.getRow(10);
            if (mTitle != null && mTitle.getCell(0) != null) {
                mTitle.getCell(0).setCellValue(year + "å¹´" + month + "月全省完成城市客运量情况");
            }
            double[] mProv = loadCityPassengerMonthMap(year + "-", month).getOrDefault("全省", new double[8]);
            double mBusPax = mProv[0], mBusTurn = mProv[1];
            double mTaxiPax = mProv[2], mTaxiTurn = mProv[3];
            double mRailPax = mProv[4], mRailTurn = mProv[5];
            double mFerryPax = mProv[6], mFerryTurn = mProv[7];
            setDataCell(sheet, 12, 1, mBusPax + mTaxiPax + mRailPax + mFerryPax); // B13 æ€»å®¢è¿é‡
            setDataCell(sheet, 12, 3, mBusTurn + mTaxiTurn + mRailTurn + mFerryTurn); // D13 æ€»å‘¨è½¬é‡
            setDataCell(sheet, 13, 1, mBusPax);   // B14 åŸŽå¸‚公交
            setDataCell(sheet, 13, 3, mBusTurn);  // D14
            setDataCell(sheet, 14, 1, mTaxiPax);  // B15 åŸŽå¸‚出租车
            setDataCell(sheet, 14, 3, mTaxiTurn); // D15
            setDataCell(sheet, 15, 1, mTaxiPax);  // B16 å…¶ä¸­å·¡æ¸¸å‡ºç§Ÿ
            setDataCell(sheet, 15, 3, mTaxiTurn); // D16
            setZeroCell(sheet, 16, 1);            // B17 åŸŽå¸‚网约车
            setZeroCell(sheet, 16, 3);            // D17
            setDataCell(sheet, 17, 1, mRailPax);  // B18 è½¨é“
            setDataCell(sheet, 17, 3, mRailTurn); // D18
            setDataCell(sheet, 18, 1, mFerryPax); // B19 è½®æ¸¡
            setDataCell(sheet, 18, 3, mFerryTurn);// D19
            for (int r = 12; r <= 18; r++) {      // å•月表 C/E åŒæ¯”:无上年单月源 â†’ æ¸…空样例
                setDataCell(sheet, r, 2, 0);
                setDataCell(sheet, r, 4, 0);
            }
            recalc(wb);
            clearFormulaErrorsAll(wb); // æ— åŽ»å¹´æ•°æ®çš„åŒæ¯”å…¬å¼ #DIV/0! â†’ æ¸…空
            return toBytes(wb);
        }
    }
@@ -2833,8 +3057,8 @@
            addZipEntry(zos, "生成_城市公交客运量分市州明细.xlsx", exportCityBusDetail(period, mode));
            addZipEntry(zos, "生成_巡游出租客运量分市州明细.xlsx", exportCityTaxiDetail(period, mode));
            addZipEntry(zos, "生成_轨道轮渡客运量分市州明细.xlsx", exportCityRailFerryDetail(period, mode));
            addZipEntry(zos, "生成_城市客运客运量分市州累计.xlsx", exportCityPassengerCitySum("导入模板_城市分市州.xlsx", period, mode));
            addZipEntry(zos, "生成_城市客运各市州明细表.xlsx", exportCityPassengerCitySum("导入模板_城市客运各市州明细表.xlsx", period, mode));
            addZipEntry(zos, "生成_城市客运客运量分市州累计.xlsx", exportCityPassengerCitySum("生成_城市客运客运量分市州累计.xlsx", period, mode));
            addZipEntry(zos, "生成_城市客运各市州明细表.xlsx", exportCityPassengerCitySum("生成_城市客运各市州明细表.xlsx", period, mode));
            addZipEntry(zos, "生成_城市客运汇总.xlsx", exportCityPassengerSummary(period, mode));
        }
        return bos.toByteArray();
@@ -2911,8 +3135,8 @@
            case "cityBusDetail": return exportCityBusDetail(period, mode);
            case "cityTaxiDetail": return exportCityTaxiDetail(period, mode);
            case "cityRailFerryDetail": return exportCityRailFerryDetail(period, mode);
            case "cityPassengerCitySum": return exportCityPassengerCitySum("导入模板_城市分市州.xlsx", period, mode);
            case "cityPassengerDetailSum": return exportCityPassengerCitySum("导入模板_城市客运各市州明细表.xlsx", period, mode);
            case "cityPassengerCitySum": return exportCityPassengerCitySum("生成_城市客运客运量分市州累计.xlsx", period, mode);
            case "cityPassengerDetailSum": return exportCityPassengerCitySum("生成_城市客运各市州明细表.xlsx", period, mode);
            case "cityPassengerSummary": return exportCityPassengerSummary(period, mode);
            default: return null;
        }
@@ -2996,10 +3220,56 @@
            } catch (Exception e) {
                log.warn("城市客运模板公式求值失败: {}", e.getMessage());
            }
            clearFormulaErrorCells(sheet, 4, sheet.getLastRowNum(), 3, 39);
            fixCityMonthHeaderText(sheet);
            return toBytes(wb);
        }
    }
    /** æ¸…空求值结果为错误的公式单元格(模板跨簿同比公式残留 #REF! æ—¶ç§»é™¤å…¬å¼ï¼Œé¿å…å¯¼å‡ºæ˜¾ç¤ºé”™è¯¯ï¼‰ */
    private void clearFormulaErrorCells(Sheet sheet, int startRow, int endRow, int startCol, int endCol) {
        for (int r = startRow; r <= endRow; r++) {
            Row row = sheet.getRow(r);
            if (row == null) continue;
            for (int c = startCol; c <= endCol; c++) {
                Cell cell = row.getCell(c);
                if (cell == null || cell.getCellType() != CellType.FORMULA) continue;
                try {
                    if (cell.getCachedFormulaResultType() == CellType.ERROR) cell.setBlank();
                } catch (Exception ignore) {
                    // ç¼“存类型读取失败时忽略
                }
            }
        }
    }
    /** æ¸…空工作簿全部工作表内求值结果为错误的公式单元格(跨簿/跨表 #REF!、缺去年数据 #DIV/0! ç­‰ï¼‰ */
    private void clearFormulaErrorsAll(XSSFWorkbook wb) {
        for (int i = 0; i < wb.getNumberOfSheets(); i++) {
            Sheet s = wb.getSheetAt(i);
            clearFormulaErrorCells(s, 2, s.getLastRowNum(), 1, 60);
        }
    }
    /** åŸŽå¸‚客运类模板表头月份列若为未格式化日期序列号(如 46082),改写为「YYYYå¹´M月」文本 */
    private void fixCityMonthHeaderText(Sheet sheet) {
        for (int r = 0; r <= Math.min(sheet.getLastRowNum(), 20); r++) {
            Row row = sheet.getRow(r);
            if (row == null) continue;
            Cell nameCell = row.getCell(0);
            String nameText = nameCell == null ? null : cellText(nameCell);
            if (nameText == null || !nameText.contains("地区")) continue;
            for (int c = 2; c <= 40; c += 2) {
                Cell cell = row.getCell(c);
                if (cell == null || cell.getCellType() != CellType.NUMERIC) continue;
                double v = cell.getNumericCellValue();
                if (v < 40000 || v > 60000) continue;
                java.util.Date d = org.apache.poi.ss.usermodel.DateUtil.getJavaDate(v);
                cell.setCellValue(new java.text.SimpleDateFormat("yyyyå¹´M月").format(d));
            }
        }
    }
    /** æ¨¡æ¿æ–‡ä»¶å®šä½ï¼šé…ç½®ç›®å½• â†’ user.dir â†’ user.dir/.. é€çº§å›žé€€ */
    private File resolveTemplate(String fileName) throws Exception {
        return resolveAnyTemplate(templateDir, fileName);
traffic-audit-web/src/views/DataImport.vue
@@ -272,8 +272,8 @@
        passengerIndividual: '公路旅客/个体客运量汇总.xlsx',
        energyMonthly: '能耗/模板_道路货运车辆能源消耗情况(2026).xlsx',
        energyAuth: '能耗/模板_能耗车辆运政信息.xlsx',
        cityBus: '城市客运/导入模板_城市公交.xlsx',
        cityTaxi: '城市客运/导入模板_巡游出租.xlsx',
        cityBus: '城市客运/生成_城市公交客运量分市州明细.xlsx',
        cityTaxi: '城市客运/生成_巡游出租客运量分市州明细.xlsx',
        cityTaxiAuth: '城市客运/导入模板_出租车信息(运政车辆信息).xlsx',
        investment: '投资/输入/客运(客运站)/更新_7月客运站投资明细表(市州汇总大表,给领导).xlsx',
        investmentLogistics: '投资/输入/物流(物流园区)/更新_7月物流站场投资明细.xls',