xyc
2 天以前 b425da0611b39f20fc868645c59e17f72b70d148
traffic-audit-server/src/main/java/com/trafficaudit/holiday/service/HolidayStatService.java
@@ -8,7 +8,9 @@
import com.trafficaudit.holiday.entity.HolidayCalendar;
import com.trafficaudit.holiday.entity.HolidayPassengerFlow;
import com.trafficaudit.holiday.entity.HolidayVehicleFlow;
import com.trafficaudit.holiday.entity.HolidayVehicleAdjustment;
import com.trafficaudit.holiday.mapper.HolidayPassengerFlowMapper;
import com.trafficaudit.holiday.mapper.HolidayVehicleAdjustmentMapper;
import com.trafficaudit.holiday.mapper.HolidayVehicleFlowMapper;
import lombok.Data;
import org.springframework.stereotype.Service;
@@ -36,6 +38,8 @@
    private HolidayPassengerFlowMapper passengerFlowMapper;
    @Resource
    private HolidayVehicleFlowMapper vehicleFlowMapper;
    @Resource
    private HolidayVehicleAdjustmentMapper vehicleAdjustmentMapper;
    @Resource
    private ImportBatchMapper importBatchMapper;
@@ -93,37 +97,33 @@
        Map<LocalDate, Map<String, BigDecimal>> vehicleByDate = loadVehicleByDate(year);
        Map<LocalDate, BigDecimal> comparisonBaseByDate = loadComparisonBaseByDate(year);
        BigDecimal coefficient = configService.coefficientOf(year, HolidayConstants.CATEGORY_HOLIDAY);
        List<Map<String, Object>> rows = new ArrayList<>();
        BigDecimal previousNationalProvincial = null;
        Map<Integer, HolidayCalendar> calendarByDay = new LinkedHashMap<>();
        for (HolidayCalendar day : calendar) {
            Map<String, BigDecimal> passenger = passengerByDate.getOrDefault(day.getHolidayDate(), Collections.emptyMap());
            Map<String, BigDecimal> vehicle = vehicleByDate.getOrDefault(day.getHolidayDate(), Collections.emptyMap());
            BigDecimal expressway = vehicle.get(HolidayConstants.ROAD_EXPRESSWAY);
            BigDecimal nationalProvincial = vehicle.get(HolidayConstants.ROAD_NATIONAL_PROVINCIAL);
            BigDecimal comparisonBase = comparisonBaseByDate.get(day.getHolidayDate());
            BigDecimal nationalProvincialRingRatio = nationalProvincialRingRatio(
                    year, nationalProvincial, previousNationalProvincial, comparisonBase);
            BigDecimal nonBusinessPersonFlow = null;
            if (coefficient != null && (expressway != null || nationalProvincial != null)) {
                nonBusinessPersonFlow = HolidayNumberUtils.multiply(
                        HolidayNumberUtils.sumNullable(expressway, nationalProvincial), coefficient);
            }
            if (day.getDayIndex() != null) calendarByDay.put(day.getDayIndex(), day);
        }
        List<Map<String, Object>> rows = new ArrayList<>();
        for (HolidayCalendar day : calendar) {
            DailyMetrics current = buildDailyMetrics(year, holidayType, day.getDayIndex(), day.getHolidayDate(),
                    passengerByDate, vehicleByDate, comparisonBaseByDate, coefficient);
            DailyMetrics ringRatioBase = ringRatioBaseFromMaps(year, holidayType, day.getDayIndex(), calendarByDay,
                    passengerByDate, vehicleByDate, comparisonBaseByDate, coefficient);
            BigDecimal nationalProvincialRingRatio = ratio(current.getNationalProvincial(),
                    ringRatioBase == null ? null : ringRatioBase.getNationalProvincial());
            Map<String, Object> row = new LinkedHashMap<>();
            row.put("dayIndex", day.getDayIndex());
            row.put("date", day.getHolidayDate());
            row.put("rail", passenger.get(HolidayConstants.MODE_RAIL));
            row.put("civilAviation", passenger.get(HolidayConstants.MODE_CIVIL_AVIATION));
            row.put("road", passenger.get(HolidayConstants.MODE_ROAD));
            row.put("water", passenger.get(HolidayConstants.MODE_WATER));
            row.put("expressway", expressway);
            row.put("nationalProvincial", nationalProvincial);
            row.put("comparisonBase", comparisonBase);
            row.put("rail", current.getRail());
            row.put("civilAviation", current.getCivilAviation());
            row.put("road", current.getRoad());
            row.put("water", current.getWater());
            row.put("expressway", current.getExpressway());
            row.put("nationalProvincial", current.getNationalProvincial());
            row.put("comparisonBase", current.getComparisonBase());
            row.put("nationalProvincialRingRatio", nationalProvincialRingRatio);
            row.put("coefficient", coefficient);
            row.put("nonBusinessPersonFlow", nonBusinessPersonFlow);
            row.put("totalPersonFlow", totalPersonFlow(passenger, nonBusinessPersonFlow));
            row.put("coefficient", current.getCoefficient());
            row.put("nonBusinessPersonFlow", current.getNonBusinessPersonFlow());
            row.put("totalPersonFlow", current.getTotalPersonFlow());
            rows.add(row);
            previousNationalProvincial = nationalProvincial;
        }
        return rows;
    }
