diff --git a/ruoyi-ems/src/main/java/org/dromara/ems/report/service/impl/TempBoardServiceImpl.java b/ruoyi-ems/src/main/java/org/dromara/ems/report/service/impl/TempBoardServiceImpl.java index 153ec02..52b5bb7 100644 --- a/ruoyi-ems/src/main/java/org/dromara/ems/report/service/impl/TempBoardServiceImpl.java +++ b/ruoyi-ems/src/main/java/org/dromara/ems/report/service/impl/TempBoardServiceImpl.java @@ -15,6 +15,7 @@ import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.Calendar; +import java.util.Collections; import java.util.Date; import java.util.List; @@ -33,6 +34,7 @@ import java.util.List; public class TempBoardServiceImpl implements ITempBoardService { private final TempBoardMapper tempBoardMapper; + //RecordIotenvPartitionService 按时间范围解析分表 private final RecordIotenvPartitionService partitionService; private static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; @@ -47,7 +49,7 @@ public class TempBoardServiceImpl implements ITempBoardService { /** * 解析查询时间范围并获取分表列表 - * 包含时间范围硬限制校验 + * 包含时间范围硬限制校验;无数据表时返回空集合(不抛异常,避免并发请求重复弹错) */ private List resolveTables(TempBoardQueryBo query) { if (query.getStartTime() == null || query.getEndTime() == null) { @@ -59,11 +61,7 @@ public class TempBoardServiceImpl implements ITempBoardService { if (diffDays > MAX_QUERY_DAYS) { throw new ServiceException("查询跨度不能超过" + MAX_QUERY_DAYS + "天,请缩小范围"); } - List tables = partitionService.resolveTables(query.getStartTime(), query.getEndTime()); - if (tables.isEmpty()) { - throw new ServiceException("所选时间范围内无数据表"); - } - return tables; + return partitionService.resolveTables(query.getStartTime(), query.getEndTime()); } /** Date → 格式化字符串(兼容旧接口) */ @@ -91,9 +89,13 @@ public class TempBoardServiceImpl implements ITempBoardService { // ==================== A. 温度总览 ==================== + /** 温度总览(测点数 + 平均温度 + 最高/最低 + TopN + 新鲜度) */ @Override public TempBoardOverviewVo getOverview(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return new TempBoardOverviewVo(); + } String startTime = fmt(query.getStartTime()); String endTime = fmt(query.getEndTime()); @@ -137,164 +139,257 @@ public class TempBoardServiceImpl implements ITempBoardService { // ==================== B. 实时监控 ==================== + /** 实时温度明细 */ @Override public List getRealtimeDetail(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectRealtimeDetail(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } + /** 高温测点 */ @Override public List getHighTempMonitors(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } double threshold = query.getHighTempThreshold() != null ? query.getHighTempThreshold() : 35.0; return tempBoardMapper.selectHighTempMonitors(tables, fmt(query.getStartTime()), fmt(query.getEndTime()), threshold); } + /** 低温测点 */ @Override public List getLowTempMonitors(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } double threshold = query.getLowTempThreshold() != null ? query.getLowTempThreshold() : 10.0; return tempBoardMapper.selectLowTempMonitors(tables, fmt(query.getStartTime()), fmt(query.getEndTime()), threshold); } + /** 长时间未更新测点 */ @Override public List getStaleMonitors(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } int threshold = query.getStaleThresholdSeconds() != null ? query.getStaleThresholdSeconds() : 600; return tempBoardMapper.selectStaleMonitors(tables, fmt(query.getStartTime()), fmt(query.getEndTime()), threshold); } + /** 入库延迟排行 */ @Override public List getDelayRanking(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectDelayRanking(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } // ==================== C. 趋势分析 ==================== + /** 单测点分钟趋势 */ @Override public List getMinuteTrend(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectMinuteTrend(tables, query.getMonitorId(), fmt(query.getStartTime()), fmt(query.getEndTime())); } + /** 单测点小时趋势 */ @Override public List getHourlyTrend(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectHourlyTrend(tables, query.getMonitorId(), fmt(query.getStartTime()), fmt(query.getEndTime())); } + /** 多测点对比趋势 */ @Override public List getMultiCompareTrend(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectMultiCompareTrend(tables, query.getMonitorIds(), fmt(query.getStartTime()), fmt(query.getEndTime())); } + /** 日均温趋势 */ @Override public List getDailyTrend(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectDailyTrend(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } + /** 温度变化率趋势 */ @Override public List getChangeRateTrend(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectChangeRateTrend(tables, query.getMonitorId(), fmt(query.getStartTime()), fmt(query.getEndTime())); } + /** 峰谷时刻表 */ @Override public List getPeakValley(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectPeakValley(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } // ==================== D. 分布分析 ==================== + /** 温度区间分布 */ @Override public List getIntervalDistribution(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectIntervalDistribution(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } + /** 温度直方图 */ @Override public List getHistogram(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectHistogram(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } + /** 温度箱线图原始数据 */ @Override public List getBoxplotData(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectBoxplotData(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } + /** 日历热力图 */ @Override public List getCalendarHeatmap(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectCalendarHeatmap(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } + /** 小时热力图 */ @Override public List getHourlyHeatmap(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectHourlyHeatmap(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } // ==================== E. 异常预警 ==================== + /** 高温事件 */ @Override public List getHighTempEvents(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } double threshold = query.getHighTempThreshold() != null ? query.getHighTempThreshold() : 35.0; return tempBoardMapper.selectHighTempEvents(tables, fmt(query.getStartTime()), fmt(query.getEndTime()), threshold); } + /** 低温事件 */ @Override public List getLowTempEvents(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } double threshold = query.getLowTempThreshold() != null ? query.getLowTempThreshold() : 10.0; return tempBoardMapper.selectLowTempEvents(tables, fmt(query.getStartTime()), fmt(query.getEndTime()), threshold); } + /** 连续高温时段 */ @Override public List getContinuousHighTemp(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } double threshold = query.getHighTempThreshold() != null ? query.getHighTempThreshold() : 35.0; return tempBoardMapper.selectContinuousHighTemp(tables, fmt(query.getStartTime()), fmt(query.getEndTime()), threshold); } + /** 温升过快事件 */ @Override public List getRapidRiseEvents(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } double threshold = query.getRapidRiseThreshold() != null ? query.getRapidRiseThreshold() : 1.0; return tempBoardMapper.selectRapidRiseEvents(tables, fmt(query.getStartTime()), fmt(query.getEndTime()), threshold); } + /** 温度抖动异常 */ @Override public List getJitterAnomalies(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } double threshold = query.getStddevThreshold() != null ? query.getStddevThreshold() : 2.0; return tempBoardMapper.selectJitterAnomalies(tables, fmt(query.getStartTime()), fmt(query.getEndTime()), threshold); } // ==================== F. 对比分析 ==================== + /** 测点平均温度排行 */ @Override public List getAvgTempRanking(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectAvgTempRanking(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } + /** 测点稳定性排行 */ @Override public List getStabilityRanking(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectStabilityRanking(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } + /** 今日vs昨日对比 */ @Override public List getDailyDiff(TempBoardQueryBo query) { // 今日和昨日的时间范围由 endTime 推算 @@ -326,91 +421,139 @@ public class TempBoardServiceImpl implements ITempBoardService { // 合并两天的分表 List tables = partitionService.resolveTables(yesterdayStart, todayEnd); if (tables.isEmpty()) { - throw new ServiceException("所选时间范围内无数据表"); + return Collections.emptyList(); } return tempBoardMapper.selectDailyDiff(tables, fmt(todayStart), fmt(todayEnd), fmt(yesterdayStart), fmt(yesterdayEnd)); } + /** 峰值对比 */ @Override public List getPeakCompare(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectPeakCompare(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } + /** 波动幅度对比 */ @Override public List getFluctuationCompare(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectFluctuationCompare(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } // ==================== G. 数据质量 ==================== + /** 入库延迟分布 */ @Override public List getDelayDistribution(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectDelayDistribution(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } + /** 时间逆序可疑数据 */ @Override public List getTimeReversal(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectTimeReversal(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } + /** 采样间隔异常 */ @Override public List getSamplingGapAnomalies(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } int threshold = query.getGapThresholdSeconds() != null ? query.getGapThresholdSeconds() : 300; return tempBoardMapper.selectSamplingGapAnomalies(tables, fmt(query.getStartTime()), fmt(query.getEndTime()), threshold); } + /** 数据完整率 */ @Override public List getCompletenessRate(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } int expectedCount = query.getExpectedSampleCount() != null ? query.getExpectedSampleCount() : 1440; return tempBoardMapper.selectCompletenessRate(tables, fmt(query.getStartTime()), fmt(query.getEndTime()), expectedCount); } + /** 测点活跃度 */ @Override public List getMonitorActivity(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectMonitorActivity(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } - // ==================== H. 高级分析(已优化) ==================== + // ==================== H. 高级分析 ==================== + /** 桑基图数据 */ @Override public List getSankeyData(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectSankeyData(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } + /** 主题河流图数据 */ @Override public List getThemeRiverData(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } // 根据时间跨度自动选择聚合粒度 String granularity = resolveGranularity(query); return tempBoardMapper.selectThemeRiverData( tables, fmt(query.getStartTime()), fmt(query.getEndTime()), granularity); } + /** 矩形树图数据 */ @Override public List getTreemapData(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectTreemapData(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } + /** 旭日图数据 */ @Override public List getSunburstData(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectSunburstData(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } + /** 平行坐标图数据 */ @Override public List getParallelData(TempBoardQueryBo query) { List tables = resolveTables(query); + if (tables.isEmpty()) { + return Collections.emptyList(); + } return tempBoardMapper.selectParallelData(tables, fmt(query.getStartTime()), fmt(query.getEndTime())); } }