交通货运统计审核系统 — 问题与注意事项汇总
用途:把项目运行、数据导入、报表生成、仓库协作中所有「踩过的坑」集中记录,供后续开发与运维快速查阅。
维护方式:新发现问题请直接在本文件追加,并注明日期。
最后更新:2026-09-16
一、速查表(最常见的 10 条)
| # |
事项 |
正确做法 |
| 1 |
启动前后端 |
项目根目录执行 powershell -NoProfile -ExecutionPolicy Bypass -File start-dev.ps1 |
| 2 |
端口占用判断 |
看 backend.log / traffic-audit-web/frontend.log,**不要**依赖 Get-NetTCPConnection |
| 3 |
后端就绪标志 |
日志出现 Started TrafficAuditApplication + Tomcat started on port(s): 8090 |
| 4 |
前端就绪标志 |
日志出现 Compiled successfully + App running at: |
| 5 |
连数据库 |
mysql.exe --host=127.0.0.1 --port=3308 --user=root --default-character-set=utf8mb4 -D traffic_audit |
| 6 |
停旧进程 |
按 PID 精确停 cmd → java(maven) → java(app) 链;**不要杀 node_repl 和用户自己的 cmd 窗口** |
| 7 |
脚本报「已添加了具有相同键的项」 |
本机同时存在 Path 与 PATH,改用 cmd.exe /c ... > log 2>&1,**严禁用 Start-Process** |
| 8 |
写中文文件 |
用 UTF-8;main.js 带 BOM 必须写回 BOM;改文件前先确认原文件是 CRLF 还是 LF |
| 9 |
提交前 |
先测试 + 写《功能测试报告》+ 更新《工作日结》,再 fetch/合并/推送 |
| 10 |
推公司 gitea |
先 git fetch gitea 与远端 main 合并,**禁止强推** |
二、启动与进程管理
| 问题 |
原因 |
处置 |
Start-Process 报「已添加了具有相同键的项」 |
环境变量同时存在 Path 与 PATH(值相同) |
统一用 cmd.exe /c ... > log 2>&1 或 ProcessStartInfo 启动 |
前端在沙箱内起不来(EPERM: lstat) |
node 访问用户目录被沙箱拦截 |
start-dev.ps1 整体在沙箱外执行 |
嵌套 powershell.exe -Command 引号被破坏 |
外层 shell 先解析一层引号 |
直接运行 .ps1 文件,不做嵌套 |
| 重启时误杀 Codex 内核 |
按名字杀 node.exe 会命中 node_repl |
按 PID 精确停后端链 cmd → java(maven) → java(app)、前端链 cmd → node(npm) → cmd → node(vue-cli-service) |
| 前端日志找不到 |
日志在子目录 |
traffic-audit-web/frontend.log;后端 backend.log 在仓库根目录 |
重启标准流程:列出 java.exe 进程 → 停 app → maven → cmd → 运行 start-dev.ps1(脚本自动跳过已在监听的端口)。
三、服务状态验证
- 沙箱内
Get-NetTCPConnection 会因权限「拒绝访问」而**静默失败**,据此判定端口未监听是错的。
- 判断服务状态一律以日志为准;HTTP 探活用:
- 后端:
GET http://127.0.0.1:8090/api/auth/captcha-config(返回 {"code":200,...} 即通)
- 前端:
http://localhost:8080/#/login
- 前端日志出现
Proxy error: Could not proxy request /api/... (ECONNREFUSED) 说明**后端当时没起来**,不是前端问题。
四、数据库
- 连接(本地开发库):
& 'C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql.exe' --host=127.0.0.1 --port=3308 --user=root --password=<见 AGENTS.md> --default-character-set=utf8mb4 -D traffic_audit
- 必须写
--host=127.0.0.1:写成 -h127.0.0.1 会被解析成 host 127,连接失败。
- 输出过滤
2>&1 | Select-String -NotMatch 'Warning' 可屏蔽密码警告。
- 常用表与关键列:
| 表 |
说明 |
关键列 |
freight_turnover_import |
货运量/周转量 |
report_period、region_name、freight_m01..m12、turnover_m01..m12、last_* |
h2031_enterprise_monthly |
公路旅客 H203-1 月报 |
report_period、enterprise_code、unified_credit_code、report_unit |
import_batch |
导入批次 |
import_type、report_period、file_name、success_rows |
audit_result / audit_run |
审核结果/运行 |
report_period |
- 排查「某期数据在不在」:
SELECT report_period, COUNT(*) FROM <表> GROUP BY report_period ORDER BY report_period;
- 排查「某期导入来自哪个文件」:查
import_batch 的 file_name。
- 表结构变更要同步三处:实际库 DDL、
docs/init.sql、docs/database.md。
- 测试用报表期建议用
2099-xx,测完用 POST /api/import/clear?period=... 或直接 DELETE 清理,避免污染真实月份下拉项。
五、数据导入:文件路径与期次约定
5.1 货运量/周转量(/api/import/freightTurnover)
| 源文件 |
覆盖期次 |
备注 |
D:\05_数据分类\高速\定稿-湖北省各市州运输量数据(2026年1-8月).xlsx |
2021-12 / 2022-12 / 2024-12 / 2025-12 / 2026-08 |
无 2023 年 Sheet |
D:\05_数据分类\货运\7月\定稿-湖北省各市州运输量数据(2026年1-7月).xlsx |
多一个 2023 Sheet |
2023 年数据的来源;2021/2022/2024 与 8 月文件逐值一致 |
- 多年度工作簿识别规则(
detectYearSheets):
- 至少 2 个 Sheet(单 Sheet 文件不识别为多年度工作簿,会走老的月度模板路径);
- 每个 Sheet 名匹配
^\d{4}\s*年?$(2023年、2023 都可以);
- 每个 Sheet 首行 A1 含「货运量」、B1 含「月」。
任一条件不满足 → 整体回退老的月度模板解析。
- 每个年度 Sheet 的结构:上方是「货运量(万吨)」块(约 20 行),下方是「周转量(万吨公里)」块;**同一市州名第二次出现即视为周转量块**。
- 报表期语义:**
2021-12 这类期放的是该年 1–12 月的全年数据**(m01..m12 全部有值),不是 12 月单月。该年最后有数据的月份决定期号(2026 年只有 1–8 月 → 2026-08)。
- 上年同期:多年度文件里自动取**上一年度 Sheet**;若上一年度不存在(如 2021 无 2020 Sheet),
last_* 为空。
- 只补某一年时,可另存一个只含该年 + 上一年的临时工作簿再导入(注意「至少 2 个 Sheet」规则)。
5.2 公路旅客 H203-1(/api/import/passengerMonthly)
| 源文件 |
备注 |
docs\公路旅客\模板_交企统H203-1表_公路旅客运输月度生产情况.xlsx |
用户修改后的模板 |
D:\桌面\测试数据\公路旅客\八月\公路旅客运输月度生产情况(2026)_2026-09-09 09_18_45.xls |
系统导出的老格式样例 |
D:\需要导入的数据\公路旅客\*.xls |
历史各月导出文件 |
- 解析**按表头名取值**(
buildHeaderMap),因此模板在中间插列/整体右移**不会**破坏其它字段。
- 新模板在「企业名称」后新增 2 列:
统一社会信用代码、填报单位;老格式文件其实也带这两列(此前代码未读取)。
- 必需列缺失会直接报错,例如选错类型时提示「表头缺少必需列【企业名称】【客运量_总计】」。
5.3 其它
- 导入失败必须在页面显示**行号**(用户要求),新增解析逻辑时不要吞掉行号信息。
六、报表生成
- 「汇总大表」预览弹窗由
ReportExport.vue 渲染:
- 弹窗内**只保留一张指标表**(分类 / 指标 / 数据 / 同比),「中口径」之后不再渲染任何表格;
- 弹窗支持拖动(
v-dialog-drag 指令,拖标题栏)+ 10px 圆角。
- 导出依赖**母版模板文件**:
docs/生成汇总大表/YYYY年M月道路运输量汇总表.xlsx。缺失时报「母版定位失败:未找到模板文件」,**不是数据问题**。
- 接口层面自查(绕过前端,定位是前端还是后端问题):
- 预览:
GET /api/report/preview?period=2026-08&mode=month&types=summaryWorkbook
- 导出:
GET /api/report/export/summaryWorkbook?...
- 失败提示已细分:能区分「连不上服务器」和「后端返回的具体原因」;导出接口是
responseType:'blob',报错时 data 也是 Blob,必须先 text() 再解析。
七、登录与验证码
| 问题 |
原因 |
处置 |
| 登录页出现空白方框 + 「验证码加载失败,请检查网络」 |
前端 captchaRequired 默认 true,读取 /api/auth/captcha-config 失败时静默忽略,页面残留加载不出来的验证码框 |
默认值改 false,改为 fail-safe:只有后端明确返回 required === true 才显示;请求失败按「不需要验证码」处理 |
| 开关位置 |
后端 application.yml 的 app.captcha.required |
关掉后应显示「测试模式:行为验证码已跳过」 |
| 换网络/换 IP 后接口 403 |
跨域白名单 |
CORS 需放行内网网段(已修复 0d2a5fc) |
八、文件写入与文本处理的坑
- 本机文件**换行符不统一**:
Login.vue、main.js 是 CRLF;ReportExport.vue、DataImportService.java、docs/*.md 是 LF。用 [System.IO.File]::WriteAllText 时必须匹配原换行符,否则后续 -replace / 字符串匹配会失败。
main.js 带 BOM(EF BB BF),改写时要用 New-Object System.Text.UTF8Encoding($true)。
git checkout -- <文件> 会把 LF 转成 CRLF(本仓库 core.autocrlf=true),会让后续基于 LF 的替换失效;操作前先确认真实换行符。
- PowerShell 多行中文替换建议写
*.py 脚本用 python 执行(apply_patch 在本机不可用)。
- 字符串替换**注意锚点唯一性**:
| enterprise_name | varchar(200) | 企业名称 | 在 docs/database.md 出现 4 次,直接 replace 会改错表;必须先截取目标章节再替换。
- 读
.xls:本机 python 无 xlrd,可用 Excel COM(New-Object -ComObject Excel.Application → Workbooks.Open → Cells.Item(r,c).Text,记得 Quit() + ReleaseComObject)。
九、浏览器自动化取证的坑
tab.playwright.evaluate() 读 DOM 才可信;AX 树可能读到缓存。
- Playwright locator 对 Element UI 表格内按钮**会超时**(
isVisible() 恒为 false);改用 AX 索引 tab.click(index)。
tab.drag([x1,y1],[x2,y2]) 拖拽时,坐标必须落在**当前视口**内(本机内嵌浏览器视口很小,约 319×790),否则报 Coordinate is outside the active tab content viewport。
tab.click 的 AX 索引**在页面刷新后会失效**,可能命中别的控件;每次操作前重新 cua.getTab(...) 取新索引。
- 截图:
const fs = await import('fs'); fs.writeFileSync(path, Buffer.from(await tab.getScreenshot()))(require 不可用)。
- 改
.vue 后需要 tab.reload()。
- 临时脚本/文件(
_*.*)未经用户同意**不要删**。
十、Git 双仓库工作流
| 仓库 |
remote |
分支 |
地址 |
| 个人 |
origin |
master |
https://gitee.com/zhizhijie/traffic-audit.git |
| 公司 |
gitea |
main |
http://61.183.254.94:3000/r/trafficAudit.git(账号 zyj) |
每次改动的固定顺序:
1. 测试 + 写《功能测试报告》 + 更新《工作日结》;
2. git fetch origin → 合并个人仓库新提交(避免覆盖用户改动);
3. git fetch gitea → 与远端 main 对比合并 → 禁止强推;
4. git commit → git push。
- 凭据只走本机 git/临时 askpass,**禁止写进仓库任何文件**。
- 公司 gitea 网络不通时记录为遗留问题,**不要**用强推绕过。
十一、当前已知遗留问题(截至 2026-09-16)
| # |
问题 |
影响 |
状态 |
| 1 |
8 月源文件缺 2023 年 Sheet |
已用 7 月文件补录 2023-12 解决 |
已解决 |
| 2 |
2026-01 ~ 2026-07 的 last_* 为空 |
这几期改动前即为空,非本次引入 |
待用户确认是否补 |
| 3 |
2026-01 ~ 2026-07 的 H203-1 unified_credit_code / report_unit 为空 |
新列本期才读取,历史期未回填 |
待用户确认是否重导 |
| 4 |
预览弹窗「共 0 行」与「月度覆盖:1~8月均有数据」口径不同 |
易误解 |
待用户确认改文案 |
| 5 |
公司 gitea 推送 |
网络无响应,未推成功 |
待补推 |
| 6 |
仓库根目录大量 _*.* 临时文件 |
体积/可读性 |
经用户同意后再清理 |
2026-09-16 傍晚更新:遗留问题 4(预览弹窗「共 0 行」文案)已按用户确认修改完毕——汇总大表改为显示「指标 N 项」,其它报表显示「共 N 行明细」。
十二、2026-09-16 补充:货运页签「累计」列修复(重要口径)
12.1 母版派生口径(必须遵守)
《 货运》页行结构:
- 全省块:r5 货运量 / r6 周转量 / r7 其中规上货运量 / r8 其中规上周转量 / r9 其中规下货运量 / r10 其中规下周转量;
- 17 个市州块每块 6 行,首行 11,17,23,...,107(武汉市...林区),块内顺序:合计货运量 / 规上货运量 / 规下货运量 / 合计周转量 / 规上周转量 / 规下周转量。
规则:全省行必须完全由 17 市州行派生。
- r7 / r8 / r9 / r10 = SUM(17 市州对应行);
- r5 = m7+m9,r6 = m8+m10。
历史教训:r9/r10(全省规下)曾是**写死常量**,与 17 市州规下之和不等 —— 2023 差 4.6e-3、2022 差 3.1e-3、2021 差 1.5e-4(2024/2025/2026 恰好为 0),导致 6 个累计列里 2022/2023 比源文件人工核算差 0.003 左右、2021 整列为空。2026-09-16 已全部改为公式。
累计列现状(全省行,4 位小数与源文件一致):
| 列 |
年度 |
公式 |
| S |
2026(1-8月) |
C+E+G+I+K+M+O+Q |
| AT |
2025 |
V+X+...+AR |
| BV |
2024 |
AX+AZ+...+BT |
| CW |
2023 |
BY+CA+...+CU |
| DZ |
2022 |
=SUM(DM:DX)(原为写死常量) |
| EO |
2021 |
=SUM(EC:EN)(原为**空**) |
| EP |
2021 累计同比 |
保持为空(页内无 2020 块,无基期) |
| EA |
2022 累计同比 |
=IFERROR(DZ/SUM(EC:EN)-1, 空串)(原为写死常量) |
12.2 母版改动方式与文件职责
- 必须用 Excel COM(改公式 -> CalculateFullRebuild -> Save),**不可用 openpyxl 另存**:会清空全本公式缓存值(曾导致 2021 年湖北省行变 0)。
- 导出件里的公式**无缓存值**:openpyxl(data_only=True) 读出来全是 None,核对数值必须用 Excel COM 重算或自写求值器。
- 文件职责:
- YYYY年M月道路运输量汇总表.xlsx = 母版(唯一数据来源);
- 生成_道路运输量汇总表.xlsx = 只作列宽参照(applySummaryReferenceLayout 只读列宽/隐藏标记,不读数值);
- 2026年8月道路运输量汇总表_版式原型.xlsx = 运行时**无任何代码引用**。
- 同期备份母版还原机制:resolveSummaryDonor 只认文件名**以
_备份_ 开头且含「{年}月」**的文件,命中即整格回填覆盖母版。=> 自建的备份文件/目录**不要**用 _备份_ 前缀,否则可能被当成 donor 把母版改回旧值。
12.3 文本处理的坑(本机 PowerShell / git)
| 问题 |
原因 |
处置 |
| 公式被写成 =SUM(DM5) |
"$m7" 被解析为变量 m7;"$r:DX" 里的 $r:DX 被当成「驱动器 r:」而吞掉 |
一律用 ${m} / ${r} 定界 |
| 命令整体不执行、无输出、退出码 1 |
一个命令里出现**嵌套的单引号 here-string**,外层在第一个结束符处提前结束 |
一个命令只放一个 here-string;或先 Out-File 写补丁文件,再用 Get-Content -Raw |
| apply_patch 传多行参数失败 |
.bat 包装器破坏了多行参数 |
直接调 codex.exe --codex-run-as-apply-patch $patch |
| git commit -m 报 "outside repository" |
PowerShell 用反引号转义,消息里的反斜杠+引号会提前结束字符串 |
用 git commit -F <消息文件> |
| PS5.1 报乱码路径「无法找到 ...」 |
PS7 的 Out-File -Encoding utf8 写的是**无 BOM** UTF-8,PS5.1 按 GBK 读脚本 |
写 .ps1 时用 -Encoding utf8BOM |
12.4 遗留问题增量(截至 2026-09-16 晚)
| # |
问题 |
影响 |
状态 |
| 7 |
h2032_enterprise_monthly 2026-09 脏期(实为 8 月文件误存为 9 月) |
636 行 + import_batch 302 |
已删除,留可还原 SQL 备份 |
| 8 |
《 货运》页累计列 2021/2022/2023 对不上人工核算 |
已修母版派生口径,6 列全部对上 |
已解决 |
| 9 |
2026-09 期还在 h204_vehicle_quarterly(1284 行) / investment_monthly(31 行) / audit_result(2061 行) / audit_run(3 行) |
若按 2026-09 出报表会取到脏数据 |
待用户确认是否清理 |
| 10 |
2026-07 导出件《 货运》页为 118x145(比 8 月少 2 列) |
7 月母版是「1-4 月骨架」,非完整母版 |
待 7 月母版定稿 |
| 11 |
2026年8月道路运输量汇总表_版式原型.xlsx 的 S 列漏 8 月(缺 Q5) |
运行时未被引用,暂无影响 |
待确认该文件去留 |
| 12 |
母版经 Excel 重存后体积 959,706 -> 1,492,121 字节(导出件 950,186 -> 1,331,599) |
纯格式开销,数据无影响 |
记录 |
详见《功能测试报告/功能测试报告_货运页签累计列修复与脏期清理_2026-09-16.md》。
十三、2026-09-16 补充:2026-07 母版补齐 & 导出件「Excel 打不开」根因(P0)
13.1 症状与根因
| 项 |
内容 |
| 症状 |
GET /api/report/export/summaryWorkbook?period=2026-07&mode=month 生成的 xlsx,**Excel 打不开**(COM 报「不能取得类 Workbooks 的 Open 属性」;CorruptLoad=1 修复模式同样打不开);2026-08 同接口正常 |
| 直接原因 |
导出件里有 19 个模式非法格:<c r="E15" s="111" t="n"><v>67.0</v><is><t>67.00</t></is></c> —— t="n" 不允许带 <is>(inlineStr 专用) |
| 深层原因 |
7 月母版由 openpyxl 写出(docProps/app.xml = Microsoft Excel Compatible / Openpyxl 3.1.5,文本存 <is>);8 月母版是 Excel 原生(文本走 sharedStrings)。POI 的部分写入路径只改 t/<v>、不清旧 <is> |
| 触发路径 |
7 月存在 _备份_2026年7月道路运输量汇总表_清理前_20260904.xlsx → restoreSummaryMonthlyBlocks 整格回填 → 往 inlineStr 格里写值留下旧 <is>。8 月无 _备份_*,不走回填,故正常 |
| 命中位置 |
leave-one-out 定位到 sheet9《公交》17 格 + sheet12《轨道、轮渡》2 格 |
13.2 修复(traffic-audit-server)
exportSummaryWorkbook 新增 normalizeStaleInlineStrings(wb):落盘前清掉所有「非 inlineStr 却残留 <is>」的格子(幂等),命中即打 warn 日志。
restoreSummaryMonthlyBlocks 新增 skipFreightHistoryBlocks:《 货运》页 T 列及以后(2025/2024/2023/2022/2021 年度块 + 各年累计/累计同比列)**永不从备份母版回填** —— 与既有「中口径排名左块永不回填」同一思路,避免补齐被「生成又复活」。
13.3 2026-07 母版补齐(口径与 8 月母版对齐)
- 年度块(每列):
r7/r9/r8/r10 = SUM(17 市州对应行)、r5 = r7+r9、r6 = r8+r10 → 360 格;
- 累计列:
DX = SUM(DK:DV)(2022)、EM = SUM(EA:EL)(2021,原**整列为空**)、DY = IFERROR(DX/SUM(EA:EL)-1,"")(2022 累计同比,原为**写死常量**)→ 324 格;
- 2023 累计
CU = BW+BY+…+CS 本来就正确,未改;EN(2021 累计同比)按口径保持为空。
- 一手证据:母版
DX5=144979.2825(旧常量 144979.285376043,差 0.0029 = 全省规下常量与 17 市州之和的差)、EM5=161309.53162、CU5=173045.296428512,与 8 月母版 DZ5/EO5/CW5 完全相等。
- 备份:
docs/生成汇总大表/_bak_2026年7月道路运输量汇总表_补齐前_20260916.xlsx。**切勿改名为 _备份_ 开头**,否则会被 resolveSummaryDonor 当 donor 回填。
13.4 本次新增的排查坑
| 问题 |
原因 |
处置 |
| Excel COM 间歇性报同一个错,导致误判「8 月件也打不开」 |
每次 New-Object -ComObject Excel.Application 留下的**孤儿 EXCEL 进程**会污染后续实例 |
每例测完把「本次新建的 EXCEL 进程」强杀再测下一例;Quit()+ReleaseComObject 并不够 |
| 编译报「找不到 isSetSheetData()」 |
CTWorksheet.sheetData 是 XSD 必填元素,不生成 isSetXxx |
改用 ctw.getSheetData() != null |
| 部件级 diff 太大跑不动 |
对 519KB 的 styles.xml 直接 difflib 是 O(n²) |
先按部件比字节尺寸/是否相等,只在必要的小部件上做 diff |
13.5 遗留问题增量
| # |
问题 |
影响 |
状态 |
| 13 |
2026-06 / 2026-09 无母版 |
预览 ready=False「未找到模板文件」,无法出数 |
需先建母版(用户第 5 问的延伸) |
| 14 |
仓库根 _*.* 临时文件继续增多(_hyb_* / _loo_* / _v2_* / _final_* / _fixed_* / _t7_* / _poijar) |
体积/可读性 |
经用户同意后再清理 |
第 10 项(2026-07 导出件少 2 列 / 7 月母版是「1-4 月骨架」)本节已处理:导出端会**自动补出 5/6/7 月表头与公式**并重算累计公式,母版已补齐 2021/2022/2023 累计列,故关闭该项。