@@ -138,27 +138,55 @@
            }
        }
        if (target == null) return null;
        return dailyMetrics(year, holidayType, dayIndex, target.getHolidayDate());
    }
    public DailyMetrics dailyMetricsByDate(LocalDate date) {
        if (date == null) return null;
        return dailyMetrics(date.getYear(), null, 0, date);
    }
    private DailyMetrics dailyMetrics(int year, String holidayType, int dayIndex, LocalDate date) {
        Map<LocalDate, Map<String, BigDecimal>> passengerByDate = loadPassengerByDate(year);
        Map<LocalDate, Map<String, BigDecimal>> vehicleByDate = loadVehicleByDate(year);
        Map<LocalDate, BigDecimal> comparisonBaseByDate = loadComparisonBaseByDate(year);
        Map<String, BigDecimal> passenger = passengerByDate.getOrDefault(target.getHolidayDate(), Collections.emptyMap());
        Map<String, BigDecimal> vehicle = vehicleByDate.getOrDefault(target.getHolidayDate(), Collections.emptyMap());
        BigDecimal coefficient = configService.coefficientOf(year, HolidayConstants.CATEGORY_HOLIDAY);
        return buildDailyMetrics(year, holidayType, dayIndex, date, passengerByDate, vehicleByDate,
                comparisonBaseByDate, coefficient);
    }
    public DailyMetrics ringRatioBaseMetrics(int year, String holidayType, int dayIndex) {
        if (dayIndex <= 1) return null;
        List<HolidayCalendar> calendar = configService.findHolidayDays(year, holidayType);
        Map<Integer, HolidayCalendar> calendarByDay = new LinkedHashMap<>();
        for (HolidayCalendar day : calendar) {
            if (day.getDayIndex() != null) calendarByDay.put(day.getDayIndex(), day);
        }
        Map<LocalDate, Map<String, BigDecimal>> passengerByDate = loadPassengerByDate(year);
        Map<LocalDate, Map<String, BigDecimal>> vehicleByDate = loadVehicleByDate(year);
        Map<LocalDate, BigDecimal> comparisonBaseByDate = loadComparisonBaseByDate(year);
        BigDecimal coefficient = configService.coefficientOf(year, HolidayConstants.CATEGORY_HOLIDAY);
        return ringRatioBaseFromMaps(year, holidayType, dayIndex, calendarByDay, passengerByDate,
                vehicleByDate, comparisonBaseByDate, coefficient);
    }
    private DailyMetrics buildDailyMetrics(int year, String holidayType, int dayIndex, LocalDate date,
                                           Map<LocalDate, Map<String, BigDecimal>> passengerByDate,
                                           Map<LocalDate, Map<String, BigDecimal>> vehicleByDate,
                                           Map<LocalDate, BigDecimal> comparisonBaseByDate,
                                           BigDecimal coefficient) {
        Map<String, BigDecimal> passenger = passengerByDate.getOrDefault(date, Collections.emptyMap());
        Map<String, BigDecimal> vehicle = vehicleByDate.getOrDefault(date, Collections.emptyMap());
        BigDecimal expressway = vehicle.get(HolidayConstants.ROAD_EXPRESSWAY);
        BigDecimal nationalProvincial = vehicle.get(HolidayConstants.ROAD_NATIONAL_PROVINCIAL);
        BigDecimal comparisonBase = comparisonBaseByDate.get(target.getHolidayDate());
        BigDecimal nonBusiness = null;
        if (coefficient != null && (expressway != null || nationalProvincial != null)) {
            nonBusiness = HolidayNumberUtils.multiply(
                    HolidayNumberUtils.sumNullable(expressway, nationalProvincial), coefficient);
        }
        BigDecimal comparisonBase = comparisonBaseByDate.get(date);
        BigDecimal nonBusiness = nonBusinessPersonFlow(expressway, nationalProvincial, coefficient);
        DailyMetrics metrics = new DailyMetrics();
        metrics.setYear(year);
        metrics.setHolidayType(holidayType);
        metrics.setDayIndex(dayIndex);
        metrics.setDate(target.getHolidayDate());
        metrics.setDate(date);
        metrics.setRail(passenger.get(HolidayConstants.MODE_RAIL));
        metrics.setCivilAviation(passenger.get(HolidayConstants.MODE_CIVIL_AVIATION));
        metrics.setRoad(passenger.get(HolidayConstants.MODE_ROAD));
@@ -168,9 +196,43 @@
        metrics.setComparisonBase(comparisonBase);
        metrics.setCoefficient(coefficient);
        metrics.setNonBusinessPersonFlow(nonBusiness);
        metrics.setRoadPersonFlow(sumNullable(metrics.getRoad(), nonBusiness));
        metrics.setTotalPersonFlow(totalPersonFlow(passenger, nonBusiness));
        recalculateDerived(metrics);
        return metrics;
    }
    private DailyMetrics ringRatioBaseFromMaps(int year, String holidayType, int dayIndex,
                                               Map<Integer, HolidayCalendar> calendarByDay,
                                               Map<LocalDate, Map<String, BigDecimal>> passengerByDate,
                                               Map<LocalDate, Map<String, BigDecimal>> vehicleByDate,
                                               Map<LocalDate, BigDecimal> comparisonBaseByDate,
                                               BigDecimal coefficient) {
        if (dayIndex <= 1) return null;
        HolidayCalendar previous = calendarByDay.get(dayIndex - 1);
        if (previous == null || previous.getHolidayDate() == null) return null;
        DailyMetrics base = buildDailyMetrics(year, holidayType, previous.getDayIndex(), previous.getHolidayDate(),
                passengerByDate, vehicleByDate, comparisonBaseByDate, coefficient);
        BigDecimal comparisonBase = comparisonBaseByDate.get(previous.getHolidayDate());
        if (comparisonBase != null) {
            base.setNationalProvincial(comparisonBase);
            recalculateDerived(base);
        }
        return base;
    }
    private void recalculateDerived(DailyMetrics metrics) {
        BigDecimal nonBusiness = nonBusinessPersonFlow(metrics.getExpressway(), metrics.getNationalProvincial(),
                metrics.getCoefficient());
        metrics.setNonBusinessPersonFlow(nonBusiness);
        metrics.setRoadPersonFlow(sumNullable(metrics.getRoad(), nonBusiness));
        metrics.setTotalPersonFlow(totalPersonFlow(nonBusiness, metrics.getRoad(), metrics.getRail(),
                metrics.getCivilAviation(), metrics.getWater()));
    }
    private BigDecimal nonBusinessPersonFlow(BigDecimal expressway, BigDecimal nationalProvincial,
                                            BigDecimal coefficient) {
        if (coefficient == null || (expressway == null && nationalProvincial == null)) return null;
        return HolidayNumberUtils.multiply(
                HolidayNumberUtils.sumNullable(expressway, nationalProvincial), coefficient);
    }
    public DailyMetrics cumulativeMetrics(int year, String holidayType, int dayIndex) {
@@ -220,6 +282,23 @@
            result.computeIfAbsent(row.getFlowDate(), key -> new LinkedHashMap<>())
                    .put(row.getRoadCategory(), row.getVehicleCount());
        }
        Map<LocalDate, BigDecimal> adjustments = loadNationalProvincialAdjustmentsByDate(year);
        for (Map.Entry<LocalDate, BigDecimal> entry : adjustments.entrySet()) {
            result.computeIfAbsent(entry.getKey(), key -> new LinkedHashMap<>())
                    .put(HolidayConstants.ROAD_NATIONAL_PROVINCIAL, entry.getValue());
        }
        return result;
    }
    private Map<LocalDate, BigDecimal> loadNationalProvincialAdjustmentsByDate(int year) {
        Map<LocalDate, BigDecimal> result = new LinkedHashMap<>();
        List<HolidayVehicleAdjustment> rows = vehicleAdjustmentMapper.selectList(
                new LambdaQueryWrapper<HolidayVehicleAdjustment>().eq(HolidayVehicleAdjustment::getYear, year));
        for (HolidayVehicleAdjustment row : rows) {
            if (row.getFlowDate() != null && row.getAdjustedValue() != null) {
                result.put(row.getFlowDate(), row.getAdjustedValue());
            }
        }
        return result;
    }
