# 功能测试报告_全精度存储与两位小数显示_2026-09-20 ## 一、功能说明 **需求(用户 2026-09-20 指令)**:所有的数据都全部全精度保留,计算得到的结果显示两位小数。 **改前问题**: 1. 后端在**写单元格之前**就做了四舍五入,底层存储值被提前截断: - `round(v, 4)`:货运规上/规下/同比、累计与当月、中口径排名/分析、`÷10000` 单位换算、投资进度、物流占比、投资计划万吨; - `round(v, 2)`:通用数据格 `setDataCell`、平均运距兜底、客运转运写入; - `round(v, 1)`:排名页占比(`setFreightShare`、货运量排名/周转量排名块)。 误差虽小,但属于「计算口径被写死」,与人工用全精度重算的结果天然对不上(正是 09-19 中口径差异问题的同源风险)。 2. 母版个别格自带 3~4 位小数**显示格式**(`0.0000_);[Red]\(0.0000\)`、`0.000_ `),展示位数不统一。 **改后实现**: 1. **全精度**:取消所有写入/运算前的预舍入,数值以 `double` 原值参与运算并写入;`/10000`、占比、同比、平均运距兜底等一律不截断。 2. **两位小数展示**:由单元格数字格式承担。重写 `applyTwoDecimalFormat()`: - 数值格格式统一为 `0.00`(`cloneStyleFrom` 保留边框/字体/对齐,只换数字格式,`;[Red]\(...\)` 等前后缀原样保留); - **3 位及以上小数的格式**(`0.000_ `、`0.0000_);[Red]\(0.0000\)`)用正则 `\.0{3,}` 收敛为 `.00`; - 百分比(`%`)、科学计数(`E`)、文本(`@`)、日期格式**不动**; - 整数值格沿用既有约定不显示 `.00`(如年份、排名)。 3. 控制台/接口返回的**预览摘要**里的 `round`(`addSum(...)`)保留,它不进报表数据。 **改动文件**: | 文件 | 改动 | | --- | --- | | `traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java` | 去除 40 处预舍入;重写 `applyTwoDecimalFormat()`(新增 `DEC_MORE_THAN_TWO` 正则常量) | | `traffic-audit-server/src/main/java/com/trafficaudit/reportexport/calc/WycSplitCalc.java` | 平均运距兜底改全精度;删除已无引用的私有 `round(double,int)` | ## 二、测试环境 | 项 | 内容 | | --- | --- | | 后端 | Spring Boot `localhost:8090`,`mvn -q -o compile` 通过后由 `start-dev.ps1` 重启(PID 15568) | | 前端 | Vue `localhost:8080`(PID 28608),与后端一并重启 | | 数据库 | MySQL `localhost:3308/traffic_audit` | | 报表期 | 2026-08(1-8 月累计块 + 8 月单月块) | | 对照件 | 改前生成件 `_after_busfix_2026-08.xlsx`(09-19 口径修复后、本次改造前) | | 改后生成件 | `_after_precision_2026-08.xlsx`、`_after_precision_midrank/midana/middetail.xlsx`,以及 `_out_precision\` 下 22 个接口产物 | | 取证脚本 | `_qa_prec_*.py`、`_regen_precision.ps1`、`_regen_all.ps1` | ## 三、用例与结果 | 编号 | 类型 | 输入 | 预期 | 实际 | 结论 | | --- | --- | --- | --- | --- | --- | | T1 | 正向 | `mvn -q -o compile` | 编译通过 | exit=0,无告警 | 通过 | | T2 | 正向 | 22 个导出接口(period=2026-08) | 全部 200 且非空 | 21 个 OK;`wycSplit` 500(缺输入文件,见「四-5」) | 通过 | | T3 | 正向 | 改前/改后《道路运输量汇总表》逐格数值对比(66205 个共有数值格) | 仅目标格出现差异 | 实际变化 **249 格**,全部落在「货运量排名」107 +「中口径排名」142 | 通过 | | T4 | 正向 | 最大变化量 | 只应是去掉舍入带来的尾数差 | **0.00022 万人公里**(=2 人公里),位置「中口径排名」全省行 O3 | 通过 | | T5 | 正向 | 武汉累计周转量 | 全精度保留,4 位小数位仍为 8912 | 中口径明细 S104 = 152330.89119999998;排名页 O4 / 道路运输周转量 Q5 = 152330.8912 | 通过 | | T6 | 正向 | 孝感累计周转量 | 不再截断到 64429.9445 | 64429.944543113306(排名页与明细页逐位一致) | 通过 | | T7 | 正向 | 「中口径排名」改前/改后按两位小数对比 | 完全一致(不应改变可见结果) | 不一致格 **0** | 通过 | | T8 | 正向 | 全省行 `=SUM(O4:O20)` 闭合 | 缓存值 = 17 市州全精度求和 | 1227147.4890200002,**差 0.0**(09-19 的 0.0002 残留已消除) | 通过 | | T9 | 正向 | 汇总大表「有值数值/公式格」的 3 位以上小数格式 | 0 格 | 改前 108 格 → 改后 **0 格** | 通过 | | T10 | 正向 | 中口径明细(独立件)`0.000_ ` 格式格 | 收敛为两位 | 改前 134 格 → 改后 **0 格**;C19 值 13.599765541547498 不变,格式变 `0.00_ ` | 通过 | | T11 | 正向 | 22 个产物的 3 位以上小数格式汇总 | 全为 0 | 15 个可解析产物合计 **0 格** | 通过 | | T12 | 回归 | 表内错误值(`#DIV/0!`/`#VALUE!`/`#REF!`)数量 | 不新增 | 改前 589 = 改后 589(分布逐项相同) | 通过 | | T13 | 回归 | 百分比格 / 两位小数格数量 | 不受影响 | 25665 / 39552,与改前一致 | 通过 | | T14 | 回归 | 独立件 `passengerMidRank`、`passengerMidAnalysis` | 无 3 位以上小数格式 | 0 格(改前本就 0) | 通过 | | T15 | 边界 | 空值格、文本格(如月份文本「2023年4月」) | 不动 | 仍带 4 位小数格式 274 格(260 空值 + 14 文本),无显示值,不处理 | 通过 | | T16 | 边界 | 整数值格(年份/排名) | 不显示 `.00` | 沿用既有「整数不显示 .00」保护,未被本次改动破坏 | 通过 | | T17 | 边界 | 与 `round(改后,4)` 不一致的 30 格 | 属二阶重算而非错误 | 同比列由全精度分子分母重算,量级 1e-9~1e-8(如 0.0712378390 → 0.0712378363) | 通过 | | T18 | 负向 | 母版排名页 Q 列公式 `=ROUND(B/L*10,1)` | 本次不改母版 | 仍保留(36×2 格),Excel 打开会按公式重算到 1 位后再按 `0.00` 展示 | 见「四-4」待拍板 | ## 四、发现的问题与处置 1. **母版带 4 位小数格式的有值格 108 个**(`货运!EO90/EO93/EO108/EO111` 等 SUM 公式格、`公路总客运!DE2` 等)→ 已由格式归一处理为 `0.00`;剩余带该格式的 274 格均为空值/文本格,无显示值。 2. **「整数不显示 .00」保护先把公式格跳过了**:首轮改造后 `货运!EO90/EO93/EO108/EO111` 仍是 `0.0000`(缓存值为 0,被判定为整数而跳过)。已把「3 位以上小数格式归一」的判断**提到整数保护之前**——这类格本来就走数值格式展示,与「General 的整数值不显示 .00」不冲突。 3. **3 位小数格式未被识别**(`0.000_ `):原判断用 `f.contains("0.00")` 认为已是两位,而 `0.000_ ` 恰好包含子串 `0.00` 而被跳过,导致中口径明细 134 格漏改。已改为正则 `\.0{3,}` 统一收敛。 4. **母版排名页 Q 列仍是 `=ROUND(B/L*10,1)`**(货运量排名 Q4:Q42、货运周转量排名 Q5:Q44,共 72 格): 程序对公式格一律不覆写(保留母版公式设计),Excel/WPS 打开时会按公式重算回 1 位小数再以 `0.00` 格式展示。 若要连这 72 格也全精度,需要把三个母版的公式改成 `=B/L*10`(并同步 R 列 `=10-Q`)——**待用户确认后再动母版**。 5. **`wycSplit` 接口 500**:`loadWycMonthlyInput()` 抛「未找到网络约车(全省)汇总.xlsx,请放到 docs/网络客运 目录」,而 `docs\网络客运` 目录当前不存在——属**缺输入数据的既有现象**,与本次改造无关。 ## 五、结论 - 报表数值已全部改为**全精度写入/运算**,展示位数统一由单元格格式承担(两位小数;百分比、日期、文本格式不变)。 - 逐格对比证实:改后与改前的可见结果(两位小数口径)**完全一致**,差异仅出现在被去掉舍入的尾数位,最大 0.00022 万人公里。 - 顺带消除了 09-19 遗留的「全省行 0.0002 万人公里」:各市州改为全精度后,母版公式 `=SUM(O4:O20)` 与明细全精度求和**逐位闭合**。 - 22 个导出接口回归通过(`wycSplit` 为既有缺数据问题);错误值数量、百分比格数量均无变化。 - 遗留一项待拍板:母版排名页 Q/R 占比公式的 `ROUND(...,1)`。 测试人:Codex(AI) 测试日期:2026-09-20