| | |
| | | } |
| | | } |
| | | |
| | | /** 只校验「必需列按名存在」(不校验列位):用于兼容同事版模板的列位差异 */ |
| | | private void requireHeaderColsByName(Sheet sheet, String typeLabel, String templateHint, String[] keywords) { |
| | | Row header = sheet == null ? null : sheet.getRow(0); |
| | | if (header == null) { |
| | | throw new RuntimeException("所选数据类型【" + typeLabel + "】文件表头缺失,请使用系统模板《" + templateHint + "》整理后再导入"); |
| | | } |
| | | List<String> missing = new ArrayList<>(); |
| | | for (String keyword : keywords) { |
| | | if (findColByKeywords(header, keyword) < 0) missing.add(keyword); |
| | | } |
| | | if (!missing.isEmpty()) { |
| | | throw new RuntimeException("所选数据类型【" + typeLabel + "】与文件内容不符:表头缺少必需列【" |
| | | + String.join("】【", missing) + "】,请确认是否选错了数据类型(模板:" + templateHint + ")"); |
| | | } |
| | | } |
| | | |
| | | /** 表头名 → 列号(首次出现);未命中时回退 fallback,保持对旧模板兼容 */ |
| | | private int colByName(Row header, int fallback, String name) { |
| | | return colByName(header, fallback, name, 1); |
| | | } |
| | | |
| | | /** 表头名 → 列号(第 occurrence 次出现);未命中时回退 fallback */ |
| | | private int colByName(Row header, int fallback, String name, int occurrence) { |
| | | if (header == null) return fallback; |
| | | int hit = 0; |
| | | for (int c = 0; c <= header.getLastCellNum(); c++) { |
| | | Cell cell = header.getCell(c); |
| | | if (cell == null) continue; |
| | | String v = FORMATTER.formatCellValue(cell).trim(); |
| | | if (v.contains(name)) { |
| | | hit++; |
| | | if (hit == occurrence) return c; |
| | | } |
| | | } |
| | | return fallback; |
| | | } |
| | | |
| | | /** 按表头关键字定位列号:从第 1 列向右扫,命中任一关键字即返回该列;未命中返回 -1 */ |
| | | private int findColByKeywords(Row header, String... keywords) { |
| | | if (header == null) return -1; |
| | |
| | | List<CityBusRow> rows = new ArrayList<>(); |
| | | try (Workbook wb = WorkbookFactory.create(file.getInputStream())) { |
| | | Sheet sheet = wb.getSheetAt(0); |
| | | requireHeaderLayout(sheet, "城市公交", "模板_交企统U203表_城市公共交通月度运营情况(2026年7月).xls", |
| | | CITY_BUS_HEADER_COLS, CITY_BUS_HEADER_KEYWORDS); |
| | | Row hdr = sheet.getRow(0); |
| | | requireHeaderColsByName(sheet, "城市公交", "模板_交企统U203表_城市公共交通月度运营情况(2026年7月).xls", CITY_BUS_HEADER_KEYWORDS); |
| | | for (int r = 1; r <= sheet.getLastRowNum(); r++) { |
| | | Row row = sheet.getRow(r); |
| | | if (row == null) continue; |
| | | String name = getString(row, 2); |
| | | String name = getString(row, colByName(hdr, 2, "企业名称")); |
| | | if (name == null || name.trim().isEmpty()) continue; |
| | | CityBusMonthly item = new CityBusMonthly(); |
| | | item.setReportPeriod(period); |
| | | item.setRegionCode(getString(row, 0)); |
| | | item.setCity(RegionUtil.cityByCode(getString(row, 0))); |
| | | item.setEnterpriseCode(getString(row, 1)); |
| | | item.setRegionCode(getString(row, colByName(hdr, 0, "所属地区"))); |
| | | item.setCity(RegionUtil.cityByCode(getString(row, colByName(hdr, 0, "所属地区")))); |
| | | item.setEnterpriseCode(getString(row, colByName(hdr, 1, "企业代码"))); |
| | | item.setEnterpriseName(name.trim()); |
| | | item.setOpVehicles(getDecimal(row, 5)); |
| | | item.setStopTotal(getDecimal(row, 6)); |
| | | item.setStopCity(getDecimal(row, 7)); |
| | | item.setPassengerVolume(getDecimal(row, 8)); |
| | | item.setPassengerCity(getDecimal(row, 9)); |
| | | item.setTurnover(getDecimal(row, 10)); |
| | | item.setTurnoverCity(getDecimal(row, 11)); |
| | | item.setRailPassengerVolume(getDecimal(row, 13)); |
| | | item.setRailTurnover(getDecimal(row, 14)); |
| | | item.setFerryPassengerVolume(getDecimal(row, 17)); |
| | | item.setFerryTurnover(getDecimal(row, 18)); |
| | | item.setAvgDistance(getDecimal(row, 19)); |
| | | item.setAvgDistanceCity(getDecimal(row, 20)); |
| | | item.setContactPerson(getString(row, 24)); |
| | | item.setContactPhone(getString(row, 25)); |
| | | item.setReportDate(getDateString(row, 26)); |
| | | item.setRateOpVehiclesMom(getDecimal(row, 29)); |
| | | item.setRatePassengerMom(getDecimal(row, 30)); |
| | | item.setRatePassengerCityMom(getDecimal(row, 31)); |
| | | item.setRateChengxiangMom(getDecimal(row, 32)); |
| | | item.setRateChengxiangTurnoverMom(getDecimal(row, 33)); |
| | | item.setAvgDistanceMomChange(getDecimal(row, 34)); |
| | | item.setAvgDistanceCityMomChange(getDecimal(row, 35)); |
| | | item.setDailyPassengerPerVehicle(getDecimal(row, 36)); |
| | | item.setRateOpVehiclesYoy(getDecimal(row, 39)); |
| | | item.setRatePassengerYoy(getDecimal(row, 40)); |
| | | item.setRatePassengerCityYoy(getDecimal(row, 41)); |
| | | item.setRateChengxiangYoy(getDecimal(row, 42)); |
| | | item.setRateChengxiangTurnoverYoy(getDecimal(row, 43)); |
| | | item.setStopCityRatio(getDecimal(row, 44)); |
| | | item.setPassengerCityRatio(getDecimal(row, 45)); |
| | | item.setChengxiangRatio(getDecimal(row, 46)); |
| | | item.setRateTurnoverYoy(getDecimal(row, 47)); |
| | | item.setRateTurnoverMom(getDecimal(row, 48)); |
| | | item.setPassengerChengxiang(getDecimal(row, 49)); |
| | | item.setTurnoverChengxiang(getDecimal(row, 50)); |
| | | item.setAvgDistanceChengxiang(getDecimal(row, 51)); |
| | | item.setVerifyExplanation(getString(row, 65)); |
| | | item.setReportNote(getString(row, 66)); |
| | | item.setModifyRecord(getString(row, 67)); |
| | | item.setOpVehicles(getDecimal(row, colByName(hdr, 5, "公共汽电车_运营车数"))); |
| | | item.setStopTotal(getDecimal(row, colByName(hdr, 6, "运营站点总个数"))); |
| | | item.setStopCity(getDecimal(row, colByName(hdr, 7, "其中:城市内"))); |
| | | item.setPassengerVolume(getDecimal(row, colByName(hdr, 8, "公共汽电车_客运量"))); |
| | | item.setPassengerCity(getDecimal(row, colByName(hdr, 9, "其中:城市内", 2))); |
| | | item.setTurnover(getDecimal(row, colByName(hdr, 10, "新增公共汽电车旅客周转量"))); |
| | | item.setTurnoverCity(getDecimal(row, colByName(hdr, 11, "新增公共汽电车旅客周转量_其中城市内"))); |
| | | item.setRailPassengerVolume(getDecimal(row, colByName(hdr, 13, "轨道交通_客运量"))); |
| | | item.setRailTurnover(getDecimal(row, colByName(hdr, 14, "轨道交通_旅客周转量"))); |
| | | item.setFerryPassengerVolume(getDecimal(row, colByName(hdr, 17, "城市客运轮渡_客运量"))); |
| | | item.setFerryTurnover(getDecimal(row, colByName(hdr, 18, "城市客运轮渡旅客周转量"))); |
| | | item.setAvgDistance(getDecimal(row, colByName(hdr, 19, "公共汽电车平均运距"))); |
| | | item.setAvgDistanceCity(getDecimal(row, colByName(hdr, 20, "公共汽电车城市内平均运距"))); |
| | | item.setContactPerson(getString(row, colByName(hdr, 24, "填表人"))); |
| | | item.setContactPhone(getString(row, colByName(hdr, 25, "联系电话"))); |
| | | item.setReportDate(getDateString(row, colByName(hdr, 26, "报出日期"))); |
| | | item.setRateOpVehiclesMom(getDecimal(row, colByName(hdr, 29, "公共汽电车_运营车数环比增速"))); |
| | | item.setRatePassengerMom(getDecimal(row, colByName(hdr, 30, "公共汽电车_客运量环比增速"))); |
| | | item.setRatePassengerCityMom(getDecimal(row, colByName(hdr, 31, "城市内客运量环比"))); |
| | | item.setRateChengxiangMom(getDecimal(row, colByName(hdr, 32, "城际城乡客运量环比增速"))); |
| | | item.setRateChengxiangTurnoverMom(getDecimal(row, colByName(hdr, 33, "城际城乡旅客周转量环比增速"))); |
| | | item.setAvgDistanceMomChange(getDecimal(row, colByName(hdr, 34, "平均运距环比增减(公里)"))); |
| | | item.setAvgDistanceCityMomChange(getDecimal(row, colByName(hdr, 35, "平均运距_城市内环比增减(公里)"))); |
| | | item.setDailyPassengerPerVehicle(getDecimal(row, colByName(hdr, 36, "公共汽电车_单车日均客运量"))); |
| | | item.setRateOpVehiclesYoy(getDecimal(row, colByName(hdr, 39, "公共汽电车_运营车数同比增速"))); |
| | | item.setRatePassengerYoy(getDecimal(row, colByName(hdr, 40, "公共汽电车_客运量同比增速"))); |
| | | item.setRatePassengerCityYoy(getDecimal(row, colByName(hdr, 41, "客运量_城市内同比增速"))); |
| | | item.setRateChengxiangYoy(getDecimal(row, colByName(hdr, 42, "城际城乡客运量同比增速"))); |
| | | item.setRateChengxiangTurnoverYoy(getDecimal(row, colByName(hdr, 43, "城际城乡旅客周转量同比增速"))); |
| | | item.setStopCityRatio(getDecimal(row, colByName(hdr, 44, "城市内运营站点占比"))); |
| | | item.setPassengerCityRatio(getDecimal(row, colByName(hdr, 45, "城市内客运量占比"))); |
| | | item.setChengxiangRatio(getDecimal(row, colByName(hdr, 46, "城际城乡客运量占比"))); |
| | | item.setRateTurnoverYoy(getDecimal(row, colByName(hdr, 47, "旅客周转量同比增速"))); |
| | | item.setRateTurnoverMom(getDecimal(row, colByName(hdr, 48, "旅客周转量环比增速"))); |
| | | item.setPassengerChengxiang(getDecimal(row, colByName(hdr, 49, "城际城乡客运量"))); |
| | | item.setTurnoverChengxiang(getDecimal(row, colByName(hdr, 50, "城际城乡旅客周转量"))); |
| | | item.setAvgDistanceChengxiang(getDecimal(row, colByName(hdr, 51, "城际城乡平均运距"))); |
| | | item.setVerifyExplanation(getString(row, colByName(hdr, 65, "核实性原因解释"))); |
| | | item.setReportNote(getString(row, colByName(hdr, 66, "上报说明"))); |
| | | item.setModifyRecord(getString(row, colByName(hdr, 67, "修改记录"))); |
| | | rows.add(new CityBusRow(r + 1, item)); |
| | | } |
| | | } catch (Exception e) { |
| | |
| | | List<TaxiRow> rows = new ArrayList<>(); |
| | | try (Workbook wb = WorkbookFactory.create(file.getInputStream())) { |
| | | Sheet sheet = wb.getSheetAt(0); |
| | | requireHeaderLayout(sheet, "巡游出租", "模板_交行统U402表-巡游出租汽车运营服务情况月报(2026).xls", |
| | | CITY_TAXI_HEADER_COLS, CITY_TAXI_HEADER_KEYWORDS); |
| | | Row hdr = sheet.getRow(0); |
| | | requireHeaderColsByName(sheet, "巡游出租", "模板_交行统U402表-巡游出租汽车运营服务情况月报(2026).xls", CITY_TAXI_HEADER_KEYWORDS); |
| | | for (int r = 1; r <= sheet.getLastRowNum(); r++) { |
| | | Row row = sheet.getRow(r); |
| | | if (row == null) continue; |
| | | String name = getString(row, 2); |
| | | String name = getString(row, colByName(hdr, 2, "企业名称")); |
| | | if (name == null || name.trim().isEmpty()) continue; |
| | | CityTaxiMonthly item = new CityTaxiMonthly(); |
| | | item.setReportPeriod(period); |
| | | item.setRegionCode(getString(row, 0)); |
| | | item.setCity(cityOf(getString(row, 0), name)); |
| | | item.setTripTotal(getDecimal(row, 4)); |
| | | item.setTripCity(getDecimal(row, 5)); |
| | | item.setPassengerVolume(getDecimal(row, 6)); |
| | | item.setPassengerCity(getDecimal(row, 7)); |
| | | item.setTurnover(getDecimal(row, 8)); |
| | | item.setTurnoverCity(getDecimal(row, 9)); |
| | | item.setOpVehicles(getDecimal(row, 10)); |
| | | item.setAvgDistance(getDecimal(row, 11)); |
| | | item.setAvgDistanceCity(getDecimal(row, 12)); |
| | | item.setContactPerson(getString(row, 15)); |
| | | item.setContactPhone(getString(row, 16)); |
| | | item.setReportDate(getDateString(row, 17)); |
| | | item.setDailyTripsPerVehicle(getDecimal(row, 18)); |
| | | item.setDailyPassengerPerVehicle(getDecimal(row, 19)); |
| | | item.setPassengersPerTrip(getDecimal(row, 20)); |
| | | item.setRateOpVehiclesMom(getDecimal(row, 21)); |
| | | item.setRateOpVehiclesYoy(getDecimal(row, 22)); |
| | | item.setRateTripMom(getDecimal(row, 23)); |
| | | item.setRateTripYoy(getDecimal(row, 24)); |
| | | item.setRatePassengerMom(getDecimal(row, 25)); |
| | | item.setRatePassengerYoy(getDecimal(row, 26)); |
| | | item.setAvgDistanceMomChange(getDecimal(row, 27)); |
| | | item.setPassengersPerTripCity(getDecimal(row, 28)); |
| | | item.setRateTripCityMom(getDecimal(row, 29)); |
| | | item.setRatePassengerCityMom(getDecimal(row, 30)); |
| | | item.setAvgDistanceCityMomChange(getDecimal(row, 31)); |
| | | item.setTripCityRatio(getDecimal(row, 32)); |
| | | item.setPassengerCityRatio(getDecimal(row, 33)); |
| | | item.setPassengersPerTripChengxiang(getDecimal(row, 34)); |
| | | item.setRateTripChengxiangMom(getDecimal(row, 35)); |
| | | item.setRatePassengerChengxiangMom(getDecimal(row, 36)); |
| | | item.setAvgDistanceChengxiang(getDecimal(row, 37)); |
| | | item.setVerifyExplanation(getString(row, 38)); |
| | | item.setReportNote(getString(row, 39)); |
| | | item.setModifyRecord(getString(row, 40)); |
| | | item.setRegionCode(getString(row, colByName(hdr, 0, "所属地区"))); |
| | | item.setCity(cityOf(getString(row, colByName(hdr, 0, "所属地区")), name)); |
| | | item.setTripTotal(getDecimal(row, colByName(hdr, 4, "载客车次总数"))); |
| | | item.setTripCity(getDecimal(row, colByName(hdr, 5, "载客车次总数_城市内"))); |
| | | item.setPassengerVolume(getDecimal(row, colByName(hdr, 6, "客运量"))); |
| | | item.setPassengerCity(getDecimal(row, colByName(hdr, 7, "客运量_其中城市内"))); |
| | | item.setTurnover(getDecimal(row, colByName(hdr, 8, "旅客周转量"))); |
| | | item.setTurnoverCity(getDecimal(row, colByName(hdr, 9, "旅客周转量_城市内"))); |
| | | item.setOpVehicles(getDecimal(row, colByName(hdr, 10, "运营车辆数"))); |
| | | item.setAvgDistance(getDecimal(row, colByName(hdr, 11, "巡游出租汽车平均运距"))); |
| | | item.setAvgDistanceCity(getDecimal(row, colByName(hdr, 12, "城市内平均运距"))); |
| | | item.setContactPerson(getString(row, colByName(hdr, 15, "填表人"))); |
| | | item.setContactPhone(getString(row, colByName(hdr, 16, "联系电话"))); |
| | | item.setReportDate(getDateString(row, colByName(hdr, 17, "报出日期"))); |
| | | item.setDailyTripsPerVehicle(getDecimal(row, colByName(hdr, 18, "单车日均载客车次"))); |
| | | item.setDailyPassengerPerVehicle(getDecimal(row, colByName(hdr, 19, "单车日均客运量"))); |
| | | item.setPassengersPerTrip(getDecimal(row, colByName(hdr, 20, "单车次载客人数"))); |
| | | item.setRateOpVehiclesMom(getDecimal(row, colByName(hdr, 21, "运营车数环比增速"))); |
| | | item.setRateOpVehiclesYoy(getDecimal(row, colByName(hdr, 22, "运营车数同比增速"))); |
| | | item.setRateTripMom(getDecimal(row, colByName(hdr, 23, "载客车次总数环比增速"))); |
| | | item.setRateTripYoy(getDecimal(row, colByName(hdr, 24, "载客车次同比增速"))); |
| | | item.setRatePassengerMom(getDecimal(row, colByName(hdr, 25, "客运量环比增速"))); |
| | | item.setRatePassengerYoy(getDecimal(row, colByName(hdr, 26, "客运量同比增速"))); |
| | | item.setAvgDistanceMomChange(getDecimal(row, colByName(hdr, 27, "平均运距环比增减"))); |
| | | item.setPassengersPerTripCity(getDecimal(row, colByName(hdr, 28, "单车次载客人数_城市内"))); |
| | | item.setRateTripCityMom(getDecimal(row, colByName(hdr, 29, "载客车次总数环比增速_城市内"))); |
| | | item.setRatePassengerCityMom(getDecimal(row, colByName(hdr, 30, "客运量环比增速_城市内"))); |
| | | item.setAvgDistanceCityMomChange(getDecimal(row, colByName(hdr, 31, "平均运距_城市内环比增减"))); |
| | | item.setTripCityRatio(getDecimal(row, colByName(hdr, 32, "载客车次总数_城市内占比"))); |
| | | item.setPassengerCityRatio(getDecimal(row, colByName(hdr, 33, "客运量_城市内占比"))); |
| | | item.setPassengersPerTripChengxiang(getDecimal(row, colByName(hdr, 34, "单车次载客人数_城际城乡"))); |
| | | item.setRateTripChengxiangMom(getDecimal(row, colByName(hdr, 35, "载客车次总数_城际城乡环比增速"))); |
| | | item.setRatePassengerChengxiangMom(getDecimal(row, colByName(hdr, 36, "客运量_城际城乡环比增速"))); |
| | | item.setAvgDistanceChengxiang(getDecimal(row, colByName(hdr, 37, "平均运距_城际城乡"))); |
| | | item.setVerifyExplanation(getString(row, colByName(hdr, 38, "核实性原因解释"))); |
| | | item.setReportNote(getString(row, colByName(hdr, 39, "上报说明"))); |
| | | item.setModifyRecord(getString(row, colByName(hdr, 40, "修改记录"))); |
| | | rows.add(new TaxiRow(r + 1, item)); |
| | | } |
| | | } catch (Exception e) { |