fix: 4项整改——审核结果按模板双Sheet导出(仅核实型+状态筛选)/明细表格化、数据查看分组选择与隐藏三列、报表页隐藏货运旅客城市客运小表、整本预览展示货运城市客运中口径当月累计同比 + 测试报告与工作日结
| New file |
| | |
| | | # åè½æµè¯æ¥åï¼å®¡æ ¸ç»ææ¨¡æ¿åå±ç¤º/导åºä¸æ°æ®æ¥çãæ¥è¡¨çæé¡µæ´æ¹ |
| | | |
| | | æ¥æï¼2026-09-09ãæ¨¡åï¼å®¡æ ¸ç»æ / æ°æ®æ¥ç / æ¥è¡¨çæãæµè¯äººï¼Codexï¼ä¸å¡ä¾§ç¹éªåè¡¥å
ï¼ |
| | | |
| | | ## ä¸ãåè½è¯´æ |
| | | 1. å®¡æ ¸ç»æé¡µæç»è§å¾æç¨æ·æ°æ¨¡æ¿ï¼docs/å®¡æ ¸çé¢ææ¥æ¨¡æ¿/模æ¿_å®¡æ ¸ç»æ_.xlsxï¼åæ 10 åå¹³éºè¡¨æ ¼ï¼é»è®¤åªçãæ ¸å®åãé®é¢ï¼RULE_004 ç¯æ¯æéé»è®¤æé¤ï¼ï¼å¯åãå
¨é¨ãï¼ç¶æå¯æ å
¨é¨/å¾
å¤ç/å·²å¤ç è¿æ»¤ï¼å¯¼åºä¸çé¢çéä¸è´ã |
| | | 2. å¯¼åº Excel ææ¨¡æ¿å Sheetï¼`å®¡æ ¸ç»æ`ï¼éæ¡ï¼ï¼`ä¼ä¸åå¹¶`ï¼æä¼ä¸æ±æ» + èªå¨ç¼å·é®é¢åï¼ä¼ä¸ä¸é®é¢åè·¨è¡åå¹¶ï¼ã |
| | | 3. æ°æ®æ¥çï¼é¡¶é¨æ¨¡åï¼æ°æ®ç±»å䏿ä¸å¯¼å
¥é¡µä¸è´ï¼ææ¡å·²å¯¹é½å¯¼å
¥é¡µï¼ï¼æ¥è¡¨æ/å
³é®åæ¥è¯¢ç§»å°ç¬¬äºè¡ï¼ä¼ä¸ä»£ç /ç»ä¸ç¤¾ä¼ä¿¡ç¨ä»£ç /å¡«æ¥åä½ 3 åéèã |
| | | 4. æ¥è¡¨çæï¼è´§è¿æ¥è¡¨/æ
客æ¥è¡¨/åå¸å®¢è¿æ¥è¡¨ä¸ç»æ¨¡åéèï¼ä»
ä¿ç æ±æ»å¤§è¡¨/æèµæ¥è¡¨/è½èæ¥è¡¨ï¼éè·¯è¿è¾éæ±æ»è¡¨ï¼æ´æ¬ï¼é¢è§å±ç¤º è´§è¿é/è´§è¿å¨è½¬éãåå¸å®¢è¿é/å¨è½¬éãä¸å£å¾å®¢è¿é/å¨è½¬é ç 彿/累计/忝ã |
| | | |
| | | ## äºãæµè¯ç¯å¢ |
| | | - å端 8090ï¼mvn ç¼è¯éè¿ãå·²éå¯å°±ç»ªï¼ï¼å端 8080ï¼dev ç¼è¯æåãçæ´æ°äº§ç©æ½æ¥éè¿ï¼ã |
| | | - æ°æ®åºï¼æ¬æº traffic_auditï¼2026-08 è´§è¿ H2032 å·²å®¡æ ¸æ°æ®å¨åºï¼ã |
| | | |
| | | ## ä¸ãç¨ä¾ä¸ç»æ |
| | | | ç¼å· | ç¨ä¾ | è¾å
¥ | 颿 | å®é
| ç»è®º | |
| | | |---|---|---|---|---|---| |
| | | | 1 | å®¡æ ¸å¯¼åºå Sheet | /api/audit/export?period=2026-08&reportType=H2032&onlyVerify=true&status=all | å®¡æ ¸ç»æ10å+ä¼ä¸åå¹¶7åãé®é¢åèªå¨ç¼å·ãä¼ä¸/é®é¢åå¹¶ | 475 è¡Ã10 åï¼ä¼ä¸åå¹¶ 150 ç»åå¹¶åºï¼B/G åï¼ï¼é®é¢å½¢å¦â1ã䏿¥å¨è½¬éä¸è½¨è¿¹æµç®â¦è¯·åèè½¨è¿¹æ ¸å®â | éè¿ | |
| | | | 2 | å¯¼åºæé¤æéå | onlyVerify=true | RULE_004 æéåä¸åºç° | æªåºç° RULE_004 | éè¿ | |
| | | | 3 | 导åºç¶æè¿æ»¤ | status=pending / handled | ä»
å¾
å¤ç / ä»
å·²å¤ç | pending=475 è¡ï¼handled æ æ°æ®ï¼å½åææ å·²å¤çè¡ï¼è¡¨å¤´ä¿çï¼ | éè¿ | |
| | | | 4 | åå¹¶åå
æ ¼å¯¹é½æ¨¡æ¿ | openpyxl æ£æ¥ merged | ä¼ä¸(B)ä¸é®é¢(G)è·¨è¡åå¹¶ | 䏿¨¡æ¿ B2:B4/G2:G4 åæ | éè¿ | |
| | | | 5 | æ´æ¬é¢è§ 7 æ | preview?period=2026-07&types=summaryWorkbook | è´§è¿/åå¸å®¢è¿/ä¸å£å¾å½æ+累计+åæ¯è¡ | è´§è¿é彿 16285.71 ä¸å¨ã累计 113423.13ï¼å¨è½¬é彿/累计/忝ï¼åå¸å®¢è¿é彿 30612.85 ä¸äººæ¬¡ï¼ä¸å£å¾å½æ/累计é½å
¨ | éè¿ | |
| | | | 6 | æ´æ¬é¢è§ç¼º 2025 åºææç¤º | å 5 | åæ¯ç¼ºæ°æ®æ¾ç¤ºæç¡®æç¤ºèééé» | è´§è¿é/åå¸å®¢è¿/ä¸å£å¾ 3 项åæç¤ºâ2025-07 åææ°æ®æªå¯¼å
¥åºï¼åæ¯æä¸æ¾ç¤ºâ | éè¿ | |
| | | | 7 | æ´æ¬é¢è§ 8 æç¼ºå½ææºæ°æ® | preview?period=2026-08 | ç¼ºå½ææ°æ®æ¶æç¤º | æç¤ºç¼º 2026-08 è´§è¿éå¨è½¬é/è§ä¸è§ä¸å½æï¼ç´¯è®¡åæè¿å¯¼å
¥æ | éè¿ | |
| | | | 8 | æ°æ®æ¥çåéè | /api/data/list?type=h2032 åéå | å端éè 3 å | æå¡ç«¯å« enterpriseCode/unifiedCreditCode/reportUnitï¼å端已æ prop+label è¿æ»¤ï¼ | éè¿ï¼é¡µé¢å±ç¤ºå¾
人工ç¹éªï¼ | |
| | | | 9 | æ¥è¡¨é¡µæ¨¡åå¯è§æ§ | åç«¯äº§ç©æ½æ¥ | è´§è¿/æ
客/åå¸å®¢è¿éè | 3 ç» hidden:trueï¼é¡µç¾ä»
æ±æ»å¤§è¡¨/æèµ/è½è | éè¿ | |
| | | | 10 | ç¼è¯/è¿è¡ | mvn compile + éå¯ | æ ç¼è¯é误 | EXIT=0ï¼æå¡å°±ç»ª | éè¿ | |
| | | |
| | | ## åãåç°é®é¢ä¸å¤ç½® |
| | | - 导åºãä¼ä¸åå¹¶ãåå®ç°åå¹¶æ¥è¡¨æåèéä¼ä¸åï¼ä¸æ¨¡æ¿ä¸ç¬¦ â 已修æ£ä¸º Bï¼ä¼ä¸ï¼+Gï¼é®é¢ï¼åå¹¶ã |
| | | - 导åºç¶ææªéçé¢çé â åç«¯åæ°ç± handledOnly æ¹ä¸º status=all/pending/handledï¼åç«¯åæ¥ä¼ åã |
| | | - é¢è§åæ¯å åºå
æ 2025-07 åºææ°æ®è缺è¡ï¼è´§è¿é/åå¸å®¢è¿/ä¸å£å¾ï¼â å¢å é项æç¤ºææ¡ï¼æç¡®âå¾
2025 å¹´å®ç¨¿æ°æ®å¯¼å
¥åèªå¨åºç°âï¼æ´æ¬å®é
çæä»ä»¥æ¯ç 2025 å¹´åå
¬å¼ä¸ºåã |
| | | - æ°æ®æ¥çç±»åææ¡ä¸å¯¼å
¥é¡µä¸ä¸è´ï¼H203-1æ
å®¢ææ¥ vs å
¬è·¯æ
客è¿è¾æåº¦ç产æ
åµçï¼â 已对é½å¯¼å
¥é¡µææ¡ï¼value æ²¿ç¨æ°æ®æ¥çåç«¯æ¯æ keyï¼ã |
| | | |
| | | ## äºãå¾
ä¸å¡ç¹éª / éç |
| | | - ä¸ä¸ªé¡µé¢ï¼å®¡æ ¸ç»æãæ°æ®æ¥çãæ¥è¡¨çæï¼å»ºè®®å¨æµè§å¨é页ç¹ä¸éï¼çéèå¨ãè¡¨æ ¼åå±ç¤ºãå¯¼åºæä»¶æå¼æ ¸å¯¹ä¸æ¨¡æ¿é忝坹ã |
| | | - æ°æ®æ¥çå½åä»
弿¾åç«¯å·²æ¯æçç±»åï¼è´§è¿ H2032/è¿æ¿/轨迹/è§ä¸è§ä¸/è´§è¿éå¨è½¬éãå
¬è·¯æ
客 H2031/æ
å®¢è¿æ¿ãå
¬äº¤/åºç§/åºç§è¿æ¿ï¼ï¼ä¸ªä½å®¢è¿éå¨è½¬éãç½çº¦è½¦æ»æ°/订åãæèµãè½èç导å
¥ç±»åçæ°æ®æ¥çå¾
åç»ç¡®è®¤æ¯å¦å¼æ¾ã |
| | | - æ´æ¬é¢è§ç忝è¡ä¾èµ 2025 å¹´åºææ°æ®å
¥åºï¼æ¤å约å®çâ忝以æ¯çç¼åä¼å
ï¼M2 SummaryFillerï¼âæ¹é 仿ªå¯å¨ã |
| | | |
| | | ## å
ãç»è®º |
| | | æ¬æ¬¡ 4 项çé¢/å¯¼åºæ´æ¹å·²è½å°å¹¶éè¿æ¥å£çº§ä¸äº§ç©çº§éªè¯ï¼é¡µé¢è§è§ä¸äº¤äºå»ºè®®ä¸å¡å¨æµè§å¨ç»éªåå³å¯ä½ä¸ºä»æ¥äº¤ä»çä¸é¨åã |
| | |
| | | |
| | | ## ææ¥è®¡å |
| | | - å¯å¨ M2 SummaryFillerï¼å
7 æåå½ diff=0ï¼å 8 æå®å¼¹ï¼ï¼è¡¥é½ 8 æè´§è¿éå¨è½¬é/è§ä¸è§ä¸/个ä½å®¢è¿ç缺æ°åæ´é¾éªè¯ã |
| | | |
| | | |
| | | --- |
| | | |
| | | ## ä¸å第äºè½®ï¼4 é¡¹æ´æ¹ï¼2026-09-09 11:xx |
| | | ### 宿å
容 |
| | | - å®¡æ ¸ç»æé¡µï¼æç»è§å¾æ¹ä¸ºä¸ç¨æ·æ¨¡æ¿å款ç 10 åè¡¨æ ¼ï¼æ¥è¡¨æ/ä¼ä¸/è§åç¼ç /è§å/ç级/å®é
/éå¼/åå·®/ç¶æ/æä½ï¼ï¼å¡çå¼ç§»é¤ï¼æ°å¢ãé®é¢ç±»åï¼æ ¸å®åé»è®¤/å
¨é¨ï¼ãä¸ãç¶æï¼å
¨é¨/å¾
å¤ç/å·²å¤çï¼ãçéï¼å¯¼åºæä¸¤é¡¹çé带ç»å端ã |
| | | - å®¡æ ¸å¯¼åºï¼æ¨¡æ¿ docs/å®¡æ ¸çé¢ææ¥æ¨¡æ¿/模æ¿_å®¡æ ¸ç»æ_.xlsx å Sheetï¼ï¼Sheet1 å®¡æ ¸ç»æï¼ä»
æ ¸å®åï¼æé¤ RULE_004 æéåï¼ï¼Sheet2 ä¼ä¸åå¹¶æä¼ä¸æ±æ»ï¼é®é¢åèªå¨çæ 1ã2ã3 ç¼å·è¯æ¯ï¼ä¼ä¸/é®é¢ä¸¤åææ¨¡æ¿åå¹¶åå
æ ¼ï¼æ¤åéåå¹¶æ¥è¡¨æå已修æ£ï¼ã |
| | | - æ°æ®æ¥çï¼æ°æ®ç±»åéæ©æ¹ä¸ºãåç»æ¨¡å+ç±»å䏿ãä¸å¯¼å
¥é¡µå款å¸å±ä¸ææ¡ï¼æ¥è¡¨æãå
³é®åæ¥è¯¢æ¾å°ä¸æ¹çéè¡ï¼ä¼ä¸ä»£ç /ç»ä¸ç¤¾ä¼ä¿¡ç¨ä»£ç /å¡«æ¥åä½ä¸åéèï¼æ prop ä¸ label åéè¿æ»¤ï¼ã |
| | | - æ¥è¡¨çæï¼è´§è¿/æ
客/åå¸å®¢è¿ä¸ä¸ªå°è¡¨æ¨¡åæ´ç»éèï¼é¡µç¾ä»
å© æ±æ»å¤§è¡¨/æèµæ¥è¡¨/è½èæ¥è¡¨ï¼éè·¯è¿è¾éæ±æ»è¡¨ï¼æ´æ¬ï¼é¢è§æ°å¢å
³é®ææ ï¼è´§è¿éãè´§è¿å¨è½¬éãåå¸å®¢è¿é/å¨è½¬éãä¸å£å¾å®¢è¿é/å¨è½¬éç彿/1..M累计/åæ¯ï¼æ°æ®é½å³æ¾ç¤ºï¼ç¼º 2025 å¹´åºææ°æ®æ¶éé¡¹ç»æç¤ºï¼ã |
| | | |
| | | ### æµè¯ç»ææè¦ |
| | | - mvn ç¼è¯éè¿ï¼å端éå¯å°±ç»ªï¼å端 dev ç¼è¯æåï¼chunk æ½æ¥ç¡®è®¤æ°åæ°å·²è¿äº§ç©ï¼ã |
| | | - /api/audit/export 2026-08 H2032ï¼å®¡æ ¸ç»æ 475 è¡ 10 å + ä¼ä¸åå¹¶ 150 ç»ï¼B/G åå¹¶ï¼ï¼ä»
æ ¸å®åï¼status=pending/handled è¿æ»¤çæã |
| | | - /api/report/preview summaryWorkbookï¼2026-07 æ¾ç¤ºå
¨çè´§è¿é 16285.71 ä¸å¨/累计 113423.13ï¼å¨è½¬é彿/累计+忝ï¼åå¸å®¢è¿é彿 30612.85 ä¸äººæ¬¡çï¼åæ¯ç¼º 2025-07 åºææ°æ®çä¸é¡¹åææç¡®æç¤ºã |
| | | - æ°æ®æ¥çåç»ææ ¸å¯¹ï¼æå¡ç«¯å« enterpriseCode/unifiedCreditCode/reportUnit ä¸åï¼å端éèçæï¼ã |
| | |
| | | |
| | | @GetMapping("/export") |
| | | public ResponseEntity<byte[]> exportResults(@RequestParam("period") String period, |
| | | @RequestParam(value = "reportType", defaultValue = "H2032") String reportType) throws Exception { |
| | | byte[] bytes = auditService.exportResults(period, reportType); |
| | | @RequestParam(value = "reportType", defaultValue = "H2032") String reportType, |
| | | @RequestParam(value = "onlyVerify", defaultValue = "true") boolean onlyVerify, |
| | | @RequestParam(value = "status", defaultValue = "all") String status) throws Exception { |
| | | byte[] bytes = auditService.exportResults(period, reportType, onlyVerify, status); |
| | | String name = java.net.URLEncoder.encode("å®¡æ ¸ç»æ_" + period + ".xlsx", "UTF-8"); |
| | | return ResponseEntity.ok() |
| | | .header("Content-Disposition", "attachment; filename*=UTF-8''" + name) |
| | |
| | | return a; |
| | | } |
| | | |
| | | /** å®¡æ ¸ç»æå¯¼åº Excelï¼å«ä¼ä¸å/è§åå/ç¶æ/å®¡æ ¸æè§ï¼ */ |
| | | /** å®¡æ ¸ç»æå¯¼åº Excelï¼ä¸¤ Sheetï¼æä¸å¡æ¨¡æ¿ï¼ï¼Sheet1 å®¡æ ¸ç»æï¼éæ¡æç»ï¼ï¼Sheet2 ä¼ä¸åå¹¶ï¼æä¼ä¸æ±æ» + é®é¢åï¼ */ |
| | | public byte[] exportResults(String reportPeriod, String reportType) throws Exception { |
| | | return exportResults(reportPeriod, reportType, true, "all"); |
| | | } |
| | | |
| | | /** onlyVerify=true æ¶åé¤âæéåâè§åï¼å¦ RULE_004 ç¯æ¯æéï¼ï¼åªä¿çæ ¸å®åé®é¢ï¼status=all/pending/handled ä¸çé¢âç¶æâçéä¸è´ */ |
| | | public byte[] exportResults(String reportPeriod, String reportType, boolean onlyVerify, String status) throws Exception { |
| | | List<AuditResult> results = queryResults(reportPeriod, reportType); |
| | | java.util.List<AuditResult> filtered = new java.util.ArrayList<>(); |
| | | String st = status == null ? "all" : status.trim(); |
| | | for (AuditResult res : results) { |
| | | if (onlyVerify && isReminderRule(res.getRuleCode())) continue; |
| | | if ("pending".equals(st) && !"PENDING".equals(res.getStatus())) continue; |
| | | if ("handled".equals(st) && (res.getStatus() == null || "PENDING".equals(res.getStatus()))) continue; |
| | | filtered.add(res); |
| | | } |
| | | try (XSSFWorkbook wb = new XSSFWorkbook()) { |
| | | // ---------- Sheet1 å®¡æ ¸ç»æï¼éæ¡ï¼åä¸ä¸å¡æ¨¡æ¿ä¸è´ï¼ ---------- |
| | | Sheet sheet = wb.createSheet("å®¡æ ¸ç»æ"); |
| | | String[] headers = {"æ¥è¡¨æ", "ä¼ä¸/å¸å·", "è§åç¼ç ", "å®¡æ ¸è§å", "ç级", "å®é
å¼", "éå¼/åºå", "å差说æ", "ç¶æ", "å®¡æ ¸æè§"}; |
| | | Row head = sheet.createRow(0); |
| | | for (int i = 0; i < headers.length; i++) { |
| | | Cell cell = head.createCell(i); |
| | | cell.setCellValue(headers[i]); |
| | | org.apache.poi.ss.usermodel.CellStyle style = wb.createCellStyle(); |
| | | org.apache.poi.ss.usermodel.Font font = wb.createFont(); |
| | | font.setBold(true); |
| | | style.setFont(font); |
| | | cell.setCellStyle(style); |
| | | } |
| | | writeAuditHeader(sheet, headers); |
| | | int r = 1; |
| | | for (AuditResult res : results) { |
| | | for (AuditResult res : filtered) { |
| | | Row row = sheet.createRow(r++); |
| | | row.createCell(0).setCellValue(valueOf(res.getReportPeriod())); |
| | | row.createCell(1).setCellValue(valueOf(res.getEnterpriseName())); |
| | |
| | | for (int i = 0; i < widths.length; i++) { |
| | | sheet.setColumnWidth(i, widths[i] * 256); |
| | | } |
| | | |
| | | // ---------- Sheet2 ä¼ä¸åå¹¶ï¼åä¸ä¼ä¸å¤æ¡è§åå¹¶æååº + é®é¢æ±æ»åï¼ ---------- |
| | | Sheet ms = wb.createSheet("ä¼ä¸åå¹¶"); |
| | | String[] h2 = {"æ¥è¡¨æ", "ä¼ä¸/å¸å·", "å®¡æ ¸è§å", "å®é
å¼", "éå¼/åºå", "å差说æ", "é®é¢"}; |
| | | writeAuditHeader(ms, h2); |
| | | java.util.LinkedHashMap<String, java.util.List<AuditResult>> groups = new java.util.LinkedHashMap<>(); |
| | | for (AuditResult res : filtered) { |
| | | String key = valueOf(res.getEnterpriseName()); |
| | | if (key.isEmpty()) key = valueOf(res.getReportPeriod()) + "#" + valueOf(res.getActualValue()); |
| | | groups.computeIfAbsent(key, k -> new java.util.ArrayList<>()).add(res); |
| | | } |
| | | int rowCursor = 1; |
| | | for (java.util.Map.Entry<String, java.util.List<AuditResult>> e : groups.entrySet()) { |
| | | java.util.List<AuditResult> items = e.getValue(); |
| | | int groupStart = rowCursor; |
| | | StringBuilder problems = new StringBuilder(); |
| | | int seq = 0; |
| | | for (AuditResult it : items) { |
| | | Row row = ms.createRow(rowCursor++); |
| | | if (seq == 0) { |
| | | row.createCell(0).setCellValue(valueOf(it.getReportPeriod())); |
| | | row.createCell(1).setCellValue(valueOf(it.getEnterpriseName()).isEmpty() ? e.getKey() : valueOf(it.getEnterpriseName())); |
| | | } |
| | | row.createCell(2).setCellValue(valueOf(it.getRuleName())); |
| | | row.createCell(3).setCellValue(valueOf(it.getActualValue())); |
| | | row.createCell(4).setCellValue(valueOf(it.getThresholdValue())); |
| | | row.createCell(5).setCellValue(valueOf(it.getDeviation())); |
| | | seq++; |
| | | if (problems.length() > 0) problems.append("\n"); |
| | | problems.append(seq).append("ã").append(issueSentence(it)); |
| | | } |
| | | if (rowCursor - groupStart > 1) { |
| | | ms.addMergedRegion(new org.apache.poi.ss.util.CellRangeAddress(groupStart, rowCursor - 1, 1, 1)); |
| | | ms.addMergedRegion(new org.apache.poi.ss.util.CellRangeAddress(groupStart, rowCursor - 1, 6, 6)); |
| | | } |
| | | Row first = ms.getRow(groupStart); |
| | | if (first.getCell(6) == null) first.createCell(6); |
| | | first.getCell(6).setCellValue(problems.toString()); |
| | | } |
| | | int[] widths2 = {12, 30, 22, 34, 22, 34, 60}; |
| | | for (int i = 0; i < widths2.length; i++) { |
| | | ms.setColumnWidth(i, widths2[i] * 256); |
| | | } |
| | | ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| | | wb.write(out); |
| | | return out.toByteArray(); |
| | | } |
| | | } |
| | | |
| | | private void writeAuditHeader(Sheet sheet, String[] headers) { |
| | | Row head = sheet.createRow(0); |
| | | for (int i = 0; i < headers.length; i++) { |
| | | Cell cell = head.createCell(i); |
| | | cell.setCellValue(headers[i]); |
| | | org.apache.poi.ss.usermodel.CellStyle style = sheet.getWorkbook().createCellStyle(); |
| | | org.apache.poi.ss.usermodel.Font font = sheet.getWorkbook().createFont(); |
| | | font.setBold(true); |
| | | style.setFont(font); |
| | | cell.setCellStyle(style); |
| | | } |
| | | } |
| | | |
| | | /** æéåè§åï¼ä»
æç¤ºååãä¸éäººå·¥æ ¸å®ï¼å¦ RULE_004 è´§è¿ç±»åç¯æ¯æéï¼ */ |
| | | private boolean isReminderRule(String ruleCode) { |
| | | return "RULE_004".equals(ruleCode); |
| | | } |
| | | |
| | | /** ä¼ä¸åå¹¶âé®é¢âåè¯æ¯ï¼æè§åç±»åçæå¯è¯»çæ ¸å®æè§ */ |
| | | private String issueSentence(AuditResult res) { |
| | | String code = res.getRuleCode(); |
| | | String dev = valueOf(res.getDeviation()); |
| | | String act = valueOf(res.getActualValue()); |
| | | String thr = valueOf(res.getThresholdValue()); |
| | | if ("RULE_001".equals(code) || "RULE_002".equals(code)) { |
| | | return "ä¼ä¸ä¸æ¥è½¦è¾/å¨ä½ä¸è¿æ¿æ°æ®å¯¹æ¯åå¨å·®å¼ï¼" + dev + "ï¼ï¼è¯·æ ¸å®"; |
| | | } |
| | | if ("RULE_003".equals(code)) { |
| | | return "䏿¥å¨è½¬éä¸è½¨è¿¹æµç®å¨è½¬é差弿æ¾ï¼" + dev + "ï¼ï¼è¯·åèè½¨è¿¹æ ¸å®ä¼ä¸å¨è½¬é"; |
| | | } |
| | | if ("RULE_004".equals(code)) { |
| | | return "è´§è¿ç±»åç¯æ¯åçååï¼è¯·æ ¸å®"; |
| | | } |
| | | if ("RULE_005".equals(code)) { |
| | | return "æ éè£
箱车ä½åå¨éè£
箱货è¿éï¼è¯·æ ¸å®è½¦è¾ç±»åä¸è´§è¿éå¡«æ¥"; |
| | | } |
| | | if ("RULE_006".equals(code)) { |
| | | return "æ´è½¦å¨ä½è¶
åº 4~40 å¨åçèå´ï¼è¯·æ ¸å®å¹³åå¨ä½å¡«æ¥"; |
| | | } |
| | | return valueOf(res.getRuleName()) + "å¼å¸¸ï¼å®é
ï¼" + act + "ï¼åºåï¼" + thr + "ï¼" + dev + "ï¼ï¼è¯·æ ¸å®"; |
| | | } |
| | | |
| | | private String auditStatusCn(String status) { |
| | | if ("CONFIRMED".equals(status)) return "已确认"; |
| | | if ("IGNORED".equals(status)) return "已忽ç¥"; |
| | |
| | | if (resolveSummaryMother(period, mode) == null) { |
| | | problems.add("docs/çææ±æ»å¤§è¡¨ ä¸ç¼ºå°å¯å¤å¶çæ¯çæ±æ»è¡¨"); |
| | | } else { |
| | | Map<Integer, Map<String, double[]>> busM = loadCityBusByMonth(yearPrefix, month); |
| | | Map<Integer, Map<String, double[]>> taxiM = loadCityTaxiByMonth(yearPrefix, month); |
| | | Map<String, double[]> bc = busM.get(month); |
| | | Map<String, double[]> tc = taxiM.get(month); |
| | | if (bc != null && bc.get("å
¨ç") != null) addSum(summary, "åå¸å
¬äº¤å®¢è¿éï¼å
¨ç彿ï¼", bc.get("å
¨ç")[0], "ä¸äºº"); |
| | | if (tc != null && tc.get("å
¨ç") != null) addSum(summary, "巡游åºç§å®¢è¿éï¼å
¨ç彿ï¼", tc.get("å
¨ç")[0], "ä¸äºº"); |
| | | summaryWorkbookPreview(period, yearNum, month, summary, problems); |
| | | } |
| | | } catch (Exception ex) { |
| | | problems.add(ex.getMessage()); |
| | |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** æ±æ»æ´æ¬å
³é®ææ é¢è§ï¼è´§è¿é/å¨è½¬éãåå¸å®¢è¿ãä¸å£å¾ç 彿ã1..M 累计ã彿忝ãç´¯è®¡åæ¯ï¼åæ¯ååºå
å»å¹´åæï¼ç¼ºåæ¾ç¤ºâï¼ */ |
| | | private void summaryWorkbookPreview(String period, int year, int month, |
| | | List<Map<String, Object>> summary, List<String> problems) { |
| | | String yearPrefix = year + "-"; |
| | | // ---- è´§è¿ï¼é=模æ¿_è´§è¿éå¨è½¬éå
¨çè¡ï¼å¨è½¬é=è§ä¸è§ä¸æå表å
¨çè¡ï¼ ---- |
| | | FreightTurnoverImport ft = loadFreightTurnover(period).get("æ¹åç"); |
| | | Double fm = ft == null ? null : freightMonth(ft, month); |
| | | Double fcum = ft == null ? null : freightCum(ft, month); |
| | | Double fy = ft == null ? null : freightYoy(ft, month); |
| | | Double fcy = ft == null ? null : freightCumYoy(ft, month); |
| | | addKpi(summary, "å
¨çè´§è¿é", fm, fcum, fy, fcy, "ä¸å¨"); |
| | | if (fm != null && fy == null) { |
| | | problems.add((year - 1) + "-" + String.format("%02d", month) + " åæè´§è¿éæ°æ®æªå¯¼å
¥åºï¼è´§è¿é彿/ç´¯è®¡åæ¯æä¸æ¾ç¤ºï¼å¾
2025 å¹´å®ç¨¿æ°æ®å¯¼å
¥åèªå¨åºç°"); |
| | | } |
| | | ScaleSplitTransport tm = loadProvinceMonthMap(period).get(month); |
| | | ScaleSplitTransport tc = getProvinceCumulative(period); |
| | | Double tvM = tm == null ? null : tm.getTotalTurnover(); |
| | | Double tvC = tc == null ? null : tc.getTotalTurnover(); |
| | | Double tvMY = tm == null ? null : getYoyMetric(tm, "turnover", "total"); |
| | | Double tvCY = tc == null ? null : getYoyMetric(tc, "turnover", "total"); |
| | | addKpi(summary, "å
¨çè´§ç©å¨è½¬é", tvM, tvC, tvMY, tvCY, "ä¸å¨å
Ž"); |
| | | if (fm == null) problems.add("模æ¿_è´§è¿éå¨è½¬é缺 " + period + " å½ææ°æ®ï¼è´§è¿éä»
è½æä¾æªè³æè¿å¯¼å
¥æç累计"); |
| | | if (tvM == null) problems.add("è§ä¸è§ä¸æå缺 " + period + " å½ææ°æ®ï¼å¨è½¬é/è§ä¸è§ä¸å½æç¼ºï¼ç´¯è®¡ä¸ºæªè³æè¿å¯¼å
¥æ"); |
| | | |
| | | // ---- åå¸å®¢è¿ï¼å
¬äº¤+åºç§+轨é+轮渡 å
¨çå°è®¡ï¼ææ ä½ 0/2/4/6=客è¿ï¼1/3/5/7=å¨è½¬ï¼ ---- |
| | | double[] cumM = cityCumProv(yearPrefix, month); |
| | | double[] cumPrev = cityCumProv(yearPrefix, month - 1); |
| | | double[] monthVec = diff8(cumM, cumPrev); |
| | | double cityPaxM = sumIdx(monthVec, new int[]{0, 2, 4, 6}); |
| | | double cityTurnM = sumIdx(monthVec, new int[]{1, 3, 5, 7}); |
| | | double cityPaxC = sumIdx(cumM, new int[]{0, 2, 4, 6}); |
| | | double cityTurnC = sumIdx(cumM, new int[]{1, 3, 5, 7}); |
| | | double[] lastCumM = cityCumProv((year - 1) + "-", month); |
| | | double[] lastCumPrev = cityCumProv((year - 1) + "-", month - 1); |
| | | double[] lastVec = diff8(lastCumM, lastCumPrev); |
| | | double lastPaxM = sumIdx(lastVec, new int[]{0, 2, 4, 6}); |
| | | double lastPaxC = sumIdx(lastCumM, new int[]{0, 2, 4, 6}); |
| | | double lastTurnM = sumIdx(lastVec, new int[]{1, 3, 5, 7}); |
| | | double lastTurnC = sumIdx(lastCumM, new int[]{1, 3, 5, 7}); |
| | | addKpiRaw(summary, "åå¸å®¢è¿é", cityPaxM, cityPaxC, lastPaxM, lastPaxC, "ä¸äººæ¬¡"); |
| | | addKpiRaw(summary, "åå¸å®¢è¿å¨è½¬é", cityTurnM, cityTurnC, lastTurnM, lastTurnC, "ä¸äººå
Ž"); |
| | | |
| | | // ---- ä¸å£å¾ï¼å
¬è·¯æ
客ä¼ä¸ H203-1 å
¨çï¼å使¢ç® /10000ï¼ ---- |
| | | Map<Integer, Map<String, PassengerAgg>> data = loadPassengerAggMap(); |
| | | double paxM = 0.0, paxC = 0.0, turnM = 0.0, turnC = 0.0; |
| | | double lastPaxM2 = 0.0, lastPaxC2 = 0.0, lastTurnM2 = 0.0, lastTurnC2 = 0.0; |
| | | for (int m = 1; m <= month; m++) { |
| | | PassengerAgg agg = aggOf(data, year, m, "æ¹åç"); |
| | | if (agg != null) { |
| | | double pax = agg.passengerTotal / 10000.0; |
| | | double turn = agg.turnoverTotal / 10000.0; |
| | | if (m == month) { paxM = pax; turnM = turn; } |
| | | paxC += pax; |
| | | turnC += turn; |
| | | } |
| | | PassengerAgg last = aggOf(data, year - 1, m, "æ¹åç"); |
| | | if (last != null) { |
| | | double lp = last.passengerTotal / 10000.0; |
| | | double lt = last.turnoverTotal / 10000.0; |
| | | if (m == month) { lastPaxM2 = lp; lastTurnM2 = lt; } |
| | | lastPaxC2 += lp; |
| | | lastTurnC2 += lt; |
| | | } |
| | | } |
| | | addKpiRaw(summary, "ä¸å£å¾å®¢è¿é", paxM, paxC, lastPaxM2, lastPaxC2, "ä¸äººæ¬¡"); |
| | | addKpiRaw(summary, "ä¸å£å¾å¨è½¬é", turnM, turnC, lastTurnM2, lastTurnC2, "ä¸äººå
Ž"); |
| | | |
| | | if (paxM <= 0 && paxC <= 0 && cityPaxC <= 0 && fm == null) { |
| | | problems.add("è´§è¿éå¨è½¬é/è§ä¸è§ä¸/å
¬è·¯æ
客/åå¸å®¢è¿å½ææ°æ®å缺失"); |
| | | } |
| | | if (cityPaxC > 0 && lastPaxC <= 0) { |
| | | problems.add((year - 1) + "-" + String.format("%02d", month) + " åæåå¸å®¢è¿æ°æ®æªå¯¼å
¥åºï¼åå¸å®¢è¿åæ¯æä¸æ¾ç¤ºï¼å¾
2025 å¹´å®ç¨¿æ°æ®å¯¼å
¥åèªå¨åºç°"); |
| | | } |
| | | if (paxC > 0 && lastPaxC2 <= 0) { |
| | | problems.add((year - 1) + "-" + String.format("%02d", month) + " åæå
¬è·¯æ
å®¢æ°æ®æªå¯¼å
¥åºï¼ä¸å£å¾åæ¯æä¸æ¾ç¤ºï¼å¾
2025 å¹´å®ç¨¿æ°æ®å¯¼å
¥åèªå¨åºç°"); |
| | | } |
| | | } |
| | | |
| | | /** åå¸å®¢è¿å
¨ç累计åéï¼8 ææ ï¼å
¬äº¤å®¢è¿/å¨è½¬ãåºç§å®¢è¿/å¨è½¬ã轨é客è¿/å¨è½¬ã轮渡客è¿/å¨è½¬ï¼ */ |
| | | private double[] cityCumProv(String yearPrefix, int month) { |
| | | if (month <= 0) return new double[8]; |
| | | return loadCityPassengerCumulative(yearPrefix, month).getOrDefault("å
¨ç", new double[8]); |
| | | } |
| | | |
| | | private double[] diff8(double[] a, double[] b) { |
| | | double[] out = new double[8]; |
| | | for (int i = 0; i < 8; i++) out[i] = a[i] - b[i]; |
| | | return out; |
| | | } |
| | | |
| | | private double sumIdx(double[] arr, int[] idx) { |
| | | double sum = 0.0; |
| | | for (int i : idx) sum += (i < arr.length ? arr[i] : 0.0); |
| | | return sum; |
| | | } |
| | | |
| | | /** ç¾åæ¯åæ¯ï¼å¼å·²ä¸ºæ¯ç 0.xxï¼ï¼è¾åºåè¡ å½æ/累计/彿忝/ç´¯è®¡åæ¯ */ |
| | | private void addKpi(List<Map<String, Object>> summary, String name, Double m, Double cum, Double yoyM, Double yoyC, String unit) { |
| | | if (m != null) addSum(summary, name + "Â·å½æ", round(m, 2), unit); |
| | | if (cum != null) addSum(summary, name + "·累计", round(cum, 2), unit); |
| | | if (yoyM != null) addSum(summary, name + "Â·å½æåæ¯", round(yoyM * 100.0, 1), "%"); |
| | | if (yoyC != null) addSum(summary, name + "Â·ç´¯è®¡åæ¯", round(yoyC * 100.0, 1), "%"); |
| | | } |
| | | |
| | | /** åå§æ°å¼çï¼æ/累计为 0 è§ä¸ºæ æ°æ®ä¸åºè¡ï¼ */ |
| | | private void addKpiRaw(List<Map<String, Object>> summary, String name, double m, double cum, double lastM, double lastC, String unit) { |
| | | if (m > 0) addSum(summary, name + "Â·å½æ", round(m, 2), unit); |
| | | if (cum > 0) addSum(summary, name + "·累计", round(cum, 2), unit); |
| | | if (m > 0 && lastM > 0) addSum(summary, name + "Â·å½æåæ¯", round((m - lastM) / lastM * 100.0, 1), "%"); |
| | | if (cum > 0 && lastC > 0) addSum(summary, name + "Â·ç´¯è®¡åæ¯", round((cum - lastC) / lastC * 100.0, 1), "%"); |
| | | } |
| | | |
| | | private void addSum(List<Map<String, Object>> summary, String label, Double value, String unit) { |
| | | Map<String, Object> m = new LinkedHashMap<>(); |
| | | m.put("label", label); |
| | |
| | | <el-option v-for="rn in ruleOptions" :key="rn" :label="rn" :value="rn"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="é®é¢ç±»å"> |
| | | <el-radio-group v-model="issueScope" size="small" @change="updateBatchSelection"> |
| | | <el-radio-button label="verify">æ ¸å®å</el-radio-button> |
| | | <el-radio-button label="all">å
¨é¨</el-radio-button> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="ç¶æ"> |
| | | <el-select v-model="statusScope" style="width:110px" @change="updateBatchSelection"> |
| | | <el-option label="å
¨é¨" value="all"></el-option> |
| | | <el-option label="å¾
å¤ç" value="pending"></el-option> |
| | | <el-option label="å·²å¤ç" value="handled"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="è§å¾"> |
| | | <el-radio-group v-model="viewMode"> |
| | | <el-radio label="detail">ææ¡æç»</el-radio> |
| | |
| | | å
± {{ results.length }} æ¡é®é¢ï¼{{ mergedResults.length }} å®¶ä¼ä¸ |
| | | </div> |
| | | <div class="table-area" style="flex:1;min-height:0"> |
| | | <!-- æç»è§å¾ï¼ä¸æ¡é®é¢ä¸å¼ å¡ç --> |
| | | <!-- æç»è§å¾ï¼ä¸æ¡é®é¢ä¸è¡ï¼ä¸å¯¼åºæ¨¡æ¿ Sheetâå®¡æ ¸ç»æâ忬¾ï¼ --> |
| | | <div v-if="viewMode === 'detail'" class="detail-cards-wrap" v-loading="loading"> |
| | | <div class="detail-toolbar"> |
| | | <el-checkbox :value="allSelected" :indeterminate="someSelected" @change="toggleSelectAll">å
¨éå½å {{ filteredResults.length }} æ¡</el-checkbox> |
| | | <span class="toolbar-tip">å¾éå坿¹é确认 / 忽ç¥</span> |
| | | </div> |
| | | <div v-for="row in filteredResults" :key="row.id" class="detail-card" |
| | | :class="{ 'card-red': row.alertLevel === 'RED', 'card-yellow': row.alertLevel === 'YELLOW', 'card-done': row.status !== 'PENDING' }"> |
| | | <div class="card-head"> |
| | | <el-table :data="filteredResults" border stripe height="100%" |
| | | :header-cell-style="{ background: '#F5F7FA', color: '#303133', fontWeight: 600 }"> |
| | | <el-table-column width="40"> |
| | | <template slot-scope="{ row }"> |
| | | <el-checkbox v-model="row._selected" @change="updateBatchSelection"></el-checkbox> |
| | | <div class="card-ent"> |
| | | <div class="ent-name">{{ row.enterpriseName || row.city || 'æªç¥ä¼ä¸' }}</div> |
| | | <div class="ent-sub">{{ row.reportPeriod }}</div> |
| | | </div> |
| | | <el-tag :type="row.alertLevel === 'RED' ? 'danger' : 'warning'" size="small" effect="dark">{{ row.alertLevel }}</el-tag> |
| | | <el-tag :type="statusType(row.status)" size="small" effect="plain" class="status-tag"> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="reportPeriod" label="æ¥è¡¨æ" width="90"></el-table-column> |
| | | <el-table-column label="ä¼ä¸/å¸å·" min-width="200" show-overflow-tooltip> |
| | | <template slot-scope="{ row }">{{ row.enterpriseName || row.city || 'æªç¥ä¼ä¸' }}</template> |
| | | </el-table-column> |
| | | <el-table-column prop="ruleCode" label="è§åç¼ç " width="100"></el-table-column> |
| | | <el-table-column prop="ruleName" label="å®¡æ ¸è§å" min-width="150" show-overflow-tooltip></el-table-column> |
| | | <el-table-column label="ç级" width="76"> |
| | | <template slot-scope="{ row }"> |
| | | <el-tag :type="row.alertLevel === 'RED' ? 'danger' : 'warning'" size="mini">{{ row.alertLevel }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="actualValue" label="å®é
å¼" min-width="230" show-overflow-tooltip></el-table-column> |
| | | <el-table-column prop="thresholdValue" label="éå¼/åºå" min-width="140" show-overflow-tooltip></el-table-column> |
| | | <el-table-column prop="deviation" label="å差说æ" min-width="170" show-overflow-tooltip></el-table-column> |
| | | <el-table-column label="ç¶æ" width="92"> |
| | | <template slot-scope="{ row }"> |
| | | <el-tag :type="statusType(row.status)" size="mini"> |
| | | <i :class="statusIcon(row.status)"></i> {{ statusText(row.status) }} |
| | | </el-tag> |
| | | <span class="spacer"></span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" width="185" align="right"> |
| | | <template slot-scope="{ row }"> |
| | | <el-link v-if="dataType(reportType)" type="primary" :underline="false" size="mini" @click="openMonthReport(row)">æ°æ®</el-link> |
| | | <el-button v-if="row.status === 'PENDING'" size="mini" type="success" icon="el-icon-check" round @click="review(row, 'CONFIRMED')">确认</el-button> |
| | | <el-button v-if="row.status === 'PENDING'" size="mini" type="info" icon="el-icon-close" round plain @click="review(row, 'IGNORED')">忽ç¥</el-button> |
| | | <span v-else class="done-text">å·²å¤ç</span> |
| | | </div> |
| | | <div class="card-body"> |
| | | <div class="rule-title"> |
| | | <b>{{ row.ruleName }}</b> |
| | | <span class="rule-code">{{ row.ruleCode }}</span> |
| | | </div> |
| | | <div class="card-details"> |
| | | <div class="detail-line"><span class="dt-label">å®é
</span><span class="dt-val">{{ row.actualValue }}</span></div> |
| | | <div class="detail-line"><span class="dt-label">åºå</span><span class="dt-val">{{ row.thresholdValue }}</span></div> |
| | | <div class="detail-line"><span class="dt-label">å·®å¼</span><span class="dt-val dt-warn">{{ row.deviation }}</span></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div v-if="!filteredResults.length" class="empty-tip"> |
| | | </template> |
| | | </el-table-column> |
| | | <div slot="empty"> |
| | | <el-empty description="å½åç鿡件䏿²¡æé®é¢æ°æ®"></el-empty> |
| | | </div> |
| | | </el-table> |
| | | </div> |
| | | <!-- åå¹¶è§å¾ --> |
| | | <el-table v-else :data="mergedResults" border stripe v-loading="loading" height="100%" |
| | |
| | | data() { |
| | | return { |
| | | period: '', reportType: 'H2032', loading: false, marking: false, results: [], ruleStats: [], statsCollapsed: false, |
| | | enterpriseFilter: '', ruleFilter: '', viewMode: 'merged', batchSelection: [], focusMode: false, |
| | | enterpriseFilter: '', ruleFilter: '', viewMode: 'detail', issueScope: 'verify', statusScope: 'all', batchSelection: [], focusMode: false, |
| | | explainDrafts: {}, savingExplainId: null, expandedExplain: null, |
| | | monthVisible: false, monthLoading: false, monthType: '', monthPeriod: '', monthKeyword: '', monthRecords: [], monthColumns: [] |
| | | } |
| | |
| | | const list = this.filteredResults |
| | | return list.some(r => r._selected) && !this.allSelected |
| | | }, |
| | | isReminderRow(r) { |
| | | return !!(r && r.ruleCode === 'RULE_004') |
| | | }, |
| | | filteredResults() { |
| | | const kw = (this.enterpriseFilter || '').trim() |
| | | const rule = this.ruleFilter |
| | | if (!kw && !rule) return this.results |
| | | const scope = this.issueScope || 'verify' |
| | | const st = this.statusScope || 'all' |
| | | return this.results.filter(r => { |
| | | if (kw && !(r.enterpriseName || '').includes(kw)) return false |
| | | if (rule && r.ruleName !== rule) return false |
| | | if (scope === 'verify' && this.isReminderRow(r)) return false |
| | | if (st === 'pending' && r.status !== 'PENDING') return false |
| | | if (st === 'handled' && (!r.status || r.status === 'PENDING')) return false |
| | | return true |
| | | }) |
| | | }, |
| | |
| | | }, |
| | | exportExcel() { |
| | | if (!this.period) { this.$message.warning('è¯·éæ©æ¥è¡¨æ'); return } |
| | | window.open('/api/audit/export?period=' + this.period + '&reportType=' + this.reportType) |
| | | const q = 'period=' + this.period + '&reportType=' + this.reportType + '&onlyVerify=' + (this.issueScope !== 'all') + '&status=' + (this.statusScope || 'all') |
| | | window.open('/api/audit/export?' + q) |
| | | }, |
| | | review(row, status) { |
| | | if (status === 'IGNORED') { |
| | |
| | | </el-aside> |
| | | <el-main> |
| | | <h3>导å
¥æ°æ®æ¥ç</h3> |
| | | <el-form :inline="true"> |
| | | <el-form-item label="æ°æ®ç±»å"> |
| | | <el-radio-group v-model="type" @change="loadData"> |
| | | <el-radio-button label="h2032">H203-2ææ¥</el-radio-button> |
| | | <el-radio-button label="transportAuth">è¿æ¿è½¦è¾</el-radio-button> |
| | | <el-radio-button label="trackMileage">轨迹éç¨</el-radio-button> |
| | | <el-radio-button label="scaleSplit">è§ä¸è§ä¸æå</el-radio-button> |
| | | <el-radio-button label="freightTurnover">è´§è¿éå¨è½¬é</el-radio-button> |
| | | <el-radio-button label="h2031">H203-1æ
å®¢ææ¥</el-radio-button> |
| | | <el-radio-button label="passengerAuth">æ
å®¢è¿æ¿è½¦è¾</el-radio-button> |
| | | <el-radio-button label="cityBus">åå¸å
¬äº¤ææ¥</el-radio-button> |
| | | <el-radio-button label="cityTaxi">巡游åºç§ææ¥</el-radio-button> |
| | | <el-radio-button label="cityTaxiAuth">åºç§è½¦è¿æ¿è½¦è¾</el-radio-button> |
| | | <div class="type-row"> |
| | | <span class="type-label">æ°æ®ç±»å</span> |
| | | <el-radio-group v-model="activeModule" size="small" @change="onModuleChange"> |
| | | <el-radio-button v-for="g in modules" :key="g.key" :label="g.key">{{ g.name }}</el-radio-button> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-select v-model="type" size="small" style="width:300px" placeholder="éæ©æ°æ®ç±»å" @change="onTypeSelect"> |
| | | <el-option-group :label="activeTypes.name"> |
| | | <el-option v-for="t in activeTypes.types" :key="t.value" :label="t.label" :value="t.value"></el-option> |
| | | </el-option-group> |
| | | </el-select> |
| | | </div> |
| | | <el-form :inline="true" class="filter-row"> |
| | | <el-form-item label="æ¥è¡¨æ"> |
| | | <el-date-picker v-model="period" type="month" placeholder="å
¨é¨" value-format="yyyy-MM" clearable style="width:140px" @change="loadData"></el-date-picker> |
| | | </el-form-item> |
| | |
| | | <div class="table-wrap" ref="tableWrap"> |
| | | <div class="table-area"> |
| | | <el-table :data="records" border v-loading="loading" size="small" style="width:100%" height="100%"> |
| | | <el-table-column v-for="c in columns" :key="c.prop" :prop="c.prop" :label="c.label" :min-width="c.width" show-overflow-tooltip> |
| | | <el-table-column v-for="c in visibleColumns" :key="c.prop" :prop="c.prop" :label="c.label" :min-width="c.width" show-overflow-tooltip> |
| | | <template slot-scope="scope"> |
| | | <span>{{ formatCell(scope.row[c.prop]) }}</span> |
| | | </template> |
| | |
| | | name: 'DataView', |
| | | data() { |
| | | return { |
| | | modules: [ |
| | | { |
| | | key: 'freight', name: 'é路货è¿', types: [ |
| | | { value: 'h2032', label: 'é路货ç©è¿è¾æåº¦ç产æ
åµ' }, |
| | | { value: 'transportAuth', label: 'è¿æ¿è½¦è¾' }, |
| | | { value: 'trackMileage', label: '轨迹éç¨' }, |
| | | { value: 'scaleSplit', label: 'è§ä¸è§ä¸æå' }, |
| | | { value: 'freightTurnover', label: 'è´§è¿éå¨è½¬é' } |
| | | ] |
| | | }, |
| | | { |
| | | key: 'passenger', name: 'å
¬è·¯æ
客', types: [ |
| | | { value: 'h2031', label: 'å
¬è·¯æ
客è¿è¾æåº¦ç产æ
åµ' }, |
| | | { value: 'passengerAuth', label: 'è¿æ¿è½¦è¾æ°' } |
| | | ] |
| | | }, |
| | | { |
| | | key: 'city', name: 'åå¸å®¢è¿', types: [ |
| | | { value: 'cityBus', label: 'åå¸å
Œ
±äº¤éæåº¦è¿è¥æ
åµ' }, |
| | | { value: 'cityTaxi', label: '巡游åºç§æ±½è½¦è¿è¥æå¡æ
嵿æ¥' }, |
| | | { value: 'cityTaxiAuth', label: 'åºç§è½¦è¿æ¿è½¦è¾' } |
| | | ] |
| | | } |
| | | ], |
| | | activeModule: 'freight', |
| | | type: 'h2032', |
| | | period: '', |
| | | keyword: '', |
| | |
| | | loadingMore: false |
| | | } |
| | | }, |
| | | computed: { |
| | | activeTypes() { |
| | | const g = this.modules.find(x => x.key === this.activeModule) || this.modules[0] |
| | | return g |
| | | }, |
| | | visibleColumns() { |
| | | const hiddenProps = ['enterpriseCode', 'unifiedCreditCode', 'reportUnit'] |
| | | const hiddenLabels = ['ä¼ä¸ä»£ç ', 'ç»ä¸ç¤¾ä¼ä¿¡ç¨ä»£ç ', 'å¡«æ¥åä½'] |
| | | return (this.columns || []).filter(c => |
| | | hiddenProps.indexOf(c.prop) < 0 && hiddenLabels.indexOf(c.label) < 0) |
| | | } |
| | | }, |
| | | methods: { |
| | | onModuleChange(key) { |
| | | const g = this.modules.find(x => x.key === key) |
| | | if (!g || !g.types.length) return |
| | | if (!g.types.some(t => t.value === this.type)) { |
| | | this.type = g.types[0].value |
| | | } |
| | | this.loadData() |
| | | }, |
| | | onTypeSelect() { this.loadData() }, |
| | | loadData() { |
| | | this.loading = true |
| | | this.loadingMore = false |
| | |
| | | }).then(res => { |
| | | const d = res.data || {} |
| | | this.records = d.records || [] |
| | | this.columns = d.columns || [] |
| | | this.columns = (d.columns || []).filter(c => ['enterpriseCode', 'unifiedCreditCode', 'reportUnit'].indexOf(c.prop) < 0 && ['ä¼ä¸ä»£ç ', 'ç»ä¸ç¤¾ä¼ä¿¡ç¨ä»£ç ', 'å¡«æ¥åä½'].indexOf(c.label) < 0) |
| | | this.total = d.total || 0 |
| | | if (this.page > 1 && this.records.length === 0) { |
| | | this.page = 1 |
| | |
| | | this.records = this.records.concat(addRows) |
| | | this.page = nextPage |
| | | if (d.total != null) this.total = d.total |
| | | if (d.columns && d.columns.length) this.columns = d.columns |
| | | if (d.columns && d.columns.length) this.columns = d.columns.filter(c => ['enterpriseCode', 'unifiedCreditCode', 'reportUnit'].indexOf(c.prop) < 0 && ['ä¼ä¸ä»£ç ', 'ç»ä¸ç¤¾ä¼ä¿¡ç¨ä»£ç ', 'å¡«æ¥åä½'].indexOf(c.label) < 0) |
| | | }).catch(e => { |
| | | if (e && e._toast) return |
| | | this.$message.error('å è½½æ´å¤å¤±è´¥') |
| | |
| | | </script> |
| | | <style scoped> |
| | | .el-header { background: #409EFF; color: white; line-height: 60px; font-size: 18px; } |
| | | .type-row { margin-bottom: 10px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; } |
| | | .type-label { color: #606266; font-weight: 600; } |
| | | .filter-row { margin-bottom: 4px; } |
| | | #app .table-wrap { |
| | | display: flex; |
| | | flex-direction: column; |
| | |
| | | |
| | | <!-- 第äºè¡ï¼æ¥è¡¨ç±»å忢ï¼è´§è¿ / æ
客 / æèµ / è½è / åå¸å®¢è¿ï¼ï¼el-radio-group æ¿ä»£ el-tabsï¼è§é¿ el-tabs å¸å±æ é循ç¯ï¼ä¸ /import ä¿®å¤ä¸è´ï¼ --> |
| | | <el-radio-group v-model="activeKey" class="module-tabs"> |
| | | <el-radio-button v-for="m in modules" :key="m.key" :label="m.key"> |
| | | <el-radio-button v-for="m in visibleModules" :key="m.key" :label="m.key"> |
| | | {{ m.title }}<el-tag v-if="m.tag" size="mini" :type="m.tagType || 'info'" style="margin-left:6px">{{ m.tag }}</el-tag> |
| | | </el-radio-button> |
| | | </el-radio-group> |
| | |
| | | ], checked: [] |
| | | }, |
| | | { |
| | | key: 'freight', title: 'è´§è¿æ¥è¡¨', items: [ |
| | | key: 'freight', title: 'è´§è¿æ¥è¡¨', hidden: true, items: [ |
| | | { key: 'cityDetail', label: 'è´§è¿éåå¸å·æç»', fileName: 'çæ_è´§è¿éåå¸å·æç».xlsx', status: null, statusNote: '' }, |
| | | { key: 'freightRank', label: 'è´§è¿éæå', fileName: 'çæ_è´§è¿éæå.xlsx', status: null, statusNote: '' }, |
| | | { key: 'turnoverRank', label: 'å¨è½¬éæå', fileName: 'çæ_å¨è½¬éæå.xlsx', status: null, statusNote: '' } |
| | | ], checked: [] |
| | | }, |
| | | { |
| | | key: 'passenger', title: 'æ
客æ¥è¡¨', items: [ |
| | | key: 'passenger', title: 'æ
客æ¥è¡¨', hidden: true, items: [ |
| | | { key: 'passengerCityDetail', label: 'å
¬è·¯æ
客åå¸å·', fileName: 'çæ_å
¬è·¯æ
客åå¸å·.xlsx', status: null, statusNote: '' }, |
| | | { key: 'passengerMidDetail', label: 'ä¸å£å¾æç»', fileName: 'çæ_å
¬è·¯æ
客ä¸å£å¾æç».xlsx', status: null, statusNote: '' }, |
| | | { key: 'passengerMidRank', label: 'ä¸å£å¾æå', fileName: 'çæ_å
¬è·¯æ
客ä¸å£å¾æå.xlsx', status: null, statusNote: '' }, |
| | | { key: 'passengerMidAnalysis', label: 'ä¸å£å¾åæ', fileName: 'çæ_å
¬è·¯æ
客ä¸å£å¾åæ.xlsx', status: null, statusNote: '' } |
| | | ], checked: [] |
| | | }, { |
| | | key: 'cityPassenger', title: 'åå¸å®¢è¿æ¥è¡¨', items: [ |
| | | key: 'cityPassenger', title: 'åå¸å®¢è¿æ¥è¡¨', hidden: true, items: [ |
| | | { key: 'cityBusDetail', label: 'åå¸å
¬äº¤å®¢è¿éåå¸å·æç»', fileName: 'çæ_åå¸å
¬äº¤å®¢è¿éåå¸å·æç».xlsx', status: null, statusNote: '' }, |
| | | { key: 'cityTaxiDetail', label: '巡游åºç§å®¢è¿éåå¸å·æç»', fileName: 'çæ_巡游åºç§å®¢è¿éåå¸å·æç».xlsx', status: null, statusNote: '' }, |
| | | { key: 'cityRailFerryDetail', label: '轨é轮渡客è¿éåå¸å·æç»', fileName: 'çæ_轨é轮渡客è¿éåå¸å·æç».xlsx', status: null, statusNote: '' }, |
| | |
| | | const s = sessionStorage.getItem('modules') |
| | | if (!s) return [] |
| | | return s.split(',').filter(Boolean) |
| | | }, |
| | | visibleModules() { |
| | | return this.modules.filter(m => !m.hidden) |
| | | }, |
| | | curModule() { |
| | | return this.modules.find(m => m.key === this.activeKey) || this.modules[0] |
| | |
| | | } |
| | | }, |
| | | created() { |
| | | const mine = this.myModules.filter(k => this.modules.some(m => m.key === k)) |
| | | this.activeKey = (mine.length ? mine : this.modules.map(m => m.key))[0] |
| | | const mine = this.myModules.filter(k => this.visibleModules.some(m => m.key === k)) |
| | | this.activeKey = (mine.length ? mine : this.visibleModules.map(m => m.key))[0] |
| | | this.ensureCycle() |
| | | this.refreshAll() |
| | | }, methods: { |