gunshi-project-ss/src/main/java/com/gunshi/project/ss/timetask/WarningRuleTask.java

424 lines
16 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.gunshi.project.ss.timetask;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gunshi.project.ss.common.model.StRiverRReal;
import com.gunshi.project.ss.common.model.StRsvrRReal;
import com.gunshi.project.ss.common.model.StStbprpB;
import com.gunshi.project.ss.common.util.LocalDateTimeConverter;
import com.gunshi.project.ss.entity.so.WeatherSo;
import com.gunshi.project.ss.entity.vo.*;
import com.gunshi.project.ss.model.*;
import com.gunshi.project.ss.service.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@EnableScheduling//开启定时任务
@Component
@Slf4j
@Profile({"prod","dev","local"})
public class WarningRuleTask {
@Autowired
private WarningRuleService warningRuleService;
@Autowired
private WarningRuleInfoService warningRuleInfoService;
//河道水位
@Autowired
private RiverWaterService riverWaterService;
@Autowired
private StRiverRRealService stRiverRRealService;
//水库水位
@Autowired
private ReservoirWaterService reservoirWaterService;
@Autowired
private StRsvrRRealService stRsvrRRealService;
@Autowired
private ForecastResultsService forecastResultsService;
@Resource
private ForecastService forecastService;
@Autowired
private RainBasinDivisionService rainBasinDivisionService;
// @Scheduled(fixedDelay = 60 * 60 * 1000) // 75分钟单位毫秒
// @Async
public void warningRuleExecute(){
//获取配置的预警规则
List<WarningRule> warningRules = warningRuleService.listData();
//过滤出启动了的预警规则
warningRules = warningRules.stream().filter(o ->{
return o.getStatus() != null && o.getStatus() == 1;
}).collect(Collectors.toList());
for (WarningRule warningRule : warningRules) {
//获取预警类型
String warningType = warningRule.getWarningType();
//获取预警的规则细节
List<WarningCondition> conditions = warningRule.getConditions();
if (conditions == null || conditions.isEmpty()) {
continue;
}
// 为每个条件计算实际值并设置是否满足
for (WarningCondition condition : conditions) {
BigDecimal actualValue = calculateActualValue(condition, warningType);
condition.setIsEnjoy(compareValue(actualValue, condition));
}
// 根据条件关系判断整个规则是否满足
boolean isRuleSatisfied = evaluateConditions(conditions);
// 这里可以根据 isRuleSatisfied 进行后续处理,比如触发预警等
if (isRuleSatisfied) {
log.info("预警规则 {} 满足条件,触发预警", warningRule.getId());
// 生成规则信息
String ruleInfo = generateRuleInfo(conditions);
WarningRuleInfo warningRuleInfo = new WarningRuleInfo();
warningRuleInfo.setRuleId(warningRule.getId());
warningRuleInfo.setConditions(conditions);
warningRuleInfo.setCreateTime(LocalDateTime.now());
warningRuleInfo.setStatus(0);
warningRuleInfoService.save(warningRuleInfo);
}
}
}
/**
* 生成规则信息描述
*/
private String generateRuleInfo(List<WarningCondition> conditions) {
List<String> conditionInfos = new ArrayList<>();
for (WarningCondition condition : conditions) {
if (condition.getIsEnjoy()) { // 只记录满足条件的报警信息
String conditionInfo = generateSingleConditionInfo(condition);
if (conditionInfo != null && !conditionInfo.isEmpty()) {
conditionInfos.add(conditionInfo);
}
}
}
return String.join("", conditionInfos);
}
@Autowired
private StStbprpBService stStbprpBService;
/**
* 生成单个条件的描述信息 - 修改格式
*/
private String generateSingleConditionInfo(WarningCondition condition) {
// String indicatorType = condition.getIndicatorType();
// String stcd = condition.getStcd();
String indicatorType = null;
String stcd = null;
String stnm="";
List<StStbprpB> stStbprpBS = stStbprpBService.lambdaQuery().eq(StStbprpB::getStcd, stcd).last("limit 1").list();
if(stStbprpBS != null && !stStbprpBS.isEmpty()){
stnm = stStbprpBS.get(0).getStnm();
}
BigDecimal thresholdValue = condition.getThresholdValue();
Integer durationHours = condition.getDurationHours();
switch (indicatorType) {
case "REAL_WATER_LEVEL":
BigDecimal currentWaterLevel = getRzByStcd(stcd);
return String.format("%s测点监测水位%sm %s %sm",
stnm, currentWaterLevel, condition.getOperator(), thresholdValue);
case "PEAK_FLOW":
return String.format("未来%dh预报洪峰流量 %s %s m³/s",
durationHours != null ? durationHours : 24, condition.getOperator(), thresholdValue);
case "RAINFALL":
BigDecimal currentRainfall = getRealRainFall(stcd, durationHours);
return String.format("%s测点过去%dh降雨量%smm %s %smm",
stnm, durationHours != null ? durationHours : 24,
currentRainfall, condition.getOperator(), thresholdValue);
// case "WATER_STORAGE":
// BigDecimal currentStoragePercent = getWaterStorage(condition.getYear());
// return String.format("蓄水量 %s 同期%s%%",
// condition.getOperator(), thresholdValue);
case "FORECAST_RAINFALL":
return String.format("%s测点未来%dh降雨量 %s %smm",
stnm, durationHours != null ? durationHours : 24,
condition.getOperator(), thresholdValue);
default:
return String.format("未知指标类型%s %s %s", stcd, condition.getOperator(), thresholdValue);
}
}
/**
* 计算条件的实际值
*/
private BigDecimal calculateActualValue(WarningCondition condition, String warningType) {
// String indicatorType = condition.getIndicatorType();
// String stcd = condition.getStcd();
String indicatorType = null;
String stcd = null;
Integer durationHours = condition.getDurationHours();
switch (indicatorType) {
case "REAL_WATER_LEVEL":
return getRzByStcd(stcd);
case "PEAK_FLOW":
return getFloowMaxQ(durationHours);
case "RAINFALL":
return getRealRainFall(stcd, durationHours);
case "WATER_STORAGE":
// return getWaterStorage(condition.getYear());
case "FORECAST_RAINFALL":
return getForecastRainFall(stcd, durationHours);
default:
return BigDecimal.ZERO;
}
}
/**
* 比较实际值和阈值
*/
private boolean compareValue(BigDecimal actualValue, WarningCondition condition) {
if (actualValue == null || condition.getThresholdValue() == null) {
return false;
}
String operator = condition.getOperator();
BigDecimal threshold = condition.getThresholdValue();
switch (operator) {
case ">":
return actualValue.compareTo(threshold) > 0;
case ">=":
return actualValue.compareTo(threshold) >= 0;
case "<":
return actualValue.compareTo(threshold) < 0;
case "<=":
return actualValue.compareTo(threshold) <= 0;
default:
return false;
}
}
/**
* 评估条件组合是否满足
* 处理 AND/OR 逻辑关系
*/
private boolean evaluateConditions(List<WarningCondition> conditions) {
if (conditions.isEmpty()) {
return false;
}
boolean result = false;
boolean currentGroup = conditions.get(0).getIsEnjoy();
for (int i = 0; i < conditions.size() - 1; i++) {
WarningCondition current = conditions.get(i);
WarningCondition next = conditions.get(i + 1);
String relation = current.getRelationType();
if ("AND".equals(relation)) {
// AND 关系:当前组与下一个条件进行与运算
currentGroup = currentGroup && next.getIsEnjoy();
} else if ("OR".equals(relation)) {
// OR 关系:当前结果与当前组进行或运算,然后开始新的组
result = result || currentGroup;
currentGroup = next.getIsEnjoy();
}
}
// 处理最后一个条件
result = result || currentGroup;
return result;
}
//获取实时水位
private BigDecimal getRzByStcd(String stcd){
//获取河道水位的站点编码
List<String> riverStcd = riverWaterService.getRiverStcd();
if(riverStcd.contains(stcd)){
LambdaQueryWrapper<StRiverRReal> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(StRiverRReal::getStcd,stcd);
StRiverRReal stRiverRReal = stRiverRRealService.getBaseMapper().selectOne(queryWrapper);
if(stRiverRReal != null){
return stRiverRReal.getZ();
}
return BigDecimal.ZERO;
}else{
LambdaQueryWrapper<StRsvrRReal> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(StRsvrRReal::getStcd,stcd);
StRsvrRReal stRsvrRReal = stRsvrRRealService.getBaseMapper().selectOne(queryWrapper);
if(stRsvrRReal != null){
return stRsvrRReal.getRz();
}
return BigDecimal.ZERO;
}
}
//获取预报洪峰流量
private BigDecimal getFloowMaxQ(Integer durationHours){
ForecastTask forecastTask = new ForecastTask();
// 设置当前时间整点
LocalDateTime now = LocalDateTime.now();
LocalDateTime nowHour = now.withMinute(0).withSecond(0).withNano(0);
forecastTask.setNowTime(LocalDateTimeConverter.toDate(nowHour));
// 设置开始时间(当前时间减去一天)
LocalDateTime startTime = nowHour.minusDays(1);
forecastTask.setStartTime(LocalDateTimeConverter.toDate(startTime));
// 设置结束时间当前时间加上durationHours
LocalDateTime endTime = nowHour.plusHours(durationHours);
forecastTask.setEndTime(LocalDateTimeConverter.toDate(endTime));
forecastTask.setForecastWarm(1);
forecastTask.setForecastPeriod(durationHours); // 设置预报时长
List<ForecastResultVo> humanForecastResult = forecastResultsService.getHumanForecastResult(forecastTask);
//过滤出预报的数据
humanForecastResult = humanForecastResult.stream().filter(o ->{
return o.getIspreDrp().equals("1") && o.getYcRkQValue() != null;
}).collect(Collectors.toList());
BigDecimal totalQ = BigDecimal.ZERO;
for (ForecastResultVo forecastResultVo : humanForecastResult) {
totalQ = totalQ.add(forecastResultVo.getYcRkQValue());
}
return totalQ;
}
//获取降雨量的值
public BigDecimal getRealRainFall(String stcd,Integer durationHours){
StPptnDetailsVo stPptnDetailsVo = rainBasinDivisionService.queryStPptnDetailsByStcd(stcd);
if (stPptnDetailsVo == null) {
return BigDecimal.ZERO; // 或返回 BigDecimal.ZERO根据业务需求调整
}
BigDecimal result = switch (durationHours) {
case 1 -> stPptnDetailsVo.getH1();
case 3 -> stPptnDetailsVo.getH3();
case 6 -> stPptnDetailsVo.getH6();
case 12 -> stPptnDetailsVo.getH12();
case 24 -> stPptnDetailsVo.getH24();
case 48 -> stPptnDetailsVo.getH48();
// 3. 未匹配的时长如2、5等返回null或默认值
default -> BigDecimal.ZERO; // 或 throw new IllegalArgumentException("不支持的时长:" + durationHours);
};
return result == null?BigDecimal.ZERO:result;
}
@Autowired
private HisWaterDataService hisWaterDataService;
//获取蓄水量 - 修改后的逻辑
private BigDecimal getWaterStorage(String year){
List<AttResBaseVo> list = reservoirWaterService.list();
if (list == null || list.isEmpty()) {
return BigDecimal.ZERO;
}
AttResBaseVo reservoir = list.get(0);
BigDecimal nowCap = reservoir.getNowCap() == null ? BigDecimal.ZERO : reservoir.getNowCap();
BigDecimal deadCap = reservoir.getDeadCap() == null ? BigDecimal.ZERO : reservoir.getDeadCap();
BigDecimal availableWater = nowCap.subtract(deadCap); // 当前可用水量
// 获取当前月份
int currentMonth = LocalDateTime.now().getMonthValue();
String month = String.valueOf(currentMonth);
// 获取某年同月的蓄水量作为基准值
List<HisWaterData> hisWaterDataList = hisWaterDataService.lambdaQuery()
.eq(HisWaterData::getYear, year)
.eq(HisWaterData::getMonth, month)
.eq(HisWaterData::getType,2)
.list();
BigDecimal baseWaterStorage = BigDecimal.ZERO;
if (!hisWaterDataList.isEmpty()) {
HisWaterData hisWaterData = hisWaterDataList.get(0);
baseWaterStorage = hisWaterData.getAvgWater() == null ? BigDecimal.ZERO : hisWaterData.getAvgWater();
}
// 如果基准值为0避免除零错误返回0
if (baseWaterStorage.compareTo(BigDecimal.ZERO) == 0) {
return BigDecimal.ZERO;
}
// 计算当前可用水量占同期蓄水量的百分比
BigDecimal percentage = availableWater.divide(baseWaterStorage, 4, RoundingMode.HALF_UP)
.multiply(new BigDecimal("100"));
return percentage;
}
//获取预测降雨量
private BigDecimal getForecastRainFall(String stcd,Integer durationHours) {
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
// 获取当前日期默认系统时区可指定时区如ZoneId.of("UTC")
LocalDate today = LocalDate.now(ZoneId.systemDefault());
String todayDateStr = today.format(dateFormatter); // 结果示例20251120
String tm = todayDateStr + "08"; // 拼接固定小时最终格式2025112008
WeatherSo weatherSo = new WeatherSo();
weatherSo.setTm(tm);
List<ForeRainVo> fore = forecastService.fore(weatherSo);
for (ForeRainVo foreRainVo : fore) {
if (stcd.equals(foreRainVo.getStcd())) {
BigDecimal forecastRain = BigDecimal.ZERO;
switch (durationHours) {
case 1:
forecastRain = foreRainVo.getH1();
return forecastRain;
case 3:
forecastRain = foreRainVo.getH3();
return forecastRain;
case 6:
forecastRain = foreRainVo.getH6();
return forecastRain;
case 12:
forecastRain = foreRainVo.getH12();
return forecastRain;
case 24:
forecastRain = new BigDecimal(foreRainVo.getH24());
return forecastRain;
default:
return BigDecimal.ZERO;
}
}
}
return BigDecimal.ZERO;
}
}