| New file |
| | |
| | | # åè½æµè¯æ¥å_æ°æ®å¯¼å
¥é¡µç©ºç½ä¿®å¤_2026-09-11 |
| | | |
| | | ## ä¸ãåè½è¯´æ |
| | | |
| | | **ç¨æ·åé¦**ï¼ç»å½åç¹ãæ°æ®å¯¼å
¥ãï¼çé¢åæä¸ç空ç½ã |
| | | |
| | | **ææ¥ä¸æ ¹å **ï¼ç¨æ 头 Chromeï¼CDP è¿ç¨è°è¯ï¼å¤ç°åï¼æ§å¶å°æ¥ï¼ |
| | | |
| | | ``` |
| | | [Vue warn]: Failed to mount component: template or render function not defined. |
| | | found in |
| | | ---> <DataImport> at src/views/DataImport.vue |
| | | ``` |
| | | |
| | | `traffic-audit-web/src/views/DataImport.vue` **ç¼ºå°æå¤å±ç `<template>` 弿 ç¾**ï¼æä»¶ç´æ¥ä» `<el-container>` å¼å§ãSFC 没æ template å â vue-loader ç¼ä¸åº render 彿° â ç»ä»¶æè½½å¤±è´¥ â æ´é¡µç©ºç½ï¼`#app` åªå© 78 å符ï¼ã |
| | | |
| | | å岿²¿é©ï¼`git log -S "SKIP/CHECK"`ï¼ï¼ |
| | | |
| | | | æäº¤ | æä»¶é¦è¡ | ç¶æ | |
| | | | --- | --- | --- | |
| | | | `0f7b7d1^` | `<template>` | æ£å¸¸ | |
| | | | `0f7b7d1` | `SKIP/CHECK (0): TYPE_LABELS upper <template>` | é¦è¡è¢«æ è®°æåè¦ç â å·²æå | |
| | | | `da614c0` | ` <el-container direction="vertical">` | æ è®°è¡è¢«å æï¼`<template>` 仿ªè¡¥å â 仿å | |
| | | | æ¬æ¬¡ä¿®å¤ | `<template>`ï¼å·²è¡¥åï¼ | æ£å¸¸ | |
| | | |
| | | **ä¿®å¤**ï¼å¨æä»¶é¦è¡è¡¥å `<template>`ï¼ä¸è¡æ¹å¨ï¼æªå¨å
¶ä½å
容ï¼ã |
| | | |
| | | ## äºãæµè¯ç¯å¢ |
| | | |
| | | - å端 `http://localhost:8080`ï¼vue-cli-service å¼åæå¡å¨ï¼æ¹å 17:44:48 éæ°ç¼è¯æåï¼ã |
| | | - å¤ç°/éªè¯æ¹å¼ï¼æ 头 Chrome `--remote-debugging-port=9222` + CDPï¼`Page.navigate` / `Runtime.evaluate` / æ§å¶å°äºä»¶æè·ï¼ï¼å
å¨ `sessionStorage` åå
¥ç»å½ token å访é®åä¿æ¤è·¯ç±ã |
| | | - æµè¯æ¶é´ï¼2026-09-11ã |
| | | |
| | | ## ä¸ãç¨ä¾è¡¨ |
| | | |
| | | | ç¼å· | è¾å
¥ | 颿 | å®é
| ç»è®º | |
| | | | --- | --- | --- | --- | --- | |
| | | | TC-1 | ä¿®å¤åè®¿é® `#/import`ï¼ç»å½æï¼ | å¤ç°ç¨æ·é®é¢ | æ§å¶å° `Failed to mount component ⦠<DataImport>`ï¼`#app` innerHTML é¿åº¦ 78ï¼é¡µé¢æ æå | å¤ç°æå | |
| | | | TC-2 | ä¿®å¤åè®¿é® `#/import` | 页颿£å¸¸æ¸²æ | `#app` innerHTML é¿åº¦ **20,821**ï¼å¯è§ã导å
¥ä¸å¡æ°æ® / æ¥è¡¨æ / éæ©æ°æ®ç±»åï¼éè·¯è´§è¿ å
¬è·¯æ
客 åå¸å®¢è¿ ç«åºæèµ è´§è¿è½è壿¥ï¼/ 模æ¿ï¼æ¨¡æ¿_交ä¼ç»H203-2表⦠/ 导å
¥ç»æï¼2026-09ï¼/ 导å
¥è¿åº¦ã | éè¿ | |
| | | | TC-3 | ä¿®å¤åæ§å¶å° | æ Vue/JS é误 | é误äºä»¶æ° **0**ï¼å« `Runtime.exceptionThrown`ã`console.error`ï¼ | éè¿ | |
| | | | TC-4 | å
¨éè·¯ç±æ«æ `#/dashboard`ã`#/import`ã`#/data`ã`#/explain`ã`#/audit`ã`#/report`ã`#/rules`ã`#/users` | 8 个页é¢é½è½æ¸²æãæ æ¥é | 8/8 渲ææåï¼innerHTML é¿åº¦ 4,409~293,029ï¼ï¼æ¯ä¸ªé¡µé¢é误æ°å为 0 | éè¿ | |
| | | | TC-5 | éææ£æ¥ææ `.vue` æ¯å¦ä»¥ `<template>` å¼å¤´ | æ åç±»é®é¢ | 13 个 `.vue` æä»¶ä¸ä»
`DataImport.vue` å¼å¸¸ï¼ä¿®å¤åå
¨é¨ OK | éè¿ | |
| | | | TC-N1 | è´åï¼ç¨å¸¦ hash æ¥è¯¢ä¸²çå°åè®¿é® `#/import?t=â¦` | 说æè·¯ç±ä¸å¹é
æ¶ç表ç°ï¼è¾
å©å®ä½ï¼ | è·¯ç±æ å¹é
â 空ç½ä¸æ æ¥éï¼ä¸æ¬æ¬¡ bug ç°è±¡ä¸åï¼æ®æ¤æé¤äºç¼ååè±¡ï¼ | éè¿ï¼å®ä½ç¨ï¼ | |
| | | |
| | | ## åãåç°çé®é¢ä¸å¤ç½® |
| | | |
| | | 1. **é¦è¡è¢«å·¥å
·åå
¥çæ è®°æåè¦ç**ï¼`0f7b7d1` 飿¬¡çè¡¥ä¸æ `<template>` æ¢æäº `SKIP/CHECK (0): TYPE_LABELS upper <template>` è¿æ ·ç说ææåãæç¤ºï¼ä»¥åæ¹ SFC é¦è¡è¦å¤æ ¸é¦è¡æ¯å¦ä»æ¯ `<template>`ã |
| | | 2. **åä¸æä»¶è¿æè¢«æ¹å/æ¹å¨å¤æ¬¡**ï¼æ¬æ¬¡ä»
è¡¥é¦è¡ï¼æªåå
¶å®æ¹å¨ï¼é¿å
å¼å
¥æ°é£é©ã |
| | | 3. å¤ç°è¿ç¨ä¸åç°æ 头æµè§å¨ä¼ç¼åæ§ bundleï¼éè¦ `Page.reload({ignoreCache:true})` æè½æ¿å°æ°ç¼è¯ç»æï¼æµè¯æ¹æ³è®°å½ï¼é产åé®é¢ï¼ã |
| | | |
| | | ## äºãç»è®º |
| | | |
| | | - ãæ°æ®å¯¼å
¥ãç½å±å·²ä¿®å¤ï¼é¡µé¢ä¸å
¶ä½ 7 个路ç±åæ£å¸¸æ¸²æãæ§å¶å° 0 æ¥éã |
| | | - å端å¼åæå¡å¨å·²çç¼è¯çæï¼ç¨æ·å·æ°é¡µé¢ï¼`Ctrl+F5`ï¼å³å¯æ¢å¤ä½¿ç¨ã |
| | | |
| | | ## å
ãåå¸ä¸äºæ¬¡ç¬ç«éªè¯ï¼2026-09-11 18:0xï¼ |
| | | |
| | | **ä»£ç æäº¤**ï¼`e8ce82e` fix: ä¿®å¤ãæ°æ®å¯¼å
¥ãæ´é¡µç©ºç½ââDataImport.vue è¡¥å缺失ç `<template>` 弿 ç¾ |
| | | |
| | | | å¨ä½ | å½ä»¤ | ç»æ | |
| | | | --- | --- | --- | |
| | | | æåå
¬å¸ä»åº | `git fetch gitea` | è¿ç«¯ `main` æ æ°æäº¤ï¼left/right = 1/0ï¼ï¼æ éåå¹¶ | |
| | | | æ¨éå
¬å¸ä»åº | `git push gitea main` | `a76a8cc..e8ce82e main -> main` | |
| | | | æå个人ä»åº | `git fetch origin` | è¿ç«¯ `master` æ æ°æäº¤ï¼1/0ï¼ï¼æ éåå¹¶ | |
| | | | æ¨é个人ä»åº | `git push origin main:master` | `a76a8cc..e8ce82e main -> master` | |
| | | | 忥æ¬å°åæ¯æé | `git branch -f master main` | `master` = `e8ce82e`ï¼`git status` æ¾ç¤º `main...gitea/main` 已忥 | |
| | | |
| | | **产ç©çº§éªè¯ï¼ä¸ä¾èµæµè§å¨ï¼ç´æ¥æ ¡éªå¼åæå¡å¨ä¸åçç¼è¯ç»æï¼** |
| | | |
| | | | æ£æ¥é¡¹ | æ¹æ³ | ç»æ | |
| | | | --- | --- | --- | |
| | | | å端æ¯å¦å·²çç¼è¯ | 读å `traffic-audit-web/frontend.log` | æå䏿¬¡ `DONE Compiled successfully in 1251ms`ï¼æ¶é´ 17:44:48ï¼`App running at: - Local: http://localhost:8080/` | |
| | | | 端å£åæ´» | `Test-NetConnection 127.0.0.1 -Port 8080/8090` | 8080=Trueã8090=True | |
| | | | ä¿®å¤æ¯å¦ççè¿äºä¸åæä»¶ | ä» `http://localhost:8080/js/6.js`ï¼å« `TYPE_LABELS` ç DataImport ååï¼æåå¹¶æ£ç´¢ | å½ä¸ `el-container`ï¼ä¸ä¸æä¸º `var render = function render() { ... _c("el-container", { attrs: { direction: "vertical" } }) ... _c("app-header", { attrs: { title: "交éç»è®¡æ¥è¡¨å®¡æ ¸ç³»ç» - æ°æ®å¯¼å
¥" } })`ï¼å³æ¨¡æ¿å·²æ£å¸¸ç¼è¯ä¸º render 彿° | |
| | | |
| | | **端å°ç«¯å¤éªï¼æ 头 Chrome + CDPï¼ç¬ç«éè·ï¼** |
| | | |
| | | | ç¨ä¾ | è¾å
¥ | 颿 | å®é
| ç»è®º | |
| | | | --- | --- | --- | --- | --- | |
| | | | TC-6 | åå
¥ `sessionStorage.token` åè®¿é® `http://localhost:8080/#/import`ï¼å¹¶ `Page.reload({ignoreCache:true})` | 页é¢å®æ´æ¸²æ | `location.href` = `http://localhost:8080/#/import`ï¼`#app` innerHTML = **20,821** å符ï¼é¡¶æ æ é¢ã交éç»è®¡æ¥è¡¨å®¡æ ¸ç³»ç» - æ°æ®å¯¼å
¥ãï¼8 个左侧èåã11 个æé®ã1 个ä¸ä¼ æ§ä»¶ã5 ä¸ªä¸ææ¡ã3 个å¡ç | éè¿ | |
| | | | TC-7 | åä¸ï¼ééæ§å¶å° | 0 é误 | `Runtime.consoleAPICalled(error)` = `[]`ï¼`Runtime.exceptionThrown` = `[]` | éè¿ | |
| | | | TC-8 | è®¿é® `http://localhost:8080/import`ï¼æ `#/`ï¼ | 说æè·¯ç±å½¢æï¼æé¤è¯¯å¤ | è·¯ç±ä¸º **hash 模å¼**ï¼è¯¥å°åè½å° `#/dashboard`ï¼å·¥ä½å°ï¼ï¼`#app` = 4409 å符ã0 é误 | éè¿ï¼æ¾æ¸
é¡¹ï¼ | |
| | | |
| | | **æªå¾çè¯**ï¼`_shots/æ°æ®å¯¼å
¥é¡µ_ä¿®å¤å_2026-09-11.png`ï¼1600x1000ï¼æ´é¡µæè·ï¼å¯è§ã导å
¥ä¸å¡æ°æ® / æ¥è¡¨æ / éæ©æ°æ®ç±»åï¼éè·¯è´§è¿ å
¬è·¯æ
客 åå¸å®¢è¿ ç«åºæèµ è´§è¿è½è壿¥ / 模æ¿ä¸è½½ / éæ©æä»¶ / ç«å³å¯¼å
¥ / 导å
¥ç»æï¼2026-09ï¼/ 导å
¥è¿åº¦ãï¼ã |
| | | |
| | | **ç¨æ·ä¾§ç»è®º**ï¼å端å¼åæå¡å¨å·²å 载修å¤åç代ç ï¼ç¨æ·æµè§å¨è¥ä»ç½å±ï¼æ¯æ¬å°ç¼åäºæ§ bundleï¼`Ctrl+F5` 强å·å³å¯æ¢å¤ã |
| New file |
| | |
| | | # åè½æµè¯æ¥å_æ±æ»å¤§è¡¨8ææ°æ®åå¡«ä¸çå¼å¯¹é½_2026-09-11 |
| | | |
| | | ## ä¸ãåè½è¯´æ |
| | | éå¯¹ç¨æ·åé¦ç 4 个é®é¢ï¼å¯¹ãéè·¯è¿è¾éæ±æ»è¡¨ã导åºé¾è·¯åæ°æ®é©±å¨åå¡«ä¸çå¼å¯¹é½ï¼ |
| | | |
| | | 1. **8 ææ°æ®å·²å
¥åºä½æ±æ»è¡¨æ²¡æ 8 ææ°æ®** â æ±æ»å·¥ä½ç°¿å¡«å
å¨è¯å«ã彿å¼åãï¼8 æä¸º Q åï¼å¹¶åå¡«ï¼ |
| | | 2. **忝ä¸å¾ä»¥æ±æ»è¡¨ 2025 å¹´ 8 ææ°æ®ä¸ºå** â 彿忝åï¼R åï¼å
¬å¼ç»ä¸ä¸º `=Q../AJ..-1`ï¼AJ åå³ 2025 å¹´ 8 æï¼ |
| | | 3. **å
¬äº¤ãåºç§æ°æ®æ¯æ¥æå½¢å¼** â åå¡«æ°å¼æ¶æåè¡ 1 æåæ ·å¼å¥ç¨ï¼é¿å
æ°å¼è¢«å¥ä¸æ¥ææ ¼å¼ï¼æ¾ç¤ºæ 1902/1910 å¹´ï¼ï¼ |
| | | 4. **ç线å
车ã轨éè½®æ¸¡åªæåå¸å·æ²¡æå
¨çæ°æ®** â 为å
¨çè¡è¡¥é½å计å
¬å¼ï¼æ¯ç忬åªå¯¹ 1 æåæ»å
¬å¼ï¼ï¼ |
| | | 5. **çå¼å®å
¨æãçæ_éè·¯è¿è¾éæ±æ»è¡¨.xlsxã** â éåå¥ç¨åç
§ä»¶å宽/éèæ è®°ï¼**åç»æ©åï¼8 æ Q/R åï¼ä¹æåç
§ä»¶å®½åº¦**ã |
| | | |
| | | æ¹å¨èå´ï¼ |
| | | - `SummaryWorkbookFiller`ï¼`fillFreightSheet` / `fillWycSheet` éåï¼åªåå¡«ç®æ æå½æï¼æ´¾çè¡ä¿æå
¬å¼ï¼ï¼æ°å¢ `ensureMonthFormulas`ã`ensureMonthYoyFormulas`ã`monthColumnCapacity`ï¼ |
| | | - `ReportExportService`ï¼å¯¼åºæ¶è°ç¨ `ensureMonthFormulas` + æ°å¢ `applySummaryReferenceLayout`ï¼æåç
§ä»¶å¯¹é½å宽ï¼ï¼ |
| | | - `WycSplitCalc`ï¼æ±æ»è¡¨ç½çº¦è½¦åæ°ä¼å
读åºã |
| | | |
| | | å
³é®å£å¾ï¼å½æå¼åï¼0 åºï¼= `2 + 2*(m-1)`ï¼åæ¯å = å¼å + 1ï¼åæ¯åæ¯åºå®ä¸º AJ åï¼2025 å¹´ 8 æï¼ã |
| | | |
| | | ## äºãæµè¯ç¯å¢ |
| | | - å端 `http://localhost:8090`ï¼å¯¼åºæ¥å£ `GET /api/report/export/summaryWorkbook?period=YYYY-MM`ã |
| | | - æ¯çï¼`docs/çææ±æ»å¤§è¡¨/2026å¹´8æéè·¯è¿è¾éæ±æ»è¡¨.xlsx`ï¼çå¼åç
§ï¼`docs/çææ±æ»å¤§è¡¨/çæ_éè·¯è¿è¾éæ±æ»è¡¨.xlsx`ã |
| | | - æµè¯æ¶é´ï¼2026-09-11ã |
| | | |
| | | ## ä¸ãç¨ä¾è¡¨ |
| | | |
| | | ### 3.1 æ£åï¼2026-08 çæä¸å½æåå¼ |
| | | |
| | | | ç¼å· | æ£æ¥é¡¹ | 颿 | å®é
| ç»è®º | |
| | | | --- | --- | --- | --- | --- | |
| | | | TC-1 | å¯¼åº 2026-08 | HTTP 200ï¼æ£å¸¸äº§åºæä»¶ | 4.6 ç§è¿åï¼948,735 åè | éè¿ | |
| | | | TC-2 | å端åå¡«æ¥å¿ | æåå
¥æ ¼æ°ç»è®¡ãæ ç¼ºæ°æç¤º | åå
¥å½æå¼æ ¼æ°=1659ï¼è¡¥å彿忝å
¬å¼æ ¼æ°=600ï¼è¡¥å彿å计å
¬å¼æ ¼æ°=43ï¼å¯¹é½å宽忰=422ï¼ç¼ºæ°æç¤º=[] | éè¿ | |
| | | | TC-3 | è´§è¿é¡µå
¨çåï¼è¡5-10ï¼Q å | è§ä¸/è§ä¸è´§è¿éä¸å¨è½¬éæå¼ï¼å计è¡ä¸ºå
¬å¼ | è§ä¸è´§è¿é 3666.1401ãè§ä¸ 13222.6214ãè§ä¸å¨è½¬ 570004.4355ãè§ä¸å¨è½¬ 1700006.166ï¼Q5=`=Q7+Q9`ãQ6=`=Q8+Q10` | éè¿ | |
| | | | TC-4 | è´§è¿é¡µ Σ17å¸å· = å
¨ç | ç¸ç | Σ17å¸å·è´§è¿é = 16888.7615ï¼å
¨ç Q5 = 3666.1401 + 13222.6214 = 16888.7615 | éè¿ | |
| | | | TC-5 | è´§è¿é¡µå¸å·æ´¾çè¡ | ä¸åæ»å¼ï¼ä¿æå
¬å¼ | æ¦æ± Q14ï¼è§ä¸+è§ä¸å¨è½¬éï¼=`=Q15+Q16`ï¼è§ä¸/è§ä¸å项为æ°å¼ | éè¿ | |
| | | | TC-6 | ç½çº¦è½¦é¡µ | 17 å¸å·å½ææå¼ï¼å
¨çè¡ä¸ºå
¬å¼ | æ¦æ± Q9=1879.9049â¦ãQ10=13407.6982â¦ï¼å
¨ç Q5=`=Q9+Q13+â¦+Q73`ï¼Î£17å¸å·å®¢è¿é=4997.74ãå¨è½¬é=29166.7 | éè¿ | |
| | | | TC-7 | å
¬äº¤é¡µ | å¸å·å½ææå¼ä¸**䏿¯æ¥ææ¾ç¤º** | Q9=3856.83ï¼æ¦æ±å®¢è¿éï¼ï¼åå
æ ¼æ ¼å¼ `0.00`ï¼å
¨ç Q5 为æ±åå
¬å¼ | éè¿ | |
| | | | TC-8 | åºç§é¡µ | åä¸ | Q9=1058.95ï¼æ¦æ±å®¢è¿éï¼ï¼æ ¼å¼ `0.00`ï¼å
¨ç Q5 为æ±åå
¬å¼ | éè¿ | |
| | | | TC-9 | ç线å
车页å
¨çè¡ | æå
¨çå计ï¼åç¼ºå¤±ï¼ | Q4=`=Q8+Q10+Q14+â¦+Q56`ãQ5=`=Q9+Q11+â¦+Q57`ãQ6/Q7 个ä½å计亦为å
¬å¼ | éè¿ | |
| | | | TC-10 | 轨éã轮渡页å
¨çè¡ | æå
¨çå计ï¼åç¼ºå¤±ï¼ | 轨é å
¨ç Q4=`=SUM(Q6,Q8)`ãQ5=`=Q7+Q9`ï¼è½®æ¸¡ å
¨ç Q13=`=Q15`ãQ14=`=Q16` | éè¿ | |
| | | | TC-11 | 忝å
¬å¼æå 2025 å¹´ 8 æ | R ååæ¯ä¸º AJ å | å页表头 AJ å = `2025å¹´8æ`ï¼R åå
¬å¼å½¢å¦ `=Q9/AJ9-1`ï¼AJ åç¡®æ 2025 å¹´ 8 ææ¯çæ°å¼ï¼å¦è´§è¿ AJ7=3716.1158ï¼ | éè¿ | |
| | | | TC-12 | æå¼å³éç® | æä»¶å¸¦å
¨ééç®æ è®° | `xl/workbook.xml` å
`<calcPr calcId="191029" fullCalcOnLoad="true"/>`ï¼Excel/WPS æå¼å³ç®åºå
¨çå计 | éè¿ | |
| | | |
| | | ### 3.2 çå¼å¯¹é½ï¼ç¬¬ 5 é¡¹ï¼ |
| | | |
| | | | ç¼å· | æ£æ¥é¡¹ | 颿 | å®é
| ç»è®º | |
| | | | --- | --- | --- | --- | --- | |
| | | | TC-13 | å
¨è¡¨å宽ä¸ãçæ_éè·¯è¿è¾éæ±æ»è¡¨ãæ¯å¯¹ï¼å±å¼ `<col min..max>` èå´éåæ¯å¯¹ï¼ | å®å
¨ä¸è´ | 19 个页ç¾å
¨é¨æ¯å¯¹ï¼**çå®å·®å¼ 0 å** | éè¿ | |
| | | | TC-14 | æ©åï¼8 æ Q/Rï¼å宽 | ä¸åç
§ä»¶ 8 æä¸è´ | è´§è¿ P/Q/R = 12.67/10.55/11.67ï¼åç
§ 12.67/10.56/11.67ï¼ä»
0.01 æµ®ç¹èå
¥ï¼ï¼ç½çº¦è½¦/轨é轮渡 Q/R=13.0/13.0ï¼å
¬äº¤ Q/R=11.89/13.0ï¼åºç§ Q/R=11.89/13.0ï¼ç线å
车 Q/R=10.22/9.78 ââ åä¸åç
§ä»¶ç¸å | éè¿ | |
| | | |
| | | ### 3.3 è´åä¸åå½ |
| | | |
| | | | ç¼å· | æ£æ¥é¡¹ | 颿 | å®é
| ç»è®º | |
| | | | --- | --- | --- | --- | --- | |
| | | | TC-15 | å岿ï¼2026-07ï¼ä¸å¾è¢«å½æå填污æï¼ä¸ `docs/çææ±æ»å¤§è¡¨/_å¤ä»½_2026å¹´7æéè·¯è¿è¾éæ±æ»è¡¨_æ¸
çå_20260904.xlsx` éæ ¼æ¯å¯¹ | 餿¢å®æ¹é 夿 å·®å¼ | å·®å¼å
±ä¸ç±»ï¼â 426 夿µ®ç¹æ«ä½å·®ï¼æå¤§ç¸å¯¹å·® 7.26e-15ï¼å± Excel 15 ä½æææ°åæªæï¼æ å®è´¨å·®å¼ï¼ï¼â¡ 57 å¤"ææ¬ vs ç弿°å"ï¼â¢ 148 å¤å
¨é¨éä¸å¨ãä¸å£å¾æåã页 ââ è¯¥é¡µå·¦ä¾§éæ§åå·²äº 2026-09-08 æéæ±æ´åå é¤ï¼å±**颿åå**ã**æ åå½** | éè¿ | |
| | | | TC-16 | 缺ææç¤º | ç¼ºæ°æ®çæä»½ææç¤º | 2026-08 å¯¼åº `ç¼ºæ°æç¤º=[]` | éè¿ | |
| | | |
| | | ## åãåç°çé®é¢ä¸å¤ç½® |
| | | |
| | | 1. **é®é¢ï¼å·²ä¿®å¤ï¼**ï¼`monthColumnCapacity` åå®ç°åªè®¤"å« 2026+累计"ç表头ï¼èè´§è¿é¡µè¡¨å¤´æ¯"累计å¨è½¬é"ï¼å¯¼è´å
¶æè¿åé»è®¤åæ°ã8 æåæ°¸ä¸åå¡«ã**å¤ç½®**ï¼æ¹ä¸ºã累计åãä¸ãæåä¸ä¸ªæä»½/æ¥ææ ¼å¼æåãåè¾å¤§å¼ã |
| | | 2. **é®é¢ï¼å·²ä¿®å¤ï¼**ï¼`shiftFormulaColumns` è¿ç»ç»å¼ç¨è¢«æ¼æ `Q5AJ5O5`ã**å¤ç½®**ï¼`sb.append(quoteReplacement(...))` â `m.appendReplacement(sb, quoteReplacement(...))`ã |
| | | 3. **é®é¢ï¼å·²ä¿®å¤ï¼**ï¼`ensureMonthYoyFormulas` ä¸ `setCellFormula` 失败被éé»åæã**å¤ç½®**ï¼æ¹ä¸ºæåºå«é¡µç¾/åå
æ ¼/åå¼/ç®æ å¼ç `IllegalStateException`ï¼ä¾¿äºå®ä½ã |
| | | 4. **é®é¢ï¼å·²ä¿®å¤ï¼**ï¼åå¡«ç®æ æ ¼è¥è¢«å¥ä¸æ¥ææ ¼å¼ï¼æ°å¼ä¼æ¾ç¤ºæ 1902/1910 å¹´ï¼å³ç¨æ·åé¦ç"æ¥æå½¢å¼"ï¼ã**å¤ç½®**ï¼`setNumeric` 对空/æ¥ææ ¼å¼æ ¼å¥ç¨åè¡ 1 æåæ ·å¼ï¼å¯¹å·²æå
¬å¼æ ¼ç´æ¥è·³è¿ä¸è¦çã |
| | | 5. **å·²ç¥æ 害åè¦**ï¼2026-08 å¯¼åºæ¶æ¥å¿åºç° `æ±æ»å·¥ä½ç°¿æªæ¾å°åæå¤ä»½æ¯çï¼_å¤ä»½_2026å¹´8æâ¦ï¼ï¼è¾åºå°ä¿ææ¯çç°ç¶`ãåå æ¯ 8 ææ²¡æ"æ¸
çåå¤ä»½æ¯ç"ï¼è 8 ææ¯çæ¬èº«å·²æ¯å®æ´æ¯çï¼æ éä»å¤ä»½è¿åï¼æ
ä¸å½±åè¾åºï¼å·²é项éªè¯å弿£ç¡®ï¼ã7 æå åå¨ `_å¤ä»½_2026å¹´7æâ¦` æ æ¤åè¦ã |
| | | 6. **æ§è½æ³¨æ**ï¼`applySummaryReferenceLayout` çåæ°ä¸éä¿ç `min(åç
§ä»¶å·²ç¨åæ°, ç®æ ä»¶å·²ç¨åæ° + 4)` ââ å»æè¯¥ä¸éä¼è®© POI å¨å¤§åå·ï¼è´§è¿é¡µ 147 åï¼ä¸åºç°ææ°çº§å¡é¡¿ã |
| | | |
| | | ## äºãç»è®º |
| | | 8 ææ±æ»å¤§è¡¨å·²è½ç±åºä¸æ°æ®èªå¨çæï¼è´§è¿è§ä¸/è§ä¸ãç½çº¦è½¦ãå
¬äº¤ãåºç§ãç线å
车ã轨é轮渡ç彿ååå·²åå¡«ï¼å
¨çå计ä¸åå¸å·å计ä¸è´ï¼åæ¯ç»ä¸å 2025 å¹´ 8 æï¼å
¬äº¤/åºç§ä¸åæ¾ç¤ºä¸ºæ¥æï¼ç线å
车ä¸è½¨é轮渡çå
¨çæ°æ®å·²è¡¥é½ï¼å
¬å¼ï¼æå¼å³ç®ï¼ï¼å
¨è¡¨å宽ä¸ç¨æ·æå®çãçæ_éè·¯è¿è¾éæ±æ»è¡¨ãéåä¸è´ï¼å« 8 ææ©å宽度ï¼ã7 æå岿å彿 å®è´¨å·®å¼ã |
| | | |
| | | éçï¼è¯·å°çå®çãç½çº¦è½¦è¡ä¸2026å¹´8æè¿è¡çæµæ
åµåææ¥åãéä¼ ä¸æ¬¡ï¼è¦çå½åç¨ 7 ææ¥å临æ¶å¯æ¬å¯¼å
¥ç 8 æå¸å·è®¢åæ°ã |
| | | |
| New file |
| | |
| | | # åè½æµè¯æ¥å_æ±æ»è¡¨æå页巿°ä¸åæ¯ç¾åæ°_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 å¹´æ°æ®å
¥åºï¼åå¼ éææå页å¾
æ°æ®é©±å¨æ¹é ã |
| New file |
| | |
| | | # åè½æµè¯æ¥å_ç½çº¦è½¦è®¢åæ¥å导å
¥_2026-09-11 |
| | | |
| | | ## ä¸ãåè½è¯´æ |
| | | æ¯æç´æ¥ä¸ä¼ é¨çº§ãç½çº¦è½¦è¡ä¸YYYYå¹´Mæè¿è¡çæµæ
åµåææ¥åãï¼.docxï¼ï¼ç³»ç»èªå¨è§£ææ¥åæ£æé件表ä¸ç **17 å¸å·è®¢åæ°**å¹¶åå
¥æ°æ®åº `wyc_order_monthly`ï¼F å订åå计 + G-W 17 å¸å·è®¢ååï¼ï¼ |
| | | æ±æ»å¤§è¡¨ãç½çº¦è½¦ã页忰æ¹ä¸º**ä¼å
读åº**ï¼å®ç°"ä¸ä¼ æ¥å â æ±æ»è¡¨å½æç½çº¦è½¦æ°æ®èªå¨åºç°"ã |
| | | |
| | | æ¹å¨èå´ï¼ |
| | | - å端 `DataImportService.importWycOrderReport()` / `parseWycOrderReportTables()` / `periodOfDocx()`ï¼è§£ææ¥åãå®ä½æ¥è¡¨æãè½åº `wyc_order_monthly`ï¼å¹¶å¨ç¼ºå¤±æ¶ä» `wyc_total_monthly` è¡¥é½å
¨ç pinï¼B-Eï¼ã |
| | | - å端 `DataImportController`ï¼æ°å¢ `POST /api/import/wycOrderReport`ï¼åæ° file + periodï¼ã |
| | | - å端 `WycSplitCalc.loadMonthlyInputFromDb()`ï¼æ±æ»è¡¨åæ°ä¼å
读 `wyc_order_monthly`ï¼åºé该æè®¢åå
¨ç©ºæ¶åé读 `docs/åå¸å®¢è¿/模æ¿_ç½çº¦è½¦è®¢ååå
¨çæ»é.xlsx`ï¼ã |
| | | - å端 `DataImport.vue`ï¼å¯¼å
¥ç±»åæ°å¢ãç½çº¦è½¦è®¢åæ¥åãï¼æ¨¡æ¿æç¤ºä¸º `åå¸å®¢è¿/模æ¿_ç½çº¦è½¦è®¢å.docx`ï¼æ¥å£ `/import/wycOrderReport`ï¼æä»¶ç±»åé `.docx/.doc`ã |
| | | - æ¸
空æ å°ï¼`wycOrderReport` å
³èæ¸
空 `WYC_ORDER` æ¹æ¬¡ï¼`wycOrder` ä¸ `wycOrderReport` äºä¸ºå
³èæ¸
é¤ã |
| | | |
| | | æ¥è¡¨æåå¼è§åï¼ä¼å
åæ¥åæ é¢ä¸çãç½çº¦è½¦è¡ä¸YYYYå¹´Mæãï¼åä¸å°æ¶ç¨é¡µé¢æéæ¥è¡¨æï¼ä¸¤è
é½åä¸å°åæ¥éã |
| | | |
| | | ## äºãæµè¯ç¯å¢ |
| | | - å端ï¼Spring Bootï¼`http://localhost:8090`ï¼8090 å·²çå¬ï¼ï¼å端ï¼`http://localhost:8080`ã |
| | | - æ°æ®åºï¼MySQL 5.7 `127.0.0.1:3308` / `traffic_audit`ã |
| | | - ç»å½ï¼adminï¼æµè¯æ¶é´ï¼2026-09-11ã |
| | | |
| | | ## ä¸ãç¨ä¾è¡¨ |
| | | |
| | | | ç¼å· | ç±»å | è¾å
¥ | 颿 | å®é
| ç»è®º | |
| | | | --- | --- | --- | --- | --- | --- | |
| | | | TC-1 | æ£å | ä¸ä¼ `docs/åå¸å®¢è¿/模æ¿_ç½çº¦è½¦è®¢å.docx`ï¼ãç½çº¦è½¦è¡ä¸2026å¹´7æè¿è¡çæµæ
åµåææ¥åãï¼ï¼period=2026-07 | è§£ææåï¼æ¥è¡¨æåæ é¢ç 2026-07ï¼17 å¸å·å
¨é¨å½ä¸ | è¿å"æ¥è¡¨æ 2026-07ï¼è®¢åå计 29,730,791 åï¼å·²åå
¥ 17 个å¸å·" | éè¿ | |
| | | | TC-2 | æ£å | åä¸ï¼æ£æ¥å端æ¥å¿ | è®°å½ period/sum/cities/missing | `WycOrderReport imported: period=2026-07 sum=2.9730791E7 cities=17 missing=[]` | éè¿ | |
| | | | TC-3 | å
¥åºæ½æ¥ | docx é件表ãå°å¸åç§° / è®¢åæ°æ»æ°ã17 è¡ï¼éé¡¹ä¸ `wyc_order_monthly` æ¯å¯¹ | 17 å¸å·éä¸ç¸çï¼å计ç¸ç | æ¦æ± 11,183,267ï¼é»ç³ 983,296ï¼åå ° 2,155,144ï¼å®æ 3,024,336ï¼è¥é³ 2,390,572ï¼éå· 321,348ï¼èé¨ 942,124ï¼åæ 1,220,812ï¼èå· 1,573,514ï¼é»å 1,125,829ï¼å¸å® 928,460ï¼éå· 528,210ï¼æ©æ½ 2,166,015ï¼ä»æ¡ 528,557ï¼æ½æ± 267,879ï¼å¤©é¨ 387,894ï¼æåº 3,534ï¼å计 29,730,791 ââ **ä¸ DB å®å
¨ä¸è´** | éè¿ | |
| | | | TC-4 | è´åï¼æä»¶ç±»åéï¼ | æ `模æ¿_ç½çº¦è½¦è®¢ååå
¨çæ»é.xlsx` ä¼ ç»æ¥å导å
¥æ¥å£ | ç»åºå¯è¯»æç¤ºï¼ä¸è½åº | è¿å"导å
¥å¤±è´¥: æ æ³è¯»å Word ææ¡£ï¼è¯·ä¸ä¼ .docx æ ¼å¼çãç½çº¦è½¦è¡ä¸YYYYå¹´Mæè¿è¡çæµæ
åµåææ¥åãï¼è¥ä¸ä¼ çå
¶å®æ¯ Excel/PDFï¼è¯·æ¹ç¨å¯¹åºæ¨¡æ¿å¯¼å
¥ãï¼åå§é误ï¼â¦ï¼" | éè¿ï¼å«ä¿®å¤ï¼è§ç¬¬åèï¼ | |
| | | | TC-5 | è´åï¼å
容ä¸ç¬¦ï¼ | ä¸ä¼ `åå¸å®¢è¿æ°æ®ä¼å.docx`ï¼éç½çº¦è½¦çæµæ¥åï¼ | æç¡®æç¤ºæªè§£æå°å¸å·è®¢åæ° | è¿å"导å
¥å¤±è´¥: æªè§£æå°ä»»ä½å¸å·è®¢åæ°ï¼è¯·ç¡®è®¤ä¸ä¼ çæ¯ãç½çº¦è½¦è¡ä¸YYYYå¹´Mæè¿è¡çæµæ
åµåææ¥åã" | éè¿ | |
| | | | TC-6 | æ£åï¼éå¤å¯¼å
¥å¹çï¼ | åä¸ä»½ 7 ææ¥åè¿ç»å¯¼å
¥ä¸¤æ¬¡ | ç¬¬äºæ¬¡è¦çåæ¥è¡¨æè¡ï¼ä¸äº§çéå¤è¡ | ä»è¿å 17 å¸å·ï¼`wyc_order_monthly` ä¸ `2026-07` ä»
1 è¡ | éè¿ | |
| | | | TC-7 | èè° | æ¥å导å
¥åéæ°å¯¼åº `period=2026-08` æ±æ»å¤§è¡¨ | ç½çº¦è½¦é¡µå½æåï¼Q åï¼åºç°æ°å¼ï¼å
¨çè¡ä¸ºæ±åå
¬å¼ | Q å 17 å¸å·å
¨é¨æå¼ï¼Q5 èµ· 4 个å
¨çè¡ä¸º `=Q9+Q13+â¦` æ±åå
¬å¼ï¼R å忝å
¬å¼ `=Q../AJ..-1`ï¼AJ=2025å¹´8æï¼ | éè¿ï¼è¯¦è§ãåè½æµè¯æ¥å_æ±æ»å¤§è¡¨8ææ°æ®åå¡«ä¸çå¼å¯¹é½_2026-09-11.mdãï¼ | |
| | | |
| | | ## åãåç°çé®é¢ä¸å¤ç½® |
| | | |
| | | 1. **é®é¢ï¼å·²ä¿®å¤ï¼**ï¼æ Excel/PDF è¯¯ä¼ å°ãç½çº¦è½¦è®¢åæ¥åãç±»åæ¶ï¼æ¥å£è¿åçæ¯ xmlbeans çè±æææ¯å¼å¸¸ï¼`org.apache.xmlbeans.XmlException: ... is not a valid document`ï¼ï¼é¡µé¢ç¨æ·æ æ³çè§£ã |
| | | **å¤ç½®**ï¼`DataImportService.importWycOrderReport()` çè§£ææ®µç»ä¸æè·å¼å¸¸ï¼æ¹åä¸ºç¨æ·å¯è¯»æç¤ºï¼å¹¶æåå§é误以"ï¼åå§é误ï¼â¦ï¼"é卿«å°¾ä¾¿äºææ¥ãä¿®å¤å TC-4 夿µéè¿ã |
| | | 2. **éè¦ç¨æ·æä½çäºé¡¹**ï¼å½ååºä¸ `2026-08` ç**å¸å·è®¢åæ°**æ¯ç¨ 7 ææ¥åæ¹æ é¢ç临æ¶å¯æ¬ï¼`_t_wyc_aug.docx`ï¼å¯¼å
¥çï¼å
¶å¸å·å¼ä¸ 7 æç¸åï¼`pin`ï¼B-Eï¼å³å®¢è¿é/å¨è½¬éå£å¾ï¼åèª `wyc_total_monthly` ç 2026-08 è¡ï¼æ¯æ£ç¡®çã**请æçå®çãç½çº¦è½¦è¡ä¸2026å¹´8æè¿è¡çæµæ
åµåææ¥åãéæ°ä¸ä¼ 䏿¬¡**ï¼ç±»åéãç½çº¦è½¦è®¢åæ¥åãï¼æ¥è¡¨æé 2026-08ï¼ï¼å³å¯è¦ç为çå® 8 æå¸å·è®¢åæ°ã |
| | | |
| | | ## äºãç»è®º |
| | | ç½çº¦è½¦è®¢åè¿è¡çæµæ¥åï¼docxï¼å¯¼å
¥åè½å¯ç¨ï¼æ£åè§£æ 17 å¸å·è®¢åæ°åç¡®å
¥åºå¹¶ä¸æºæä»¶é项ä¸è´ï¼æä»¶ç±»åé误ãå
容ä¸ç¬¦ä¸¤ç±»è´ååºæ¯åè½ç»åºæç¡®æç¤ºï¼éå¤å¯¼å
¥å¹çï¼å¯¼å
¥åæ±æ»å¤§è¡¨å¯èªå¨åå°å½ææ°æ®ã建议å°çå® 8 ææ¥åéä¼ å忬¡å¯¼åºæ ¸å¯¹ã |
| | | |
| New file |
| | |
| | | # 工使¥ç»_2026-09-11 |
| | | |
| | | ## ä¸ãä»å¤©åäºä»ä¹ |
| | | |
| | | ### 1. åå¸å®¢è¿ï¼ç½çº¦è½¦è®¢åè¿è¡çæµæ¥åï¼docxï¼å¯¼å
¥ï¼ç¨æ·ç¬¬ 1 é¡¹ï¼ |
| | | - å端æ°å¢ `POST /api/import/wycOrderReport` ä¸ `DataImportService.importWycOrderReport()`ï¼è§£æãç½çº¦è½¦è¡ä¸YYYYå¹´Mæè¿è¡çæµæ
åµåææ¥åãé件表ãå°å¸åç§° / è®¢åæ°æ»æ°ãï¼å 17 å¸å·è®¢åæ°åå
¥ `wyc_order_monthly`ï¼F 订åå计 + G-W å¸å·åï¼ï¼æ¥è¡¨æä¼å
åæ¥åæ é¢å¹´æã |
| | | - å
¨ç pinï¼B-Eï¼å¨è¯¥æè¡ç¼ºå¤±æ¶ï¼ä» `wyc_total_monthly` åæ¥è¡¨æè¡¥é½ã |
| | | - å端导å
¥ç颿°å¢ç±»åãç½çº¦è½¦è®¢åæ¥åãï¼ç»å® `åå¸å®¢è¿/模æ¿_ç½çº¦è½¦è®¢å.docx`ï¼é .docx/.docï¼ï¼å¹¶æ¥å
¥æç±»åæ¸
空ã |
| | | - æ±æ»å¤§è¡¨ç½çº¦è½¦åæ°æ¹ä¸º**ä¼å
读åº**ï¼`WycSplitCalc.loadMonthlyInputFromDb`ï¼ï¼åºéæ æ°æ®èªå¨åé读 xlsx æ¯çã |
| | | - ä¿®å¤ï¼è¯¯ä¼ Excel æ¶æåº xmlbeans è±æå¼å¸¸ â æ¹ä¸ºç¨æ·å¯è¯»æç¤ºã |
| | | |
| | | ### 2. æ±æ»å¤§è¡¨ 8 ææ°æ®åå¡«ä¸çå¼å¯¹é½ï¼ç¨æ·ç¬¬ 2/3/4/5 é¡¹ï¼ |
| | | - 8 ææºæ°æ®å·²å¨åº â å¯¼åºæ¶èªå¨å填彿å¼åï¼Q åï¼ï¼å岿ä¸å¨ã |
| | | - 忝ç»ä¸ä»¥æ±æ»è¡¨ **2025 å¹´ 8 æï¼AJ åï¼** ä¸ºåæ¯ï¼å
¬å¼ `=Q../AJ..-1`ã |
| | | - å
¬äº¤/åºç§æ°å¼ä¸åè¢«æ¥ææ ¼å¼åæï¼æåè¡ 1 æåæ ·å¼å¥ç¨ï¼`0.00`ï¼ã |
| | | - ç线å
车ã轨é轮渡ãå
¨çãè¡è¡¥é½å计å
¬å¼ï¼æ¯çååªå¯¹ 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. ä¿®ãæ°æ®å¯¼å
¥ãç½å±ï¼ç¨æ·ç´§æ¥åé¦ï¼ |
| | | - ç°è±¡ï¼ç»å½åç¹ãæ°æ®å¯¼å
¥ãæ´é¡µç©ºç½ã |
| | | - æ ¹å ï¼`DataImport.vue` é¦è¡ç `<template>` 被æ©åææ¬¡è¡¥ä¸è¦çæè¯´ææå `SKIP/CHECK (0): â¦`ï¼æ¬æ¬¡æ¨éç `da614c0` åæè¿è¡å æï¼å¯¼è´ SFC 没æ template å â `Failed to mount component: template or render function not defined` â æ´é¡µç©ºç½ï¼`#app` ä»
78 å符ï¼ã |
| | | - ä¿®å¤ï¼é¦è¡è¡¥å `<template>`ï¼åè¡æ¹å¨ï¼ï¼æ 头 Chrome + CDP å¤ç°å¹¶éªè¯ï¼8 个路ç±å
¨é¨æ£å¸¸ãæ§å¶å° 0 æ¥éã |
| | | |
| | | ### 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 ä¾å
¨é¨éè¿ã |
| | | - `docs/åè½æµè¯æ¥å/åè½æµè¯æ¥å_æ°æ®å¯¼å
¥é¡µç©ºç½ä¿®å¤_2026-09-11.md`ï¼5 ä¾éè¿ï¼ä¿®å¤åå¤ç°ç½å± â ä¿®å¤å `#app` 20,821 å符ã8 个路ç±å
¨éè¿ã0 æ§å¶å°æ¥éï¼ã |
| | | - 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 å**ã |
| | | - 7 æå岿åå½ï¼æ å®è´¨å·®å¼ï¼148 å¤å·®å¼å
¨é¨æ¯ãä¸å£å¾æåã页 09-08 å·²æéæ±å é¤çæ§å·¦åï¼ã |
| | | |
| | | ## ä¸ãéçé®é¢ä¸å¾
å |
| | | 1. **éç¨æ·æä½**ï¼åºä¸ `2026-08` çå¸å·è®¢åæ°ç®åæ¯ç¨ 7 ææ¥åæ¹æ é¢ç临æ¶å¯æ¬ï¼`_t_wyc_aug.docx`ï¼å¯¼å
¥çï¼å¸å·å¼ä¸ 7 æç¸åï¼è¯·æçå®ç 8 æè¿è¡çæµæ¥åéä¼ ä¸æ¬¡ï¼ç±»åãç½çº¦è½¦è®¢åæ¥åãï¼æ¥è¡¨æ 2026-08ï¼è¦çã |
| | | 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 æï¼éåç»åææ°æ®é©±å¨åä¸å¹¶æ´æ°ã |
| | | |
| | | ### 4. ãæ°æ®å¯¼å
¥ãç½å±ä¿®å¤çåå¸ï¼2026-09-11 åæï¼ |
| | | - æäº¤ `e8ce82e`ï¼`DataImport.vue` è¡¥å缺失ç `<template>` 弿 ç¾ï¼å·²æ¨éåä»åºï¼`git push gitea main`ï¼`a76a8cc..e8ce82e`ï¼ã`git push origin main:master`ï¼`a76a8cc..e8ce82e`ï¼ï¼å¹¶ `git branch -f master main` 忥æ¬å° `master` æéãæ¨éå `git fetch gitea` / `git fetch origin` å确认è¿ç«¯æ æ°æäº¤ï¼æªåçè¦çã |
| | | - åå¸ååäºä¸¤å±ç¬ç«å¤éªï¼â 产ç©å±ââä»å¼åæå¡å¨æ `http://localhost:8080/js/6.js`ï¼ç¡®è®¤ DataImport ååå·²å«ç¼è¯åç `render` 彿°ï¼`_c("el-container", ...)`ãæ é¢ã交éç»è®¡æ¥è¡¨å®¡æ ¸ç³»ç» - æ°æ®å¯¼å
¥ãï¼ï¼â¡ 端å°ç«¯ââæ å¤´ Chrome + CDP è®¿é® `#/import`ï¼`#app` 20,821 å符ã8 èå/11 æé®/1 ä¸ä¼ æ§ä»¶é½å
¨ãæ§å¶å° 0 éè¯¯ï¼æªå¾å `_shots/æ°æ®å¯¼å
¥é¡µ_ä¿®å¤å_2026-09-11.png`ã |
| | | - å¤çæ¾æ¸
ï¼æ¬é¡¹ç®åç«¯è·¯ç±æ¯ hash 模å¼ï¼å¤éªå°åå¿
é¡»æ¯ `http://localhost:8080/#/import`ï¼ç´æ¥è®¿é® `/import` ä¼éå®åå° `#/dashboard`ï¼å®¹æè¢«è¯¯å¤æãç½å±æ²¡ä¿®å¥½ãã |
| | | - æ¥åï¼`docs/åè½æµè¯æ¥å/åè½æµè¯æ¥å_æ°æ®å¯¼å
¥é¡µç©ºç½ä¿®å¤_2026-09-11.md`ï¼å·²è¡¥ãå
ãåå¸ä¸äºæ¬¡ç¬ç«éªè¯ãï¼ã |
| | | |
| | | |
| | | ## åãæå¤©è®¡å |
| | | 1. ç¨æ·éä¼ çå® 8 æç½çº¦è½¦æ¥ååï¼éæ°å¯¼åº 2026-08 å¹¶é项夿 ¸ç½çº¦è½¦é¡µã |
| | | 2. ç»§ç»æç¨æ·å馿 ¸å¯¹ 8 ææ±æ»å¤§è¡¨æåï¼éç¹ï¼ä¸å£å¾å页ãè´§è¿æå页ï¼ã |
| | | 3. æ¸
çä¸´æ¶æä»¶ï¼éç¨æ·ç¡®è®¤ï¼ã |
| | | 4. è§ç¨æ·åé¦å³å®æ¯å¦æåå¼ éææå页ï¼å叿±æ»/åå¸åå¸å·/ä¸å£å¾åæ/éè·¯è¿è¾å¨è½¬éï¼åææ°æ®é©±å¨ã |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | /** ç½çº¦è½¦è®¢åè¿è¡çæµåææ¥åï¼docxï¼ãç½çº¦è½¦è¡ä¸YYYYå¹´Mæè¿è¡çæµæ
åµåææ¥åãï¼ */ |
| | | @PostMapping("/wycOrderReport") |
| | | public Result<String> importWycOrderReport(@RequestParam("file") MultipartFile file, |
| | | @RequestParam("period") String period) { |
| | | try { |
| | | DataImportService.WycOrderReportResult r = importService.importWycOrderReport(file, period); |
| | | StringBuilder msg = new StringBuilder("ç½çº¦è½¦è®¢åæ¥å导å
¥æåï¼æ¥è¡¨æ " + r.getPeriod() |
| | | + "ï¼è®¢åå计 " + String.format("%,.0f", r.getOrderSum()) + " åï¼å·²åå
¥ " + r.getCityCount() + " 个å¸å·"); |
| | | if (!r.getMissingCities().isEmpty()) { |
| | | msg.append("ï¼ä»¥ä¸å¸å·æªå¨æ¥åä¸è§£æå°ï¼æªåå
¥ï¼").append(String.join("ã", r.getMissingCities())); |
| | | } |
| | | return Result.ok(msg.toString()); |
| | | } catch (Exception e) { |
| | | log.error("wycOrderReport import error", e); |
| | | return Result.error("导å
¥å¤±è´¥: " + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** æèµææ¥ï¼å
¨çæ±æ»å¤§è¡¨ï¼ï¼category=客è¿ç«åº/ç©æµååº */ |
| | | @PostMapping("/investment") |
| | | public Result<String> importInvestment(@RequestParam("file") MultipartFile file, |
| | |
| | | import org.apache.poi.ss.usermodel.Sheet; |
| | | import org.apache.poi.ss.usermodel.Workbook; |
| | | import org.apache.poi.ss.usermodel.WorkbookFactory; |
| | | import org.apache.poi.xwpf.usermodel.XWPFDocument; |
| | | import org.apache.poi.xwpf.usermodel.XWPFParagraph; |
| | | import org.apache.poi.xwpf.usermodel.XWPFTable; |
| | | import org.apache.poi.xwpf.usermodel.XWPFTableRow; |
| | | import cn.hutool.core.io.IoUtil; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | |
| | | CLEAR_TYPE_TO_OP.put("cityTaxiAuth", "CITY_TAXI_AUTH"); |
| | | CLEAR_TYPE_TO_OP.put("wycTotal", "WYC_TOTAL"); |
| | | CLEAR_TYPE_TO_OP.put("wycOrder", "WYC_ORDER"); |
| | | CLEAR_TYPE_TO_OP.put("wycOrderReport", "WYC_ORDER"); |
| | | |
| | | CLEAR_TYPE_TO_AUDIT.put("h2032", new String[]{"H2032"}); |
| | | CLEAR_TYPE_TO_AUDIT.put("transportAuth", new String[]{"H2032"}); |
| | |
| | | CLEAR_TYPE_TO_BATCH.put("cityTaxi", new String[]{"CITY_TAXI"}); |
| | | CLEAR_TYPE_TO_BATCH.put("cityTaxiAuth", new String[]{"CITY_TAXI_AUTH"}); |
| | | CLEAR_TYPE_TO_BATCH.put("wycTotal", new String[]{"WYC_TOTAL"}); |
| | | CLEAR_TYPE_TO_BATCH.put("wycOrder", new String[]{"WYC_ORDER"}); |
| | | CLEAR_TYPE_TO_BATCH.put("wycOrder", new String[]{"WYC_ORDER", "WYC_ORDER_REPORT"}); |
| | | CLEAR_TYPE_TO_BATCH.put("wycOrderReport", new String[]{"WYC_ORDER_REPORT", "WYC_ORDER"}); |
| | | } |
| | | |
| | | /** |
| | |
| | | return ok; |
| | | } |
| | | |
| | | // ========== ç½çº¦è½¦è®¢åè¿è¡çæµåææ¥åï¼docxï¼å¯¼å
¥ ========== |
| | | |
| | | /** ç½çº¦è½¦è®¢åæ¥å导å
¥ç»æï¼æ¥è¡¨æ/订åå计/è¦çå¸å·æ°/缺失å¸å·ï¼ */ |
| | | public static class WycOrderReportResult { |
| | | private final String period; |
| | | private final double orderSum; |
| | | private final int cityCount; |
| | | private final List<String> missingCities; |
| | | |
| | | public WycOrderReportResult(String period, double orderSum, int cityCount, List<String> missingCities) { |
| | | this.period = period; |
| | | this.orderSum = orderSum; |
| | | this.cityCount = cityCount; |
| | | this.missingCities = missingCities; |
| | | } |
| | | |
| | | public String getPeriod() { return period; } |
| | | public double getOrderSum() { return orderSum; } |
| | | public int getCityCount() { return cityCount; } |
| | | public List<String> getMissingCities() { return missingCities; } |
| | | } |
| | | |
| | | /** |
| | | * ãç½çº¦è½¦è¡ä¸YYYYå¹´Mæè¿è¡çæµæ
åµåææ¥åãï¼docxï¼å¯¼å
¥ï¼ |
| | | * è§£ææ¥åéä»¶ä¸ãå°å¸åç§° | ⦠| è®¢åæ°æ»æ°ã表ç 17 å¸å·è®¢åæ°ï¼åå
¥ wyc_order_monthly ç |
| | | * F 订ååè®¡ä¸ G-W 17 å¸å·è®¢ååï¼å
¨ç pinï¼B-Eï¼æ²¿ç¨è¯¥æå·²æè¡ï¼è¥æ 该æè¡åä» |
| | | * wyc_total_monthly åæ¥è¡¨æå¤å¶ãæ¥è¡¨æä¼å
åæ¥åæ é¢å¹´æï¼åä¸å°æ¶ç¨é¡µé¢æéæ¥è¡¨æã |
| | | */ |
| | | public synchronized WycOrderReportResult importWycOrderReport(MultipartFile file, String period) throws Exception { |
| | | 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); |
| | | } catch (Exception e) { |
| | | throw new RuntimeException("æ æ³è¯»å Word ææ¡£ï¼è¯·ä¸ä¼ .docx æ ¼å¼çãç½çº¦è½¦è¡ä¸YYYYå¹´Mæè¿è¡çæµæ
åµåææ¥åãï¼" |
| | | + "è¥ä¸ä¼ çå
¶å®æ¯ Excel/PDFï¼è¯·æ¹ç¨å¯¹åºæ¨¡æ¿å¯¼å
¥ãï¼åå§é误ï¼" + e.getMessage() + "ï¼"); |
| | | } |
| | | if (orders.isEmpty()) { |
| | | throw new RuntimeException("æªè§£æå°ä»»ä½å¸å·è®¢åæ°ï¼è¯·ç¡®è®¤ä¸ä¼ çæ¯ãç½çº¦è½¦è¡ä¸YYYYå¹´Mæè¿è¡çæµæ
åµåææ¥åã"); |
| | | } |
| | | String rp = null; |
| | | if (docPeriod != null && docPeriod.matches("\\d{4}-\\d{2}")) rp = docPeriod; |
| | | else if (period != null && period.matches("\\d{4}-\\d{2}")) rp = period; |
| | | if (rp == null) { |
| | | throw new RuntimeException("æ æ³ç¡®å®æ¥è¡¨æï¼æ¥åæ 颿ªå«ãYYYYå¹´Mæãï¼ä¸é¡µé¢æªéæ©æ¥è¡¨æ"); |
| | | } |
| | | |
| | | List<String> missing = new ArrayList<>(); |
| | | double citySum = 0.0; |
| | | for (String city : RegionUtil.cityList()) { |
| | | Double v = orders.get(city); |
| | | if (v == null) missing.add(city); |
| | | else citySum += v; |
| | | } |
| | | double sum = sumHolder[0] > 0 ? sumHolder[0] : citySum; |
| | | |
| | | WycOrderMonthly it = wycOrderMapper.selectOne(new LambdaQueryWrapper<WycOrderMonthly>() |
| | | .eq(WycOrderMonthly::getReportPeriod, rp).last("LIMIT 1")); |
| | | if (it == null) it = new WycOrderMonthly(); |
| | | it.setReportPeriod(rp); |
| | | it.setOrderSum(sum > 0 ? sum : null); |
| | | it.setOrderWuhan(orderOf(orders, "æ¦æ±å¸")); |
| | | it.setOrderHuangshi(orderOf(orders, "é»ç³å¸")); |
| | | it.setOrderShiyan(orderOf(orders, "åå °å¸")); |
| | | it.setOrderYichang(orderOf(orders, "宿å¸")); |
| | | it.setOrderXiangyang(orderOf(orders, "è¥é³å¸")); |
| | | it.setOrderEzhou(orderOf(orders, "éå·å¸")); |
| | | it.setOrderJingmen(orderOf(orders, "èé¨å¸")); |
| | | it.setOrderXiaogan(orderOf(orders, "åæå¸")); |
| | | it.setOrderJingzhou(orderOf(orders, "èå·å¸")); |
| | | it.setOrderHuanggang(orderOf(orders, "é»åå¸")); |
| | | it.setOrderXianning(orderOf(orders, "å¸å®å¸")); |
| | | it.setOrderSuizhou(orderOf(orders, "éå·å¸")); |
| | | it.setOrderEnshi(orderOf(orders, "æ©æ½å·")); |
| | | it.setOrderXiantao(orderOf(orders, "仿¡å¸")); |
| | | it.setOrderQianjiang(orderOf(orders, "æ½æ±å¸")); |
| | | it.setOrderTianmen(orderOf(orders, "天é¨å¸")); |
| | | it.setOrderShennong(orderOf(orders, "ç¥åæ¶æåº")); |
| | | |
| | | if (it.getPinK() == null || it.getPinCK() == null || it.getPinZ() == null || it.getPinCZ() == null) { |
| | | WycTotalMonthly tot = wycTotalMapper.selectOne(new LambdaQueryWrapper<WycTotalMonthly>() |
| | | .eq(WycTotalMonthly::getReportPeriod, rp).last("LIMIT 1")); |
| | | if (tot != null) { |
| | | if (it.getPinK() == null) it.setPinK(tot.getPinK()); |
| | | if (it.getPinCK() == null) it.setPinCK(tot.getPinCK()); |
| | | if (it.getPinZ() == null) it.setPinZ(tot.getPinZ()); |
| | | if (it.getPinCZ() == null) it.setPinCZ(tot.getPinCZ()); |
| | | } |
| | | } |
| | | |
| | | wycOrderMapper.delete(new LambdaQueryWrapper<WycOrderMonthly>().eq(WycOrderMonthly::getReportPeriod, rp)); |
| | | wycOrderMapper.insert(it); |
| | | recordBatch(file.getOriginalFilename(), "WYC_ORDER_REPORT", rp, 1, 1, 0, null); |
| | | log.info("WycOrderReport imported: period={} sum={} cities={} missing={}", rp, sum, orders.size(), missing); |
| | | return new WycOrderReportResult(rp, sum, orders.size(), missing); |
| | | } |
| | | |
| | | /** æ¥åæ é¢ä¸çæ¥è¡¨æï¼ç½çº¦è½¦è¡ä¸2026å¹´7æ -> 2026-07ï¼åä¸å°è¿å null */ |
| | | private String periodOfDocx(XWPFDocument doc) { |
| | | 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(); |
| | | if (text == null) continue; |
| | | String flat = text.replaceAll("\\s+", ""); |
| | | if (flat.isEmpty()) continue; |
| | | java.util.regex.Matcher m = titlePat.matcher(flat); |
| | | if (m.find()) return ymd(m.group(1), m.group(2)); |
| | | if (fallback == null && scanned < 10) { |
| | | java.util.regex.Matcher m2 = anyPat.matcher(flat); |
| | | if (m2.find()) fallback = ymd(m2.group(1), m2.group(2)); |
| | | } |
| | | scanned++; |
| | | } |
| | | return fallback; |
| | | } |
| | | |
| | | private String ymd(String y, String mo) { |
| | | try { |
| | | int month = Integer.parseInt(mo); |
| | | if (month < 1 || month > 12) return null; |
| | | return String.format("%04d-%02d", Integer.parseInt(y), month); |
| | | } catch (NumberFormatException e) { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | /** è§£ææ¥åä¸çãå°å¸åç§° | ⦠| è®¢åæ°æ»æ°ã表ï¼orders=å¸å·è®¢åï¼sumHolder[0]=å计è¡è®¢åæ° */ |
| | | private void parseWycOrderReportTables(XWPFDocument doc, Map<String, Double> orders, double[] sumHolder) { |
| | | for (XWPFTable table : doc.getTables()) { |
| | | List<XWPFTableRow> rows = table.getRows(); |
| | | 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(); |
| | | for (int c = 0; c < cells.size(); c++) { |
| | | String norm = flat(cells.get(c).getText()); |
| | | if (norm.contains("è®¢åæ°æ»æ°") || "è®¢åæ°".equals(norm)) { |
| | | headerRow = r; |
| | | orderCol = c; |
| | | break; |
| | | } |
| | | } |
| | | if (headerRow >= 0) break; |
| | | } |
| | | if (headerRow < 0 || orderCol < 0) continue; |
| | | |
| | | Map<String, Double> found = new LinkedHashMap<>(); |
| | | 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()); |
| | | if (name.isEmpty()) continue; |
| | | Double val = parsePlainNumber(cells.get(orderCol).getText()); |
| | | if (val == null) continue; |
| | | String city = RegionUtil.normalizeCityName(name); |
| | | if (city != null && RegionUtil.cityList().contains(city)) { |
| | | found.put(city, val); |
| | | citySum += val; |
| | | } else if (name.contains("å计") || name.contains("æ»è®¡") || name.contains("å
¨ç") || name.contains("æ¹å")) { |
| | | hasTotal = true; |
| | | sumHolder[0] = val; |
| | | } |
| | | } |
| | | if (!found.isEmpty()) { |
| | | orders.clear(); |
| | | orders.putAll(found); |
| | | if (!hasTotal) sumHolder[0] = citySum; |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | |
| | | private String flat(String s) { |
| | | return s == null ? "" : s.replaceAll("\\s+", "").trim(); |
| | | } |
| | | |
| | | /** ã11,183,267 åãè¿ç±»ææ¬åæ°å¼ */ |
| | | private Double parsePlainNumber(String s) { |
| | | if (s == null) return null; |
| | | String t = s.replaceAll("[,\\s]", "").trim(); |
| | | if (t.isEmpty()) return null; |
| | | java.util.regex.Matcher m = java.util.regex.Pattern.compile("-?\\d+(?:\\.\\d+)?").matcher(t); |
| | | if (!m.find()) return null; |
| | | try { |
| | | return Double.parseDouble(m.group()); |
| | | } catch (NumberFormatException e) { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | private Double orderOf(Map<String, Double> orders, String city) { |
| | | Double v = orders.get(city); |
| | | return (v == null || v <= 0) ? null : v; |
| | | } |
| | | private String periodOfCell(Cell c) { |
| | | if (c == null) return null; |
| | | if (c.getCellType() == CellType.NUMERIC) { |
| | |
| | | case "scaleSplit": return new ImportResult(importScaleSplit(file, period), 0, new ArrayList<>()); |
| | | case "wycTotal": return new ImportResult(importWycTotal(file, period), 0, new ArrayList<>()); |
| | | case "wycOrder": return new ImportResult(importWycOrder(file, period), 0, new ArrayList<>()); |
| | | case "wycOrderReport": return new ImportResult(importWycOrderReport(file, period).getCityCount(), 0, new ArrayList<>()); |
| | | default: throw new RuntimeException("䏿¯æç导å
¥ç±»åï¼" + type); |
| | | } |
| | | } |
| | |
| | | package com.trafficaudit.reportexport.calc; |
| | | |
| | | import com.trafficaudit.common.util.RegionUtil; |
| | | import com.trafficaudit.reportexport.calc.FreightCalc.FreightMatrix; |
| | | import com.trafficaudit.reportexport.calc.FreightCalc.FreightMetrics; |
| | | import org.apache.poi.ss.usermodel.Cell; |
| | | import org.apache.poi.ss.usermodel.Row; |
| | | import org.apache.poi.ss.usermodel.Sheet; |
| | |
| | | private MidCalc midCalc; |
| | | @Resource |
| | | private PaxCalc paxCalc; |
| | | @Resource |
| | | private FreightCalc freightCalc; |
| | | @Resource |
| | | private WycSplitCalc wycSplitCalc; |
| | | |
| | | /** 2026 å¹´ 1 æå½æå¼åï¼0 åºï¼å³ C åï¼ */ |
| | | private static final int FIRST_MONTH_COL = 2; |
| | | |
| | | /** åå¡« 1..keepMonths æå°è´¦é¡µï¼è¿ååå
¥æ ¼æ°ï¼ç¼ºæ°æç¤ºåå
¥ problems */ |
| | | public int fillMonthlyLedger(XSSFWorkbook wb, int year, int keepMonths, List<String> problems) { |
| | | public int fillMonthlyLedger(XSSFWorkbook wb, String period, int year, int keepMonths, List<String> problems) { |
| | | if (wb == null || keepMonths <= 0) return 0; |
| | | if (problems == null) problems = new ArrayList<>(); |
| | | String yearPrefix = year + "-"; |
| | |
| | | filled += fillCityRows(wb, "å
¬äº¤", paxCalc.busMonthly(yearPrefix, keepMonths), year, keepMonths, problems, false); |
| | | filled += fillCityRows(wb, "åºç§", paxCalc.taxiMonthly(yearPrefix, keepMonths), year, keepMonths, problems, false); |
| | | filled += fillTrackFerry(wb, paxCalc.railFerryMonthly(yearPrefix, keepMonths), year, keepMonths, problems); |
| | | filled += fillFreightSheet(wb, period, keepMonths, problems); |
| | | filled += fillWycSheet(wb, period, keepMonths, problems); |
| | | return filled; |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | return filled; |
| | | } |
| | | |
| | | /** è´§è¿é¡µåå¡«ï¼å
¨çå + 17 å¸å·åç è§ä¸/è§ä¸/å计 à 货è¿éãå¨è½¬éï¼éæç°ç®ï¼å½æå¼å=2+2*(m-1)ï¼ */ |
| | | private int fillFreightSheet(XSSFWorkbook wb, String period, int keepMonths, List<String> problems) { |
| | | Sheet sh = wb.getSheet(" è´§è¿"); |
| | | if (sh == null) sh = wb.getSheet("è´§è¿"); |
| | | if (sh == null) { |
| | | problems.add("è´§è¿é¡µä¸åå¨ï¼æ¯ç缺失该页ï¼ï¼è·³è¿èªå¨åå¡«"); |
| | | return 0; |
| | | } |
| | | int cap = monthColumnCapacity(sh); |
| | | int mMax = Math.min(keepMonths, cap); |
| | | if (mMax <= 0) { |
| | | problems.add("è´§è¿é¡µæªè¯å«å° 2026 年累计åï¼è·³è¿èªå¨åå¡«"); |
| | | return 0; |
| | | } |
| | | int year = periodYear(period); |
| | | // åï¼å
¨ç/å¸å·ï¼ï¼ææ é® -> è¡å· |
| | | Map<String, Map<String, Integer>> blockRows = new LinkedHashMap<>(); |
| | | String cur = null; |
| | | for (int r = sh.getFirstRowNum(); r <= sh.getLastRowNum(); r++) { |
| | | Row row = sh.getRow(r); |
| | | if (row == null) continue; |
| | | String a = text(row.getCell(0)); |
| | | if (a != null && !a.trim().isEmpty()) { |
| | | String norm = RegionUtil.normalizeCityName(a.trim()); |
| | | if (FreightCalc.PROVINCE.equals(norm) || RegionUtil.cityList().contains(norm)) { |
| | | cur = norm; |
| | | blockRows.computeIfAbsent(cur, k -> new LinkedHashMap<>()); |
| | | } else { |
| | | cur = null; // æ é¢è¡ / éå
¨çéå¸å· -> è±ç¦»å |
| | | } |
| | | } |
| | | if (cur == null) continue; |
| | | String key = freightMetricKey(text(row.getCell(1))); |
| | | if (key == null) continue; |
| | | blockRows.get(cur).putIfAbsent(key, r); |
| | | } |
| | | if (blockRows.isEmpty()) { |
| | | problems.add("è´§è¿é¡µæªè¯å«å°å
¨ç/å¸å·è¡ï¼è·³è¿èªå¨åå¡«"); |
| | | return 0; |
| | | } |
| | | int filled = 0; |
| | | // åªåå¡«ç®æ æå½æï¼1..ç®æ æ-1 çå¼ä»¥æ¯çï¼å«åæå¤ä»½æ¯çè¿åï¼ä¸ºåï¼é¿å
æ¹å已确认å£å¾ |
| | | int targetM = Math.min(periodMonth(period), mMax); |
| | | for (int m = targetM; m <= targetM; m++) { |
| | | String mp = String.format("%04d-%02d", year, m); |
| | | FreightMatrix mx; |
| | | try { |
| | | mx = freightCalc.calc(mp); |
| | | } catch (Exception e) { |
| | | problems.add("è´§è¿é¡µ " + mp + " åæ°å¤±è´¥ï¼" + e.getMessage()); |
| | | continue; |
| | | } |
| | | int col = FIRST_MONTH_COL + 2 * (m - 1); |
| | | for (Map.Entry<String, Map<String, Integer>> e : blockRows.entrySet()) { |
| | | FreightMetrics fm = mx.getMonth().get(e.getKey()); |
| | | if (fm == null) continue; |
| | | Map<String, Integer> rows = e.getValue(); |
| | | // 1 æåæ¯å
¬å¼çâæ´¾çè¡âï¼å
¨çå计 è´§è¿é/å¨è½¬éãå¸å· è§ä¸+è§ä¸å¨è½¬éï¼ä¸åå¼ï¼ |
| | | // ç± ensureMonthFormulas æå
¬å¼ææå³ç§»ï¼ä¿æä¸æ¯çä¸è´ |
| | | filled += setFreightCell(sh, skipIfDerived(sh, rows.get("totalFreight")), col, fm.getTotalFreight()); |
| | | filled += setFreightCell(sh, skipIfDerived(sh, rows.get("aboveFreight")), col, fm.getAboveFreight()); |
| | | filled += setFreightCell(sh, skipIfDerived(sh, rows.get("belowFreight")), col, fm.getBelowFreight()); |
| | | filled += setFreightCell(sh, skipIfDerived(sh, rows.get("totalTurnover")), col, fm.getTotalTurnover()); |
| | | filled += setFreightCell(sh, skipIfDerived(sh, rows.get("aboveTurnover")), col, fm.getAboveTurnover()); |
| | | filled += setFreightCell(sh, skipIfDerived(sh, rows.get("belowTurnover")), col, fm.getBelowTurnover()); |
| | | } |
| | | } |
| | | return filled; |
| | | } |
| | | |
| | | /** è¯¥è¡ 1 æåï¼Cï¼æ¯å
¬å¼ -> æ´¾çè¡ï¼è¿å null 表示ä¸åå¡«æ°å¼ */ |
| | | private Integer skipIfDerived(Sheet sh, Integer r) { |
| | | if (r == null) return null; |
| | | Row row = sh.getRow(r); |
| | | if (row == null) return r; |
| | | Cell c = row.getCell(FIRST_MONTH_COL); |
| | | if (c != null && c.getCellType() == org.apache.poi.ss.usermodel.CellType.FORMULA) return null; |
| | | return r; |
| | | } |
| | | |
| | | private int setFreightCell(Sheet sh, Integer r, int col, Double v) { |
| | | if (r == null || v == null) return 0; |
| | | return setNumeric(sh, r, col, v); |
| | | } |
| | | |
| | | /** è´§è¿é¡µ B åææ ææ¡ -> ææ é®ï¼è§ä¸+è§ä¸ / è§ä¸ / è§ä¸ à 货è¿é / å¨è½¬éï¼ */ |
| | | private String freightMetricKey(String b) { |
| | | if (b == null) return null; |
| | | String s = b.replaceAll("\\s+", ""); |
| | | if (s.isEmpty()) return null; |
| | | boolean turnover = s.contains("å¨è½¬é"); |
| | | if (s.contains("è§ä¸+è§ä¸")) return turnover ? "totalTurnover" : "totalFreight"; |
| | | if (s.contains("è§ä¸")) return turnover ? "aboveTurnover" : "aboveFreight"; |
| | | if (s.contains("è§ä¸")) return turnover ? "belowTurnover" : "belowFreight"; |
| | | return turnover ? "totalTurnover" : "totalFreight"; // å
¨çåçâè´§è¿é/è´§ç©å¨è½¬éâ= å计 |
| | | } |
| | | |
| | | /** ç½çº¦è½¦é¡µåå¡«ï¼17 å¸å· ç 客è¿é/å¨è½¬é/å
¶ä¸åå¸å
客è¿é/å
¶ä¸åå¸å
å¨è½¬éï¼éæç°ç®ï¼ |
| | | * å
¨çè¡ï¼=17 å¸å·æ±åå
¬å¼ï¼ç± ensureMonthFormulas æææ©åï¼ä¸å¨æ¤å¤åå¼ã */ |
| | | private int fillWycSheet(XSSFWorkbook wb, String period, int keepMonths, List<String> problems) { |
| | | Sheet sh = wb.getSheet("ç½çº¦è½¦"); |
| | | if (sh == null) { |
| | | problems.add("ç½çº¦è½¦é¡µä¸åå¨ï¼æ¯ç缺失该页ï¼ï¼è·³è¿èªå¨åå¡«"); |
| | | return 0; |
| | | } |
| | | int cap = monthColumnCapacity(sh); |
| | | int mMax = Math.min(keepMonths, cap); |
| | | if (mMax <= 0) { |
| | | problems.add("ç½çº¦è½¦é¡µæªè¯å«å° 2026 年累计åï¼è·³è¿èªå¨åå¡«"); |
| | | return 0; |
| | | } |
| | | int year = periodYear(period); |
| | | Map<String, Map<String, Integer>> cityMetricRows = new LinkedHashMap<>(); |
| | | String cur = null; |
| | | for (int r = sh.getFirstRowNum(); r <= sh.getLastRowNum(); r++) { |
| | | Row row = sh.getRow(r); |
| | | if (row == null) continue; |
| | | String a = text(row.getCell(0)); |
| | | if (a != null && !a.trim().isEmpty()) { |
| | | String norm = RegionUtil.normalizeCityName(a.trim()); |
| | | cur = RegionUtil.cityList().contains(norm) ? norm : null; |
| | | if (cur != null) cityMetricRows.computeIfAbsent(cur, k -> new LinkedHashMap<>()); |
| | | } |
| | | if (cur == null) continue; |
| | | String key = wycMetricKey(text(row.getCell(1))); |
| | | if (key == null) continue; |
| | | cityMetricRows.get(cur).putIfAbsent(key, r); |
| | | } |
| | | if (cityMetricRows.isEmpty()) { |
| | | problems.add("ç½çº¦è½¦é¡µæªè¯å«å°å¸å·è¡ï¼è·³è¿èªå¨åå¡«"); |
| | | return 0; |
| | | } |
| | | int filled = 0; |
| | | // åªåå¡«ç®æ æå½æï¼å岿以æ¯ç/åå²çæä»¶ä¸ºåï¼ |
| | | int targetM = Math.min(periodMonth(period), mMax); |
| | | for (int m = targetM; m <= targetM; m++) { |
| | | String mp = String.format("%04d-%02d", year, m); |
| | | WycSplitCalc.WycResult wr; |
| | | try { |
| | | wr = wycSplitCalc.calc(mp); |
| | | } catch (Exception e) { |
| | | if (m == mMax) { |
| | | problems.add("ç½çº¦è½¦é¡µ " + mp + " æºæ°æ®ç¼ºå¤±ï¼å½ææªåå¡«ï¼" + e.getMessage()); |
| | | } |
| | | continue; |
| | | } |
| | | int col = FIRST_MONTH_COL + 2 * (m - 1); |
| | | for (Map.Entry<String, Map<String, Integer>> e : cityMetricRows.entrySet()) { |
| | | WycSplitCalc.WycMetrics wm = wr.getByCity().get(e.getKey()); |
| | | if (wm == null) continue; |
| | | Map<String, Integer> rows = e.getValue(); |
| | | filled += setFreightCell(sh, rows.get("pax"), col, wm.getTotalPax()); |
| | | filled += setFreightCell(sh, rows.get("turnover"), col, wm.getTotalTurnover()); |
| | | filled += setFreightCell(sh, rows.get("cityPax"), col, wm.getCityPax()); |
| | | filled += setFreightCell(sh, rows.get("cityTurnover"), col, wm.getCityTurnover()); |
| | | } |
| | | } |
| | | return filled; |
| | | } |
| | | |
| | | /** ç½çº¦è½¦é¡µ B åææ ææ¡ -> ææ é® */ |
| | | private String wycMetricKey(String b) { |
| | | if (b == null) return null; |
| | | String s = b.replaceAll("\\s+", ""); |
| | | if (s.isEmpty()) return null; |
| | | boolean city = s.contains("åå¸å
"); |
| | | boolean turnover = s.contains("å¨è½¬é"); |
| | | if (city) return turnover ? "cityTurnover" : "cityPax"; |
| | | return turnover ? "turnover" : "pax"; |
| | | } |
| | | |
| | | /** 轨é轮渡页ï¼è½¨é=æ¦æ±/é»ç³ï¼è½®æ¸¡ä»
æ¦æ±ï¼ä¸ç¨åå¡« */ |
| | |
| | | return -1; |
| | | } |
| | | |
| | | /** åæ°å¼ï¼æ ¼ä¸åå¨åå»ºæ ¼å¹¶å¤å¶åè¡ 1 æåæ ·å¼ï¼è¿å 1 */ |
| | | /** åæ°å¼ï¼æ ¼ä¸åå¨åå»ºæ ¼ï¼æ ¼å¸¦æ¥ææ ·å¼ï¼å¦å
¬äº¤/åºç§ 8 æåç»§æ¿äºè¡¨å¤´âyyyyå¹´mæâï¼æ¶æ¹ååè¡ 1 æåçæ°å¼æ ·å¼ï¼é¿å
æ°å¼æ¾ç¤ºææ¥æ */ |
| | | private int setNumeric(Sheet sh, int r, int col, double val) { |
| | | Row row = sh.getRow(r); |
| | | if (row == null) row = sh.createRow(r); |
| | | Cell c = row.getCell(col); |
| | | if (c != null && c.getCellType() == org.apache.poi.ss.usermodel.CellType.FORMULA) { |
| | | return 0; // æ¯çæ¬æ¥å°±é å
¬å¼ç®çè¡ï¼å计/å页æ±åï¼ä¿æå
¬å¼ï¼äº¤ Excel éç® |
| | | } |
| | | Cell ref = row.getCell(FIRST_MONTH_COL); |
| | | boolean needStyle = false; |
| | | if (c == null) { |
| | | c = row.createCell(col); |
| | | Cell ref = row.getCell(FIRST_MONTH_COL); |
| | | if (ref != null && ref.getCellStyle() != null) c.setCellStyle(ref.getCellStyle()); |
| | | needStyle = true; |
| | | } else if (c.getCellType() == org.apache.poi.ss.usermodel.CellType.BLANK |
| | | || (c.getCellType() == org.apache.poi.ss.usermodel.CellType.NUMERIC |
| | | && org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(c))) { |
| | | // æ¯çæ 8 æåçè¡¨å¤´æ¥ææ ¼å¼å¸¦å°äºæ°æ®æ ¼ï¼æææ ¼å¼æ å¼ï¼ï¼åå¼åæ¹ååè¡ 1 æåçæ°åæ ¼å¼ |
| | | needStyle = true; |
| | | } |
| | | if (needStyle && ref != null && ref.getCellStyle() != null) { |
| | | c.setCellStyle(ref.getCellStyle()); |
| | | } |
| | | c.setCellValue(val); |
| | | return 1; |
| | |
| | | return row == null ? null : cityOf(row.getCell(0)); |
| | | } |
| | | |
| | | /** æä»½å®¹éï¼å¨è¡¨å¤´ï¼å 5 è¡ï¼æ¾â2026â¦ç´¯è®¡âåï¼å®¹é=(累计å-1 æå)/2 */ |
| | | /** |
| | | * 为第 month æè¡¥â彿å¼âåå
¬å¼ï¼ååä¸è¡æè¿ä¸ä¸ªæä»ä¸ºå
¬å¼çå¼åï¼æ´åå³ç§»è¿æ¥ |
| | | * ï¼å¦å
¬äº¤ 7 æå O ç =O9+O13+... -> 8 æå Q ç =Q9+Q13+...ï¼ã |
| | | * åªè¡¥ç©ºåå
æ ¼ï¼å·²ææ°å¼ï¼è´§è¿å
¨çå/å¸å·åç±æ°æ®åå¡«ï¼æå·²æå
¬å¼çæ ¼ä¸å¨ã |
| | | */ |
| | | public int ensureMonthFormulas(XSSFWorkbook wb, int year, int month) { |
| | | if (wb == null || month <= 1) return 0; |
| | | int targetCol = FIRST_MONTH_COL + 2 * (month - 1); |
| | | int written = 0; |
| | | for (int i = 0; i < wb.getNumberOfSheets(); i++) { |
| | | Sheet sh = wb.getSheetAt(i); |
| | | if (sh == null || !isFilledLedgerSheet(sh.getSheetName())) continue; |
| | | for (int r = sh.getFirstRowNum(); r <= sh.getLastRowNum(); r++) { |
| | | Row row = sh.getRow(r); |
| | | if (row == null) continue; |
| | | if (hasContent(row.getCell(targetCol))) continue; |
| | | Cell srcCell = null; |
| | | int srcMonth = -1; |
| | | for (int s = month - 1; s >= 1; s--) { |
| | | Cell c = row.getCell(FIRST_MONTH_COL + 2 * (s - 1)); |
| | | if (c != null && c.getCellType() == org.apache.poi.ss.usermodel.CellType.FORMULA) { |
| | | srcCell = c; |
| | | srcMonth = s; |
| | | break; |
| | | } |
| | | } |
| | | if (srcCell == null) continue; |
| | | String f = srcCell.getCellFormula(); |
| | | if (f == null || f.isEmpty()) continue; |
| | | Cell target = row.getCell(targetCol); |
| | | if (target == null) target = row.createCell(targetCol); |
| | | if (srcCell.getCellStyle() != null) target.setCellStyle(srcCell.getCellStyle()); |
| | | target.setCellFormula(shiftFormulaColumns(f, 2 * (month - srcMonth))); |
| | | written++; |
| | | } |
| | | } |
| | | return written; |
| | | } |
| | | |
| | | /** è¯¥æ ¼æ¯å¦å·²æå
å®¹ï¼æ°å¼/ææ¬/å
¬å¼ï¼ï¼ä»
å¸¦æ ·å¼ç空壳ï¼å¦æ¯çéç»§æ¿è¡¨å¤´æ¥ææ ¼å¼çæ ¼åï¼è§ä¸ºç©º */ |
| | | private boolean hasContent(Cell c) { |
| | | if (c == null) return false; |
| | | switch (c.getCellType()) { |
| | | case BLANK: return false; |
| | | case STRING: return c.getStringCellValue() != null && !c.getStringCellValue().trim().isEmpty(); |
| | | default: return true; |
| | | } |
| | | } |
| | | |
| | | /** åä¸éææ°æ®åå¡«çå°è´¦é¡µï¼è´§è¿/ç线å
车/å
¬äº¤/åºç§/ç½çº¦è½¦/轨éè½®æ¸¡ï¼ */ |
| | | private boolean isFilledLedgerSheet(String name) { |
| | | if (name == null) return false; |
| | | String n = name.trim(); |
| | | return "è´§è¿".equals(n) || "ç线å
车".equals(n) || "å
¬äº¤".equals(n) |
| | | || "åºç§".equals(n) || "ç½çº¦è½¦".equals(n) || "轨éã轮渡".equals(n); |
| | | } |
| | | |
| | | /** 0 åºåå· + 1 åºè¡å· -> "Q5" */ |
| | | private String cellRef(int col0, int row1) { |
| | | StringBuilder sb = new StringBuilder(); |
| | | int n = col0 + 1; |
| | | while (n > 0) { |
| | | int rem = (n - 1) % 26; |
| | | sb.insert(0, (char) ('A' + rem)); |
| | | n = (n - 1) / 26; |
| | | } |
| | | return sb.toString() + row1; |
| | | } |
| | | |
| | | /** ä» "2026-08" åæä»½ï¼è§£æå¤±è´¥è¿å 1ï¼ */ |
| | | private int periodMonth(String period) { |
| | | if (period != null && period.length() >= 7) { |
| | | try { return Integer.parseInt(period.substring(5, 7)); } catch (Exception ignore) { } |
| | | } |
| | | return 1; |
| | | } |
| | | |
| | | /** ä» "2026-08" å年份 */ |
| | | private int periodYear(String period) { |
| | | if (period != null && period.length() >= 4) { |
| | | try { return Integer.parseInt(period.substring(0, 4)); } catch (Exception ignore) { } |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | /** |
| | | * 为第 m æè¡¥âä¸å»å¹´åæ¯âå
¬å¼ï¼æç¬¬ m-1 æåæ¯åçå
¬å¼æ´ä½å³ç§» 2 å |
| | | * ï¼å¦å
¬äº¤ 7 æ P5 å
¬å¼ =O5/AH5-1 -> 8 æ R5 =Q5/AJ5-1ï¼ï¼ |
| | | * å æ¤åæ¯åæ¯åçå°±æ¯æ±æ»è¡¨ 2025 å¹´åæåï¼ç¨æ·å£å¾ï¼ã |
| | | */ |
| | | public int ensureMonthYoyFormulas(XSSFWorkbook wb, int year, int month) { |
| | | if (wb == null || month <= 1) return 0; |
| | | int valueCol = FIRST_MONTH_COL + 2 * (month - 1); |
| | | int yoyCol = valueCol + 1; |
| | | int prevYoyCol = yoyCol - 2; |
| | | int written = 0; |
| | | for (int i = 0; i < wb.getNumberOfSheets(); i++) { |
| | | Sheet sh = wb.getSheetAt(i); |
| | | if (sh == null) continue; |
| | | if (!isMonthLedgerSheet(sh.getSheetName())) continue; |
| | | for (int r = sh.getFirstRowNum(); r <= sh.getLastRowNum(); r++) { |
| | | Row row = sh.getRow(r); |
| | | if (row == null) continue; |
| | | Cell prev = row.getCell(prevYoyCol); |
| | | if (prev == null || prev.getCellType() != org.apache.poi.ss.usermodel.CellType.FORMULA) continue; |
| | | Cell target = row.getCell(yoyCol); |
| | | if (target != null && target.getCellType() == org.apache.poi.ss.usermodel.CellType.FORMULA) continue; |
| | | String f = prev.getCellFormula(); |
| | | if (f == null || f.isEmpty()) continue; |
| | | String shifted = shiftFormulaColumns(f, 2); |
| | | if (target == null) target = row.createCell(yoyCol); |
| | | // æ¯çææ°æä»½ç忝ååæäºæ®éæ°å¼æ ¼å¼ï¼æ¾ç¤ºæå°æ°ï¼ï¼ç»ä¸æ²¿ç¨ä¸æåæ¯åçæ ·å¼ï¼ç¾åæ°ï¼ |
| | | if (prev.getCellStyle() != null) target.setCellStyle(prev.getCellStyle()); |
| | | try { |
| | | target.setCellFormula(shifted); |
| | | written++; |
| | | } catch (Exception e) { |
| | | throw new IllegalStateException(String.format( |
| | | "忝å
¬å¼è¡¥å失败ï¼sheet=%s cell=%s åå¼=%s ç®æ å¼=%s", |
| | | sh.getSheetName(), cellRef(yoyCol, r + 1), f, shifted), e); |
| | | } |
| | | } |
| | | } |
| | | return written; |
| | | } |
| | | |
| | | /** éææ©åçé¿è¡¨é¡µï¼è¡¨å¤´å¨ 1..3 è¡ãæä»½ç»ä¸ºâ彿å¼+忝â交æ¿ï¼ */ |
| | | private boolean isMonthLedgerSheet(String name) { |
| | | if (name == null) return false; |
| | | String n = name.trim(); |
| | | return "è´§è¿".equals(n) || "å
¬è·¯æ»å®¢è¿".equals(n) || "ç线å
车".equals(n) || "åå¸å®¢è¿".equals(n) |
| | | || "å
¬äº¤".equals(n) || "åºç§".equals(n) || "ç½çº¦è½¦".equals(n) |
| | | || "轨éã轮渡".equals(n) || "轨é轮渡".equals(n) |
| | | || "ä¸å£å¾æç»".equals(n) || "ä¸å£å¾å®¢è¿é".equals(n); |
| | | } |
| | | |
| | | /** å
¬å¼å
ææ A1 å½¢å¼çåå¼ç¨å³ç§» delta åï¼SUM ç彿°ååæ æ°åï¼ä¸ä¼è¢«å¹é
ï¼ */ |
| | | private String shiftFormulaColumns(String formula, int delta) { |
| | | 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 = idx + delta; |
| | | StringBuilder nc = new StringBuilder(); |
| | | while (nidx > 0) { |
| | | int rem = (nidx - 1) % 26; |
| | | nc.insert(0, (char) ('A' + rem)); |
| | | nidx = (nidx - 1) / 26; |
| | | } |
| | | m.appendReplacement(sb, java.util.regex.Matcher.quoteReplacement(m.group(1) + nc + m.group(3) + m.group(4))); |
| | | } |
| | | m.appendTail(sb); |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** æä»½å®¹éï¼ä¼å
å表头ï¼å 5 è¡ï¼â2026â¦ç´¯è®¡âå忍ï¼è´§è¿é¡µæ è¯¥ææ¡ï¼ |
| | | * åç¨è¡¨å¤´éæåä¸ä¸ªâ2026å¹´Mæâ/æ¥ææ ¼å¼çæåå
åºï¼å¦è´§è¿ Q3=2026-08-01 -> 8ï¼ */ |
| | | private int monthColumnCapacity(Sheet sh) { |
| | | int byCumulative = 0; |
| | | int byMonthHeader = 0; |
| | | for (int r = 0; r <= 4 && r <= sh.getLastRowNum(); r++) { |
| | | Row row = sh.getRow(r); |
| | | if (row == null) continue; |
| | | for (Cell c : row) { |
| | | if (c == null) continue; |
| | | int idx = c.getColumnIndex(); |
| | | if (idx <= FIRST_MONTH_COL || (idx - FIRST_MONTH_COL) % 2 != 0) continue; // åªçâ彿å¼âå |
| | | String t = text(c); |
| | | if (t != null && t.contains("2026") && t.contains("累计") && c.getColumnIndex() > FIRST_MONTH_COL) { |
| | | return (c.getColumnIndex() - FIRST_MONTH_COL) / 2; |
| | | if (byCumulative == 0 && t != null && t.contains("2026") && t.contains("累计")) { |
| | | byCumulative = (idx - FIRST_MONTH_COL) / 2; |
| | | } |
| | | if (t != null && t.contains("2026") && t.contains("æ") && !t.contains("累计") |
| | | && !t.contains("忝")) { |
| | | byMonthHeader = Math.max(byMonthHeader, (idx - FIRST_MONTH_COL) / 2 + 1); |
| | | } else if (c.getCellType() == org.apache.poi.ss.usermodel.CellType.NUMERIC |
| | | && org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(c)) { |
| | | byMonthHeader = Math.max(byMonthHeader, (idx - FIRST_MONTH_COL) / 2 + 1); |
| | | } |
| | | } |
| | | } |
| | | return 7; |
| | | int cap = Math.max(byCumulative, byMonthHeader); |
| | | return cap > 0 ? cap : 7; |
| | | } |
| | | |
| | | private String text(Cell c) { |
| | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.trafficaudit.common.util.RegionUtil; |
| | | import com.trafficaudit.dataimport.entity.CityTaxiMonthly; |
| | | import com.trafficaudit.dataimport.entity.WycOrderMonthly; |
| | | import com.trafficaudit.dataimport.mapper.CityTaxiMonthlyMapper; |
| | | import com.trafficaudit.dataimport.mapper.WycOrderMonthlyMapper; |
| | | import org.apache.poi.ss.usermodel.Cell; |
| | | import org.apache.poi.ss.usermodel.CellType; |
| | | import org.apache.poi.ss.usermodel.DataFormatter; |
| | |
| | | |
| | | @Resource |
| | | private CityTaxiMonthlyMapper cityTaxiMapper; |
| | | @Resource |
| | | private WycOrderMonthlyMapper wycOrderMapper; |
| | | @Value("${city-passenger.template-dir:docs/åå¸å®¢è¿}") |
| | | private String templateDir; |
| | | |
| | |
| | | |
| | | /** 读å docs/åå¸å®¢è¿/ãç½çº¦è½¦è®¢ååå
¨çæ»é.xlsxãï¼æ period(yyyy-MM) è¡å pin(B-E) ä¸ 17 å¸å·è®¢å(G-W) */ |
| | | private Map<String, Object> loadMonthlyInput(String period) throws Exception { |
| | | Map<String, Object> db = loadMonthlyInputFromDb(period); |
| | | if (db != null) return db; |
| | | File f = findInput(); |
| | | try (InputStream in = new FileInputStream(f); |
| | | Workbook wb = WorkbookFactory.create(in)) { |
| | |
| | | } |
| | | } |
| | | |
| | | /** ä¼å
ä»åºåæ°ï¼wyc_order_monthlyï¼ï¼åºéæ 该ææè®¢åå
¨ç©ºæ¶è¿å nullï¼åé读æ¯çæä»¶ */ |
| | | private Map<String, Object> loadMonthlyInputFromDb(String period) { |
| | | WycOrderMonthly row = wycOrderMapper.selectOne(new LambdaQueryWrapper<WycOrderMonthly>() |
| | | .eq(WycOrderMonthly::getReportPeriod, period).last("LIMIT 1")); |
| | | if (row == null) return null; |
| | | List<String> cities = RegionUtil.cityList(); |
| | | Double[] vals = { |
| | | row.getOrderWuhan(), row.getOrderHuangshi(), row.getOrderShiyan(), row.getOrderYichang(), |
| | | row.getOrderXiangyang(), row.getOrderEzhou(), row.getOrderJingmen(), row.getOrderXiaogan(), |
| | | row.getOrderJingzhou(), row.getOrderHuanggang(), row.getOrderXianning(), row.getOrderSuizhou(), |
| | | row.getOrderEnshi(), row.getOrderXiantao(), row.getOrderQianjiang(), row.getOrderTianmen(), |
| | | row.getOrderShennong() |
| | | }; |
| | | double[] orders = new double[cities.size()]; |
| | | double sum = 0.0; |
| | | for (int i = 0; i < orders.length && i < vals.length; i++) { |
| | | orders[i] = vals[i] == null ? 0.0 : vals[i]; |
| | | sum += orders[i]; |
| | | } |
| | | if (sum <= 0) return null; |
| | | double orderSum = sum; |
| | | if (row.getOrderSum() != null && row.getOrderSum() > 0) orderSum = row.getOrderSum(); |
| | | Map<String, Object> map = new LinkedHashMap<>(); |
| | | map.put("pinK", row.getPinK() == null ? 0.0 : row.getPinK()); |
| | | map.put("pinCK", row.getPinCK() == null ? 0.0 : row.getPinCK()); |
| | | map.put("pinZ", row.getPinZ() == null ? 0.0 : row.getPinZ()); |
| | | map.put("pinCZ", row.getPinCZ() == null ? 0.0 : row.getPinCZ()); |
| | | map.put("orders", orders); |
| | | map.put("orderSum", orderSum); |
| | | map.put("source", "db"); |
| | | return map; |
| | | } |
| | | private File findInput() throws Exception { |
| | | String rel = templateDir; |
| | | while (rel.startsWith("./")) rel = rel.substring(2); |
| | |
| | | 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; |
| | |
| | | cleanSummarySheetPresentation(wb); // åæ¶å页çéãè¿åéèè¡ï¼å¦åâç线å
车âç页çèµ·æ¥åç¼ºæ°æ®ï¼ |
| | | int effMonth = (toMonth != null && toMonth > 0 && toMonth < month) ? toMonth : month; |
| | | List<String> dbProblems = new ArrayList<>(); |
| | | int dbFilled = summaryWorkbookFiller.fillMonthlyLedger(wb, year, effMonth, dbProblems); |
| | | log.info("æ±æ»å·¥ä½ç°¿æ°æ®é©±å¨å填宿ï¼åå
¥å°è´¦é¡µå½æå¼æ ¼æ°={}ï¼ç¼ºæ°æç¤º={}", dbFilled, dbProblems); |
| | | String effPeriod = String.format("%04d-%02d", year, effMonth); |
| | | 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, rankRefreshed, widthApplied, dbProblems); |
| | | applyTwoDecimalFormat(wb); // æ°å¼æ¾ç¤ºä¸¤ä½å°æ°ï¼ä¿çå
¨ç²¾åº¦ï¼ï¼% / æ¥æçæ¢ææ ·å¼ä¸æ¹å |
| | | if (!wb.getCTWorkbook().isSetCalcPr()) wb.getCTWorkbook().addNewCalcPr(); |
| | | wb.getCTWorkbook().getCalcPr().setFullCalcOnLoad(true); // è¿å/æ¹åå
¬å¼åæå¼å³éç® |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * çå¼å¯¹é½ï¼æ docs/çææ±æ»å¤§è¡¨/ãçæ_éè·¯è¿è¾éæ±æ»è¡¨.xlsxãï¼ç¨æ·æä¾ççå¼åç
§ï¼éåå¥ç¨å宽ä¸éèæ è®°ï¼ |
| | | * 使çæä»¶ä¸åç
§ä»¶âæ ¼å¼å®å
¨ä¸è´âï¼å¹¶è®©æ¯ç没å®ä¹å®½åº¦çâåç»æ©åâï¼å¦ 8 æåï¼ä¹æä¸ 8 æä¸è´çå宽ã |
| | | * åç
§ä»¶ç¼ºå¤±æ¶éé»è·³è¿ï¼è¿å 0ï¼ï¼ä¸å½±ååæå¯¼åºã |
| | | */ |
| | | private int applySummaryReferenceLayout(XSSFWorkbook wb) { |
| | | File ref; |
| | | try { |
| | | ref = resolveSummaryLayoutRef(); |
| | | } catch (Exception e) { |
| | | return 0; |
| | | } |
| | | if (ref == null) return 0; |
| | | double savedZipRatio = ZipSecureFile.getMinInflateRatio(); |
| | | ZipSecureFile.setMinInflateRatio(0.0001); |
| | | int applied = 0; |
| | | try (InputStream in = new FileInputStream(ref); XSSFWorkbook rwb = new XSSFWorkbook(in)) { |
| | | for (int i = 0; i < rwb.getNumberOfSheets(); i++) { |
| | | org.apache.poi.xssf.usermodel.XSSFSheet rs = rwb.getSheetAt(i); |
| | | if (rs == null) continue; |
| | | org.apache.poi.xssf.usermodel.XSSFSheet ts = wb.getSheet(rs.getSheetName()); |
| | | if (ts == null) continue; |
| | | int maxCol = Math.min(usedColumnCount(rs), usedColumnCount(ts) + 4); |
| | | if (maxCol <= 0) continue; |
| | | double[] width = new double[maxCol]; |
| | | boolean[] hasWidth = new boolean[maxCol]; |
| | | boolean[] hidden = new boolean[maxCol]; |
| | | for (org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols cols : rs.getCTWorksheet().getColsArray()) { |
| | | for (org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol col : cols.getColArray()) { |
| | | long min = col.getMin(); |
| | | long max = col.getMax(); |
| | | for (long c = min; c <= max; c++) { |
| | | int idx = (int) (c - 1); |
| | | if (idx < 0 || idx >= maxCol) { |
| | | if (idx >= maxCol) break; |
| | | continue; |
| | | } |
| | | if (col.isSetWidth()) { |
| | | width[idx] = col.getWidth(); |
| | | hasWidth[idx] = true; |
| | | } |
| | | hidden[idx] = col.isSetHidden() && col.getHidden(); |
| | | } |
| | | } |
| | | } |
| | | for (int c = 0; c < maxCol; c++) { |
| | | if (hasWidth[c]) { |
| | | int w = (int) Math.round(width[c] * 256d); |
| | | if (ts.getColumnWidth(c) != w) { |
| | | ts.setColumnWidth(c, w); |
| | | applied++; |
| | | } |
| | | } |
| | | if (hidden[c] != ts.isColumnHidden(c)) ts.setColumnHidden(c, hidden[c]); |
| | | } |
| | | } |
| | | log.info("æ±æ»å·¥ä½ç°¿çå¼å¯¹é½ãçæ_éè·¯è¿è¾éæ±æ»è¡¨ã宿ï¼å¥ç¨å宽 {} åï¼åç
§ä»¶ï¼{}ï¼", applied, ref.getName()); |
| | | } catch (Exception e) { |
| | | log.warn("æ±æ»å·¥ä½ç°¿çå¼å¯¹é½å¤±è´¥ï¼å¿½ç¥ï¼ç»§ç»ææ¯ççå¼è¾åºï¼ï¼{}", e.getMessage()); |
| | | return 0; |
| | | } finally { |
| | | ZipSecureFile.setMinInflateRatio(savedZipRatio); |
| | | } |
| | | return applied; |
| | | } |
| | | |
| | | /** ä¸é¡µå·²ç¨å°çæå¤§åæ°ï¼0 åºè®¡æ°ï¼ */ |
| | | private int usedColumnCount(org.apache.poi.ss.usermodel.Sheet sh) { |
| | | int max = 0; |
| | | for (int r = sh.getFirstRowNum(); r <= sh.getLastRowNum(); r++) { |
| | | org.apache.poi.ss.usermodel.Row row = sh.getRow(r); |
| | | if (row == null) continue; |
| | | if (row.getLastCellNum() > max) max = row.getLastCellNum(); |
| | | } |
| | | 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; |
| | | while (rel != null && rel.startsWith("./")) rel = rel.substring(2); |
| | | String[] roots = { |
| | | summaryTemplateDir, |
| | | System.getProperty("user.dir") + "/" + rel, |
| | | System.getProperty("user.dir") + "/../" + rel |
| | | }; |
| | | for (String root : roots) { |
| | | if (root == null || root.trim().isEmpty()) continue; |
| | | File f = new File(root, "çæ_éè·¯è¿è¾éæ±æ»è¡¨.xlsx"); |
| | | if (f.isFile()) return f; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** æ±æ»è¡¨æ¯çå®ä½ï¼ä»
精确å¹é
{year}å¹´{month}æâ¦ï¼P0-P1 éª¨æ¶æä¸å
许跨æ/跨年éé»åéï¼ |
| | | * ç®æ ææ å¯¹åºæ¯çæ¶æç¡®æ¥éï¼æä»½æ©å±è§åå¾
P0 æ¯çå®ç¨¿ååæ¾å¼ï¼ */ |
| | | private File resolveSummaryMother(String period, String mode) throws Exception { |
| | |
| | | SKIP/CHECK (0): TYPE_LABELS upper <template> |
| | | <template> |
| | | <el-container direction="vertical"> |
| | | <app-header title="交éç»è®¡æ¥è¡¨å®¡æ ¸ç³»ç» - æ°æ®å¯¼å
¥"></app-header> |
| | | <el-container> |
| | |
| | | <div v-else-if="moduleSel[g.key] && !isDirOnlyType(moduleSel[g.key])" class="module-file"> |
| | | <div class="file-name" :title="fileNamesText(moduleSel[g.key])">{{ fileNamesText(moduleSel[g.key]) || 'æªéæ©æä»¶' }}</div> |
| | | <div class="file-btns"> |
| | | <el-upload action="#" :auto-upload="false" :show-file-list="false" multiple accept=".xlsx,.xls,.et" |
| | | <el-upload action="#" :auto-upload="false" :show-file-list="false" multiple :accept="acceptOf(moduleSel[g.key])" |
| | | :ref="'up' + g.key" :on-change="f => onFilePicked(g.key, f)" style="display:inline-block"> |
| | | <el-button size="mini" type="primary" plain icon="el-icon-folder-opened" :disabled="importing">éæ©æä»¶</el-button> |
| | | </el-upload> |
| | |
| | | investCityPassenger: 'å¸å·å表ï¼å®¢è¿ç«åºï¼', investCityLogistics: 'å¸å·å表ï¼ç©æµååºï¼', |
| | | 'INVEST_客è¿ç«åº_CITY': 'å¸å·å表ï¼å®¢è¿ç«åºï¼', 'INVEST_ç©æµååº_CITY': 'å¸å·å表ï¼ç©æµååºï¼', |
| | | cityBus: 'åå¸å
¬äº¤ææ¥', cityTaxi: '巡游åºç§ææ¥', cityTaxiAuth: 'åºç§è½¦è¿æ¿è½¦è¾', |
| | | wycTotal: 'ç½çº¦è½¦æ»æ°', wycOrder: 'ç½çº¦è½¦è®¢ååå
¨çæ»é', |
| | | wycTotal: 'ç½çº¦è½¦æ»æ°', wycOrder: 'ç½çº¦è½¦è®¢ååå
¨çæ»é', wycOrderReport: 'ç½çº¦è½¦è®¢åæ¥å', |
| | | H2032: 'H203-2ææ¥', H2031: 'H203-1æ
å®¢ææ¥', H204: 'H204è½è壿¥', PASSENGER_AUTH: 'æ
å®¢è¿æ¿è½¦è¾æ°', |
| | | PASSENGER_INDIVIDUAL: '个ä½å®¢è¿é/å¨è½¬é', ENERGY_AUTH: 'è½è车è¾è¿æ¿ä¿¡æ¯', TRANSPORT_AUTH: 'è¿æ¿è½¦è¾', |
| | | TRACK_MILEAGE: '轨迹éç¨', SCALE_SPLIT: 'è§ä¸è§ä¸æå', FREIGHT_TURNOVER: 'è´§è¿éå¨è½¬é', |
| | | INVEST_SYSTEM: 'æèµç³»ç»å¯¼åº', CITY_BUS: 'åå¸å
¬äº¤ææ¥', CITY_TAXI: '巡游åºç§ææ¥', CITY_TAXI_AUTH: 'åºç§è½¦è¿æ¿è½¦è¾', WYC_TOTAL: 'ç½çº¦è½¦æ»æ°', WYC_ORDER: 'ç½çº¦è½¦è®¢ååå
¨çæ»é' |
| | | INVEST_SYSTEM: 'æèµç³»ç»å¯¼åº', CITY_BUS: 'åå¸å
¬äº¤ææ¥', CITY_TAXI: '巡游åºç§ææ¥', CITY_TAXI_AUTH: 'åºç§è½¦è¿æ¿è½¦è¾', WYC_TOTAL: 'ç½çº¦è½¦æ»æ°', WYC_ORDER: 'ç½çº¦è½¦è®¢ååå
¨çæ»é', WYC_ORDER_REPORT: 'ç½çº¦è½¦è®¢åæ¥å' |
| | | } |
| | | const BATCH_TYPE_MAP = { |
| | | H2032: 'h2032', TRANSPORT_AUTH: 'transportAuth', TRACK_MILEAGE: 'trackMileage', |
| | |
| | | H2031: 'passengerMonthly', PASSENGER_AUTH: 'passengerAuth', PASSENGER_INDIVIDUAL: 'passengerIndividual', |
| | | H204: 'energyMonthly', ENERGY_AUTH: 'energyAuth', |
| | | CITY_BUS: 'cityBus', CITY_TAXI: 'cityTaxi', CITY_TAXI_AUTH: 'cityTaxiAuth', |
| | | WYC_TOTAL: 'wycTotal', WYC_ORDER: 'wycOrder', |
| | | WYC_TOTAL: 'wycTotal', WYC_ORDER: 'wycOrder', WYC_ORDER_REPORT: 'wycOrderReport', |
| | | INVEST_SYSTEM: 'investmentSystem' |
| | | } |
| | | export default { |
| | |
| | | { value: 'cityTaxi', label: '巡游åºç§æ±½è½¦è¿è¥æå¡æ
嵿æ¥' }, |
| | | { value: 'cityTaxiAuth', label: 'åºç§è½¦è¿æ¿è½¦è¾' }, |
| | | { value: 'wycTotal', label: 'ç½çº¦è½¦æ»æ°' }, |
| | | { value: 'wycOrder', label: 'ç½çº¦è½¦è®¢ååå
¨çæ»é' } |
| | | { value: 'wycOrder', label: 'ç½çº¦è½¦è®¢ååå
¨çæ»é' }, |
| | | { value: 'wycOrderReport', label: 'ç½çº¦è½¦è®¢åæ¥å' } |
| | | ] |
| | | }, |
| | | { |
| | |
| | | cityTaxi: '导å
¥_巡游åºç§æ±½è½¦è¿è¥æå¡æ
嵿æ¥ï¼YYYYå¹´Mæï¼.xlsï¼å¸å·çº§17è¡ï¼', |
| | | cityTaxiAuth: '导å
¥æ¨¡æ¿_åºç§è½¦ä¿¡æ¯(è¿æ¿è½¦è¾ä¿¡æ¯).xlsxï¼è½¦è¾çº§æç»ï¼ç¨äºè¿è¥è½¦æ°å¯¹æ¯ï¼', |
| | | wycTotal: '模æ¿_ç½çº¦è½¦æ»æ°.xlsxï¼Aå=æä»½ï¼B-E=å
¨ç客è¿é/åå¸å
/å¨è½¬é/åå¸å
å¨è½¬éï¼', |
| | | wycOrder: '模æ¿_ç½çº¦è½¦è®¢ååå
¨çæ»é.xlsxï¼Aå=æä»½ï¼B-E=å
¨çpinï¼F=订åå计ï¼G-W=17å¸å·è®¢åï¼' |
| | | wycOrder: '模æ¿_ç½çº¦è½¦è®¢ååå
¨çæ»é.xlsxï¼Aå=æä»½ï¼B-E=å
¨çpinï¼F=订åå计ï¼G-W=17å¸å·è®¢åï¼', |
| | | wycOrderReport: '模æ¿_ç½çº¦è½¦è®¢å.docxï¼ãç½çº¦è½¦è¡ä¸YYYYå¹´Mæè¿è¡çæµæ
åµåææ¥åãï¼èªå¨è§£æé件表ãå°å¸åç§°â¦è®¢åæ°æ»æ°ãç 17 å¸å·è®¢åï¼' |
| | | } |
| | | return map[this.importType] || '' |
| | | }, |
| | |
| | | cityTaxiAuth: 'åå¸å®¢è¿/导å
¥æ¨¡æ¿_åºç§è½¦ä¿¡æ¯(è¿æ¿è½¦è¾ä¿¡æ¯).xlsx', |
| | | wycTotal: 'åå¸å®¢è¿/模æ¿_ç½çº¦è½¦æ»æ°.xlsx', |
| | | wycOrder: 'åå¸å®¢è¿/模æ¿_ç½çº¦è½¦è®¢ååå
¨çæ»é.xlsx', |
| | | wycOrderReport: 'åå¸å®¢è¿/模æ¿_ç½çº¦è½¦è®¢å.docx', |
| | | investment: 'æèµ/è¾å
¥/客è¿ï¼å®¢è¿ç«ï¼/æ´æ°_7æå®¢è¿ç«æèµæç»è¡¨ï¼å¸å·æ±æ»å¤§è¡¨ï¼ç»é¢å¯¼ï¼.xlsx', |
| | | investmentLogistics: 'æèµ/è¾å
¥/ç©æµï¼ç©æµååºï¼/æ´æ°_7æç©æµç«åºæèµæç».xls', |
| | | investmentSystem: 'æèµ/模æ¿_æ¥è¯¢ç»æ(æèµç³»ç»-客è¿+ç©æµ 2026.7).xls' |
| | |
| | | cityTaxi: '/import/cityTaxi', |
| | | cityTaxiAuth: '/import/cityTaxiAuth', |
| | | wycTotal: '/import/wycTotal', |
| | | wycOrder: '/import/wycOrder' |
| | | wycOrder: '/import/wycOrder', |
| | | wycOrderReport: '/import/wycOrderReport' |
| | | } |
| | | return map[t] || '' |
| | | }, |
| | |
| | | this.$message.error((e.response && e.response.data && e.response.data.message) || 'æ¹é导å
¥å¤±è´¥') |
| | | }) |
| | | }, |
| | | acceptOf(type) { return type === 'wycOrderReport' ? '.docx,.doc' : '.xlsx,.xls,.et' }, |
| | | isCityDirType(t) { return t === 'investCityPassenger' || t === 'investCityLogistics' }, |
| | | isDirOnlyType(t) { return t === 'investCityPassenger' || t === 'investCityLogistics' }, |
| | | importCityDir(type) { |
| | |
| | | map[key] = { totalRows: r.totalRows, successRows: r.successRows, failRows: r.failRows, latestId: r.id } |
| | | } |
| | | }) |
| | | if (map.wycOrderReport && !map.wycOrder) map.wycOrder = map.wycOrderReport |
| | | this.overview = map |
| | | }) |
| | | .catch(e => { if (!e || !e._toast) this.$message.error('导å
¥è®°å½å 载失败ï¼è¯·å·æ°éè¯') }) |