2026-03-31提交:分时图高级筛选未来条件修改;
This commit is contained in:
parent
b253668d8b
commit
93f0092f75
@ -94,7 +94,7 @@ public class DnerEventController {
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping("/downloadTemplate")
|
||||
@GetMapping("/downloadTemplate")
|
||||
public ResponseEntity<Resource> downloadTemplate() {
|
||||
return dnerEventService.downloadTemplate();
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -52,8 +52,10 @@ public class DataExcelListener extends AnalysisEventListener<DataExcelEntity> {
|
||||
@Setter
|
||||
private ImportTask task;
|
||||
|
||||
@Setter
|
||||
private int success = 0;
|
||||
|
||||
@Setter
|
||||
private int fail = 0;
|
||||
|
||||
// 逐行读取(不会OOM)
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<DnerEventMapper, DnerEvent
|
||||
public List<DnerEventVO> listVO() {
|
||||
List<DnerEventVO> dnerEventVOS = dnerEventMapper.listVO();
|
||||
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(
|
||||
new LambdaQueryWrapper<DnerEventExportRecord>().in(DnerEventExportRecord::getEventId,
|
||||
dnerEventVOS.stream().map(DnerEventVO::getId).collect(Collectors.toList())));
|
||||
new LambdaQueryWrapper<DnerEventExportRecord>().in(DnerEventExportRecord::getEventId, eventIds));
|
||||
// 结果按eventId分组获取map
|
||||
Map<Long, List<DnerEventExportRecord>> groupMap = dnerEventExportRecords.stream().collect(
|
||||
Collectors.groupingBy(DnerEventExportRecord::getEventId));
|
||||
@ -70,6 +80,12 @@ public class DnerEventServiceImpl extends ServiceImpl<DnerEventMapper, DnerEvent
|
||||
a1, a2) -> 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()));
|
||||
});
|
||||
}
|
||||
|
||||
@ -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<AreaTreeVO> queryAreaTree(AreaTreeReq req) {
|
||||
// 判断是否开启高级筛选
|
||||
@ -44,8 +53,13 @@ public class DnerSiteAreaConfigurationServiceImpl
|
||||
List<DnerSiteAreaConfiguration> 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<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) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<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");
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
44
src/main/resources/mapper/PmdsQxjCityWeatherMapper.xml
Normal file
44
src/main/resources/mapper/PmdsQxjCityWeatherMapper.xml
Normal 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>
|
||||
2
src/main/resources/sql/20260313-DDL-002.sql
Normal file
2
src/main/resources/sql/20260313-DDL-002.sql
Normal file
@ -0,0 +1,2 @@
|
||||
ALTER TABLE pmds_qxj_city_weather
|
||||
MODIFY COLUMN `prediction_time` int COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '预报时效,小时';
|
||||
Loading…
x
Reference in New Issue
Block a user