feat(h2031): 适配模板新增「统一社会信用代码/填报单位」两列并入库;fix(import): 补录 2023 年货运量周转量;fix(login/report): 验证码容错、预览指标对齐、弹窗可拖动圆角、失败提示细分;docs: 新增问题与注意事项汇总

- H203-1:库 DDL / init.sql / database.md / 实体 / 导入解析 / 数据查看列 六处同步新增两列,新老格式双向兼容
- 货运量周转量:用 7 月源文件的 2023 Sheet 补录 2023-12(8 月源文件缺该 Sheet),432 项逐格比对零差异
- 登录:captchaRequired 默认改 false 并改为 fail-safe,换网络后不再残留验证码白框
- 报表预览:表头补为 4 列(分类/指标/数据/同比)修正错位;新增 v-dialog-drag 指令支持拖动 + 10px 圆角;failWith 区分网络与后端原因
- 文档:新增《问题与注意事项汇总_2026-09-16》及 3 份功能测试报告,更新 2026-09-16 工作日结
10个文件已修改
5个文件已添加
551 ■■■■■ 已修改文件
docs/database.md 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/init.sql 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/公路旅客/模板_交企统H203-1表_公路旅客运输月度生产情况.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
docs/功能测试报告/功能测试报告_H2031模板新增列适配_2026-09-16.md 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/功能测试报告/功能测试报告_登录验证码容错与报表预览整改_2026-09-16.md 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/功能测试报告/功能测试报告_货运量周转量2023年数据补录_2026-09-16.md 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/工作日结/工作日结_2026-09-16.md 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/问题汇总/问题与注意事项汇总_2026-09-16.md 181 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-server/src/main/java/com/trafficaudit/dataimport/controller/DataViewController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-server/src/main/java/com/trafficaudit/dataimport/entity/PassengerEnterpriseMonthly.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-server/src/main/java/com/trafficaudit/dataimport/service/DataImportService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-web/src/directives/dialogDrag.js 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-web/src/main.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-web/src/views/Login.vue 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traffic-audit-web/src/views/ReportExport.vue 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/database.md
@@ -222,6 +222,8 @@
| region_code | varchar(20) | æ‰€å±žåœ°åŒºï¼ˆè¡Œæ”¿åŒºåˆ’代码) |
| enterprise_code | varchar(50) | ä¼ä¸šä»£ç  |
| enterprise_name | varchar(200) | ä¼ä¸šåç§° |
| unified_credit_code | varchar(50) | ç»Ÿä¸€ç¤¾ä¼šä¿¡ç”¨ä»£ç ï¼ˆæ–°ç‰ˆæ¨¡æ¿æ–°å¢žåˆ—;老模板无此列时为 NULL) |
| report_unit | varchar(200) | å¡«æŠ¥å•位(新版模板新增列;老模板无此列时为 NULL) |
| vehicle_total | int | å®¢è¿è½¦è¾†_总计 |
| seat_total | int | æ ¸å®šè½½å®¢ä½_总计 |
| vehicle_schedule | int | è½¦è¾†æ•°_客运班车(含定线旅游) |
docs/init.sql
@@ -399,6 +399,8 @@
    region_code VARCHAR(20) COMMENT '所属地区',
    enterprise_code VARCHAR(50) COMMENT '企业代码',
    enterprise_name VARCHAR(200) COMMENT '企业名称',
    unified_credit_code VARCHAR(50) COMMENT '统一社会信用代码',
    report_unit VARCHAR(200) COMMENT '填报单位',
    vehicle_total INT COMMENT '客运车辆_总计',
    seat_total INT COMMENT '核定载客位_总计',
    vehicle_schedule INT COMMENT '车辆数_客运班车(含定线旅游客运客车)',
