feat: 汇总大表日期格式/小数位复核+VBA列宽宏+DataView滚动加载+RULE_004双向与P005阈值联动

- 母版/导出日期锚点统一 yyyy年m月,修复货运页 CQ 列期次显示成数字;数值 0.00/排名 0、无 3/4 位小数、去底色全簿复验
- 新增 VBA 全工作表列宽自适应工具(docs/工具)
- DataView.vue:修复滚动容器识别(capture 监听 el-table body-wrapper),滚动到底自动加载更多;Chrome 真机 20→140 行验证
- AuditEngineService:RULE_004 改为双向(上月无→新增/上月有→消失均提醒),2026-07 实测新增6/消失3/双向1 家
- RuleManageController:规则名称/说明 ±N% 随阈值字段自动同步并持久化;P005 实测 20→30→20
- init.sql 种子同步(RULE_004 说明、P005 名称/说明/阈值20);新增要求与验收基线清单及本批测试报告、工作日结追加
7个文件已修改
3个文件已添加
290 ■■■■■ 已修改文件
docs/init.sql 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/功能测试报告/功能测试报告_汇总大表日期格式与规则联动及数据查看滚动加载_2026-09-08.md 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/工作日结/工作日结_2026-09-08.md 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/工具/VBA_生成物全表自动列宽_2026-09-08.txt 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/生成汇总大表/2026年7月道路运输量汇总表.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/生成汇总大表/2026年8月道路运输量汇总表.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/要求与验收基线清单.md 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-server/src/main/java/com/trafficaudit/auditengine/service/AuditEngineService.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-server/src/main/java/com/trafficaudit/rulemanage/controller/RuleManageController.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-web/src/views/DataView.vue 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/init.sql
@@ -290,7 +290,7 @@
('车辆数运政对比', 'RULE_001', '企业上报车辆数与运政数据对比,差距>5台需核实', 'vehicleTotal', 'DIFF', '5', 'RED', 'H2032', 1, 1),
('吨位运政对比', 'RULE_002', '企业上报吨位与运政数据对比,差距>50需核实', 'tonsTotal', 'DIFF', '50', 'RED', 'H2032', 1, 2),
('周转量轨迹对比', 'RULE_003', '上报周转量与轨迹测算周转量对比,高出30%需核实', 'turnoverTotal,trackMileage', 'RATIO', '1.3', 'RED', 'H2032', 1, 3),
('货运类型环比', 'RULE_004', '本月新增货运类型需核实(上月为0、本月有量)', 'freightContainer,freightCoal,freightOilGas,freightCrudeOil,freightMetalOre,freightIronOre,freightBuilding,freightGrain', 'MOM', '0', 'YELLOW', 'H2032', 1, 4),
('货运类型环比', 'RULE_004', '上月无,本月新增,提醒;上月有,本月无,提醒(货运类型环比)', 'freightContainer,freightCoal,freightOilGas,freightCrudeOil,freightMetalOre,freightIronOre,freightBuilding,freightGrain', 'MOM', '0', 'YELLOW', 'H2032', 1, 4),
('集装箱异常', 'RULE_005', '无集装箱车但有集装箱货运量需核实', 'freightContainer,vehicleContainer', 'NULL_CHECK', '0', 'RED', 'H2032', 1, 5),
('整车吨位范围', 'RULE_006', '整车吨位不在4-40吨之间', 'tonsWhole', 'OUT_RANGE', '4,40', 'YELLOW', 'H2032', 1, 6);
@@ -446,7 +446,7 @@
('载客位数运政对比(旅客)', 'RULE_P002', '核定载客位数与运政载客位数对比,差距>50需核实', 'seatTotal', 'DIFF', '50', 'RED', 'H2031', 1, 22),
('客运量环比=0核实', 'RULE_P003', '一类/二类/三类/四类/包车客运量环比上个月等于0需核实', 'passengerClass1,passengerClass2,passengerClass3,passengerClass4,passengerCharter', 'MOM_EQ_ZERO', '0', 'YELLOW', 'H2031', 1, 23),
('旅客周转量环比=0核实', 'RULE_P004', '一类/二类/三类/四类/包车旅客周转量环比上个月等于0需核实', 'turnoverClass1,turnoverClass2,turnoverClass3,turnoverClass4,turnoverCharter', 'MOM_EQ_ZERO', '0', 'YELLOW', 'H2031', 1, 24),
('平均运距环比超±10%核实', 'RULE_P005', '一类/二类/三类/四类平均运距环比上个月超过±10%需核实', 'avgDistanceClass1,avgDistanceClass2,avgDistanceClass3,avgDistanceClass4', 'MOM_PCT', '10', 'YELLOW', 'H2031', 1, 25),
('平均运距环比超±20%核实', 'RULE_P005', '一类/二类/三类/四类平均运距环比上个月超过±20%需核实', 'avgDistanceClass1,avgDistanceClass2,avgDistanceClass3,avgDistanceClass4', 'MOM_PCT', '20', 'YELLOW', 'H2031', 1, 25),
('包车平均运距等于上月核实', 'RULE_P006', '旅游包车平均运距等于上个月需核实', 'avgDistanceCharter', 'MOM_EQ', '0', 'YELLOW', 'H2031', 1, 26),
('无班线有班线客运量核实', 'RULE_P007', '无客运班车(班线车辆数为0)但有班线客运量需核实', 'vehicleSchedule,passengerClass1,passengerClass2,passengerClass3,passengerClass4', 'EXISTENCE', '0', 'RED', 'H2031', 1, 27),
('无包车有包车客运量核实', 'RULE_P008', '无客运包车(包车车辆数为0)但有包车客运量需核实', 'vehicleCharter,passengerCharter', 'EXISTENCE', '0', 'RED', 'H2031', 1, 28);
docs/¹¦ÄܲâÊÔ±¨¸æ/¹¦ÄܲâÊÔ±¨¸æ_»ã×Ü´ó±íÈÕÆÚ¸ñʽÓë¹æÔòÁª¶¯¼°Êý¾Ý²é¿´¹ö¶¯¼ÓÔØ_2026-09-08.md
New file
@@ -0,0 +1,49 @@
# åŠŸèƒ½æµ‹è¯•æŠ¥å‘Š_汇总大表日期格式与规则联动及数据查看滚动加载_2026-09-08
- åŠŸèƒ½èŒƒå›´ï¼šæœ¬æ‰¹ 7 é¡¹è¦æ±‚(日期统一显示、VBA åˆ—宽宏、数据查看滚动加载、小数位/排名复核、要求基线清单、RULE_004 åŒå‘提醒、RULE_P005 é˜ˆå€¼ä¸Žåç§°/说明联动)
- æµ‹è¯•环境:本机 traffic-audit(后端 8090、前端 8080 çƒ­ç¼–译运行中);MySQL 5.7 @ localhost:3308 traffic_audit;Chrome å†…嵌浏览器真机(Playwright/CUA)实测 UI
- éªŒè¯åŸºçº¿ï¼š`docs/要求与验收基线清单.md`;决策基线《确认回执汇总…_2026-09-07》
## ç”¨ä¾‹ä¸Žç»“论
| # | ç”¨ä¾‹ï¼ˆè¾“入) | é¢„期 | å®žé™… | ç»“论 |
|---|---|---|---|---|
| 1 | ç”Ÿæˆæ±‡æ€»å¤§è¡¨ 2026-07/08,检查货运页 CQ åˆ—等日期锚点显示 | æœŸæ¬¡æ˜¾ç¤º `yyyy"å¹´"m"月"`,不得显示成数字 | ä¸¤æ–‡ä»¶å…¨ç°¿æ‰«æï¼šæ—¥æœŸåž‹å•元格坏格式=0;`货运`页 CQ3 ç­‰ = datetime(2023-10-01) ä¸”格式 `yyyy"å¹´"m"月"`;无 General æ•°å­—残留 | âœ… é€šè¿‡ |
| 2 | å…¨ç°¿æ ¼å¼ä½“检(导出的 7/8 æœˆå¤§è¡¨ï¼‰ | æ•°å€¼ 0.00 / ç™¾åˆ†æ¯” 0.00% / æŽ’名 0;无 3/4 ä½å°æ•°ã€æ— åº•色 | bad3=0、General æ•°å€¼=0、fills=0(两份文件) | âœ… é€šè¿‡ |
| 3 | æŽ’名与数值尾数抽查:货运量排名/货运周转量排名/中口径排名/道路运输周转量 | æŽ’名整列整数,数值列显示两位小数且保留全精度 | è´§è¿é‡æŽ’名 C/F/H/K/M/P åˆ—格式 `0`(34 è¡Œï¼‰ï¼›è´§è¿å‘¨è½¬é‡æŽ’名/道路运输周转量排名为 `=RANK()(0)` å…¬å¼åˆ—;数值/同比列 0.00/0.00%;周转量无 3/4 ä½å°æ•° | âœ… é€šè¿‡ |
| 4 | VBA å®äº¤ä»˜ç‰© | æä¾›å¯å¯¼å…¥æ¨¡å—,含全表/当前表两个宏与用法 | `docs/工具/VBA_生成物全表自动列宽_2026-09-08.txt`(AutoFitAllSheets + AutoFitActiveSheet + è¯´æ˜Žï¼‰ | âœ… é€šè¿‡ |
| 5 | æ•°æ®æŸ¥çœ‹é¡µæ»šåŠ¨åˆ°åº•è‡ªåŠ¨åŠ è½½ | æ™®é€š/全屏滚动至底部追加下一页,行数递增、总数不变、无 JS æŠ¥é”™ | Chrome çœŸæœºï¼šè¡Œæ•° 20→40→60→80→100→120→140,共 13056 æ¡ä¸å˜ï¼›æŽ§åˆ¶å° error/warning=0 | âœ… é€šè¿‡ |
| 6 | RULE_004 åŒå‘(货运类型环比)审核 2026-07 | ä¸Šæœˆæ— â†’本月有、上月有→本月无均提醒 | å‘½ä¸­ 7 å®¶ï¼šæ–°å¢ž 6、消失 3(1 å®¶åŒå‘);样例 `91420700090568838U æœ¬æœˆæ¶ˆå¤±: é›†è£…箱(上月=32210,本月无)` ä¸Žåº“中 6/7 æœˆæ•°æ®é€å­—吻合;`91429006793269842X` æ–°å¢žç…¤ç‚­+消失油气双向命中且吻合 | âœ… é€šè¿‡ |
| 7 | RULE_P005 é˜ˆå€¼è”动:20 â†’ 30 â†’ 20 | åç§°/说明里的 Â±N% éšé˜ˆå€¼è‡ªåŠ¨æ”¹å†™å¹¶æŒä¹…åŒ– | åˆ—表 20 æ—¶åç§°=平均运距环比超±20%核实;改 30 åŽåˆ—表与 DB å‡ä¸º Â±30%;改回 20 æ¢å¤ Â±20%;DB id=11 threshold=20 æŒä¹…化确认 | âœ… é€šè¿‡ |
## å…³é”®æ•°æ®ä¸ŽæŠ½æŸ¥è¯æ®
- æ ¼å¼ä½“检(两份导出)汇总行:`SUM: bad3=0 genNum=0 dtBadFmt=0`,各排名页格式 TOP è§ä¸‹è¡¨ï¼š
  - è´§è¿é‡æŽ’名:`0`×204 / `0.00`×108 / `0.00%`×210
  - è´§è¿å‘¨è½¬é‡æŽ’名:`0.00`×85 / `0.00%`×108(排名列为 RANK å…¬å¼ï¼Œæ ¼å¼ 0)
  - é“路运输周转量:`0.00`×216 / `0.00%`×107,无 3/4 ä½å°æ•°
- RULE_004 åº“核对 SQL:6/7 æœˆå„ 636 å®¶ï¼›å®¡æ ¸ç»“果(`audit_result` join `audit_rule` id=4)2026-07 å…± 7 æ¡ï¼š
  - `本月新增: é›†è£…ç®±=9716`、`本月新增: é“çŸ¿çŸ³=2114`、`本月消失: é›†è£…箱(上月=32210,本月无)`、
  - `本月新增: é‡‘属矿石=223041`、`本月新增: çŸ³æ²¹å¤©ç„¶æ°”及制品=10757;本月消失: ç…¤ç‚­åŠåˆ¶å“ï¼ˆä¸Šæœˆ=10137,本月无)`、
  - `本月新增: ç…¤ç‚­åŠåˆ¶å“=20231;本月消失: çŸ³æ²¹å¤©ç„¶æ°”及制品(上月=22310,本月无)` ç­‰
- RULE_P005 API åºåˆ—:`GET /api/rules/list?reportType=H2031`(id=11)threshold=20 åç§°Â±20% â†’ `POST /api/rules/update {id:11,threshold:"30"}` åŽåç§°/描述±30% â†’ æ”¹å›ž 20 åŽæ¢å¤ Â±20%;`audit_rule` è¡¨æ ¸å¯¹ä¸€è‡´ã€‚
- æ•°æ®æŸ¥çœ‹ï¼š`GET /api/data/list?type=h2032&page=1&size=20` total=13056、页间 0 é‡å¤ï¼›UI æ»šåŠ¨å®žæµ‹è§ #5。
## æ¶‰åŠæ”¹åЍ
- `docs/生成汇总大表/2026å¹´7月道路运输量汇总表.xlsx`、`2026å¹´8月道路运输量汇总表.xlsx`(版式归一:日期锚点/0.00/排名 0/去底色,本次复验导出按此母版)
- `traffic-audit-server/.../auditengine/service/AuditEngineService.java`(RULE_004 æ–°å¢ž/消失双向)
- `traffic-audit-server/.../rulemanage/controller/RuleManageController.java`(阈值 Â±N% â†’ åç§°/说明联动)
- `traffic-audit-web/src/views/DataView.vue`(滚动捕获监听修复 + åŠ è½½æ›´å¤šï¼Œè§ä¸‹ï¼‰
- `docs/init.sql`(RULE_004 è¯´æ˜Žã€RULE_P005 åç§°/说明种子同步)
- `docs/工具/VBA_生成物全表自动列宽_2026-09-08.txt`(新增)
- `docs/要求与验收基线清单.md`(新增,含本批登记)
## ä¿®å¤è¿‡ç¨‹è®°å½•(DataView)
- åˆç‰ˆä»…监听 window ä¸Ž `.table-wrap`;实测发现普通/全屏下真正滚动容器是 el-table å†…部 `.el-table__body-wrapper`(overflow-y:auto),初版在普通模式不会触发。
- ä¿®å¤ï¼š`onScroll` æ”¹ä¸ºå–事件 target çš„实际滚动容器度量(scrollTop/clientHeight/scrollHeight),scroll ç›‘听加 `capture:true`(scroll ä¸å†’泡但可捕获),mounted/beforeDestroy æˆå¯¹æ³¨å†Œ/移除。
- ä¿®å¤åŽ Chrome çœŸæœºå¤æµ‹ï¼ˆè§ #5)通过,控制台无异常。
## å‘现的问题与处置
- æ— é˜»å¡žé—®é¢˜ã€‚待办沿用基线:8 æœˆæ•°æ®å¯¼å…¥åŽ M2/M3 å¡«å€¼å¤éªŒï¼›æ—¥æœŸé”šç‚¹åœ¨ 8 æœˆæ¯ç‰ˆä¸­æ˜¾ç¤ºä¸ºåºåˆ—号期的显示口径已在基线 F3 å…³é—­ã€‚
## ç»“论
本批 7 é¡¹è¦æ±‚全部实现并通过实测,可交付。相关产物:导出验证文件在 `docs/生成汇总大表/输出/生成_道路运输量汇总表_2026-07_格式验证.xlsx` ä¸Ž `_2026-08_格式验证.xlsx`。
docs/¹¤×÷ÈÕ½á/¹¤×÷ÈÕ½á_2026-09-08.md
@@ -58,4 +58,19 @@
- `mvn -q -DskipTests compile` exit=0。
### é—留与下一步
- 8 æœˆå½“月数据导入后按 M2/M3 å¡«å€¼å¤éªŒï¼›æ—¥æœŸé”šç‚¹åˆ—(原表 General åºåˆ—号期次行)显示方式待业务确认。
- ä¸´æ—¶è„šæœ¬ `_unify_all.py` åŠ `_test_tmp/` å‰¯æœ¬ä¸åˆ ä¸å…¥åº“。
- ä¸´æ—¶è„šæœ¬ `_unify_all.py` åŠ `_test_tmp/` å‰¯æœ¬ä¸åˆ ä¸å…¥åº“。
---
## è¡¥å……(2026-09-08 æ™šé—´ï¼ŒåŒä¸€ä¼šè¯ç»­ï¼‰ï¼šæ—¥æœŸæ ¼å¼/小数复核/VBA/滚动加载/规则双向与阈值联动
### ä»Šæ—¥æ–°å¢ž
1. **日期锚点统一**:7/8 æœˆæ¯ç‰ˆä¸Žå¯¼å‡ºå…¨ç°¿æ—¥æœŸåž‹å•元格统一 `yyyy"å¹´"m"月"`,修复货运页 CQ åˆ—等期次显示成数字的问题(全簿扫描日期坏格式=0)。
2. **小数位/排名复核(约定:数值保留全精度显示 0.00,排名整数 0)**:导出 2026-07/08 å¤éªŒâ€”—无 3/4 ä½å°æ•°ã€æ—  General æ•°å€¼ã€æ— åº•色;货运量排名列 `0`,周转量/道路运输周转量排名为 RANK å…¬å¼åˆ—格式 `0`。
3. **VBA åˆ—宽宏交付**:`docs/工具/VBA_生成物全表自动列宽_2026-09-08.txt`(AutoFitAllSheets/AutoFitActiveSheet)。
4. **数据查看滚动加载修复+真机验证**:定位真正滚动容器为 el-table å†…部 body-wrapper,onScroll å–事件 target åº¦é‡ + capture ç›‘听;Chrome çœŸæœºæ»šåЍ 20→40→…→140 è¡Œé€’增、总数 13056 ä¸å˜ã€æŽ§åˆ¶å° 0 æŠ¥é”™ã€‚
5. **RULE_004 åŒå‘**:上月无→本月新增、上月有→本月无均提醒;2026-07 å®žæµ‹å‘½ä¸­ 7 å®¶ï¼ˆæ–°å¢ž 6、消失 3、1 å®¶åŒå‘),消失样例与库数据逐字吻合。
6. **RULE_P005 é˜ˆå€¼è”动**:名称/说明 Â±N% éšé˜ˆå€¼å­—段同步并持久化(实测 20→30→20,DB å¤æ ¸ä¸€è‡´ï¼‰ï¼Œå…¶å®ƒå« Â±N% è§„则同理。
### æµ‹è¯•结果摘要
- è¯¦è§ã€ŠåŠŸèƒ½æµ‹è¯•æŠ¥å‘Š_汇总大表日期格式与规则联动及数据查看滚动加载_2026-09-08.md》。
- `mvn` ç¼–译通过(前一交接已完成);前端热编译 3 æ¬¡æˆåŠŸï¼ˆ15:19/15:24)。
### é—留与下一步
- 8 æœˆå½“月数据导入后 M2/M3 å¡«å€¼å¤éªŒï¼›ä¸´æ—¶è„šæœ¬ `_verify_*.py/.sql`、`_do_patch1.py` ä¸åˆ ä¸å…¥åº“。
docs/¹¤¾ß/VBA_Éú³ÉÎïÈ«±í×Ô¶¯Áпí_2026-09-08.txt
New file
@@ -0,0 +1,39 @@
VBA å®ï¼šç”Ÿæˆæ±‡æ€»å¤§è¡¨ï¼ˆæˆ–任意工作簿)全工作表列宽自适应
日期:2026-09-08
说明:打开要处理的 xlsx â†’ Alt+F11 â†’ èœå•“插入→模块” â†’ ç²˜è´´ä»¥ä¸‹ä»£ç  â†’ å…³é—­ç¼–辑器 â†’ Alt+F8 è¿è¡Œ AutoFitAllSheets。
      ä¹Ÿå¯å°†æœ¬æ–‡ä»¶å¦å­˜ä¸º .bas,在 VBA ç¼–辑器里“文件→导入文件”。
--------------------------------------------------------------------------------
Option Explicit
' ä¸»å®ï¼šå¯¹å…¨éƒ¨å·¥ä½œè¡¨åšæ•´åˆ—列宽自适应(公式先整体重算,以显示值宽度为准)
Public Sub AutoFitAllSheets()
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationAutomatic
    Application.CalculateFullRebuild
    Dim ws As Worksheet
    For Each ws In ThisWorkbook.Worksheets
        ws.Activate
        On Error Resume Next
        ' è‡ªåŠ¨é€‚åº”æ•´åˆ—å®½åº¦ï¼ˆéšè—è¡Œ/列不影响;合并单元格内的文字不会被 Excel è‡ªåŠ¨è®¡å…¥ï¼‰
        ws.Cells.EntireColumn.AutoFit
        On Error GoTo 0
    Next ws
    Application.ScreenUpdating = True
    MsgBox "全部工作表列宽自适应完成。", vbInformation, "完成"
End Sub
' å¤‡ç”¨å®ï¼šåªå¯¹â€œå½“前选中的工作表”执行自适应
Public Sub AutoFitActiveSheet()
    Application.ScreenUpdating = False
    Application.CalculateFullRebuild
    ActiveSheet.Cells.EntireColumn.AutoFit
    Application.ScreenUpdating = True
    MsgBox "当前表列宽自适应完成。", vbInformation, "完成"
End Sub
--------------------------------------------------------------------------------
注意:
1) è¿è¡Œå‰å…ˆå…¨é€‰çœ‹ä¸€éæ˜¯å¦æœ‰â€œ###”溢出列;若个别列因合并标题仍偏窄,可手动拖一下该列。
2) æœ¬å®åªæ”¹åˆ—宽,不改任何数据、公式、底色与边框。
3) å»ºè®®ç”ŸæˆåŽç«‹åˆ»è¿è¡Œä¸€æ¬¡ï¼Œå†å¦å­˜ä¸ºæ­£å¼äº¤ä»˜æ–‡ä»¶ã€‚
docs/Éú³É»ã×Ü´ó±í/2026Äê7ÔµÀ·ÔËÊäÁ¿»ã×ܱí.xlsx
Binary files differ
docs/Éú³É»ã×Ü´ó±í/2026Äê8ÔµÀ·ÔËÊäÁ¿»ã×ܱí.xlsx
Binary files differ
docs/ÒªÇóÓëÑéÊÕ»ùÏßÇåµ¥.md
New file
@@ -0,0 +1,63 @@
# è¦æ±‚与验收基线清单(干活前必读)
> ç”¨é€”:汇总用户(业务)陆续提出的**明确要求/口径**,每次改代码/母版/规则前先对照本表,避免“做一半、漏口径、重复问”。
> åŸºçº¿æ–‡æ¡£ï¼šã€Šç¡®è®¤å›žæ‰§æ±‡æ€»ä¸Žå‰©ä½™ç–‘é—®_汇总大表数据驱动改造_2026-09-07.md》(唯一决策基线,第六节为 09-08 æ‹æ¿ï¼‰ã€‚
> ç»´æŠ¤ï¼šä¼šè¯æŽ¨è¿›æ—¶åŒæ­¥å¢žè¡¥ï¼›çŠ¶æ€ï¼šâœ…å·²å®žçŽ° / ðŸš§è¿›è¡Œä¸­ / â¬œå¾…办。
## ä¸€ã€æ±‡æ€»å¤§è¡¨ç‰ˆå¼ä¸Žç”Ÿæˆå£å¾„
| ç¼–号 | è¦æ±‚/口径 | çŠ¶æ€ | å¤‡æ³¨ |
|---|---|---|---|
| F1 | æ•°å€¼ï¼ˆå«å…¬å¼ç»“果)一律**显示两位小数**(0.00),但**保留全精度小数**,不得四舍五入改值 | âœ… 2026-09-08 | 7/8月母版+导出已验:无 3/4 ä½å°æ•°æ®‹ç•™ |
| F2 | **排名一律显示整数**(0 æ ¼å¼ï¼Œå«å¢žé€ŸæŽ’名) | âœ… 2026-09-08 | è¡¨å¤´â€œæŽ’名/增速排名”(允许带空格)整列生效 |
| F3 | æ—¥æœŸ/期次类单元格统一显示 **yyyy"å¹´"m"月"**(如货运页 CQ åˆ—等日期锚点不得显示成数字) | âœ… 2026-09-08 | æ¯ç‰ˆ+导出均验 |
| F4 | èƒŒæ™¯è‰²å…¨éƒ¨ç»Ÿä¸€ï¼ˆ**无填充/去底色**),生成产物不得从还原源带旧底色复活 | âœ… 2026-09-08 | è¿˜åŽŸæºå¤‡ä»½åŒåšå½’ä¸€ |
| F5 | åˆ—宽按显示内容**自适应**;长公式文本不得撑爆列宽;生成的最终表可在 Excel é‡Œè·‘ VBA å…¨è¡¨è‡ªé€‚应 | âœ… 2026-09-08 | VBA è§ `docs/工具/VBA_生成物全表自动列宽_2026-09-08.txt` |
| F6 | ç”Ÿæˆé“¾è·¯ = å¤åˆ¶æ¯ç‰ˆâ†’填值/还原;**母版文件本身不带业务数据作伪装**,数据一律由导入+计算写入 | ðŸš§ æŽ¨è¿›ä¸­ | ä¾ã€Šç¡®è®¤å›žæ‰§ã€‹E1 å…ˆå›žå½’7月再填8月 |
| F7 | æ±‡æ€»å¤§è¡¨å«å½“月 + 1-X月累计 + åŒæ¯”;排名/分析表需当月与累计两套 | âœ…(当月+累计结构) | å½“月排名修正已入 M2 éªŒè¯ |
| F8 | 2025 å¹´å‰æ•°æ®ä»¥æ¯ç‰ˆç¼“存为准;**母版缓存优先作同比基准**,库只做校验,人工核对重导一致后才切库值(Q1) | âœ… å£å¾„确认 | |
| F9 | å†…部计算页不对外;货运/公路旅客/城市客运小表前端全部隐藏(内部中间表保留) | âœ… æ‹æ¿ | |
| F10 | æ‰©åˆ—按月按需(加月份才扩列,不预做 12 æœˆæ»¡ç‰ˆï¼‰ï¼›æ–°å¢žåˆ—“当月/同比”标题为两行合并单元格,扩列须保留 | âœ… M0 v4 | |
| F11 | åŒæ¯”无数据的“增速为 0 éœ€æ ¸å®žâ€ç±»è§„则已入公交/出租/货运/旅客审核规则(补充规则类先缓) | ðŸš§ | å®¡æ ¸è§„则类近期以导入与报表为先 |
## äºŒã€æ•°æ®å¯¼å…¥
| ç¼–号 | è¦æ±‚ | çŠ¶æ€ | å¤‡æ³¨ |
|---|---|---|---|
| I1 | å¯¼å…¥è¿‡ç¨‹æ˜¾ç¤º**进度**;导入失败提示到**行号** | âœ… | |
| I2 | å…è®¸é‡å¤å¯¼å…¥ï¼ˆé‡æ–°å¯¼å…¥è¦†ç›–) | âœ… æ‹æ¿ | |
| I3 | åŸŽå¸‚客运导入类型下拉需含:**公交/出租月报、网约车拆分、网约车订单、全省总量等**模板 | âœ… å·²åŠ  | æ¯ç‰ˆåœ¨ `docs/城市客运` |
| I4 | å¯¼å…¥æ¨¡æ¿å·®å¼‚(企业代码/单位详细名称列有无)要与三种模板的差异兼容 | âœ… å·²å…¼å®¹ | è§ 09-04 æµ‹è¯•报告 |
| I5 | æ•°æ®æŸ¥çœ‹ï¼š**滚动到底部自动加载并显示更多行**(全屏/普通模式均可翻页) | âœ… 2026-09-08 | DataView.vue ä¿®å¤æ»šåЍ容噍+capture ç›‘听;Chrome çœŸæœº 20→140 è¡Œé€’增验证 |
## ä¸‰ã€æŠ¥è¡¨ç”Ÿæˆ
| ç¼–号 | è¦æ±‚ | çŠ¶æ€ | å¤‡æ³¨ |
|---|---|---|---|
| R1 | é€æœˆæ‰©å±•生成;保留母版缓存与母版程序复制;累计公式去掉未到月份、同比分母联动 | âœ… M0/M1 | |
| R2 | ç”Ÿæˆâ€œé“路运输量汇总表(整本)”= å½“月表 + ç´¯è®¡ï¼ˆ1-X月)| âœ… | |
| R3 | ç”Ÿæˆç‰©ä¸Žæ¯ç‰ˆ/库 0 å·®å¼‚为验收标准(含中口径分析页、排名页累计块) | âœ… 7月回归 | |
| R4 | ç‹¬ç«‹å°è¡¨ä¿ç•™ä½†å‰ç«¯éšè—ï¼Œç­‰å¤§è¡¨è·‘通后可取消 | âœ… æ‹æ¿ | |
| R5 | æŽ’名/分析/汇总的**当月数据**要与累计数据分别计算,禁止把累计值当当月值 | ðŸš§ M2/M3 å®žå¼¹ | |
## å››ã€å®¡æ ¸è§„则
| ç¼–号 | è¦æ±‚ | çŠ¶æ€ | å¤‡æ³¨ |
|---|---|---|---|
| A1 | RULE_004(货运类型环比):**上月无→本月新增,提醒;上月有→本月无,提醒**(双向) | âœ… 2026-09-08 | å¼•擎+DB+init.sql å·²æ”¹ï¼›2026-07 å®žæµ‹ï¼šæ–°å¢ž6/消失3/双向1 å®¶ï¼Œä¸Žæºæ•°æ®å»åˆ |
| A2 | è§„则名称/说明里的阈值(±N%)**随阈值字段改动自动同步**(如 Â±10%→±20%),其它含阈值规则同理 | âœ… 2026-09-08 | å®žæµ‹ 20→30→20:名称/说明随动并持久化;DB id=11 å¤æ ¸ä¸€è‡´ |
| A3 | æ•´è½¦å¨ä½åˆ¤å®šç”¨**平均吨位=整车吨位/整车数**,区间 4-40 | âœ… | 09-04 ä¿®å¤ |
| A4 | å®¡æ ¸ç»“果里的异常数值要可解释(如“轨迹测算=1.04E7”需给出算法说明/口径标注) | â¬œ | å£å¾„解释页推进中 |
## äº”、工作纪律与交付
| ç¼–号 | è¦æ±‚ | çŠ¶æ€ |
|---|---|---|
| W1 | æ¯å®Œæˆä¸€ä¸ªåŠŸèƒ½ï¼šç«‹å³æµ‹è¯•å¹¶å†™ã€ŠåŠŸèƒ½æµ‹è¯•æŠ¥å‘Š_<功能>_<日期>.md》到 `docs/功能测试报告/` | âœ… å¸¸æ€æ‰§è¡Œ |
| W2 | æ¯å¤©ä¸‹ç­å†™ã€Šå·¥ä½œæ—¥ç»“_<日期>.md》到 `docs/工作日结/` | âœ… å¸¸æ€æ‰§è¡Œ |
| W3 | å¹²æ´»å‰è¯»æœ¬æ¸…单与《确认回执汇总…》,已确认项不再重复向用户提问 | âœ… æ‰§è¡Œ |
| W4 | ä¸ªäºº gitee(origin) æœ‰æ”¹åŠ¨å…ˆ fetch/合并;公司 gitea(main) å…ˆæµ‹è¯•+报告→合并→commit→push,禁强推 | âœ… æ‰§è¡Œ |
## å…­ã€æœ¬ä¼šè¯ï¼ˆ2026-09-08 ä¸‹åˆ/晚间)处理登记
1. æ—¥æœŸé”šç‚¹ç»Ÿä¸€ yyyyå¹´m月(F3)+ ä¿®å¤è´§è¿é¡µ CQ åˆ—日期显示成数字的问题;
2. æä¾›å…¨è¡¨åˆ—宽自适应 VBA(F5);
3. DataView æ»šåŠ¨åˆ°åº•åŠ è½½æ›´å¤šï¼ˆI5);
4. æŽ’名/小数位格式复核(F1/F2:货运量排名排名=整数、周转量排名数据=0.00、道路运输周转量无 3/4 ä½å°æ•°ï¼‰ï¼›
5. æœ¬æ¸…单建立(W3);
6. RULE_004 åŒå‘提醒(A1);RULE_P005 é˜ˆå€¼ 20% ä¸Žåç§°/说明联动(A2)。
7. æœ¬æ‰¹å®žæµ‹æ”¶å£ï¼šå…¨ç°¿æ ¼å¼ä½“检(bad3/General/底色=0)、RULE_004 åŒå‘ 2026-07 å‘½ä¸­æ ¸å¯¹ã€P005 è”动 20→30→20、DataView Chrome çœŸæœºæ»šåŠ¨åŠ è½½ 20→140 è¡Œâ€”—详见《功能测试报告_汇总大表日期格式与规则联动及数据查看滚动加载_2026-09-08.md》。
traffic-audit-server/src/main/java/com/trafficaudit/auditengine/service/AuditEngineService.java
@@ -1645,26 +1645,34 @@
        return null;
    }
    /** è´§è¿ç±»åž‹çŽ¯æ¯”ï¼šæœ¬æœˆæ–°å¢žï¼ˆä¸Šæœˆä¸º0、本月>0)需核实,少的不管 */
    /** è´§è¿ç±»åž‹çŽ¯æ¯”ï¼ˆRULE_004):上月无→本月新增 æˆ– ä¸Šæœˆæœ‰â†’本月无,均提醒核实 */
    private AuditResult checkMom(AuditRule rule, H2032EnterpriseMonthly report,
                                 Map<String, H2032EnterpriseMonthly> lastMonthMap) {
        H2032EnterpriseMonthly lastMonth = lastMonthMap.get(key(report.getEnterpriseCode()));
        if (lastMonth == null) return null;
        List<String> hits = new ArrayList<>();
        List<String> addHits = new ArrayList<>();
        List<String> delHits = new ArrayList<>();
        for (String field : rule.getCheckField().split(",")) {
            double current = getH2032FieldValue(report, field);
            double last = getH2032FieldValue(lastMonth, field);
            if (current > 0 && last == 0) {
                hits.add(h2032FieldLabel(field) + "=" + fmt(current));
                addHits.add(h2032FieldLabel(field) + "=" + fmt(current));
            } else if (last > 0 && current == 0) {
                delHits.add(h2032FieldLabel(field) + "(上月=" + fmt(last) + ",本月无)");
            }
        }
        if (!hits.isEmpty()) {
            return buildResult(rule, report, "本月新增: " + String.join("、", hits),
                "上月该类型为0", "本月新增货运类型(上月无)");
        if (!addHits.isEmpty() || !delHits.isEmpty()) {
            StringBuilder msg = new StringBuilder();
            if (!addHits.isEmpty()) msg.append("本月新增: ").append(String.join("、", addHits));
            if (!delHits.isEmpty()) {
                if (msg.length() > 0) msg.append(";");
                msg.append("本月消失: ").append(String.join("、", delHits));
            }
            return buildResult(rule, report, msg.toString(),
                "上月无→本月新增 æˆ– ä¸Šæœˆæœ‰â†’本月无", "货运类型环比新增/消失需核实");
        }
        return null;
    }
    /** æœ‰è´§è¿é‡ä½†å¯¹åº”车辆为0 éœ€æ ¸å®žï¼ˆå¦‚ æœ‰é›†è£…箱货运量无集装箱车辆) */
    private AuditResult checkNull(AuditRule rule, H2032EnterpriseMonthly report) {
        String[] fields = rule.getCheckField().split(",");
traffic-audit-server/src/main/java/com/trafficaudit/rulemanage/controller/RuleManageController.java
@@ -8,6 +8,8 @@
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.List;
/** è§„则管理:按报表类型查看/启停/调整阈值 */
@@ -26,7 +28,9 @@
            qw.eq(AuditRule::getReportType, reportType.trim());
        }
        qw.orderByAsc(AuditRule::getSortOrder);
        return Result.ok(ruleMapper.selectList(qw));
        List<AuditRule> list = ruleMapper.selectList(qw);
        for (AuditRule r : list) syncThresholdText(r); // åç§°/说明随阈值动态展示(如 Â±10% â†’ Â±20%)
        return Result.ok(list);
    }
    /** å¯åœè§„则 */
