2026-03-31提交:分时图高级筛选未来条件修改;

This commit is contained in:
junzhangfm 2026-03-31 16:34:16 +08:00
parent b253668d8b
commit 93f0092f75
11 changed files with 493 additions and 37 deletions

View File

@ -94,7 +94,7 @@ public class DnerEventController {
* *
* @return 结果 * @return 结果
*/ */
@PostMapping("/downloadTemplate") @GetMapping("/downloadTemplate")
public ResponseEntity<Resource> downloadTemplate() { public ResponseEntity<Resource> downloadTemplate() {
return dnerEventService.downloadTemplate(); return dnerEventService.downloadTemplate();
} }

View File

@ -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<PmdsQxjCityWeather> {
/**
* 查询符合条件的气象数据
*
* @param districtCodeList 地区编码集合
* @param startDateTimeStr 查看开始时间比如2026-03-30 20:00:00.0
* @return 结果
*/
List<PmdsQxjCityWeather> selectListFilter(@Param("districtCodeList") List<String> districtCodeList,
@Param("startDateTimeStr") String startDateTimeStr);
}

View File

@ -97,7 +97,7 @@ public class AreaTreeReq {
/** /**
* 未来XX小时/ * 未来XX小时/
*/ */
Integer futureTempPastTime; Integer avgTempFutureTime;
/** /**
* 未来XX小时/天的平均气温超过的 * 未来XX小时/天的平均气温超过的
@ -107,7 +107,7 @@ public class AreaTreeReq {
/** /**
* 未来XX小时/ * 未来XX小时/
*/ */
Integer futureWindPastTime; Integer maxWindFutureTime;
/** /**
* 未来XX小时/天的极大风速超过的m/s * 未来XX小时/天的极大风速超过的m/s

View File

@ -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;
}

View File

@ -52,8 +52,10 @@ public class DataExcelListener extends AnalysisEventListener<DataExcelEntity> {
@Setter @Setter
private ImportTask task; private ImportTask task;
@Setter
private int success = 0; private int success = 0;
@Setter
private int fail = 0; private int fail = 0;
// 逐行读取不会OOM // 逐行读取不会OOM

View File

@ -54,6 +54,8 @@ public class AsyncImportServiceImpl {
.set(ImportTask::getStatus, ImportTaskStatusEnum.FAILED.getCode()) // 失败状态 .set(ImportTask::getStatus, ImportTaskStatusEnum.FAILED.getCode()) // 失败状态
.set(ImportTask::getFailMsg, e.getMessage()) // 更新原因 .set(ImportTask::getFailMsg, e.getMessage()) // 更新原因
.eq(ImportTask::getTaskNo, task.getTaskNo())); .eq(ImportTask::getTaskNo, task.getTaskNo()));
dataExcelListener.setSuccess(0);
dataExcelListener.setFail(0);
log.error("导入异常", e); log.error("导入异常", e);
} }
} }

View File

@ -22,6 +22,7 @@ import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -59,9 +60,18 @@ public class DnerEventServiceImpl extends ServiceImpl<DnerEventMapper, DnerEvent
public List<DnerEventVO> listVO() { public List<DnerEventVO> listVO() {
List<DnerEventVO> dnerEventVOS = dnerEventMapper.listVO(); List<DnerEventVO> dnerEventVOS = dnerEventMapper.listVO();
if (!CollectionUtil.isEmpty(dnerEventVOS)) { if (!CollectionUtil.isEmpty(dnerEventVOS)) {
List<Long> eventIds = dnerEventVOS.stream().map(DnerEventVO::getId).collect(Collectors.toList());
// 查询附件信息
List<DnerEventAttachment> attachmentList = dnerEventAttachmentMapper.selectList(
new LambdaQueryWrapper<DnerEventAttachment>().eq(DnerEventAttachment::getIsLatest, 1)
.in(DnerEventAttachment::getEventId, eventIds));
// 结果按eventId分组获取map
Map<Long, DnerEventAttachment> attachmentGroupMap = attachmentList.stream().collect(Collectors.toMap(
DnerEventAttachment::getEventId, Function.identity(), (k1, k2) -> k1
));
// 查询附件导出记录
List<DnerEventExportRecord> dnerEventExportRecords = dnerEventExportRecordMapper.selectList( List<DnerEventExportRecord> dnerEventExportRecords = dnerEventExportRecordMapper.selectList(
new LambdaQueryWrapper<DnerEventExportRecord>().in(DnerEventExportRecord::getEventId, new LambdaQueryWrapper<DnerEventExportRecord>().in(DnerEventExportRecord::getEventId, eventIds));
dnerEventVOS.stream().map(DnerEventVO::getId).collect(Collectors.toList())));
// 结果按eventId分组获取map // 结果按eventId分组获取map
Map<Long, List<DnerEventExportRecord>> groupMap = dnerEventExportRecords.stream().collect( Map<Long, List<DnerEventExportRecord>> groupMap = dnerEventExportRecords.stream().collect(
Collectors.groupingBy(DnerEventExportRecord::getEventId)); Collectors.groupingBy(DnerEventExportRecord::getEventId));
@ -70,6 +80,12 @@ public class DnerEventServiceImpl extends ServiceImpl<DnerEventMapper, DnerEvent
a1, a2) -> a2.getExportTime().compareTo(a1.getExportTime()))); a1, a2) -> a2.getExportTime().compareTo(a1.getExportTime())));
// 塞入导出记录 // 塞入导出记录
dnerEventVOS.forEach(e -> { 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())); e.setEventExportRecordList(groupMap.get(e.getId()));
}); });
} }

View File

@ -1,10 +1,13 @@
package com.southern.power.grid.service.impl; package com.southern.power.grid.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.southern.power.grid.dao.DnerSiteAreaConfigurationMapper; 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.AreaTreeReq;
import com.southern.power.grid.entity.AreaTreeVO; import com.southern.power.grid.entity.AreaTreeVO;
import com.southern.power.grid.entity.DnerSiteAreaConfiguration; 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.enums.ChartQueryTypeEnum;
import com.southern.power.grid.service.IDnerSiteAreaConfigurationService; import com.southern.power.grid.service.IDnerSiteAreaConfigurationService;
import com.southern.power.grid.utils.TimeUtil; import com.southern.power.grid.utils.TimeUtil;
@ -12,9 +15,12 @@ import lombok.NonNull;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.Duration;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
/** /**
* 行政区划配置表 -- service实现类 * 行政区划配置表 -- service实现类
@ -29,6 +35,9 @@ public class DnerSiteAreaConfigurationServiceImpl
@Autowired @Autowired
private DnerSiteAreaConfigurationMapper dnerSiteAreaConfigurationMapper; private DnerSiteAreaConfigurationMapper dnerSiteAreaConfigurationMapper;
@Autowired
private PmdsQxjCityWeatherMapper pmdsQxjCityWeatherMapper;
@Override @Override
public List<AreaTreeVO> queryAreaTree(AreaTreeReq req) { public List<AreaTreeVO> queryAreaTree(AreaTreeReq req) {
// 判断是否开启高级筛选 // 判断是否开启高级筛选
@ -44,8 +53,13 @@ public class DnerSiteAreaConfigurationServiceImpl
List<DnerSiteAreaConfiguration> dataList; List<DnerSiteAreaConfiguration> dataList;
if (ChartQueryTypeEnum.HOURLY_CHART.getCode().equals(req.getQueryType())) { if (ChartQueryTypeEnum.HOURLY_CHART.getCode().equals(req.getQueryType())) {
// 分时图 // 分时图
handleHourlyAdvancedFilter(req); // 分时图高级筛选处理 handleHourlyAdvancedFilter(req); // 分时图高级筛选处理 -- 过去条件
dataList = dnerSiteAreaConfigurationMapper.selectHourlyChartAreaTree(req); dataList = dnerSiteAreaConfigurationMapper.selectHourlyChartAreaTree(req);
if (CollectionUtil.isEmpty(dataList)) {
return new ArrayList<>();
}
// 过滤未来条件
dataList = filterFutureCondition(req, dataList);
} else { } else {
// 日K图 // 日K图
handleDailyAdvancedFilter(req); // 日K图高级筛选处理 handleDailyAdvancedFilter(req); // 日K图高级筛选处理
@ -62,6 +76,223 @@ public class DnerSiteAreaConfigurationServiceImpl
return result; return result;
} }
private @NonNull List<DnerSiteAreaConfiguration> filterFutureCondition(AreaTreeReq req,
List<DnerSiteAreaConfiguration> dataList) {
List<String> districtCodeList = dataList.stream().map(
DnerSiteAreaConfiguration::getDistrictCode).collect(Collectors.toList());
List<PmdsQxjCityWeather> before20WeatherList = new ArrayList<>();
List<PmdsQxjCityWeather> current8weatherList = new ArrayList<>();
List<PmdsQxjCityWeather> 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<PmdsQxjCityWeather> 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<DnerSiteAreaConfiguration> filterFutureWind(AreaTreeReq req,
List<DnerSiteAreaConfiguration> dataList,
List<PmdsQxjCityWeather> before20WeatherList,
List<PmdsQxjCityWeather> current8weatherList,
List<PmdsQxjCityWeather> 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<PmdsQxjCityWeather> 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<String> 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<DnerSiteAreaConfiguration> filterFutureAvgTem(AreaTreeReq req,
List<DnerSiteAreaConfiguration> dataList,
List<PmdsQxjCityWeather> before20WeatherList,
List<PmdsQxjCityWeather> current8weatherList,
List<PmdsQxjCityWeather> 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<PmdsQxjCityWeather> 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<String> 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<DnerSiteAreaConfiguration> filterFutureRain(AreaTreeReq req,
List<DnerSiteAreaConfiguration> dataList,
List<PmdsQxjCityWeather> before20WeatherList,
List<PmdsQxjCityWeather> current8weatherList,
List<PmdsQxjCityWeather> 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<PmdsQxjCityWeather> 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<String> 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<String, PmdsQxjCityWeather> getAreaCodeAndWeather(LocalDateTime startDateTime,
LocalDateTime futureDateTime,
List<PmdsQxjCityWeather> startWeatherList,
int filterType) {
Map<String, PmdsQxjCityWeather> 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) { private void handleDailyAdvancedFilter(AreaTreeReq req) {
if ("1".equals(req.getAdvancedFilterFlag())) { if ("1".equals(req.getAdvancedFilterFlag())) {
String currentDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); String currentDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
@ -94,34 +325,31 @@ public class DnerSiteAreaConfigurationServiceImpl
private static void handleHourlyAdvancedFilter(AreaTreeReq req) { private static void handleHourlyAdvancedFilter(AreaTreeReq req) {
if ("1".equals(req.getAdvancedFilterFlag())) { if ("1".equals(req.getAdvancedFilterFlag())) {
String currentDateTime = LocalDateTime.now() // 获取当前时间 LocalDateTime now = LocalDateTime.now();
.withMinute(0) // 分钟设置为0 DateTimeFormatter beforeDateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00");
.withSecond(0) // 秒设置为0 req.setCurrentDateTime(now.format(beforeDateTimeFormatter));
.withNano(0) // 毫秒设置为0
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00")); // 转换为字符串
req.setCurrentDateTime(currentDateTime);
if (!Objects.isNull(req.getRainPastTime()) && req.getRainPastTime() != 0) { 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) { 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) { 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) { if (!Objects.isNull(req.getPowerOutageTimePastTime()) && req.getPowerOutageTimePastTime() != 0) {
req.setPowerOutageTimeStartDateTime( req.setPowerOutageTimeStartDateTime(
TimeUtil.getBeforeHourTime(currentDateTime, req.getPowerOutageTimePastTime())); TimeUtil.getBeforeHourTime(now, req.getPowerOutageTimePastTime(), beforeDateTimeFormatter));
req.setPastTimePowerOutageTimeCount(Math.round( req.setPastTimePowerOutageTimeCount(Math.round(
req.getPastTimePowerOutageTimeCount() * 60 * 100) / 100.00); // 小时转分钟四舍五入取小数点后两位 req.getPastTimePowerOutageTimeCount() * 60 * 100) / 100.00); // 小时转分钟四舍五入取小数点后两位
} }
if (!Objects.isNull(req.getPowerOutageUserPastTime()) && req.getPowerOutageUserPastTime() != 0) { if (!Objects.isNull(req.getPowerOutageUserPastTime()) && req.getPowerOutageUserPastTime() != 0) {
req.setPowerOutageUserStartDateTime( req.setPowerOutageUserStartDateTime(
TimeUtil.getBeforeHourTime(currentDateTime, req.getPowerOutageUserPastTime())); TimeUtil.getBeforeHourTime(now, req.getPowerOutageUserPastTime(), beforeDateTimeFormatter));
} }
if (!Objects.isNull(req.getPowerOutageRatioPastTime()) && req.getPowerOutageRatioPastTime() != 0) { if (!Objects.isNull(req.getPowerOutageRatioPastTime()) && req.getPowerOutageRatioPastTime() != 0) {
req.setPowerOutageRatioStartDateTime( req.setPowerOutageRatioStartDateTime(
TimeUtil.getBeforeHourTime(currentDateTime, req.getPowerOutageRatioPastTime())); TimeUtil.getBeforeHourTime(now, req.getPowerOutageRatioPastTime(), beforeDateTimeFormatter));
} }
} }
} }

View File

@ -2,6 +2,7 @@ package com.southern.power.grid.utils;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException; import java.time.format.DateTimeParseException;
import java.util.ArrayList; import java.util.ArrayList;
@ -22,6 +23,11 @@ public class TimeUtil {
// 仅小时格式 // 仅小时格式
private static final DateTimeFormatter HOUR = DateTimeFormatter.ofPattern("dd日HH时"); 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] * 比如[2026/03/13/22, 13/23, 2026/03/14/00, 14/01]
@ -123,20 +129,14 @@ public class TimeUtil {
/** /**
* 获取前n个小时的时间 * 获取前n个小时的时间
* *
* @param hourTime 指定时间比如2026-03-17 11:00 * @param dateTime 指定时间
* @param beforeHourNum 前n小时比如2 * @param beforeHourNum 前n小时比如2
* @param formatter 返回格式 比如yyyy-MM-dd HH:00
* @return 前n小时的时间比如2026-03-17 09:00 * @return 前n小时的时间比如2026-03-17 09:00
*/ */
public static String getBeforeHourTime(String hourTime, int beforeHourNum) { public static String getBeforeHourTime(LocalDateTime dateTime, int beforeHourNum, DateTimeFormatter formatter) {
// 定义格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00");
// 1. 把字符串转成 LocalDateTime
LocalDateTime dateTime = LocalDateTime.parse(hourTime, formatter);
// 2. 减去 n 小时核心方法 // 2. 减去 n 小时核心方法
LocalDateTime beforeHour = dateTime.minusHours(beforeHourNum); LocalDateTime beforeHour = dateTime.minusHours(beforeHourNum);
// 3. 格式化返回精确到小时分钟固定 00 // 3. 格式化返回精确到小时分钟固定 00
return beforeHour.format(formatter); return beforeHour.format(formatter);
} }
@ -152,16 +152,6 @@ public class TimeUtil {
return LocalDate.parse(dayTime).minusDays(beforeDayNum).toString(); return LocalDate.parse(dayTime).minusDays(beforeDayNum).toString();
} }
public static void main(String[] args) {
// List<String> strings = generateHourList("2026-03-13 22:00", "2026-03-14 01:00");
// List<String> 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"); private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public static LocalDateTime parseToLocalDateTime(String dateTimeStr) { public static LocalDateTime parseToLocalDateTime(String dateTimeStr) {
@ -174,4 +164,28 @@ public class TimeUtil {
return null; 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;
}
}
} }

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 必须 = Mapper 接口全类名 -->
<mapper namespace="com.southern.power.grid.dao.PmdsQxjCityWeatherMapper">
<select id="selectListFilter" resultType="com.southern.power.grid.entity.PmdsQxjCityWeather">
select t1.v01301,
t1.v_prcode,
t1.v_city,
t1.v_county,
t1.v05001,
t1.v06001,
t1.ddatetime,
t1.prediction_time,
t1.weather_type,
t1.tem,
t1.tem_max,
t1.tem_min,
t1.precipitation,
t1.rhum,
t1.wind_speed,
t1.wind_direction,
t1.cloud,
t1.vis,
t1.d_updatetime,
t1.rksj,
t2.district_code as v_acode
from pmds_qxj_city_weather t1
left join (select DISTINCT weather_province,
weather_city,
weather_district,
left(district_code, 6) as district_code
from weather_site_area_configuration) t2
on t1.v_prcode = t2.weather_province
and t1.v_city = t2.weather_city
and t1.v_county = t2.weather_district
where t2.district_code in
<foreach collection="districtCodeList" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
and t1.ddatetime >= #{startDateTimeStr}
</select>
</mapper>

View File

@ -0,0 +1,2 @@
ALTER TABLE pmds_qxj_city_weather
MODIFY COLUMN `prediction_time` int COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '预报时效,小时';