docs/¹«Â·ÂÿÍ/Ä£°å_½»ÆóͳH203-1±í_¹«Â·ÂÿÍÔËÊäÔ¶ÈÉú²úÇé¿ö.xlsx
Binary files differ
docs/¹¦ÄܲâÊÔ±¨¸æ/¹¦ÄܲâÊÔ±¨¸æ_H2031Ä£°åÐÂÔöÁÐÊÊÅä_2026-09-16.md
New file
@@ -0,0 +1,53 @@
# åŠŸèƒ½æµ‹è¯•æŠ¥å‘Šï¼šH203-1 æ¨¡æ¿æ–°å¢žã€Œç»Ÿä¸€ç¤¾ä¼šä¿¡ç”¨ä»£ç  / å¡«æŠ¥å•位」两列适配
- æ—¥æœŸï¼š2026-09-16
- æ¨¡å—:数据导入 / æ•°æ®æŸ¥çœ‹ / æ•°æ®åº“表结构
- ç»“论:**通过**(正向 4 æ¡ã€è´Ÿå‘ 2 æ¡ã€å…¼å®¹ 2 æ¡ã€å…¥åº“抽查 814×2 é¡¹å…¨éƒ¨å¯¹é½ï¼‰
## ä¸€ã€åŠŸèƒ½è¯´æ˜Ž
用户修改了《模板_交企统H203-1表_公路旅客运输月度生产情况》模板,在「企业名称」之后**插入两列**:`统一社会信用代码`、`填报单位`,其余 48 åˆ—整体右移,总列数由 50 â†’ 52。本次改动让后端能读取并入库这两列,同时保证老格式文件兼容。
改动清单:
| å±‚ | æ–‡ä»¶ | æ”¹åЍ |
|----|------|------|
| æ•°æ®åº“ | `h2031_enterprise_monthly` | `ADD COLUMN unified_credit_code VARCHAR(50) NULL AFTER enterprise_name`、`ADD COLUMN report_unit VARCHAR(200) NULL AFTER unified_credit_code` |
| å»ºè¡¨è„šæœ¬ | `docs/init.sql` | åŒæ­¥è¡¥ä¸¤åˆ— |
| æ•°æ®å­—å…¸ | `docs/database.md` | åŒæ­¥è¡¥ä¸¤åˆ—说明 |
| å®žä½“ | `PassengerEnterpriseMonthly.java` | æ–°å¢ž `unifiedCreditCode`、`reportUnit` |
| å¯¼å…¥è§£æž | `DataImportService.java` | `importPassengerMonthly` å†…按表头名取值 |
| å‰ç«¯åˆ—配置 | `DataViewController.java` | `H2031_COLUMNS` æ–°å¢žä¸¤åˆ—(数据查看页可见) |
## äºŒã€æµ‹è¯•环境
- åŽç«¯ï¼š`Started TrafficAuditApplication` / `Tomcat started on port(s): 8090`(重启后新编译,13:30)
- å‰ç«¯ï¼š8080 å·²å°±ç»ªï¼ˆæœ¬æ¬¡æœªæ”¹å‰ç«¯ï¼Œæœªé‡å¯ï¼‰
- æ•°æ®åº“:`traffic_audit` @ 127.0.0.1:3308
- æ–°æ¨¡æ¿ï¼š`docs\公路旅客\模板_交企统H203-1表_公路旅客运输月度生产情况.xlsx`(Sheet1,816×52)
- è€æ ¼å¼ï¼š`D:\桌面\测试数据\公路旅客\八月\公路旅客运输月度生产情况(2026)_2026-09-09 09_18_45.xls`(Sheet0,769×52)
## ä¸‰ã€ç”¨ä¾‹è¡¨
| # | åœºæ™¯ | è¾“å…¥ | é¢„期 | å®žé™… | ç»“论 |
|---|------|------|------|------|------|
| 1 | æ­£å‘-新模板导入 | æ–°æ¨¡æ¿ â†’ `POST /api/import/passengerMonthly?period=2099-07` | æˆåŠŸä¸”æ¡æ•°ä¸Žæºæ–‡ä»¶ä¸€è‡´ | `成功 814 æ¡ï¼Œå¤±è´¥ 0 æ¡` | é€šè¿‡ |
| 2 | æ­£å‘-新列入库 | æŸ¥ `unified_credit_code` / `report_unit` | 814 è¡Œå…¨éƒ¨æœ‰å€¼ | `count=814, c1=814, c2=814` | é€šè¿‡ |
| 3 | å…¥åº“抽查-首行 | æºç¬¬ 1 è¡Œ vs åº“第 1 è¡Œ | é€å­—段一致 | åº“:`enterprise_code=91420105MA4F5Q3R68`、`unified_credit_code=91420105MA4F5Q3R68`、`report_unit=武汉市宏干线公路客运有限公司金地分公司`、`vehicle_total=26`、`passenger_total=12835`,与 Excel å®Œå…¨ä¸€è‡´ | é€šè¿‡ |
| 4 | å…¥åº“抽查-汇总列 | æºæ–‡ä»¶æ±‡æ€» vs åº“汇总 | ä¸€è‡´ | å®¢è¿è½¦è¾† 24584、核定载客位 711018、客运量 16371625、周转量 1023386179,四项全等 | é€šè¿‡ |
| 5 | å…¼å®¹-老格式导入 | è€ `.xls` â†’ `period=2099-09` | æˆåŠŸä¸”æ–°åˆ—æœ‰å€¼ï¼ˆè€æ–‡ä»¶ä¹Ÿå«è¿™ä¸¤åˆ—ï¼‰ | `成功 767 æ¡ï¼Œå¤±è´¥ 0 æ¡`;`c1=767, c2=767` | é€šè¿‡ |
| 6 | å…¼å®¹-老格式数值不变 | 2099-09 vs æ—¢æœ‰ 2026-08(同源同内容) | å®Œå…¨ä¸€è‡´ | n=767 / v=22091 / p=16286506 / t=1158473501,四项全等 | é€šè¿‡ |
| 7 | å…¼å®¹-老格式首行抽查 | Excel COM è¯» `.xls` ç¬¬ 2 è¡Œ vs åº“ | ä¸€è‡´ | æºï¼š`914201005519761659 / 914201005519761659 / æ­¦æ±‰æ·å®‰é¡ºè¾¾æ±½è½¦æœåŠ¡æœ‰é™å…¬å¸ / 24 / 54330`;库同 | é€šè¿‡ |
| 8 | è´Ÿå‘-选错数据类型 | `H203_1_2026-公路旅客运输月度生产情况(2026).xlsx` â†’ passengerMonthly | æ˜Žç¡®æŠ¥é”™ã€ä¸å†™åº“ | `导入失败: æ‰€é€‰æ•°æ®ç±»åž‹ã€å…¬è·¯æ—…客运输月度生产情况】与文件内容不符:表头缺少必需列【企业名称】【客运量_总计】` | é€šè¿‡ |
| 9 | è´Ÿå‘-列右移不影响旧字段 | æ–°æ¨¡æ¿ï¼ˆæ•´ä½“右移 2 åˆ—) | ä¼ä¸šä»£ç /企业名称/车辆/客运量等旧字段取值不变 | è§£æžæŒ‰è¡¨å¤´å `buildHeaderMap` å–值,814 æ¡ 0 å¤±è´¥ï¼Œæ±‡æ€»å››é¡¹ä¸Žæºæ–‡ä»¶ä¸€è‡´ï¼ˆè§ç”¨ä¾‹ 4) | é€šè¿‡ |
## å››ã€å‘现的问题与处置
1. **老格式文件其实也带这两列**(`统一社会信用代码`、`填报单位`),此前代码未读取 â†’ æœ¬æœŸä¸€å¹¶å¼€å§‹å…¥åº“。这也意味着 2026-01 ~ 2026-08 çš„存量数据这两列为空,**需要重导对应文件才能回填**(已列入待办,等用户确认)。
2. **表结构变更必须同步三处**:本次首次只改了库与实体,漏了 `docs/init.sql` / `docs/database.md`,已补齐。
3. **替换锚点不唯一导致改错文档**:`docs/database.md` ä¸­ `| enterprise_name | varchar(200) | ä¼ä¸šåç§° |` å‡ºçް 4 æ¬¡ï¼Œé¦–次批量替换误改了 H203-2 ç­‰ 3 å¼ è¡¨ï¼Œå·² `git checkout` å›žé€€å¹¶æ”¹ä¸ºã€Œå…ˆæˆªå– h2031 ç« èŠ‚å†æ›¿æ¢ã€ã€‚
## äº”、结论
- æ–°æ¨¡æ¿ä¸Žè€æ ¼å¼**双向兼容**,导入 0 å¤±è´¥ï¼ŒæŠ½æŸ¥åˆ—逐项对齐;旧字段未受列右移影响。
- æ•°æ®åº“、建表脚本、数据字典、实体、导入解析、前端列配置**六处一致**。
- é—留:存量月份(2026-01 ~ 2026-08)的两列待回填,等用户确认后重导。
docs/¹¦ÄܲâÊÔ±¨¸æ/¹¦ÄܲâÊÔ±¨¸æ_µÇ¼ÑéÖ¤ÂëÈÝ´íÓ뱨±íÔ¤ÀÀÕû¸Ä_2026-09-16.md
New file
@@ -0,0 +1,51 @@
# åŠŸèƒ½æµ‹è¯•æŠ¥å‘Šï¼šç™»å½•éªŒè¯ç å®¹é”™ + æŠ¥è¡¨é¢„览整改(指标错位 / å¼¹çª—拖动圆角 / å¤±è´¥æç¤ºï¼‰
- æ—¥æœŸï¼š2026-09-16
- æ¨¡å—:登录页、报表生成-汇总大表预览
- ç»“论:**通过**(4 ä¸ªé—®é¢˜å…¨éƒ¨ä¿®å¤ï¼Œæµè§ˆå™¨å®žæµ‹å–证)
## ä¸€ã€åŠŸèƒ½è¯´æ˜Ž
用户反馈 3 ä¸ªé—®é¢˜ï¼š
| # | ç”¨æˆ·æè¿° | æ ¹å›  | ä¿®å¤ |
|---|----------|------|------|
| 1 | æ¢ WiFi åŽç™»å½•页出现验证码白色方框、提示「验证码加载失败,请检查网络」 | åŽç«¯ `app.captcha.required=false` å·²ç¦ç”¨éªŒè¯ç ï¼Œä½†å‰ç«¯ `Login.vue` çš„ `captchaRequired` é»˜è®¤å€¼æ˜¯ `true`,且 `/api/auth/captcha-config` è¯·æ±‚失败时 `.catch(() => {})` **静默忽略**,页面残留一个加载不出来的验证码框 | é»˜è®¤å€¼æ”¹ `false`;改为 fail-safe:仅当后端明确返回 `code===200 && data.required===true` æ‰æ˜¾ç¤ºéªŒè¯ç ï¼Œè¯·æ±‚异常一律按「不需要验证码」处理 |
| 2 | æŠ¥è¡¨ç”Ÿæˆ-汇总大表预览:点击后弹「导出失败,请确认导入数据,或查看后端日志」 | å‰ç«¯ `failWith(err, action)` æŠŠ**所有**异常(含网络/代理层失败)都渲染成同一句笼统文案,默认 action è¿˜æ˜¯ã€Œå¯¼å‡ºã€ï¼Œè¯¯å¯¼è¯»æˆæ•°æ®é—®é¢˜ | é‡å†™ `failWith` + æ–°å¢ž `errReason(raw)`:区分「连不上服务器」与「后端真实原因」;预览调用传 `action='预览'`;Blob é”™è¯¯å“åº”å…ˆ `text()` å†è§£æž |
| 3 | é¢„览弹窗指标错位(指标压在「当月货运量」上);弹窗不可拖动、无圆角 | è¡¨å¤´æ˜¯ 3 åˆ—(指标/数据/同比),与 4 åˆ—数据行(分类/指标/数据/同比)不匹配;Element UI 2.15.14 **没有** `draggable` å±žæ€§ï¼ˆé‚£æ˜¯ Element Plus) | è¡¨å¤´è¡¥ä¸º 4 åˆ— `分类/指标/数据/同比`;新增 `v-dialog-drag` æŒ‡ä»¤å®žçŽ°æ‹–åŠ¨ï¼ˆåªæ”¹ `.el-dialog` çš„ `transform`,关闭时复位),加 `border-radius:10px` |
改动文件:`traffic-audit-web/src/views/Login.vue`、`traffic-audit-web/src/views/ReportExport.vue`、新增 `traffic-audit-web/src/directives/dialogDrag.js`、`traffic-audit-web/src/main.js`(注册指令)。
## äºŒã€æµ‹è¯•环境
- å‰ç«¯ï¼š`http://localhost:8080`(vue-cli-service serve,dev æž„建)
- åŽç«¯ï¼š8090(`Started TrafficAuditApplication`,重启后新编译)
- æµè§ˆå™¨ï¼šCodex å†…嵌浏览器(视口约 319×790),取证方式 `tab.playwright.evaluate()` ç›´è¯» DOM + æˆªå›¾
## ä¸‰ã€ç”¨ä¾‹è¡¨
| # | åœºæ™¯ | è¾“å…¥/操作 | é¢„期 | å®žé™… | ç»“论 |
|---|------|-----------|------|------|------|
| 1 | éªŒè¯ç -后端已关闭 | æ–°å¼€æ ‡ç­¾è®¿é—® `#/login`(后端不可用时同样验证) | ä¸å‡ºçŽ°éªŒè¯ç æ–¹æ¡†ï¼Œä¸å‡ºçŽ°ã€ŒéªŒè¯ç åŠ è½½å¤±è´¥ã€ | é¡µé¢æ—  `.captcha-box`,提示「测试模式:行为验证码已跳过」 | é€šè¿‡ |
| 2 | éªŒè¯ç -接口正常 | `GET /api/auth/captcha-config` | `required=false` | `{"code":200,"message":"success","data":{"required":false}}` | é€šè¿‡ |
| 3 | é¢„览-表头列数 | æ‰“开预览弹窗读 `thead th` | 4 åˆ—且顺序为 åˆ†ç±»/指标/数据/同比 | `['分类','指标','数据','同比']` | é€šè¿‡ |
| 4 | é¢„览-指标对齐 | è¯»é¦–行各单元格 x åæ ‡ | åˆ†ç±»å¯¹é½ã€Œé“路货运」、指标对齐「当月货运量(万吨)」、数据对齐 16888.76、同比在数据右侧 | åˆ†ç±» x=35、指标 x=118、数据 x=394、同比 x=587(`16888.76` åœ¨ x=394) | é€šè¿‡ |
| 5 | é¢„览-弹窗圆角 | è¯» `.el-dialog` è®¡ç®—样式 | æœ‰åœ†è§’ | `borderRadius=10px`、`overflow=hidden` | é€šè¿‡ |
| 6 | é¢„览-弹窗拖动 | `tab.drag([150,60],[270,220])` æ‹–标题栏 | å¼¹çª—跟随移动 | ç”± `(0,40)` â†’ `(120,200)`,`transform=matrix(1,0,0,1,120,160)`,位移量等于拖拽增量 | é€šè¿‡ |
| 7 | é¢„览-关闭复位 | å…³é—­å¼¹çª—后读 transform | å¤ä½ä¸º none | `transform=none`、`visible=false` | é€šè¿‡ |
| 8 | é¢„览-中口径之后无表格 | è¯»å¼¹çª—内 `table` æ•°é‡ä¸Žå†…容 | æœ‰ä¸”仅有 1 å¼ æŒ‡æ ‡è¡¨ | å¼¹çª—内 1 å¼ è¡¨ï¼ˆ12 è¡ŒæŒ‡æ ‡ï¼Œå«ä¸­å£å¾„ 4 è¡Œï¼‰ï¼Œè¡¨ä¸‹ä»…两条同比缺失提示与「关闭」按钮 | é€šè¿‡ |
| 9 | å¤±è´¥æç¤º-网络异常 | åŽç«¯åœæŽ‰æ—¶ç‚¹é¢„览 | æ˜Žç¡®æç¤ºç½‘络/服务未启动,而非「导出失败,请确认导入数据」 | `预览失败:无法连接服务器,请检查网络连接,或确认后端服务是否已启动` | é€šè¿‡ |
| 10 | å¯¼å‡º-正常路径 | ç‚¹ã€Œå¯¼å‡ºã€ | ä¸‹è½½æˆåŠŸæç¤º | `报表导出成功` | é€šè¿‡ |
## å››ã€å‘现的问题与处置
1. **「导出失败,请确认导入数据,或查看后端日志」不是数据问题**:用 API é€æœˆç›´è¿ž `/api/report/preview` ä¸Ž `/api/report/export/summaryWorkbook` å…¨éƒ¨è¿”回 200(2026-08 å¯¼å‡º 950747 å­—节)。该文案只在**网络/代理层失败**时出现(换 WiFi åŽè¯·æ±‚打不到后端),属于提示误导。现已改为区分具体原因。
2. **Element UI 2.15.14 ä¸æ”¯æŒ `draggable`**:弹窗拖动只能自己实现,已用 `v-dialog-drag` æŒ‡ä»¤ï¼›`<style>` å¿…é¡»**非 scoped**(el-dialog é»˜è®¤ append-to-body)。
3. **浏览器自动化取证的坑**:`tab.click(index)` çš„索引在页面刷新后会失效,曾误点到「投资报表」Tab;Playwright locator ç‚¹ Element UI è¡¨æ ¼å†…按钮会超时;`tab.drag` åæ ‡å¿…须在视口内。以上均已记入《问题与注意事项汇总》。
4. é¢„览弹窗标题在未打开时显示为「预览数据 - ï¼ˆï¼‰ã€ï¼Œå±žæœªèµ‹å€¼çŠ¶æ€ï¼Œä¸å½±å“ä½¿ç”¨ã€‚
## äº”、结论
- 4 ä¸ªé—®é¢˜å…¨éƒ¨ä¿®å¤å¹¶æœ‰æµè§ˆå™¨å®žæµ‹è¯æ®ï¼ˆè¡¨å¤´ 4 åˆ—且 x åæ ‡å¯¹é½ã€åœ†è§’ 10px、拖动位移 120/160、关闭复位、无第二张表、失败提示已细分)。
- ã€Œä¸­å£å¾„之后不再渲染表格」的专项验证见《功能测试报告_汇总大表预览删除中口径后明细表_2026-09-16.md》。
- é—留:预览弹窗内「共 0 è¡Œã€ä¸Žã€Œæœˆåº¦è¦†ç›–:1~8月均有数据」两个口径文案不同,易误解,等用户确认后调整。
docs/¹¦ÄܲâÊÔ±¨¸æ/¹¦ÄܲâÊÔ±¨¸æ_»õÔËÁ¿ÖÜתÁ¿2023ÄêÊý¾Ý²¹Â¼_2026-09-16.md
New file
@@ -0,0 +1,49 @@
# åŠŸèƒ½æµ‹è¯•æŠ¥å‘Šï¼šè´§è¿é‡/周转量 2023 å¹´æ•°æ®è¡¥å½•入库
- æ—¥æœŸï¼š2026-09-16
- æ¨¡å—:数据导入 / è´§è¿é‡å‘¨è½¬é‡
- ç»“论:**通过**(正向 1 æ¡ã€å…¥åº“抽查 216 é¡¹å…¨å¯¹é½ã€ä¸Šå¹´åŒæœŸ 1 æ¡ã€å¹‚ç­‰/回归 2 æ¡ï¼‰
## ä¸€ã€åŠŸèƒ½è¯´æ˜Ž
用户反馈「2023 å¹´æœ‰ 12 æœˆçš„æ•°æ®ã€ï¼Œè€Œä¸Šè½®å…¥åº“使用的 8 æœˆæºæ–‡ä»¶**缺 2023 å¹´ Sheet**(只有 `2026å¹´/2025å¹´/2024å¹´/2022å¹´/2021å¹´`),因此库里没有 `2023-12`。
排查后在 7 æœˆæºæ–‡ä»¶ä¸­æ‰¾åˆ° 2023 å¹´æ•°æ®ï¼Œå°†å…¶è¡¥å½•入库:
| é¡¹ | å†…容 |
|----|------|
| æ•°æ®æ¥æº | `D:\05_数据分类\货运\7月\定稿-湖北省各市州运输量数据(2026å¹´1-7月).xlsx` çš„ `2023` Sheet |
| è¡¥å½•方式 | å¦å­˜ä¸´æ—¶å·¥ä½œç°¿ `_2023_import_tmp.xlsx`(仅保留 `2023` + `2022å¹´` ä¸¤ä¸ª Sheet,满足多年度工作簿「至少 2 ä¸ª Sheet」规则),走 `POST /api/import/freightTurnover?period=2023-12` |
| ç»“æžœ | `货运量周转量导入成功, å…± 36 æ¡è®°å½•`(18 åœ°å¸‚ Ã— 2 ä¸ªæŠ¥è¡¨æœŸï¼š2022-12 é‡å†™ + 2023-12 æ–°å¢žï¼‰ |
**为什么带上 2022 å¹´ Sheet**:`2023` çš„上年同期取自「上一年度 Sheet」,只放 2023 ä¼šå¯¼è‡´ 2023 çš„ `last_*` ä¸ºç©ºï¼›åŒæ—¶é¿å…æ•´æœ¬å¯¼å…¥ 7 æœˆæ–‡ä»¶è€Œå¤šå‡ºæ— ç”¨çš„ `2026-07` æŠ¥è¡¨æœŸã€‚
## äºŒã€æµ‹è¯•环境
- åŽç«¯ï¼šé‡å¯åŽæ–°ç¼–译,`Tomcat started on port(s): 8090`,PID 31384
- æ•°æ®åº“:`traffic_audit.freight_turnover_import`
- æºæ–‡ä»¶ï¼š7 æœˆæ–‡ä»¶ `2023` Sheet(A1:N48:`货运量(万吨)` å— + `周转量(万吨公里)` å—,1–12 æœˆ + ç´¯è®¡åˆ—)
## ä¸‰ã€ç”¨ä¾‹è¡¨
| # | åœºæ™¯ | è¾“å…¥ | é¢„期 | å®žé™… | ç»“论 |
|---|------|------|------|------|------|
| 1 | æ­£å‘-2023 å…¥åº“ | `_2023_import_tmp.xlsx` â†’ freightTurnover | ç”Ÿæˆ `2023-12`,18 è¡Œ | `共 36 æ¡è®°å½•`;`SELECT report_period,COUNT(*)` å‡ºçް `2023-12 = 18` | é€šè¿‡ |
| 2 | å…¥åº“抽查-逐格比对 | 2023 Sheet è´§è¿é‡å— + å‘¨è½¬é‡å—(18 åœ°å¸‚ Ã— 12 æœˆ Ã— 2 æŒ‡æ ‡ = 432 é¡¹ï¼‰ | ä¸Žåº“中 `freight_m01..m12` / `turnover_m01..m12` å®Œå…¨ä¸€è‡´ | **mismatches = 0**(18 ä¸ªåœ°åŒºå…¨éƒ¨åŒ¹é…ï¼‰ | é€šè¿‡ |
| 3 | ä¸Šå¹´åŒæœŸ | æŸ¥ 2023-12 çš„ `last_freight_*` / `last_turnover_*` | ç­‰äºŽ 2022 å¹´åŒæœˆå€¼ | æ­¦æ±‰ `last_freight_m01=3527.89407360113`、`last_freight_m12=4334.42636773157`、`last_turnover_m12=608823.495390257`,与 `2022-12` è¡Œé€å€¼ç›¸åŒ | é€šè¿‡ |
| 4 | æŠ¥è¡¨æœŸæ¸…单回归 | æŸ¥å…¨éƒ¨æŠ¥è¡¨æœŸ | æ— é‡å¤ã€æ—  2099 æ®‹ç•™ | 2021-12 / 2022-12 / **2023-12** / 2024-12 / 2025-12 / 2026-01…2026-08,每期 18 è¡Œ | é€šè¿‡ |
| 5 | åŽ†å²æœŸæœªè¢«æ±¡æŸ“ | 2022-12 é‡å†™åŽä¸ŽåŽŸå€¼æ¯”è¾ƒ | å®Œå…¨ä¸€è‡´ | ä¸Žæ”¹åŠ¨å‰ 2022-12 é€å€¼ç›¸åŒ | é€šè¿‡ |
## å››ã€å‘现的问题与处置
| # | é—®é¢˜ | å¤„ç½® |
|---|------|------|
| 1 | 8 æœˆæºæ–‡ä»¶æ—  2023 å¹´ Sheet,导致库里长期缺 `2023-12`、且 `2024-12` æ— ä¸Šå¹´åŒæœŸ | ä»Ž 7 æœˆæºæ–‡ä»¶è¡¥å½• `2023-12`;`2024-12` çš„上年同期本次**未重算**(需重导 2024 æ‰ä¼šç”Ÿæ•ˆï¼‰ï¼Œå¦‚需可另行补导 |
| 2 | 7 æœˆæ–‡ä»¶ä¸Ž 8 æœˆæ–‡ä»¶çš„ 2021/2022/2024 ä¸‰å¹´æ•°æ®æ˜¯å¦ä¸€è‡´æ— æ³•确定 | é€æ ¼æ¯”对:`onlyJuly/onlyAug/differ` å…¨éƒ¨ä¸ºç©ºï¼Œ**三年 0 å¤„差异**,因此补导 2022 ä¸ä¼šå¼•入偏差 |
| 3 | è‹¥æ•´æœ¬å¯¼å…¥ 7 æœˆæ–‡ä»¶ä¼šå¤šå‡º `2026-07` æŠ¥è¡¨æœŸ | æ”¹ä¸ºåªä¿ç•™ `2023 + 2022å¹´` ä¸¤ä¸ª Sheet çš„临时工作簿,避免产生无用期次 |
| 4 | å• Sheet æ–‡ä»¶ä¸ä¼šè¢«è¯†åˆ«ä¸ºå¤šå¹´åº¦å·¥ä½œç°¿ | å·²åœ¨æœ¬æŠ¥å‘Šä¸Žã€Šé—®é¢˜ä¸Žæ³¨æ„äº‹é¡¹æ±‡æ€»ã€‹ä¸­è®°å½•该规则,供后续补数参考 |
## äº”、结论
- 2023 å¹´è´§è¿é‡/周转量已完整入库(18 åœ°å¸‚ Ã— 12 æœˆï¼‰ï¼Œ**432 é¡¹é€æ ¼æ¯”对零差异**,上年同期正确取自 2022 å¹´ã€‚
- æŠ¥è¡¨æœŸæ¸…单连贯:2021-12 â†’ 2026-08 å…± 13 æœŸï¼Œæ¯æœŸ 18 è¡Œã€‚
- é—留:`2024-12` çš„上年同期(2023 å¹´å€¼ï¼‰æœªå›žå¡«ï¼Œå¦‚需要可重导 2024 å¹´æ•°æ®ã€‚
docs/¹¤×÷ÈÕ½á/¹¤×÷ÈÕ½á_2026-09-16.md
@@ -77,4 +77,74 @@
1. ä¸Žç”¨æˆ·ç¡®è®¤ `2021-12` / `2022-12` ç­‰ã€Œæ•´å¹´æŠ¥è¡¨æœŸã€çš„业务口径,以及是否需要把年度数据拆成逐月报表期。
2. ç¡®è®¤æ˜¯å¦éœ€è¦è¡¥ 2023 å¹´æ•°æ®ã€ä»¥åŠ `2026-01`~`2026-07` çš„上年同期是否需要补齐。
3. è§†ç”¨æˆ·æ„è§å¤„理预览弹窗「共 0 è¡Œã€æ–‡æ¡ˆã€‚
4. ç½‘络恢复后补推公司 gitea。
4. ç½‘络恢复后补推公司 gitea。
---
## åã€å‚æ™šè¿½åŠ ï¼ˆç¬¬ 3 è½®ç”¨æˆ·åé¦ˆ 6 æ¡ï¼Œ2026-09-16)
用户本轮提出 6 æ¡åé¦ˆï¼Œé€æ¡å¤„理结果如下:
| # | ç”¨æˆ·åé¦ˆ | å¤„理结果 |
|---|----------|----------|
| 1 | 21–26 å¹´è´§è¿é‡å‘¨è½¬é‡è¡¨æ•°æ®å…¥åº“ | ä¸Šè½®å·²å®Œæˆï¼ˆ`0cfd6e0`),本轮补齐 2023 å¹´ï¼ˆè§ #2) |
| 2 | ç”¨æˆ·æ ¸å®žã€Œ23 å¹´æœ‰ 12 æœˆçš„æ•°æ®ã€ | **属实**。8 æœˆæºæ–‡ä»¶ç¡®å®žæ²¡æœ‰ 2023 å¹´ Sheet,但 7 æœˆæ–‡ä»¶ `D:\05_数据分类\货运\7月\定稿-湖北省各市州运输量数据(2026å¹´1-7月).xlsx` é‡Œæœ‰ä¸€ä¸ªåä¸º `2023` çš„ Sheet。已另存 `_2023_import_tmp.xlsx`(`2023` + `2022å¹´` ä¸¤ä¸ª Sheet)导入,生成 `2023-12`(18 è¡Œï¼‰ï¼Œ**432 é¡¹é€æ ¼æ¯”对零差异** |
| 3 | è¦ä¸€ä»½ã€Œæ‰€æœ‰è¦æ³¨æ„çš„点」的汇总文档 | æ–°å»º `docs/问题汇总/问题与注意事项汇总_2026-09-16.md`(11 ç«  + é€ŸæŸ¥è¡¨ï¼Œå«å¯åЍ/进程、日志验证、数据库、导入路径与期次约定、报表、验证码、文件编码、浏览器取证、git åŒä»“库、遗留问题) |
| 4 | æ¢ WiFi åŽç™»å½•页出现验证码白框 + ã€ŒéªŒè¯ç åŠ è½½å¤±è´¥ã€ | å·²ä¿®å¤ï¼ˆå‰ç«¯é»˜è®¤å€¼ + fail-safe),本轮浏览器复测通过 |
| 5 | é¢„览点一下弹「导出失败,请确认导入数据」 | å·²ä¿®å¤æç¤ºé€»è¾‘(区分网络/后端原因);另外两小项(指标错位、弹窗拖动圆角)本轮浏览器实测通过 |
| 6 | å…¬è·¯æ—…客 H203-1 æ¨¡æ¿è¢«ä¿®æ”¹ | å·²é€‚配并验证:新增 `统一社会信用代码` / `填报单位` ä¸¤åˆ—入库,新老格式双向兼容 |
### 1. 2023 å¹´è´§è¿æ•°æ®è¡¥å½•(用户第 2 æ¡ï¼‰
- **排查过程**:先确认 8 æœˆæºæ–‡ä»¶ 5 ä¸ª Sheet å…¨ä¸ºå¯è§ã€æ—  2023;再全盘搜索 `*运输量*`、`*23å¹´*`、`*货运量*` æ–‡ä»¶åï¼›æœ€åŽæ‰«æ `D:\05_数据分类` ä¸Ž `D:\桌面` ä¸‹æ‰€æœ‰ `.xlsx` çš„ **Sheet å**,命中 7 æœˆæ–‡ä»¶çš„ `2023` Sheet。
- **一致性预检**:7 æœˆä¸Ž 8 æœˆæ–‡ä»¶çš„ `2021å¹´ / 2022å¹´ / 2024å¹´` ä¸‰å¹´æ•°æ®é€æ ¼æ¯”对,`onlyJuly / onlyAug / differ` å…¨ä¸ºç©º â†’ ä¸‰å¹´**零差异**,可安全用 7 æœˆæ–‡ä»¶è¡¥ 2022(作为 2023 çš„上年同期来源)。
- **导入**:`POST /api/import/freightTurnover?period=2023-12`,返回「共 36 æ¡è®°å½•」。
- **验证**:`2023-12` 18 è¡Œï¼›è´§è¿é‡ + å‘¨è½¬é‡å…± 432 é¡¹ä¸Ž Excel é€æ ¼æ¯”对 **mismatches=0**;`last_*` ä¸Ž `2022-12` é€å€¼ç›¸åŒï¼›å…¨éƒ¨æŠ¥è¡¨æœŸ 2021-12 â†’ 2026-08 å…± 13 æœŸã€æ¯æœŸ 18 è¡Œã€‚
- è¯¦è§ã€ŠåŠŸèƒ½æµ‹è¯•æŠ¥å‘Š_货运量周转量2023年数据补录_2026-09-16.md》。
### 2. H203-1 æ¨¡æ¿æ–°å¢žåˆ—适配(用户第 6 æ¡ï¼‰
- **模板 diff ç»“论**:Sheet1 ç”± 773×50 â†’ 816×52;在「企业名称」后插入 `统一社会信用代码`、`填报单位` ä¸¤åˆ—,其余 48 åˆ—整体右移。
- **改动 6 å¤„**:库 DDL、`docs/init.sql`、`docs/database.md`、`PassengerEnterpriseMonthly.java`、`DataImportService.java`、`DataViewController.java`(数据查看页列)。
- **验证**:新模板导入 814 æ¡ 0 å¤±è´¥ï¼Œå››é¡¹æ±‡æ€»ï¼ˆå®¢è¿è½¦è¾† 24584 / æ ¸å®šè½½å®¢ä½ 711018 / å®¢è¿é‡ 16371625 / å‘¨è½¬é‡ 1023386179)与源文件全等;老格式 `.xls` å¯¼å…¥ 767 æ¡ 0 å¤±è´¥ä¸”新列有值(**老文件其实也带这两列**),数值与既有 2026-08 å®Œå…¨ä¸€è‡´ï¼›è´Ÿå‘用例(选错类型)报错清晰。
- **过程中的失误**:`docs/database.md` é‡Œ `| enterprise_name | varchar(200) | ä¼ä¸šåç§° |` å‡ºçް 4 æ¬¡ï¼Œé¦–次批量替换误改 3 å¼ è¡¨ï¼Œå·² `git checkout` å›žé€€åŽæ”¹ä¸ºã€Œæˆªå–章节再替换」。
- è¯¦è§ã€ŠåŠŸèƒ½æµ‹è¯•æŠ¥å‘Š_H2031模板新增列适配_2026-09-16.md》。
### 3. ç™»å½•验证码容错 + æŠ¥è¡¨é¢„览整改(用户第 4、5 æ¡ï¼‰
- **验证码**:`Login.vue` é»˜è®¤ `captchaRequired=false`,改为 fail-safe(仅后端明确返回 `required===true` æ‰æ˜¾ç¤ºï¼‰ï¼›æ¢ WiFi/后端不可达时不再残留验证码白框。
- **失败提示**:`failWith(err, action)` + `errReason(raw)` é‡å†™ï¼ŒåŒºåˆ†ã€Œè¿žä¸ä¸ŠæœåŠ¡å™¨ã€ä¸Žã€ŒåŽç«¯çœŸå®žåŽŸå› ã€ï¼›é¢„è§ˆè°ƒç”¨å¸¦ `action='预览'`;Blob é”™è¯¯å…ˆ `text()` å†è§£æžã€‚
- **指标错位**:预览表头由 3 åˆ—补为 4 åˆ—(分类/指标/数据/同比),实测 x åæ ‡ 35 / 118 / 394 / 587,`16888.76` è½åœ¨ã€Œæ•°æ®ã€åˆ—。
- **弹窗拖动 + åœ†è§’**:新增 `dialogDrag.js` æŒ‡ä»¤ï¼ˆElement UI 2.15.14 æ—  `draggable`),`border-radius:10px`;实测拖动 `(0,40) â†’ (120,200)`,`transform=matrix(1,0,0,1,120,160)`,关闭后复位 `none`。
- ã€Œä¸­å£å¾„之后不再渲染表格」上轮已修,本轮复核弹窗内**有且仅有一张表**。
- è¯¦è§ã€ŠåŠŸèƒ½æµ‹è¯•æŠ¥å‘Š_登录验证码容错与报表预览整改_2026-09-16.md》。
### 4. æ³¨æ„äº‹é¡¹æ±‡æ€»æ–‡æ¡£ï¼ˆç”¨æˆ·ç¬¬ 3 æ¡ï¼‰
新建 `docs/问题汇总/问题与注意事项汇总_2026-09-16.md`,共 11 ç« ï¼š
速查表(10 æ¡ï¼‰ã€å¯åŠ¨ä¸Žè¿›ç¨‹ç®¡ç†ã€æœåŠ¡çŠ¶æ€éªŒè¯ã€æ•°æ®åº“ã€æ•°æ®å¯¼å…¥ï¼ˆè·¯å¾„ + æœŸæ¬¡çº¦å®š + å¤šå¹´åº¦å·¥ä½œç°¿è¯†åˆ«è§„则)、报表生成、登录与验证码、文件写入与文本处理的坑、浏览器自动化取证的坑、Git åŒä»“库工作流、当前已知遗留问题。
## åä¸€ã€æµ‹è¯•结果摘要(傍晚追加部分)
- **2023 è¡¥å½•**(5 æ¡ç”¨ä¾‹ï¼‰ï¼šæ­£å‘入库、432 é¡¹é€æ ¼æ¯”对零差异、上年同期取自 2022、报表期清单无重复/无残留、2022-12 é‡å†™åŽé€å€¼ä¸å˜ â€”— å…¨éƒ¨é€šè¿‡ã€‚
- **H203-1 æ–°å¢žåˆ—**(9 æ¡ç”¨ä¾‹ï¼‰ï¼šæ–°æ¨¡æ¿ 814 æ¡ 0 å¤±è´¥ã€ä¸¤åˆ— 814/814 æœ‰å€¼ã€é¦–行与汇总四项与源文件全等、老格式 767 æ¡ 0 å¤±è´¥ä¸”数值与 2026-08 å…¨ç­‰ã€Excel COM æŠ½æŸ¥é¦–行一致、负向选错类型报错清晰、列右移不影响旧字段 â€”— å…¨éƒ¨é€šè¿‡ã€‚
- **登录验证码 + é¢„览整改**(10 æ¡ç”¨ä¾‹ï¼‰ï¼šæ— éªŒè¯ç ç™½æ¡†ã€æŽ¥å£ `required=false`、表头 4 åˆ—且 x åæ ‡å¯¹é½ã€åœ†è§’ 10px、拖动位移 120/160、关闭复位、弹窗内仅 1 å¼ è¡¨ã€å¤±è´¥æç¤ºå·²ç»†åˆ†ã€å¯¼å‡ºæˆåŠŸ â€”— å…¨éƒ¨é€šè¿‡ã€‚
- **测试数据清理**:H203-1 å¯¼å…¥éªŒè¯äº§ç”Ÿçš„ `2099-06 / 2099-07 / 2099-09` ä¸‰ä¸ªæµ‹è¯•期(共 2395 è¡Œï¼‰åŠå…¶ `import_batch` è®°å½•已删除,`h2031_enterprise_monthly` æ¢å¤ä¸º 2026-01 ~ 2026-08 å…± 8 æœŸï¼›`freight_turnover_import` ä¸º 13 æœŸ Ã— 18 è¡Œã€‚
## åäºŒã€é—留问题与待办(傍晚更新)
| # | é—®é¢˜ | çŠ¶æ€ |
|---|------|------|
| 1 | 8 æœˆæºæ–‡ä»¶ç¼º 2023 å¹´ Sheet | **已解决**(用 7 æœˆæ–‡ä»¶è¡¥å½• `2023-12`) |
| 2 | `2026-01` ~ `2026-07` çš„ `last_*` ä¸ºç©º | å¾…用户确认是否补 |
| 3 | `2026-01` ~ `2026-08` çš„ H203-1 `unified_credit_code` / `report_unit` ä¸ºç©ºï¼ˆæ­¤å‰ä»£ç æœªè¯»è¿™ä¸¤åˆ—) | **待用户确认是否重导历史文件回填** |
| 4 | `2024-12` çš„上年同期未回填(需重导 2024 å¹´æ•°æ®ï¼‰ | å¾…用户确认 |
| 5 | é¢„览弹窗「共 0 è¡Œã€ä¸Žã€Œæœˆåº¦è¦†ç›–:1~8月均有数据」口径文案不同 | å¾…用户确认改文案 |
| 6 | `2021-12` ç­‰ã€Œæ•´å¹´æŠ¥è¡¨æœŸã€çš„业务口径 | å¾…用户确认 |
| 7 | å…¬å¸ gitea æŽ¨é€ï¼ˆç½‘络无响应) | å¾…补推,**禁强推** |
| 8 | ä»“库根目录大量 `_*.*` ä¸´æ—¶æ–‡ä»¶ | ç»ç”¨æˆ·åŒæ„åŽå†æ¸…理 |
## åä¸‰ã€ä¸‹ä¸€æ­¥è®¡åˆ’(傍晚更新)
1. ç­‰ç”¨æˆ·ç¡®è®¤ 3 ä»¶äº‹ï¼šæ˜¯å¦é‡å¯¼ 2026 å¹´åŽ†å² H203-1 æ–‡ä»¶å›žå¡«ä¸¤åˆ—、是否补 `last_*` / `2024-12` ä¸Šå¹´åŒæœŸã€é¢„览弹窗文案是否调整。
2. ç½‘络恢复后补推公司 gitea(先 fetch åˆå¹¶ï¼Œç¦å¼ºæŽ¨ï¼‰ã€‚
3. è§†ç”¨æˆ·æ„è§æ¸…理仓库根目录 `_*.*` ä¸´æ—¶æ–‡ä»¶ã€‚
docs/ÎÊÌâ»ã×Ü/ÎÊÌâÓë×¢ÒâÊÂÏî»ã×Ü_2026-09-16.md
New file
@@ -0,0 +1,181 @@
# äº¤é€šè´§è¿ç»Ÿè®¡å®¡æ ¸ç³»ç»Ÿ â€” é—®é¢˜ä¸Žæ³¨æ„äº‹é¡¹æ±‡æ€»
> ç”¨é€”:把项目运行、数据导入、报表生成、仓库协作中所有「踩过的坑」集中记录,供后续开发与运维快速查阅。
> ç»´æŠ¤æ–¹å¼ï¼šæ–°å‘现问题请直接在本文件追加,并注明日期。
> æœ€åŽæ›´æ–°ï¼š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`):
  1. **至少 2 ä¸ª Sheet**(单 Sheet æ–‡ä»¶ä¸è¯†åˆ«ä¸ºå¤šå¹´åº¦å·¥ä½œç°¿ï¼Œä¼šèµ°è€çš„æœˆåº¦æ¨¡æ¿è·¯å¾„);
  2. æ¯ä¸ª Sheet ååŒ¹é… `^\d{4}\s*å¹´?$`(`2023å¹´`、`2023` éƒ½å¯ä»¥ï¼‰ï¼›
  3. æ¯ä¸ª 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 | ä»“库根目录大量 `_*.*` ä¸´æ—¶æ–‡ä»¶ | ä½“积/可读性 | ç»ç”¨æˆ·åŒæ„åŽå†æ¸…理 |
traffic-audit-server/src/main/java/com/trafficaudit/dataimport/controller/DataViewController.java
@@ -359,6 +359,8 @@
        H2031_COLUMNS.add(col("regionCode", "所属地区", 100));
        H2031_COLUMNS.add(col("enterpriseCode", "企业代码", 130));
        H2031_COLUMNS.add(col("enterpriseName", "企业名称", 220));
        H2031_COLUMNS.add(col("unifiedCreditCode", "统一社会信用代码", 180));
        H2031_COLUMNS.add(col("reportUnit", "填报单位", 160));
        H2031_COLUMNS.add(col("vehicleTotal", "客运车辆合计", 110));
        H2031_COLUMNS.add(col("seatTotal", "核定载客位合计", 130));
        H2031_COLUMNS.add(col("vehicleSchedule", "班线车辆数", 110));
traffic-audit-server/src/main/java/com/trafficaudit/dataimport/entity/PassengerEnterpriseMonthly.java
@@ -22,6 +22,10 @@
    private String enterpriseCode;
    /** ä¼ä¸šåç§° */
    private String enterpriseName;
    /** ç»Ÿä¸€ç¤¾ä¼šä¿¡ç”¨ä»£ç  */
    private String unifiedCreditCode;
    /** å¡«æŠ¥å•位 */
    private String reportUnit;
    /** å®¢è¿è½¦è¾†_总计 */
    private Integer vehicleTotal;
traffic-audit-server/src/main/java/com/trafficaudit/dataimport/service/DataImportService.java
@@ -319,6 +319,9 @@
                entity.setRegionCode(gs(row, colMap, "所属地区"));
                entity.setEnterpriseCode(gs(row, colMap, "企业代码"));
                entity.setEnterpriseName(name.trim());
                // æ–°ç‰ˆæ¨¡æ¿åœ¨ã€Œä¼ä¸šåç§°ã€åŽæ–°å¢žäº†ä¸¤åˆ—(统一社会信用代码/填报单位),按表头取值,老模板无该列时为 null
                entity.setUnifiedCreditCode(gs(row, colMap, "统一社会信用代码"));
                entity.setReportUnit(gs(row, colMap, "填报单位"));
                entity.setVehicleTotal(gi(row, colMap, "客运车辆_总计"));
                entity.setSeatTotal(gi(row, colMap, "核定载客位_总计"));
                entity.setVehicleSchedule(gi(row, colMap, "车辆数_客运班车(含定线旅游客运客车)"));
traffic-audit-web/src/directives/dialogDrag.js
New file
@@ -0,0 +1,61 @@
/**
 * v-dialog-drag:让 Element UI 2.x çš„ el-dialog èƒ½ç”¨æ ‡é¢˜æ æ‹–动。
 * Element UI 2.x çš„ el-dialog æ²¡æœ‰ draggable å±žæ€§ï¼ˆé‚£æ˜¯ Element Plus çš„功能),
 * æ‰€ä»¥è¿™é‡Œç”¨æŒ‡ä»¤å®žçŽ°ï¼šåªæ”¹ .el-dialog çš„ transform,不改布局;
 * å¼¹çª—关闭(wrapper è¢«ç½®ä¸º display:none)时自动复位,下次打开仍在原位。
 * ç”¨æ³•:<el-dialog v-dialog-drag custom-class="xxx">
 */
export default {
  inserted(el) {
    const dialog = el.querySelector('.el-dialog')
    const header = el.querySelector('.el-dialog__header')
    if (!dialog || !header) return
    let startX = 0
    let startY = 0
    let baseX = 0
    let baseY = 0
    let curX = 0
    let curY = 0
    let dragging = false
    const reset = () => {
      curX = 0
      curY = 0
      dialog.style.transform = ''
    }
    const onMove = (e) => {
      if (!dragging) return
      curX = baseX + (e.clientX - startX)
      curY = baseY + (e.clientY - startY)
      dialog.style.transform = 'translate(' + curX + 'px, ' + curY + 'px)'
      if (e.preventDefault) e.preventDefault()
    }
    const onUp = () => {
      if (!dragging) return
      dragging = false
      document.removeEventListener('mousemove', onMove)
      document.removeEventListener('mouseup', onUp)
    }
    const onDown = (e) => {
      if (e.button !== 0) return
      const t = e.target
      if (t && t.closest && t.closest('.el-dialog__headerbtn')) return
      dragging = true
      startX = e.clientX
      startY = e.clientY
      baseX = curX
      baseY = curY
      document.addEventListener('mousemove', onMove)
      document.addEventListener('mouseup', onUp)
      if (e.preventDefault) e.preventDefault()
    }
    header.addEventListener('mousedown', onDown)
    if (typeof MutationObserver !== 'undefined') {
      const mo = new MutationObserver(() => {
        if (el.style.display === 'none') reset()
      })
      mo.observe(el, { attributes: true, attributeFilter: ['style'] })
    }
  }
}
traffic-audit-web/src/main.js
@@ -3,8 +3,10 @@
import 'element-ui/lib/theme-chalk/index.css'
import App from './App.vue'
import router from './router'
import dialogDrag from './directives/dialogDrag'
Vue.use(ElementUI)
Vue.directive('dialog-drag', dialogDrag)   // è®© el-dialog å¯æ‹–动(Element UI 2.x æ—  draggable å±žæ€§ï¼‰
Vue.config.productionTip = false
// å…¨å±€ç™»å‡ºï¼šæ¸…除登录态并回登录页(各页面侧边栏「退出登录」菜单共用)
traffic-audit-web/src/views/Login.vue
@@ -40,16 +40,20 @@
      captchaId: '',
      clickIds: [],
      loggingIn: false,
      captchaRequired: true
      captchaRequired: false
    }
  },
  created() {
    // éªŒè¯ç æ˜¯å¦å¯ç”¨ä¸€å¾‹ä»¥åŽç«¯ /api/auth/captcha-config ä¸ºå‡†ï¼š
    // é»˜è®¤ä¸æ˜¾ç¤ºï¼Œåªæœ‰åŽç«¯æ˜Žç¡®è¿”回 required=true æ‰æ¸²æŸ“验证码组件。
    // ä¿®å¤ï¼šæ­¤å‰é»˜è®¤ true ä¸”请求失败时静默忽略,切换网络后该配置读不到,
    // ç™»å½•页就会残留一个加载不出来的验证码白框并提示“验证码加载失败,请检查网络”。
    axios.get('/api/auth/captcha-config', { timeout: 10000 })
      .then(res => {
        const d = res.data
        if (d && d.code === 200) this.captchaRequired = d.data.required !== false
        this.captchaRequired = !!(d && d.code === 200 && d.data && d.data.required === true)
      })
      .catch(() => {})
      .catch(() => { this.captchaRequired = false })
  },
  methods: {
    onCaptchaVerified(payload) {
traffic-audit-web/src/views/ReportExport.vue
@@ -99,7 +99,8 @@
            </div>
          </el-alert>
        </div>
        <el-dialog :title="'预览数据 - ' + previewModule + '(' + previewPeriod + ')'" :visible.sync="previewVisible" width="760px">
        <el-dialog :title="'预览数据 - ' + previewModule + '(' + previewPeriod + ')'" :visible.sync="previewVisible" width="760px"
                   top="5vh" custom-class="pv-dialog" v-dialog-drag>
          <div class="preview-body">
            <div v-for="it in previewItems" :key="it.key" class="preview-item">
              <div class="preview-head">
@@ -114,7 +115,7 @@
              </div>
              <table class="preview-summary wb-table" v-if="it.key === 'summaryWorkbook' && it.summary && it.summary.length">
                <thead>
                  <tr><th style="width:44%">指标</th><th style="width:30%">数据</th><th>同比</th></tr>
                  <tr><th style="width:12%">分类</th><th style="width:40%">指标</th><th style="width:28%">数据</th><th>同比</th></tr>
                </thead>
                <tbody>
                  <template v-for="(sec, si) in wbRows(it.summary)">
@@ -388,7 +389,7 @@
          this.previewVisible = true
          this.loading = ''
        })
        .catch(err => this.failWith(err))
        .catch(err => this.failWith(err, '预览'))
    },
    fmtVal(v) {
      if (v === null || v === undefined || v === '') return '—'
@@ -505,13 +506,45 @@
        })
        .catch(() => doExport())
    },
    failWith(err) {
    // é¢„览/导出失败统一提示:区分“连不上服务器”与“后端返回的错误原因”。
    // å¯¼å‡ºæŽ¥å£ç”¨ responseType: 'blob',报错时 data ä¹Ÿæ˜¯ Blob,必须先读文本再解析,
    // å¦åˆ™æ‹¿ä¸åˆ°åŽç«¯çœŸå®žåŽŸå› ï¼Œåªä¼šæ˜¾ç¤ºç¬¼ç»Ÿçš„â€œè¯·ç¡®è®¤å·²å¯¼å…¥å¯¹åº”æ•°æ®â€ã€‚
    failWith(err, action) {
      if (err && err._toast) { this.loading = ''; return }
      let msg = ''
      const d = err && err.response && err.response.data
      if (d && typeof d === 'object' && d.message) msg = d.message
      this.$message.error('导出失败:' + (msg || '请确认已导入对应数据,或查看后端日志'))
      this.loading = ''
      const act = action || '导出'
      const finish = (reason) => {
        this.$message.error(act + '失败:' + reason)
        this.loading = ''
      }
      if (!err || !err.response) {
        if (err && err.code === 'ECONNABORTED') { finish('请求超时,请稍后重试'); return }
        finish('无法连接服务器,请检查网络连接,或确认后端服务是否已启动')
        return
      }
      const d = err.response.data
      const fallback = '请确认已导入对应数据,或查看后端日志'
      if (d && typeof d.text === 'function') {
        Promise.resolve(d.text()).then(txt => finish(this.errReason(txt) || fallback)).catch(() => finish(fallback))
        return
      }
      finish(this.errReason(typeof d === 'string' ? d : (d && d.message)) || fallback)
    },
    // åŽç«¯å¼‚常响应可能是 JSON/HTML/纯文本,尽量提取出可读的原因
    errReason(raw) {
      if (!raw) return ''
      let text = String(raw).trim()
      if (text.charAt(0) === '{' || text.charAt(0) === '[') {
        try {
          const j = JSON.parse(text)
          if (j && j.message) return j.message
        } catch (e) { /* éž JSON,按纯文本处理 */ }
      }
      text = text.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim()
      // å¼€å‘代理/网络层报错转成人话,避免直接把 ECONNREFUSED ä¹‹ç±»æŠ›ç»™ç”¨æˆ·
      if (/ECONNREFUSED|ECONNRESET|Proxy error|socket hang up|Network Error|Failed to fetch/i.test(text)) {
        return '无法连接服务器,请检查网络连接,或确认后端服务是否已启动'
      }
      return text.length > 200 ? text.slice(0, 200) + '…' : text
    },
    downloadBlob(res, fileName) {
      const isZip = /\.zip$/.test(fileName)
@@ -579,3 +612,11 @@
.wb-yoy.yoy-empty { color:#C0C4CC; }
.wb-note { color:#E6A23C; font-size:12px; margin:2px 0 8px; }
</style>
<style>
/* é¢„览数据弹窗:圆角 + å¯é€šè¿‡æ ‡é¢˜æ æ‹–动(v-dialog-drag æŒ‡ä»¤ï¼‰ã€‚
   ä¸èƒ½å†™è¿› scoped:el-dialog é»˜è®¤ append-to-body,DOM æŒ‚在 body ä¸Šï¼Œscoped é€‰æ‹©å™¨åŒ¹é…ä¸åˆ°ã€‚ */
.pv-dialog { border-radius: 10px; overflow: hidden; }
.pv-dialog .el-dialog__header { cursor: move; user-select: none; -webkit-user-select: none; }
.pv-dialog .el-dialog__headerbtn { cursor: pointer; }
</style>