| | |
| | | import org.apache.poi.ss.usermodel.Row; |
| | | import org.apache.poi.ss.usermodel.Sheet; |
| | | import org.apache.poi.xssf.usermodel.XSSFWorkbook; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import javax.annotation.Resource; |
| | |
| | | */ |
| | | @Service |
| | | public class SummaryWorkbookFiller { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(SummaryWorkbookFiller.class); |
| | | |
| | | @Resource |
| | | private MidCalc midCalc; |
| | |
| | | if (wb == null || month <= 1) return 0; |
| | | int targetCol = FIRST_MONTH_COL + 2 * (month - 1); |
| | | int written = 0; |
| | | int carried = 0; |
| | | for (int i = 0; i < wb.getNumberOfSheets(); i++) { |
| | | Sheet sh = wb.getSheetAt(i); |
| | | if (sh == null || !isFilledLedgerSheet(sh.getSheetName())) continue; |
| | | if (sh == null || !isMonthLedgerSheet(sh.getSheetName())) continue; |
| | | boolean derivedSheet = isDerivedFormulaSheet(sh.getSheetName()); |
| | | for (int r = sh.getFirstRowNum(); r <= sh.getLastRowNum(); r++) { |
| | | Row row = sh.getRow(r); |
| | | if (row == null) continue; |
| | |
| | | break; |
| | | } |
| | | } |
| | | if (srcCell == null) continue; |
| | | if (srcCell == null) { |
| | | if (!derivedSheet) continue; |
| | | // 派生页(城市客运/中口径明细/公路总客运)里「各月都是同一个常量」的结构性常量行 |
| | | // (如中口径明细 武汉 城际城乡巡游出租=0),按月沿用该常量,避免当月值列空着导致累计缺项 |
| | | double struct = structuralConstant(row, month); |
| | | if (Double.isNaN(struct)) continue; |
| | | Cell target = row.getCell(targetCol); |
| | | if (target == null) target = row.createCell(targetCol); |
| | | Cell prev = row.getCell(FIRST_MONTH_COL + 2 * (month - 2)); |
| | | if (prev != null && prev.getCellStyle() != null) target.setCellStyle(prev.getCellStyle()); |
| | | target.setCellValue(struct); |
| | | carried++; |
| | | written++; |
| | | continue; |
| | | } |
| | | String f = srcCell.getCellFormula(); |
| | | if (f == null || f.isEmpty()) continue; |
| | | Cell target = row.getCell(targetCol); |
| | |
| | | written++; |
| | | } |
| | | } |
| | | if (carried > 0 && log != null) { |
| | | log.info("汇总工作簿:派生页结构性常量行按月沿用 {} 格(第 {} 月)", carried, month); |
| | | } |
| | | return written; |
| | | } |
| | | |
| | | /** 该行 1..month-1 月的当月值列是否全为同一个数值常量(结构性常量行,如各月恒为 0) */ |
| | | private double structuralConstant(Row row, int month) { |
| | | if (row == null || month <= 2) return Double.NaN; |
| | | Double v = null; |
| | | for (int s = 1; s < month; s++) { |
| | | Cell c = row.getCell(FIRST_MONTH_COL + 2 * (s - 1)); |
| | | if (c == null || c.getCellType() != org.apache.poi.ss.usermodel.CellType.NUMERIC) return Double.NaN; |
| | | double d = c.getNumericCellValue(); |
| | | if (v == null) v = d; |
| | | else if (Math.abs(d - v) > 1e-9) return Double.NaN; |
| | | } |
| | | return v == null ? Double.NaN : v; |
| | | } |
| | | |
| | | /** 派生页(当月值全部来自其他页/常量,纯公式驱动):城市客运 / 中口径明细 / 公路总客运 / 中口径客运量 */ |
| | | private boolean isDerivedFormulaSheet(String name) { |
| | | if (name == null) return false; |
| | | String n = name.trim(); |
| | | return "城市客运".equals(n) || "中口径明细".equals(n) || "公路总客运".equals(n) || "中口径客运量".equals(n); |
| | | } |
| | | |
| | | /** 该格是否已有内容(数值/文本/公式);仅带样式的空壳(如母版里继承表头日期格式的格子)视为空 */ |
| | |
| | | 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" */ |
| | |
| | | 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()); |
| | | } |
| | | if (target == null) target = row.createCell(yoyCol); |
| | | // 母版把新月份的同比列做成了普通数值格式(显示成小数),统一沿用上月同比列的样式(百分数) |
| | | if (prev.getCellStyle() != null) target.setCellStyle(prev.getCellStyle()); |
| | | try { |
| | | target.setCellFormula(shifted); |
| | | written++; |