diff --git a/src/main/java/com/southern/power/grid/controller/DnerEventController.java b/src/main/java/com/southern/power/grid/controller/DnerEventController.java index 887517e..65ca835 100644 --- a/src/main/java/com/southern/power/grid/controller/DnerEventController.java +++ b/src/main/java/com/southern/power/grid/controller/DnerEventController.java @@ -94,7 +94,7 @@ public class DnerEventController { * * @return 结果 */ - @PostMapping("/downloadTemplate") + @GetMapping("/downloadTemplate") public ResponseEntity downloadTemplate() { return dnerEventService.downloadTemplate(); } diff --git a/src/main/java/com/southern/power/grid/dao/PmdsQxjCityWeatherMapper.java b/src/main/java/com/southern/power/grid/dao/PmdsQxjCityWeatherMapper.java new file mode 100644 index 0000000..10ec885 --- /dev/null +++ b/src/main/java/com/southern/power/grid/dao/PmdsQxjCityWeatherMapper.java @@ -0,0 +1,27 @@ +package com.southern.power.grid.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.southern.power.grid.entity.PmdsQxjCityWeather; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 城市天气表 Mapper接口 + * + * @Author junzhangfm + * @Date 2026-03-31 + */ +@Mapper +public interface PmdsQxjCityWeatherMapper extends BaseMapper { + /** + * 查询符合条件的气象数据 + * + * @param districtCodeList 地区编码集合 + * @param startDateTimeStr 查看开始时间,比如2026-03-30 20:00:00.0 + * @return 结果 + */ + List selectListFilter(@Param("districtCodeList") List districtCodeList, + @Param("startDateTimeStr") String startDateTimeStr); +} diff --git a/src/main/java/com/southern/power/grid/entity/AreaTreeReq.java b/src/main/java/com/southern/power/grid/entity/AreaTreeReq.java index 2c5f93d..ba3e2bd 100644 --- a/src/main/java/com/southern/power/grid/entity/AreaTreeReq.java +++ b/src/main/java/com/southern/power/grid/entity/AreaTreeReq.java @@ -97,7 +97,7 @@ public class AreaTreeReq { /** * 未来XX小时/天 */ - Integer futureTempPastTime; + Integer avgTempFutureTime; /** * 未来XX小时/天的平均气温超过的℃ @@ -107,7 +107,7 @@ public class AreaTreeReq { /** * 未来XX小时/天 */ - Integer futureWindPastTime; + Integer maxWindFutureTime; /** * 未来XX小时/天的极大风速超过的m/s diff --git a/src/main/java/com/southern/power/grid/entity/PmdsQxjCityWeather.java b/src/main/java/com/southern/power/grid/entity/PmdsQxjCityWeather.java new file mode 100644 index 0000000..5eefdf3 --- /dev/null +++ b/src/main/java/com/southern/power/grid/entity/PmdsQxjCityWeather.java @@ -0,0 +1,121 @@ +package com.southern.power.grid.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 城市天气表 实体类 + * 表名:pmds_qxj_city_weather + * + * @Author junzhangfm + * @Date 2026-03-31 + */ +@Data +@TableName("pmds_qxj_city_weather") +public class PmdsQxjCityWeather { + + /** + * 站号 + */ + private String v01301; + + /** + * 行政区编码 + */ + private String vAcode; + + /** + * 所属省份 + */ + private String vPrcode; + + /** + * 所属地市 + */ + private String vCity; + + /** + * 所属区县 + */ + private String vCounty; + + /** + * 纬度 + */ + private String v05001; + + /** + * 经度 + */ + private String v06001; + + /** + * 预报时次 + */ + private String ddatetime; + + /** + * 预报时效,小时 + */ + private Integer predictionTime; + + /** + * 天气现象 + */ + private String weatherType; + + /** + * 温度 + */ + private String tem; + + /** + * 最高温度 + */ + private String temMax; + + /** + * 最低温度 + */ + private String temMin; + + /** + * 降水量,毫米 + */ + private String precipitation; + + /** + * 相对湿度 + */ + private String rhum; + + /** + * 风速 + */ + private String windSpeed; + + /** + * 风向 + */ + private String windDirection; + + /** + * 云量,成 + */ + private String cloud; + + /** + * 能见度,km + */ + private String vis; + + /** + * 资料更新时间 + */ + private String dUpdatetime; + + /** + * 入库时间 + */ + private String rksj; +} diff --git a/src/main/java/com/southern/power/grid/listener/DataExcelListener.java b/src/main/java/com/southern/power/grid/listener/DataExcelListener.java index 416b2cf..86bfb0a 100644 --- a/src/main/java/com/southern/power/grid/listener/DataExcelListener.java +++ b/src/main/java/com/southern/power/grid/listener/DataExcelListener.java @@ -52,8 +52,10 @@ public class DataExcelListener extends AnalysisEventListener { @Setter private ImportTask task; + @Setter private int success = 0; + @Setter private int fail = 0; // 逐行读取(不会OOM) diff --git a/src/main/java/com/southern/power/grid/service/impl/AsyncImportServiceImpl.java b/src/main/java/com/southern/power/grid/service/impl/AsyncImportServiceImpl.java index fca7ee6..eac47d1 100644 --- a/src/main/java/com/southern/power/grid/service/impl/AsyncImportServiceImpl.java +++ b/src/main/java/com/southern/power/grid/service/impl/AsyncImportServiceImpl.java @@ -54,6 +54,8 @@ public class AsyncImportServiceImpl { .set(ImportTask::getStatus, ImportTaskStatusEnum.FAILED.getCode()) // 失败状态 .set(ImportTask::getFailMsg, e.getMessage()) // 更新原因 .eq(ImportTask::getTaskNo, task.getTaskNo())); + dataExcelListener.setSuccess(0); + dataExcelListener.setFail(0); log.error("导入异常", e); } } diff --git a/src/main/java/com/southern/power/grid/service/impl/DnerEventServiceImpl.java b/src/main/java/com/southern/power/grid/service/impl/DnerEventServiceImpl.java index 95e8188..65d3ecd 100644 --- a/src/main/java/com/southern/power/grid/service/impl/DnerEventServiceImpl.java +++ b/src/main/java/com/southern/power/grid/service/impl/DnerEventServiceImpl.java @@ -22,6 +22,7 @@ import java.time.LocalDateTime; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.function.Function; import java.util.stream.Collectors; /** @@ -59,9 +60,18 @@ public class DnerEventServiceImpl extends ServiceImpl listVO() { List dnerEventVOS = dnerEventMapper.listVO(); if (!CollectionUtil.isEmpty(dnerEventVOS)) { + List eventIds = dnerEventVOS.stream().map(DnerEventVO::getId).collect(Collectors.toList()); + // 查询附件信息 + List attachmentList = dnerEventAttachmentMapper.selectList( + new LambdaQueryWrapper().eq(DnerEventAttachment::getIsLatest, 1) + .in(DnerEventAttachment::getEventId, eventIds)); + // 结果按eventId分组获取map + Map attachmentGroupMap = attachmentList.stream().collect(Collectors.toMap( + DnerEventAttachment::getEventId, Function.identity(), (k1, k2) -> k1 + )); + // 查询附件导出记录 List dnerEventExportRecords = dnerEventExportRecordMapper.selectList( - new LambdaQueryWrapper().in(DnerEventExportRecord::getEventId, - dnerEventVOS.stream().map(DnerEventVO::getId).collect(Collectors.toList()))); + new LambdaQueryWrapper().in(DnerEventExportRecord::getEventId, eventIds)); // 结果按eventId分组获取map Map> groupMap = dnerEventExportRecords.stream().collect( Collectors.groupingBy(DnerEventExportRecord::getEventId)); @@ -70,6 +80,12 @@ public class DnerEventServiceImpl extends ServiceImpl a2.getExportTime().compareTo(a1.getExportTime()))); // 塞入导出记录 dnerEventVOS.forEach(e -> { + DnerEventAttachment eventAttachment = attachmentGroupMap.get(e.getId()); + if (!Objects.isNull(eventAttachment)) { + e.setAttachmentId(eventAttachment.getId()); + e.setFileName(eventAttachment.getFileName()); + e.setFileType(eventAttachment.getFileType()); + } e.setEventExportRecordList(groupMap.get(e.getId())); }); } diff --git a/src/main/java/com/southern/power/grid/service/impl/DnerSiteAreaConfigurationServiceImpl.java b/src/main/java/com/southern/power/grid/service/impl/DnerSiteAreaConfigurationServiceImpl.java index a1c6cd4..7c35376 100644 --- a/src/main/java/com/southern/power/grid/service/impl/DnerSiteAreaConfigurationServiceImpl.java +++ b/src/main/java/com/southern/power/grid/service/impl/DnerSiteAreaConfigurationServiceImpl.java @@ -1,10 +1,13 @@ package com.southern.power.grid.service.impl; +import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.southern.power.grid.dao.DnerSiteAreaConfigurationMapper; +import com.southern.power.grid.dao.PmdsQxjCityWeatherMapper; import com.southern.power.grid.entity.AreaTreeReq; import com.southern.power.grid.entity.AreaTreeVO; import com.southern.power.grid.entity.DnerSiteAreaConfiguration; +import com.southern.power.grid.entity.PmdsQxjCityWeather; import com.southern.power.grid.enums.ChartQueryTypeEnum; import com.southern.power.grid.service.IDnerSiteAreaConfigurationService; import com.southern.power.grid.utils.TimeUtil; @@ -12,9 +15,12 @@ import lombok.NonNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.time.Duration; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.util.*; +import java.util.stream.Collectors; /** * 行政区划配置表 -- service实现类 @@ -29,6 +35,9 @@ public class DnerSiteAreaConfigurationServiceImpl @Autowired private DnerSiteAreaConfigurationMapper dnerSiteAreaConfigurationMapper; + @Autowired + private PmdsQxjCityWeatherMapper pmdsQxjCityWeatherMapper; + @Override public List queryAreaTree(AreaTreeReq req) { // 判断是否开启高级筛选 @@ -44,8 +53,13 @@ public class DnerSiteAreaConfigurationServiceImpl List dataList; if (ChartQueryTypeEnum.HOURLY_CHART.getCode().equals(req.getQueryType())) { // 分时图 - handleHourlyAdvancedFilter(req); // 分时图高级筛选处理 + handleHourlyAdvancedFilter(req); // 分时图高级筛选处理 -- 过去条件 dataList = dnerSiteAreaConfigurationMapper.selectHourlyChartAreaTree(req); + if (CollectionUtil.isEmpty(dataList)) { + return new ArrayList<>(); + } + // 过滤未来条件 + dataList = filterFutureCondition(req, dataList); } else { // 日K图 handleDailyAdvancedFilter(req); // 日K图高级筛选处理 @@ -62,6 +76,223 @@ public class DnerSiteAreaConfigurationServiceImpl return result; } + private @NonNull List filterFutureCondition(AreaTreeReq req, + List dataList) { + List districtCodeList = dataList.stream().map( + DnerSiteAreaConfiguration::getDistrictCode).collect(Collectors.toList()); + List before20WeatherList = new ArrayList<>(); + List current8weatherList = new ArrayList<>(); + List current20weatherList = new ArrayList<>(); + LocalDateTime now = LocalDateTime.now(); + LocalDateTime before20DateTime = now.minusDays(1).toLocalDate().atTime( + LocalTime.of(20, 0)); + LocalDateTime current8DateTime = now.toLocalDate().atTime(LocalTime.of(8, 0)); + LocalDateTime current20DateTime = now.toLocalDate().atTime(LocalTime.of(20, 0)); + if ((!Objects.isNull(req.getRainFutureTime()) && req.getRainFutureTime() != 0) + || (!Objects.isNull(req.getAvgTempFutureTime()) && req.getAvgTempFutureTime() != 0) + || (!Objects.isNull(req.getMaxWindFutureTime()) && req.getMaxWindFutureTime() != 0)) { + // 查询当前时间前一天晚上20点开始后的记录 + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S"); + String before20 = before20DateTime.format(dateTimeFormatter); + List weatherList = pmdsQxjCityWeatherMapper.selectListFilter(districtCodeList, before20); + // 过滤获取前一天20点、当天8点、当天20点的数据 + before20WeatherList = weatherList.stream().filter( + e -> e.getDdatetime().equals(before20)).collect(Collectors.toList()); + String current8DateTimeStr = current8DateTime.format(dateTimeFormatter); + current8weatherList = weatherList.stream().filter(e -> e.getDdatetime().equals( + current8DateTimeStr)).collect(Collectors.toList()); + String current20DateTimeStr = current20DateTime.format(dateTimeFormatter); + current20weatherList = weatherList.stream().filter(e -> e.getDdatetime().equals( + current20DateTimeStr)).collect(Collectors.toList()); + } + // 未来天气条件过滤 + // 未来降雨 + dataList = filterFutureRain(req, dataList, before20WeatherList, current8weatherList, current20weatherList); + // 未来平均气温 + dataList = filterFutureAvgTem(req, dataList, before20WeatherList, current8weatherList, current20weatherList); + // 未来风速 + dataList = filterFutureWind(req, dataList, before20WeatherList, current8weatherList, current20weatherList); + return dataList; + } + + private static List filterFutureWind(AreaTreeReq req, + List dataList, + List before20WeatherList, + List current8weatherList, + List current20weatherList) { + if (!Objects.isNull(req.getMaxWindFutureTime()) && req.getMaxWindFutureTime() != 0) { + // 过滤未来最大风速 + // 查询符合条件的天气记录,当前时间加上未来小时与早8和晚8做比较 + LocalDateTime now = LocalDateTime.now(); + LocalDateTime before20DateTime = now.minusDays(1).toLocalDate().atTime( + LocalTime.of(20, 0)); + LocalDateTime current8DateTime = now.toLocalDate().atTime(LocalTime.of(8, 0)); + LocalDateTime current20DateTime = now.toLocalDate().atTime(LocalTime.of(20, 0)); + int flag = TimeUtil.getTargetTimeRange(req.getMaxWindFutureTime()); + LocalDateTime futureDateTime = now.plusHours(req.getMaxWindFutureTime()) + .withMinute(0).withSecond(0).withNano(0); + List pmdsQxjCityWeathers = new ArrayList<>(); + if (TimeUtil.BEFORE_8 == flag) { + // 当前时间加未来小时小于8点 + // 1、计算当前时间+未来小时~前一天晚上8点之间的小时数 + pmdsQxjCityWeathers = new ArrayList<>(getAreaCodeAndWeather( + before20DateTime, futureDateTime, before20WeatherList, 3).values()); + } + if (TimeUtil.BETWEEN_8_20 == flag) { + // 当前时间加未来小时位于早8点 ~ 晚8点(不含),查询早上8点开始取最接近的预报时效 + pmdsQxjCityWeathers = new ArrayList<>(getAreaCodeAndWeather( + current8DateTime, futureDateTime, current8weatherList, 3).values()); + } + if (TimeUtil.AFTER_20 == flag) { + // 当前时间加未来小时位于早8点 ~ 晚8点(不含),查询早上8点开始取最接近的预报时效 + pmdsQxjCityWeathers = new ArrayList<>(getAreaCodeAndWeather( + current20DateTime, futureDateTime, current20weatherList, 3).values()); + } + if (CollectionUtil.isEmpty(pmdsQxjCityWeathers)) { // 无可筛选的气象数据 + throw new RuntimeException("no pmdsQxjCityWeather data!"); + } + // 根据风俗来过滤dataList + List areaCodeList = pmdsQxjCityWeathers.stream().filter(e -> Double.compare( + Double.parseDouble(e.getWindSpeed()), req.getFutureTimeMaxWindCount()) >= 0) + .map(PmdsQxjCityWeather::getVAcode).collect(Collectors.toList()); + dataList = dataList.stream().filter( + e -> areaCodeList.contains(e.getDistrictCode())).collect(Collectors.toList()); + } + return dataList; + } + + private static List filterFutureAvgTem(AreaTreeReq req, + List dataList, + List before20WeatherList, + List current8weatherList, + List current20weatherList) { + if (!Objects.isNull(req.getAvgTempFutureTime()) && req.getAvgTempFutureTime() != 0) { + // 过滤未来平均气温 + // 查询符合条件的天气记录,当前时间加上未来小时与早8和晚8做比较 + LocalDateTime now = LocalDateTime.now(); + LocalDateTime before20DateTime = now.minusDays(1).toLocalDate().atTime( + LocalTime.of(20, 0)); + LocalDateTime current8DateTime = now.toLocalDate().atTime(LocalTime.of(8, 0)); + LocalDateTime current20DateTime = now.toLocalDate().atTime(LocalTime.of(20, 0)); + int flag = TimeUtil.getTargetTimeRange(req.getAvgTempFutureTime()); + LocalDateTime futureDateTime = now.plusHours(req.getAvgTempFutureTime()) + .withMinute(0).withSecond(0).withNano(0); + List pmdsQxjCityWeathers = new ArrayList<>(); + if (TimeUtil.BEFORE_8 == flag) { + // 当前时间加未来小时小于8点 + // 1、计算当前时间+未来小时~前一天晚上8点之间的小时数 + pmdsQxjCityWeathers = new ArrayList<>(getAreaCodeAndWeather( + before20DateTime, futureDateTime, before20WeatherList, 2).values()); + } + if (TimeUtil.BETWEEN_8_20 == flag) { + // 当前时间加未来小时位于早8点 ~ 晚8点(不含),查询早上8点开始取最接近的预报时效 + pmdsQxjCityWeathers = new ArrayList<>(getAreaCodeAndWeather( + current8DateTime, futureDateTime, current8weatherList, 2).values()); + } + if (TimeUtil.AFTER_20 == flag) { + // 当前时间加未来小时位于早8点 ~ 晚8点(不含),查询早上8点开始取最接近的预报时效 + pmdsQxjCityWeathers = new ArrayList<>(getAreaCodeAndWeather( + current20DateTime, futureDateTime, current20weatherList, 2).values()); + } + if (CollectionUtil.isEmpty(pmdsQxjCityWeathers)) { // 无可筛选的气象数据 + throw new RuntimeException("no pmdsQxjCityWeather data!"); + } + // 根据气温来过滤dataList + List areaCodeList = pmdsQxjCityWeathers.stream().filter(e -> Double.compare( + Double.parseDouble(e.getTem()), req.getFutureTimeAvgTempCount()) >= 0) + .map(PmdsQxjCityWeather::getVAcode).collect(Collectors.toList()); + dataList = dataList.stream().filter( + e -> areaCodeList.contains(e.getDistrictCode())).collect(Collectors.toList()); + } + return dataList; + } + + private static List filterFutureRain(AreaTreeReq req, + List dataList, + List before20WeatherList, + List current8weatherList, + List current20weatherList) { + if (!Objects.isNull(req.getRainFutureTime()) && req.getRainFutureTime() != 0) { + // 过滤未来降雨量 + // 查询符合条件的天气记录,当前时间加上未来小时与早8和晚8做比较 + LocalDateTime now = LocalDateTime.now(); + LocalDateTime before20DateTime = now.minusDays(1).toLocalDate().atTime( + LocalTime.of(20, 0)); + LocalDateTime current8DateTime = now.toLocalDate().atTime(LocalTime.of(8, 0)); + LocalDateTime current20DateTime = now.toLocalDate().atTime(LocalTime.of(20, 0)); + int flag = TimeUtil.getTargetTimeRange(req.getRainFutureTime()); + LocalDateTime futureDateTime = now.plusHours(req.getRainFutureTime()) + .withMinute(0).withSecond(0).withNano(0); + List pmdsQxjCityWeathers = new ArrayList<>(); + if (TimeUtil.BEFORE_8 == flag) { + // 当前时间加未来小时小于8点 + // 1、计算当前时间+未来小时~前一天晚上8点之间的小时数 + pmdsQxjCityWeathers = new ArrayList<>(getAreaCodeAndWeather( + before20DateTime, futureDateTime, before20WeatherList, 1).values()); + } + if (TimeUtil.BETWEEN_8_20 == flag) { + // 当前时间加未来小时位于早8点 ~ 晚8点(不含),查询早上8点开始取最接近的预报时效 + pmdsQxjCityWeathers = new ArrayList<>(getAreaCodeAndWeather( + current8DateTime, futureDateTime, current8weatherList, 1).values()); + } + if (TimeUtil.AFTER_20 == flag) { + // 当前时间加未来小时位于早8点 ~ 晚8点(不含),查询早上8点开始取最接近的预报时效 + pmdsQxjCityWeathers = new ArrayList<>(getAreaCodeAndWeather( + current20DateTime, futureDateTime, current20weatherList, 1).values()); + } + if (CollectionUtil.isEmpty(pmdsQxjCityWeathers)) { // 无可筛选的气象数据 + throw new RuntimeException("no pmdsQxjCityWeather data!"); + } + // 根据降雨量来过滤dataList + List areaCodeList = pmdsQxjCityWeathers.stream().filter(e -> Double.compare( + Double.parseDouble(e.getPrecipitation()), req.getFutureTimeRainCount()) >= 0) + .map(PmdsQxjCityWeather::getVAcode).collect(Collectors.toList()); + dataList = dataList.stream().filter( + e -> areaCodeList.contains(e.getDistrictCode())).collect(Collectors.toList()); + } + return dataList; + } + + private static Map getAreaCodeAndWeather(LocalDateTime startDateTime, + LocalDateTime futureDateTime, + List startWeatherList, + int filterType) { + Map resultMap = new HashMap<>(); + long hours = Duration.between(startDateTime, futureDateTime).toHours(); + // 获取大于等于hours的最小预报时效数据 + for (PmdsQxjCityWeather weather : startWeatherList) { + // 过滤:只保留 >=hours 的 + if (weather.getPredictionTime() < hours) { + continue; + } + // 过滤null值 + if (filterType == 1 && Objects.isNull(weather.getPrecipitation())) { + // 降雨量不能为空 + continue; + } + if (filterType == 2 && Objects.isNull(weather.getTem())) { + // 温度不能为空 + continue; + } + if (filterType == 2 && Objects.isNull(weather.getWindSpeed())) { + // 风速不能为空 + continue; + } + // key + String key = weather.getVAcode(); + PmdsQxjCityWeather exist = resultMap.get(key); + // 不存在 → 直接放 + if (Objects.isNull(exist)) { + resultMap.put(key, weather); + } + if (!Objects.isNull(exist) && weather.getPredictionTime() < exist.getPredictionTime()) { + // 存在 → 比较谁更接近hours + resultMap.put(key, weather); + } + } + return resultMap; + } + private void handleDailyAdvancedFilter(AreaTreeReq req) { if ("1".equals(req.getAdvancedFilterFlag())) { String currentDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); @@ -94,34 +325,31 @@ public class DnerSiteAreaConfigurationServiceImpl private static void handleHourlyAdvancedFilter(AreaTreeReq req) { if ("1".equals(req.getAdvancedFilterFlag())) { - String currentDateTime = LocalDateTime.now() // 获取当前时间 - .withMinute(0) // 分钟设置为0 - .withSecond(0) // 秒设置为0 - .withNano(0) // 毫秒设置为0 - .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00")); // 转换为字符串 - req.setCurrentDateTime(currentDateTime); + LocalDateTime now = LocalDateTime.now(); + DateTimeFormatter beforeDateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00"); + req.setCurrentDateTime(now.format(beforeDateTimeFormatter)); if (!Objects.isNull(req.getRainPastTime()) && req.getRainPastTime() != 0) { - req.setRainStartDateTime(TimeUtil.getBeforeHourTime(currentDateTime, req.getRainPastTime())); + req.setRainStartDateTime(TimeUtil.getBeforeHourTime(now, req.getRainPastTime(), beforeDateTimeFormatter)); } if (!Objects.isNull(req.getAvgTempPastTime()) && req.getAvgTempPastTime() != 0) { - req.setAvgTempStartDateTime(TimeUtil.getBeforeHourTime(currentDateTime, req.getAvgTempPastTime())); + req.setAvgTempStartDateTime(TimeUtil.getBeforeHourTime(now, req.getAvgTempPastTime(), beforeDateTimeFormatter)); } if (!Objects.isNull(req.getMaxWindPastTime()) && req.getMaxWindPastTime() != 0) { - req.setMaxWindStartDateTime(TimeUtil.getBeforeHourTime(currentDateTime, req.getMaxWindPastTime())); + req.setMaxWindStartDateTime(TimeUtil.getBeforeHourTime(now, req.getMaxWindPastTime(), beforeDateTimeFormatter)); } if (!Objects.isNull(req.getPowerOutageTimePastTime()) && req.getPowerOutageTimePastTime() != 0) { req.setPowerOutageTimeStartDateTime( - TimeUtil.getBeforeHourTime(currentDateTime, req.getPowerOutageTimePastTime())); + TimeUtil.getBeforeHourTime(now, req.getPowerOutageTimePastTime(), beforeDateTimeFormatter)); req.setPastTimePowerOutageTimeCount(Math.round( req.getPastTimePowerOutageTimeCount() * 60 * 100) / 100.00); // 小时转分钟,四舍五入,取小数点后两位 } if (!Objects.isNull(req.getPowerOutageUserPastTime()) && req.getPowerOutageUserPastTime() != 0) { req.setPowerOutageUserStartDateTime( - TimeUtil.getBeforeHourTime(currentDateTime, req.getPowerOutageUserPastTime())); + TimeUtil.getBeforeHourTime(now, req.getPowerOutageUserPastTime(), beforeDateTimeFormatter)); } if (!Objects.isNull(req.getPowerOutageRatioPastTime()) && req.getPowerOutageRatioPastTime() != 0) { req.setPowerOutageRatioStartDateTime( - TimeUtil.getBeforeHourTime(currentDateTime, req.getPowerOutageRatioPastTime())); + TimeUtil.getBeforeHourTime(now, req.getPowerOutageRatioPastTime(), beforeDateTimeFormatter)); } } } diff --git a/src/main/java/com/southern/power/grid/utils/TimeUtil.java b/src/main/java/com/southern/power/grid/utils/TimeUtil.java index 98a6090..bc4b22b 100644 --- a/src/main/java/com/southern/power/grid/utils/TimeUtil.java +++ b/src/main/java/com/southern/power/grid/utils/TimeUtil.java @@ -2,6 +2,7 @@ package com.southern.power.grid.utils; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.util.ArrayList; @@ -22,6 +23,11 @@ public class TimeUtil { // 仅小时格式 private static final DateTimeFormatter HOUR = DateTimeFormatter.ofPattern("dd日HH时"); + // 三个区间常量 + public static final int BEFORE_8 = 1; // 小于当天早8点 + public static final int BETWEEN_8_20 = 2; // 早8点 ~ 晚8点(不含) + public static final int AFTER_20 = 3; // 晚8点及以后 + /** * 获取开始时间到结束时间的小时数组,仅当天的第一条数据会展示年月日 * 比如[2026/03/13/22, 13/23, 2026/03/14/00, 14/01] @@ -123,20 +129,14 @@ public class TimeUtil { /** * 获取前n个小时的时间 * - * @param hourTime 指定时间,比如2026-03-17 11:00 + * @param dateTime 指定时间 * @param beforeHourNum 前n小时,比如2 + * @param formatter 返回格式 比如yyyy-MM-dd HH:00 * @return 前n小时的时间,比如2026-03-17 09:00 */ - public static String getBeforeHourTime(String hourTime, int beforeHourNum) { - // 定义格式 - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00"); - - // 1. 把字符串转成 LocalDateTime - LocalDateTime dateTime = LocalDateTime.parse(hourTime, formatter); - + public static String getBeforeHourTime(LocalDateTime dateTime, int beforeHourNum, DateTimeFormatter formatter) { // 2. 减去 n 小时(核心方法) LocalDateTime beforeHour = dateTime.minusHours(beforeHourNum); - // 3. 格式化返回(精确到小时,分钟固定 00) return beforeHour.format(formatter); } @@ -152,16 +152,6 @@ public class TimeUtil { return LocalDate.parse(dayTime).minusDays(beforeDayNum).toString(); } - public static void main(String[] args) { -// List strings = generateHourList("2026-03-13 22:00", "2026-03-14 01:00"); -// List strings = getBetweenDates("2026-03-10", "2026-03-14"); -// String strings = getBeforeNumDays("2026-03-15", 5); -// String beforeHourTime = getBeforeHourTime("2026-03-17 11:00", 2); -// System.out.println(beforeHourTime); -// System.out.println(getBeforeDate("2026-03-20", 2)); - System.out.println(Math.round(12.12345 * 100) / 100.0); - } - private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); public static LocalDateTime parseToLocalDateTime(String dateTimeStr) { @@ -174,4 +164,28 @@ public class TimeUtil { return null; } } + + /** + * 判断【当前时间 + X小时】落在哪个时间段 + * @param hoursToAdd 要加的小时数 X + * @return 1=早8点前, 2=8点~20点, 3=20点后 + */ + public static int getTargetTimeRange(long hoursToAdd) { + LocalDateTime now = LocalDateTime.now(); + // 当前时间 + X小时 + LocalDateTime targetTime = now.plusHours(hoursToAdd); + + // 当天 08:00 + LocalDateTime eightClock = targetTime.toLocalDate().atTime(LocalTime.of(8, 0)); + // 当天 20:00 + LocalDateTime twentyClock = targetTime.toLocalDate().atTime(LocalTime.of(20, 0)); + + if (targetTime.isBefore(eightClock)) { + return BEFORE_8; + } else if (targetTime.isBefore(twentyClock)) { + return BETWEEN_8_20; + } else { + return AFTER_20; + } + } } diff --git a/src/main/resources/mapper/PmdsQxjCityWeatherMapper.xml b/src/main/resources/mapper/PmdsQxjCityWeatherMapper.xml new file mode 100644 index 0000000..6522ff9 --- /dev/null +++ b/src/main/resources/mapper/PmdsQxjCityWeatherMapper.xml @@ -0,0 +1,44 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/sql/20260313-DDL-002.sql b/src/main/resources/sql/20260313-DDL-002.sql new file mode 100644 index 0000000..a3c603d --- /dev/null +++ b/src/main/resources/sql/20260313-DDL-002.sql @@ -0,0 +1,2 @@ +ALTER TABLE pmds_qxj_city_weather + MODIFY COLUMN `prediction_time` int COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '预报时效,小时'; \ No newline at end of file