| docs/功能测试报告/功能测试报告_汇总表排名页刷新与同比百分数_2026-09-11.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| docs/工作日结/工作日结_2026-09-11.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| traffic-audit-server/src/main/java/com/trafficaudit/reportexport/calc/SummaryWorkbookFiller.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
docs/¹¦ÄܲâÊÔ±¨¸æ/¹¦ÄܲâÊÔ±¨¸æ_»ã×ܱíÅÅÃûҳˢÐÂÓëͬ±È°Ù·ÖÊý_2026-09-11.md
New file @@ -0,0 +1,80 @@ # åè½æµè¯æ¥å_æ±æ»è¡¨æå页巿°ä¸åæ¯ç¾åæ°_2026-09-11 ## ä¸ãåè½è¯´æ ç¨æ·åé¦ãéè·¯è¿è¾éæ±æ»è¡¨ã两个é®é¢ï¼**1. æææå表éé¢çæ°æ®æ²¡ææ´æ°ï¼2. 忝åºè¯¥æ¯ç¾åæ°è䏿¯å°æ°**ãæ¬è½®å®ä½å¹¶ä¿®å¤ï¼ ### 1. æåé¡µæ°æ®å·æ°ï¼é®é¢ 1ï¼ - ç°è±¡ï¼æ±æ»å¤§è¡¨æ¯ç `2026å¹´8æéè·¯è¿è¾éæ±æ»è¡¨.xlsx` éç `è´§è¿éæå` / `è´§è¿å¨è½¬éæå` / `ä¸å£å¾æå` ä¸é¡µæ¯**ä¸ä¸æ¥è¡¨æçéæå¼**ï¼æ é¢åã2026å¹´1-7æ / 2026å¹´7æãï¼æ°å¼ä¹æ¯ 7 æï¼ï¼å¯¼åº 8 ææ¶æ´é¡µä¸éæ°æ®ååã - å¤ç½®ï¼å¯¼åºé¾è·¯æ°å¢ `refreshSummaryRankSheets`ï¼ç¨ç¨åºèªå·±çç¬ç«æå表ï¼`çæ_è´§è¿éæå.xlsx` / `çæ_å¨è½¬éæå.xlsx` / `çæ_ä¸å£å¾æå.xlsx`ï¼ä¸ç¨æ·æ¥å¸¸æ ¸å¯¹å£å¾ä¸è´ï¼å·æ°è¿ä¸é¡µï¼ - æ°å¼æ ¼æ¬æ°å¼ï¼æºä¾§æ¯å ¬å¼çï¼RANK/å æ¯çï¼æç®æ ååç§»æ´ä½å¹³ç§»ååæå ¬å¼ï¼æå¼æ¶ææ±æ»è¡¨èªèº«æ°æ®éç®ï¼ï¼ç®æ æ ¼æ¬èº«å·²æ¯å ¬å¼çï¼æ¯ç SUM/RANK/å æ¯ï¼ä¿çä¸å¨ï¼ - åæ é¢éæ¥è¡¨æåæ¥ï¼`2026å¹´1-7æâ¦` â `2026å¹´1-8æâ¦`ã`2026å¹´7æâ¦` â `2026å¹´8æâ¦`ï¼ã ### 2. åæ¯åæ¾ç¤ºæå°æ°ï¼é®é¢ 2ï¼ - ç°è±¡ï¼æ¯çææ°æä»½ï¼8 æï¼ç忝ååæäºãæ®éæ°å¼ `0.00`ãæ ¼å¼ï¼è 7 æå以åç忝忝 `0.00%`ï¼åå¡«å ¬å¼å 8 æåæ¯æ¾ç¤ºæ `-0.0294` è¿æ ·çå°æ°ã - å¤ç½®ï¼`SummaryWorkbookFiller.ensureMonthYoyFormulas` 忥åªå¨ç®æ æ ¼ä¸ºç©ºæ¶å¥ç¨ä¸æåæ¯åæ ·å¼ï¼æ¹ä¸º**æ æ¡ä»¶æ²¿ç¨ä¸æåæ¯åæ ·å¼**ï¼`0.00%`ï¼ã ### æ¹å¨æä»¶ - `traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java`ï¼æ°å¢ `refreshSummaryRankSheets` / `copyRankValues` / `rankCell` / `shiftFormula`ï¼å¨ `ensureMonthFormulas` ä¹åã`applySummaryReferenceLayout` ä¹åè°ç¨ã - `traffic-audit-server/src/main/java/com/trafficaudit/reportexport/calc/SummaryWorkbookFiller.java`ï¼`ensureMonthYoyFormulas` æ ·å¼æ²¿ç¨ã ## äºãæµè¯ç¯å¢ - å端 `http://localhost:8090`ï¼`start-dev.ps1` å¯å¨ï¼ï¼å¯¼åºæ¥å£ `GET /api/report/export/summaryWorkbook?period=YYYY-MM`ã - æ¯çï¼`docs/çææ±æ»å¤§è¡¨/2026å¹´8æéè·¯è¿è¾éæ±æ»è¡¨.xlsx`ï¼çå¼åç §ï¼`docs/çææ±æ»å¤§è¡¨/çæ_éè·¯è¿è¾éæ±æ»è¡¨.xlsx`ã - ç¬ç«æå表åºç¨¿ï¼`docs/è´§è¿/çæ_è´§è¿éæå.xlsx`ã`docs/è´§è¿/çæ_å¨è½¬éæå.xlsx`ã`docs/å ¬è·¯æ 客/çæ_ä¸å£å¾æå.xlsx`ã - æµè¯æ¶é´ï¼2026-09-11ï¼æµè¯äº§ç©ï¼`_gen2_2026-08.xlsx`ã`_gen2_2026-07.xlsx`ã`_v2_freight_rank.xlsx`ã`_v2_turnover_rank.xlsx`ã`_v2_mid_rank.xlsx`ã ## ä¸ãç¨ä¾è¡¨ ### 3.1 æ£åç¨ä¾ | ç¼å· | è¾å ¥ | 颿 | å®é | ç»è®º | | --- | --- | --- | --- | --- | | TC-1 | å¯¼åº `period=2026-08` | HTTP 200ï¼æ£å¸¸äº§åºæä»¶ | 949,956 åèï¼23.8 ç§è¿å | éè¿ | | TC-2 | å端åå¡«æ¥å¿ | ææå页巿°ç»è®¡ãæ ç¼ºæ°æç¤º | åå ¥å½æå¼æ ¼æ°=1659ï¼è¡¥åå½æåæ¯å ¬å¼æ ¼æ°=600ï¼è¡¥å彿åè®¡å ¬å¼æ ¼æ°=43ï¼**å·æ°æå页æ°å¼æ ¼æ°=711**ï¼å¯¹é½å宽忰=422ï¼ç¼ºæ°æç¤º=[] | éè¿ | | TC-3 | è´§è¿éæååæ é¢ | éæ¥è¡¨ææ¹ä¸º 1-8 æ/8 æ | `A1=2026å¹´1-8æå ¨çåå¸å·ç´¯è®¡å®æå ¬è·¯è´§è¿éæ åµ`ï¼`A22=2026å¹´8æå ¨çåå¸å·å®æå ¬è·¯è´§è¿éæ åµ` | éè¿ | | TC-4 | è´§è¿å¨è½¬éæååæ é¢ | åä¸ | `A2=â¦2026å¹´1-8æâ¦`ï¼`A24=â¦2026å¹´8æâ¦` | éè¿ | | TC-5 | ä¸å£å¾æååæ é¢ | åä¸ | `J1=2026å¹´1-8æå ¨çåå¸å·ç´¯è®¡å®æé路客è¿ç产æ åµ`ï¼`J22=2026å¹´8æâ¦` | éè¿ | | TC-6 | æ é¢è½çæ¹å¼ï¼åå§ XML æ ¡éªï¼ | `<is><t>` 䏿¾ç¤ºä¸è´ï¼ä¸è½ååºç° `<v>` æ°å¼ + `<is>` æ§å¼ï¼ | `xl/worksheets/sheet2.xml`ï¼`<c r="A1" s="776" t="s"><v>0</v></c>`ï¼å ±äº«ä¸² 0 = `2026å¹´1-8æâ¦`ï¼æ§æä»¶æ¯ inlineStrï¼`<v>`=8æã`<is><t>`=7æï¼ | éè¿ | | TC-7 | è´§è¿éæåéæ ¼å ¥åºæ½æ¥ï¼ä¸ç¬ç«æå表æ¯å¯¹ï¼ | å ¨åä¸è´ | 累计å + 彿åå ± **454 æ ¼é个æ¯å¯¹ï¼0 å¤ä¸ä¸è´** | éè¿ | | TC-8 | è´§è¿å¨è½¬éæåå½æåæ½æ¥ | ä¸ç¬ç«è¡¨ä¸è´ | æ¦æ± B28=192320.5226ï¼æº B27ï¼ãG28=504369.61288609065ï¼æº G27ï¼ãE28=0.3334642531154999ï¼æº E27ï¼ãJ28=-0.021161120884320206ï¼æº J27ï¼ | éè¿ | | TC-9 | è´§è¿å¨è½¬éæåæ¯çå ¬å¼ä¿ç | ä¸åæ»å¼ï¼ä¿ç SUM/RANK/å æ¯ | å ¨ç B27=`=SUM(B28:B44)`ï¼æ¦æ± C28=`=RANK(B28,B$28:B$44)`ãD28=`=B28/B$27` | éè¿ | | TC-10 | ä¸å£å¾æåæ°å¼æ½æ¥ | ä¸ç¬ç«è¡¨ä¸è´ | K4=2759.8855ï¼æº B4ï¼ãO4=152330.9312ï¼æº F4ï¼ãK25=349.536ï¼æº L4ï¼ãO25=18917.1637ï¼æº P4ï¼ | éè¿ | | TC-11 | ä¸å£å¾æåãå¢éæåãå | ä¸åæ¯éææªå¼ï¼ä¸ä¸é¡µå åæ¯èªæ´½ | ç±éæå¼ï¼å¤è¡å为 1.0ï¼æ¹ä¸º `=RANK(M4,M$4:M$20)`ã`=RANK(M25,M$25:M$41)` çèªæ´½å ¬å¼ï¼ç¼åå¼ä¸æ¯çåå¼ä¸è´ï¼L25=5ãN25=10ãP25=2ãR25=5ï¼ | éè¿ | | TC-12 | 8 æåæ¯åæ ¼å¼ï¼é®é¢ 2ï¼ | ç¾åæ° `0.00%` | è´§è¿ R5=`=Q5/AJ5-1` / `0.00%`ï¼ç线å 车ãåå¸å®¢è¿ãå ¬äº¤ãåºç§ãç½çº¦è½¦ã轨é轮渡ãä¸å£å¾æç» 8 æåæ¯åï¼R åï¼**å ¨é¨ `0.00%`** | éè¿ | | TC-13 | æåé¡µåæ¯åæ ¼å¼ | ç¾åæ° `0.00%` | è´§è¿éæå E4=-0.0763 / `0.00%`ãD5=0.3207⦠/ `0.00%`ï¼è´§è¿å¨è½¬éæåãä¸å£å¾æå忝åå为 `0.00%` | éè¿ | | TC-14 | æå¼å³éç® | ä»å¸¦å ¨ééç®æ è®° | `<calcPr ⦠fullCalcOnLoad="true"/>` ä¿ç | éè¿ | ### 3.2 è´åç¨ä¾ | ç¼å· | è¾å ¥ | 颿 | å®é | ç»è®º | | --- | --- | --- | --- | --- | | TC-N1 | å ¨è¡¨æ«æã表头å«åæ¯ + æ°å¼/å ¬å¼ + æ ¼å¼éç¾åæ°ãçæ ¼ | ä¸åºææ°å¼å ¥çå°æ°åæ¯ | 8 æä»¶å½ä¸ 3 æ ¼ï¼å ¨é¨å¨éè页ï¼`2025å¹´åå¸å®¢è¿é!E13`ã`ä¸å£å¾è®¡ç®è¿ç¨!G85/G86`ï¼ï¼æ¯çåä½ç½®åæ ·å¦æ¤ | éè¿ï¼éæ¬è½®å¼å ¥ï¼ | | TC-N2 | ç¬ç«æå表æºä¾§åæ¯ä¸ºç©ºæ¶ï¼åºä¸æ 2025 å¹´ä¸å£å¾æ°æ®ï¼ | ä¸åºæ POI 对空å¼çæ±å¼ç»æï¼å ¨ä¸º 1ï¼æ¬è¿æ±æ»è¡¨ | æ¹ä¸ºåå ¬å¼åï¼è¯¥å为 `=RANK(â¦)` å ¬å¼ï¼æé¡µå 忝åå¼ï¼ä¸åæ¯ 17 è¡å ¨ 1 | éè¿ | | TC-N3 | è°è¯æ¥å¿æ¸ ç | å¯¼åºæ¥å¿ä¸åºæ®ç `RANKDBG` | `backend.log` ä¸ `RANKDBG` è®¡æ° = 0 | éè¿ | ### 3.3 å岿åå½ï¼2026-07ï¼ | ç¼å· | è¾å ¥ | 颿 | å®é | ç»è®º | | --- | --- | --- | --- | --- | | TC-R1 | å¯¼åº `period=2026-07` | æ£å¸¸äº§åºã彿忝仿å 2025 å¹´ 7 æ | 941,903 åèï¼è´§è¿ P5=`=O5/AF5-1` / `0.00%` | éè¿ | | TC-R2 | 䏿¹å¨å 7 æäº§ç©ï¼`_gen_2026-07.xlsx`ï¼éæ ¼ diff | å·®å¼ä» éè¢«å·æ°çæå页 | ä» `è´§è¿éæå` 51 æ ¼ã`ä¸å£å¾æå` 133 æ ¼æå·®å¼ï¼æå页ç±éæå¼æ¹ä¸ºææ°æ®å·æ°ï¼å±é¢æï¼ï¼å ¶ä½ 16 页 0 å·®å¼ | éè¿ | | TC-R3 | 7 ææå页æ é¢ | ä»ä¸º 1-7 æ/7 æï¼ææ¥è¡¨æï¼ | `A1=2026å¹´1-7æâ¦`ã`A22=2026å¹´7æâ¦`ï¼ä¸å£å¾ `J22=2026å¹´7æâ¦` | éè¿ | | TC-R4 | 7 æåæ¯æ ¼å¼ | æ æ°å¢å°æ°åæ¯ | å ¨è¡¨å½ä¸ 3 æ ¼ï¼å为éè页æ¯çåææ ¼ | éè¿ | ## åãåç°çé®é¢ä¸å¤ç½® 1. **æå页æ 颿¹äºä½ Excel 仿¾ç¤ºæ§æä»½**ï¼æ¯çæ é¢åå æ ¼æ¯ `inlineStr`ï¼POI å¨ `t="inlineStr"` åå æ ¼ä¸ `setCellValue(String)` åªå `<v>`ãä¸å¨ `<is><t>`ï¼è Excel/WPS ä¼å 读 `<is><t>`ãå¤ç½®ï¼åå¼åå `setBlank()` æ¸ æååå æ ¼ååï¼è½çä¸ºå ±äº«ä¸²ï¼`<is>` ä¸åæ®çæ§ææ¡ï¼ã 2. **POI æ±å¼å£å¾åå·®**ï¼æºç¬ç«æå表éæå·¥ç空ç忝ä¼è®© `RANK` 彿°æ±å¼ä¸å¾è¿å 1ï¼ç´æ¥æ¬å¼ä¼æ 17 è¡ãå¢éæåãåæå ¨ 1ãå¤ç½®ï¼æºä¾§å ¬å¼ä¸åæ¬æ±å¼ç»æï¼èæ¯æç®æ åå移平移æå ¬å¼åå ¥ï¼åç¨æ±æ»è¡¨èªèº«æ°æ®æ±å¼ç¼åã 3. **ä¸å£å¾æå忝åä»ä¸ºæ¯çæ§å¼**ï¼åºä¸åªæ 2026-01~08 çå®¢è¿æ°æ®ï¼`h2031_enterprise_monthly` / `city_bus_monthly`ï¼ï¼æ²¡æ 2025 å®ç¨¿æ°æ®ï¼ç¬ç«æå表ç®ä¸åºä¸å£å¾åæ¯ â 该åæè®¾è®¡ä¿çæ¯çå¼ï¼ç 2025 æ°æ®å ¥åºåé导åºèªå¨å·æ°ã 4. **éæé¡µå¾ å**ï¼`å叿±æ»`ã`åå¸åå¸å·`ã`ä¸å£å¾åæ`ã`éè·¯è¿è¾å¨è½¬é` å页卿¯ç鿝æ´é¡µéæï¼æ¬è½®å¯¼åºä¸æ¯çéæ ¼ 0 å·®å¼ï¼ï¼é¡µæ é¢ä»åã1-7 æ / 7 æããå æ´é¡µæ°æ®æªæ°æ®é©±å¨ï¼æ¬è½®**æª**åªæ¹æ é¢ï¼é¿å æ é¢ 8 æãæ°æ® 7 æï¼ï¼çå¾ åç»åææ°æ®é©±å¨æ¶ä¸å¹¶å¤çã ## äºãç»è®º - ç¨æ·åé¦ç两个é®é¢å已修å¤å¹¶éªè¯ï¼ä¸å¼ æåé¡µçæ é¢ä¸æ°å¼éæ¥è¡¨æå·æ°ï¼è´§è¿éæå 454 æ ¼éæ ¼æ¯å¯¹ 0 å·®å¼ï¼ï¼8 æåæ¯åç»ä¸ä¸ºç¾åæ°æ¾ç¤ºã - 2026-08 / 2026-07 åæå¯¼åºéè¿ï¼7 æå岿åå½å·®å¼ä» éè¢«å·æ°çæåé¡µï¼æ å¯ä½ç¨ã - éçï¼ä¸å£å¾åæ¯å¾ 2025 å¹´æ°æ®å ¥åºï¼åå¼ éææåé¡µå¾ æ°æ®é©±å¨æ¹é ã docs/¹¤×÷ÈÕ½á/¹¤×÷ÈÕ½á_2026-09-11.md
@@ -16,12 +16,22 @@ - ç线å 车ã轨é轮渡ãå ¨çãè¡è¡¥é½åè®¡å ¬å¼ï¼æ¯çååªå¯¹ 1 æåæ»å ¬å¼ï¼ã - çå¼æç¨æ·æå®åç §ä»¶ `docs/çææ±æ»å¤§è¡¨/çæ_éè·¯è¿è¾éæ±æ»è¡¨.xlsx` éå对é½å宽/éèï¼**8 ææ©å Q/R ç宽度ä¹åèªåç §ä»¶**ã ### 3. æ±æ»è¡¨æå页巿° + 忝ç¾åæ°ï¼ç¨æ·æ°åé¦ 2 é¡¹ï¼ - ç¨æ·åé¦ãè´§è¿çæ±æ»è¡¨é 1.æææåè¡¨æ°æ®æ²¡ææ´æ°ï¼2.忝åºè¯¥æ¯ç¾åæ°è䏿¯å°æ°ãã - æåé¡µï¼æ¯çé `è´§è¿éæå`/`è´§è¿å¨è½¬éæå`/`ä¸å£å¾æå` ä¸é¡µæ¯ä¸ä¸æçéæå¼ãå¯¼åºæ¶æ¹ç¨ç¨åºèªå·±çç¬ç«æå表ï¼çæ_è´§è¿éæå/å¨è½¬éæå/ä¸å£å¾æåï¼å·æ°è¿ä¸é¡µï¼æ°å¼æ¬å¼ãæºä¾§å ¬å¼æå移平移ååå ¬å¼ï¼æå¼éç®ï¼ãæ¯çèªå¸¦å ¬å¼ä¿çãåæ é¢éæ¥è¡¨æåæ¥ï¼1-7æâ1-8æï¼ã - åæ¯æ ¼å¼ï¼`ensureMonthYoyFormulas` æ¹ä¸ºæ æ¡ä»¶æ²¿ç¨ä¸æåæ¯åæ ·å¼ï¼æ¯çææ°æä»½åæ¯ååææ®éæ°å¼ `0.00`ï¼æ¾ç¤ºæå°æ°ï¼ã - ä¿®æä¸¤ä¸ªåï¼â æ¯çæ 颿¯ inlineStrï¼POI `setCellValue` åªå `<v>` 䏿´æ° `<is>`ï¼Excel ç»§ç»æ¾ç¤º 7 æ â å `setBlank()` ååï¼â¡ ç´æ¥æ¬ POI 对æºè¡¨ RANK çæ±å¼ç»æä¼æãå¢éæåãåæ 17 è¡å ¨ 1 â æ¹ä¸ºå¹³ç§»åå ¬å¼ã ### 3. ææ¡£å½æ¡£ - æ¨å¤©å·²å®æãæ¹åçé路货ç©è¿è¾éåå¸å·ç»è®¡æ¹æ³(2023)ç¼å¶è¯´æãå¦ä¹ ç¬è®°å½æ¡£ï¼`docs/è´§è¿/å¦ä¹ ç¬è®°_åå¸å·é路货ç©è¿è¾éç»è®¡æ¹æ³_2026-09-10.md`ï¼ï¼ä»å¤©æªåæ¹å¨ã ## äºãæµè¯ç»ææè¦ï¼è¯¦è§ãåè½æµè¯æ¥åãï¼ - `docs/åè½æµè¯æ¥å/åè½æµè¯æ¥å_ç½çº¦è½¦è®¢åæ¥åå¯¼å ¥_2026-09-11.md`ï¼TC-1~TC-7 å ¨é¨éè¿ï¼7 ææ¥åè§£æ 17 å¸å·ãå计 29,730,791ï¼ä¸åºä¸é项ä¸è´ï¼ä¸¤ç±»è´åç¨ä¾æç¤ºæç¡®ã - `docs/åè½æµè¯æ¥å/åè½æµè¯æ¥å_æ±æ»å¤§è¡¨8ææ°æ®åå¡«ä¸çå¼å¯¹é½_2026-09-11.md`ï¼TC-1~TC-16 å ¨é¨éè¿ã - `docs/åè½æµè¯æ¥å/åè½æµè¯æ¥å_æ±æ»è¡¨æå页巿°ä¸åæ¯ç¾åæ°_2026-09-11.md`ï¼æ£å 14 ä¾ / è´å 3 ä¾ / åå½ 4 ä¾å ¨é¨éè¿ã - 2026-08 å¯¼åºæåï¼23.8s / 949,956 åèï¼ï¼æ¥å¿ãå·æ°æå页æ°å¼æ ¼æ°=711ï¼ç¼ºæ°æç¤º=[]ãã - ä¸å¼ æå页æ é¢å·²å° 1-8 æ/8 æï¼è´§è¿éæåä¸ç¬ç«æåè¡¨éæ ¼æ¯å¯¹ 454 æ ¼ 0 å·®å¼ï¼8 æåæ¯åå ¨é¨ `0.00%`ã - 7 æå岿åå½ï¼ä» è¢«å·æ°çæå页æé¢æå·®å¼ï¼è´§è¿éæå 51 æ ¼ãä¸å£å¾æå 133 æ ¼ï¼ï¼å ¶ä½ 16 页 0 å·®å¼ã - 2026-08 å¯¼åºæåï¼4.6s / 948,735 åèï¼ï¼åå ¥å½æå¼ 1659 æ ¼ãå½æåæ¯å ¬å¼ 600 æ ¼ã彿åè®¡å ¬å¼ 43 æ ¼ãç¼ºæ°æç¤ºä¸ºç©ºã - è´§è¿ Î£17 å¸å· = å ¨çï¼16888.7615ï¼ï¼ç½çº¦è½¦/å ¬äº¤/åºç§/ç线å 车/轨éè½®æ¸¡å ¨çè¡ä¸å¸å·è¡åæ£ç¡®ã - å宽ä¸åç §ä»¶**çå®å·®å¼ 0 å**ã @@ -32,9 +42,12 @@ 2. 2026-08 导åºä¼æå°ãæªæ¾å°åæå¤ä»½æ¯çï¼_å¤ä»½_2026å¹´8æâ¦ï¼ãåè¦ï¼å±æ 害æç¤ºï¼8 ææ¯çæ¬èº«å®æ´ï¼ï¼åç»å¯èèæéæ±å³å®æ¯å¦æ¶é¤ã 3. æ ¹ç®å½å 积è¾å¤åå²ä¸´æ¶æä»¶ï¼`_t_*.py`ã`_*.sql`ã`_gen_*.xlsx`ã`_bak_*.java`ã`_token.txt` çï¼ï¼å¾ ç¨æ·åæåé䏿¸ çã 4. çå¼åç §ä»¶ `docs/çææ±æ»å¤§è¡¨/çæ_éè·¯è¿è¾éæ±æ»è¡¨.xlsx` ç®å为æªå ¥åºæä»¶ï¼æ¯å¦çº³å ¥çæ¬ç®¡çå¾ ç¡®è®¤ã 5. ä¸å£å¾æåçã忝å¢éãå仿¯æ¯çæ§å¼ï¼åºä¸åªæ 2026 å¹´æ°æ®ï¼æ²¡æ 2025 å¹´ä¸å£å¾å®ç¨¿æ°æ®ï¼ç®ä¸åº 8 æåæ¯ï¼ç 2025 æ°æ®å ¥åºåèªå¨å·æ°ã 6. `å叿±æ»`/`åå¸åå¸å·`/`ä¸å£å¾åæ`/`éè·¯è¿è¾å¨è½¬é` å页卿¯ç鿝æ´é¡µéæï¼æ¬è½®å¯¼åºä¸æ¯ç 0 å·®å¼ï¼ï¼æ é¢ä»å 7 æï¼éåç»åææ°æ®é©±å¨åä¸å¹¶æ´æ°ã ## åãæå¤©è®¡å 1. ç¨æ·éä¼ çå® 8 æç½çº¦è½¦æ¥ååï¼éæ°å¯¼åº 2026-08 å¹¶é项夿 ¸ç½çº¦è½¦é¡µã 2. ç»§ç»æç¨æ·å馿 ¸å¯¹ 8 ææ±æ»å¤§è¡¨æåï¼éç¹ï¼ä¸å£å¾å页ãè´§è¿æå页ï¼ã 3. æ¸ çä¸´æ¶æä»¶ï¼éç¨æ·ç¡®è®¤ï¼ã 4. è§ç¨æ·åé¦å³å®æ¯å¦æåå¼ éææå页ï¼å叿±æ»/åå¸åå¸å·/ä¸å£å¾åæ/éè·¯è¿è¾å¨è½¬éï¼åææ°æ®é©±å¨ã traffic-audit-server/src/main/java/com/trafficaudit/reportexport/calc/SummaryWorkbookFiller.java
@@ -530,10 +530,9 @@ String f = prev.getCellFormula(); if (f == null || f.isEmpty()) continue; String shifted = shiftFormulaColumns(f, 2); if (target == null) { target = row.createCell(yoyCol); if (target == null) target = row.createCell(yoyCol); // æ¯çææ°æä»½ç忝ååæäºæ®éæ°å¼æ ¼å¼ï¼æ¾ç¤ºæå°æ°ï¼ï¼ç»ä¸æ²¿ç¨ä¸æåæ¯åçæ ·å¼ï¼ç¾åæ°ï¼ if (prev.getCellStyle() != null) target.setCellStyle(prev.getCellStyle()); } try { target.setCellFormula(shifted); written++; traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java
@@ -53,6 +53,7 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; @@ -3351,10 +3352,11 @@ int dbFilled = summaryWorkbookFiller.fillMonthlyLedger(wb, effPeriod, year, effMonth, dbProblems); int yoyFilled = summaryWorkbookFiller.ensureMonthYoyFormulas(wb, year, effMonth); int monthFormulaFilled = summaryWorkbookFiller.ensureMonthFormulas(wb, year, effMonth); int rankRefreshed = refreshSummaryRankSheets(wb, effPeriod, "month"); int widthApplied = applySummaryReferenceLayout(wb); log.info("æ±æ»å·¥ä½ç°¿æ°æ®é©±å¨å填宿ï¼åå ¥å½æå¼æ ¼æ°={}ï¼è¡¥åå½æåæ¯å ¬å¼æ ¼æ°={}ï¼è¡¥å彿åè®¡å ¬å¼æ ¼æ°={}ï¼" + "æãçæ_éè·¯è¿è¾éæ±æ»è¡¨ã对é½å宽忰={}ï¼ç¼ºæ°æç¤º={}", dbFilled, yoyFilled, monthFormulaFilled, widthApplied, dbProblems); + "å·æ°æå页æ°å¼æ ¼æ°={}ï¼æãçæ_éè·¯è¿è¾éæ±æ»è¡¨ã对é½å宽忰={}ï¼ç¼ºæ°æç¤º={}", dbFilled, yoyFilled, monthFormulaFilled, rankRefreshed, widthApplied, dbProblems); applyTwoDecimalFormat(wb); // æ°å¼æ¾ç¤ºä¸¤ä½å°æ°ï¼ä¿çå ¨ç²¾åº¦ï¼ï¼% / æ¥æçæ¢ææ ·å¼ä¸æ¹å if (!wb.getCTWorkbook().isSetCalcPr()) wb.getCTWorkbook().addNewCalcPr(); wb.getCTWorkbook().getCalcPr().setFullCalcOnLoad(true); // è¿å/æ¹åå ¬å¼åæå¼å³éç® @@ -3441,6 +3443,216 @@ return max; } // ==================== æ±æ»å·¥ä½ç°¿å çæå页巿° ==================== /** * æ±æ»å·¥ä½ç°¿éçãè´§è¿éæå / è´§è¿å¨è½¬éæå / ä¸å£å¾æåã卿¯ç鿝ä¸ä¸æ¥è¡¨æçéæå¼ï¼ * å¯¼åºæ¶ç¨ç¬ç«æå表ï¼ãçæ_è´§è¿éæåããçæ_å¨è½¬éæåããçæ_ä¸å£å¾æåãï¼ä¸ç¨æ·æ¥å¸¸æ ¸å¯¹çå£å¾ä¸è´ï¼ * çç»æå·æ°æ°å¼ï¼é¿å æ±æ»è¡¨éçæå页åç卿§æä»½ã * æ°å¼æ ¼æ¬å¼ãå ¬å¼æ ¼æåç§»å¹³ç§»å ¬å¼ååå ¥ï¼ç®æ æ ¼æ¬èº«å·²æ¯å ¬å¼çï¼SUM/RANK/å æ¯/è¡¥æ°ï¼ä¿çä¸å¨ï¼æå¼æ¶ææ°æ°æ®éç®ã */ private int refreshSummaryRankSheets(XSSFWorkbook wb, String period, String mode) throws Exception { int n = 0; n += copyRankValues(wb, "è´§è¿éæå", exportFreightRank(period, mode), new int[][]{{0, 0}, {22, 0}}); n += copyRankValues(wb, "è´§è¿å¨è½¬éæå", exportTurnoverRank(period, mode), new int[][]{{0, 0}, {22, 0}}); n += copyRankValues(wb, "ä¸å£å¾æå", exportPassengerMidRank(period, mode), new int[][]{{0, 0}, {0, 10}}); return n; } /** * æç¬ç«æå表çåä¸ªåææ é¢å¯¹é½æ¬è¿æ±æ»å¤§è¡¨å¯¹åºé¡µã * srcBlocks[i] = æºå i çèµ·å§ {è¡, å}ï¼0 åºï¼ï¼ç®æ åææ é¢é¡ºåºï¼ç´¯è®¡åå¨åã彿åå¨åï¼å¯¹åºã * æ°å¼æ ¼ç´æ¥æ¬å¼ï¼æºä¾§æ¯å ¬å¼çï¼æå/å æ¯çï¼æç®æ ååç§»æ´ä½å¹³ç§»ååå ¥å ¬å¼ï¼æå¼æ¶ææ±æ»è¡¨èªèº«æ°æ®éç®ã */ private int copyRankValues(XSSFWorkbook dstWb, String dstSheetName, byte[] srcBytes, int[][] srcBlocks) throws Exception { XSSFSheet dst = dstWb.getSheet(dstSheetName); if (dst == null) return 0; List<XSSFCell> dstTitles = rankTitleCells(dst); if (dstTitles.isEmpty()) return 0; int copied = 0; FormulaEvaluator dstEv = dstWb.getCreationHelper().createFormulaEvaluator(); try (InputStream sin = new ByteArrayInputStream(srcBytes); XSSFWorkbook srcWb = new XSSFWorkbook(sin)) { XSSFSheet src = srcWb.getSheetAt(0); FormulaEvaluator ev = srcWb.getCreationHelper().createFormulaEvaluator(); int blocks = Math.min(srcBlocks.length, dstTitles.size()); for (int b = 0; b < blocks; b++) { int sr0 = srcBlocks[b][0]; int sc0 = srcBlocks[b][1]; XSSFCell dstTitle = dstTitles.get(b); int rowOff = dstTitle.getRowIndex() - sr0; int colOff = dstTitle.getColumnIndex() - sc0; int h = rankBlockHeight(src, sr0, sc0); int w = rankBlockWidth(src, sr0, sc0); for (int r = 0; r < h; r++) { Row srcRow = src.getRow(sr0 + r); if (srcRow == null) continue; Row dstRow = dst.getRow(sr0 + r + rowOff); if (dstRow == null) dstRow = dst.createRow(sr0 + r + rowOff); for (int c = 0; c < w; c++) { Cell sc = srcRow.getCell(sc0 + c); if (sc == null) continue; int dc = sc0 + c + colOff; if (r == 0) { // æ é¢è¡ï¼åæ¥åæ 颿æ¡ãæ¯çæ 颿¯ inlineStrï¼POI ç setCellValue åªå <v>ã // 䏿´æ° <is>ï¼Excel ä¼ç»§ç»æ¾ç¤ºæ§æä»½ï¼å¿ é¡»å setBlank æ¸ æååã Cell dt = dstRow.getCell(dc); if (dt == null) dt = rankCell(dstRow, dc); if (sc.getCellType() == CellType.STRING && dt.getCellType() != CellType.FORMULA) { String text = sc.getStringCellValue(); String old = dt.getCellType() == CellType.STRING ? dt.getStringCellValue() : null; if (text != null && !text.equals(old)) { dt.setBlank(); dt.setCellValue(text); } } continue; } Cell dcCell = dstRow.getCell(dc); if (dcCell != null && dcCell.getCellType() == CellType.FORMULA) continue; // ä¿çæ¯çèªå·±çå ¬å¼ if (sc.getCellType() == CellType.FORMULA) { // æºä¾§å ¬å¼ï¼æå/å æ¯ï¼ï¼æç®æ åå移平移ååæ ·åå ¥ï¼åææ±æ»è¡¨èªèº«æ°æ®æ±å¼ç¼åã // ä¸ç´æ¥æ¬ POI 对æºè¡¨çæ±å¼ç»æï¼å¦ RANK 对æå·¥ç空ç忝ä¸å¾è¿å 1ï¼ã String f = sc.getCellFormula(); if (f == null || f.isEmpty()) continue; String shifted = shiftFormula(f, colOff, rowOff); if (dcCell == null) dcCell = rankCell(dstRow, dc); dcCell.setCellFormula(shifted); try { dstEv.evaluateFormulaCell(dcCell); } catch (Exception ignore) { // æ±å¼å¤±è´¥ä¸é»å¡å¯¼åºï¼æå¼æ¶ç± Excel/WPS éç® } copied++; continue; } Double v = rankNumeric(sc, ev); if (v == null) continue; if (dcCell == null) dcCell = rankCell(dstRow, dc); dcCell.setCellValue(v); copied++; } } } } return copied; } /** ç®æ åç¼ºæ ¼æ¶æ°å»ºï¼å¹¶æ²¿ç¨åè¡å·¦é»æ ¼æ ·å¼ï¼é²æ°æ ¼ä¸¢è¾¹æ¡/ç¾åæ°æ ¼å¼ï¼ */ private Cell rankCell(Row row, int col) { Cell c = row.createCell(col); Cell left = col > 0 ? row.getCell(col - 1) : null; if (left != null) c.setCellStyle(left.getCellStyle()); return c; } /** å ¬å¼å ææ A1 å¼ç¨æ´ä½å¹³ç§»ï¼å +dColãè¡ +dRowï¼SUM/RANK ç彿°å忥æ¬å·ä¸ä¼è¢«å¹é ï¼ */ private String shiftFormula(String formula, int dCol, int dRow) { if (formula == null || (dCol == 0 && dRow == 0)) return formula; java.util.regex.Matcher m = java.util.regex.Pattern .compile("(?<![A-Za-z0-9_$])([$]?)([A-Z]{1,3})([$]?)([0-9]+)") .matcher(formula); StringBuffer sb = new StringBuffer(); while (m.find()) { String col = m.group(2); int idx = 0; for (int i = 0; i < col.length(); i++) idx = idx * 26 + (col.charAt(i) - 'A' + 1); int nidx = Math.max(1, idx + dCol); StringBuilder nc = new StringBuilder(); while (nidx > 0) { int rem = (nidx - 1) % 26; nc.insert(0, (char) ('A' + rem)); nidx = (nidx - 1) / 26; } int nrow = Math.max(1, Integer.parseInt(m.group(4)) + dRow); m.appendReplacement(sb, java.util.regex.Matcher.quoteReplacement(m.group(1) + nc + m.group(3) + nrow)); } m.appendTail(sb); return sb.toString(); } /** æå页éçâåæ é¢âåå æ ¼ï¼å«âå ¨çåå¸å·âç说ææåï¼ï¼æè¡ãå顺åºè¿å */ private List<XSSFCell> rankTitleCells(Sheet sh) { List<XSSFCell> out = new ArrayList<>(); for (int r = sh.getFirstRowNum(); r <= sh.getLastRowNum(); r++) { Row row = sh.getRow(r); if (row == null) continue; for (int c = row.getFirstCellNum(); c < row.getLastCellNum(); c++) { Cell cell = row.getCell(c); if (cell == null || cell.getCellType() != CellType.STRING) continue; String t = cell.getStringCellValue(); if (t != null && t.contains("å ¨çåå¸å·")) out.add((XSSFCell) cell); } } return out; } /** åé«åº¦ï¼ä»èµ·å§è¡åä¸ç´å°æ´è¡ä¸ºç©ºï¼å¨ååèå´å ï¼ */ private int rankBlockHeight(Sheet sh, int r0, int c0) { int h = 0; for (int r = r0; r <= sh.getLastRowNum(); r++) { Row row = sh.getRow(r); boolean any = false; if (row != null) { int last = row.getLastCellNum(); for (int c = c0; c < last; c++) { if (rankHasContent(row.getCell(c))) { any = true; break; } } } if (!any) break; h++; } return h; } /** å宽度ï¼ä»èµ·å§ååå³ç´å°æ´å为空ï¼å¨åè¡èå´å ï¼æ«æä¸é 40 åï¼ */ private int rankBlockWidth(Sheet sh, int r0, int c0) { int w = 0; for (int c = c0; c < c0 + 40; c++) { boolean any = false; for (int r = r0; r < r0 + 30; r++) { Row row = sh.getRow(r); if (row != null && rankHasContent(row.getCell(c))) { any = true; break; } } if (!any) break; w++; } return w; } private boolean rankHasContent(Cell c) { if (c == null) return false; CellType t = c.getCellType(); if (t == CellType.BLANK) return false; if (t == CellType.STRING) { String v = c.getStringCellValue(); return v != null && !v.trim().isEmpty(); } return true; } /** ååå æ ¼æ°å¼ï¼å ¬å¼åæ±å¼ç»æï¼çº¯æ°åææ¬ææ°å¼è§£æï¼ï¼åä¸å°è¿å null */ private Double rankNumeric(Cell c, FormulaEvaluator ev) { try { CellType t = c.getCellType(); if (t == CellType.NUMERIC) return c.getNumericCellValue(); if (t == CellType.FORMULA) { org.apache.poi.ss.usermodel.CellValue cv = ev.evaluate(c); return cv != null && cv.getCellType() == CellType.NUMERIC ? cv.getNumberValue() : null; } if (t == CellType.STRING) { String v = c.getStringCellValue(); if (v == null) return null; String x = v.replace(",", "").trim(); if (x.isEmpty()) return null; try { return Double.parseDouble(x); } catch (NumberFormatException ignore) { return null; } } } catch (Exception ignore) { return null; } return null; } /** å®ä½çå¼åç §ä»¶ docs/çææ±æ»å¤§è¡¨/çæ_éè·¯è¿è¾éæ±æ»è¡¨.xlsxï¼ä¼å çº§åæ¯çï¼é ç½®ç®å½ â user.dir ç¸å¯¹ â ä¸çº§ï¼ */ private File resolveSummaryLayoutRef() { String rel = summaryTemplateDir;