@@ -47,11 +51,33 @@
        if (body.getId() == null) return Result.error("缺少规则ID");
        AuditRule rule = ruleMapper.selectById(body.getId());
        if (rule == null) return Result.error("规则不存在");
        String oldThreshold = rule.getThreshold();
        if (body.getThreshold() != null) rule.setThreshold(body.getThreshold());
        if (body.getAlertLevel() != null) rule.setAlertLevel(body.getAlertLevel());
        if (body.getDescription() != null) rule.setDescription(body.getDescription());
        // é˜ˆå€¼å˜åŒ–时同步规则名称与说明(名称/说明里的 Â±N% æŒ‰æ–°é˜ˆå€¼æ”¹å†™ï¼‰ï¼Œå¹¶éšä¿å­˜æŒä¹…化
        if (body.getThreshold() != null && !body.getThreshold().equals(oldThreshold)) {
            syncThresholdText(rule);
        }
        rule.setUpdatedAt(LocalDateTime.now());
        ruleMapper.updateById(rule);
        return Result.ok("已保存");
    }
}
    /** Â±N% å­—样匹配(名称/说明中随阈值动态变化的片段) */
    private static final Pattern PCT_TOKEN = Pattern.compile("±\\s*\\d+(?:\\.\\d+)?\\s*%");
    /** æŠŠæ–‡æœ¬ä¸­çš„ Â±N% æ›¿æ¢ä¸º Â±threshold%(含已带 Â± çš„前缀,避免双 Â±ï¼‰ */
    private String decorateThresholdText(String text, String threshold) {
        if (text == null || text.trim().isEmpty() || threshold == null || threshold.trim().isEmpty()) return text;
        String token = "±" + threshold.trim() + "%";
        return PCT_TOKEN.matcher(text).replaceAll(Matcher.quoteReplacement(token));
    }
    /** åç§°/说明随阈值同步(读列表时也动态校正,DB ä¸­æ—§æ–‡æœ¬ä¸é˜»å¡žæ˜¾ç¤ºï¼‰ */
    private void syncThresholdText(AuditRule rule) {
        if (rule == null || rule.getThreshold() == null) return;
        rule.setRuleName(decorateThresholdText(rule.getRuleName(), rule.getThreshold()));
        rule.setDescription(decorateThresholdText(rule.getDescription(), rule.getThreshold()));
    }
}
traffic-audit-web/src/views/DataView.vue
@@ -81,12 +81,14 @@
      total: 0,
      records: [],
      columns: [],
      loading: false
      loading: false,
      loadingMore: false
    }
  },
  methods: {
    loadData() {
      this.loading = true
      this.loadingMore = false
      api.get('/data/list', {
        params: {
          type: this.type,
@@ -111,6 +113,57 @@
        this.loading = false
      })
    },
    // æ»šåŠ¨åˆ°åº•éƒ¨è‡ªåŠ¨è¿½åŠ ä¸‹ä¸€é¡µï¼ˆä¿ç•™æ‰‹åŠ¨åˆ†é¡µè·³é¡µèƒ½åŠ›ï¼‰
    loadMore() {
      if (this.loading || this.loadingMore) return
      if (this.records.length >= this.total || this.total <= 0) return
      const nextPage = this.page + 1
      this.loadingMore = true
      api.get('/data/list', {
        params: {
          type: this.type,
          period: this.period || undefined,
          keyword: this.keyword || undefined,
          page: nextPage,
          size: this.size
        }
      }).then(res => {
        const d = res.data || {}
        const addRows = d.records || []
        if (!addRows.length) {
          this.page = nextPage - 1
          return
        }
        this.records = this.records.concat(addRows)
        this.page = nextPage
        if (d.total != null) this.total = d.total
        if (d.columns && d.columns.length) this.columns = d.columns
      }).catch(e => {
        if (e && e._toast) return
        this.$message.error('加载更多失败')
      }).finally(() => {
        this.loadingMore = false
      })
    },
    onScroll(e) {
      // æ™®é€š/全屏下真正的滚动容器都是 el-table å†…部 body-wrapper(捕获阶段可收到);
      // é¡µé¢æ•´ä½“滚动时以 window/document ä¸ºå‡†ã€‚
      const t = e && e.target
      let scrollTop, clientHeight, scrollHeight
      if (t && t.nodeType === 1 && t !== document && typeof t.scrollTop === 'number' && t.scrollHeight > t.clientHeight) {
        scrollTop = t.scrollTop
        clientHeight = t.clientHeight
        scrollHeight = t.scrollHeight
      } else {
        const se = document.scrollingElement || document.documentElement
        scrollTop = se.scrollTop
        clientHeight = window.innerHeight
        scrollHeight = se.scrollHeight
      }
      if (scrollHeight > 0 && scrollTop + clientHeight >= scrollHeight - 80) {
        this.loadMore()
      }
    },
    toggleFullscreen() {
      const el = this.$refs.tableWrap
      if (!document.fullscreenElement) {
@@ -131,6 +184,17 @@
    if (q.period) this.period = q.period
    if (q.keyword) this.keyword = q.keyword
    this.loadData()
    window.addEventListener('scroll', this.onScroll, { passive: true })
    if (this.$refs.tableWrap) {
      // capture=true:el-table å†…部 body-wrapper çš„æ»šåŠ¨åœ¨æ•èŽ·é˜¶æ®µä¹Ÿèƒ½æ”¶åˆ°
      this.$refs.tableWrap.addEventListener('scroll', this.onScroll, { passive: true, capture: true })
    }
  },
  beforeDestroy() {
    window.removeEventListener('scroll', this.onScroll)
    if (this.$refs.tableWrap) {
      this.$refs.tableWrap.removeEventListener('scroll', this.onScroll, { capture: true })
    }
  }
}
</script>