| docs/功能测试报告/功能测试报告_网约车订单报告WordML兼容导入_2026-09-18.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| docs/工作日结/工作日结_2026-09-18.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| traffic-audit-server/src/main/java/com/trafficaudit/dataimport/service/DataImportService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
docs/¹¦ÄܲâÊÔ±¨¸æ/¹¦ÄܲâÊÔ±¨¸æ_ÍøÔ¼³µ¶©µ¥±¨¸æWordML¼æÈݵ¼Èë_2026-09-18.md
New file @@ -0,0 +1,72 @@ # åè½æµè¯æ¥å_ç½çº¦è½¦è®¢åæ¥å WordML å ¼å®¹å¯¼å ¥_2026-09-18 ## ä¸ãåè½è¯´æ **èæ¯ï¼ç¨æ·æ¥éï¼**ï¼æãæ¹åç½ç»é¢çº¦åºç§æ±½è½¦2025å¹´09æåææ¥å.docxãæ¾å°æ¡é¢åç¨ãç½çº¦è½¦è®¢åæ¥åãå¯¼å ¥ï¼ä¸ç´å¤±è´¥ã **å®ä½ç»è®º**ï¼è¯¥æä»¶**䏿¯çæ£ç docx**ã宿¯ **Word 2003 XMLï¼WordML å¹³éº XMLï¼åæä»¶ï¼**被æ¹åæäº `.docx`ï¼ - æä»¶å¤´æ¯ `<?xml version="1.0" ...?> <?mso-application progid="Word.Document"?> <w:wordDocument xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml" ...>` - 3.1MB 纯 XMLï¼**䏿¯ zip å **ï¼POI ç `XWPFDocument` åªè½è¯» OPC(zip) å ï¼äºæ¯æ `File is not a zip file`ã - è¿ç±»æä»¶æ¯ WPS/WordãWord 2003 XML ææ¡£ãæ ¼å¼ï¼ç½çº¦è½¦ç管平å°/åäºä¹é´æµè½¬å¾å¸¸è§ï¼ä¼åå¤åºç°ã **æ¹å¨**ï¼`traffic-audit-server/src/main/java/com/trafficaudit/dataimport/service/DataImportService.java` 1. `importWycOrderReport()` å ¥å£å ææä»¶å¤´å æ¢æ ¼å¼ï¼ååæ´¾ï¼ - `PK` å¼å¤´ â docxï¼zipï¼ï¼å `XWPFDocument` è·¯å¾ï¼ - `<w:wordDocument` + `wordml` â **WordML å¹³éº XMLï¼æ°å¢è§£æè·¯å¾**ï¼ - `D0CF11E0` â OLE2 è `.doc`ï¼ç»åºã请å¦å为 docxãçæç¡®æç¤ºï¼ - å ¶å® â ãæ æ³è¯å«çæä»¶æ ¼å¼ãã 2. æ°å¢ `isWordPackage()`ï¼zip ä½å å æ²¡æ `word/document.xml`ï¼å¦ xlsx æ¹åï¼æ¶ï¼ç´æ¥æç¤ºãè¿ä¸æ¯ Word ææ¡£â¦â¦å¤åæ¯ Excel æå ¶å®æ ¼å¼ãï¼ä¸åæåº XMLBeans çè±æå æ ã 3. æ°å¢ `parseXmlSafely()`ï¼DOM è§£æå¹¶**å ³éå¤é¨å®ä½/DTD**ï¼æ¥åæ¥èªå¤é¨å¹³å°ï¼é² XXEï¼ã 4. è¡¨æ ¼å¹é é»è¾æ½æä¸æ ¼å¼æ å ³ç `matchWycOrderTable(tables, orders, sumHolder)`ï¼ - docx è·¯å¾æ `XWPFTable` ææ¬ååè°ç¨ï¼ - WordML è·¯å¾æ `<w:tbl>/<w:tr>/<w:tc>` ææ¬ååè°ç¨ï¼ - 表头è¯å«ã17 å¸å·åå¼ãå计è¡è¯å«**å®å ¨å¤ç¨åä¸å¥é»è¾**ï¼ä¸¤æ¡è·¯å¾ä¸ä¼åºç°å£å¾ååã 5. æ¥è¡¨æè¯å«æ½æ `periodOfParagraphs(List<String>)`ï¼ä¸¤ç§æ ¼å¼å ±ç¨ï¼æ é¢ `ç½çº¦è½¦è¡ä¸YYYYå¹´Mæ` ä¼å ï¼åä¸å°åéãå 10 段任æ YYYYå¹´Mæãï¼ã ## äºãæµè¯ç¯å¢ - å端 8090ï¼`mvn -o compile` åéå¯ï¼å è½½æ°ç±»ï¼å¯å¨æ¥å¿ `Started TrafficAuditApplication`ï¼ï¼æ°æ®åº `traffic_audit`ï¼127.0.0.1:3308ï¼ã - æ¥å£ï¼`POST /api/import/wycOrderReport`ï¼`file` + `period`ï¼`period` å¯ä¸ºç©º â ç±æ¥åæ 颿¨æï¼ã - æµè¯æä»¶ï¼`D:\æ¡é¢\æ¹åç½ç»é¢çº¦åºç§æ±½è½¦2025å¹´09æåææ¥å.docx`ï¼WordMLï¼3,145,560 åèï¼ï¼`D:\05_æ°æ®åç±»\åå¸å®¢è¿\8æ\æ¹åç½ç»é¢çº¦åºç§æ±½è½¦2026å¹´08æåææ¥å0910æç»ç.docx`ï¼ç docxï¼ã - è¯æ®æä»¶ï¼`_tmp/_qa_out/`ï¼å½ä»¤è¾åºè§æ¬æ¥åè¡¨æ ¼ï¼æ°æ®æ ¸å¯¹è§ `_wyc_2025_09_row.txt`ï¼ã ## ä¸ãç¨ä¾è¡¨ | ç¼å· | ç±»å | è¾å ¥ | 颿 | å®é | ç»è®º | |---|---|---|---|---|---| | 1 | æ£å | WordMLã2025å¹´09æãæ¥åï¼`period=2025-09` | è§£æåº 17 å¸å·è®¢åï¼åå ¥ 2025-09 | `å¯¼å ¥æåï¼æ¥è¡¨æ 2025-09ï¼è®¢åå计 17,652,159 åï¼å·²åå ¥ 17 个å¸å·` | éè¿ | | 2 | æ£å | åä¸ï¼`period=` ç空 | ç±æ é¢ `ç½çº¦è½¦è¡ä¸2025å¹´9æ` æ¨æåº 2025-09 | æ¥è¡¨æ 2025-09ï¼ç»æä¸ç¨ä¾ 1 ä¸è´ | éè¿ | | 3 | æ£å | ç docxã2026å¹´08æãæ¥åé导 | ä¸åºå æ¢æå¼ä¸è´ï¼å¹çï¼ä¸æ¹åç»æï¼ | 订åå计 30,508,652ãæ¦æ± 11,550,551ï¼ä¸å¯¼å ¥åå®å ¨ç¸å | éè¿ | | 4 | æ£å | 2026å¹´06ææ¥å | 订åå计 = æ¥åæ£æãå ¨çè®¢åæ»æ° 2684.30 ä¸åã | åºå 2026-06 = 26,843,037 | éè¿ | | 5 | è´å | `.doc`ï¼OLE2 å¤åææ¡£ï¼Word 97-2003ï¼ | æç¡®æç¤ºæ¹ç¨ docx | `è¿æ¯ Word 97-2003 èæ ¼å¼ï¼.docï¼ï¼è¯·ç¨ WPS/Word æå¼åãå¦å为ãdocx æ ¼å¼åå¯¼å ¥` | éè¿ | | 6 | è´å | xlsx æ¹åæ `.docx` ä¸ä¼ | æç¡®æç¤ºä¸æ¯ Word | `è¿ä¸æ¯ Word ææ¡£ï¼å缩å éæ²¡æ word/document.xmlï¼ï¼å¤åæ¯ Excel æå ¶å®æ ¼å¼â¦â¦` | éè¿ | | 7 | è´å | éç½çº¦è½¦æ¥åç docxï¼ãæèµè¡¨ä¹é´çå ³ç³».docxãï¼ | æç¤ºæªè§£æå°è®¢åæ° | `æªè§£æå°ä»»ä½å¸å·è®¢åæ°ï¼è¯·ç¡®è®¤ä¸ä¼ çæ¯ãç½çº¦è½¦è¡ä¸YYYYå¹´Mæè¿è¡çæµæ åµåææ¥åã` | éè¿ | | 8 | è¾¹ç | WordML ä¸è¡¨æ ¼å« 16 åã表头å¨ç¬¬ 1 è¡ãå¸å·åç¨ç®ç§°ï¼`æ¦æ±`/`æåº`ï¼ | ç®ç§°è½æ å°å°è§èåï¼æ¦æ±å¸/ç¥åæ¶æåºï¼ | 17 å¸å·å ¨é¨è¯å«ï¼æ 缺失 | éè¿ | **å ¥åºæ½æ¥**ï¼æ¥è¡¨æ 2025-09ï¼ä¸æ¥åéä»¶1é项对é½ï¼ | 项 | æ¥åéä»¶1 | åºå `wyc_order_monthly` | ç»è®º | |---|---|---|---| | 订åå计 | 17,652,159 | 17,652,159 | ä¸è´ | | æ¦æ± | 8,076,610 | 8,076,610 | ä¸è´ | | é»ç³ | 676,644 | 676,644 | ä¸è´ | | åå ° | 1,048,593 | 1,048,593 | ä¸è´ | | æ©æ½ | 804,736 | 804,736 | ä¸è´ | | ç¥åæ¶æåº | 1,424 | 1,424 | ä¸è´ | | å ¨ç pinï¼B~Eï¼ | æ¥åæ | 2794.31 / 2522.54 / 16394.73 / 12998.74ï¼ä» `wyc_total_monthly` åæå¤å¶ï¼ | 符å设计 | ## åãåç°çé®é¢ä¸å¤ç½® 1. **æ ¼å¼å ¼å®¹ç¼ºå£ï¼æ¬æ¬¡ä¿®å¤ï¼**ï¼WordML æ¥åæ æ³å¯¼å ¥ãå·²å è§£æè·¯å¾ï¼ä¸¤ç§æ ¼å¼å ±ç¨åä¸å¥è¡¨æ ¼å¹é é»è¾ï¼é¿å å£å¾ååã 2. **é误信æ¯ä¸åå¥½ï¼æ¬æ¬¡ä¿®å¤ï¼**ï¼xlsx æ¹å忥 `org.apache.xmlbeans.XmlException: Element workbook@... is not a valid document@...`ãå·²æ¹ä¸ºä¸æä¸å¡æç¤ºã 3. **20XX å¹´ååæ¥åæ é¢æ ¼å¼ä¸å**ï¼2025 å¹´æ¥åæ 颿¯ãæ¹å**ç½çº¦è½¦è¡ä¸ 2025å¹´9æ** è¿è¡æ åµåææ¥åãï¼2026 å¹´æ¯ãç½çº¦è½¦è¡ä¸2026å¹´6æè¿è¡çæµæ åµåææ¥åããåä¸å¥æ£ååå¯å½ä¸ï¼æ éåæ¹ã 4. **æ°æ®ç¼ºå£å·²ç±ç¨æ·è¡¥é½**ï¼2026-01~06ï¼14:21 å¯¼å ¥ 6 份ï¼ã2025-01ï¼14:47ï¼ã2025-10~12ï¼14:49ï¼åå·²å ¥åºï¼2025-09 ç±æ¬æ¬¡ä¿®å¤åè¡¥å ¥ï¼14:59 馿¬¡ã15:04 夿 ¸ï¼ã - å ¨é¨ 2025-01~12ã2026-01~08 ç订åä¸ pin ç°å·²é½å ¨ã - å½±åï¼ä¸å£å¾ç»´åº¦ 4ï¼åé å乡ç½çº¦è½¦ï¼1~6 æç±ãæ æºãå为ãå¯ç®ãï¼**ä¸å£å¾æåä»¶ä¸ä¸å£å¾æç»ä»¶ç´¯è®¡å£å¾èªå¨å½ä¸**ï¼æ¤åå·®å¼ 2063.45 = 1~6 æç½çº¦è½¦å乡ï¼ã ## äºãç»è®º - WordMLï¼Word 2003 XML æ¹å .docxï¼æ¥åç°å·²å¯ç´æ¥å¯¼å ¥ï¼17 å¸å· + åè®¡è§£ææ£ç¡®ãå ¥åºé项对é½ï¼ç docx è·¯å¾æ åå½ã - 3 æ¡è´åç¨ä¾åç»åºä¸æå¯æä½æç¤ºï¼.doc / é Word å / 鿬æ¥åï¼ã - 8 ä¾ç¨ä¾å ¨é¨éè¿ï¼`docs/åè½æµè¯æ¥å/` ä¸å·²å½æ¡£æ¬æ¥åã docs/¹¤×÷ÈÕ½á/¹¤×÷ÈÕ½á_2026-09-18.md
@@ -60,6 +60,23 @@ 飿¯æ§å¶å°ä¸æä¹±ç é æçè¯¯è¯»ï¼æ¯ç/模æ¿çå®å ¬å¼æ¯æ£ç¡®ç `=[1]åºç§!C13-[1]åºç§!C15` / `=[1]ç½çº¦è½¦!C13-[1]ç½çº¦è½¦!C15`ï¼ å°è´¦é¡µãæ»éâåå¸å ãΣ17 å¸å· = 535.83 / 333.39ï¼ä¸æ¯çå®ç¨¿å ¨çè¡å®å ¨ä¸è´ã**æ¯çå ¬å¼ä¸éè¦ä¿®ï¼ä¹å"å¾ ä¿®æ¯ç"çç»è®ºä½åºã** ### 5. ç½çº¦è½¦è®¢åæ¥åï¼Word 2003 XMLï¼WordMLï¼å ¼å®¹å¯¼å ¥ï¼15:00ï¼ **ç¨æ·æ¥é**ï¼ãæ¹åç½ç»é¢çº¦åºç§æ±½è½¦2025å¹´09æåææ¥å.docxãæ¾å¨æ¡é¢å¯¼ä¸è¿å»ã **å®ä½**ï¼è¯¥æä»¶æ ¹æ¬ä¸æ¯ docx ââ æ¯ **Word 2003 XMLï¼WordML å¹³éº XMLï¼** 被æ¹åæ `.docx`ï¼æä»¶å¤´ `<?mso-application progid="Word.Document"?><w:wordDocument xmlns:w=".../word/2003/wordml">`ï¼3.1MB 纯 XMLã䏿¯ zip å ï¼ï¼POI ç `XWPFDocument` åªè½è¯» OPC(zip) å â æ `File is not a zip file`ãç管平å°/åäºé´æµè½¬çæ¥å常æ¯è¿ç§æ ¼å¼ï¼ä¼åå¤åºç°ã **æ¹å¨ï¼`DataImportService.java`ï¼**ï¼ - `importWycOrderReport()` å ¥å£ææä»¶å¤´å æ¢æ ¼å¼åæ´¾ï¼zipâdocxï¼`<w:wordDocument`+`wordml`â**æ°å¢ WordML DOM è§£æè·¯å¾**ï¼`D0CF11E0`âæç¡®æç¤ºã.doc 请å¦å为 docxãï¼å ¶å®âãæ æ³è¯å«ãï¼ - æ°å¢ `isWordPackage()`ï¼zip 使 `word/document.xml`ï¼xlsx æ¹åï¼â 䏿æç¤ºï¼ä¸åæ XMLBeans è±æå æ ï¼ - æ°å¢ `parseXmlSafely()`ï¼DOM è§£æå ³éå¤é¨å®ä½/DTDï¼é² XXEï¼ï¼ - è¡¨æ ¼å¹é æ½æä¸æ ¼å¼æ å ³ç `matchWycOrderTable()`ï¼docx ä¸ WordML 两æ¡è·¯å¾**å ±ç¨åä¸å¥è¡¨å¤´è¯å«/17 å¸å·åå¼/å计è¡é»è¾**ï¼ä¸ä¼å£å¾ååï¼ - æ¥è¡¨æè¯å«æ½æ `periodOfParagraphs()`ï¼ä¸¤ç§æ ¼å¼å ±ç¨ã **éªè¯**ï¼8 æ¡ç¨ä¾å ¨é¨éè¿ï¼è§ãåè½æµè¯æ¥å_ç½çº¦è½¦è®¢åæ¥åWordMLå ¼å®¹å¯¼å ¥_2026-09-18ãï¼ã2025-09 å ¥åºï¼è®¢åå计 17,652,159ï¼æ¦æ± 8,076,610 / é»ç³ 676,644 / åå ° 1,048,593 / æ©æ½ 804,736 / æåº 1,424ï¼ä¸æ¥åéä»¶1 é项ä¸è´ï¼pin ä» `wyc_total_monthly` åæå¤å¶ãç docxï¼2026-08ï¼é导å¹çæ ååï¼`.doc`ãxlsx æ¹åã鿬æ¥å docx ä¸ç§è´ååç»åºä¸æå¯æä½æç¤ºã **æ°æ®ç¼ºå£å·²è¡¥é½ï¼éè¦ï¼**ï¼ç¨æ·å¨ 14:21~14:49 ä¹é´èªè¡å¯¼å ¥ 2026-01~06ï¼6 份ï¼ã2025-01ã2025-10~12ï¼2025-09 ç±æ¬æ¬¡ä¿®å¤åè¡¥å ¥ãç°å¨ **2025-01~12 + 2026-01~08 ç订åä¸ pin å ¨é¨é½å ¨**ãç´æ¥ææï¼ä¸å£å¾ç»´åº¦ 4 ç 1~6 æä»ãæ æºãå为ãå¯ç®ãï¼**ä¸å£å¾æåä»¶ä¸ä¸å£å¾æç»ä»¶ç累计å£å¾èªå¨å½ä¸**ï¼ä¸¤è 1-8 æç´¯è®¡å为 31528.0606ï¼æ¤åå·® 2063.45ï¼ã ## äºãæµè¯ç»ææè¦ è§ `docs/åè½æµè¯æ¥å/åè½æµè¯æ¥å_æ±æ»è¡¨å ¬å¼æ©é¡µä¸éç®_2026-09-18.md`ï¼8 æ¡æ£å + 4 æ¡è´å/è¾¹ç + 4 é¡¹å ¥åºæ½æ¥ï¼å ¨é¨éè¿ã @@ -88,15 +105,18 @@ - åå½ï¼æ±æ»å¤§è¡¨ 17 页 **0 æ ¼å·®å¼**ããçæ_ä¸å£å¾æåã**0 æ ¼å·®å¼**ï¼ æç»ä»¶å·®å¼ä» è½å¨ æ»è¡ / åºç§å乡 / ç½çº¦è½¦å乡 è¡çæä»½åä¸ AA 累计åï¼å±é¢æï¼ã ### ç½çº¦è½¦è®¢åæ¥å WordML å¯¼å ¥ï¼15:00ï¼éªè¯ - 8 æ¡ç¨ä¾ï¼4 æ£å / 3 è´å / 1 è¾¹çï¼å ¨é¨éè¿ï¼WordML 2025-09 å¯¼å ¥æåãæ¥è¡¨æç空æ¶é æ é¢èªå¨è¯å«ãç docx å¹çæ ååã`.doc`/xlsx æ¹å/鿬æ¥å docx åç»åºä¸ææç¤ºã - æ°æ®è¡¥é½åéè· 8 æå¯¼åºåå½ï¼ç¬ç«ãçæ_ä¸å£å¾æç»ãæ¥è¡¨æå ä¸ä¸è´ 0ãæ¥è¡¨æåä»æå¼ 0ï¼ä¸æ±æ»å¤§è¡¨ãä¸å£å¾æç»ã页 **704 å¯¹æ ¼ 0 å·®å¼**ï¼å ¨ç 1-8 ææ»å®¢è¿é 3733.79â¦4003.57ï¼ç½çº¦è½¦å乡 333.39â¦426.56ï¼ç´¯è®¡ AA5=31528.0607ãAA9=2911.47ã - æå件䏿ç»ä»¶ç´¯è®¡å£å¾ä¸è´ï¼å 31528.0606ï¼ï¼å·®å¼ 2063.45 æ¶å¤±ã ## ä¸ãéçé®é¢ä¸å¾ å 1. ~~ä¸å£å¾æå忝仿¯åæ»å¼~~ â **å·²ææ°å£å¾åå¼**ï¼M3=0.638 / Q3=0.2247ï¼ï¼ä½ä»ä¸ä¸å£å¾æç»ç 0.0581 ä¸èªæ´½ï¼å·®å¼ 2063.45 = ç½çº¦è½¦ 1-6 ææ æºï¼**æ¶å£åæ³è§ä¸æ¹"第 3 æ¥æ¶å£å»ºè®®"**ã 2. ~~`loadMidClassMap()` 缺巡游åºç§ + ç½çº¦è½¦ä¸¤ç»´~~ â **已补**ï¼ç»´åº¦ 3ã4ï¼ï¼ç¬ç«ä¸å£å¾æç»åç»´é½å ¨ã 3. ~~**æ¯ç缺é·å¾ ä¿®**ï¼ä¸å£å¾æç»åå¸çº§å ¬å¼å¼é页~~ â **误å¤ï¼å·²ä½åº**ï¼çå®å ¬å¼æ¯æ£ç¡®ç跨簿å¼ç¨ï¼æ¯çæ éä¿®æ¹ï¼å½æ¶ç"å¼é页"æ¯æ§å¶å°ä¸æä¹±ç 误读ã 4. **æ°æ®ç¼ºå£ï¼å·²æ ¸å®ï¼å±æºå¤´å°±æ²¡æï¼**ï¼2026-01~06 ç½çº¦è½¦è®¢åå¨**æºæä»¶**ãæ¨¡æ¿_ç½çº¦è½¦è®¢ååå ¨çæ»é.xlsxãéå°±æ¯ç©ºçï¼åªæå ¨ç pinãæ è®¢ååï¼ï¼ 䏿¯å¯¼å ¥å¤±è´¥ââ`wyc_order_monthly` 该 6 æ `order_*` å ¨ NULL ä¸ä¹å»åï¼å¯¼å ¥æ¹æ¬¡ `WYC_ORDER`ï¼09-04ï¼ã å½±åé¢åªæä¸ä¸ªï¼`WycSplitCalc.calc()` å `orderSum<=0` ç®ä¸åºç½çº¦è½¦æå â 维度 4 该 6 ä¸ªææ æºï¼ç°å·²ç±ç¬¬ 4 æ¡æ¹å¨ä¿çæ¯çå®ç¨¿å¼å ä½ï¼ã **建议**ï¼ç»ç½çº¦è½¦è®¢åå¯¼å ¥å 䏿¡ã订ååå ¨ç©ºãçæ¾å¼æç¤ºï¼ç°å¨ä¼é黿åï¼ï¼å¹¶è¯·ä¸å¡ç¡®è®¤è¿ 6 个æè®¢åæ¯å¦å¯è¡¥ã 4. ~~**æ°æ®ç¼ºå£**ï¼2026-01~06 ç½çº¦è½¦è®¢åæªå ¥åº~~ â **已补é½**ï¼ç¨æ· 14:21~14:49 å¯¼å ¥ 2026-01~06 + 2025-01 + 2025-10~12ï¼2025-09 ç» WordML ä¿®å¤åè¡¥å ¥ï¼ãç°å¨ 2025-01~12 + 2026-01~08 订åé½å ¨ï¼ç»´åº¦ 4 å ¨æå¯ç®ï¼æåä»¶/æç»ä»¶å£å¾å½ä¸ãä»å»ºè®®è¡¥ä¸æ¡ãå¯¼å ¥æ¶è®¢ååå ¨ç©ºãçæ¾å¼æç¤ºï¼ã模æ¿_ç½çº¦è½¦è®¢ååå ¨çæ»é.xlsxãé£ç±»æä»¶ç°å¨ä¼é黿åï¼ã 5. åºå h2031ãå ¨çãè¡ â Σ17 å¸å·ï¼1-8 æ 27524.49 vs 24481.74ï¼å·® 3042.75ï¼ï¼ä¸å¡å£å¾é®é¢ï¼å»ºè®®ä¸å¡ä¾§æ ¸å¯¹ã 6. æèµï¼æ¨¡æ¿é没æçæ°é¡¹ç®ä¸ä¼èªå¨æè¡ï¼æç»è¡¨èµéæ¸ éåç»è¡æªå ¥åºï¼éå `fund_channel`ï¼ï¼ååä¸åé¡¹ç®æªå¼¹çªã 7. æèµä¸¤å¼ æç»è¡¨ï¼`Xæå®¢è¿ç«æèµæç»è¡¨` / `Xæç©æµç«åºæèµæç»`ï¼çæå¨æªåã @@ -116,6 +136,6 @@ ## åãæå¤©è®¡å 1. 第 3 æ¥æ¶å£ï¼æå件䏿ç»ä»¶å£å¾å½ä¸ï¼å·®å¼ 2063.45 = 2026 å¹´ 1-6 æç½çº¦è½¦å乡ï¼â æåä»¶æ¹åæ±æ»è¡¨åæºå¼ â åºå"çæä»¶ vs æ¯çéç®"éæ ¼åå½èæ¬ã 2. ç½çº¦è½¦è®¢åå¯¼å ¥ç©ºåæç¤ºï¼é¡µé¢æç¡®æç¤º"该æè®¢ååä¸ºç©ºï¼æªåå ¥è®¢åæ°"ï¼+ åç¨æ·ç¡®è®¤ 2026-01~06 æ¯å¦è¡¥æ°ã 2. ç½çº¦è½¦è®¢åå¯¼å ¥ç©ºåæç¤ºï¼é¡µé¢æç¡®æç¤º"该æè®¢ååä¸ºç©ºï¼æªåå ¥è®¢åæ°"ï¼ââæ°æ®è½å·²è¡¥é½ï¼ä½é黿å仿¯éæ£ã 3. æèµ"æ°å¢é¡¹ç®æè¡ + åç»è¡å ¥åºï¼`fund_channel`ï¼"æ¹æ¡è½å°ï¼çç¨æ·å¯¹"模å"å£å¾çæå确认ï¼ã 4. æèµä¸¤å¼ æç»è¡¨çæå¨ï¼`Xæå®¢è¿ç«æèµæç»è¡¨` / `Xæç©æµç«åºæèµæç»`ï¼ã traffic-audit-server/src/main/java/com/trafficaudit/dataimport/service/DataImportService.java
@@ -60,6 +60,10 @@ import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFTable; import org.apache.poi.xwpf.usermodel.XWPFTableRow; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import cn.hutool.core.io.IoUtil; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -3319,10 +3323,36 @@ Map<String, Double> orders = new LinkedHashMap<>(); double[] sumHolder = new double[]{0.0}; String docPeriod; try (java.io.InputStream in = file.getInputStream(); XWPFDocument doc = new XWPFDocument(in)) { docPeriod = periodOfDocx(doc); parseWycOrderReportTables(doc, orders, sumHolder); byte[] bytes; try (java.io.InputStream in = file.getInputStream()) { bytes = IoUtil.readBytes(in); } boolean isZip = bytes.length > 3 && (bytes[0] & 0xFF) == 0x50 && (bytes[1] & 0xFF) == 0x4B; boolean isWordMl = !isZip && looksLikeWordMl(bytes); try { if (isZip && !isWordPackage(bytes)) { throw new RuntimeException("è¿ä¸æ¯ Word ææ¡£ï¼å缩å éæ²¡æ word/document.xmlï¼ï¼" + "å¤åæ¯ Excel æå ¶å®æ ¼å¼ã请ä¸ä¼ ç½çº¦è½¦è®¢ååææ¥åç .docxï¼æ Word 2003 XMLï¼"); } if (isZip) { try (XWPFDocument doc = new XWPFDocument(new java.io.ByteArrayInputStream(bytes))) { docPeriod = periodOfParagraphs(paragraphsOfDocx(doc)); parseWycOrderReportTables(doc, orders, sumHolder); } } else if (isWordMl) { // ç½çº¦è½¦ç管平å°ä¸åçæ¥å常被 WPS/Word åæãWord 2003 XMLï¼å¹³éº XMLï¼ãååæ¹å .docxï¼ // è¿ç§æä»¶ä¸æ¯ zip å ï¼XWPFDocument æä¸å¼ï¼æ¥ "File is not a zip file"ï¼ï¼éæ XML ç´æ¥è§£æã String xml = new String(bytes, java.nio.charset.StandardCharsets.UTF_8); Document dom = parseXmlSafely(xml); docPeriod = periodOfParagraphs(paragraphsOfDocxXml(dom)); parseWycOrderReportTablesXml(dom, orders, sumHolder); } else if (isOle2(bytes)) { throw new RuntimeException("è¿æ¯ Word 97-2003 èæ ¼å¼ï¼.docï¼ï¼è¯·ç¨ WPS/Word æå¼åãå¦å为ãdocx æ ¼å¼åå¯¼å ¥"); } else { throw new RuntimeException("æ æ³è¯å«çæä»¶æ ¼å¼ï¼æ¢ä¸æ¯ docxï¼zip å ï¼ï¼ä¹ä¸æ¯ Word 2003 XML æ .doc"); } } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException("æ æ³è¯»å Word ææ¡£ï¼è¯·ä¸ä¼ .docx æ ¼å¼çãç½çº¦è½¦è¡ä¸YYYYå¹´Mæè¿è¡çæµæ åµåææ¥åãï¼" + "è¥ä¸ä¼ çå ¶å®æ¯ Excel/PDFï¼è¯·æ¹ç¨å¯¹åºæ¨¡æ¿å¯¼å ¥ãï¼åå§é误ï¼" + e.getMessage() + "ï¼"); @@ -3388,13 +3418,12 @@ } /** æ¥åæ é¢ä¸çæ¥è¡¨æï¼ç½çº¦è½¦è¡ä¸2026å¹´7æ -> 2026-07ï¼åä¸å°è¿å null */ private String periodOfDocx(XWPFDocument doc) { private String periodOfParagraphs(List<String> paragraphs) { java.util.regex.Pattern titlePat = java.util.regex.Pattern.compile("ç½çº¦è½¦è¡ä¸\\s*(\\d{4})\\s*å¹´\\s*(\\d{1,2})\\s*æ"); java.util.regex.Pattern anyPat = java.util.regex.Pattern.compile("(\\d{4})\\s*å¹´\\s*(\\d{1,2})\\s*æ"); String fallback = null; int scanned = 0; for (XWPFParagraph para : doc.getParagraphs()) { String text = para.getText(); for (String text : paragraphs) { if (text == null) continue; String flat = text.replaceAll("\\s+", ""); if (flat.isEmpty()) continue; @@ -3409,6 +3438,92 @@ return fallback; } /** docx æ®µè½ææ¬ï¼ä¿æåå§é¡ºåºï¼ */ private List<String> paragraphsOfDocx(XWPFDocument doc) { List<String> out = new ArrayList<>(); for (XWPFParagraph para : doc.getParagraphs()) out.add(para.getText()); return out; } /** Word 2003 XMLï¼WordMLï¼æ®µè½ææ¬ï¼<w:p> 䏿æ <w:t> æ¼æ¥ååæç©ºç½ */ private List<String> paragraphsOfDocxXml(Document dom) { List<String> out = new ArrayList<>(); for (Element p : elementsByLocalName(dom, "p")) out.add(textOfXmlElement(p)); return out; } /** æ¯å¦ä¸º Word 2003 XMLï¼WordML å¹³éº XMLï¼ââè¿ç§æä»¶å¸¸è¢«æ¹åæ .docx */ private boolean looksLikeWordMl(byte[] bytes) { int n = Math.min(bytes.length, 4096); String head = new String(bytes, 0, n, java.nio.charset.StandardCharsets.UTF_8); return head.contains("wordml") && head.contains("<w:wordDocument"); } /** zip å å æ¯å¦å« word/document.xmlï¼ç¨äºåºå docx ä¸ xlsx/å ¶å® OPC å ï¼ */ private boolean isWordPackage(byte[] bytes) { try (java.util.zip.ZipInputStream zin = new java.util.zip.ZipInputStream(new java.io.ByteArrayInputStream(bytes))) { java.util.zip.ZipEntry e; while ((e = zin.getNextEntry()) != null) { String n = e.getName(); if ("word/document.xml".equals(n)) return true; } } catch (Exception ignore) { return false; } return false; } /** æ¯å¦ä¸º OLE2 å¤åææ¡£ï¼Word 97-2003 .docï¼ */ private boolean isOle2(byte[] b) { return b.length > 8 && (b[0] & 0xFF) == 0xD0 && (b[1] & 0xFF) == 0xCF && (b[2] & 0xFF) == 0x11 && (b[3] & 0xFF) == 0xE0; } /** å®å ¨è§£æ XMLï¼ç¦ç¨å¤é¨å®ä½/DTDï¼æ¥åæ¥èªå¤é¨å¹³å°ï¼é² XXEï¼ */ private Document parseXmlSafely(String xml) throws Exception { javax.xml.parsers.DocumentBuilderFactory f = javax.xml.parsers.DocumentBuilderFactory.newInstance(); f.setNamespaceAware(true); try { f.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); } catch (Exception ignore) { } try { f.setFeature("http://xml.org/sax/features/external-general-entities", false); } catch (Exception ignore) { } try { f.setFeature("http://xml.org/sax/features/external-parameter-entities", false); } catch (Exception ignore) { } javax.xml.parsers.DocumentBuilder b = f.newDocumentBuilder(); b.setEntityResolver(new org.xml.sax.EntityResolver() { @Override public org.xml.sax.InputSource resolveEntity(String publicId, String systemId) { return new org.xml.sax.InputSource(new java.io.StringReader("")); } }); return b.parse(new org.xml.sax.InputSource(new java.io.StringReader(xml))); } /** æ localName åå ¨é¨å代å ç´ ï¼å½åç©ºé´æ å ³ï¼å ¼å®¹ WordML ä¸ docx ç w: åç¼ï¼ */ private List<Element> elementsByLocalName(Document dom, String localName) { List<Element> out = new ArrayList<>(); NodeList list = dom.getElementsByTagNameNS("*", localName); for (int i = 0; i < list.getLength(); i++) out.add((Element) list.item(i)); return out; } /** åªåç´æ¥åå ç´ ï¼é¿å åµå¥è¡¨æ ¼/åµå¥å±æ§å ç´ è¢«ç®è¿æ¥ï¼ */ private List<Element> childElementsByLocalName(Element parent, String localName) { List<Element> out = new ArrayList<>(); NodeList kids = parent.getChildNodes(); for (int i = 0; i < kids.getLength(); i++) { Node n = kids.item(i); if (n.getNodeType() == Node.ELEMENT_NODE && localName.equals(n.getLocalName())) out.add((Element) n); } return out; } /** å ç´ å ææ <w:t> ææ¬æ¼æ¥å¹¶åæç©ºç½ */ private String textOfXmlElement(Element el) { StringBuilder sb = new StringBuilder(); NodeList ts = el.getElementsByTagNameNS("*", "t"); for (int i = 0; i < ts.getLength(); i++) sb.append(ts.item(i).getTextContent()); return flat(sb.toString()); } private String ymd(String y, String mo) { try { int month = Integer.parseInt(mo); @@ -3421,15 +3536,47 @@ /** è§£ææ¥åä¸çãå°å¸åç§° | ⦠| è®¢åæ°æ»æ°ã表ï¼orders=å¸å·è®¢åï¼sumHolder[0]=å计è¡è®¢åæ° */ private void parseWycOrderReportTables(XWPFDocument doc, Map<String, Double> orders, double[] sumHolder) { List<List<List<String>>> tables = new ArrayList<>(); for (XWPFTable table : doc.getTables()) { List<XWPFTableRow> rows = table.getRows(); List<List<String>> rows = new ArrayList<>(); for (XWPFTableRow row : table.getRows()) { List<String> cells = new ArrayList<>(); for (org.apache.poi.xwpf.usermodel.XWPFTableCell c : row.getTableCells()) cells.add(flat(c.getText())); rows.add(cells); } tables.add(rows); } matchWycOrderTable(tables, orders, sumHolder); } /** Word 2003 XMLï¼WordMLï¼åæ¯ï¼<w:tbl>/<w:tr>/<w:tc> æ½æææ¬è¡¨åèµ°åä¸å¥å¹é é»è¾ */ private void parseWycOrderReportTablesXml(Document dom, Map<String, Double> orders, double[] sumHolder) { List<List<List<String>>> tables = new ArrayList<>(); for (Element tbl : elementsByLocalName(dom, "tbl")) { List<List<String>> rows = new ArrayList<>(); for (Element tr : childElementsByLocalName(tbl, "tr")) { List<String> cells = new ArrayList<>(); for (Element tc : childElementsByLocalName(tr, "tc")) cells.add(textOfXmlElement(tc)); rows.add(cells); } tables.add(rows); } matchWycOrderTable(tables, orders, sumHolder); } /** * å¨ãææ¬åè¡¨æ ¼ãéæ¾éä»¶1ï¼è¡¨å¤´å«ãè®¢åæ°æ»æ°ã/ãè®¢åæ°ãï¼å¹¶å 17 å¸å·è®¢åæ°ä¸å计ã * å ¥å tables = 表 -> è¡ -> åå æ ¼ææ¬ï¼å·²å空ç½ï¼ï¼ä¸æ¥æºæ ¼å¼æ å ³ã */ private void matchWycOrderTable(List<List<List<String>>> tables, Map<String, Double> orders, double[] sumHolder) { for (List<List<String>> rows : tables) { if (rows.size() < 3) continue; int headerRow = -1; int orderCol = -1; for (int r = 0; r < Math.min(rows.size(), 3); r++) { List<org.apache.poi.xwpf.usermodel.XWPFTableCell> cells = rows.get(r).getTableCells(); List<String> cells = rows.get(r); for (int c = 0; c < cells.size(); c++) { String norm = flat(cells.get(c).getText()); String norm = cells.get(c); if (norm.contains("è®¢åæ°æ»æ°") || "è®¢åæ°".equals(norm)) { headerRow = r; orderCol = c; @@ -3444,11 +3591,11 @@ double citySum = 0.0; boolean hasTotal = false; for (int r = headerRow + 1; r < rows.size(); r++) { List<org.apache.poi.xwpf.usermodel.XWPFTableCell> cells = rows.get(r).getTableCells(); if (orderCol >= cells.size()) continue; String name = flat(cells.get(0).getText()); List<String> cells = rows.get(r); if (cells.isEmpty() || orderCol >= cells.size()) continue; String name = cells.get(0); if (name.isEmpty()) continue; Double val = parsePlainNumber(cells.get(orderCol).getText()); Double val = parsePlainNumber(cells.get(orderCol)); if (val == null) continue; String city = RegionUtil.normalizeCityName(name); if (city != null && RegionUtil.cityList().contains(city)) {