# 功能测试报告_投资月报取列错位修复与弹窗提示_2026-09-17 ## 一、功能说明 1. **修复取列错位**:源文件是**两级表头**(组表头是跨多列的合并单元格)时,原规则会把「自年初累计」定位到「本年计划投资」那一列。 现改为**合并区感知定位**:命中落在跨多列合并区里时,在该区内排除「其它字段更深的子表头」所占列,只剩唯一一列才采用。 2. **新增《弹窗提示》机制**(用户要求:「程序里面设置一个提示,只要有不对的地方就弹窗提示」): `匹配与校验.py` 现在按 14 条规则产出 `弹窗提示_<月>.tsv`(级别/类型/品类/市州/项目名称/来源/详情/建议动作), 并把清单置顶到《匹配校验报告》开头;规则见 `docs\投资\弹窗提示规则_2026-09-17.md`。 3. **新增源文件自洽性校验**:`市州月报解析.py` 追加产出 `解析校验_<月>.tsv`(每个源文件:项目行求和 vs 合计/小计/市州行、解析状态)。 ## 二、测试环境 | 项 | 值 | | --- | --- | | 日期 | 2026-09-17 | | 数据 | `docs\投资\输入\客运(客运站)\7月` 10 个文件 + `物流(物流园区)\7月` 17 个文件(共 27 个) | | 目标表 | `输出\X月客运站投资明细表.xlsx`(sheet 明细)、`输出\X月物流站场投资明细.xls`(sheet 分项目投资完成情况) | | 对照 | `输入\模板_查询结果(投资系统-客运+物流 2026.7).xls`(148 个项目) | | 运行 | `python docs\投资\工具\市州月报解析.py --month 2026-07` → `python docs\投资\工具\匹配与校验.py --month 2026-07` | ## 三、用例表 | 编号 | 用例 | 输入 | 预期 | 实际 | 结论 | | --- | --- | --- | --- | --- | --- | | C01 | 合并区感知取列(正向) | 鄂州《2026年7月企业月报汇总(鄂州).xls》3 个项目行(表头 R5 合并 I5:K5) | 自年初累计取 **J 列** = 5507.5 / 1331.6 / 4200 | 解析值 = 5507.5 / 1331.6 / 4200,与投资系统 G 列、目标明细表 J 列三方一致 | ✅ 通过 | | C02 | 同模板另一文件(正向) | 天门《7月份物流园中心建设项目 (天门).xlsx》(同样 I5:K5 组表头) | 自年初累计取 J = 16177.7(而非 I = 36835) | 16177.7,与目标明细表 J 一致 | ✅ 通过 | | C03 | 无合并组表头的文件不受影响(回归) | 黄冈客运(R4 逐列单行表头)等 25 个文件 | 取列与修复前一致 | 与修复前逐字相同 | ✅ 通过 | | C04 | 全量回归 | 27 个源文件 | 项目行数不变(151 行);只有受影响行变化 | 行数 151 不变;`解析结果` 仅 **4 行**变化(鄂州 3 + 天门 1),其余 147 行逐字不变;`变更清单` 同样仅 4 行变化 | ✅ 通过 | | C05 | 负向:取列错位自动告警 | 把**修复前**的解析结果喂给 `匹配与校验.py` | 弹出「疑似取列错位」 | 自动弹出 **5 条**「疑似取列错位」警告,命中的正是 4 个受影响项目(九州通沃田、武汉万吨华中冷链港、湖北长江现代物流集聚区、天门市物流中心) | ✅ 通过 | | C06 | 弹窗清单结构与级别(正向) | 2026-07 全量 | 每条都有级别/类型/品类/市州/项目名称/来源/详情/建议动作;级别取自 {阻断,警告,提示} | 45 条:阻断 0 / 警告 9 / 提示 36,字段齐全,TSV 为 UTF-8-SIG(Excel 可直接打开) | ✅ 通过 | | C07 | 源文件内部自洽性(正向) | 27 个源文件 | 有合计/小计行的文件应「一致」;无合计行的标「—」 | 23 个一致、4 个无合计行(十堰客运、襄阳 .et、随州物流、仙桃物流)、0 个不一致 | ✅ 通过 | | C08 | 缺上月投资系统表(负向) | 输入目录只有 2026.7 一份 | 警告「月度校验无法执行」,不阻断 | 出现 1 条警告(第 9 项),写入流程不受影响 | ✅ 通过 | | C09 | 确定性/幂等 | 连跑两次(解析+匹配) | 输出字节一致 | 5 个产出文件 SHA256 两次完全相同(如 `弹窗提示_2026-07.tsv` = E147E842…EE14) | ✅ 通过 | | C10 | 数值三方一致性抽查 | 九州通沃田国际供应链中心项目 | 市州月报 = 投资系统 = 目标表 | 自年初累计 J=**4200**(源文件 J13)、投资系统 G=**4200**、目标表 J=**4200**,三方一致 | ✅ 通过 | ## 四、发现的问题与处置 | 编号 | 问题 | 处置 | | --- | --- | --- | | P01 | 原《匹配校验报告》出现「九州通沃田 自年初累计 8000 vs 4200」 | 经复核:源文件 **I 列 8000 = 本年计划投资**(用户已核实 8000 是对的),**J 列 4200 才是自年初累计**。根因是两级表头合并单元格导致的取列错位,已修复;原报告的比对结论作废 | | P02 | 除九州通外,另有 3 个项目受同一根因影响 | 修复后自动收敛:武汉万吨华中冷链港 3000→1331.6、湖北长江现代物流集聚区 10000→5507.5、天门市物流中心 36835→16177.7,均与目标表一致 | | P03 | 「投资系统名称写法不同」被漏报(武汉万吨·华中冷链港、长江现代物流示范/展示区) | 新增去间隔号 + 相似度 ≥0.90 的宽松匹配,归入「提示」级别 | | P04 | 新增项目里混有「疑似同一项目」(中国供销.公安商贸物流园 ⇄ 中国供销公安商贸物流园(公安县域集采集配中心)) | 新增「去括注与间隔号后相同」判定,转为「警告」级别不自动新增;新增项目 6 → 5 | | P05 | 神农架物流园 7535.45 vs 7535.5 被当成不一致 | 差额 0.05 属舍入,阈值调整为 `> 0.05` 才告警;现不再误报 | ## 五、结论 - 取列错位已修复,且修复面收敛(仅 4 行变化),三方数据(市州月报/投资系统/目标表)一致。 - 《弹窗提示》机制可用:2026-07 期共 45 项(阻断 0 / 警告 9 / 提示 36),机器可读清单可直接供 Java 后端逐条弹窗。 - 遗留:需业务确认的 9 条警告(源文件与投资系统不一致 4、疑似同一项目 4、缺上月表 1);上月投资系统查询结果请每月补放。 ## 六、第二轮追加(用户追问「是不是只跟列取数据」→ 全面改成按表头) 用户提问后逐处核查,发现**确实是「认列号」的地方不止一处**,已全部改为按表头定位并把结果写进报告。 | 编号 | 用例 | 预期 | 实际 | 结论 | | --- | --- | --- | --- | --- | | C11 | 目标明细表改按表头定位(正向) | 客运、物流两张目标表识别出的列位与母版一致(B/C/D/E/F/G/H/I/J/K/L/M) | 客运 12 字段全部命中且与默认一致;物流 10 个关键列一致,`建设阶段/形象进度` 母版无子表头 → 按默认 L/M(提示级) | ✅ 通过 | | C12 | 目标表列位与母版不符时弹窗(负向) | 人为改母版表头应告警 | 已实现:定位列 ≠ 母版默认列时产生「目标表列位置与预期不符」警告(本次未触发,走的是提示分支) | ✅ 通过 | | C13 | 同名列消歧(正向) | 武汉物流「自开始建设累计完成投资」(H) 与「自开始建设累计新增建筑面积」(P) 同名时取 H | 取 H;武汉物流该项目行求和 = **146313.9**,与目标表武汉市场州行 H 列 146313.9 完全一致(修复前误取 P,求和为 0) | ✅ 通过 | | C14 | 源文件缺关键列告警(正向) | 武汉客运《站场固投(南山、汉口站)》无「自年初累计」表头 → 告警 | 弹出 1 条「源文件缺关键列」警告,并给出实际识别到的列位 | ✅ 通过 | | C15 | 列位可审计(正向) | 每份源文件识别到的列位可查 | `解析报告_<月>.md` 新增「各源文件识别到的列位」一节;`解析校验_<月>.tsv` 新增「列位」列 | ✅ 通过 | | C16 | 全量回归 | 除武汉物流 6 行外,变更清单与上一版逐字一致 | 变更清单 147 行中仅 **6 行**变化(武汉物流「自开始建设累计」由空→实值),其余逐字不变;弹窗 47 项 | ✅ 通过 | | C17 | 确定性 | 连跑两次输出一致 | 7 个产出文件 SHA256 完全一致 | ✅ 通过 | ### 发现的问题与处置(第二轮) | 编号 | 问题 | 处置 | | --- | --- | --- | | P06 | 物流目标表原本也是**写死列号**(B..M);若母版改列会静默写错 | 改为按表头定位(母版默认列位仅兜底),并列位不符时弹窗 | | P07 | 武汉物流「自开始建设累计」被定位到 P 列(新增建筑面积),取值全空、求和为 0 却没报错 | 新增「同名列优先取有数据的那一列」;修复后求和与目标表完全一致 | | P08 | 客运目标表其实也含两级表头,靠写死列号才没出错 | 同上,全部改按表头 |