From 8719902780eadfc55d4d159d5a111b433f065137 Mon Sep 17 00:00:00 2001
From: zhizhijie <zhizhijie@users.noreply.gitee.com>
Date: 星期五, 18 九月 2026 11:34:33 +0800
Subject: [PATCH] 功能(中口径): 四维口径统一 + 修独立中口径明细扩列月份总行为空
---
traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java | 125 ++++++++++++++++++++++++++++++-----------
1 files changed, 92 insertions(+), 33 deletions(-)
diff --git a/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java b/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java
index 1950983..16dd5e5 100644
--- a/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java
+++ b/traffic-audit-server/src/main/java/com/trafficaudit/reportexport/service/ReportExportService.java
@@ -13,6 +13,7 @@
import com.trafficaudit.dataimport.entity.PassengerEnterpriseMonthly;
import com.trafficaudit.dataimport.entity.PassengerIndividualMonthly;
import com.trafficaudit.dataimport.entity.ScaleSplitTransport;
+import com.trafficaudit.dataimport.entity.WycOrderMonthly;
import com.trafficaudit.auditengine.entity.AuditResult;
import com.trafficaudit.auditengine.entity.AuditRun;
import com.trafficaudit.auditengine.mapper.AuditResultMapper;
@@ -29,9 +30,11 @@
import com.trafficaudit.dataimport.mapper.PassengerEnterpriseMonthlyMapper;
import com.trafficaudit.dataimport.mapper.PassengerIndividualMonthlyMapper;
import com.trafficaudit.dataimport.mapper.ScaleSplitTransportMapper;
+import com.trafficaudit.dataimport.mapper.WycOrderMonthlyMapper;
import com.trafficaudit.reportexport.calc.MidCalc;
import com.trafficaudit.reportexport.calc.PaxCalc;
import com.trafficaudit.reportexport.calc.SummaryWorkbookFiller;
+import com.trafficaudit.reportexport.calc.WycSplitCalc;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
@@ -98,6 +101,10 @@
private CityTaxiMonthlyMapper cityTaxiMapper;
@Resource
private SummaryWorkbookFiller summaryWorkbookFiller;
+ @Resource
+ private WycSplitCalc wycSplitCalc;
+ @Resource
+ private WycOrderMonthlyMapper wycOrderMapper;
@Resource
private AuditResultMapper auditResultMapper;
@Resource
@@ -1179,17 +1186,16 @@
return lv == 0.0 ? null : (v - lv) / lv;
}
- /** 涓彛寰勬湀鍚屾瘮锛歬=-1 琛ㄧず鎬昏锛堢彮绾�+鍏氦涔嬪拰锛屽嚭绉�/缃戠害杞︽棤婧愭暟鎹寜 0锛夛紱鏃犲幓骞存暟鎹暀绌� */
+ /** 涓彛寰勬湀鍚屾瘮锛歬=-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++) {
- if (kk >= 3) continue;
v += midClassVal(mid, year, month, area, kk, volume);
lv += midClassVal(mid, year - 1, month, area, kk, volume);
}
- } else if (k <= 2) {
+ } else {
v = midClassVal(mid, year, month, area, k, volume);
lv = midClassVal(mid, year - 1, month, area, k, volume);
}
@@ -1197,7 +1203,7 @@
if (v != 0.0 && lv != 0.0) c.setCellValue(round((v - lv) / lv, 4));
}
- /** 涓彛寰勭疮璁″悓姣斿垪锛�1..months 鏈堢疮璁★紱k=-1 鎬昏 = 鐝嚎+鍏氦锛� */
+ /** 涓彛寰勭疮璁″悓姣斿垪锛�1..months 鏈堢疮璁★紱鍥涚淮榻愬叏锛� */
private void fillMidCumYoyColumn(Sheet sheet, Map<Integer, Map<String, double[][]>> mid, int year,
int months, int colIdx) {
List<String> areas = midTemplateAreas();
@@ -1217,7 +1223,7 @@
String area = areas.get(blockOffset / 5);
double v = 0.0, lv = 0.0;
for (int m = 1; m <= months; m++) {
- if (k <= 2) {
+ {
v += midClassVal(mid, year, m, area, k, volume);
lv += midClassVal(mid, year - 1, m, area, k, volume);
}
@@ -2181,20 +2187,15 @@
boolean extended = fillMonths > 6;
if (extended) extendMonthlyColumns(sheet, 2, currentYear, 4, sheet.getLastRowNum());
List<String> areas = midTemplateAreas();
+ // 2026-09-18锛氭敼涓恒�屾寜鍗曞厓鏍肩被鍨嬫棤鍏炽�嶉亶鍘嗏�斺�旀墿鍒楋紙7~12 鏈堬級鍑烘潵鐨勫�煎垪鍦ㄦā鏉块噷鏄┖鏍硷紝
+ // 鏃у疄鐜板彧澶勭悊 CellType.FORMULA 鐨勬牸锛屽鑷� 7 鏈堝強浠ュ悗鏈堜唤姘歌繙濉笉涓婏紙8 鏈堟暣鍒� 0銆佺疮璁″彧鍒� 6 鏈堬級銆�
for (Row row : sheet) {
if (row == null) continue;
- for (Cell c : row) {
- if (c.getCellType() != CellType.FORMULA) continue;
- String f = c.getCellFormula();
- if (f == null) continue;
- boolean crossBook = f.contains("[");
- if (!crossBook && !isYoyMonthCol(c.getColumnIndex() + 1)) continue; // 鍐呴儴鍏紡锛堝悎璁�/绱锛変繚鐣欓噸绠楋紱鍚屾瘮鍒� #REF! 瑕嗗啓涓烘暟鍊�
- if (crossBook && !is2026MonthCol(c.getColumnIndex() + 1)) {
- keepCached(c); // 2025 骞村垪淇濈暀妯℃澘缂撳瓨鍊�
- continue;
- }
+ for (int c0 = 0; c0 < Math.max(row.getLastCellNum(), 0); c0++) {
+ Cell c = row.getCell(c0);
+ if (c == null) continue;
int r = c.getRowIndex() + 1;
- int col = c.getColumnIndex() + 1;
+ int col = c0 + 1;
int blockOffset = -1;
boolean volume = false;
if (r >= 5 && r <= 94) {
@@ -2205,31 +2206,48 @@
volume = false;
}
if (blockOffset < 0) {
- keepCached(c); // r1/r2 澶囨敞绛�
+ if (c.getCellType() == CellType.FORMULA) keepCached(c); // r1/r2 澶囨敞銆侀〉澶栬法绨垮紩鐢ㄧ瓑
continue;
}
- if (blockOffset % 5 == 0) {
- if (isYoyMonthCol(col)) {
- fillMidYoyCell(c, mid, currentYear, monthOfCol(col), areas.get(blockOffset / 5), -1, volume);
- } else {
- keepCached(c); // 鎬昏鍐呴儴鍏紡锛堥槻寰★級
+ boolean isVal = is2026MonthCol(col);
+ boolean isYoy = isYoyMonthCol(col);
+ if (!isVal && !isYoy) {
+ // 2025 骞村垪绛夛細璺ㄧ翱鍏紡鍙栫紦瀛樺�兼柇閾撅紱鍐呴儴鍏紡锛堝悎璁�/绱锛変繚鐣欙紝绋嶅悗 recalc 閲嶇畻
+ if (c.getCellType() == CellType.FORMULA) {
+ String f = c.getCellFormula();
+ if (f != null && f.contains("[")) keepCached(c);
}
continue;
}
- int k = blockOffset % 5; // 1=鐝嚎 2=鍏氦 3=鍑虹 4=缃戠害杞�
String area = areas.get(blockOffset / 5);
- if (is2026MonthCol(col)) {
+ if (blockOffset % 5 == 0) {
+ if (isYoy) {
+ fillMidYoyCell(c, mid, currentYear, monthOfCol(col), area, -1, volume);
+ } else if (monthOfCol(col) > 6) {
+ // 鎵╁垪鍑烘潵鐨� 7~12 鏈堟�昏鍊煎垪锛氭ā鏉块噷鏈棤姝ゅ垪锛屽厠闅嗗悗鏃㈡病鏈夊叕寮忎篃娌℃湁缂撳瓨鍊硷紝
+ // 鐩存帴鍐欏簱鍐呭洓缁村悎璁★紙缁村害0锛夈��1~6 鏈堜繚鐣欐ā鏉跨紦瀛樺�硷紝閬垮厤涓㈡帀妯℃澘閲岀殑瀹氱鏁般��
+ double total = midClassVal(mid, currentYear, monthOfCol(col), area, 0, volume);
+ c.setBlank();
+ if (total != 0.0) c.setCellValue(round(total, 4));
+ } else if (c.getCellType() == CellType.FORMULA) {
+ keepCached(c); // 1~6 鏈堟�昏鍊煎垪 = 妯℃澘缂撳瓨鍊硷紝淇濈暀
+ }
+ continue;
+ }
+ int k = blockOffset % 5; // 1=鐝嚎 2=鍏氦 3=鍑虹鍩庝埂 4=缃戠害杞﹀煄涔�
+ if (isVal) {
fillMidCell(c, mid, currentYear, monthOfCol(col), area, k, volume);
- } else if (isYoyMonthCol(col)) {
- fillMidYoyCell(c, mid, currentYear, monthOfCol(col), area, k, volume);
} else {
- keepCached(c); // 2025 骞村垪淇濈暀妯℃澘缂撳瓨鍊�
+ fillMidYoyCell(c, mid, currentYear, monthOfCol(col), area, k, volume);
}
}
}
// 绱鍚屾瘮鍒楋紙妯℃澘 #REF! 鈫� 搴撳唴鍘诲勾 1..N 鏈堢疮璁″悓姣旀暟鍊硷級
fillMidCumYoyColumn(sheet, mid, currentYear, fillMonths, extended ? 27 : 15);
- recalc(wb);
+ // evaluateAll 浼氬湪璺ㄧ翱鍏紡锛圫heet2 鐨� [1]xx!A1锛夊鏁存湰涓柇锛岀疮璁″垪 AA 灏辨案杩滄嬁涓嶅埌鏂扮紦瀛樺�硷紝
+ // 鏀圭敤閫愭牸瀹归敊鐨� recalcWorkbookFormulas锛氬潖鏍艰烦杩囥�佸ソ鏍肩収绠椼��
+ int[] recalc = recalcWorkbookFormulas(wb);
+ log.info("涓彛寰勬槑缁嗗叕寮忛噸绠楀畬鎴愶細鎴愬姛 {} 鏍硷紝澶辫触 {} 鏍�", recalc[0], recalc[1]);
clearFormulaErrorsAll(wb); // 鍘诲勾鍚屾湡鏄庣粏椤垫畫鐣� #REF! 鍚屾瘮鍏紡 鈫� 娓呯┖
return toBytes(wb);
}
@@ -2256,12 +2274,8 @@
return (col - 1) / 2;
}
- /** 濉腑鍙e緞鏁版嵁鍗曞厓鏍硷細鍑虹/缃戠害杞�(3/4)鏄惧紡 0锛岀彮绾�/鍏氦濉簱鍐呭�硷紙鏃犲�兼竻绌猴級 */
+ /** 濉腑鍙e緞鏁版嵁鍗曞厓鏍硷細鐝嚎/鍏氦/鍑虹鍩庝埂/缃戠害杞﹀煄涔� 鍥涚淮缁熶竴鍙栧簱鍐呭�硷紙鏃犲�兼竻绌猴級 */
private void fillMidCell(Cell c, Map<Integer, Map<String, double[][]>> mid, int year, int month, String area, int k, boolean volume) {
- if (k == 3 || k == 4) {
- writeExplicitZero(c); // 鍑虹/缃戠害杞︽殏鏃犳暟鎹簮锛屾樉寮� 0
- return;
- }
double v = midClassVal(mid, year, month, area, k, volume);
// POI setCellValue(double) 瀵瑰叕寮忓崟鍏冩牸鍙洿鏂扮紦瀛樹笉绉婚櫎鍏紡锛屽繀椤诲厛 setBlank 鍐嶅啓鍊�
c.setBlank();
@@ -2369,9 +2383,54 @@
addMidClass(mid, key, city, 2, nz(b.getPassengerChengxiang()), nz(b.getTurnoverChengxiang()));
addMidClass(mid, key, "婀栧寳鐪�", 2, nz(b.getPassengerChengxiang()), nz(b.getTurnoverChengxiang()));
}
+ // 缁村害3锛氬煄闄呭煄涔″贰娓稿嚭绉� = 鍙拌处椤点�屽嚭绉�!鎬婚噺 鈭� 鍑虹!鍩庡競鍐呫�嶏紙婧� city_taxi_monthly锛�
+ for (CityTaxiMonthly t : cityTaxiMapper.selectList(null)) {
+ if (t.getReportPeriod() == null || t.getCity() == null) continue;
+ int key = midPeriodKey(t.getReportPeriod());
+ if (key <= 0) continue;
+ String city = RegionUtil.normalizeCityName(t.getCity());
+ if (city == null) continue;
+ double pass = nz(t.getPassengerVolume()) - nz(t.getPassengerCity());
+ double turn = nz(t.getTurnover()) - nz(t.getTurnoverCity());
+ addMidClass(mid, key, city, 3, pass, turn);
+ addMidClass(mid, key, "婀栧寳鐪�", 3, pass, turn);
+ }
+ // 缁村害4锛氬煄闄呭煄涔$綉绾﹁溅 = 缃戠害杞︽媶鍒嗙粨鏋滐紙涓庡彴璐︺�岀綉绾﹁溅銆嶉〉鍚屾簮鍚屾硶锛�
+ for (WycOrderMonthly o : wycOrderMapper.selectList(null)) {
+ String per = o.getReportPeriod();
+ if (per == null) continue;
+ int key = midPeriodKey(per);
+ if (key <= 0) continue;
+ WycSplitCalc.WycResult wr;
+ try {
+ wr = wycSplitCalc.calc(per);
+ } catch (Exception e) {
+ continue; // 璇ユ湡缂鸿鍗�/pin 鎴栧嚭绉熸簮鏁版嵁锛岃烦杩囷紙涓嶅奖鍝嶅叾瀹冩湡锛�
+ }
+ 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());
+ }
+ }
return mid;
}
+ /** "yyyy-MM" -> yyyy*100+MM锛涢潪娉曡繑鍥� 0锛堜笌 loadMidClassMap 鐨� key 鍙e緞涓�鑷达級 */
+ private int midPeriodKey(String period) {
+ if (period == null) return 0;
+ String[] parts = period.trim().split("-");
+ if (parts.length != 2) return 0;
+ try {
+ int y = Integer.parseInt(parts[0]);
+ int m = Integer.parseInt(parts[1]);
+ if (y <= 0 || m < 1 || m > 12) return 0;
+ return y * 100 + m;
+ } catch (NumberFormatException e) {
+ return 0;
+ }
+ }
+
/** 鍐欏叆鍒嗙被鍊煎苟绱姞鎬婚噺锛堢淮搴�0锛� */
private void addMidClass(Map<Integer, Map<String, double[][]>> mid, int key, String city, int k, double pass, double turn) {
double[][] arr = mid.computeIfAbsent(key, kk -> new HashMap<>()).computeIfAbsent(city, kk -> new double[5][2]);
--
Gitblit v1.9.1