| | |
| | | import com.ruoyi.http.service.StatisticEleService; |
| | | import com.ruoyi.http.util.StatisticEleAggregateUtil; |
| | | import com.ruoyi.http.util.StatisticEleAggregateUtil.HourRange; |
| | | import com.ruoyi.http.util.StatisticEleAnalyticsUtil; |
| | | import com.ruoyi.http.util.StatisticEleAnalyticsUtil.DateBounds; |
| | | import com.ruoyi.http.vo.StatisticEleAnalyticsVo; |
| | | import com.ruoyi.http.vo.StatisticEleRecordVo; |
| | | import com.ruoyi.http.vo.StatisticEleSummaryVo; |
| | | import com.ruoyi.http.vo.StatisticEleSyncStatusVo; |
| | |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.function.Function; |
| | | import java.util.stream.Collectors; |
| | | |
| | | @Service |
| | | @Slf4j |
| | | @RequiredArgsConstructor |
| | | public class StatisticEleServiceImpl implements StatisticEleService { |
| | | |
| | | private static final Set<String> STAT_DIMENSIONS = Set.of("day", "month", "quarter", "year"); |
| | | private static final Set<String> STAT_DIMENSIONS = Set.of("day", "week", "month", "quarter", "year"); |
| | | private static final List<String> DATA_DIMENSIONS = List.of("hour", "manual"); |
| | | private static final DateTimeFormatter LOG_TIME_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); |
| | | |
| | | private static final DateTimeFormatter DAY_FMT = DateTimeFormatter.ofPattern("yyyyMMdd"); |
| | | |
| | | private final TqdianbiaoConfig config; |
| | | private final TqdianbiaoEleRecordMapper eleRecordMapper; |
| | |
| | | throw new ServiceException("开始时间和结束时间不能为空"); |
| | | } |
| | | if ("hour".equals(dimension)) { |
| | | List<StatisticEleRecordVo> detailRecords = queryHourRecords(startTime, endTime); |
| | | List<StatisticEleRecordVo> hourRecords = queryHourRecords(startTime, endTime); |
| | | List<StatisticEleRecordVo> chartRecords = StatisticEleAggregateUtil.aggregateHourToBuckets( |
| | | detailRecords, StatisticEleAggregateUtil.HOUR_TO_HOUR); |
| | | return buildSummary(detailRecords, chartRecords); |
| | | hourRecords, StatisticEleAggregateUtil.HOUR_TO_HOUR); |
| | | return buildSummary(hourRecords, chartRecords, hourRecords); |
| | | } |
| | | if (!STAT_DIMENSIONS.contains(dimension)) { |
| | | throw new ServiceException("统计维度无效,支持 hour/day/month/quarter/year"); |
| | | throw new ServiceException("统计维度无效,支持 hour/day/week/month/quarter/year"); |
| | | } |
| | | |
| | | if ("day".equals(dimension)) { |
| | | return getDayDimensionSummary(startTime, endTime); |
| | | } |
| | | |
| | | HourRange range = StatisticEleAggregateUtil.toHourQueryRange(dimension, startTime, endTime); |
| | | List<StatisticEleRecordVo> hourRecords = queryHourRecords(range.startTime(), range.endTime()); |
| | | List<StatisticEleRecordVo> detailRecords = aggregateFromHour(dimension, startTime, endTime, true); |
| | | List<StatisticEleRecordVo> chartRecords = aggregateFromHour(dimension, startTime, endTime, false); |
| | | return buildSummary(detailRecords, chartRecords); |
| | | return buildSummary(detailRecords, chartRecords, hourRecords); |
| | | } |
| | | |
| | | @Override |
| | | public StatisticEleAnalyticsVo getAnalytics(String dimension, String startTime, String endTime, String trendGranularity) { |
| | | if (!StringUtils.hasText(startTime) || !StringUtils.hasText(endTime)) { |
| | | throw new ServiceException("开始时间和结束时间不能为空"); |
| | | } |
| | | StatisticEleSummaryVo summary = getSummary(dimension, startTime, endTime); |
| | | HourRange range = StatisticEleAggregateUtil.toHourQueryRange( |
| | | normalizeAnalyticsDimension(dimension), startTime, endTime); |
| | | List<StatisticEleRecordVo> hourRecords = queryHourRecords(range.startTime(), range.endTime()); |
| | | List<StatisticEleRecordVo> hourlyMerged = StatisticEleAggregateUtil.aggregateHourToBuckets( |
| | | hourRecords, StatisticEleAggregateUtil.HOUR_TO_HOUR); |
| | | |
| | | boolean singleDay = "day".equals(dimension) && startTime.equals(endTime); |
| | | String trend = StringUtils.hasText(trendGranularity) |
| | | ? trendGranularity |
| | | : StatisticEleAnalyticsUtil.defaultTrendGranularity(dimension, singleDay); |
| | | |
| | | StatisticEleAnalyticsVo analytics = copyToAnalytics(summary); |
| | | analytics.setLoadRate(StatisticEleAnalyticsUtil.calcLoadRate( |
| | | summary.getAvgConsumption(), summary.getMaxConsumption())); |
| | | analytics.setPeriodSplits(StatisticEleAnalyticsUtil.calcPeriodSplits(hourlyMerged)); |
| | | analytics.setShiftSplits(StatisticEleAnalyticsUtil.calcShiftSplits(hourlyMerged)); |
| | | analytics.setDayTypeSplits(StatisticEleAnalyticsUtil.calcDayTypeSplits(hourlyMerged)); |
| | | analytics.setTrendGranularity(trend); |
| | | analytics.setTrendRecords(StatisticEleAggregateUtil.aggregateHourToBuckets( |
| | | hourRecords, StatisticEleAnalyticsUtil.trendBucketFn(trend))); |
| | | |
| | | DateBounds bounds = StatisticEleAnalyticsUtil.resolveBounds(dimension, startTime, endTime); |
| | | Double chainTotal = queryTotalByDayBounds(StatisticEleAnalyticsUtil.shiftChain(bounds)); |
| | | Double yoyTotal = queryTotalByDayBounds(StatisticEleAnalyticsUtil.shiftYoy(bounds)); |
| | | analytics.setChainComparison(StatisticEleAnalyticsUtil.buildComparison( |
| | | "chain", "环比上期", summary.getTotalConsumption(), chainTotal)); |
| | | analytics.setYoyComparison(StatisticEleAnalyticsUtil.buildComparison( |
| | | "yoy", "同比去年同期", summary.getTotalConsumption(), yoyTotal)); |
| | | return analytics; |
| | | } |
| | | |
| | | private String normalizeAnalyticsDimension(String dimension) { |
| | | return STAT_DIMENSIONS.contains(dimension) ? dimension : "day"; |
| | | } |
| | | |
| | | private Double queryTotalByDayBounds(DateBounds bounds) { |
| | | String start = bounds.start().format(DAY_FMT); |
| | | String end = bounds.end().format(DAY_FMT); |
| | | HourRange range = StatisticEleAggregateUtil.toHourQueryRange("day", start, end); |
| | | List<StatisticEleRecordVo> hourRecords = queryHourRecords(range.startTime(), range.endTime()); |
| | | if (hourRecords.isEmpty()) { |
| | | return 0.0; |
| | | } |
| | | return StatisticEleAnalyticsUtil.calcCombinedMetrics( |
| | | hourRecords, |
| | | StatisticEleAggregateUtil.aggregateHourToBuckets(hourRecords, StatisticEleAggregateUtil.HOUR_TO_DAY) |
| | | ).getTotalConsumption(); |
| | | } |
| | | |
| | | private StatisticEleAnalyticsVo copyToAnalytics(StatisticEleSummaryVo summary) { |
| | | StatisticEleAnalyticsVo analytics = new StatisticEleAnalyticsVo(); |
| | | analytics.setTotalConsumption(summary.getTotalConsumption()); |
| | | analytics.setAvgConsumption(summary.getAvgConsumption()); |
| | | analytics.setMaxConsumption(summary.getMaxConsumption()); |
| | | analytics.setMinConsumption(summary.getMinConsumption()); |
| | | analytics.setRecordCount(summary.getRecordCount()); |
| | | analytics.setChartRecords(summary.getChartRecords()); |
| | | analytics.setRecords(summary.getRecords()); |
| | | return analytics; |
| | | } |
| | | |
| | | /** |
| | |
| | | ? StatisticEleAggregateUtil.aggregateHourToBuckets(hourRecords, StatisticEleAggregateUtil.HOUR_TO_HOUR) |
| | | : StatisticEleAggregateUtil.aggregateHourToBuckets(hourRecords, StatisticEleAggregateUtil.HOUR_TO_DAY); |
| | | |
| | | return buildSummary(detailRecords, chartRecords); |
| | | return buildSummary(detailRecords, chartRecords, hourRecords); |
| | | } |
| | | |
| | | private StatisticEleSummaryVo buildSummary( |
| | | List<StatisticEleRecordVo> detailRecords, List<StatisticEleRecordVo> chartRecords) { |
| | | List<StatisticEleRecordVo> detailRecords, |
| | | List<StatisticEleRecordVo> chartRecords, |
| | | List<StatisticEleRecordVo> hourRecords) { |
| | | StatisticEleAggregateUtil.StatisticEleSummaryMetrics metrics = |
| | | StatisticEleAggregateUtil.calcMetrics(chartRecords); |
| | | StatisticEleAnalyticsUtil.calcCombinedMetrics(hourRecords, chartRecords); |
| | | StatisticEleSummaryVo summary = new StatisticEleSummaryVo(); |
| | | summary.setRecords(detailRecords); |
| | | summary.setChartRecords(chartRecords); |