diff --git a/src/main/java/com/gunshi/project/hsz/controller/DebugController.java b/src/main/java/com/gunshi/project/hsz/controller/DebugController.java index 9464b61..fa2bf97 100644 --- a/src/main/java/com/gunshi/project/hsz/controller/DebugController.java +++ b/src/main/java/com/gunshi/project/hsz/controller/DebugController.java @@ -3,6 +3,7 @@ package com.gunshi.project.hsz.controller; import com.gunshi.core.result.R; import com.gunshi.project.hsz.timetask.JcskDataTask; import com.gunshi.project.hsz.timetask.PaDataTask; +import com.gunshi.project.hsz.timetask.WarningRuleTask; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; @@ -24,6 +25,19 @@ public class DebugController { @Autowired private JcskDataTask jcskDataTask; + @Autowired + private WarningRuleTask warningRuleTask; + + @GetMapping("/warnRule") + public String warningRuleTast(){ + try { + warningRuleTask.warningRuleExecute(); + return "success"; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @GetMapping("/patask") public String patask(){ diff --git a/src/main/java/com/gunshi/project/hsz/controller/HisWaterDataController.java b/src/main/java/com/gunshi/project/hsz/controller/HisWaterDataController.java new file mode 100644 index 0000000..ea55c32 --- /dev/null +++ b/src/main/java/com/gunshi/project/hsz/controller/HisWaterDataController.java @@ -0,0 +1,74 @@ +package com.gunshi.project.hsz.controller; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.gunshi.core.result.R; +import com.gunshi.project.hsz.common.model.JcskSlB; +import com.gunshi.project.hsz.common.model.so.JcskSlBPageSo; +import com.gunshi.project.hsz.common.validate.markers.Insert; +import com.gunshi.project.hsz.common.validate.markers.Update; +import com.gunshi.project.hsz.entity.so.HisWaterDataPageSo; +import com.gunshi.project.hsz.mapper.HisWaterDataMapper; +import com.gunshi.project.hsz.model.HisWaterData; +import com.gunshi.project.hsz.service.HisWaterDataService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Objects; + +@Tag(name = "预警-历史水库水量资料") +@RestController +@RequestMapping(value="/hiswater") +public class HisWaterDataController { + + + @Autowired + private HisWaterDataService hisWaterDataService; + + + @Operation(summary = "分页") + @PostMapping("/page") + public R> page(@RequestBody @Validated HisWaterDataPageSo page) { + return R.ok(hisWaterDataService.pageQuery(page)); + } + + + @Operation(summary = "新增") + @PostMapping("/insert") + public R insert(@Validated(Insert.class) @RequestBody HisWaterData dto) { + boolean result = hisWaterDataService.saveData(dto); + return R.ok(result ? dto : null); + } + + @Operation(summary = "修改") + @PostMapping("/update") + public R update(@Validated(Update.class) @RequestBody HisWaterData dto) { + boolean result = hisWaterDataService.updateById(dto); + return R.ok(result ? dto : null); + } + + @Operation(summary = "删除") + @GetMapping("/del/{id}") + public R del(@Schema(name = "id") @PathVariable("id") Serializable id) { + if (Objects.isNull(hisWaterDataService.getById(id))) { + throw new IllegalArgumentException("当前数据不存在"); + } + return R.ok(hisWaterDataService.removeById(id)); + } + + @Operation(summary = "导出") + @PostMapping("/export") + public void export(@RequestBody @Validated HisWaterDataPageSo pageSo, HttpServletResponse response) { + pageSo.getPageSo().setPageSize(99999); + Page hisWaterDataPage = hisWaterDataService.pageQuery(pageSo); + List records = hisWaterDataPage.getRecords(); + hisWaterDataService.export(records,response); + } +} diff --git a/src/main/java/com/gunshi/project/hsz/controller/WarningRuleController.java b/src/main/java/com/gunshi/project/hsz/controller/WarningRuleController.java index 8aeafdf..644d0f0 100644 --- a/src/main/java/com/gunshi/project/hsz/controller/WarningRuleController.java +++ b/src/main/java/com/gunshi/project/hsz/controller/WarningRuleController.java @@ -3,24 +3,30 @@ package com.gunshi.project.hsz.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.gunshi.core.result.R; +import com.gunshi.core.session.entity.SessionUser; +import com.gunshi.project.hsz.common.validate.markers.Update; import com.gunshi.project.hsz.entity.so.TermiteSurveyPageSo; import com.gunshi.project.hsz.entity.so.WarningRulePageSo; import com.gunshi.project.hsz.model.TermiteSurvey; import com.gunshi.project.hsz.model.WarningRule; +import com.gunshi.project.hsz.model.WarningRuleInfo; +import com.gunshi.project.hsz.model.WaterAlarm; +import com.gunshi.project.hsz.service.WarningRuleInfoService; import com.gunshi.project.hsz.service.WarningRuleService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import java.io.Serializable; @Tag(name = "预警规则") @RestController -@RequestMapping(value="/warn/rule") -public class WarningRuleController { +@RequestMapping(value="/warnRule") +public class WarningRuleController extends AbstractCommonFileController { @Autowired private WarningRuleService warningRuleService; @@ -35,7 +41,44 @@ public class WarningRuleController { @Operation(summary = "新增") @PostMapping("/insert") - public R insert(@RequestBody @Validated WarningRule dto) { + public R insert(@RequestBody @Validated WarningRule dto, HttpServletRequest request) { + SessionUser sessionUser = checkLogin(request); + if(sessionUser == null){ + throw new IllegalArgumentException("未登录"); + } + Long userId = sessionUser.getUserId(); + dto.setCreateName(userId.toString()); return R.ok(warningRuleService.saveData(dto)); } + + + @Operation(summary = "修改") + @PostMapping("/update") + public R update(@Validated(Update.class) @RequestBody WarningRule dto) { + boolean result = warningRuleService.updateData(dto); + return R.ok(result ? dto : null); + } + + @Operation(summary = "删除") + @GetMapping("/del/{id}") + public R del(@Schema(name = "id") @PathVariable("id") Serializable id) { + boolean b = warningRuleService.deleteById(id); + return R.ok(b); + } + + + @Autowired + private WarningRuleInfoService warningRuleInfoService; + + @Operation(summary = "预警信息分页") + @PostMapping("/info/page") + public R> infoPage(@RequestBody @Validated WarningRulePageSo page) { + return R.ok(warningRuleInfoService.pageQuery(page)); + } + + + @Override + public String getGroupId() { + return "warningRule"; + } } diff --git a/src/main/java/com/gunshi/project/hsz/entity/so/HisWaterDataPageSo.java b/src/main/java/com/gunshi/project/hsz/entity/so/HisWaterDataPageSo.java new file mode 100644 index 0000000..ef40f92 --- /dev/null +++ b/src/main/java/com/gunshi/project/hsz/entity/so/HisWaterDataPageSo.java @@ -0,0 +1,17 @@ +package com.gunshi.project.hsz.entity.so; + + +import com.gunshi.db.dto.PageSo; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class HisWaterDataPageSo { + + @NotNull(message = "分页参数不能为空") + @Schema(description = "分页参数") + private PageSo pageSo; + + +} diff --git a/src/main/java/com/gunshi/project/hsz/entity/so/WarningRulePageSo.java b/src/main/java/com/gunshi/project/hsz/entity/so/WarningRulePageSo.java index 3729097..350b632 100644 --- a/src/main/java/com/gunshi/project/hsz/entity/so/WarningRulePageSo.java +++ b/src/main/java/com/gunshi/project/hsz/entity/so/WarningRulePageSo.java @@ -1,6 +1,7 @@ package com.gunshi.project.hsz.entity.so; +import com.gunshi.db.dto.DateTimeRangeSo; import com.gunshi.db.dto.PageSo; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; @@ -16,4 +17,6 @@ public class WarningRulePageSo { private String ruleName; private String warningType; + + private DateTimeRangeSo dateTimeRangeSo; } diff --git a/src/main/java/com/gunshi/project/hsz/entity/vo/HisWaterDataVo.java b/src/main/java/com/gunshi/project/hsz/entity/vo/HisWaterDataVo.java new file mode 100644 index 0000000..e3d0d9c --- /dev/null +++ b/src/main/java/com/gunshi/project/hsz/entity/vo/HisWaterDataVo.java @@ -0,0 +1,9 @@ +package com.gunshi.project.hsz.entity.vo; + +import com.gunshi.project.hsz.model.HisWaterData; +import lombok.Data; + +@Data +public class HisWaterDataVo { + +} diff --git a/src/main/java/com/gunshi/project/hsz/mapper/HisWaterDataMapper.java b/src/main/java/com/gunshi/project/hsz/mapper/HisWaterDataMapper.java new file mode 100644 index 0000000..e12b910 --- /dev/null +++ b/src/main/java/com/gunshi/project/hsz/mapper/HisWaterDataMapper.java @@ -0,0 +1,9 @@ +package com.gunshi.project.hsz.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gunshi.project.hsz.model.HisWaterData; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface HisWaterDataMapper extends BaseMapper { +} diff --git a/src/main/java/com/gunshi/project/hsz/mapper/WarningRuleInfoMapper.java b/src/main/java/com/gunshi/project/hsz/mapper/WarningRuleInfoMapper.java new file mode 100644 index 0000000..152ae87 --- /dev/null +++ b/src/main/java/com/gunshi/project/hsz/mapper/WarningRuleInfoMapper.java @@ -0,0 +1,9 @@ +package com.gunshi.project.hsz.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.gunshi.project.hsz.model.WarningRuleInfo; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface WarningRuleInfoMapper extends BaseMapper { +} diff --git a/src/main/java/com/gunshi/project/hsz/model/HisWaterData.java b/src/main/java/com/gunshi/project/hsz/model/HisWaterData.java new file mode 100644 index 0000000..f194012 --- /dev/null +++ b/src/main/java/com/gunshi/project/hsz/model/HisWaterData.java @@ -0,0 +1,38 @@ +package com.gunshi.project.hsz.model; + + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +@TableName("his_water_data") +public class HisWaterData { + + @TableId(value = "id",type = IdType.AUTO) + private Long id; + + + @TableField("year") + @Schema(description = "年度") + private String year; + + @TableField("month") + @Schema(description = "月份") + private String month; + + @TableField("avg_water") + @Schema(description = "月份平均蓄水量") + private BigDecimal avgWater; + + @TableField(exist = false) + @Schema(description = "年度总蓄水量") + private BigDecimal totalWater; + + +} diff --git a/src/main/java/com/gunshi/project/hsz/model/WarningCondition.java b/src/main/java/com/gunshi/project/hsz/model/WarningCondition.java index d33ab33..97b3481 100644 --- a/src/main/java/com/gunshi/project/hsz/model/WarningCondition.java +++ b/src/main/java/com/gunshi/project/hsz/model/WarningCondition.java @@ -31,9 +31,20 @@ public class WarningCondition { /** * 预警指标类型 + * 实时水位 REAL_WATER_LEVEL + * 预报洪峰流量 PEAK_FLOW + * 降雨量 RAINFALL + * 蓄水量 WATER_STORAGE + * 预报降雨量 FORECAST_RAINFALL */ @TableField("indicator_type") private String indicatorType; + + /** + * 预警类型:FLOOD-洪水预警,DROUGHT-干旱预警 + */ + @TableField("warning_type") + private String warningType; /** * 测点编码 @@ -64,4 +75,13 @@ public class WarningCondition { */ @TableField("relation_type") private String relationType; + + @TableField("warning_level") + private Integer warningLevel; + + @TableField("year") + private String year; + + @TableField(exist = false) + private Boolean isEnjoy = false;//该预警规则是否满足条件,默认不满足 } \ No newline at end of file diff --git a/src/main/java/com/gunshi/project/hsz/model/WarningRule.java b/src/main/java/com/gunshi/project/hsz/model/WarningRule.java index 71ce078..34fb3f6 100644 --- a/src/main/java/com/gunshi/project/hsz/model/WarningRule.java +++ b/src/main/java/com/gunshi/project/hsz/model/WarningRule.java @@ -18,6 +18,7 @@ public class WarningRule { */ @TableId(type = IdType.AUTO) private Long id; + /** * 规则名称 @@ -49,10 +50,15 @@ public class WarningRule { @TableField("create_time") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime; + + + @TableField("warning_level") + private Integer warningLevel; /** * 预警条件列表 */ @TableField(exist = false) private List conditions; + } \ No newline at end of file diff --git a/src/main/java/com/gunshi/project/hsz/model/WarningRuleInfo.java b/src/main/java/com/gunshi/project/hsz/model/WarningRuleInfo.java new file mode 100644 index 0000000..595661b --- /dev/null +++ b/src/main/java/com/gunshi/project/hsz/model/WarningRuleInfo.java @@ -0,0 +1,69 @@ +package com.gunshi.project.hsz.model; + + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@TableName("warning_rule_info") +public class WarningRuleInfo { + + /** + * 主键ID + */ + @TableId(type = IdType.AUTO) + private Long id; + + @TableField("rule_id") + private Long ruleId; + + /** + * 规则名称 + */ + @TableField("rule_name") + private String ruleName; + + /** + * 预警类型:FLOOD-洪水预警,DROUGHT-干旱预警 + */ + @TableField("warning_type") + private String warningType; + + /** + * 状态:0-未启用,1-启用 + */ + @TableField("status") + private Integer status; + + /** + * 创建人 + */ + @TableField("create_name") + private String createName; + + /** + * 创建时间 + */ + @TableField("create_time") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @TableField("rule_info") + private String ruleInfo; + + @TableField("warning_level") + private Integer warningLevel; + + /** + * 预警条件列表 + */ + @TableField(exist = false) + private List conditions; +} diff --git a/src/main/java/com/gunshi/project/hsz/service/HisWaterDataService.java b/src/main/java/com/gunshi/project/hsz/service/HisWaterDataService.java new file mode 100644 index 0000000..0aabe36 --- /dev/null +++ b/src/main/java/com/gunshi/project/hsz/service/HisWaterDataService.java @@ -0,0 +1,129 @@ +package com.gunshi.project.hsz.service; + + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +import com.gunshi.project.hsz.entity.so.HisWaterDataPageSo; +import com.gunshi.project.hsz.mapper.HisWaterDataMapper; +import com.gunshi.project.hsz.model.HisWaterData; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +@Service +@Slf4j +@Transactional(rollbackFor = Exception.class) +public class HisWaterDataService extends ServiceImpl { + public Page pageQuery(HisWaterDataPageSo page) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.last("order by year desc,month asc"); + Page hisWaterDataPage = this.baseMapper.selectPage(page.getPageSo().toPage(), queryWrapper); + List records = hisWaterDataPage.getRecords(); + // 按年度分组 + Map> groupedByYear = records.stream() + .collect(Collectors.groupingBy(HisWaterData::getYear)); + // 遍历每个年度,计算并设置年度总蓄水量 + for (Map.Entry> entry : groupedByYear.entrySet()) { + String year = entry.getKey(); + List yearData = entry.getValue(); + // 计算年度总蓄水量 + BigDecimal totalWater = yearData.stream() + .map(HisWaterData::getAvgWater) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add); + // 为每个该年度的数据设置总蓄水量 + for (HisWaterData data : yearData) { + data.setTotalWater(totalWater); + } + } + return hisWaterDataPage; + } + + public boolean saveData(HisWaterData dto) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(HisWaterData::getYear,dto.getYear()); + queryWrapper.eq(HisWaterData::getMonth,dto.getMonth()); + HisWaterData hisWaterData = this.baseMapper.selectOne(queryWrapper); + if (hisWaterData != null) { + throw new IllegalArgumentException(dto.getYear() + "年-" + dto.getMonth() +"月,数据已存在,请勿重复添加"); + } + return this.baseMapper.insert(dto) > 0; + } + + public void export(List records, HttpServletResponse response) { + try { + Workbook workbook = new XSSFWorkbook(); + Sheet sheet = workbook.createSheet("蓄水量数据"); + + int rowNum = 0; + + // 按年度分组 + Map> groupedByYear = records.stream() + .collect(Collectors.groupingBy(HisWaterData::getYear)); + + // 遍历每个年度 + for (Map.Entry> entry : groupedByYear.entrySet()) { + String year = entry.getKey(); + List yearData = entry.getValue(); + + // 计算年度总蓄水量 + BigDecimal totalWater = yearData.stream() + .map(HisWaterData::getAvgWater) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add); + + // 写入年度和总蓄水量(每个值单独单元格) + Row yearRow = sheet.createRow(rowNum++); + yearRow.createCell(0).setCellValue("年:"); + yearRow.createCell(1).setCellValue(year); + yearRow.createCell(2).setCellValue("总蓄水量(万m³):"); + yearRow.createCell(3).setCellValue(totalWater.toString()); + + // 写入月份数据 + for (HisWaterData data : yearData) { + Row monthRow = sheet.createRow(rowNum++); + monthRow.createCell(0).setCellValue("月份:"); + monthRow.createCell(1).setCellValue(data.getMonth()); + monthRow.createCell(2).setCellValue("平均蓄水量(万m³):"); + if (data.getAvgWater() != null) { + monthRow.createCell(3).setCellValue(data.getAvgWater().toString()); + } else { + monthRow.createCell(3).setCellValue(""); + } + } + + // 年度之间空一行 + rowNum++; + } + + // 简单自适应列宽 + for (int i = 0; i < 4; i++) { + sheet.autoSizeColumn(i); + } + + // 设置响应头 + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setHeader("Content-Disposition", "attachment; filename=water_data.xlsx"); + + // 写入响应流 + workbook.write(response.getOutputStream()); + workbook.close(); + + } catch (Exception e) { + throw new RuntimeException("导出Excel失败", e); + } + } +} diff --git a/src/main/java/com/gunshi/project/hsz/service/JcskSyRService.java b/src/main/java/com/gunshi/project/hsz/service/JcskSyRService.java index 7fa39d3..33a1dee 100644 --- a/src/main/java/com/gunshi/project/hsz/service/JcskSyRService.java +++ b/src/main/java/com/gunshi/project/hsz/service/JcskSyRService.java @@ -823,9 +823,11 @@ public class JcskSyRService extends ServiceImpl { )); //组合成为 时间 库水位 管道水位的数据 List data = new ArrayList<>(); - for (JcskSyREightAm eightAm : jcskSyREightAms) { + Iterator iterator = jcskSyREightAms.iterator(); + while (iterator.hasNext()) { + JcskSyREightAm eightAm = iterator.next(); if(eightAm.getMstm() == null || eightAm.getSpprwl() == null){ - continue; + iterator.remove(); } OsmoticPressDetailVo detailVo = new OsmoticPressDetailVo(); @@ -837,7 +839,7 @@ public class JcskSyRService extends ServiceImpl { // 查找对应的库水位 BigDecimal rzValue = findClosestRzValue(rzMap, mstmStr); if(rzValue == null){ - continue; + iterator.remove(); } detailVo.setRz(rzValue); //获取数据清洗规则 @@ -846,11 +848,11 @@ public class JcskSyRService extends ServiceImpl { //校验这条数据是否符合规则 if(rzValue.compareTo(rule.getRz()) >=0){ //如果当前库水位大于等于设置库水位,则跳过这条数据 - continue; + iterator.remove(); } if(eightAm.getSpprwl().compareTo(rule.getSyValue()) <=0){ //如果当前监测值小于等于设置值,则跳过这套数据 - continue; + iterator.remove(); } } data.add(detailVo); diff --git a/src/main/java/com/gunshi/project/hsz/service/WarningConditionService.java b/src/main/java/com/gunshi/project/hsz/service/WarningConditionService.java index 9ce0964..0b9c55e 100644 --- a/src/main/java/com/gunshi/project/hsz/service/WarningConditionService.java +++ b/src/main/java/com/gunshi/project/hsz/service/WarningConditionService.java @@ -25,4 +25,44 @@ public class WarningConditionService extends ServiceImpl queryWrapper = new LambdaQueryWrapper<>(); + if(dto.getId() != null){ + queryWrapper.ne(WarningCondition::getId, dto.getId()); + } + if(dto.getIndicatorType() != null){ + //预警指标类型 + queryWrapper.eq(WarningCondition::getIndicatorType,dto.getIndicatorType()); + } + if(dto.getWarningLevel() != null){ + //预警等级 + queryWrapper.eq(WarningCondition::getWarningLevel,dto.getWarningLevel()); + } + if(dto.getWarningType() != null){ + //预警类型 + queryWrapper.eq(WarningCondition::getWarningType,dto.getWarningType()); + } + if(dto.getOperator() != null){ + //比较符 + queryWrapper.eq(WarningCondition::getOperator,dto.getOperator()); + } + if(dto.getThresholdValue() != null){ + //阈值 + queryWrapper.eq(WarningCondition::getThresholdValue,dto.getThresholdValue()); + } + if(dto.getDurationHours() != null){ + //时长/时段(小时) + queryWrapper.eq(WarningCondition::getDurationHours,dto.getDurationHours()); + } + WarningCondition warningCondition = this.baseMapper.selectOne(queryWrapper); + return warningCondition; + } + + public boolean removeByRuleId(Long ruleId){ + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(WarningCondition::getRuleId,ruleId); + return this.remove(queryWrapper); + } } diff --git a/src/main/java/com/gunshi/project/hsz/service/WarningRuleInfoService.java b/src/main/java/com/gunshi/project/hsz/service/WarningRuleInfoService.java new file mode 100644 index 0000000..667efc8 --- /dev/null +++ b/src/main/java/com/gunshi/project/hsz/service/WarningRuleInfoService.java @@ -0,0 +1,35 @@ +package com.gunshi.project.hsz.service; + +import com.alibaba.excel.util.StringUtils; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gunshi.core.result.R; +import com.gunshi.project.hsz.entity.so.WarningRulePageSo; +import com.gunshi.project.hsz.mapper.WarningRuleInfoMapper; +import com.gunshi.project.hsz.model.WarningRuleInfo; +import kotlin.jvm.internal.Lambda; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Slf4j +@Transactional(rollbackFor = Exception.class) +public class WarningRuleInfoService extends ServiceImpl { + public Page pageQuery(WarningRulePageSo page) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + if(!StringUtils.isBlank(page.getRuleName())){ + queryWrapper.like(WarningRuleInfo::getRuleName, page.getRuleName()); + } + if(!StringUtils.isBlank(page.getWarningType())){ + queryWrapper.eq(WarningRuleInfo::getWarningType, page.getWarningType()); + } + if(page.getDateTimeRangeSo() != null){ + queryWrapper.ge(WarningRuleInfo::getCreateTime,page.getDateTimeRangeSo().getStart()); + queryWrapper.le(WarningRuleInfo::getCreateTime,page.getDateTimeRangeSo().getEnd()); + } + Page warningRuleInfoPage = this.baseMapper.selectPage(page.getPageSo().toPage(), queryWrapper); + return warningRuleInfoPage; + } +} diff --git a/src/main/java/com/gunshi/project/hsz/service/WarningRuleService.java b/src/main/java/com/gunshi/project/hsz/service/WarningRuleService.java index f3eb551..22c0adf 100644 --- a/src/main/java/com/gunshi/project/hsz/service/WarningRuleService.java +++ b/src/main/java/com/gunshi/project/hsz/service/WarningRuleService.java @@ -16,7 +16,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.io.Serializable; import java.util.List; +import java.util.Map; @Service @Slf4j @@ -34,6 +36,7 @@ public class WarningRuleService extends ServiceImpl warningRulePage = this.baseMapper.selectPage(page.getPageSo().toPage(), queryWrapper); for (WarningRule record : warningRulePage.getRecords()) { @@ -43,7 +46,55 @@ public class WarningRuleService extends ServiceImpl listData(){ + List warningRules = this.baseMapper.selectList(null); + for (WarningRule warningRule : warningRules) { + List listByRuleId = warningConditionService.getListByRuleId(warningRule.getId()); + warningRule.setConditions(listByRuleId); + } + return warningRules; + } + public WarningRule saveData(WarningRule dto) { - return null; + if(dto.getConditions() == null || dto.getConditions().isEmpty()){ + throw new IllegalArgumentException("请至少配置一条预警规则"); + } + save(dto); + List conditions = dto.getConditions(); + for (WarningCondition condition : conditions) { + WarningCondition warningCondition = warningConditionService.checkConditionExists(condition); + if(warningCondition != null){ + throw new IllegalArgumentException("对不起,该预警规则已配置"); + } + condition.setRuleId(dto.getId()); + condition.setWarningType(dto.getWarningType()); + condition.setWarningLevel(dto.getWarningLevel()); + } + warningConditionService.saveBatch(conditions); + return dto; + } + + public boolean updateData(WarningRule dto) { + if(dto.getConditions() == null || dto.getConditions().isEmpty()){ + throw new IllegalArgumentException("请至少配置一条预警规则"); + } + updateById(dto); + List conditions = dto.getConditions(); + for (WarningCondition condition : conditions) { + WarningCondition warningCondition = warningConditionService.checkConditionExists(condition); + if(warningCondition != null){ + throw new IllegalArgumentException("对不起,该预警规则已配置"); + } + condition.setRuleId(dto.getId()); + } + warningConditionService.updateBatchById(conditions); + return true; + } + + + public boolean deleteById(Serializable id) { + removeById(id); + warningConditionService.removeByRuleId(Long.valueOf(id.toString())); + return true; } } diff --git a/src/main/java/com/gunshi/project/hsz/timetask/WarningRuleTask.java b/src/main/java/com/gunshi/project/hsz/timetask/WarningRuleTask.java new file mode 100644 index 0000000..003483c --- /dev/null +++ b/src/main/java/com/gunshi/project/hsz/timetask/WarningRuleTask.java @@ -0,0 +1,410 @@ +package com.gunshi.project.hsz.timetask; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gunshi.project.hsz.common.model.StRiverRReal; +import com.gunshi.project.hsz.common.model.StRsvrRReal; +import com.gunshi.project.hsz.common.util.LocalDateTimeConverter; +import com.gunshi.project.hsz.entity.so.WeatherSo; +import com.gunshi.project.hsz.entity.vo.*; +import com.gunshi.project.hsz.model.*; +import com.gunshi.project.hsz.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; + + public void warningRuleExecute(){ + //获取配置的预警规则 + List 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 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.getRuleName()); + + // 生成规则信息 + String ruleInfo = generateRuleInfo(conditions); + + WarningRuleInfo warningRuleInfo = new WarningRuleInfo(); + warningRuleInfo.setRuleId(warningRule.getId()); + warningRuleInfo.setRuleName(warningRule.getRuleName()); + warningRuleInfo.setConditions(conditions); + warningRuleInfo.setStatus(1); + warningRuleInfo.setCreateTime(LocalDateTime.now()); + warningRuleInfo.setRuleInfo(ruleInfo); + warningRuleInfo.setWarningType(warningType); + warningRuleInfoService.save(warningRuleInfo); + } + } + } + + /** + * 生成规则信息描述 + */ + private String generateRuleInfo(List conditions) { + List 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); + } + + /** + * 生成单个条件的描述信息 - 修改格式 + */ + private String generateSingleConditionInfo(WarningCondition condition) { + String indicatorType = condition.getIndicatorType(); + String stcd = condition.getStcd(); + 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", + stcd, 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", + stcd, 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", + stcd, 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(); + 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 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 riverStcd = riverWaterService.getRiverStcd(); + if(riverStcd.contains(stcd)){ + LambdaQueryWrapper 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 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 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 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 hisWaterDataList = hisWaterDataService.lambdaQuery() + .eq(HisWaterData::getYear, year) + .eq(HisWaterData::getMonth, month) + .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 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; + } + +}