| .gitignore | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| docs/功能测试报告/功能测试报告_汇总大表四页数据驱动_2026-09-13.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| docs/功能测试报告/功能测试报告_部署包打包与独立启动_2026-09-13.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| docs/工作日结/工作日结_2026-09-13.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| docs/打包部署说明.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| package-deploy.py | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| traffic-audit-server/src/main/java/com/trafficaudit/security/utils/JwtUtils.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
.gitignore
@@ -67,3 +67,10 @@ # ==== packaged static dir (copied from dist, not committed) ==== web/ traffic-audit-server/web/ # ==== é¨ç½²äº§ç©ï¼ä¸å ¥åºï¼==== deploy/ traffic-audit-deploy-*.zip _t_wyc_aug.docx _deploytest/ traffic_audit_full_*.sql docs/¹¦ÄܲâÊÔ±¨¸æ/¹¦ÄܲâÊÔ±¨¸æ_»ã×Ü´ó±íËÄÒ³Êý¾ÝÇý¶¯_2026-09-13.md
New file @@ -0,0 +1,146 @@ # åè½æµè¯æ¥å_æ±æ»å¤§è¡¨åé¡µæ°æ®é©±å¨_2026-09-13 ## ä¸ãåè½è¯´æ ### 1. èæ¯ ç¨æ·åé¦ï¼å¯¼åº 2026 å¹´ 8 æãéè·¯è¿è¾éæ±æ»è¡¨ãåï¼ä»¥ä¸ 4 å¼ **跨页åæé¡µ**仿¯ä¸ä¸æ¥è¡¨æçéæå¼ï¼æ é¢åã2026å¹´1-7æ / 2026å¹´7æãï¼æ°å¼ä¹æ¯ 7 æçï¼ä¸éæ¥è¡¨æååï¼ï¼ | 页å | æ¯çåç¶æ | | --- | --- | | `å叿±æ»` | æ´é¡µéæï¼1-7 æç´¯è®¡ + 7 æå½æï¼ | | `åå¸åå¸å·` | 4 åæ´é¡µéæ | | `ä¸å£å¾åæ` | 2 åæ´é¡µéæ | | `éè·¯è¿è¾å¨è½¬é` | 2 åæ´é¡µéæ | ç¨æ·éå®**æ¹æ¡ A**ï¼æ²¿ç¨è´§è¿æå页çåæ³ââç¨æ¯çå°è´¦é¡µèªå¸¦ç 2025 å¹´åæåç¼åå¼å½åæ¯åºæ°ï¼æãå½å¹´ç´¯è®¡å¼ãå·æ 1-8 æï¼åæ¯åæ²¿ç¨æ¯çå£å¾ï¼ï¼4 页䏿¬¡æ§ååºæ¥ã ### 2. å£å¾ï¼å éªè¯ãåç¼ç ï¼ ç¼ç åå ç¨æ¯çå°è´¦é¡µéæ ¼èå忍å页å£å¾ï¼ä¸å页æåéæ ¼æ¯å¯¹ **0 å·®å¼**åç¡®è®¤ï¼ | ææ | å£å¾ | | --- | --- | | åå¸å®¢è¿é | å ¬äº¤åå¸å 客è¿é + 巡游åºç§åå¸å 客è¿é + ç½çº¦è½¦åå¸å 客è¿é + 轨é客è¿é + 轮渡客è¿é | | åå¸å®¢è¿å¨è½¬é | åä¸ï¼æ¢æåèªæ 客å¨è½¬é | | ä¸å£å¾å®¢è¿é/å¨è½¬é | å ¬è·¯ç线å 车 + åé åä¹¡å ¬äº¤ + åé å乡巡游åºç§ + åé å乡ç½çº¦è½¦ï¼å ¶ä¸ãåé å乡 X = X æ»é â X åå¸å ãï¼ä» å ¬äº¤/åºç§/ç½çº¦è½¦ï¼ç线å 车æ åå¸å æ¦å¿µï¼ç´æ¥ç¨æ»éï¼ | | é路货è¿å¨è½¬é | è´§è¿é¡µå¸å·ãè§ä¸è´§ç©å¨è½¬é + è§ä¸è´§ç©å¨è½¬éãï¼**ä¸ç¨**æ¯çãè§ä¸+è§ä¸ãå ¬å¼è¡ï¼ | | éè·¯è¿è¾å¨è½¬é页ãé路客è¿å¨è½¬éã | ç线å 车å¨è½¬é + åé åä¹¡å ¬äº¤/åºç§/ç½çº¦è½¦å¨è½¬é | | 忝 | 彿 ÷ æ¯çå°è´¦é¡µ 2025 å¹´åæå â 1 | **å ³äº 2025 åæåºæ°**ï¼åºä¸åªæ 2026 å¹´åå¸å®¢è¿/ç½çº¦è½¦æ°æ®ï¼æ²¡æ 2025 å¹´æ°æ®ï¼æ 2025 åæä¸å¾å**æ¯çå°è´¦é¡µèªå¸¦ç 2025 å¹´éæåç¼åå¼**ï¼V=1æãX=2æ ⦠AJ=8æï¼ãè¿ä¹æ£æ¯æ¹æ¡ A çåå·§ç¹ï¼æ¯çå°è´¦é¡µæ¬èº«å¸¦å ¨ 2025 éæåï¼æ éç 2025 æ°æ®å ¥åºã ### 3. å®ç° æ¹å¨æä»¶ï¼`traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java`ï¼+494 â2ï¼ã - æ°å¢å ¥å£ `refreshSummaryCumulativeSheets(XSSFWorkbook wb, int year, int month)`ï¼æ¥å¨å¯¼åºé¾è·¯ç `refreshSummaryRankSheets(...)` ä¹åã`applySummaryReferenceLayout(wb)` ä¹åè°ç¨ã - å°è´¦åæ° `smReadLedgerMetrics`ï¼**æè¡æ ç¾è¯å«ãä¸åæ»è¡å·** - `å ¬äº¤`/`åºç§`/`ç½çº¦è½¦`ï¼æ¯å¸å·ã客è¿é / æ 客å¨è½¬é / å ¶ä¸åå¸å 客è¿é / å ¶ä¸åå¸å æ 客å¨è½¬éã4 è¡ï¼ - `轨éã轮渡`ï¼è½¨éï¼å ¨ç/æ¦æ±/é»ç³ï¼ä¸è½®æ¸¡ï¼å ¨ç/æ¦æ±ï¼ååï¼ - `ç线å 车`ï¼å ¨çä¸ 17 å¸å·å®¢è¿é/å¨è½¬éï¼ãå ¶ä¸ä¸ªä½ãè¡ä¸éå¤è®¡å ¥ï¼ï¼ - ` è´§è¿`ï¼é¡µå带åå¯¼ç©ºæ ¼ï¼ï¼å¸å·ãè§ä¸è´§ç©å¨è½¬é + è§ä¸è´§ç©å¨è½¬éãã - æä»½åï¼2026 å¹´éæå C=1æ ⦠Q=8æï¼`SM_CUR_COL0=2`ï¼ï¼2025 å¹´åæå V=1æ ⦠AJ=8æï¼`SM_LAST_COL0=21`ï¼ï¼æ¯æé´é 2 åï¼å¼å + 忝åï¼ã - 19 ç»´ææ ä½ï¼`SM_DIM=19`ï¼ï¼å ¬äº¤/åºç§/ç½çº¦è½¦ å 4 ç»´ï¼æ»éãå¨è½¬éãåå¸å æ»éãåå¸å å¨è½¬éï¼+ 轨é 2 ç»´ + 轮渡 2 ç»´ + ç线å 车 2 ç»´ + è´§è¿å¨è½¬é 1 ç»´ã - åå¼è§å `smSetVal`ï¼**ç®æ æ ¼åæ¬æ¯å ¬å¼ â ä¿çæ¯çå ¬å¼ä¸è¦ç**ï¼æå¼å³éç®ï¼ï¼ç®æ æ ¼ä¸ºç©ºä¸æ°å¼ä¸º 0 â 䏿°å¢ï¼å ¶ä½å `setBlank()` ååï¼é¿å inlineStr æ®çã - å页å®é åå ¥ **1056 æ ¼**ã ## äºãæµè¯ç¯å¢ - å端 `http://localhost:8090`ï¼`start-dev.ps1` å¯å¨ï¼PID 27840ï¼ï¼å端 `http://localhost:8080`ï¼PID 23416ï¼å就绪ã - æ¯çï¼`docs/çææ±æ»å¤§è¡¨/2026å¹´8æéè·¯è¿è¾éæ±æ»è¡¨.xlsx`ï¼çå¼åç §ï¼`docs/çææ±æ»å¤§è¡¨/çæ_éè·¯è¿è¾éæ±æ»è¡¨.xlsx`ã - å¯¼åºæ¥å£ï¼`GET /api/report/export/summaryWorkbook?period=YYYY-MM`ï¼Bearer tokenï¼ã - æµè¯æ¶é´ï¼2026-09-13ã - æµè¯äº§ç©ï¼`_t3_2026-08.xlsx`ï¼950,783 åè / HTTP 200 / 36.8 ç§ï¼ã`_t3_2026-07.xlsx`ï¼942,691 åè / HTTP 200 / 25.7 ç§ï¼ï¼å½æ¡£ä»¶ `docs/çææ±æ»å¤§è¡¨/è¾åº/çæ_éè·¯è¿è¾éæ±æ»è¡¨_2026-08_åé¡µæ°æ®é©±å¨_2026-09-13.xlsx`ï¼950,783 åèï¼ã - ç¬ç«å¤æ ¸èæ¬ï¼`_v5_four.py`ï¼è¾åº `_v5_four.txt`ï¼ã`_verify_four.py`ï¼è¾åº `_verify_four.txt`ï¼ã ## ä¸ãç¨ä¾è¡¨ ### 3.1 æ£åç¨ä¾ | ç¼å· | è¾å ¥ | 颿 | å®é | ç»è®º | | --- | --- | --- | --- | --- | | TC-1 | å¯¼åº `period=2026-08` | HTTP 200ï¼æ£å¸¸äº§åº | 950,783 åèï¼36.8 ç§ | éè¿ | | TC-2 | ä¸ 09-13 13:06 彿¡£ä»¶æ¯å¯¹ | å忰坼åºç»æç¡®å® | 两次产ç©å为 950,783 åè | éè¿ | | TC-3 | å端åå¡«æ¥å¿ | æå页巿°ç»è®¡ãæ ç¼ºæ°æç¤ºãæ å¼å¸¸ | ãå·æ°å页ï¼å叿±æ»/åå¸åå¸å·/ä¸å£å¾åæ/éè·¯è¿è¾å¨è½¬éï¼æ°å¼æ ¼æ°=1056ããå·æ°æå页æ°å¼æ ¼æ°=711ããç¼ºæ°æç¤º=[]ãï¼æè¿ 4MB æ¥å¿æ `ERROR`/`Exception`/`WARN` | éè¿ | | TC-4 | `å叿±æ»` æ é¢ | éæ¥è¡¨ææ¹ä¸º 1-8 æ / 8 æ | `A1=2026å¹´1-8æå ¨çç´¯è®¡å®æåå¸å®¢è¿éæ åµ`ã`A12=2026å¹´8æå ¨ç宿åå¸å®¢è¿éæ åµ` | éè¿ | | TC-5 | `å叿±æ»` 累计åï¼B3:E9ï¼ | 客è¿é/忝/å¨è½¬é/忝 å 7 è¡ | 28 æ ¼å ¨é¨ä¸è´ï¼å¦ B3=269628.07ãC3=0.00117ãD3=1681467.65ãE3=0.00835ï¼ | éè¿ | | TC-6 | `å叿±æ»` 彿åï¼B14:E20ï¼ | åä¸ï¼å½æå£å¾ | 28 æ ¼å ¨é¨ä¸è´ï¼å¦ B14=32215.74ãC14=0.0444ï¼ | éè¿ | | TC-7 | `åå¸åå¸å·` æ é¢ Ã4 | 4 åæ é¢éæ¥è¡¨æ | `A1=â¦1-8æç´¯è®¡æ åµ`ã`A23=â¦1-8æç´¯è®¡æ åµ`ã`A46=â¦8ææ åµ`ã`A68=â¦8ææ åµ` | éè¿ | | TC-8 | `åå¸åå¸å·` 4 å à 17 å¸å· à 6 å¼å | 6 ç»å¼ = æ»é/å ¬äº¤/åºç§/ç½çº¦è½¦/轨é/轮渡 | 408 æ ¼å ¨é¨ä¸è´ | éè¿ | | TC-9 | `ä¸å£å¾åæ` æ é¢ + æ°å¼ | 2 åæ é¢ + æ¯å æ»/ç线/åä¹¡å ¬äº¤/å乡åºç§/å乡ç½çº¦è½¦ | `A1=1-8æä¸å£å¾å®¢è¿éåå¨è½¬é`ã`A10=8æä¸å£å¾å®¢è¿éåå¨è½¬é`ï¼B3=31528.0607ãF3=1227147.4890 ç 10 æ ¼å ¨é¨ä¸è´ | éè¿ | | TC-10 | `éè·¯è¿è¾å¨è½¬é` æ é¢ + æ°å¼ | 2 åæ é¢ + 17 å¸å· G/L/Q/W/X/Y | `A1=2026å¹´1-8æå ¨çç´¯è®¡å®æäº¤éå¨è½¬éæ åµ`ã`A23=2026å¹´8æå ¨çå®æäº¤éå¨è½¬éæ åµ`ï¼102 æ ¼å ¨é¨ä¸è´ï¼å¦ G4=17492129.04788293ãL4=269628.07ãQ4=1227147.48902ï¼W/X/Y åæåå 2025 å¹´åæç´¯è®¡ï¼å¦ W4=17492068.4575ãX4=269312.48ãY4=1256684.2157ï¼ | éè¿ | ### 3.2 è´åç¨ä¾ | ç¼å· | è¾å ¥ | 颿 | å®é | ç»è®º | | --- | --- | --- | --- | --- | | TC-N1 | ç®æ æ ¼æ¯æ¯çå ¬å¼ï¼`åå¸åå¸å·` å ¨çè¡ `B5=G5+L5+Q5+V5+X5`ã`éè·¯è¿è¾å¨è½¬é` `J4=G4/W4-1`ï¼ | ä¸è¢«åå¼è¦çï¼ä¿çæ¯çå ¬å¼ | 两è ä»ä¸ºå ¬å¼ï¼å页åå ¥æ ¼æ° 1056 < å页çè®ºæ ¼æ°ï¼è¯´æå ¬å¼æ ¼è¢«è·³è¿ | éè¿ | | TC-N2 | ç®æ æ ¼ä¸ºç©ºä¸æ°å¼ä¸º 0 | 䏿°å¢ 0ï¼é¿å ææå页忿»¡é¡µ 0 | `SM_è´§è¿` æ æ°æ®çå¸å·è½¨é/è½®æ¸¡å¼æªäº§çæ°å¢ 0 æ ¼ | éè¿ | | TC-N3 | 2025 åææ åºæ°æ® | 忝çå°è´¦é¡µ 2025 åç¼åï¼ä¸åºç° NaN/Inf | åæ¯å ¨é¨ä¸ºæéæ°ï¼å¦ `å叿±æ» C7=0.4870`ã`C14=0.0444`ï¼ | éè¿ | | TC-N4 | å°è´¦é¡µè¯»ä¸å°å¸å·æ°æ®ï¼æç«¯æ åµï¼ | è®° `WARN` å¹¶**ä¿ææ¯çåå¼**ãä¸åå页 | 代ç è·¯å¾ `curCum.isEmpty()` â `log.warn("â¦å°è´¦é¡µæªè¯»å°å¸å·æ°æ®ï¼è·³è¿ï¼ä¿ææ¯çåå¼ï¼")`ï¼æ¬è½®å°è´¦é¡µæ°æ®é½å ¨ï¼æªå®é 触åï¼**代ç 审æ¥ç¨ä¾**ï¼ | éè¿ï¼å®¡æ¥ï¼ | | TC-N5 | æ¯çæ é¢ä¸º inlineStr | æ é¢å¿ é¡»çæ£è½çæ´æ°ï¼ä¸è½åªæ¹ `<v>` | `smSetTitle` å `setBlank()` ååï¼æ 颿 ¡éªå ¨é¨è¯»åå°æ°ææ¡ | éè¿ | ### 3.3 åå½ç¨ä¾ | ç¼å· | è¾å ¥ | 颿 | å®é | ç»è®º | | --- | --- | --- | --- | --- | | TC-R1 | å¯¼åº `period=2026-07` | ä¸å´©ï¼ä¸å页åºåéæã1-7 æãå£å¾ | HTTP 200 / 942,691 åè / 25.7 ç§ï¼æ é¢ `å叿±æ» A1=2026å¹´1-7æâ¦`ã`åå¸å®¢è¿å®¢è¿éåå¸å·1-7æç´¯è®¡æ åµ`ã`1-7æä¸å£å¾å®¢è¿éåå¨è½¬é`ã`2026å¹´1-7æå ¨çç´¯è®¡å®æäº¤éå¨è½¬éæ åµ` | éè¿ | | TC-R2 | 2026-07 导åºå¼ vs æ¯ç 1-7 æéææå¨å¼ | **åºå®å ¨ä¸è´**ï¼è¯æå£å¾ä¸æ¯çä¸è´ï¼åªæ¯éæä»½å»¶é¿ï¼ | å叿±æ» B3=237412.33000000002ï¼æ¯ç 237412.33ï¼ãä¸å£å¾ B3=27524.4906ãéè·¯è¿è¾å¨è½¬é G4=15222118.44638293ãåå¸åå¸å· B6=135474.77989442425 ââ 䏿¯çé项ä¸è´ | éè¿ | | TC-R3 | å端æå¡å¯ç¨æ§ | å端é¦é¡µå¯è®¿é® | `http://localhost:8080/` HTTP 200ï¼æ é¢ã交éç»è®¡æ¥è¡¨å®¡æ ¸ç³»ç»ã | éè¿ | ### 3.4 éæ ¼ç¬ç«å¤æ ¸ï¼å ³é®è¯æ®ï¼ **æ¹æ³**ï¼ä»çæä»¶**èªèº«çå°è´¦é¡µ**éæ°èåï¼ä¸è¯»åºãä¸åèä»»ä½å ¶å®æä»¶ï¼ï¼åä¸åé¡µéæ ¼æ¯å¯¹ã | 夿 ¸èå´ | æ ¼æ° | | --- | --- | | æ é¢ï¼å叿±æ» 2 + åå¸åå¸å· 4 + ä¸å£å¾ 2 + éè·¯è¿è¾å¨è½¬é 2ï¼ | 10 | | å叿±æ» 累计åï¼7 è¡ Ã å®¢è¿é/忝/å¨è½¬é/åæ¯ï¼ | 28 | | å叿±æ» 彿åï¼åä¸ï¼ | 28 | | åå¸åå¸å· 4 å à 17 å¸å· à 6 å¼å | 408 | | ä¸å£å¾åæ 2 å à 5 è¡ Ã 2 å | 10 | | éè·¯è¿è¾å¨è½¬é 2 å à 17 å¸å· à 6 åï¼G/L/Q + J/O/T + W/X/Yï¼ | 102 | | **å计** | **586** | ç»æï¼**æ¯å¯¹ 586 æ ¼ï¼å·®å¼ 0 æ ¼**ï¼`_v5_four.txt` æ«å°¾ãæ±æ»ï¼æ¯å¯¹æ ¼æ° = 586ï¼å·®å¼æ ¼æ° = 0ãï¼ã è¡¥å èªæ´½æ ¡éªï¼å ¨çè¡ = Σ17 å¸å·ï¼ï¼éè·¯è¿è¾å¨è½¬é G4=17492129.04788293 = Σ(G5:G21)ãL4=269628.07 = Σ(L5:L21)ãQ4=1227147.48902 = Σ(Q5:Q21)ãW4/X4/Y4 åçï¼å·® ⤠6e-11ï¼æµ®ç¹è¯¯å·®çº§ï¼ã å¦ï¼13:06 é£ä¸ç彿¡£ä»¶ç¨ `_verify_four.py` 夿 ¸ï¼å«ã䏿¯ç 1-7 æéæå¼å¯¹ç §ãå°èï¼ï¼åæ ·**å·®å¼ 0 æ ¼**ã 䏿¯çéæå¼çå¯¹ç §ï¼è¯æãç¡®å®ä»éæå卿ãï¼ï¼ | åå æ ¼ | æ¯çï¼1-7 æéæï¼ | çæä»¶ï¼1-8 æï¼ | | --- | --- | --- | | å叿±æ» B3 | 237412.33 | 269628.07 | | å叿±æ» A12 | 2026å¹´7æå ¨ç宿åå¸å®¢è¿éæ åµ | 2026å¹´8æå ¨ç宿åå¸å®¢è¿éæ åµ | | åå¸åå¸å· B6 | 135474.779894424 | 153695.70483259356 | | ä¸å£å¾åæ B3 | 27524.4906 | 31528.060700000005 | | éè·¯è¿è¾å¨è½¬é G4 | 15222118.4463982 | 17492129.04788293 | ## åãåç°çé®é¢ä¸å¤ç½® 1. **æ¯çæ 颿¯ inlineStr**ï¼POI ç´æ¥ `setCellValue` åªå `<v>`ã䏿¹ `<is>`ï¼Excel 仿¾ç¤ºæ§ææ¡ï¼7 æï¼ãâ `smSetTitle` æ¹ä¸ºå `setBlank()` ååã 2. **æå页鿷·ææ¯çå ¬å¼**ï¼åå¸åå¸å·å ¨çè¡ãéè·¯è¿è¾å¨è½¬é J å忝çï¼ï¼è¥ä¸å¾åå¼ä¼ç ´åæ¯çèªæ´½å ¬å¼ãâ `smSetVal` é `FORMULA` ç´æ¥è·³è¿ï¼åå ¥æ ¼æ° 1056 å°äºå页çè®ºæ ¼æ°å³ä¸ºæ¤ã 3. **å叿±æ»ç¬¬ 5 è¡æ¯ãåºç§+ç½çº¦è½¦ãå计**ï¼ä¸æ¯ååºç§ãâ ä»£ç æãåºç§ + ç½çº¦è½¦ãåå ¥ï¼æ¯ç第 6 è¡ææ¯ååºç§ï¼ï¼ä¸æ¯çå£å¾ä¸è´ã 4. **ä¸å£å¾çãåé å乡ãä¸è½ç´æ¥åå°è´¦æ»é**ãâ æãæ»é â åå¸å ã计ç®ï¼ä» å ¬äº¤/åºç§/ç½çº¦è½¦ï¼ã 5. **åºä¸æ 2025 å¹´åå¸å®¢è¿/ç½çº¦è½¦æ°æ®**ãâ åæ¯åºæ°åæ¯çå°è´¦é¡µ 2025 å¹´éæåç¼åå¼ï¼æ¹æ¡ A çæ ¸å¿ï¼ï¼åç» 2025 æ°æ®å ¥åºåå¯ååæ¢ä¸ºè¯»åºã ## äºãç»è®º - æ£å 10 ä¾ãè´å 5 ä¾ãåå½ 3 ä¾ãéæ ¼ç¬ç«å¤æ ¸ 586 æ ¼ï¼å ¨é¨éè¿ã - åå¼ è·¨é¡µåæé¡µå·²ä»**éæ**å为**éæ¥è¡¨ææ°æ®é©±å¨**ï¼å¯¼åº 2026-08 æ¶æ é¢ä¸æ°å¼å为 1-8 æ/8 æå£å¾ï¼å¯¼åº 2026-07 æ¶åè½ç²¾ç¡®åéæä¸æ¯çä¸è´ç 1-7 ææå¨å¼ã - æ¯çå ¬å¼ä¿çãåæ¯åºæ°æ²¿ç¨æ¯ç 2025 ç¼åï¼æ¥è¡¨æå¼åä»èµ°æ¯çèªå¸¦çéç®é¾è·¯ï¼`fullCalcOnLoad`ï¼ã - éçï¼ä¸å£å¾æå页çã忝å¢éãå仿¯æ¯çæ§å¼ï¼åºä¸æ 2025 å¹´ä¸å£å¾å®ç¨¿æ°æ®ï¼ç®ä¸åºåæ¯ï¼ï¼å¾ 2025 æ°æ®å ¥åºåå·æ°ã ## å ãåå¸ä¸äºæ¬¡ç¬ç«éªè¯ï¼2026-09-13ï¼ - æäº¤ `ea7cc07`ï¼`ReportExportService.java` + æ¬æ¥å + ã工使¥ç»_2026-09-13ãå ± 3 æä»¶ï¼+689 â2ï¼å·²æ¨éåä»åºï¼ `git push gitea main`ï¼`09e612a..ea7cc07`ï¼ã`git push origin main:master`ï¼`09e612a..ea7cc07`ï¼ï¼å¹¶ `git branch -f master main`ã - æ¨éå `git fetch gitea` / `git fetch origin` å确认è¿ç«¯æ æ°æäº¤ï¼`git rev-list --left-right --count` å为 `0 0`ï¼ï¼æªè¦çåäºä»£ç ã - **åå¸åå¤è·**ï¼éæ°å¯¼åº `period=2026-08` â HTTP 200 / 950,783 åè / 29.2 ç§ï¼ç¬¬ä¸æ¬¡å尺寸ï¼ï¼å¯¹åå¸åäº§ç© `_t4_2026-08.xlsx` åè·ä¸æ¬¡ 586 æ ¼ç¬ç«å¤æ ¸ â **å·®å¼ 0 æ ¼**ï¼`_v6_four.txt`ï¼ã - **容å¨çº§æ¯å¯¹**ï¼æåå¸åäº§ç© `_t3_2026-08.xlsx` ä¸åå¸åäº§ç© `_t4_2026-08.xlsx` é zip æ¡ç®æ¯å¯¹ï¼**å ¨é¨å 鍿¡ç® ï¼`xl/worksheets/*`ã`xl/sharedStrings.xml` çï¼åèå®å ¨ä¸è´**ï¼ä¸¤è MD5 ä¸åä» æºäº xlsx 容å¨ç zip 头æ¶é´æ³ï¼åè½çä»·ã - è¿è¡ä¸çå端ï¼PID 27840ï¼æ§è¡ç代ç å³å·²æäº¤çæ¬ï¼å·¥ä½åºå¯¹è¯¥ Java æä»¶ `git diff HEAD` 为空ï¼ã docs/¹¦ÄܲâÊÔ±¨¸æ/¹¦ÄܲâÊÔ±¨¸æ_²¿Êð°ü´ò°üÓë¶ÀÁ¢Æô¶¯_2026-09-13.md
New file @@ -0,0 +1,91 @@ # åè½æµè¯æ¥å_é¨ç½²å æå ä¸ç¬ç«å¯å¨_2026-09-13 ## ä¸ãåè½è¯´æ ç¨æ·éè¦æç³»ç»æå é¨ç½²å°å¦ä¸å°æºå¨ãæ¬è½®äº¤ä»ä¸ä»¶äºï¼ ### 1. ä¸é®æå èæ¬ `package-deploy.py`ï¼æ°å¢ï¼ 䏿¡å½ä»¤å®æï¼å端æå»º â æ `dist` å åµè¿å端 jarï¼æ·è¿ `src/main/resources/static`ï¼â `mvn clean package` â æ¸ 空 staticï¼ä¿æä»åºå¹²åï¼â ç»è£ é¨ç½²ç®å½ â å缩 zipã 产ç©ï¼ - ç®å½ `deploy/traffic-audit-deploy-YYYYMMDD/` - å缩å `traffic-audit-deploy-YYYYMMDD.zip`ï¼æ¬æ¬¡ 69.9 MB / 246 个æä»¶ï¼ é¨ç½²ç®å½ç»æï¼æ²¿ç¨ 8 æçå ä¹ æ¯ï¼ï¼ ``` backend/ jarï¼å«å åµå端ï¼+ docs/ + application.yml + start-backend.cmd/.sh frontend/ dist/ + nginx.conf.example ï¼ä» nginx æ¹æ¡éè¦ï¼ db/ init.sql + sql_city_bus.sql + sql_city_taxi.sql + sql_wyc.sql README-é¨ç½²è¯´æ.txt ``` ### 2. ä¿®å¤ `JwtUtils`ï¼`jwt.secret` éæ³ Base64 导è´ç»å½ 500ï¼æ ¹å ä¿®å¤ï¼ - ç°è±¡ï¼æ¬æ¬¡çæµå®æµï¼ï¼æå¤ç½® `application.yml` ç `jwt.secret` å¡«æä¸æä¸²åï¼ç»å½æ¥å£è¿å `500 {"code":500,"message":"20018"}`ã - æ ¹å ï¼jjwt 0.9.1 é»è®¤æ secret å½ **Base64** è§£ç ï¼éæ³å符ä¼å¨ `DatatypeConverter.guessLength` æ `ArrayIndexOutOfBoundsException`ï¼è¢« `GlobalExceptionHandler` å æ 500ãé¨ç½²åäºç¬¬ä¸æ¬¡æ¹é ç½®å¾å®¹æè¸©ã - å¤ç½®ï¼`JwtUtils` æ°å¢ `secretKeyBytes()`ââè½æ Base64 è§£ç å°±ç¨è§£ç ç»æï¼ä¸åå² token å ¼å®¹ï¼ï¼å¦åæ UTF-8 åèå¤çå¹¶æ WARNã ### 3. æ´æ£ãæå é¨ç½²è¯´æãï¼`docs/æå é¨ç½²è¯´æ.md`ï¼ æ§çï¼2026-08-27ï¼æä¸å¤ä¸ç°ç¶ä¸ç¬¦ï¼æ¬æ¬¡ä¸å¹¶æ¹æ£ï¼ | æ§è¯´æ | å®é æ åµ | å¤ç | |--------|----------|------| | ãRedis å端å¯å¨å¿ éã | pom æ redis ä¾èµï¼ä»£ç 乿ªä½¿ç¨ | æ¹ä¸ºãä¸éè¦ Redisãï¼å¹¶å»æå¤ç½®é ç½®éç redis 段 | | ãjar å·²å ç½®åç«¯éææç®¡ï¼file:./web/ï¼ã | jar å æ ä»»ä½éææä»¶ï¼ä¹æ²¡æ `static-locations` é ç½®ï¼æ§å å®é é nginx | æ¹ä¸ºãæå æ¶æ dist å åµè¿ jarãï¼è®¿é® 8090 å³å¯ï¼æ é nginx | | æ°æ®åºåªæ 3 ä¸ªèæ¬ | ç°ç½è¿æ `wyc_total_monthly` / `wyc_order_monthly` ä¸¤å¼ è¡¨ | è¡¥ `db/sql_wyc.sql`ï¼å¹¶è¡¥å `summary.template-dir` çé ç½®ä¸æ¶åº | ## äºãæµè¯ç¯å¢ - å¼åæºï¼å端 8090ï¼`start-dev.ps1`ï¼éå¯å PID ååï¼ãå端 8080ãMySQL 127.0.0.1:3308ã - é¨ç½²å éªè¯ï¼æ `deploy/traffic-audit-deploy-20260913/backend` æ·å° `_deploytest/`ï¼ç¨ **8091** 端å£ç¬ç«å¯å¨ ï¼æ°æ®åºç¨å½ä»¤è¡åæ°è¦ç为 3308ï¼æ¨¡æãå¤ç½® yml + å½ä»¤è¡è¦çãä¸¤ç§æ¹é ç½®æ¹å¼ï¼ã - æµè¯æ¶é´ï¼2026-09-13ï¼èæ¬ï¼`package-deploy.py`ã`_deploy_smoke.py`ï¼ç»æ `_deploytest_result.txt`ã`_deploytest_backend.log`ï¼ã ## ä¸ãç¨ä¾è¡¨ ### 3.1 æ£åç¨ä¾ | ç¼å· | è¾å ¥ | 颿 | å®é | ç»è®º | | --- | --- | --- | --- | --- | | TC-1 | `python package-deploy.py --no-build` | äº§åº zipï¼ä¸æ æ¥é | `traffic-audit-deploy-20260913.zip` 69.9 MB / 246 æä»¶ | éè¿ | | TC-2 | æ£æ¥ jar å 容 | å«å åµå端 | jar 55.5 MBï¼`BOOT-INF/classes/static/` ä¸ 42 个æä»¶ï¼`static/index.html` åå¨ | éè¿ | | TC-3 | æ£æ¥é¨ç½²ç®å½ç»æ | backend/frontend/db/README é½å ¨ | backendï¼jar + docs + application.yml + 2 个å¯å¨èæ¬ï¼ãfrontend/distãdb 4 个 sqlãREADME | éè¿ | | TC-4 | æå åæºç ç®å½ | `src/main/resources/static` åºè¢«æ¸ 空 | æå ç»æèªå¨æ¸ 空ï¼ä»åºæ 污æï¼ | éè¿ | | TC-5 | ä»é¨ç½²å ç¬ç«å¯å¨ï¼8091ï¼ | å¯å¨æå | æ¥å¿åºç° `Started TrafficAuditApplication`ã`Tomcat started on port(s): 8091` | éè¿ | | TC-6 | `GET /` | 200 ä¸è¿åé¡µé¢ | 200ï¼1828 åèï¼å« `<div id="app">` | éè¿ | | TC-7 | `GET /js/app.*.js` | 200ï¼éæèµæºå¯è®¿é®ï¼ | 200ï¼6253 åè | éè¿ | | TC-8 | `POST /api/auth/login`ï¼admin/123456ï¼ | 200 ä¸è¿å token | 200ï¼`{"code":200,"message":"success","data":{...,"token":"eyJ..."}}` | éè¿ | | TC-9 | 带 token 导åºãéè·¯è¿è¾éæ±æ»è¡¨ã2026-08 | 200 䏿¯åæ³ xlsx | 200ï¼950,783 åèï¼å¤´é¨ `PK`ï¼ä¸å¼åæºå¯¼åºä»¶åå°ºå¯¸ï¼ | éè¿ | ### 3.2 è´åç¨ä¾ | ç¼å· | è¾å ¥ | 颿 | å®é | ç»è®º | | --- | --- | --- | --- | --- | | TC-N1 | ä¿®å¤åï¼`--jwt.secret=è¿æ¯ä¸ä¸ªä¸æå¯é¥` | æ´é²é®é¢ | ç»å½ 500ï¼æ¥å¿ `ArrayIndexOutOfBoundsException: 20018 at JwtUtils.generateToken` | å·²å¤ç°ï¼é®é¢æç«ï¼ | | TC-N2 | ä¿®å¤åï¼åæ ·ä¼ ä¸æ secret | ä¸å å¯é¥æ ¼å¼å´©ï¼ç»å½ä»å¯ç¨ | ç»å½ 200 æ¿å° tokenï¼å¯¼åºåæ · 200 / 950,783 åèï¼æ¥å¿åºç°ãjwt.secret 䏿¯åæ³ç Base64 å符串â¦ãWARN | éè¿ | | TC-N3 | å¤ç½® application.yml ä¿çå ä½å¯ç ï¼ç¨å½ä»¤è¡ `--spring.datasource.password` è¦ç | å½ä»¤è¡è¦ççæ | å¯å¨æåå¹¶æ£å¸¸æ¥åºï¼ç»å½ 200ï¼ | éè¿ | | TC-N4 | æå èæ¬é夿§è¡ï¼æ§ staging ç®å½å«åªè¯»æä»¶ï¼ | è½æ¸ çå¹¶é建 | é¦è½®æ¥ `PermissionError WinError 5`ï¼å `rmtree_force`ï¼å æ¸ åªè¯»å±æ§ï¼åæ£å¸¸ | å·²ä¿®å¤ | ### 3.3 åå½ç¨ä¾ | ç¼å· | è¾å ¥ | 颿 | å®é | ç»è®º | | --- | --- | --- | --- | --- | | TC-R1 | å¼åæºéå¯å端ï¼è½½å ¥ JwtUtils æ¹å¨ï¼ | åè½ä¸åå½ | ç»å½ 200ï¼å¯¼åº 2026-08 â HTTP 200 / 950,783 åèï¼ä¸é¨ç½²å 产ç©ã9-13 彿¡£ä»¶åå°ºå¯¸ï¼ | éè¿ | | TC-R2 | å端ç产æå»º | æå»ºæå | `npm run build` æåï¼`dist/index.html` + css/js/fonts é½å ¨ | éè¿ | ## åãåç°çé®é¢ä¸å¤ç½® 1. **`jwt.secret` éæ³ Base64 â ç»å½ 500**ï¼çæµæå°ï¼ï¼å·²ææ ¹å ä¿®å¤ï¼Base64 ä¼å ãå¦å UTF-8 å åº + WARNï¼ï¼å¹¶å¨æå é ç½®éç»åºå¯ç´æ¥ä½¿ç¨ç 32 ä½åå è¿å¶ç¤ºä¾å¼ãå¨è¯´æææ¡£éåæåå¼è§åã 2. **æå èæ¬æ¸ çæ§ç®å½è¢«åªè¯»æä»¶æ¡ä½**ï¼æº `docs` éæåªè¯» xlsxï¼`copy2` 伿åªè¯»å±æ§å¸¦è¿å»ï¼å¯¼è´ Windows ä¸ `rmtree` æ¥ãæç»è®¿é®ãâ æ°å¢ `rmtree_force()` å `chmod` åå ã 3. **æ§ãæå é¨ç½²è¯´æãä¸å¤ä¸å®**ï¼Redis å¿ é / jar å·²å ç½®å端 / 缺 sql_wyc.sqlï¼ï¼å·²å ¨é¨æ´æ£ï¼å¹¶è¡¥ä¸é¨ç½²åéªè¯æ¸ åä¸å¸¸è§é®é¢ã 4. 说æï¼çæµèæ¬éãæ¿å° tokenãé£ä¸é¡¹æå°ä¸º Falseï¼æ¯èæ¬æååºä½æªæå° 120 å符åå夿å符串导è´ï¼æªæåçä¸å° `"token"`ï¼ï¼åå§ååºä¸åç»å¸¦ token ç导åºè¯·æ±åæåï¼HTTP 200ï¼ï¼ç¨åºæ¬èº«æ é®é¢ã ## äºãç»è®º - æå èæ¬ä¸é®å¯äº§åºå¯ç´æ¥é¨ç½²ç zipï¼é¨ç½²å å¨**è±ç¦»æºç ç®å½**ãä» é jar + docs + å¤ç½®é ç½®çåæä¸ï¼ç¬ç«å¯å¨ã页é¢/éæèµæº/ç»å½/导åºå ¨é¨éè¿ï¼å¯¼åºäº§ç©ä¸å¼åæºä¸è´ï¼950,783 åèï¼ã - `jwt.secret` çé¨ç½²é·é±å·²æ ¹å ä¿®å¤ï¼é¨ç½²åäºå³ä½¿å¡«äºä¸è§èçå¼ä¹ä¸ä¼ååºç°ãç»å½ 500ãèæ ä»ä¸æã - é¨ç½²è¯´æå·²ä¸å½å代ç 对é½ï¼ä¸éè¦ Redisãä¸éè¦ nginxã4 ä¸ªå»ºè¡¨èæ¬ãå¤ç½®é 置项é½å ¨ï¼ã docs/¹¤×÷ÈÕ½á/¹¤×÷ÈÕ½á_2026-09-13.md
New file @@ -0,0 +1,117 @@ # 工使¥ç»_2026-09-13 > 补记ï¼2026-09-12 æ ä»£ç æ¹å¨ãæ æäº¤ï¼`git log --since=2026-09-12` 为空ï¼ï¼æ æªåç¬çæ¡£ã ## ä¸ãä»å¤©åäºä»ä¹ ### 1. æ±æ»å¤§è¡¨ãå页éæãé®é¢å®ä½ä¸æ¹æ¡ç¡®è®¤ - ç¨æ·åé¦ï¼å¯¼åº 2026-08 æ±æ»å¤§è¡¨åï¼`å叿±æ»`ã`åå¸åå¸å·`ã`ä¸å£å¾åæ`ã`éè·¯è¿è¾å¨è½¬é` å页æ é¢ä»åã1-7æ/7æããæ°å¼ä¹æ¯ 7 æéæå¼ã - ç»åºä¸å¥æ¹æ¡ï¼A æ²¿ç¨æ¯ç 2025 ç¼åååæ¯åºæ°çå¿«è·¯å / B ç 2025 æ°æ®å ¥åº / C åªå彿åï¼ï¼ç¨æ·éå® **æ¹æ¡ A**ã ### 2. å£å¾åæ¨ï¼å è¯ååï¼ - ææ¯çå°è´¦é¡µï¼`å ¬äº¤`/`åºç§`/`ç½çº¦è½¦`/`轨éã轮渡`/`ç线å 车`/` è´§è¿`ï¼éæ ¼èåï¼åæ¨å页å£å¾ï¼ä¸å页æå**éæ ¼ 0 å·®å¼**åæå¨ä»£ç ã - 确认å£å¾ï¼åå¸å®¢è¿é = å ¬äº¤åå¸å + åºç§åå¸å + ç½çº¦è½¦åå¸å + 轨é + 轮渡ï¼ä¸å£å¾ = ç线å 车 + (æ»é â åå¸å )Ã(å ¬äº¤/åºç§/ç½çº¦è½¦)ï¼é路货è¿å¨è½¬é = è§ä¸ + è§ä¸ï¼åæ¯ = 彿 ÷ æ¯çå°è´¦é¡µ 2025 åæå â 1ï¼åºä¸æ 2025 åå¸å®¢è¿æ°æ®ï¼æ 忝çç¼åï¼ã ### 3. 代ç å®ç°ï¼å¯ä¸æ¹å¨æä»¶ï¼ - `traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java`ï¼+494 â2ï¼ï¼ - æ°å¢ `refreshSummaryCumulativeSheets(wb, year, month)`ï¼æå¨ `refreshSummaryRankSheets` ä¹åã`applySummaryReferenceLayout` ä¹åï¼ - å°è´¦åæ° `smReadLedgerMetrics` å ¨é¨**æè¡æ ç¾è¯å«**ï¼ä¸åæ»è¡å·ï¼ï¼19 ç»´ææ ä½ï¼2026 éæå Câ¦Qã2025 åæå Vâ¦AJï¼ - åå¼ `smSetVal` éç®æ æ ¼æ¯å ¬å¼**ç´æ¥è·³è¿**ï¼ä¿çæ¯çå ¬å¼ï¼æå¼éç®ï¼ã0 ä¸åä¸ºç©ºæ ¼ä¸æ°å¢ï¼`smSetTitle` å `setBlank()` ååï¼æ¯çæ 颿¯ inlineStrï¼POI åªå `<v>` 䏿´æ° `<is>` çåï¼ã - åé¡µéæ¥è¡¨æåå ¥ **1056 æ ¼**ã ### 4. ç¼è¯ãéå¯ä¸å®æµ - `mvn -o -q compile` éè¿ï¼`start-dev.ps1` éå¯å端ï¼PID 27840ï¼ä¸å端ï¼PID 23416ï¼å就绪ã - å¯¼åº 2026-08ï¼HTTP 200 / 950,783 åè / 36.8 ç§ï¼æ¥å¿ãå·æ°åé¡µâ¦æ°å¼æ ¼æ°=1056ãå·æ°æå页æ°å¼æ ¼æ°=711ãç¼ºæ°æç¤º=[]ãï¼æè¿ 4MB æ¥å¿æ ERROR/WARNã - 彿¡£ä»¶ï¼`docs/çææ±æ»å¤§è¡¨/è¾åº/çæ_éè·¯è¿è¾éæ±æ»è¡¨_2026-08_åé¡µæ°æ®é©±å¨_2026-09-13.xlsx`ã ### 5. ç¬ç«å¤æ ¸ï¼ä»çæä»¶èªèº«å°è´¦é¡µéæ°èåï¼ - æ°å `_v5_four.py`ï¼è¦çæ é¢ 10 æ ¼ + å叿±æ»ç´¯è®¡å 28 æ ¼ + 彿å 28 æ ¼ + åå¸åå¸å· 408 æ ¼ + ä¸å£å¾ 10 æ ¼ + éè·¯è¿è¾å¨è½¬é 102 æ ¼ = **586 æ ¼ï¼å·®å¼ 0 æ ¼**ã - å¦ç¨ `_verify_four.py` 夿 ¸ 13:06 彿¡£ä»¶ï¼å«ä¸æ¯ç 1-7 æéæå¼å¯¹ç §ï¼ï¼åæ · **0 å·®å¼**ã - å ¨çè¡èªæ´½ï¼G4/L4/Q4/W4/X4/Y4 = Σ17 å¸å·ï¼å·® ⤠6e-11ï¼ã ### 6. ææ¡£ - ãåè½æµè¯æ¥å_æ±æ»å¤§è¡¨åé¡µæ°æ®é©±å¨_2026-09-13.mdãåå ¥ `docs/åè½æµè¯æ¥å/`ã - æ¬ã工使¥ç»ãã ### 7. æäº¤ä¸åå¸ - æäº¤ `ea7cc07`ï¼`ReportExportService.java` + ãåè½æµè¯æ¥å_æ±æ»å¤§è¡¨åé¡µæ°æ®é©±å¨_2026-09-13.mdã + æ¬ã工使¥ç»ãï¼3 æä»¶ +689 â2ï¼å·²æ¨éåä»åºï¼`git push gitea main`ï¼`09e612a..ea7cc07`ï¼ã`git push origin main:master`ï¼`09e612a..ea7cc07`ï¼ï¼å¹¶ `git branch -f master main`ã - æ¨éå `git fetch gitea` / `git fetch origin` åæ æ°æäº¤ï¼`rev-list --left-right --count` = `0 0`ï¼ï¼æªè¦çåäºä»£ç ã - åå¸åå¤è· 2026-08 导åºï¼HTTP 200 / 950,783 åè / 29.2 ç§ï¼ï¼å¯¹åå¸åäº§ç© `_t4_2026-08.xlsx` åå 586 æ ¼ç¬ç«å¤æ ¸ = å·®å¼ 0 æ ¼ï¼ä¸åå¸å产ç©é zip æ¡ç®æ¯å¯¹ï¼å 鍿¡ç®åèå®å ¨ä¸è´ï¼MD5 å·®å¼ä» æ¥èª zip 头æ¶é´æ³ï¼ã ### 8. æå é¨ç½²æ¯æï¼ç¨æ·æ°éæ±ï¼é¨ç½²å°å¦ä¸å°æºå¨ï¼ - æ°å¢ä¸é®æå èæ¬ `package-deploy.py`ï¼å端 `npm run build` â `dist` å åµè¿å端 jarï¼æ·å ¥ `resources/static`ï¼â `mvn clean package` â æ¸ 空 static â ç»è£ `deploy/traffic-audit-deploy-YYYYMMDD/` â å缩 `traffic-audit-deploy-YYYYMMDD.zip`ï¼æ¬æ¬¡ 69.9 MB / 246 æä»¶ï¼jar 55.5 MBï¼ã - é¨ç½²å ç»æï¼`backend/`ï¼jar + docs + application.yml + start-backend.cmd/.shï¼ã`frontend/`ï¼dist + nginx 示ä¾ï¼ã`db/`ï¼init.sql + sql_city_bus/taxi/wyc.sqlï¼ãREADMEã - **ä¿®å¤é¨ç½²é·é±**ï¼`jwt.secret` å¡«æéæ³ Base64ï¼å¦ä¸æï¼ä¼è®©ç»å½æ¥å£ 500ï¼jjwt 0.9.1 æ Base64 è§£ç secretï¼â `JwtUtils` æ°å¢ `secretKeyBytes()` å åºï¼Base64 ä¼å ãå¦å UTF-8 åè + WARNï¼ã - æ´æ£ `docs/æå é¨ç½²è¯´æ.md` ä¸å¤ä¸å®ï¼â ä¸éè¦ Redisï¼pom æ ä¾èµãä»£ç æªç¨ï¼ï¼â¡ å端æ¹ä¸ºå åµè¿ jarï¼æ§è¯´æç§°ãå·²å ç½® file:./web/ãï¼å®é jar å æ éææä»¶ï¼ï¼â¢ è¡¥ `sql_wyc.sql` ä¸ `summary.template-dir`ã - ç¬ç«éªè¯ï¼æé¨ç½²å backend æ·å° `_deploytest/` ç¨ 8091 端å£ç¬ç«å¯å¨ â å¯å¨æåã`GET /` 200 æ `#app`ãéæ js 200ãç»å½ 200 æ¿å° tokenãå¯¼åºæ±æ»å¤§è¡¨ 200 / 950,783 åèï¼ä¸å¼åæºäº§ç©å尺寸ï¼ï¼å¦æµä¸æ secret å åºè·¯å¾åæ · 200ã - å¼åæºåç«¯å·²ææ°ä»£ç éå¯ï¼æ§ PID 27840 å·²åï¼ï¼éå¯åç»å½ 200ãå¯¼åº 950,783 åèï¼æ åå½ã - æ¥åï¼`docs/åè½æµè¯æ¥å/åè½æµè¯æ¥å_é¨ç½²å æå ä¸ç¬ç«å¯å¨_2026-09-13.md`ã ### 9. æ°æ®åºæ¬è¿æ¯æï¼åçãè½ä¸è½ç´æ¥å¤ä»½æ°æ®åºè¿å»ãï¼ - ç»è®ºï¼å¯ä»¥ï¼ä¸æ¯è· 4 ä¸ªå»ºè¡¨èæ¬æ´çäºãå·²å¨ãæå é¨ç½²è¯´æãéè¡¥ã路线 A ç©ºåº 4 èæ¬ / 路线 B æ´å¥å¤ä»½è¿åãäºéä¸è¯´æï¼å¹¶æ 注 **init.sql æ¯ç ´åæ§çï¼åºç¡è¡¨é½å¸¦ DROP TABLEï¼**ï¼å·²ææ°æ®çåºä¸ä¸è½é夿§è¡ã - çæå¤ä»½ `traffic_audit_full_20260913.sql`ï¼45.5 MBï¼mysqldump --databasesï¼å«å»ºåºè¯å¥ä¸å ¨é¨ 29 å¼ è¡¨æ°æ®ï¼ã - è¿åéªè¯ï¼æå¤ä»½éçåºåæ¹æä¸´æ¶åº `traffic_audit_vfy` å¯¼å ¥ï¼é表 `COUNT(*)` 䏿ºåºæ¯å¯¹ ââ **29 å¼ è¡¨ 0 å·®å¼**ï¼æ½æ¥ `wyc_order_monthly` 2026-08 è¡æ°æ£ç¡®ï¼éªè¯åå é¤ä¸´æ¶åºã - 顺带确认ï¼å¦å¤ 3 ä¸ªèæ¬ï¼sql_city_bus/taxi/wycï¼æ²¡æ `USE` è¯å¥ï¼å¿ é¡» `-D traffic_audit` æ§è¡ï¼init.sql èªå¸¦å»ºåºè¯å¥å¯ç¬ç«æ§è¡ã ### 10. å¤ä»½è¿åççæ¬æ ¸æ¥ä¸å¼ºéªè¯ï¼å¤æ¥åç°çé®é¢ï¼ - 夿¥åç°ä¸¤ä¸ªæ¤å表述ä¸åçç¹ï¼â æ¬æº **MySQL æå¡ç«¯æ¯ 8.0.29**ï¼`D:\mysql\mysql-5.7.41-winx64` åªæ¯ 5.7 客æ·ç«¯å·¥å ·ï¼ï¼æ¨ææãæ¬æºæ¯ 5.7ãåç说æä¸åç¡®ï¼â¡ 29 å¼ è¡¨çæåºè§åç»ä¸ä¸º `utf8mb4_0900_ai_ci`ï¼**ç®æ æºå¿ é¡»è£ MySQL 8.0ï¼5.7 ä¼å¯¼å ¥å¤±è´¥**ã - å æ¤æ¹ç¨ä¸æå¡ç«¯åçæ¬ç `C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqldump.exe` 鿰坼åºå¤ä»½ `traffic_audit_full_20260913.sql`ï¼45.5 MBï¼ã - 强éªè¯ï¼8.0 客æ·ç«¯ï¼ï¼å¤ä»½æ¹åºåå¯¼å ¥ä¸´æ¶åº `traffic_audit_vfy` â 表æ°é 29=29ã表åä¸è´ã**é表 `SHOW CREATE TABLE` ç»æå·®å¼ 0**ã**é表 `COUNT(*)` è¡æ°å·®å¼ 0**ãæ½æ¥ `wyc_order_monthly` 2026-08 `order_sum` ä¸è´ â éªè¯åå é¤ä¸´æ¶åºã - é¨ç½²è¯´æå·²åæ¥æ´æ£ï¼ç¯å¢è¦æ±è¡¨ã路线 B å½ä»¤ä¸çæ¬è¯´æã`DROP TABLE` è¦çè¦åï¼ã ### 11. æ¥è¯ Navicat .nb3 å¤ä»½æ ¼å¼ï¼åçã䏿¯å¯ä»¥æå æä¸ä¸ªæä»¶ç´æ¥è¿ååãï¼ - ç¨æ·è®°å¿ä¸çãä¸ä¸ªæä»¶ç´æ¥è¿åå¤ä»½ã= Navicat ç§ææ ¼å¼ **`.nb3`**ï¼æ¬æºå·²æ 8/27 é£ä»½ï¼`D:\ææ¡£\Navicat\MySQL\Servers\mysql80\traffic_audit\20260827152017.nb3`ï¼**å·²è¿æ**ï¼27 å¼ è¡¨ã缺ç½çº¦è½¦ä¸¤å¼ ãæ°æ®åå¨ 8/27ï¼ã - è§£æåºæ ¼å¼ï¼`tar` å®¹å¨ = æ¯å¼ 表 `<uuid>.meta.json.gz`ï¼DDL/åæ®µï¼+ `<uuid>.data.000NN.sql.gz`ï¼gz æ°æ®åçï¼+ æ«å°¾æªå缩 `meta.json`ï¼DatabaseType/Schema/Objects[UUID,Type,Name,Rows,Metadata{Filename,Checksum}]ï¼ï¼`Checksum` ç»å®æµå°±æ¯è¯¥ meta æä»¶ç **SHA1ï¼å¤§åï¼**ã - ç»è®ºä¸å»ºè®®ï¼`.nb3` åªè½ç± Navicat èªèº«çæãä¹åªè½ç¨ãè¿åå¤ä»½ãè¿åï¼**ç¨ .sql ç¹ãè¿åå¤ä»½ãå¿ ç¶å¤±è´¥**ï¼ææ æ³å¨å½ä»¤è¡ä¾§å¯é åæå¹¶éªè¯ Navicat æ¯å¦æ¥åï¼æä»¥ä¸æä¾æå·¥æ¼ç .nb3ï¼æ¹ä¸ºå¨ææ¡£é忏 ãæ¬æº Navicat ç¹ä¸æ¬¡å¤ä»½ â æ·å°ç®æ æºåè·¯å¾ â è¿åå¤ä»½ãçå»çæ¥éª¤ã - `docs/æå é¨ç½²è¯´æ.md` 5.1 èæ°å¢ã路线 B2ï¼Navicat å¤ä»½/è¿åï¼.nb3ï¼ãï¼å¹¶æ³¨æä¸ç§æ¹å¼ä»»éå ¶ä¸ãä¸å¯å å ã ### 12. ãè¿è·å¼å¸¸åæãââæ¡é¢ãåææ¥åï¼åºçï¼ãéåï¼è·¨ä¼è¯ç»ä½ï¼ - ä¸ä¸ªä¼è¯ï¼thread `01a08b6d-30de-7500-8c98-f6e87100e55c`ï¼æç¨æ· 23:05 çè¦æ±ï¼ä¾æ® `D:\05\_æ°æ®åç±»\è¿è·å¼å¸¸\2026å¹´1-8æå ¨çè§ä¸è´§ç©å¨è½¬éå·®å¼çæ±æ»è¡¨(4).xlsx`ï¼`å¸å·æ±æ»`/`ä¼ä¸æç»å¯æ¬`ï¼ä¸ `D:\æ¡é¢\坿¬1-6æè´§è¿éæµç®æ°æ®åå¸å·.xlsx`ï¼`Sheet1` åå¸å·è§ä¸è´§è¿éã`Sheet2` é«é车货æ»é/æ»ééç¨/è¿è·ï¼éå `D:\æ¡é¢\åææ¥åï¼åºçï¼.docx`ï¼äº§åº **`D:\æ¡é¢\åææ¥åï¼åºçï¼_æ°_20260913.docx`ï¼43045 åèï¼6 页ï¼5 å¼ è¡¨ï¼**ï¼çæèæ¬ `_gen_report.py`ï¼ç»æä¸º ä¸ æ»ä½æ åµï¼äº ä¸é«éå ¬è·¯ææ å¯¹æ¯ï¼è¡¨1 åæã表2 累计ï¼ï¼ä¸ åè¿è¾æ¹å¼ï¼è¡¨3ï¼ï¼å åå¸å·ï¼è¡¨4ï¼ï¼äº ä¼ä¸ä¸è¿åï¼è¡¨5ï¼ï¼å ä¸ä¸æ¥å¯¹å¸å·çè¦æ±ä¸å»ºè®®ï¼6 æ¡ï¼ã - 该ä¼è¯å ä¸ä¸æè¶ é䏿ï¼requested 1,189,201 > 1,048,576 tokensï¼ï¼æ¬ä¼è¯ç»ä½ï¼è¯¥ä¼è¯ç»æåå·²æ¸²ææ ¡éª `_render_check\rp01~rp06.png`ã **äºæ 䏿¢å¤ï¼éè¦ï¼** - æ¬ä¼è¯ä¸ä¸æ¡åæ°ååçå½ä»¤æ `D:\æ¡é¢\åææ¥åï¼åºçï¼_æ°_20260913.docx` è¦çæ**çº¯ææ¬**ï¼10508 åèï¼`zipfile.is_zipfile=False`ï¼ï¼Word æå¼å³ä¸ºæ æççæåæµãè¡¨æ ¼è¢«ææä¸è¡ä¸è¯ââè¿å°±æ¯ç¨æ·åé¦ãæ ¼å¼å ¨ä¹±ãå 容差太å¤ãçç´æ¥åå ã - å¤ç½®ï¼è¯¯è¦çä»¶å·²å¤ä»½å° `_误è¦çå¤ä»½_åææ¥å_æ°_20260913_çº¯ææ¬.txt`ï¼ç¨ `D:\render_src.docx`ï¼23:10:07 åæ ·å¯æ¬ï¼è¿åæ¡é¢æä»¶ï¼**SHA256 ä¸è´**ï¼`1723594DC746BA4458F19381D893AC0A17060CCC5B20513A8A10AFB19B415373`ï¼ï¼ç»ææ ¡éª zip æ£å¸¸ã5 表 262 段ãå·²æ ¸å¯¹ï¼å¤ä»½çº¯ææ¬å 容ä¸è¿åä»¶å 容ä¸è´ï¼**æ å 容丢失**ã **å·²æ¥æ¸ çæ®çæ ¼å¼ç¼ºé·ï¼å¾ ä¿®ï¼** - `_gen_report.py` ç `borders()` æ `w:tblBorders` 追å å¨ `w:tblLook` **ä¹å**ï¼åæ³é¡ºåºåºä¸º `tblWâjcâtblBordersâtblLayoutâtblLook`ï¼ï¼ä¸ `tblW=0`ï¼type=autoï¼ã`gridCol` 6 ååå 1568ï¼å宽ä¸å 容ä¸å¹é ã - 页é¢å°ºå¯¸ï¼è¿å件为 12240Ã15840ï¼Letterï¼+1417 twips 页边è·ï¼ç¨æ·åºç¨¿ãåææ¥åï¼åºçï¼.docxã为 A4ï¼11906Ã16838ï¼+1800 twipsï¼å¾ ç»ä¸ã - 已起èä¿®å¤èæ¬ `_gen_report_v3.py`ï¼èªè¿å件读åå 容 â éæ `tblPr` 顺åºã`tblLayout=fixed`ã`autofit=False`ãæå 容åé å宽ãA4/25.4mm 页边è·ã表å è¡è·æ¹ååï¼ï¼**æ¬æ¬¡æªæ§è¡ãæªäº§åºæä»¶**ï¼ææ¥ç»§ç»ã ## äºãæµè¯ç»ææè¦ï¼è¯¦è§ãåè½æµè¯æ¥åãï¼ | 项 | ç»æ | | --- | --- | | å¯¼åº 2026-08 | HTTP 200 / 950,783 åè / 36.8 ç§ï¼ä¸¤æ¬¡å¯¼åºåèæ°ä¸è´ï¼ç¡®å®æ§ï¼ | | å页æ é¢ | å叿±æ»ãåå¸åå¸å·ï¼4 åï¼ãä¸å£å¾åæï¼2 åï¼ãéè·¯è¿è¾å¨è½¬éï¼2 åï¼å ¨é¨æ´æ°ä¸º 1-8æ/8æ | | éæ ¼å¤æ ¸ | 586 æ ¼ï¼å·®å¼ 0 æ ¼ï¼ä»çæä»¶èªèº«å°è´¦é¡µç¬ç«éç®ï¼ | | æä»½åéï¼åå½ï¼ | å¯¼åº 2026-07 æ¶å页精确åéææ¯ç 1-7 ææå¨å¼ï¼å叿±æ» B3=237412.33ãä¸å£å¾ B3=27524.4906ãå¨è½¬é G4=15222118.44638293ãåå¸åå¸å· B6=135474.77989442425 ââ 䏿¯çé项ä¸è´ | | è´å | æ¯çå ¬å¼æ ¼æªè¢«è¦çï¼`åå¸åå¸å·!B5`ã`éè·¯è¿è¾å¨è½¬é!J4` ä»ä¸ºå ¬å¼ï¼ï¼2025 æ åºæ°æ®æ¶åæ¯åæ¯çç¼åãä¸åºç° NaN/Infï¼ç©º+0 䏿°å¢ | | å端 | `http://localhost:8080/` HTTP 200ï¼é¦é¡µæ£å¸¸ï¼ | ## ä¸ãéçé®é¢ä¸å¾ å 1. **ä¸å£å¾æå页ã忝å¢éãå仿¯æ¯çæ§å¼**ï¼åºä¸åªæ 2026 å¹´æ°æ®ã没æ 2025 å¹´ä¸å£å¾å®ç¨¿æ°æ®ï¼ç®ä¸åº 8 æåæ¯ï¼ç 2025 æ°æ®å ¥åºåèªå¨å·æ°ã 2. **ç½çº¦è½¦ 8 æè®¢åæ°ä»æ¯ 7 æå¯æ¬**ï¼å·²æ¥è¯ï¼ï¼`wyc_order_monthly` ç 2026-08 è¡ `created_at=2026-09-11 16:35:10`ï¼å¯¹åº `import_batch` **#317**ãæä»¶å `_t_wyc_aug.docx`ï¼09-11 èªæµæ¶ç¨ 7 ææ¥åæ¹æ é¢ç临æ¶å¯æ¬ï¼ï¼ä½ çå®ç `模æ¿_ç½çº¦è½¦è®¢å.docx` åªå¯¼å ¥è¿ 2026-07 æï¼#314/#318/#319ï¼ã该è¡åªæ 4 ä¸ªå ¨ç pin æ¯çå® 8 ææ°æ®ï¼æ¥èªãç½çº¦è½¦æ»æ°ã#306ï¼ï¼17 å¸å·è®¢åæ°ä¸ 7 æå®å ¨ç¸åã**å¾ ç¨æ·éä¼ çå® 8 æè¿è¡çæµæ¥åï¼æ¥è¡¨æ 2026-08ï¼è¦çã** 3. **æ ¹ç®å½ä¸´æ¶æä»¶**ï¼æ¬æ¬¡ç»ç¨æ·åæå é¤èªæµå¯æ¬ `_t_wyc_aug.docx`ï¼å ¶ä½ 100+ 个 `_*` ä¸´æ¶æä»¶æªå¨ï¼ï¼`_*.py` / `_*.sql` / `_*.xlsx` / `_*.txt` / `_bak_*.java` ç 100+ 个æªè·è¸ªæä»¶ï¼ç¨æ·æªåæå䏿¸ çãä¸æäº¤ï¼ã 4. `docs/çææ±æ»å¤§è¡¨/çæ_éè·¯è¿è¾éæ±æ»è¡¨.xlsx`ï¼çå¼åç §ä»¶ï¼ä¸ `docs/çææ±æ»å¤§è¡¨/è¾åº/` ä¸çåå²äº§ç©å为æªè·è¸ªæä»¶ï¼æææ¯ä¾ä¸çº³å ¥æäº¤ã 5. 2026-08 导åºçãæªæ¾å°åæå¤ä»½æ¯çãåè¦å±æ 害æç¤ºï¼æ¯å¦æ¶é¤å¾ ç¨æ·å®ã 6. **ãåææ¥åï¼åºçï¼_æ°_20260913.docxãè¡¨æ ¼æ ¼å¼æªä¿®å®**ï¼`tblPr` 顺åºãå宽ã页边è·å¾ éæï¼èæ¬ `_gen_report_v3.py` å·²èµ·èæªæ§è¡ï¼ã 7. æ¥åãäºãä¼ä¸ä¸è¿åæ åµãæ«å°¾æ³¨æãè§ä¸ä¼ä¸æ·æ°åæ¯ãèªæè½¦è¾åå¨ä½åæ¯ä¸¤é¡¹ææ æ¬æ¬¡æªå徿°æ®ãï¼ä½ç¨æ·æç¡®è¦ãä»å¹´ä¼ä¸åå°ãè¿åä¸éãè¿ä¸å±ï¼æ°æ®æºçä¼¼ `D:\05_æ°æ®åç±»\è´§è¿\8æ\é路货ç©è¿è¾æåº¦ç产æ åµï¼2026ï¼_2026-09-13 18_24_49.xls`ï¼636 å®¶ï¼å¯¹æ¯ `D:\éè¦å¯¼å ¥çæ°æ®\è´§è¿\2025å¹´ææ¥\é路货ç©è¿è¾æåº¦ç产æ åµï¼2025å¹´8æï¼.xls`ï¼664 å®¶ï¼ââ**å°æªç±æç¬ç«æ ¸å®ï¼ä¸å¾ç´æ¥åå ¥æ¥å**ã 8. 注æï¼æ¥ååæãè¿å忝å¢é¿ 1.92%ãä¸ç¨æ·ãè¿åä¸éãç说æ³å£å¾ä¸åï¼åè ä¸ºå ¨çè¥è¿è´§è½¦å¨ä½ï¼åè ç为è§ä¸ä¼ä¸èªæè½¦è¾å¨ä½ï¼ï¼ææ¥éå ä¸ç¨æ·ç¡®è®¤å£å¾åå®ç¨¿ã ## åãæå¤©è®¡å 1. ç¨æ·æ ¸å¯¹/éä¼ çå® 8 æç½çº¦è½¦è¿è¡çæµæ¥ååï¼é导 2026-08 并夿 ¸ç½çº¦è½¦é¡µã 2. æç¨æ·åé¦ç»§ç»æ ¸å¯¹å页æåï¼éç¹ï¼åå¸åå¸å·å¢éåãéè·¯è¿è¾å¨è½¬éåæåå£å¾æ¯å¦ç¬¦åä¸å¡é¢æï¼ã 3. è·è¿ 2025 å¹´åå¸å®¢è¿/ä¸å£å¾æ°æ®å ¥åºï¼å ¥åºåæå页忝ä»ãæ¯çç¼åãåå°ã读åºãã 4. è§ç¨æ·ææ¿æ¸ çæ ¹ç®å½ä¸´æ¶æä»¶ã 5. **ï¼ä¼å ï¼** 宿ãåææ¥åï¼åºçï¼_æ°_20260913.docxãçè¡¨æ ¼æ ¼å¼ä¿®å¤ï¼æ§è¡/修订 `_gen_report_v3.py`ï¼éæ 5 å¼ è¡¨ç `tblPr` 顺åºã`tblLayout=fixed`ãæå 容åé å宽ãç»ä¸ A4 页é¢ï¼äº§åºå**èªæ¥æ¸²æ**ï¼WordâPDFâPNGï¼å¾çåªç¨äºèªæ¥ä¸åç»ç¨æ·ï¼ï¼ç¡®è®¤è¡¨æ ¼ä¸è¶çãæå¼ä¸æ¥ä¿®å¤æç¤ºã 6. å°±ãä¼ä¸ä¸è¿åãä¸¤é¡¹ææ å£å¾ä¸ç¨æ·ç¡®è®¤ï¼å ¨çè¥è¿è´§è½¦å¨ä½ +1.92% vs è§ä¸ä¼ä¸èªæè½¦è¾å¨ä½ä¸éï¼ï¼ç¡®è®¤ååè¡¥æ°ãè¡¥åæã 7. æ¥åå®ç¨¿åæè§èè¡¥ãåè½æµè¯æ¥åãï¼docs/åè½æµè¯æ¥å/ï¼ï¼åæ git åä»åºæµç¨æäº¤æ¨éã docs/´ò°ü²¿Êð˵Ã÷.md
@@ -1,6 +1,6 @@ # 交éç»è®¡æ¥è¡¨å®¡æ ¸ç³»ç» â æå ä¸é¨ç½²è¯´æ > éç¨ï¼åå¹¶å main 忝ï¼2026-08-27 èµ·ï¼ãå端 Spring Boot 2.7ï¼Java 8ï¼ï¼å端 Vue 2 + Element UIã > éç¨ï¼main åæ¯ï¼ææ°æ´æ° 2026-09-13ï¼ãå端 Spring Boot 2.7ï¼Java 8ï¼ï¼å端 Vue 2 + Element UIã > æ¬ææ¡£é¢åå¼åä¸é¨ç½²åäºï¼å½ä»¤åå¨ Windows ä¸éªè¯ã ## ä¸ã项ç®ç»æ @@ -9,156 +9,213 @@ |------|------| | `traffic-audit-server` | å端ï¼Spring Bootï¼Java 8ï¼ç«¯å£ 8090ï¼æ¥å£å ¨é¨å¨ `/api/**`ï¼ | | `traffic-audit-web` | å端ï¼Vue 2 + Element UIï¼å¼åç«¯å£ 8080ï¼`/api` 代çå° 8090ï¼ | | `docs` | è¿è¡æ°æ®ç®å½ï¼æ¥è¡¨ Word/Excel æ¨¡æ¿ + ç®å½å¯¼å ¥æ°æ®ï¼ï¼**åå¸å¿ 须带ä¸** | | `docs/init.sql` | æ°æ®åºåå§åèæ¬ï¼å»ºåºå»ºè¡¨ + åå§è´¦å·ï¼ | | `docs` | è¿è¡æ°æ®ç®å½ï¼æ¥è¡¨æ¨¡æ¿ãæ±æ»å¤§è¡¨æ¯ççï¼ï¼**åå¸å¿ 须带ä¸** | | `package-deploy.py` | ä¸é®æå èæ¬ï¼å端æå»º â å åµè¿ jar â ç»è£ é¨ç½²å â æ zipï¼ | ## äºãç¯å¢è¦æ± | ç»ä»¶ | çæ¬ | ç¨é | | ç»ä»¶ | çæ¬ | 说æ | |------|------|------| | JDK | 1.8 | å端ç¼è¯ä¸è¿è¡ | | Maven | 3.x | å端æå | | Node.js | 14+ | å端æå ï¼vue-cli 4.5ï¼ | | MySQL | 8.0 | æ°æ®åºï¼åºå `traffic_audit`ï¼ | | JDK | 1.8 | é¨ç½²æºå¿ é¡»ï¼å端ç¼è¯/è¿è¡ | | MySQL | **8.0** | é¨ç½²æºå¿ é¡»ï¼åºå `traffic_audit`ï¼ç°ç½/å¼åæºä¸º 8.0.29ï¼è¡¨æåºè§åæ¯ `utf8mb4_0900_ai_ci`ï¼**ç®æ æºè£ 5.7 ä¼å¯¼å ¥å¤±è´¥** | | Maven 3.x / Node.js 14+ | â | **åªæãå¨é¨ç½²æºä¸æå ãæéè¦**ï¼ç¨ä¸é®èæ¬äº§åºçå é¨ç½²åä¸éè¦ | | Redis | **ä¸éè¦** | ä»£ç æªä½¿ç¨ Redisï¼æ§è¯´æä¸ç Redis é ç½®æ¯éç项ï¼å¯å¿½ç¥ï¼ | | nginx / IIS | **ä¸éè¦** | å端已å åµè¿ jarï¼è®¿é® 8090 å³å¯ï¼è¦åå端åç¦»æ¶ææ¯å¤é | ## ä¸ãæ°æ®åºåå§å å æ§è¡å»ºåºå»ºè¡¨èæ¬ï¼åæéå¯¼å ¥åå¸å®¢è¿æ°æ®ï¼ ```bash mysql --default-character-set=utf8mb4 -h <主æº> -P 3306 -u root -p < docs/init.sql mysql --default-character-set=utf8mb4 -h <主æº> -P 3306 -u root -p traffic_audit < docs/sql_city_bus.sql mysql --default-character-set=utf8mb4 -h <主æº> -P 3306 -u root -p traffic_audit < docs/sql_city_taxi.sql ``` - `init.sql` ä¼é建 `traffic_audit` åºå¹¶é¢ç½®åå§è´¦å·ï¼`admin / admin123`ï¼ç产ç¯å¢è¯·ç»å½åæ¹å¯ç ï¼ - `sql_city_bus.sql`ã`sql_city_taxi.sql` 为åå¸å®¢è¿ï¼å ¬äº¤/åºç§ï¼ç¤ºä¾æ°æ®ï¼æéå¯¼å ¥ ## åãæå ### 4.1 å端ï¼é¡¹ç®æ ¹ç®å½æ§è¡ï¼ ## ä¸ãæå ï¼å¨å¼åæºä¸æ§è¡ï¼æ¨èä¸é®èæ¬ï¼ ```powershell cd D:\ææ¡£\ChatGPT\traffic-audit python package-deploy.py # å ¨æµç¨ï¼å端æå»º + å端æå + ç»è£ + å缩 python package-deploy.py --no-build # è·³è¿å端æå»ºï¼dist å·²æ¯ææ°æ¶æ´å¿«ï¼ ``` èæ¬åäºä»ä¹ï¼ 1. `traffic-audit-web` ä¸ `npm run build` â `dist`ï¼ 2. æ `dist` å¤å¶è¿ `traffic-audit-server/src/main/resources/static`ï¼ä½¿ **jar èªå¸¦å端**ï¼å `mvn clean package -DskipTests`ï¼è·å®èªå¨æ¸ 空 staticï¼ä¿æä»åºå¹²åï¼ï¼ 3. ç»è£ `deploy/traffic-audit-deploy-YYYYMMDD/`ï¼ 4. å缩为 `traffic-audit-deploy-YYYYMMDD.zip`ï¼çº¦ 70 MBï¼ã æå·¥çä»·å½ä»¤ï¼ä¸æ³ç¨èæ¬æ¶ï¼ï¼ ```powershell cd traffic-audit-web ; npm run build ; cd .. robocopy traffic-audit-web\dist traffic-audit-server\src\main\resources\static /E cmd /c "mvn -q clean package -DskipTests -f traffic-audit-server\pom.xml" ``` 产ç©ï¼`traffic-audit-server\target\traffic-audit-server-1.0.0-SNAPSHOT.jar`ï¼å¯æ§è¡ fat jarï¼çº¦ 57MBï¼ã > 注æï¼æå·¥æ¹å¼è·å®è®°å¾å æ `traffic-audit-server/src/main/resources/static` ä¸çå 容ï¼å¦å伿±¡ææºç ç®å½ã ### 4.2 å端ï¼`traffic-audit-web` ç®å½æ§è¡ï¼ ```powershell cd traffic-audit-web npm run build ``` 产ç©ï¼`traffic-audit-web\dist\`ï¼`index.html` + `css/js/fonts`ï¼çº¯éææä»¶ï¼ã ## äºãé¨ç½²ç®å½ç»æï¼æ¨èï¼ ## åãé¨ç½²å å 容 ``` deploy\ ââ app.jar # å端 jarï¼å¯æ¹åï¼ ââ docs\ # å¿ é¡»ï¼æ¨¡æ¿ä¸ç®å½å¯¼å ¥æ°æ®ç®å½ â ââ åå¸å®¢è¿\ â ââ å ¬è·¯æ 客\ â ââ è´§è¿\ â ââ è½è\ â ââ æèµ\ â â ââ æ¨¡æ¿\ â ââ (6æ\ 7æ\ çå¯¼å ¥æ°æ®ç®å½ï¼æé) ââ web\ # å端 dist çå 容ï¼ç±å端 8090 æç®¡ï¼ ââ index.html ââ css\ js\ fonts\ traffic-audit-deploy-YYYYMMDD/ ââ backend/ â ââ traffic-audit-server-1.0.0-SNAPSHOT.jar å端 + å åµå端ï¼çº¦ 55 MBï¼ â ââ docs/ 模æ¿ä¸è¿è¡æ°æ®ï¼å¿ éï¼å¿å ï¼ â ââ application.yml å¤é¨é ç½®ï¼æ¹è¿éå³å¯ï¼æ ééæå ï¼ â ââ start-backend.cmd / start-backend.sh å¯å¨èæ¬ ââ frontend/ â ââ dist/ å端产ç©ï¼ä» nginx æ¹æ¡éè¦ï¼ â ââ nginx.conf.example nginx é ç½®ç¤ºä¾ ââ db/ â ââ init.sql 建åºå»ºè¡¨ + é¢ç½®è´¦å·ï¼å¿ é¡»æ§è¡ï¼ â ââ sql_city_bus.sql åå¸å®¢è¿-å ¬äº¤æåº¦è¡¨ï¼å¿ é¡»æ§è¡ï¼ â ââ sql_city_taxi.sql åå¸å®¢è¿-åºç§æåº¦è¡¨/ææè¡¨ï¼å¿ é¡»æ§è¡ï¼ â ââ sql_wyc.sql ç½çº¦è½¦å ¨çæ»é/订ååå¸å·è¡¨ï¼å¿ é¡»æ§è¡ï¼ ââ README-é¨ç½²è¯´æ.txt ``` å ³é®ç¹ï¼ ## äºãç®æ æºå¨é¨ç½²æ¥éª¤ - **`docs` å¿ é¡»æ¾å¨ jar å级**ãå端è¿è¡æ¶æå¯å¨ç®å½å䏿¥æ¾ `docs`ï¼æ¥è¡¨å¯¼åºç Word 模æ¿ãå¯¼å ¥é¡µãä¸è½½æ¨¡æ¿ããç®å½å¯¼å ¥æ°æ®é½ä»è¿é读ï¼ï¼æ¾ä¸å°ä¼æ¥ãæªæ¾å°æ°æ®ç®å½ docsãæãæªæ¾å°æ¨¡æ¿æä»¶ xxxãã - 馿¬¡é¨ç½²ç´æ¥æé¡¹ç®éçæ´ä¸ª `docs` æ·è¿å»æç¨³å¦¥ï¼åç»å¯ç²¾ç®ï¼åªç模æ¿åç®å½ï¼ï¼è¯¦è§ã常è§é®é¢ãã - `application.yml` æå å¨ jar å ï¼å·²å ç½®åç«¯éææç®¡ï¼`file:./web/`ï¼ï¼é¨ç½²æºéè¦æ¹é ç½®æ¶ï¼å¯å¨ jar å级æ¾ä¸ä¸ªå¤ç½® `application.yml`ï¼å¤ç½®ä¼å 级é«äºå ç½®ï¼æ³¨æéå å«å®æ´é ç½®ï¼ï¼ææ¹å®åæå ã - å¯å¨åæµè§å¨ç´æ¥è®¿é® `http://<æå¡å¨>:8090`ï¼æ éé¢å¤ Web æå¡å¨ã ### 5.1 å夿°æ®åºï¼ä¸¤æ¡è·¯çº¿äºéä¸ï¼**ä¸è¦æ··çå**ï¼ ## å ãå ³é®é ç½®ï¼application.ymlï¼ #### 路线 Aï¼å ¨æ°ç©ºåºï¼è¦è· 4 ä¸ªèæ¬ï¼ `init.sql` èªå¸¦ `CREATE DATABASE` ä¸ `USE traffic_audit`ï¼å¯ç¬ç«æ§è¡ï¼å¦å¤ 3 ä¸ªèæ¬æ²¡æ `USE` è¯å¥ï¼å¿ é¡»ç¨ `-D traffic_audit`ï¼æ `mysql ... traffic_audit < æä»¶`ï¼æå®åºï¼ ```bash cd db mysql --default-character-set=utf8mb4 -u root -p < init.sql # å»ºåº + 24 å¼ åºç¡è¡¨ + é¢ç½®è´¦å· mysql --default-character-set=utf8mb4 -u root -p -D traffic_audit < sql_city_bus.sql mysql --default-character-set=utf8mb4 -u root -p -D traffic_audit < sql_city_taxi.sql mysql --default-character-set=utf8mb4 -u root -p -D traffic_audit < sql_wyc.sql ``` > â ï¸ **`init.sql` æ¯ç ´åæ§ç**ï¼éé¢çåºç¡è¡¨é½å¸¦ `DROP TABLE IF EXISTS`ã**å·²ææ°æ®çåºä¸åä¸ä¸è¦åè· init.sql**ï¼å¦åè¡¨æ°æ®ä¼è¢«æ¸ 空é建ã > 4 ä¸ªèæ¬å ±è¦ç 29 å¼ è¡¨ï¼init.sql 24 å¼ + åå¸å®¢è¿ 3 å¼ + ç½çº¦è½¦ 2 å¼ ï¼ã #### 路线 Bï¼æç°ç½/å¼åæºçæ°æ®æ´å¥æ¬è¿å»ï¼æ¨èï¼ä¸ç¨è·èæ¬ï¼ å 确认两端 MySQL 齿¯ **8.0**ï¼æ¬åºè¡¨æåºè§å为 `utf8mb4_0900_ai_ci`ï¼5.7 ä¸è¯å«ä¼å¯¼è´å¯¼å ¥å¤±è´¥ï¼ï¼å¹¶ä¸**ç¨ä¸æå¡ç«¯åçæ¬ç mysqldump**ï¼ä¸è¦ç¨ 5.7 ç客æ·ç«¯å»å¯¼ 8.0 æå¡ç«¯ï¼ã 卿ºæºå¨ï¼æ¬æº MySQL 端å£ç¤ºä¾ 3308ï¼æå®é æ¹ï¼ï¼ ```bash "C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqldump.exe" ^ --host=127.0.0.1 --port=3308 --user=root --password=ä½ çå¯ç ^ --default-character-set=utf8mb4 --single-transaction --routines --triggers --events ^ --databases traffic_audit > traffic_audit_full_YYYYMMDD.sql ``` å¨ç®æ æºå¨ï¼ ```bash mysql --default-character-set=utf8mb4 -u root -p < traffic_audit_full_YYYYMMDD.sql ``` - `--databases` 伿 `CREATE DATABASE` + `USE` ä¸èµ·åè¿å¤ä»½ï¼æä»¥ç®æ æºå¨**ä¸ç¨å 建åºãä¹ä¸ç¨è·é£ 4 ä¸ªèæ¬**ã - å¤ä»½éå å« `sys_user`ï¼è´¦å·å¯ç 䏿ºæºå¨å®å ¨ä¸è´ï¼æ¬æºæ¯ `admin / 123456`ï¼ï¼ä¸ä¼è¢«éç½®æ `admin/admin123`ã - â ï¸ å¤ä»½éæ¯å¼ 表é½å¸¦ `DROP TABLE IF EXISTS`ï¼å ± 29 å¼ ï¼ï¼**ç®æ åºè¦æ¯å·²ææ°æ®ï¼ä¼è¢«ç´æ¥è¦ç**ã请è¿åå°ç©ºåºï¼æå èªå·±å¤ä»½ç®æ åºã - æ¬æ¬¡å·²çæå¹¶**éªè¯è¿**å¤ä»½ï¼`traffic_audit_full_20260913.sql`ï¼45.5 MBï¼8.0.29 客æ·ç«¯å¯¼åºï¼ã éªè¯æ¹å¼ï¼æå¤ä»½åºåæ¹æä¸´æ¶åºå¯¼å ¥ï¼é表æ¯å¯¹ `SHOW CREATE TABLE`ï¼è¡¨ç»æï¼ä¸ `COUNT(*)`ï¼è¡æ°ï¼ââ**29 å¼ è¡¨ç»æä¸è¡æ°å 0 å·®å¼**ï¼æ½æ¥ `wyc_order_monthly` 2026-08 æ°æ®ä¸è´ï¼éªè¯åå·²å é¤ä¸´æ¶åºã #### 路线 B2ï¼ç¨ Navicat çãå¤ä»½ / è¿åå¤ä»½ãï¼.nb3ï¼æè´´è¿æ¥å¸¸ä¹ æ¯ï¼ `.nb3` æ¯ Navicat ç§æå¤ä»½æ ¼å¼ï¼tar 容å¨ï¼æ¯å¼ 表ä¸ä»½ meta.json + gz åç¼©çæ°æ®åç + SHA1 æ ¡éª + æ» meta.jsonï¼ï¼ åªè½ç± Navicat èªå·±çæãä¹åªè½å¨ Navicat éç¨ãè¿åå¤ä»½ãè¿åââ**ç¨ `.sql` ç¹ãè¿åå¤ä»½ãä¸å®å¤±è´¥**ï¼é£ä¸ªå ¥å£åªè®¤ .nb3ï¼ã 卿ºæºå¨ï¼30 ç§ï¼ï¼ 1. Navicat â è¿æ¥ `mysql80` â éä¸ `traffic_audit` â å³é® âãå¤ä»½â¦ãâ 起个åå â ç¡®å®ï¼çå®è·å®ï¼ 2. çæçå¤ä»½æä»¶å¨ Navicat ç profile ç®å½ï¼`D:\ææ¡£\Navicat\MySQL\Servers\mysql80\traffic_audit\<æ¶é´æ³>.nb3` ï¼æ¬æº 8/27 é£ä»½å°±å¨è¿éï¼ä½å®**å·²è¿æ**ï¼åªæ 27 å¼ è¡¨ã缺ç½çº¦è½¦ä¸¤å¼ è¡¨ãæ°æ®æ¯ 8/27 çï¼ä¸è¦ç¨ï¼ã å¨ç®æ æºå¨ï¼ 3. å å¨ Navicat é建ä¸ä¸ªè¿å°æ¬æº MySQL 8.0 çè¿æ¥ï¼**è¿æ¥åå»ºè®®ä¸æºæºå¨ä¸è´ï¼æ¯å¦ `mysql80`**ï¼ï¼å¹¶æ°å»ºç©ºåº `traffic_audit`ï¼å符é utf8mb4ï¼ï¼ 4. æ `.nb3` æ¾å°ç®æ æºå¨ç对åºç®å½ `<Navicat profile>\MySQL\Servers\<è¿æ¥å>\traffic_audit\`ï¼æ²¡æå°±ç §ç建ç®å½ï¼ï¼ 5. å³é®è¯¥åº âãè¿åå¤ä»½ãâ å¨éæ©å表éå¾éè¿ä»½å¤ä»½ â å¼å§ï¼å表éçä¸å°å°±éå¯ä¸æ¬¡ Navicatï¼ã > ä¸ç§æ¹å¼ï¼è·¯çº¿ A ç©ºåº 4 èæ¬ / 路线 B å½ä»¤è¡è¿å .sql / 路线 B2 Navicat .nb3ï¼**ä»»éå ¶ä¸**å³å¯ï¼ > ä½**ä¸è¦å å **ï¼è¿åå®å¤ä»½ååè· `init.sql` ä¼ææ°æ®æ¸ 空é建ã > 注æï¼`docs/` ç®å½ï¼æ¥è¡¨æ¨¡æ¿ãæ±æ»å¤§è¡¨æ¯çï¼**䏿°æ®åºæ å ³ï¼æ è®ºåªæ¡è·¯çº¿é½å¿ é¡»ä¸å¹¶æ·è´**ã ### 5.2 æ¹é ç½® `backend/application.yml` | é 置项 | 说æ | |--------|------| | `spring.datasource.url/username/password` | æ°æ®åºè¿æ¥ï¼æ¨¡æ¿é»è®¤ `localhost:3305/root/root`ï¼é¨ç½²æº**å¿ é¡»æ¹**ï¼ç产建议ç¨ç¯å¢åé `MYSQL_PASSWORD` æ³¨å ¥ï¼ | | `deepseek.api-key` | AI åææ¥å£å¯é¥ï¼ç¯å¢åé `DEEPSEEK_API_KEY`ï¼ä¸ä½¿ç¨ AI åæå¯çç©ºï¼ | | `jwt.secret` | ç»å½ä»¤çå¯é¥ï¼çäº§å¿ é¡»æ¹ï¼ç¯å¢åé `JWT_SECRET`ï¼ | | `docs.template-root` | å¯¼å ¥æ¨¡æ¿ä¸è½½æ ¹ç®å½ï¼é»è®¤ `docs`ï¼ | | `city-passenger.template-dir` | åå¸å®¢è¿æ¥è¡¨æ¨¡æ¿ç®å½ï¼é»è®¤ `docs/åå¸å®¢è¿`ï¼ | | `passenger.template-dir` | å ¬è·¯æ 客æ¥è¡¨æ¨¡æ¿ç®å½ï¼é»è®¤ `docs/å ¬è·¯æ 客`ï¼ | | `freight.template-dir` | è´§è¿æ¥è¡¨æ¨¡æ¿ç®å½ï¼é»è®¤ `docs/è´§è¿`ï¼ | | `energy.template-dir` | è½èæ¥è¡¨æ¨¡æ¿ç®å½ï¼é»è®¤ `docs/è½è`ï¼ | | `investment.template-dir` | æèµæ¥è¡¨æ¨¡æ¿ç®å½ï¼é»è®¤ `docs/æèµ/模æ¿`ï¼ | | `spring.datasource.url` | æ°æ®åºå°åï¼åºåå¼ `127.0.0.1:3306/traffic_audit`ï¼æå®é æ¹ï¼ | | `spring.datasource.username/password` | æ°æ®åºè´¦å·å¯ç ï¼**å¿ æ¹**ï¼ | | `jwt.secret` | ç»å½ä»¤çå¯é¥ï¼**å¿ é¡»æ¯ Base64 åæ³å符ä¸é¿åº¦æ¯ 4 çåæ°**ï¼åºå弿¯ä¸ä¸² 32 ä½åå è¿å¶ï¼ï¼å¡«ä¸ææéæ³å符ä¼å¯¼è´ç»å½ 500ï¼ç¨åºå·²åå åºå¹¶æ WARNï¼ä½ä»å»ºè®®å¡«è§èå¼ï¼ | | `deepseek.api-key` | AI åæç¨ï¼ä¸ç¨å¯ç空 | | `server.port` | é»è®¤ 8090 | > 注æï¼ä»åºåªæäº¤å 使¨¡æ¿ `application.yml.example`ï¼çå® `application.yml` ä¸å ¥åºã > å¤ç½® `application.yml` ä¸ jar å级å³çæï¼ä¼å 级é«äº jar å ç½®é ç½®ï¼ï¼æ¹å®ä¸ç¨éæ°æå ã ## ä¸ãå¯å¨å端 ### 5.3 å¯å¨ï¼å¿ é¡»å¨ `backend` ç®å½ä¸ï¼ ```powershell cd deploy java -jar app.jar # Windowsï¼åå» start-backend.cmdï¼æ cd backend ; java -jar traffic-audit-server-1.0.0-SNAPSHOT.jar ``` - æåæ å¿ï¼æ¥å¿åºç° `Started TrafficAuditApplication` å `Tomcat started on port(s): 8090`ã - å¨ `deploy` ç®å½ä¸å¯å¨å³å¯å½ä¸å级ç `docs`ã ## å «ãå端é¨ç½²ï¼æ¨èï¼Spring Boot ç´æ¥æç®¡ï¼æ é IIS/nginxï¼ - æå端æå»ºäº§ç© `dist` çå 容æ¾å° jar å级ç®å½ `web\`ï¼å³ `web\index.html`ã`web\js\`ã`web\css\`ã`web\fonts\`ï¼ã - å端已å ç½®ï¼`spring.web.resources.static-locations: file:./web/`ï¼éææç®¡ï¼+ å®å ¨é ç½®æ¾è¡éæèµæºï¼å¯å¨åç´æ¥è®¿é® `http://<æå¡å¨>:8090` å³å¯ï¼é¡µé¢ä¸ `/api` åæºï¼**ä¸éè¦ IIS/nginx å代**ã - å端路ç±ä¸º hash 模å¼ï¼å·æ°/ç´è¾¾æ 404 é®é¢ã ### å¤éï¼nginx æç®¡ + /api å代ï¼å¦éåå端åç¦»ï¼ ```nginx server { listen 80; server_name _; root D:/deploy/web; # å端 dist ç®å½ index index.html; location / { try_files $uri $uri/ /index.html; } location /api { proxy_pass http://127.0.0.1:8090; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } client_max_body_size 100m; # ä¸ä¼ Excel éè¦ï¼ä¸å端 multipart 100MB å¯¹é½ } ```bash # Linux cd backend && sh start-backend.sh ``` > è¥åç«¯ç± IIS æç®¡ï¼éå®è£ URL Rewrite 2.0 + ARR 3.0 å¹¶å¯ç¨ proxyï¼ç«ç¹æ ¹ç®å½æ¾ `docs/iis-web.config.example`ï¼éå½å web.configï¼ï¼è§å示ä¾è§è¯¥æä»¶ã æåæ å¿ï¼æ¥å¿åºç° `Started TrafficAuditApplication` ä¸ `Tomcat started on port(s): 8090`ã ## ä¹ãé¨ç½²åéªè¯ ### 5.4 è®¿é® 1. æµè§å¨æå¼ `http://<æå¡å¨>:8090`ï¼ 2. ç¨ `admin / admin123` ç»å½ï¼ç产æ¹å¯åä½¿ç¨æ°å¯ç ï¼ï¼ 3. æ°æ®å¯¼å ¥ï¼ä¸è½½æ¨¡æ¿ â ä¸ä¼ Excelï¼æç®å½å¯¼å ¥ï¼ï¼ 4. æ¥è¡¨ï¼æ¥è¯¢ â é¢è§/导åºï¼ä¾èµ `docs` æ¨¡æ¿æä»¶ï¼ï¼ 5. AI åæï¼éé ç½® `deepseek.api-key` åå¯ç¨ã æµè§å¨æå¼ `http://<é¨ç½²æºIP>:8090`ï¼å端已å åµï¼é¡µé¢ä¸æ¥å£åæºï¼æ é nginxï¼ï¼è´¦å· `admin / admin123`ã ## åã常è§é®é¢ ## å ãå ³é®é ç½®ï¼application.ymlï¼ä¸è¿è¡æ°æ® | é 置项 | é»è®¤å¼ | 说æ | |--------|--------|------| | `docs.template-root` | `docs` | å¯¼å ¥æ¨¡æ¿ä¸è½½æ ¹ç®å½ | | `city-passenger.template-dir` | `docs/åå¸å®¢è¿` | åå¸å®¢è¿ï¼å«ã模æ¿_ç½çº¦è½¦è®¢å.docxãï¼ | | `passenger.template-dir` | `docs/å ¬è·¯æ 客` | å ¬è·¯æ 客 | | `freight.template-dir` | `docs/è´§è¿` | è´§è¿ | | `energy.template-dir` | `docs/è½è` | è½è | | `investment.template-dir` | `docs/æèµ/模æ¿` | æèµ | | `summary.template-dir` | `docs/çææ±æ»å¤§è¡¨` | **æ±æ»å¤§è¡¨æ¯çä¸çå¼åç §ä»¶**ï¼å¯¼åºæ¥è¡¨ä¾èµï¼ | `docs/çææ±æ»å¤§è¡¨` è³å°è¦æï¼ - `çæ_éè·¯è¿è¾éæ±æ»è¡¨.xlsx`ï¼çå¼åç §ä»¶ï¼ç¼ºå¤±ä¼éåé»è®¤å宽ï¼ï¼ - éè¦å¯¼åºçåæä»½æ¯ç `YYYYå¹´Mæéè·¯è¿è¾éæ±æ»è¡¨.xlsx`ï¼ç¼ºåªä¸ªæï¼å¯¼é£ä¸ªæå°±ä¼æç¡®æ¥éï¼ã ## ä¸ãå端é¨ç½²ï¼ä¸¤ç§æ¹å¼ï¼ 1. **æ¨èï¼jar å åµ**ââä¸é®èæ¬å·²æ `dist` æè¿ jarï¼ç´æ¥è®¿é® `http://<IP>:8090` å³å¯ï¼æ éé¢å¤ Web æå¡å¨ã 2. å¤éï¼nginx æç®¡ `frontend/dist` å¹¶æ `/api` åä»£å° 8090ï¼é ç½®è§ `frontend/nginx.conf.example`ï¼ï¼ä¸ä¼ 100MB 大æä»¶æ¶è®°å¾è®¾ `client_max_body_size 100m`ã å端路ç±ä¸º hash 模å¼ï¼å·æ°/ç´è¾¾ä¸ä¼ 404ã ## å «ãé¨ç½²åéªè¯æ¸ å 1. `http://<IP>:8090` æå¼ç»å½é¡µï¼é¡µé¢ä¸æ¯ç©ºç½ï¼ï¼ 2. `admin / admin123` è½ç»å½ï¼å·¦ä¸è§æ¾ç¤ºã管çåãï¼ 3. ãæ°æ®å¯¼å ¥ã页è½ä¸è½½æ¨¡æ¿ãè½ä¸ä¼ Excelï¼ 4. ãæ¥è¡¨ã页æ¥è¯¢ + 导åºãéè·¯è¿è¾éæ±æ»è¡¨ãï¼è½ä¸è½½å° xlsxï¼ 5. æå¼å¯¼åºç xlsxï¼æ ¸å¯¹å½ææ°å¼æ¯å¦ä¸ºææ°æ¥è¡¨æã ## ä¹ã常è§é®é¢ | ç°è±¡ | åå / å¤ç | |------|------------| | å¯å¨æ¥ãæªæ¾å°æ°æ®ç®å½ docsã | å½åè¿è¡ç®å½ä¸å¯¹ï¼æ `docs` æ¾å° jar å级åå¯å¨ | | å¯¼åºæ¥ãæªæ¾å°æ¨¡æ¿æä»¶ xxxã | `docs` 对åºåç®å½ç¼ºæ¨¡æ¿æä»¶ï¼é¦æ¬¡é¨ç½²æ·æ´ä¸ª `docs` | | 页é¢è½å¼ä½æ¥å£ 404ï¼éªè¯ç å è½½å¤±è´¥ï¼ | åç«¯ç± IIS/nginx æç®¡æ¶æ²¡é `/api` åä»£ï¼æ¹ç¨ Spring Boot æç®¡ï¼web\ ç®å½ï¼åæ æ¤é®é¢ | | æ°æ®åºè¿æ¥å¤±è´¥ | æ£æ¥ `application.yml` å°å/è´¦å·/å¯ç ï¼å æ§è¡ `init.sql` | | ä¸ä¼ 大æä»¶å¤±è´¥ | æ£æ¥ nginx `client_max_body_size` ä¸å端 multipart éå¶ | | 端å£å ç¨ | å端 8090ãå端 80/8080 | | å¯å¨æ¥ãæªæ¾å°æ°æ®ç®å½ docsã | å¿ é¡»å¨ `backend` ç®å½ä¸å¯å¨ï¼jar ä¸ docs åçº§ï¼ | | å¯¼åºæ¥ãæªæ¾å°æ¨¡æ¿æä»¶ xxxã | `docs` 对åºåç®å½ç¼ºæ¨¡æ¿ï¼ä»æºæºå¨æ·è´ | | å¯¼åºæ¥ãæªæ¾å°æ±æ»è¡¨æ¯çãYYYYå¹´Mæâ¦ãã | `docs/çææ±æ»å¤§è¡¨` ç¼ºè¯¥ææ¯ç | | ç»å½æ¥å£ 500 | `jwt.secret` å¡«äºéæ³å符ï¼å¦ä¸æï¼ï¼æ¹æ 32 ä½åå è¿å¶ä¸² | | 页é¢è½å¼ä½æ¥å£ 404 | èµ° nginx æ¹æ¡æ¶æ²¡é `/api` åä»£ï¼æ¹ç¨ jar å åµè®¿é® 8090 | | æ°æ®åºè¿æ¥å¤±è´¥ | æ£æ¥ `application.yml`ï¼ç¡®è®¤ 4 个 SQL èæ¬å·²æ§è¡ | | 端å£å ç¨ | æ¹ `server.port`ï¼å端å¼åç«¯å£ 8080 | ## åä¸ãå¼åç¯å¢æ¥å¸¸å¯å¨ é¡¹ç®æ ¹ç®å½è¿è¡ä¸é®èæ¬ï¼èªå¨æèµ·å端 8090 + å端 8080ï¼ï¼ ## åãå¼åç¯å¢æ¥å¸¸å¯å¨ ```powershell powershell -NoProfile -ExecutionPolicy Bypass -File start-dev.ps1 ``` ``` å端 8090ï¼`mvn spring-boot:run`ï¼+ å端 8080ï¼`npm run serve`ï¼ï¼è®¿é® `http://localhost:8080`ã ## åä¸ãåæ´è®°å½ - **2026-09-13**ï¼æ°å¢ä¸é®æå èæ¬ `package-deploy.py`ï¼jar æ¹ä¸ºå åµå端ï¼é¨ç½²æºä¸åéè¦ nginxï¼ï¼å é¤ Redis ç¸å ³è¯´æï¼ä»£ç æªä½¿ç¨ï¼ï¼è¡¥ `sql_wyc.sql` ä¸ `summary.template-dir`ï¼è¡¥ `jwt.secret` åå¼è§åï¼è¡¥é¨ç½²åéªè¯æ¸ åã - 2026-08-27ï¼é¦çï¼zip é¨ç½²å + nginx æ¹æ¡ï¼ã package-deploy.py
New file @@ -0,0 +1,283 @@ # -*- coding: utf-8 -*- """TrafficAudit ä¸é®æå èæ¬ï¼å端æå»º -> å åµè¿å端 jar -> ç»è£ é¨ç½²å -> æ zip ç¨æ³ï¼python package-deploy.py [--no-build] """ import io, os, sys, shutil, zipfile, subprocess, datetime ROOT = os.path.dirname(os.path.abspath(__file__)) WEB = os.path.join(ROOT, "traffic-audit-web") SERVER = os.path.join(ROOT, "traffic-audit-server") STATIC = os.path.join(SERVER, "src", "main", "resources", "static") STAMP = datetime.datetime.now().strftime("%Y%m%d") STAGE = os.path.join(ROOT, "deploy", "traffic-audit-deploy-" + STAMP) ZIP = os.path.join(ROOT, "traffic-audit-deploy-" + STAMP + ".zip") JAR_NAME = "traffic-audit-server-1.0.0-SNAPSHOT.jar" SKIP_DOC_DIRS = {"ai_demo", "usage_screenshots", "åè½æµè¯æ¥å", "工使¥ç»"} def rmtree_force(path): """å é¤ç®å½ï¼å æ¸ æåªè¯»å±æ§ï¼æºç®å½éåå¨åªè¯»æä»¶ï¼copy2 ä¼å¸¦è¿æ¥ï¼å¯¼è´ Windows ä¸ rmtree æ¥æç»è®¿é®ï¼""" if not os.path.isdir(path): return for r, d, fs in os.walk(path): for f in fs: try: os.chmod(os.path.join(r, f), 0o666) except OSError: pass shutil.rmtree(path, ignore_errors=True) def run(cmd, cwd, log): with io.open(log, "w", encoding="utf-8", newline="") as f: p = subprocess.run(cmd, cwd=cwd, stdout=f, stderr=subprocess.STDOUT, shell=True) return p.returncode def main(): do_build = "--no-build" not in sys.argv print("[1/6] å端æå»º ...") if do_build: rc = run('cmd /c "npm.cmd run build 1>build_prod.log 2>&1"', WEB, os.path.join(WEB, "build_prod.log")) print(" npm run build rc=%d" % rc) if rc != 0: raise SystemExit("å端æå»ºå¤±è´¥ï¼è§ traffic-audit-web/build_prod.log") dist = os.path.join(WEB, "dist") if not os.path.isfile(os.path.join(dist, "index.html")): raise SystemExit("æªæ¾å° dist/index.htmlï¼è¯·å æå»ºå端") print("[2/6] æ dist å åµè¿å端 static å¹¶æ jar ...") copied = [] try: rmtree_force(STATIC) shutil.copytree(dist, STATIC) for r, d, fs in os.walk(STATIC): for f in fs: copied.append(os.path.join(r, f)) rc = run('cmd /c "mvn.cmd -o -q clean package -DskipTests -f traffic-audit-server\\pom.xml"', ROOT, os.path.join(ROOT, "package_build.log")) if rc != 0: print(" 离线æå å¤±è´¥ï¼æ¹ä¸ºèç½æå ...") rc = run('cmd /c "mvn.cmd -q clean package -DskipTests -f traffic-audit-server\\pom.xml"', ROOT, os.path.join(ROOT, "package_build.log")) if rc != 0: raise SystemExit("å端æå 失败ï¼è§ package_build.log") finally: rmtree_force(STATIC) os.makedirs(STATIC, exist_ok=True) jar = os.path.join(SERVER, "target", JAR_NAME) if not os.path.isfile(jar): raise SystemExit("æªæ¾å° jar: " + jar) print(" jar=%.1f MB" % (os.path.getsize(jar) / 1048576.0)) print("[3/6] ç»è£ é¨ç½²ç®å½ %s ..." % STAGE) rmtree_force(STAGE) be = os.path.join(STAGE, "backend") fe = os.path.join(STAGE, "frontend") db = os.path.join(STAGE, "db") for d in (be, fe, db): os.makedirs(d) shutil.copy2(jar, os.path.join(be, JAR_NAME)) rmtree_force(os.path.join(be, "docs")) dst_docs = os.path.join(be, "docs") os.makedirs(dst_docs) for name in os.listdir(os.path.join(ROOT, "docs")): if name in SKIP_DOC_DIRS: continue src = os.path.join(ROOT, "docs", name) dst = os.path.join(dst_docs, name) if os.path.isdir(src): shutil.copytree(src, dst, ignore=shutil.ignore_patterns("è¾åº")) else: shutil.copy2(src, dst) shutil.copytree(dist, os.path.join(fe, "dist")) for s in ("init.sql", "sql_city_bus.sql", "sql_city_taxi.sql", "sql_wyc.sql"): shutil.copy2(os.path.join(ROOT, "docs", s), os.path.join(db, s)) print("[4/6] åå ¥é ç½®ä¸å¯å¨èæ¬ ...") io.open(os.path.join(be, "application.yml"), "w", encoding="utf-8", newline="\r\n").write(APPLICATION_YML) io.open(os.path.join(be, "start-backend.cmd"), "w", encoding="utf-8", newline="\r\n").write(START_CMD) io.open(os.path.join(be, "start-backend.sh"), "w", encoding="utf-8", newline="\n").write(START_SH) io.open(os.path.join(STAGE, "frontend", "nginx.conf.example"), "w", encoding="utf-8", newline="\n").write(NGINX) io.open(os.path.join(STAGE, "README-é¨ç½²è¯´æ.txt"), "w", encoding="utf-8", newline="\r\n").write(README) print("[5/6] æ zip ...") if os.path.isfile(ZIP): os.remove(ZIP) n = 0 with zipfile.ZipFile(ZIP, "w", zipfile.ZIP_DEFLATED, compresslevel=6) as z: for r, d, fs in os.walk(STAGE): for f in fs: full = os.path.join(r, f) z.write(full, os.path.relpath(full, STAGE)) n += 1 print("[6/6] 宿ï¼%s (%.1f MB, %d 个æä»¶)" % (ZIP, os.path.getsize(ZIP) / 1048576.0, n)) APPLICATION_YML = u"""# ============================================================ # TrafficAudit å端å¤é¨é ç½®ï¼ä¸ jar å级å³å¯çæï¼ä¼å 级é«äº jar å ç½®é ç½®ï¼ # é¨ç½²å°æ°æºå¨åï¼è¯·**è³å°**ä¿®æ¹ä¸é¢æ 注 TODO çä¸å¤æ°æ®åºé ç½®ï¼ # ============================================================ server: port: 8090 app: captcha: required: false # ç产ç¯å¢å¦éå¾å½¢éªè¯ç ï¼æ¹ä¸º true spring: datasource: url: jdbc:mysql://127.0.0.1:3306/traffic_audit?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true username: root # TODO æ¹æä½ ç MySQL è´¦å· password: è¯·æ¹æä½ çæ°æ®åºå¯ç # TODO æ¹æä½ ç MySQL å¯ç driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 100MB max-request-size: 100MB jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: Asia/Shanghai mybatis-plus: mapper-locations: classpath*:/mapper/**/*.xml type-aliases-package: com.trafficaudit configuration: map-underscore-to-camel-case: true global-config: db-config: id-type: auto logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0 jwt: # å¿ é¡»æ¯ãBase64 åæ³å符 + é¿åº¦æ¯ 4 çåæ°ãï¼ä¸é¢è¿ä¸² 32 ä½åå è¿å¶å¯ç´æ¥ç¨ï¼ # ç产ç¯å¢å»ºè®®æ¢æèªå·±çéæºä¸²ï¼å¡«ä¸ææä¸åæ³å符ä¼å¯¼è´ç»å½ 500ï¼ secret: 8f2c1d64a7b34e09c5d81f6a2b0e7c93 expiration: 86400000 docs: template-root: docs city-passenger: template-dir: docs/åå¸å®¢è¿ passenger: template-dir: docs/å ¬è·¯æ 客 freight: template-dir: docs/è´§è¿ energy: template-dir: docs/è½è investment: template-dir: docs/æèµ/æ¨¡æ¿ summary: template-dir: docs/çææ±æ»å¤§è¡¨ # æ±æ»å¤§è¡¨æ¯çä¸çå¼åç §ä»¶æå¨ç®å½ï¼å¿ éï¼ deepseek: api-key: "" # AI åæç¨ï¼ç空å AI åæä¸å¯ç¨ api-url: https://api.deepseek.com/v1/chat/completions model: deepseek-chat """ START_CMD = u"""@echo off chcp 65001 >nul cd /d %~dp0 where java >nul 2>nul if errorlevel 1 ( echo [ERROR] æªæ¾å° javaï¼è¯·å å®è£ JDK 8 å¹¶å å ¥ PATH pause exit /b 1 ) echo ============================================ echo TrafficAudit å¯å¨ä¸ï¼http://localhost:8090 echo å端已å åµï¼ç´æ¥è®¿é® 8090 å³å¯ï¼ä¸éè¦ nginxï¼ echo æ¥å¿æ¾ç¤ºå¨æ¬çªå£ï¼å ³éçªå£å³åæ¢æå¡ echo ============================================ java -jar traffic-audit-server-1.0.0-SNAPSHOT.jar pause """ START_SH = u"""#!/bin/sh cd "$(dirname "$0")" || exit 1 echo "TrafficAudit å¯å¨ä¸ï¼http://localhost:8090 ï¼Ctrl+C 忢ï¼" java -jar traffic-audit-server-1.0.0-SNAPSHOT.jar 2>&1 | tee app.log """ NGINX = u"""# å端 nginx é 置示ä¾ï¼åªæå¨ä¸æ³ç¨ãjar å åµåç«¯ãæ¶æéè¦ï¼ server { listen 8080; server_name localhost; root /opt/traffic-audit/frontend/dist; # æ¹æå®é è·¯å¾ index index.html; location /api/ { proxy_pass http://127.0.0.1:8090; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_read_timeout 300s; } location / { try_files $uri $uri/ /index.html; } } """ README = u"""TrafficAudit 交éè´§è¿ç»è®¡å®¡æ ¸ç³»ç» ââ é¨ç½²å ï¼{stamp}ï¼ ======================================================== ãç®å½ç»æã backend/ traffic-audit-server-1.0.0-SNAPSHOT.jar å端ç¨åºï¼å«å ¨é¨ä¾èµï¼**å·²å åµå端**ï¼ docs/ æ¥è¡¨æ¨¡æ¿ä¸è¿è¡æ°æ®ç®å½ï¼å¿ éï¼å¿å ï¼ application.yml å¤é¨é ç½®ï¼æ¹è¿éå³å¯ï¼æ ééæ°æå ï¼ start-backend.cmd / start-backend.sh å¯å¨èæ¬ frontend/ dist/ å端æå»ºäº§ç©ï¼å¤ç¨ï¼æ³ç¨ nginx æç®¡æ¶ç¨ï¼ nginx.conf.example nginx é ç½®ç¤ºä¾ db/ init.sql 建åºå»ºè¡¨ + é¢ç½®è´¦å·ï¼å¿ é¡»æ§è¡ï¼ sql_city_bus.sql åå¸å®¢è¿-å ¬äº¤æåº¦è¡¨ï¼å¿ é¡»æ§è¡ï¼ sql_city_taxi.sql åå¸å®¢è¿-åºç§æåº¦è¡¨/åºç§ææè¡¨ï¼å¿ é¡»æ§è¡ï¼ sql_wyc.sql ç½çº¦è½¦å ¨çæ»é表/订ååå¸å·è¡¨ï¼å¿ é¡»æ§è¡ï¼ README-é¨ç½²è¯´æ.txt ãé¨ç½²æºç¯å¢è¦æ±ã JDK 8ï¼å¿ éï¼ MySQL 5.7 / 8.0ï¼å¿ éï¼ **ä¸éè¦ Redis**ï¼ä»£ç æªä½¿ç¨ï¼æ§ç说æéç Redis æ¯éçé ç½®ï¼å¯å¿½ç¥ï¼ **ä¸éè¦ nginx**ï¼å端已å åµè¿ jarï¼è®¿é® 8090 å³å¯ï¼nginx ä» ä¸ºå¤éæ¹æ¡ï¼ ãé¨ç½²æ¥éª¤ã 1. åå§åæ°æ®åºï¼4 ä¸ªèæ¬é½è¦æ§è¡ï¼é¡ºåºå¦ä¸ï¼ mysql --default-character-set=utf8mb4 -u root -p < db/init.sql mysql --default-character-set=utf8mb4 -u root -p traffic_audit < db/sql_city_bus.sql mysql --default-character-set=utf8mb4 -u root -p traffic_audit < db/sql_city_taxi.sql mysql --default-character-set=utf8mb4 -u root -p traffic_audit < db/sql_wyc.sql é¢ç½®è´¦å·ï¼admin / admin123ï¼é¦æ¬¡ç»å½å请æ¹å¯ç ï¼ 2. æ¹é ç½® backend/application.yml - spring.datasource.url / username / password ï¼æ¹æé¨ç½²æºç MySQLï¼é»è®¤ç«¯å£ 3306ï¼ - jwt.secret ï¼æ¹æä¸ä¸²éæºå符串ï¼**å¿ é¡»æ¯ Base64 åæ³å符ä¸é¿åº¦æ¯ 4 çåæ°**ï¼å¦ 32 ä½åå è¿å¶ï¼å¡«ä¸æä¼ç»å½å¤±è´¥ï¼ - deepseek.api-key ï¼éè¦ AI åææ¶å¡«ï¼ä¸éè¦å¯ç空 注ï¼application.yml ä¸ jar å级å³çæï¼ä¸ç¨éæ°æå ã 3. å¯å¨å端ï¼å¨ backend ç®å½ä¸ï¼ Windowsï¼åå» start-backend.cmd Linuxï¼ sh start-backend.sh æåæ å¿ï¼åºç° "Started TrafficAuditApplication" ä¸ "Tomcat started on port(s): 8090" 4. 访é®ç³»ç» æµè§å¨æå¼ http://<é¨ç½²æºIP>:8090 ï¼å端已å åµï¼é¡µé¢ä¸æ¥å£åæºï¼ è´¦å·ï¼admin / admin123 ãæ°æ®è¿ç§»ï¼å¯éï¼ã æ³ææ¬æºæ°æ®ä¸å¹¶æ¬å°æ°æºå¨ï¼ç¨ mysqldumpï¼æ¬æº MySQL è¥ä¸å¨ 3306ï¼æå®é ç«¯å£æ¹ï¼ï¼ mysqldump -h 127.0.0.1 -P 3306 -u root -p --databases traffic_audit > traffic_audit_full.sql å卿°æºå¨æ§è¡ï¼ mysql -u root -p < traffic_audit_full.sql 注æï¼å ¨é dump ä¼å¸¦ä¸æ¬æºçè´¦å·å¯ç ï¼è¦ç init.sql é¢ç½®ç admin è´¦å·ã ã常è§é®é¢ã 1. å¯å¨æ¥ãæªæ¾å°æ°æ®ç®å½ docsã/ å¯¼åºæ¥ãæªæ¾å°æ¨¡æ¿æä»¶ãï¼ å¿ é¡»å¨ backend ç®å½ä¸å¯å¨ï¼jar ä¸ docs å级ï¼ï¼ä¸è¦åªæ· jarã 2. æ¥è¡¨å¯¼åºæ¥ãæªæ¾å°æ±æ»è¡¨æ¯çãYYYYå¹´Mæéè·¯è¿è¾éæ±æ»è¡¨.xlsxããï¼ docs/çææ±æ»å¤§è¡¨ ä¸ç¼ºå°è¯¥æä»½æ¯çï¼ææºæºå¨ç该æä»¶æ·è¿å»ã 3. 8090 端å£è¢«å ç¨ï¼æ¹ application.yml ç server.port åéå¯ã 4. 页颿弿¯ç©ºç½ï¼ç¡®è®¤è®¿é®çæ¯ http://<IP>:8090 æ ¹è·¯å¾ï¼ä¸æµè§å¨å¼ºå¶å·æ°ï¼Ctrl+F5ï¼ã 5. ä¸ä¼ 大æä»¶å¤±è´¥ï¼å端éå¶ 100MBï¼å·²é ç½®ï¼å¦åé¢è¿æäº nginxï¼é忥æ¾å¤§ client_max_body_sizeã ã忢æå¡ã Windowsï¼å ³é start-backend.cmd çªå£ Linuxï¼ Ctrl+Cï¼æ kill å¯¹åº java è¿ç¨ï¼ps -ef | grep javaï¼ """ if __name__ == "__main__": main() traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java
@@ -3353,10 +3353,12 @@ int yoyFilled = summaryWorkbookFiller.ensureMonthYoyFormulas(wb, year, effMonth); int monthFormulaFilled = summaryWorkbookFiller.ensureMonthFormulas(wb, year, effMonth); int rankRefreshed = refreshSummaryRankSheets(wb, effPeriod, "month"); int cumulativeRefreshed = refreshSummaryCumulativeSheets(wb, year, effMonth); // åå¼ è·¨é¡µåæé¡µéæ¥è¡¨æå·æ° int widthApplied = applySummaryReferenceLayout(wb); log.info("æ±æ»å·¥ä½ç°¿æ°æ®é©±å¨å填宿ï¼åå ¥å½æå¼æ ¼æ°={}ï¼è¡¥åå½æåæ¯å ¬å¼æ ¼æ°={}ï¼è¡¥å彿åè®¡å ¬å¼æ ¼æ°={}ï¼" + "å·æ°æå页æ°å¼æ ¼æ°={}ï¼æãçæ_éè·¯è¿è¾éæ±æ»è¡¨ã对é½å宽忰={}ï¼ç¼ºæ°æç¤º={}", dbFilled, yoyFilled, monthFormulaFilled, rankRefreshed, widthApplied, dbProblems); + "å·æ°æå页æ°å¼æ ¼æ°={}ï¼å·æ°å页ï¼å叿±æ»/åå¸åå¸å·/ä¸å£å¾åæ/éè·¯è¿è¾å¨è½¬éï¼æ°å¼æ ¼æ°={}ï¼" + "æãçæ_éè·¯è¿è¾éæ±æ»è¡¨ã对é½å宽忰={}ï¼ç¼ºæ°æç¤º={}", dbFilled, yoyFilled, monthFormulaFilled, rankRefreshed, cumulativeRefreshed, widthApplied, dbProblems); applyTwoDecimalFormat(wb); // æ°å¼æ¾ç¤ºä¸¤ä½å°æ°ï¼ä¿çå ¨ç²¾åº¦ï¼ï¼% / æ¥æçæ¢ææ ·å¼ä¸æ¹å if (!wb.getCTWorkbook().isSetCalcPr()) wb.getCTWorkbook().addNewCalcPr(); wb.getCTWorkbook().getCalcPr().setFullCalcOnLoad(true); // è¿å/æ¹åå ¬å¼åæå¼å³éç® @@ -3654,6 +3656,496 @@ } /** å®ä½çå¼åç §ä»¶ docs/çææ±æ»å¤§è¡¨/çæ_éè·¯è¿è¾éæ±æ»è¡¨.xlsxï¼ä¼å çº§åæ¯çï¼é ç½®ç®å½ â user.dir ç¸å¯¹ â ä¸çº§ï¼ */ // ==================== æ±æ»å¤§è¡¨ï¼åå¼ â跨页åæâé¡µéæ¥è¡¨æå·æ° ==================== // å叿±æ» / åå¸åå¸å· / ä¸å£å¾åæ / éè·¯è¿è¾å¨è½¬é æ¤åæ´é¡µæ²¿ç¨æ¯çéæå¼ï¼æ é¢åå¨ 1-7 æï¼ã // æ¬æ®µæ 2026-09-13 å·²éªè¯å£å¾ï¼ä¸ 8 ææ¯çéæ ¼ 0 å·®å¼ï¼ä»æ¯çå°è´¦é¡µç°ç®ï¼ // åå¸å®¢è¿é = åå¸å å ¬äº¤ + åå¸å 巡游åºç§ + åå¸å ç½çº¦è½¦ + 轨é + 轮渡 // é路客è¿å¨è½¬é = å ¬è·¯ç线 + åé åä¹¡å ¬äº¤ + åé å乡巡游åºç§ + åé å乡ç½çº¦è½¦ // é路货è¿å¨è½¬é = è´§è¿é¡µ å¸å· è§ä¸è´§ç©å¨è½¬é + è§ä¸è´§ç©å¨è½¬é // 2026 å¹´ 1..N æåå°è´¦é¡µ 2026 åï¼C/E/Gâ¦ï¼ï¼å»å¹´åæåæ¯çç¼å 2025 åï¼V/X/Zâ¦ï¼ââåºé没æ 2025 å¹´åå¸å®¢è¿æ°æ®ã /** åå¸å®¢è¿å£å¾ææ ä½ï¼0..17 åå¸å®¢è¿ï¼18 è´§è¿å¨è½¬éï¼ */ private static final int SM_BUS_PAX = 0, SM_BUS_TURN = 1; private static final int SM_TAXI_PAX = 2, SM_TAXI_TURN = 3; private static final int SM_WYC_PAX = 4, SM_WYC_TURN = 5; private static final int SM_RAIL_PAX = 6, SM_RAIL_TURN = 7; private static final int SM_FERRY_PAX = 8, SM_FERRY_TURN = 9; private static final int SM_BX_PAX = 10, SM_BX_TURN = 11; private static final int SM_BUS_CX_PAX = 12, SM_BUS_CX_TURN = 13; private static final int SM_TAXI_CX_PAX = 14, SM_TAXI_CX_TURN = 15; private static final int SM_WYC_CX_PAX = 16, SM_WYC_CX_TURN = 17; private static final int SM_FREIGHT_TURN = 18; private static final int SM_DIM = 19; /** 2026 å¹´ 1 æå½æå¼åï¼0 åºï¼C åï¼ï¼2025 å¹´ 1 æå½æå¼åï¼0 åºï¼V åï¼ */ private static final int SM_CUR_COL0 = 2; private static final int SM_LAST_COL0 = 21; /** * å·æ°åå¼ è·¨é¡µåæé¡µï¼å½å¹´ç´¯è®¡ï¼1..month æï¼ã彿ï¼month æï¼å对åºåæ¯ï¼ * 2026 ä¸ 2025 åæé½åèªæ¯çå°è´¦é¡µç¼åï¼è¿ååå ¥åå æ ¼æ°ã */ private int refreshSummaryCumulativeSheets(XSSFWorkbook wb, int year, int month) { if (wb == null || month <= 0) return 0; int[] cumMonths = new int[month]; for (int m = 1; m <= month; m++) cumMonths[m - 1] = m; int[] oneMonth = new int[]{month}; Map<String, double[]> curCum = smReadLedgerMetrics(wb, true, cumMonths); Map<String, double[]> lastCum = smReadLedgerMetrics(wb, false, cumMonths); Map<String, double[]> curMon = smReadLedgerMetrics(wb, true, oneMonth); Map<String, double[]> lastMon = smReadLedgerMetrics(wb, false, oneMonth); if (curCum.isEmpty()) { log.warn("æ±æ»å¤§è¡¨å页巿°ï¼å°è´¦é¡µæªè¯»å°å¸å·æ°æ®ï¼è·³è¿ï¼ä¿ææ¯çåå¼ï¼"); return 0; } double[] pCurCum = smProvinceSum(curCum); double[] pLastCum = smProvinceSum(lastCum); double[] pCurMon = smProvinceSum(curMon); double[] pLastMon = smProvinceSum(lastMon); int n = 0; n += smWriteCitySummary(wb, year, month, pCurCum, pLastCum, pCurMon, pLastMon); n += smWriteCityByRegion(wb, month, curCum, lastCum, curMon, lastMon); n += smWriteMidAnalysis(wb, month, pCurCum, pLastCum, pCurMon, pLastMon); n += smWriteTurnoverSheets(wb, year, month, curCum, lastCum, curMon, lastMon); return n; } /** 17 å¸å·å计ï¼ä¸å«å°è´¦é¡µâå ¨çâå ¬å¼è¡ï¼ */ private double[] smProvinceSum(Map<String, double[]> m) { double[] p = new double[SM_DIM]; for (String c : RegionUtil.cityList()) { double[] a = m.get(c); if (a == null) continue; for (int i = 0; i < SM_DIM; i++) p[i] += a[i]; } return p; } /** å°è´¦é¡µç´¯è®¡åæ°ï¼å¸å·è§èå -> 19 ç»´ææ */ private Map<String, double[]> smReadLedgerMetrics(XSSFWorkbook wb, boolean curYear, int[] months) { Map<String, double[]> out = new LinkedHashMap<>(); smReadCityPaxPage(wb, "å ¬äº¤", curYear, months, out, SM_BUS_PAX, SM_BUS_TURN, SM_BUS_CX_PAX, SM_BUS_CX_TURN); smReadCityPaxPage(wb, "åºç§", curYear, months, out, SM_TAXI_PAX, SM_TAXI_TURN, SM_TAXI_CX_PAX, SM_TAXI_CX_TURN); smReadCityPaxPage(wb, "ç½çº¦è½¦", curYear, months, out, SM_WYC_PAX, SM_WYC_TURN, SM_WYC_CX_PAX, SM_WYC_CX_TURN); smReadRailFerry(wb, curYear, months, out); smReadBanxian(wb, curYear, months, out); smReadFreightTurnover(wb, curYear, months, out); return out; } /** å ¬äº¤/åºç§/ç½çº¦è½¦é¡µï¼æ¯å¸å· 4 è¡ï¼å®¢è¿é/æ 客å¨è½¬é/å ¶ä¸åå¸å 客è¿é/å ¶ä¸åå¸å æ 客å¨è½¬éï¼ */ private void smReadCityPaxPage(XSSFWorkbook wb, String sheetName, boolean curYear, int[] months, Map<String, double[]> out, int paxIdx, int turnIdx, int cxPaxIdx, int cxTurnIdx) { Sheet sh = wb.getSheet(sheetName); if (sh == null) return; int last = sh.getLastRowNum(); for (int r = sh.getFirstRowNum(); r <= last; r++) { Row row = sh.getRow(r); if (row == null) continue; String city = smCityOf(row.getCell(0)); if (city == null) continue; int paxRow = -1, turnRow = -1, cxPaxRow = -1, cxTurnRow = -1; for (int k = r; k <= Math.min(last, r + 4); k++) { Row kr = sh.getRow(k); if (kr == null) continue; String b = smText(kr.getCell(1)); if (b == null || b.contains("个ä½")) continue; boolean inner = b.contains("åå¸å "); boolean turn = b.contains("å¨è½¬é"); if (inner) { if (turn) { if (cxTurnRow < 0) cxTurnRow = k; } else if (cxPaxRow < 0) cxPaxRow = k; } else { if (turn) { if (turnRow < 0) turnRow = k; } else if (paxRow < 0) paxRow = k; } } double totalPax = smSumMonths(sh, paxRow, curYear, months); double totalTurn = smSumMonths(sh, turnRow, curYear, months); double cityPax = smSumMonths(sh, cxPaxRow, curYear, months); double cityTurn = smSumMonths(sh, cxTurnRow, curYear, months); double[] arr = out.computeIfAbsent(city, k -> new double[SM_DIM]); arr[paxIdx] += cityPax; // åå¸å®¢è¿å£å¾åâåå¸å â arr[turnIdx] += cityTurn; arr[cxPaxIdx] += totalPax - cityPax; // åé å乡 = æ»é - åå¸å arr[cxTurnIdx] += totalTurn - cityTurn; } } /** 轨éã轮渡页ï¼è½¨éåï¼æ¦æ±/é»ç³ï¼+ 轮渡åï¼æ¦æ±ï¼ */ private void smReadRailFerry(XSSFWorkbook wb, boolean curYear, int[] months, Map<String, double[]> out) { Sheet sh = wb.getSheet("轨éã轮渡"); if (sh == null) return; int last = sh.getLastRowNum(); int ferryTitle = -1; for (int r = sh.getFirstRowNum(); r <= last; r++) { Row row = sh.getRow(r); if (row == null) continue; String a = smText(row.getCell(0)); if (a != null && a.contains("轮渡客è¿é")) { ferryTitle = r; break; } } smReadRailFerryBlock(sh, curYear, months, out, sh.getFirstRowNum(), ferryTitle < 0 ? last : ferryTitle - 1, SM_RAIL_PAX); if (ferryTitle >= 0) smReadRailFerryBlock(sh, curYear, months, out, ferryTitle, last, SM_FERRY_PAX); } private void smReadRailFerryBlock(Sheet sh, boolean curYear, int[] months, Map<String, double[]> out, int start, int end, int baseIdx) { for (int r = start; r <= end; r++) { Row row = sh.getRow(r); if (row == null) continue; String city = smCityOf(row.getCell(0)); if (city == null) continue; int paxRow = -1, turnRow = -1; for (int k = r; k <= Math.min(end, r + 3); k++) { Row kr = sh.getRow(k); if (kr == null) continue; String b = smText(kr.getCell(1)); if (b == null) continue; if (b.contains("å¨è½¬é")) { if (turnRow < 0) turnRow = k; } else if (paxRow < 0) paxRow = k; } double[] arr = out.computeIfAbsent(city, k -> new double[SM_DIM]); arr[baseIdx] += smSumMonths(sh, paxRow, curYear, months); arr[baseIdx + 1] += smSumMonths(sh, turnRow, curYear, months); } } /** ç线å è½¦é¡µï¼æ¯å¸å· 客è¿é / æ 客å¨è½¬éï¼âå ¶ä¸ä¸ªä½âè¡ä¸éå¤è®¡å ¥ï¼ */ private void smReadBanxian(XSSFWorkbook wb, boolean curYear, int[] months, Map<String, double[]> out) { Sheet sh = wb.getSheet("ç线å 车"); if (sh == null) return; int last = sh.getLastRowNum(); for (int r = sh.getFirstRowNum(); r <= last; r++) { Row row = sh.getRow(r); if (row == null) continue; String city = smCityOf(row.getCell(0)); if (city == null) continue; int paxRow = -1, turnRow = -1; for (int k = r; k <= Math.min(last, r + 4); k++) { Row kr = sh.getRow(k); if (kr == null) continue; String b = smText(kr.getCell(1)); if (b == null || b.contains("个ä½")) continue; if (b.contains("å¨è½¬é")) { if (turnRow < 0) turnRow = k; } else if (b.contains("客è¿é") && paxRow < 0) paxRow = k; } double[] arr = out.computeIfAbsent(city, k -> new double[SM_DIM]); arr[SM_BX_PAX] += smSumMonths(sh, paxRow, curYear, months); arr[SM_BX_TURN] += smSumMonths(sh, turnRow, curYear, months); } } /** è´§è¿é¡µï¼æ¯å¸å· è§ä¸è´§ç©å¨è½¬é + è§ä¸è´§ç©å¨è½¬éï¼âè§ä¸+è§ä¸âè¡æ¬èº«æ¯æ±åå ¬å¼ï¼ä¸ç´æ¥åï¼ */ private void smReadFreightTurnover(XSSFWorkbook wb, boolean curYear, int[] months, Map<String, double[]> out) { Sheet sh = wb.getSheet(" è´§è¿"); if (sh == null) sh = wb.getSheet("è´§è¿"); if (sh == null) return; int last = sh.getLastRowNum(); for (int r = sh.getFirstRowNum(); r <= last; r++) { Row row = sh.getRow(r); if (row == null) continue; String city = smCityOf(row.getCell(0)); if (city == null) continue; int above = -1, below = -1; for (int k = r; k <= Math.min(last, r + 6); k++) { Row kr = sh.getRow(k); if (kr == null) continue; String b = smText(kr.getCell(1)); if (b == null || b.contains("å ¶ä¸")) continue; if (b.contains("è§ä¸è´§ç©å¨è½¬é")) { if (above < 0) above = k; } else if (b.contains("è§ä¸è´§ç©å¨è½¬é")) { if (below < 0) below = k; } } double[] arr = out.computeIfAbsent(city, k -> new double[SM_DIM]); arr[SM_FREIGHT_TURN] += smSumMonths(sh, above, curYear, months) + smSumMonths(sh, below, curYear, months); } } private double smSumMonths(Sheet sh, int rowIdx, boolean curYear, int[] months) { if (sh == null || rowIdx < 0) return 0; Row row = sh.getRow(rowIdx); if (row == null) return 0; double s = 0; for (int m : months) { int col = (curYear ? SM_CUR_COL0 : SM_LAST_COL0) + 2 * (m - 1); s += smNum(row.getCell(col)); } return s; } /** å°è´¦é¡µåå æ ¼åæ°ï¼æ°å / æ°åææ¬ / å ¬å¼ç¼åï¼ */ private double smNum(Cell c) { if (c == null) return 0; try { CellType t = c.getCellType(); if (t == CellType.NUMERIC) return c.getNumericCellValue(); if (t == CellType.FORMULA) { return c.getCachedFormulaResultType() == CellType.NUMERIC ? c.getNumericCellValue() : 0; } if (t == CellType.STRING) { String s = c.getStringCellValue(); if (s == null) return 0; s = s.replace(",", "").replace("%", "").trim(); if (s.isEmpty()) return 0; return Double.parseDouble(s); } } catch (Exception ignore) { return 0; } return 0; } private String smText(Cell c) { if (c == null) return null; try { return c.getCellType() == CellType.STRING ? c.getStringCellValue() : null; } catch (Exception e) { return null; } } /** å A ææ¡ -> è§èå¸å·åï¼âå ¨ç/æ¹åçâä¸éå¸å·è¡è¿å nullï¼ */ private String smCityOf(Cell a) { String t = smText(a); if (t == null || t.trim().isEmpty()) return null; String norm = RegionUtil.normalizeCityName(t.trim()); if (norm == null) return null; return RegionUtil.cityList().contains(norm) ? norm : null; } private double smYoy(double cur, double last) { return last == 0.0 ? 0.0 : (cur - last) / last; } /** åå¼ï¼å ¬å¼æ ¼ä¸å¨ï¼ä¿çæ¯çå ¬å¼ï¼æå¼å³éç®ï¼ï¼0 ä¸åä¸ºç©ºæ ¼å䏿°å¢ */ private int smSetVal(Sheet sh, int r0, int c0, double v) { Row row = sh.getRow(r0); if (row == null) return 0; Cell c = row.getCell(c0); if (c != null && c.getCellType() == CellType.FORMULA) return 0; if (c == null) { if (v == 0.0) return 0; c = row.createCell(c0); Cell left = row.getCell(c0 - 1); if (left != null) c.setCellStyle(left.getCellStyle()); } else if (v == 0.0 && c.getCellType() == CellType.BLANK) { return 0; } c.setBlank(); c.setCellValue(v); return 1; } private void smSetTitle(Sheet sh, int r0, int c0, String text) { if (sh == null) return; Row row = sh.getRow(r0); if (row == null) return; Cell c = row.getCell(c0); if (c == null || c.getCellType() == CellType.FORMULA) return; c.setBlank(); c.setCellValue(text); } /** å叿±æ»é¡µï¼å1ï¼1..N æç´¯è®¡ï¼è¡ 3-9ï¼å2ï¼å½æï¼è¡ 14-20ï¼å B/C/D/E = 客è¿é/忝/å¨è½¬é/忝 */ private int smWriteCitySummary(XSSFWorkbook wb, int year, int month, double[] pCurCum, double[] pLastCum, double[] pCurMon, double[] pLastMon) { Sheet sh = wb.getSheet("å叿±æ»"); if (sh == null) return 0; smSetTitle(sh, 0, 0, year + "å¹´1-" + month + "æå ¨çç´¯è®¡å®æåå¸å®¢è¿éæ åµ"); smSetTitle(sh, 11, 0, year + "å¹´" + month + "æå ¨ç宿åå¸å®¢è¿éæ åµ"); int n = 0; int[] rows = {2, 3, 4, 5, 6, 7, 8}; for (int i = 0; i < rows.length; i++) { double[] v = smCitySummaryRow(pCurCum, pLastCum, i); n += smSetVal(sh, rows[i], 1, v[0]); n += smSetVal(sh, rows[i], 2, v[2]); n += smSetVal(sh, rows[i], 3, v[1]); n += smSetVal(sh, rows[i], 4, v[3]); } for (int i = 0; i < rows.length; i++) { double[] v = smCitySummaryRow(pCurMon, pLastMon, i); n += smSetVal(sh, rows[i] + 11, 1, v[0]); n += smSetVal(sh, rows[i] + 11, 2, v[2]); n += smSetVal(sh, rows[i] + 11, 3, v[1]); n += smSetVal(sh, rows[i] + 11, 4, v[3]); } return n; } /** i=0 æ»å®¢è¿é 1 å ¬äº¤ 2 åºç§è½¦ 3 巡游åºç§ 4 ç½çº¦è½¦ 5 轨é 6 轮渡ï¼è¿å [客è¿é, å¨è½¬é, 客è¿é忝, å¨è½¬é忝] */ private double[] smCitySummaryRow(double[] p, double[] pl, int i) { double pax, turn, lPax, lTurn; if (i == 0) { pax = p[SM_BUS_PAX] + p[SM_TAXI_PAX] + p[SM_WYC_PAX] + p[SM_RAIL_PAX] + p[SM_FERRY_PAX]; turn = p[SM_BUS_TURN] + p[SM_TAXI_TURN] + p[SM_WYC_TURN] + p[SM_RAIL_TURN] + p[SM_FERRY_TURN]; lPax = pl[SM_BUS_PAX] + pl[SM_TAXI_PAX] + pl[SM_WYC_PAX] + pl[SM_RAIL_PAX] + pl[SM_FERRY_PAX]; lTurn = pl[SM_BUS_TURN] + pl[SM_TAXI_TURN] + pl[SM_WYC_TURN] + pl[SM_RAIL_TURN] + pl[SM_FERRY_TURN]; } else if (i == 1) { pax = p[SM_BUS_PAX]; turn = p[SM_BUS_TURN]; lPax = pl[SM_BUS_PAX]; lTurn = pl[SM_BUS_TURN]; } else if (i == 2) { pax = p[SM_TAXI_PAX] + p[SM_WYC_PAX]; turn = p[SM_TAXI_TURN] + p[SM_WYC_TURN]; lPax = pl[SM_TAXI_PAX] + pl[SM_WYC_PAX]; lTurn = pl[SM_TAXI_TURN] + pl[SM_WYC_TURN]; } else if (i == 3) { pax = p[SM_TAXI_PAX]; turn = p[SM_TAXI_TURN]; lPax = pl[SM_TAXI_PAX]; lTurn = pl[SM_TAXI_TURN]; } else if (i == 4) { pax = p[SM_WYC_PAX]; turn = p[SM_WYC_TURN]; lPax = pl[SM_WYC_PAX]; lTurn = pl[SM_WYC_TURN]; } else if (i == 5) { pax = p[SM_RAIL_PAX]; turn = p[SM_RAIL_TURN]; lPax = pl[SM_RAIL_PAX]; lTurn = pl[SM_RAIL_TURN]; } else { pax = p[SM_FERRY_PAX]; turn = p[SM_FERRY_TURN]; lPax = pl[SM_FERRY_PAX]; lTurn = pl[SM_FERRY_TURN]; } return new double[]{pax, turn, smYoy(pax, lPax), smYoy(turn, lTurn)}; } /** åå¸åå¸å·é¡µï¼4 åï¼ç´¯è®¡å®¢è¿é/累计å¨è½¬é/彿客è¿é/彿å¨è½¬éï¼ï¼æ¯å å ¨ç 1 è¡ + 17 å¸å· */ private int smWriteCityByRegion(XSSFWorkbook wb, int month, Map<String, double[]> curCum, Map<String, double[]> lastCum, Map<String, double[]> curMon, Map<String, double[]> lastMon) { Sheet sh = wb.getSheet("åå¸åå¸å·"); if (sh == null) return 0; smSetTitle(sh, 0, 0, "åå¸å®¢è¿å®¢è¿éåå¸å·1-" + month + "æç´¯è®¡æ åµ"); smSetTitle(sh, 22, 0, "åå¸å®¢è¿å®¢è¿å¨è½¬éåå¸å·1-" + month + "æç´¯è®¡æ åµ"); smSetTitle(sh, 45, 0, "åå¸å®¢è¿å®¢è¿éåå¸å·" + month + "ææ åµ"); smSetTitle(sh, 67, 0, "åå¸å®¢è¿å®¢è¿å¨è½¬éåå¸å·" + month + "ææ åµ"); int n = 0; n += smWriteCityByRegionBlock(sh, 4, true, curCum, lastCum); n += smWriteCityByRegionBlock(sh, 26, false, curCum, lastCum); n += smWriteCityByRegionBlock(sh, 49, true, curMon, lastMon); n += smWriteCityByRegionBlock(sh, 71, false, curMon, lastMon); return n; } private int smWriteCityByRegionBlock(Sheet sh, int provRow, boolean pax, Map<String, double[]> cur, Map<String, double[]> last) { int n = 0; double[] provCur = smProvinceSum(cur); double[] provLast = smProvinceSum(last); List<String> cities = RegionUtil.cityList(); for (int i = -1; i < cities.size(); i++) { int r = provRow + i + 1; double[] c = i < 0 ? provCur : cur.get(cities.get(i)); double[] l = i < 0 ? provLast : last.get(cities.get(i)); if (c == null) c = new double[SM_DIM]; if (l == null) l = new double[SM_DIM]; double[] g = smCityGroupValues(c, l, pax); n += smSetVal(sh, r, 1, g[0]); n += smSetVal(sh, r, 4, g[6]); n += smSetVal(sh, r, 6, g[1]); n += smSetVal(sh, r, 9, g[7]); n += smSetVal(sh, r, 11, g[2]); n += smSetVal(sh, r, 14, g[8]); n += smSetVal(sh, r, 16, g[3]); n += smSetVal(sh, r, 19, g[9]); n += smSetVal(sh, r, 21, g[4]); n += smSetVal(sh, r, 22, g[10]); n += smSetVal(sh, r, 23, g[5]); n += smSetVal(sh, r, 24, g[11]); } return n; } /** 6 ç»å¼ + 6 ç»å¢éï¼[æ»é, å ¬äº¤, åºç§, ç½çº¦è½¦, 轨é, 轮渡, æ»éå¢é, å ¬äº¤â¦, 轮渡] */ private double[] smCityGroupValues(double[] c, double[] l, boolean pax) { int busI = pax ? SM_BUS_PAX : SM_BUS_TURN; int taxiI = pax ? SM_TAXI_PAX : SM_TAXI_TURN; int wycI = pax ? SM_WYC_PAX : SM_WYC_TURN; int railI = pax ? SM_RAIL_PAX : SM_RAIL_TURN; int ferryI = pax ? SM_FERRY_PAX : SM_FERRY_TURN; double bus = c[busI], taxi = c[taxiI], wyc = c[wycI], rail = c[railI], ferry = c[ferryI]; double lBus = l[busI], lTaxi = l[taxiI], lWyc = l[wycI], lRail = l[railI], lFerry = l[ferryI]; double total = bus + taxi + wyc + rail + ferry; double lTotal = lBus + lTaxi + lWyc + lRail + lFerry; return new double[]{total, bus, taxi, wyc, rail, ferry, smYoy(total, lTotal), smYoy(bus, lBus), smYoy(taxi, lTaxi), smYoy(wyc, lWyc), smYoy(rail, lRail), smYoy(ferry, lFerry)}; } /** ä¸å£å¾åæé¡µï¼å1ï¼ç´¯è®¡ï¼è¡ 3-7ï¼å2ï¼å½æï¼è¡ 12-16ï¼å B/C/F/G = 客è¿é/忝/å¨è½¬é/忝 */ private int smWriteMidAnalysis(XSSFWorkbook wb, int month, double[] pCurCum, double[] pLastCum, double[] pCurMon, double[] pLastMon) { Sheet sh = wb.getSheet("ä¸å£å¾åæ"); if (sh == null) return 0; smSetTitle(sh, 0, 0, "1-" + month + "æä¸å£å¾å®¢è¿éåå¨è½¬é"); smSetTitle(sh, 9, 0, month + "æä¸å£å¾å®¢è¿éåå¨è½¬é"); int n = 0; int[] rows = {2, 3, 4, 5, 6}; for (int i = 0; i < rows.length; i++) { double[] v = smMidRow(pCurCum, pLastCum, i); n += smSetVal(sh, rows[i], 1, v[0]); n += smSetVal(sh, rows[i], 2, v[2]); n += smSetVal(sh, rows[i], 5, v[1]); n += smSetVal(sh, rows[i], 6, v[3]); } for (int i = 0; i < rows.length; i++) { double[] v = smMidRow(pCurMon, pLastMon, i); n += smSetVal(sh, rows[i] + 9, 1, v[0]); n += smSetVal(sh, rows[i] + 9, 2, v[2]); n += smSetVal(sh, rows[i] + 9, 5, v[1]); n += smSetVal(sh, rows[i] + 9, 6, v[3]); } return n; } /** i=0 æ» 1 å ¬è·¯ç线 2 åé åä¹¡å ¬äº¤ 3 åé å乡巡游åºç§ 4 åé å乡ç½çº¦è½¦ï¼è¿å [客è¿é, å¨è½¬é, 客è¿é忝, å¨è½¬é忝] */ private double[] smMidRow(double[] p, double[] pl, int i) { int[] paxIdx = {SM_BX_PAX, SM_BX_PAX, SM_BUS_CX_PAX, SM_TAXI_CX_PAX, SM_WYC_CX_PAX}; int[] turnIdx = {SM_BX_TURN, SM_BX_TURN, SM_BUS_CX_TURN, SM_TAXI_CX_TURN, SM_WYC_CX_TURN}; double pax, turn, lPax, lTurn; if (i == 0) { pax = p[SM_BX_PAX] + p[SM_BUS_CX_PAX] + p[SM_TAXI_CX_PAX] + p[SM_WYC_CX_PAX]; turn = p[SM_BX_TURN] + p[SM_BUS_CX_TURN] + p[SM_TAXI_CX_TURN] + p[SM_WYC_CX_TURN]; lPax = pl[SM_BX_PAX] + pl[SM_BUS_CX_PAX] + pl[SM_TAXI_CX_PAX] + pl[SM_WYC_CX_PAX]; lTurn = pl[SM_BX_TURN] + pl[SM_BUS_CX_TURN] + pl[SM_TAXI_CX_TURN] + pl[SM_WYC_CX_TURN]; } else { pax = p[paxIdx[i]]; turn = p[turnIdx[i]]; lPax = pl[paxIdx[i]]; lTurn = pl[turnIdx[i]]; } return new double[]{pax, turn, smYoy(pax, lPax), smYoy(turn, lTurn)}; } /** éè·¯è¿è¾å¨è½¬é页ï¼å1ï¼ç´¯è®¡ï¼è¡ 4-21ï¼å2ï¼å½æï¼è¡ 26-43ï¼åªåå¼åï¼B/E/V çå ¬å¼ä¿çï¼ */ private int smWriteTurnoverSheets(XSSFWorkbook wb, int year, int month, Map<String, double[]> curCum, Map<String, double[]> lastCum, Map<String, double[]> curMon, Map<String, double[]> lastMon) { Sheet sh = wb.getSheet("éè·¯è¿è¾å¨è½¬é"); if (sh == null) return 0; smSetTitle(sh, 0, 0, year + "å¹´1-" + month + "æå ¨çç´¯è®¡å®æäº¤éå¨è½¬éæ åµ"); smSetTitle(sh, 22, 0, year + "å¹´" + month + "æå ¨çå®æäº¤éå¨è½¬éæ åµ"); int n = 0; n += smWriteTurnoverBlock(sh, 3, curCum, lastCum); n += smWriteTurnoverBlock(sh, 25, curMon, lastMon); return n; } private int smWriteTurnoverBlock(Sheet sh, int provRow, Map<String, double[]> cur, Map<String, double[]> last) { int n = 0; double[] provCur = smProvinceSum(cur); double[] provLast = smProvinceSum(last); List<String> cities = RegionUtil.cityList(); for (int i = -1; i < cities.size(); i++) { int r = provRow + i + 1; double[] c = i < 0 ? provCur : cur.get(cities.get(i)); double[] l = i < 0 ? provLast : last.get(cities.get(i)); if (c == null) c = new double[SM_DIM]; if (l == null) l = new double[SM_DIM]; double freight = c[SM_FREIGHT_TURN], lFreight = l[SM_FREIGHT_TURN]; double pax = c[SM_BUS_PAX] + c[SM_TAXI_PAX] + c[SM_WYC_PAX] + c[SM_RAIL_PAX] + c[SM_FERRY_PAX]; double lPax = l[SM_BUS_PAX] + l[SM_TAXI_PAX] + l[SM_WYC_PAX] + l[SM_RAIL_PAX] + l[SM_FERRY_PAX]; double road = c[SM_BX_TURN] + c[SM_BUS_CX_TURN] + c[SM_TAXI_CX_TURN] + c[SM_WYC_CX_TURN]; double lRoad = l[SM_BX_TURN] + l[SM_BUS_CX_TURN] + l[SM_TAXI_CX_TURN] + l[SM_WYC_CX_TURN]; n += smSetVal(sh, r, 6, freight); n += smSetVal(sh, r, 9, smYoy(freight, lFreight)); n += smSetVal(sh, r, 11, pax); n += smSetVal(sh, r, 14, smYoy(pax, lPax)); n += smSetVal(sh, r, 16, road); n += smSetVal(sh, r, 19, smYoy(road, lRoad)); n += smSetVal(sh, r, 22, lFreight); n += smSetVal(sh, r, 23, lPax); n += smSetVal(sh, r, 24, lRoad); } return n; } private File resolveSummaryLayoutRef() { String rel = summaryTemplateDir; while (rel != null && rel.startsWith("./")) rel = rel.substring(2); traffic-audit-server/src/main/java/com/trafficaudit/security/utils/JwtUtils.java
@@ -3,9 +3,13 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.impl.TextCodec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -13,11 +17,27 @@ @Component public class JwtUtils { private static final Logger log = LoggerFactory.getLogger(JwtUtils.class); @Value("${jwt.secret}") private String secret; @Value("${jwt.expiration}") private Long expiration; /** * ç¾åå¯é¥åèï¼jjwt 0.9.x é»è®¤æ secret å½ Base64 è§£ç ï¼è¥é ç½®æä¸æçéæ³ Base64 ä¼å¨ç»å½æ¶æ * ArrayIndexOutOfBoundsExceptionï¼è¡¨ç°ä¸ºãç»å½æ¥å£ 500ããè¿éåå åºï¼è½æ Base64 è§£ç å°±ç¨è§£ç ç»æ * ï¼ä¸åå² token å ¼å®¹ï¼ï¼å¦åæ UTF-8 åèå¤çï¼å¹¶ææç¤ºæå°æ¥å¿éã */ private byte[] secretKeyBytes() { try { return TextCodec.BASE64.decode(secret); } catch (Exception e) { log.warn("jwt.secret 䏿¯åæ³ç Base64 å符串ï¼å·²æ UTF-8 åèä½ä¸ºç¾åå¯é¥ï¼å»ºè®®æ¹æ 32 ä½éæºåå è¿å¶ä¸²ã"); return secret.getBytes(StandardCharsets.UTF_8); } } public String generateToken(String username) { Map<String, Object> claims = new HashMap<>(); @@ -27,19 +47,19 @@ .setSubject(username) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + expiration)) .signWith(SignatureAlgorithm.HS256, secret) .signWith(SignatureAlgorithm.HS256, secretKeyBytes()) .compact(); } public String getUsernameFromToken(String token) { Claims claims = Jwts.parser().setSigningKey(secret) Claims claims = Jwts.parser().setSigningKey(secretKeyBytes()) .parseClaimsJws(token).getBody(); return claims.getSubject(); } public boolean validateToken(String token) { try { Jwts.parser().setSigningKey(secret).parseClaimsJws(token); Jwts.parser().setSigningKey(secretKeyBytes()).parseClaimsJws(token); return true; } catch (Exception e) { return false;