@@ -235,23 +314,16 @@
        return result;
    }
    private BigDecimal totalPersonFlow(Map<String, BigDecimal> passenger, BigDecimal nonBusinessPersonFlow) {
    private BigDecimal totalPersonFlow(BigDecimal nonBusinessPersonFlow, BigDecimal road, BigDecimal rail,
                                       BigDecimal civilAviation, BigDecimal water) {
        BigDecimal total = nonBusinessPersonFlow;
        total = sumNullable(total, passenger.get(HolidayConstants.MODE_ROAD));
        total = sumNullable(total, passenger.get(HolidayConstants.MODE_RAIL));
        total = sumNullable(total, passenger.get(HolidayConstants.MODE_CIVIL_AVIATION));
        total = sumNullable(total, passenger.get(HolidayConstants.MODE_WATER));
        total = sumNullable(total, road);
        total = sumNullable(total, rail);
        total = sumNullable(total, civilAviation);
        total = sumNullable(total, water);
        return total;
    }
    private BigDecimal nationalProvincialRingRatio(int year, BigDecimal current,
                                                   BigDecimal previous, BigDecimal comparisonBase) {
        if (current == null) return null;
        if (HolidayConstants.supportsComparisonBase(year) && comparisonBase != null) {
            return ratio(current, comparisonBase);
        }
        return previous == null ? null : ratio(current, previous);
    }
    private BigDecimal ratio(BigDecimal current, BigDecimal base) {
        BigDecimal quotient = HolidayNumberUtils.divide(current, base);