| | |
| | | /** ä¸å£å¾æåæ¯ï¼k=-1 表示æ»è¡ï¼ç线+å
¬äº¤+åºç§å乡+ç½çº¦è½¦å乡 å项ä¹åï¼ï¼æ å»å¹´æ°æ®ç空 */ |
| | | private void fillMidYoyCell(Cell c, Map<Integer, Map<String, double[][]>> mid, int year, int month, |
| | | String area, int k, boolean volume) { |
| | | double v = 0.0, lv = 0.0; |
| | | if (k == -1) { |
| | | for (int kk = 1; kk <= 4; kk++) { |
| | | v += midClassVal(mid, year, month, area, kk, volume); |
| | | lv += midClassVal(mid, year - 1, month, area, kk, volume); |
| | | } |
| | | } else { |
| | | v = midClassVal(mid, year, month, area, k, volume); |
| | | lv = midClassVal(mid, year - 1, month, area, k, volume); |
| | | } |
| | | Double y = midMonthYoy(mid, year, month, area, k, volume); |
| | | c.setBlank(); |
| | | if (v != 0.0 && lv != 0.0) c.setCellValue(round((v - lv) / lv, 4)); |
| | | if (y != null) c.setCellValue(y); |
| | | } |
| | | |
| | | /** ä¸å£å¾ç´¯è®¡åæ¯åï¼1..months æç´¯è®¡ï¼åç»´é½å
¨ï¼ */ |
| | |
| | | if (blockOffset < 0 || blockOffset % 5 == 0) continue; |
| | | int k = blockOffset % 5; |
| | | String area = areas.get(blockOffset / 5); |
| | | double v = 0.0, lv = 0.0; |
| | | for (int m = 1; m <= months; m++) { |
| | | { |
| | | v += midClassVal(mid, year, m, area, k, volume); |
| | | lv += midClassVal(mid, year - 1, m, area, k, volume); |
| | | } |
| | | } |
| | | Double y = midCumYoy(mid, year, area, months, k, volume); |
| | | Row row = sheet.getRow(r0); |
| | | if (row == null) continue; |
| | | Cell c = row.getCell(colIdx); |
| | | if (c == null) c = row.createCell(colIdx); |
| | | c.setBlank(); |
| | | if (v != 0.0 && lv != 0.0) c.setCellValue(round((v - lv) / lv, 4)); |
| | | if (y != null) c.setCellValue(y); |
| | | } |
| | | } |
| | | |
| | |
| | | return volume ? arr[k][0] : arr[k][1]; |
| | | } |
| | | |
| | | /** B3ï¼ç»è®°ã该æè¯¥å¸å·è¯¥ç»´åº¦ææºè¡ãã夿®æ¯æºè¡¨ææ²¡æè¿ä¸è¡ï¼è䏿¯ç®åºæ¥ç弿¯å¦é 0 |
| | | * ââå 为ãå¼ä¸º 0ãå¯è½æ¯çå®ä¸å¡ï¼å¦æ¦æ±å¸å·¡æ¸¸åºç§å
¨é¨ä¸ºåå¸å
ï¼åé
å乡æä¸º 0ï¼ã */ |
| | | private void markMid(Map<Integer, Map<String, boolean[]>> pres, int key, String city, int k) { |
| | | pres.computeIfAbsent(key, kk -> new HashMap<>()) |
| | | .computeIfAbsent(city, kk -> new boolean[5])[k] = true; |
| | | } |
| | | |
| | | /** |
| | | * B3ï¼è¯¥æè¯¥ç»´åº¦æ¯å¦ãææºãï¼åæ¯å®å¤æ§æ ¡éªç¨ï¼ã |
| | | * k <= 0 è¡¨ç¤ºãæ»éè¡ãï¼è¦æ±åç»´ï¼ç线/å
¬äº¤/åºç§/ç½çº¦è½¦ï¼é½ææºæç®é½å
¨ã |
| | | */ |
| | | private boolean midMonthHas(Map<Integer, Map<String, double[][]>> mid, int year, int month, String area, int k, boolean volume) { |
| | | Map<String, boolean[]> pm = midPresence.get().get(year * 100 + month); |
| | | if (pm == null) return false; |
| | | boolean[] b = pm.get(area); |
| | | if (b == null) return false; |
| | | if (k <= 0) { |
| | | for (int kk = 1; kk <= 4; kk++) { |
| | | if (!b[kk]) return false; |
| | | } |
| | | return true; |
| | | } |
| | | return k < b.length && b[k]; |
| | | } |
| | | |
| | | /** B3ï¼å»å¹´ 1..monthCount æçå½ä¸æä»½æ°ï¼ç¨äºå¤å®åæ¯åºæ°æ¯å¦é½å
¨ï¼ */ |
| | | private int midCumHitMonths(Map<Integer, Map<String, double[][]>> mid, int year, String area, int monthCount, int k, boolean volume) { |
| | | int n = 0; |
| | | for (int m = 1; m <= monthCount; m++) { |
| | | if (midMonthHas(mid, year, m, area, k, volume)) n++; |
| | | } |
| | | return n; |
| | | } |
| | | |
| | | /** B3ï¼å½æåæ¯ââå»å¹´åæåºæ°ç¼ºå¤±åç空ï¼ç¼ºæ°æ®ä¸åå½ 0 计ç®ï¼ */ |
| | | private Double midMonthYoy(Map<Integer, Map<String, double[][]>> mid, int year, int month, String area, int k, boolean volume) { |
| | | if (!midMonthHas(mid, year - 1, month, area, k, volume)) return null; |
| | | double v = midClassVal(mid, year, month, area, k, volume); |
| | | if (v == 0.0) return null; |
| | | return yoyOf(v, midClassVal(mid, year - 1, month, area, k, volume)); |
| | | } |
| | | |
| | | /** B3ï¼ç´¯è®¡åæ¯ââå»å¹´ 1..monthCount åæé½å
¨æè®¡ç®ï¼ç¼ºä»»ä½ä¸æä¸å¾ç空 */ |
| | | private Double midCumYoy(Map<Integer, Map<String, double[][]>> mid, int year, String area, int monthCount, int k, boolean volume) { |
| | | if (midCumHitMonths(mid, year - 1, area, monthCount, k, volume) < monthCount) return null; |
| | | double v = midCumClass(mid, year, area, monthCount, k, volume); |
| | | if (v == 0.0) return null; |
| | | return yoyOf(v, midCumClass(mid, year - 1, area, monthCount, k, volume)); |
| | | } |
| | | |
| | | /** å
¬å¼åå
æ ¼æ¿æ¢ä¸ºç¼åæ°å¼ï¼é¿å
跨簿å¼ç¨æé¾ï¼éæ°å¼ç¼åç½®ç©ºï¼ */ |
| | | private void keepCached(Cell c) { |
| | | try { |
| | |
| | | * ä¸å£å¾åç±»æåº¦æ°æ®ï¼å¹´*100+æ -> (å¸å·/å
¨ç -> double[5][2]) |
| | | * 维度 0=æ»é 1=å
¬è·¯ç线(h2031+个ä½) 2=åé
å乡å
¬äº¤(cityBus) 3=巡游åºç§ 4=ç½çº¦è½¦ï¼[客è¿é(ä¸äºº), å¨è½¬é(ä¸äººå
Ž)] |
| | | */ |
| | | /** B3ï¼æè¿ä¸æ¬¡ loadMidClassMap çã维度æ¯å¦ææºè¡ãç»è®°è¡¨ï¼key -> city -> boolean[5]ï¼ï¼ç¨äºåæ¯å®å¤æ§æ ¡éª */ |
| | | private final ThreadLocal<Map<Integer, Map<String, boolean[]>>> midPresence = |
| | | ThreadLocal.withInitial(HashMap::new); |
| | | |
| | | /** B4/B5ï¼æè¿ä¸æ¬¡ loadMidClassMap çæ°æ®é®é¢æ¸
åï¼çº¿ç¨å
ï¼é导åºä½æ£è¾åº/åçæä»¶ï¼ */ |
| | | private final ThreadLocal<java.util.List<String>> midIssues = ThreadLocal.withInitial(java.util.ArrayList::new); |
| | | |
| | | /** B4/B5ï¼åæè¿ä¸æ¬¡ä¸å£å¾æ°æ®å è½½çé®é¢æ¸
åï¼åªè¯»å¯æ¬ï¼ */ |
| | | public java.util.List<String> getLastMidIssues() { return new java.util.ArrayList<>(midIssues.get()); } |
| | | |
| | | private Map<Integer, Map<String, double[][]>> loadMidClassMap() { |
| | | midIssues.get().clear(); // B5ï¼æ¬æ¬¡å è½½çé®é¢æ¸
å |
| | | Map<Integer, Map<String, boolean[]>> pres = new HashMap<>(); |
| | | midPresence.set(pres); // B3ï¼æ¬æ¬¡å è½½çç»´åº¦ææºç»è®° |
| | | Map<Integer, Map<String, double[][]>> mid = new HashMap<>(); |
| | | for (PassengerEnterpriseMonthly e : passengerMapper.selectList(null)) { |
| | | if (e.getReportPeriod() == null) continue; |
| | |
| | | + nz(e.getTurnoverClass4()) + nz(e.getTurnoverCharter())) / 10000.0; |
| | | addMidClass(mid, key, city, 1, pass, turn); |
| | | addMidClass(mid, key, "æ¹åç", 1, pass, turn); |
| | | markMid(pres, key, city, 1); |
| | | markMid(pres, key, "æ¹åç", 1); |
| | | } |
| | | for (PassengerIndividualMonthly e : passengerIndividualMapper.selectList(null)) { // 个ä½å¹¶å
¥å
¬è·¯ç线/æ»éï¼09-03 å£å¾ï¼ |
| | | if (e.getReportPeriod() == null) continue; |
| | |
| | | double turn = nz(e.getTurnover()) / 10000.0; |
| | | addMidClass(mid, key, city, 1, pass, turn); |
| | | addMidClass(mid, key, "æ¹åç", 1, pass, turn); |
| | | markMid(pres, key, city, 1); |
| | | markMid(pres, key, "æ¹åç", 1); |
| | | } |
| | | for (CityBusMonthly b : cityBusMapper.selectList(null)) { |
| | | if (b.getReportPeriod() == null || b.getCity() == null) continue; |
| | |
| | | String city = RegionUtil.normalizeCityName(b.getCity()); |
| | | if (city == null) continue; |
| | | int key = y * 100 + m; |
| | | addMidClass(mid, key, city, 2, nz(b.getPassengerChengxiang()), nz(b.getTurnoverChengxiang())); |
| | | addMidClass(mid, key, "æ¹åç", 2, nz(b.getPassengerChengxiang()), nz(b.getTurnoverChengxiang())); |
| | | // B1 å
åºï¼åå¨çãåé
å乡ã缺失(<=0)æ¶ç¨ãæ»å®¢è¿é â åå¸å
ãç°ç®ï¼é¿å
2025 å
¨å¹´å
¬äº¤ç»´åº¦è¢«å½æ 0 |
| | | double cxPass = nz(b.getPassengerChengxiang()); |
| | | if (cxPass <= 0) cxPass = nz(b.getPassengerVolume()) - nz(b.getPassengerCity()); |
| | | double cxTurn = nz(b.getTurnoverChengxiang()); |
| | | if (cxTurn <= 0) cxTurn = nz(b.getTurnover()) - nz(b.getTurnoverCity()); |
| | | if (cxPass < 0) cxPass = 0.0; |
| | | if (cxTurn < 0) cxTurn = 0.0; |
| | | addMidClass(mid, key, city, 2, cxPass, cxTurn); |
| | | addMidClass(mid, key, "æ¹åç", 2, cxPass, cxTurn); |
| | | markMid(pres, key, city, 2); |
| | | markMid(pres, key, "æ¹åç", 2); |
| | | } |
| | | // 维度3ï¼åé
å乡巡游åºç§ = å°è´¦é¡µãåºç§!æ»é â åºç§!åå¸å
ãï¼æº city_taxi_monthlyï¼ |
| | | for (CityTaxiMonthly t : cityTaxiMapper.selectList(null)) { |
| | |
| | | double turn = nz(t.getTurnover()) - nz(t.getTurnoverCity()); |
| | | addMidClass(mid, key, city, 3, pass, turn); |
| | | addMidClass(mid, key, "æ¹åç", 3, pass, turn); |
| | | markMid(pres, key, city, 3); |
| | | markMid(pres, key, "æ¹åç", 3); |
| | | } |
| | | // 维度4ï¼åé
å乡ç½çº¦è½¦ = ç½çº¦è½¦æåç»æï¼ä¸å°è´¦ãç½çº¦è½¦ãé¡µåæºåæ³ï¼ |
| | | for (WycOrderMonthly o : wycOrderMapper.selectList(null)) { |
| | |
| | | try { |
| | | wr = wycSplitCalc.calc(per); |
| | | } catch (Exception e) { |
| | | continue; // 该æç¼ºè®¢å/pin æåºç§æºæ°æ®ï¼è·³è¿ï¼ä¸å½±åå
¶å®æï¼ |
| | | // B5ï¼ä¸åéé»è·³è¿ââè®°å½ãæ + åå ã并忥å¿ï¼é导åºä½æ£ä¸å¹¶è¾åº |
| | | String msg = per + " ç½çº¦è½¦åé
å乡维度缺失ï¼" + e.getMessage(); |
| | | midIssues.get().add(msg); |
| | | log.warn("loadMidClassMap {}", msg); |
| | | continue; |
| | | } |
| | | for (Map.Entry<String, WycSplitCalc.WycMetrics> en : wr.getByCity().entrySet()) { |
| | | WycSplitCalc.WycMetrics wm = en.getValue(); |
| | | addMidClass(mid, key, en.getKey(), 4, wm.getSuburbanPax(), wm.getSuburbanTurnover()); |
| | | addMidClass(mid, key, "æ¹åç", 4, wm.getSuburbanPax(), wm.getSuburbanTurnover()); |
| | | markMid(pres, key, en.getKey(), 4); |
| | | markMid(pres, key, "æ¹åç", 4); |
| | | } |
| | | } |
| | | return mid; |
| | |
| | | title.getCell(10).setCellValue(currentYear + "å¹´" + maxMonth + "æå
¨çåå¸å·å®æé路客è¿ç产æ
åµ"); |
| | | } |
| | | // å
¨çè¡ r3ï¼B3/F3 为 SUM å
¬å¼ä¿çï¼D3/H3 忝填å¼ï¼0-based å 3/7ï¼ |
| | | setValOrBlank(sheet, 2, 3, yoyOf(midCumClass(mid, currentYear, "æ¹åç", maxMonth, 0, true), |
| | | midCumClass(mid, currentYear - 1, "æ¹åç", maxMonth, 0, true))); |
| | | setValOrBlank(sheet, 2, 7, yoyOf(midCumClass(mid, currentYear, "æ¹åç", maxMonth, 0, false), |
| | | midCumClass(mid, currentYear - 1, "æ¹åç", maxMonth, 0, false))); |
| | | setValOrBlank(sheet, 2, 3, midCumYoy(mid, currentYear, "æ¹åç", maxMonth, 0, true)); |
| | | setValOrBlank(sheet, 2, 7, midCumYoy(mid, currentYear, "æ¹åç", maxMonth, 0, false)); |
| | | // å³åå
¨çè¡ N3/R3ï¼å½æåæ¯ï¼L3/P3 为 SUM å
¬å¼ä¿çï¼ |
| | | setValOrBlank(sheet, 2, 13, yoyOf(midClassVal(mid, currentYear, maxMonth, "æ¹åç", 0, true), |
| | | midClassVal(mid, currentYear - 1, maxMonth, "æ¹åç", 0, true))); |
| | | setValOrBlank(sheet, 2, 17, yoyOf(midClassVal(mid, currentYear, maxMonth, "æ¹åç", 0, false), |
| | | midClassVal(mid, currentYear - 1, maxMonth, "æ¹åç", 0, false))); |
| | | setValOrBlank(sheet, 2, 13, midMonthYoy(mid, currentYear, maxMonth, "æ¹åç", 0, true)); |
| | | setValOrBlank(sheet, 2, 17, midMonthYoy(mid, currentYear, maxMonth, "æ¹åç", 0, false)); |
| | | // å¸å·è¡ r4-20ï¼B/F 累计å¼ãD/H 忝ï¼C/E/G/I æåå
¬å¼ä¿ç |
| | | List<String> cities = RegionUtil.CITY_LIST; |
| | | for (int i = 0; i < cities.size(); i++) { |
| | |
| | | double lastPass = midCumClass(mid, currentYear - 1, city, maxMonth, 0, true); |
| | | double lastTurn = midCumClass(mid, currentYear - 1, city, maxMonth, 0, false); |
| | | setValOrBlank(sheet, r0, 1, pass == 0 ? null : round(pass, 4)); |
| | | setValOrBlank(sheet, r0, 3, yoyOf(pass, lastPass)); |
| | | setValOrBlank(sheet, r0, 3, midCumYoy(mid, currentYear, city, maxMonth, 0, true)); |
| | | setValOrBlank(sheet, r0, 5, turn == 0 ? null : round(turn, 4)); |
| | | setValOrBlank(sheet, r0, 7, yoyOf(turn, lastTurn)); |
| | | setValOrBlank(sheet, r0, 7, midCumYoy(mid, currentYear, city, maxMonth, 0, false)); |
| | | // å³å彿ï¼L/P å¼ãN/R 彿忝ï¼M/O/Q/S æåå
¬å¼ä¿çï¼ |
| | | double mPass = midClassVal(mid, currentYear, maxMonth, city, 0, true); |
| | | double mTurn = midClassVal(mid, currentYear, maxMonth, city, 0, false); |
| | | double mLastPass = midClassVal(mid, currentYear - 1, maxMonth, city, 0, true); |
| | | double mLastTurn = midClassVal(mid, currentYear - 1, maxMonth, city, 0, false); |
| | | setValOrBlank(sheet, r0, 11, mPass == 0 ? null : round(mPass, 4)); |
| | | setValOrBlank(sheet, r0, 13, mPass == 0 ? null : yoyOf(mPass, mLastPass)); |
| | | setValOrBlank(sheet, r0, 13, mPass == 0 ? null : midMonthYoy(mid, currentYear, maxMonth, city, 0, true)); |
| | | setValOrBlank(sheet, r0, 15, mTurn == 0 ? null : round(mTurn, 4)); |
| | | setValOrBlank(sheet, r0, 17, mTurn == 0 ? null : yoyOf(mTurn, mLastTurn)); |
| | | setValOrBlank(sheet, r0, 17, mTurn == 0 ? null : midMonthYoy(mid, currentYear, maxMonth, city, 0, false)); |
| | | } |
| | | recalc(wb); |
| | | return toBytes(wb); |
| | |
| | | double lastPass = midCumClass(mid, currentYear - 1, "æ¹åç", maxMonth, dims[i], true); |
| | | double lastTurn = midCumClass(mid, currentYear - 1, "æ¹åç", maxMonth, dims[i], false); |
| | | setValOrBlank(sheet, r0, 1, pass == 0 ? null : round(pass, 4)); |
| | | setValOrBlank(sheet, r0, 2, yoyOf(pass, lastPass)); |
| | | setValOrBlank(sheet, r0, 2, midCumYoy(mid, currentYear, "æ¹åç", maxMonth, dims[i], true)); |
| | | setValOrBlank(sheet, r0, 5, turn == 0 ? null : round(turn, 4)); |
| | | setValOrBlank(sheet, r0, 6, yoyOf(turn, lastTurn)); |
| | | setValOrBlank(sheet, r0, 6, midCumYoy(mid, currentYear, "æ¹åç", maxMonth, dims[i], false)); |
| | | } |
| | | // ä¸ååï¼å½æï¼ï¼æ é¢è¡9ãæ°æ®è¡11-15ï¼0-based 8ã10-14ï¼ |
| | | Row bottomTitle = sheet.getRow(8); |
| | |
| | | double lastPass = midClassVal(mid, currentYear - 1, maxMonth, "æ¹åç", dims[i], true); |
| | | double lastTurn = midClassVal(mid, currentYear - 1, maxMonth, "æ¹åç", dims[i], false); |
| | | setValOrBlank(sheet, r0, 1, pass == 0 ? null : round(pass, 4)); |
| | | setValOrBlank(sheet, r0, 2, pass == 0 ? null : yoyOf(pass, lastPass)); |
| | | setValOrBlank(sheet, r0, 2, pass == 0 ? null : midMonthYoy(mid, currentYear, maxMonth, "æ¹åç", dims[i], true)); |
| | | setValOrBlank(sheet, r0, 5, turn == 0 ? null : round(turn, 4)); |
| | | setValOrBlank(sheet, r0, 6, turn == 0 ? null : yoyOf(turn, lastTurn)); |
| | | setValOrBlank(sheet, r0, 6, turn == 0 ? null : midMonthYoy(mid, currentYear, maxMonth, "æ¹åç", dims[i], false)); |
| | | } |
| | | // ä¸ååå æ¯å
¬å¼ç±æ ·ä¾æåä¸ååï¼B$3/F$3ï¼ï¼æ¹å为æ¬åæ»è¡ï¼B$11/F$11ï¼ï¼è¡12-15 |
| | | for (int i = 1; i < names.length; i++) { |
| | |
| | | case "investFiveYearLogistics": return investFiveYearLogistics(period, mode); |
| | | case "investBillion": return investBillion(period, mode); |
| | | case "investCounty": return investCounty(period, mode); |
| | | case "investPassengerDetail": return exportInvestPassengerDetail(period, mode); |
| | | case "investLogisticsDetail": return exportInvestLogisticsDetail(period, mode); |
| | | case "cityBusDetail": return exportCityBusDetail(period, mode); |
| | | case "cityTaxiDetail": return exportCityTaxiDetail(period, mode); |
| | | case "cityRailFerryDetail": return exportCityRailFerryDetail(period, mode); |
| | |
| | | REPORT_FILE_NAMES.put("investFiveYearLogistics", "çæ_åäºäºè§åç©æµé¡¹ç®è¿å±æ
åµ.xls"); |
| | | REPORT_FILE_NAMES.put("investBillion", "çæ_æ¹åçï¼å®¢è´§ç«åºï¼äº¿å
æèµé¡¹ç®.xls"); |
| | | REPORT_FILE_NAMES.put("investCounty", "çæ_ç»æµå¼ºå¿äº¤éç©æµåºç¡è®¾æ½æèµç»è®¡æ¥è¡¨.xls"); |
| | | REPORT_FILE_NAMES.put("investPassengerDetail", "çæ_客è¿ç«æèµæç»è¡¨.xlsx"); |
| | | REPORT_FILE_NAMES.put("investLogisticsDetail", "çæ_ç©æµç«åºæèµæç».xls"); |
| | | REPORT_FILE_NAMES.put("cityBusDetail", "çæ_åå¸å
¬äº¤å®¢è¿éåå¸å·æç».xlsx"); |
| | | REPORT_FILE_NAMES.put("cityTaxiDetail", "çæ_巡游åºç§å®¢è¿éåå¸å·æç».xlsx"); |
| | | REPORT_FILE_NAMES.put("cityRailFerryDetail", "çæ_轨é轮渡客è¿éåå¸å·æç».xlsx"); |
| | |
| | | } |
| | | |
| | | |
| | | |
| | | // ==================== æèµæ¨¡åï¼å®¢è¿ç«æèµæç»è¡¨ / ç©æµç«åºæèµæç»ï¼æ¨¡æ¿åºç¨¿å使¿æ¢ï¼ ==================== |
| | | |
| | | /** ç©æµç«åºæç»è¡¨æ¨¡æ¿ä¸çå¸å·å°èçå -> åºå
è§èå
¨å */ |
| | | private static final Map<String, String> LOGI_CITY_LABELS = new LinkedHashMap<>(); |
| | | static { |
| | | LOGI_CITY_LABELS.put("æ¦æ±", "æ¦æ±å¸"); |
| | | LOGI_CITY_LABELS.put("é»ç³", "é»ç³å¸"); |
| | | LOGI_CITY_LABELS.put("åå °", "åå °å¸"); |
| | | LOGI_CITY_LABELS.put("宿", "宿å¸"); |
| | | LOGI_CITY_LABELS.put("è¥é³", "è¥é³å¸"); |
| | | LOGI_CITY_LABELS.put("éå·", "éå·å¸"); |
| | | LOGI_CITY_LABELS.put("èé¨", "èé¨å¸"); |
| | | LOGI_CITY_LABELS.put("åæ", "åæå¸"); |
| | | LOGI_CITY_LABELS.put("èå·", "èå·å¸"); |
| | | LOGI_CITY_LABELS.put("é»å", "é»åå¸"); |
| | | LOGI_CITY_LABELS.put("å¸å®", "å¸å®å¸"); |
| | | LOGI_CITY_LABELS.put("éå·", "éå·å¸"); |
| | | LOGI_CITY_LABELS.put("æ©æ½", "æ©æ½å·"); |
| | | LOGI_CITY_LABELS.put("仿¡", "仿¡å¸"); |
| | | LOGI_CITY_LABELS.put("æ½æ±", "æ½æ±å¸"); |
| | | LOGI_CITY_LABELS.put("天é¨", "天é¨å¸"); |
| | | LOGI_CITY_LABELS.put("æåº", "ç¥åæ¶æåº"); |
| | | } |
| | | |
| | | /** 该æåé¡¹ç®æåº¦æ°æ®ï¼projectId -> InvestmentMonthly */ |
| | | private Map<Long, InvestmentMonthly> investMonthlyOf(String period) { |
| | | Map<Long, InvestmentMonthly> map = new HashMap<>(); |
| | | for (InvestmentMonthly m : investMonthlyMapper.selectList( |
| | | new LambdaQueryWrapper<InvestmentMonthly>().eq(InvestmentMonthly::getReportPeriod, period))) { |
| | | map.put(m.getProjectId(), m); |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | /** ååå
æ ¼æ°å¼ï¼ä¿çæ ·å¼/åå¹¶ï¼ï¼null æ¸
空 */ |
| | | private void putNum(Row row, int idx, Double v) { |
| | | if (row == null) return; |
| | | Cell c = row.getCell(idx); |
| | | if (c == null) c = row.createCell(idx); |
| | | c.setBlank(); |
| | | if (v != null) c.setCellValue(v); |
| | | } |
| | | |
| | | /** ååå
æ ¼ææ¬ï¼ä¿çæ ·å¼/åå¹¶ï¼ï¼ç©ºä¸²æ¸
空 */ |
| | | private void putText(Row row, int idx, String v) { |
| | | if (row == null) return; |
| | | Cell c = row.getCell(idx); |
| | | if (c == null) c = row.createCell(idx); |
| | | c.setBlank(); |
| | | if (v != null && !v.trim().isEmpty()) c.setCellValue(v.trim()); |
| | | } |
| | | |
| | | /** 读åå
æ ¼æ°å¼ï¼ç©º/éæ°å¼/å
¬å¼æ ç¼åä¸å¾ 0ï¼ */ |
| | | private double numOf(Cell c) { |
| | | if (c == null) return 0.0; |
| | | try { |
| | | if (c.getCellType() == CellType.NUMERIC || c.getCellType() == CellType.FORMULA) { |
| | | return c.getNumericCellValue(); |
| | | } |
| | | String s = cellText(c); |
| | | if (s == null) return 0.0; |
| | | s = s.replace(",", "").trim(); |
| | | return s.isEmpty() ? 0.0 : Double.parseDouble(s); |
| | | } catch (Exception e) { |
| | | return 0.0; |
| | | } |
| | | } |
| | | |
| | | /** æ¨¡æ¿æ é¢éçãï¼Næææ¥ï¼ããï¼Næï¼ãæ¹ä¸ºæ¥è¡¨ææä»½ */ |
| | | private void fixInvestMonthTitle(Sheet sheet, int rowIdx, int colIdx, int month) { |
| | | Row row = sheet.getRow(rowIdx); |
| | | if (row == null) return; |
| | | String t = cellText(row.getCell(colIdx)); |
| | | if (t == null) return; |
| | | String nv = t.replaceAll("ï¼\\d+æææ¥ï¼", "ï¼" + month + "æææ¥ï¼") |
| | | .replaceAll("ï¼\\d+æï¼", "ï¼" + month + "æï¼"); |
| | | if (!nv.equals(t)) putText(row, colIdx, nv); |
| | | } |
| | | |
| | | /** 模æ¿è¡ A 忝å¦ä¸ºãä¸äºä¸åããæ¸ éåç»æ é¢ */ |
| | | private boolean isInvestChannelLabel(String a) { |
| | | return a != null && a.matches("^[ä¸äºä¸åäºå
ä¸å
«ä¹å]+ã.*"); |
| | | } |
| | | |
| | | /** |
| | | * çæ_Xæå®¢è¿ç«æèµæç»è¡¨.xlsxï¼æ¨¡æ¿ï¼docs/æèµ/模æ¿/模æ¿_Xæå®¢è¿ç«æèµæç»è¡¨.xlsxï¼sheetï¼æç» + æ±æ»ï¼ã |
| | | * å£å¾ï¼æ¨¡æ¿å³ä¸æå°è´¦åºç¨¿ï¼æ¬æåªè¦çãåºå
æè¯¥ææ°æ®ãç项ç®è¡ |
| | | * ï¼Hèªå¼å§å»ºè®¾ç´¯è®¡ / Iæ¬å¹´è®¡å / Jèªå¹´å累计 / Kæ¬æå®æ / Lå»ºè®¾é¶æ®µ / M形象è¿åº¦ï¼ï¼ |
| | | * åºå
æ 该æç项ç®è¡ä¿çæ¯çåå¼ï¼çå人工ã䏿ç»è½¬ + æ¬ææ´æ°ãï¼ï¼ |
| | | * åå¸/æ¸ é/åè®¡è¡æ²¿ç¨æ¨¡æ¿ SUM å
¬å¼ï¼é表å
æ°å¼èªå¨éç®ã |
| | | */ |
| | | public byte[] exportInvestPassengerDetail(String period, String mode) throws Exception { |
| | | int year = Integer.parseInt(period.split("-")[0]); |
| | | int month = monthOf(period, mode); |
| | | List<InvestmentProject> projects = investProjectMapper.selectList( |
| | | new LambdaQueryWrapper<InvestmentProject>().eq(InvestmentProject::getCategory, "客è¿ç«åº")); |
| | | Map<Long, InvestmentMonthly> mByProject = investMonthlyOf(period); |
| | | File tpl = resolveAnyTemplate(investTemplateDir, "模æ¿_Xæå®¢è¿ç«æèµæç»è¡¨.xlsx"); |
| | | try (InputStream in = new FileInputStream(tpl); |
| | | XSSFWorkbook wb = new XSSFWorkbook(in)) { |
| | | Sheet sheet = wb.getSheet("æç»"); |
| | | if (sheet == null) throw new RuntimeException("模æ¿ã模æ¿_Xæå®¢è¿ç«æèµæç»è¡¨.xlsxã缺å°ãæç»ãå·¥ä½è¡¨"); |
| | | fixInvestMonthTitle(sheet, 0, 1, month); |
| | | String curCity = null; |
| | | Set<Long> used = new HashSet<>(); |
| | | int filled = 0, kept = 0, dup = 0; |
| | | for (int r = 8; r <= sheet.getLastRowNum(); r++) { |
| | | Row row = sheet.getRow(r); |
| | | if (row == null) continue; |
| | | String a = nvl(cellText(row.getCell(0))); |
| | | String b = nvl(cellText(row.getCell(1))); |
| | | if (isCityLabel(a)) { curCity = templateCityFull(a); continue; } |
| | | if (isInvestChannelLabel(a)) continue; |
| | | if (a.contains("å计") || a.contains("æ»è®¡")) continue; |
| | | if (!a.matches("\\d+(\\.\\d+)?")) continue; |
| | | if (b.isEmpty() || curCity == null) continue; |
| | | InvestmentProject p = matchInvest(projects, b, curCity, "客è¿ç«åº", used); |
| | | InvestmentMonthly m = p == null ? null : mByProject.get(p.getId()); |
| | | if (p == null || m == null) { |
| | | kept++; |
| | | // æåºå
项ç®ä½å½ææ æ°æ® â 记为å¾
æ ¸å¯¹ï¼æ å¹é
é¡¹ç® â ç»è½¬ä¸æ |
| | | if (p != null) dup++; |
| | | continue; |
| | | } |
| | | used.add(p.getId()); |
| | | // å£å¾ï¼ç¨æ· 2026-09-18 确认ï¼ï¼åªè¦ç人工ä¼éææ¥æ´æ°çååââ |
| | | // H èªå¼å§å»ºè®¾ç´¯è®¡ / J èªå¹´å累计 / K æ¬æå®æ / M 形象è¿åº¦ï¼ |
| | | // I æ¬å¹´è®¡åæèµãL å»ºè®¾é¶æ®µãG è®¡åæ»æèµä¸ºçå®/æ¯çå£å¾ï¼ä¸å¾ä¸å¨ï¼åºå
为空åä¿çæ¯çåå¼ |
| | | if (m.getStartCum() != null) putNum(row, 7, m.getStartCum()); |
| | | if (m.getYearCum() != null) putNum(row, 9, m.getYearCum()); |
| | | if (m.getMonthDone() != null) putNum(row, 10, m.getMonthDone()); |
| | | if (m.getProgressDesc() != null && !m.getProgressDesc().trim().isEmpty()) putText(row, 12, m.getProgressDesc()); |
| | | filled++; |
| | | } |
| | | Sheet sumSheet = wb.getSheet("æ±æ»"); |
| | | if (sumSheet != null) { |
| | | Row r2 = sumSheet.getRow(1); |
| | | if (r2 != null) { |
| | | Cell c = r2.getCell(0); |
| | | if (c == null) c = r2.createCell(0); |
| | | c.setBlank(); |
| | | c.setCellValue(java.time.LocalDate.of(year, month, 1).atStartOfDay()); |
| | | } |
| | | } |
| | | try { |
| | | wb.getCreationHelper().createFormulaEvaluator().evaluateAll(); |
| | | } catch (Exception e) { |
| | | log.warn("客è¿ç«æèµæç»è¡¨å
¬å¼æ±å¼å¤±è´¥: {}", e.getMessage()); |
| | | } |
| | | log.info("客è¿ç«æèµæç»è¡¨ {}ï¼åå
¥ {} è¡ï¼ç»è½¬æ¯çåå¼ {} è¡ï¼å
¶ä¸åºå
æé¡¹ç®ä½å½ææ æ°æ® {} è¡ï¼", |
| | | period, filled, kept, dup); |
| | | return toBytes(wb); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * çæ_Xæç©æµç«åºæèµæç».xlsï¼æ¨¡æ¿ï¼docs/æèµ/模æ¿/模æ¿_Xæç©æµç«åºæèµæç».xlsï¼ã |
| | | * è¦çã åé¡¹ç®æèµå®ææ
åµã项ç®è¡ï¼å£å¾å客è¿ç«æç»è¡¨ï¼ï¼å¹¶æè¡¨å
æ°å¼éç® |
| | | * æ¸ éè¡ / å¸å·è¡ / å计è¡ï¼åæ¥å·æ°ãåå¸å·è§åå
å¤é¡¹ç®å®ææ
åµããå¸å·æ±æ»ãä¸¤å¼ æ±æ»é¡µã |
| | | */ |
| | | public byte[] exportInvestLogisticsDetail(String period, String mode) throws Exception { |
| | | int year = Integer.parseInt(period.split("-")[0]); |
| | | int month = monthOf(period, mode); |
| | | List<InvestmentProject> projects = investProjectMapper.selectList( |
| | | new LambdaQueryWrapper<InvestmentProject>().eq(InvestmentProject::getCategory, "ç©æµååº")); |
| | | Map<Long, InvestmentMonthly> mByProject = investMonthlyOf(period); |
| | | HSSFWorkbook wb = loadInvestTemplate("模æ¿_Xæç©æµç«åºæèµæç».xls"); |
| | | HSSFSheet sheet = wb.getSheet(" åé¡¹ç®æèµå®ææ
åµ"); |
| | | if (sheet == null) throw new RuntimeException("模æ¿ã模æ¿_Xæç©æµç«åºæèµæç».xlsã缺å°ã åé¡¹ç®æèµå®ææ
åµãå·¥ä½è¡¨"); |
| | | fixInvestMonthTitle(sheet, 0, 0, month); |
| | | Row head = sheet.getRow(3); |
| | | if (head != null) { |
| | | String t = cellText(head.getCell(0)); |
| | | if (t != null) { |
| | | String nv = t.replaceAll("\\d{4}å¹´\\d+æ", year + "å¹´" + month + "æ"); |
| | | if (!nv.equals(t)) putText(head, 0, nv); |
| | | } |
| | | } |
| | | // 1) ç»ææ«æï¼å¸å·å°èè¡ |
| | | List<Integer> cityRows = new ArrayList<>(); |
| | | for (int r = 7; r <= sheet.getLastRowNum(); r++) { |
| | | HSSFRow row = sheet.getRow(r); |
| | | if (row == null) continue; |
| | | String a = nvl(cellText(row.getCell(0))); |
| | | String b = nvl(cellText(row.getCell(1))); |
| | | if (LOGI_CITY_LABELS.containsKey(a) && b.isEmpty()) cityRows.add(r); |
| | | } |
| | | Map<String, double[]> citySums = new LinkedHashMap<>(); // å
¨å -> G,H,I,J,K |
| | | Map<String, double[]> cityStats = new LinkedHashMap<>(); // å
¨å -> {æ»æ°, 累计, è§åå
æ°, è§åå
累计, è§å夿°, è§åå¤ç´¯è®¡} |
| | | Set<Long> used = new HashSet<>(); |
| | | int filled = 0, kept = 0; |
| | | for (int i = 0; i < cityRows.size(); i++) { |
| | | int cr = cityRows.get(i); |
| | | String cityLabel = nvl(cellText(sheet.getRow(cr).getCell(0))); |
| | | String city = LOGI_CITY_LABELS.getOrDefault(cityLabel, cityLabel); |
| | | int start = cr + 1; |
| | | int end = (i + 1 < cityRows.size() ? cityRows.get(i + 1) : sheet.getLastRowNum() + 1) - 1; |
| | | List<Integer> chRows = new ArrayList<>(); |
| | | for (int r = start; r <= end; r++) { |
| | | HSSFRow row = sheet.getRow(r); |
| | | if (row == null) continue; |
| | | if (isInvestChannelLabel(nvl(cellText(row.getCell(0))))) chRows.add(r); |
| | | } |
| | | // (1) å
æé¡¹ç®å+å¸å· è¦çæåºå
å½ææ°æ®ç项ç®è¡ |
| | | for (int r = start; r <= end; r++) { |
| | | HSSFRow row = sheet.getRow(r); |
| | | if (row == null) continue; |
| | | String a = nvl(cellText(row.getCell(0))); |
| | | String b = nvl(cellText(row.getCell(1))); |
| | | if (isInvestChannelLabel(a)) continue; |
| | | if (!a.matches("\\d+(\\.\\d+)?")) continue; |
| | | if (b.isEmpty()) continue; |
| | | InvestmentProject p = matchInvest(projects, b, city, "ç©æµååº", used); |
| | | InvestmentMonthly m = p == null ? null : mByProject.get(p.getId()); |
| | | if (p == null || m == null) { kept++; continue; } |
| | | used.add(p.getId()); |
| | | // å£å¾å客è¿ç«æç»è¡¨ï¼åªè¦ç H èªå¼å§å»ºè®¾ç´¯è®¡ / J èªå¹´å累计 / K æ¬æå®æ / M 形象è¿åº¦ |
| | | if (m.getStartCum() != null) putNum(row, 7, m.getStartCum()); |
| | | if (m.getYearCum() != null) putNum(row, 9, m.getYearCum()); |
| | | if (m.getMonthDone() != null) putNum(row, 10, m.getMonthDone()); |
| | | if (m.getProgressDesc() != null && !m.getProgressDesc().trim().isEmpty()) putText(row, 12, m.getProgressDesc()); |
| | | filled++; |
| | | } |
| | | // (2) åææ¸ éåæ±æ»ï¼å¹¶å忏 éè¡ / å¸å·è¡ |
| | | double[] citySum = new double[5]; |
| | | double[] stat = new double[6]; |
| | | for (int j = 0; j < chRows.size(); j++) { |
| | | int r0 = chRows.get(j); |
| | | int r1 = (j + 1 < chRows.size() ? chRows.get(j + 1) : end + 1) - 1; |
| | | boolean planned = !nvl(cellText(sheet.getRow(r0).getCell(0))).startsWith("åã"); |
| | | double[] s = new double[5]; |
| | | for (int r = r0 + 1; r <= r1; r++) { |
| | | HSSFRow row = sheet.getRow(r); |
| | | if (row == null) continue; |
| | | String a = nvl(cellText(row.getCell(0))); |
| | | String b = nvl(cellText(row.getCell(1))); |
| | | if (isInvestChannelLabel(a) || !a.matches("\\d+(\\.\\d+)?")) continue; |
| | | if (b.isEmpty()) continue; |
| | | for (int k = 0; k < 5; k++) s[k] += numOf(row.getCell(6 + k)); |
| | | stat[0] += 1; |
| | | stat[1] += numOf(row.getCell(9)); |
| | | if (planned) { stat[2] += 1; stat[3] += numOf(row.getCell(9)); } |
| | | else { stat[4] += 1; stat[5] += numOf(row.getCell(9)); } |
| | | } |
| | | HSSFRow crow = sheet.getRow(r0); |
| | | for (int k = 0; k < 5; k++) putNum(crow, 6 + k, s[k] == 0 ? null : s[k]); |
| | | for (int k = 0; k < 5; k++) citySum[k] += s[k]; |
| | | } |
| | | // æ¸ éåä¹å¤ç游离项ç®è¡ï¼æ¨¡æ¿æªåç»æ¶ï¼ä¹è®¡å
¥å¸å·å计 |
| | | for (int r = start; r <= end; r++) { |
| | | HSSFRow row = sheet.getRow(r); |
| | | if (row == null) continue; |
| | | String a = nvl(cellText(row.getCell(0))); |
| | | String b = nvl(cellText(row.getCell(1))); |
| | | if (isInvestChannelLabel(a) || !a.matches("\\d+(\\.\\d+)?")) continue; |
| | | if (b.isEmpty()) continue; |
| | | boolean inChannel = false; |
| | | for (int j = 0; j < chRows.size(); j++) { |
| | | int r0 = chRows.get(j); |
| | | int r1 = (j + 1 < chRows.size() ? chRows.get(j + 1) : end + 1) - 1; |
| | | if (r > r0 && r <= r1) { inChannel = true; break; } |
| | | } |
| | | if (inChannel) continue; |
| | | for (int k = 0; k < 5; k++) citySum[k] += numOf(row.getCell(6 + k)); |
| | | stat[0] += 1; |
| | | stat[1] += numOf(row.getCell(9)); |
| | | } |
| | | HSSFRow cityRow = sheet.getRow(cr); |
| | | for (int k = 0; k < 5; k++) putNum(cityRow, 6 + k, citySum[k] == 0 ? null : citySum[k]); |
| | | citySums.put(city, citySum); |
| | | cityStats.put(city, stat); |
| | | } |
| | | // 2) å计è¡ï¼ç¬¬ 7 è¡ï¼ |
| | | double[] total = new double[5]; |
| | | for (double[] s : citySums.values()) { |
| | | for (int k = 0; k < 5; k++) total[k] += s[k]; |
| | | } |
| | | for (int k = 0; k < 5; k++) putNum(sheet.getRow(6), 6 + k, total[k] == 0 ? null : total[k]); |
| | | |
| | | // 3) åå¸å·è§åå
å¤é¡¹ç®å®ææ
åµ |
| | | HSSFSheet citySheet = wb.getSheet("åå¸å·è§åå
å¤é¡¹ç®å®ææ
åµ"); |
| | | if (citySheet != null) { |
| | | Row t1 = citySheet.getRow(0); |
| | | if (t1 != null) { |
| | | String t = cellText(t1.getCell(0)); |
| | | if (t != null) { |
| | | String nv = t.replaceAll("\\d{4}å¹´", year + "å¹´"); |
| | | if (!nv.equals(t)) putText(t1, 0, nv); |
| | | } |
| | | } |
| | | double[] st = new double[6]; |
| | | for (int r = 3; r <= citySheet.getLastRowNum(); r++) { |
| | | HSSFRow row = citySheet.getRow(r); |
| | | if (row == null) continue; |
| | | String a = nvl(cellText(row.getCell(0))); |
| | | String b = nvl(cellText(row.getCell(1))); |
| | | if (a.contains("å计") || b.contains("å计")) { |
| | | for (int k = 0; k < 6; k++) putNum(row, 2 + k, st[k] == 0 ? null : st[k]); |
| | | continue; |
| | | } |
| | | double[] s = cityStats.get(LOGI_CITY_LABELS.getOrDefault(b, b)); |
| | | if (s == null) continue; |
| | | for (int k = 0; k < 6; k++) { |
| | | putNum(row, 2 + k, s[k] == 0 ? null : s[k]); |
| | | st[k] += s[k]; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 4) å¸å·æ±æ»ï¼B 年度计åæèµä¸ºå®æ¹å£å¾ï¼ä¿ææ¨¡æ¿åå¼ï¼C/D/E æå项ç®é¡µéç®ï¼ |
| | | HSSFSheet sumSheet = wb.getSheet("å¸å·æ±æ»"); |
| | | if (sumSheet != null) { |
| | | HSSFRow r2 = sumSheet.getRow(1); |
| | | if (r2 != null) { |
| | | putNum(r2, 0, (double) org.apache.poi.ss.usermodel.DateUtil.getExcelDate( |
| | | java.time.LocalDate.of(year, month, 1).atStartOfDay())); |
| | | } |
| | | double cT = 0.0, dT = 0.0; |
| | | for (int r = 7; r <= 23; r++) { |
| | | HSSFRow row = sumSheet.getRow(r); |
| | | if (row == null) continue; |
| | | String a = nvl(cellText(row.getCell(0))); |
| | | double[] s = citySums.get(LOGI_CITY_LABELS.getOrDefault(a, a)); |
| | | if (s == null) continue; |
| | | putNum(row, 2, s[3] == 0 ? null : s[3]); |
| | | putNum(row, 3, s[4] == 0 ? null : s[4]); |
| | | double b = numOf(row.getCell(1)); |
| | | putNum(row, 4, b > 0 ? round(s[3] / b * 100, 4) : null); |
| | | cT += s[3]; |
| | | dT += s[4]; |
| | | } |
| | | HSSFRow tot = sumSheet.getRow(6); |
| | | if (tot != null) { |
| | | putNum(tot, 2, cT == 0 ? null : cT); |
| | | putNum(tot, 3, dT == 0 ? null : dT); |
| | | double b = numOf(tot.getCell(1)); |
| | | putNum(tot, 4, b > 0 ? round(cT / b * 100, 4) : null); |
| | | } |
| | | } |
| | | try { |
| | | wb.getCreationHelper().createFormulaEvaluator().evaluateAll(); |
| | | } catch (Exception e) { |
| | | log.warn("ç©æµç«åºæèµæç»å
¬å¼æ±å¼å¤±è´¥: {}", e.getMessage()); |
| | | } |
| | | log.info("ç©æµç«åºæèµæç» {}ï¼åå
¥ {} è¡ï¼ç»è½¬æ¯çåå¼ {} è¡", period, filled, kept); |
| | | return toBytesHssf(wb); |
| | | } |
| | | |
| | | private static class InvestAgg { |
| | | double total, startCum, yearPlan, yearCum; |
| | | |