feat: 电站告警描点列表

This commit is contained in:
tangwei 2026-06-23 18:08:12 +08:00
parent 158f331777
commit 939ddd11e0
4 changed files with 419 additions and 0 deletions

View File

@ -56,4 +56,10 @@ public class WarnDataController {
public ResponseResult getAiPfwRecordKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { public ResponseResult getAiPfwRecordKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(warnDataService.getAiPfwRecordKendoListCust(dataSourceRequest)); return ResponseResult.successData(warnDataService.getAiPfwRecordKendoListCust(dataSourceRequest));
} }
@PostMapping("/alarmPoint/GetKendoListCust")
@Operation(summary = "电站告警描点列表")
public ResponseResult getAlarmPointKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(warnDataService.getAlarmPointKendoListCust(dataSourceRequest));
}
} }

View File

@ -0,0 +1,103 @@
package com.yfd.platform.qgc_env.warn.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
@Data
@Accessors(chain = true)
@Schema(description = "电站告警描点")
public class AlarmPointVo {
@Schema(description = "站点类型")
private String sttp;
@Schema(description = "站点编码")
private String stcd;
@Schema(description = "经度")
private BigDecimal lgtd;
@Schema(description = "纬度")
private BigDecimal lttd;
@Schema(description = "高程")
private BigDecimal dtmel;
@Schema(description = "描点状态")
private String anchoPointState;
@Schema(description = "锚点类型")
private String sttpMap;
@Schema(description = "弹框站点名称")
private String titleName;
@Schema(description = "地图避让")
private Integer distance;
@Schema(description = "流域编码")
private String rvcd;
@Schema(description = "行政编码")
private String addvcd;
@Schema(description = "基地编码")
private String baseId;
@Schema(description = "关联电站编码")
private String rstcds;
@Schema(description = "设施类型")
private String sttpCode;
@Schema(description = "电站名称")
private String ennm;
@Schema(description = "流域名称")
private String rvnm;
@Schema(description = "电站装机类型")
private Integer endInstalledType;
@Schema(description = "生态流量告警数")
private Integer stqCount;
@Schema(description = "水质告警数")
private Integer wqCount;
@Schema(description = "水位告警数")
private Integer zCount;
@Schema(description = "水温告警数")
private Integer wtCount;
@Schema(description = "年份")
private String yyyy;
@Schema(description = "告警区间范围")
private String range;
@Schema(description = "装机容量")
private BigDecimal ttpwr;
@Schema(description = "基地名称")
private String baseName;
@Schema(description = "电站编码")
private String rstcd;
@Schema(description = "流域沿程")
private Integer rvcdStepSort;
@Schema(description = "电站沿程")
private Integer rstcdStepSort;
@Schema(description = "站点沿程")
private Integer siteStepSort;
@Schema(description = "电站图片")
private String logo;
}

View File

@ -2,6 +2,7 @@ package com.yfd.platform.qgc_env.warn.service;
import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.common.DataSourceResult; import com.yfd.platform.common.DataSourceResult;
import com.yfd.platform.qgc_env.warn.entity.vo.AlarmPointVo;
import com.yfd.platform.qgc_env.warn.entity.vo.AiRecordVo; import com.yfd.platform.qgc_env.warn.entity.vo.AiRecordVo;
import com.yfd.platform.qgc_env.warn.entity.vo.AiProtectVo; import com.yfd.platform.qgc_env.warn.entity.vo.AiProtectVo;
import com.yfd.platform.qgc_env.warn.entity.vo.AiDmRunVo; import com.yfd.platform.qgc_env.warn.entity.vo.AiDmRunVo;
@ -24,4 +25,6 @@ public interface WarnDataService {
DataSourceResult<AiRstcdVo> getAiRstcdListKendoListCust(DataSourceRequest dataSourceRequest); DataSourceResult<AiRstcdVo> getAiRstcdListKendoListCust(DataSourceRequest dataSourceRequest);
List<AiRecordVo> getAiPfwRecordKendoListCust(DataSourceRequest dataSourceRequest); List<AiRecordVo> getAiPfwRecordKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<AlarmPointVo> getAlarmPointKendoListCust(DataSourceRequest dataSourceRequest);
} }

View File

@ -10,6 +10,7 @@ import com.yfd.platform.common.DataSourceResult;
import com.yfd.platform.common.GroupHelper; import com.yfd.platform.common.GroupHelper;
import com.yfd.platform.common.GroupingInfo; import com.yfd.platform.common.GroupingInfo;
import com.yfd.platform.common.MicroservicDynamicSQLMapper; import com.yfd.platform.common.MicroservicDynamicSQLMapper;
import com.yfd.platform.qgc_env.warn.entity.vo.AlarmPointVo;
import com.yfd.platform.qgc_env.warn.entity.vo.AiComListVo; import com.yfd.platform.qgc_env.warn.entity.vo.AiComListVo;
import com.yfd.platform.qgc_env.warn.entity.vo.AiDmRunVo; import com.yfd.platform.qgc_env.warn.entity.vo.AiDmRunVo;
import com.yfd.platform.qgc_env.warn.entity.vo.AiProtectVo; import com.yfd.platform.qgc_env.warn.entity.vo.AiProtectVo;
@ -21,6 +22,7 @@ import com.yfd.platform.utils.QgcQueryWrapperUtil;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
@ -236,6 +238,48 @@ public class WarnDataServiceImpl implements WarnDataService {
return list; return list;
} }
@Override
public DataSourceResult<AlarmPointVo> getAlarmPointKendoListCust(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
String startTimeText = loadOptions == null ? null : QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "startTime");
String endTimeText = loadOptions == null ? null : QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "endTime");
Date startTime = null;
Date endTime = null;
String yyyy = null;
if (StrUtil.isNotBlank(startTimeText) && StrUtil.isNotBlank(endTimeText)) {
startTime = parseAiTime(startTimeText);
endTime = parseAiTime(endTimeText);
} else {
yyyy = String.valueOf(DateUtil.year(new Date()));
Map<String, Date> yearRange = buildAlarmPointYearRange(yyyy);
startTime = yearRange.get("startTime");
endTime = yearRange.get("endTime");
}
List<AlarmPointVo> points = microservicDynamicSQLMapper.getAllListWithResultType(
buildAlarmPointBaseSql(),
new HashMap<>(),
AlarmPointVo.class
);
Map<String, Object> countParamMap = new HashMap<>();
countParamMap.put("alarmPointStartTime", startTime);
countParamMap.put("alarmPointEndTime", endTime);
List<Map<String, Object>> countRows = microservicDynamicSQLMapper.getAllList(buildAlarmPointCountSql(), countParamMap);
Map<String, Integer> qecCountMap = buildAlarmPointQecCountMap(countRows);
Map<String, Integer> wqCountMap = buildAlarmPointWqCountMap(countRows);
List<Map<String, Object>> expressionRows = microservicDynamicSQLMapper.getAllList(buildAlarmPointLegendSql(), new HashMap<>());
List<AlarmPointVo> resultList = mergeAlarmPointData(points, qecCountMap, wqCountMap, expressionRows, yyyy);
DataSourceResult<AlarmPointVo> result = new DataSourceResult<>();
result.setData(resultList);
result.setTotal(resultList.size());
result.setAggregates(new HashMap<>());
return result;
}
private AiDmRunVo buildAiDmRunVo(Map<String, Object> row) { private AiDmRunVo buildAiDmRunVo(Map<String, Object> row) {
if (row == null || row.isEmpty()) { if (row == null || row.isEmpty()) {
return null; return null;
@ -326,6 +370,88 @@ public class WarnDataServiceImpl implements WarnDataService {
return sql.toString(); return sql.toString();
} }
private String buildAlarmPointBaseSql() {
return "SELECT " +
"eng.STCD AS stcd, " +
"'ENG' AS sttp, " +
"eng.ENNM AS ennm, " +
"eng.ENNM AS titleName, " +
"eng.LOGO AS logo, " +
"eng.RVCD AS rvcd, " +
"eng.RVCD_NAME AS rvnm, " +
"eng.ADDVCD AS addvcd, " +
"eng.BASE_ID AS baseId, " +
"NVL(eng.BASE_NAME, hb.BASENAME) AS baseName, " +
"eng.LGTD AS lgtd, " +
"eng.LTTD AS lttd, " +
"eng.ELEV AS dtmel, " +
"eng.YRGEB AS ttpwr, " +
"'ENG' AS sttpMap, " +
"CASE WHEN eng.PRSC IN (1, 2) THEN 1 WHEN eng.PRSC = 3 THEN 2 END AS endInstalledType, " +
"CASE " +
" WHEN eng.PRSC IN (1, 2) AND NVL(eng.BLDSTT_CODE, 0) = 2 THEN 'large_eng_built' " +
" WHEN eng.PRSC IN (1, 2) AND NVL(eng.BLDSTT_CODE, 0) = 1 THEN 'large_eng_ubuilt' " +
" WHEN eng.PRSC IN (1, 2) THEN 'large_eng_nbuilt' " +
" WHEN eng.PRSC = 3 AND NVL(eng.BLDSTT_CODE, 0) = 2 THEN 'mid_eng_built' " +
" WHEN eng.PRSC = 3 AND NVL(eng.BLDSTT_CODE, 0) = 1 THEN 'mid_eng_ubuilt' " +
" WHEN eng.PRSC = 3 THEN 'mid_eng_nbuilt' " +
" ELSE NULL END AS anchoPointState, " +
"NVL(along.ORDER_INDEX, 999999) AS rvcdStepSort, " +
"NVL(rstSort.SORT, 999999) AS rstcdStepSort, " +
"NVL(siteSort.SORT, 999999) AS siteStepSort " +
"FROM SD_ENGINFO_B_H eng " +
"LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = eng.BASE_ID AND NVL(hb.IS_DELETED, 0) = 0 " +
"LEFT JOIN MS_ALONG_B along ON along.RVCD = eng.HBRVCD AND along.CODE = 'common' AND NVL(along.IS_DELETED, 0) = 0 " +
"LEFT JOIN ( " +
" SELECT det.SORT, cfg.RVCD, det.STCD " +
" FROM MS_ALONGDET_B det " +
" INNER JOIN MS_ALONG_B cfg ON det.ALONG_ID = cfg.ID " +
" WHERE NVL(det.IS_DELETED, 0) = 0 AND NVL(cfg.IS_DELETED, 0) = 0 AND cfg.CODE = 'common' " +
") rstSort ON rstSort.RVCD = eng.HBRVCD AND rstSort.STCD = eng.STCD " +
"LEFT JOIN ( " +
" SELECT det.SORT, cfg.RVCD, det.STCD " +
" FROM MS_ALONGDET_B det " +
" INNER JOIN MS_ALONG_B cfg ON det.ALONG_ID = cfg.ID " +
" WHERE NVL(det.IS_DELETED, 0) = 0 AND NVL(cfg.IS_DELETED, 0) = 0 AND cfg.CODE = 'common' " +
") siteSort ON siteSort.RVCD = eng.HBRVCD AND siteSort.STCD = eng.STCD " +
"WHERE NVL(eng.IS_DELETED, 0) = 0 " +
"AND NVL(eng.USFL, 0) = 1 " +
"AND eng.LGTD IS NOT NULL " +
"AND eng.LTTD IS NOT NULL " +
"ORDER BY NVL(hb.ORDER_INDEX, 999999), NVL(along.ORDER_INDEX, 999999), NVL(siteSort.SORT, 999999), eng.ENNM";
}
private String buildAlarmPointCountSql() {
return "SELECT wr.STCD AS stcd, wr.STCD AS rstcd, COUNT(wr.STCD) AS count, 'QEC' AS ys " +
"FROM MS_WARN_RECORD_W wr " +
"WHERE NVL(wr.IS_DELETED, 0) = 0 " +
"AND wr.TB_ID IN (SELECT tb.ID FROM ST_TB_B tb WHERE tb.TB_CODE = 'QEC_R' AND NVL(tb.IS_DELETED, 0) = 0) " +
"AND wr.YS = 'QEC' " +
"AND wr.SFGB = 'N' " +
"AND wr.BTM BETWEEN #{map.alarmPointStartTime} AND #{map.alarmPointEndTime} " +
"GROUP BY wr.STCD " +
"UNION ALL " +
"SELECT wr.STCD AS stcd, wq.RSTCD AS rstcd, COUNT(wr.STCD) AS count, 'WQ' AS ys " +
"FROM MS_WARN_RECORD_W wr " +
"LEFT JOIN SD_WQ_B_H wq ON wr.STCD = wq.STCD AND NVL(wq.IS_DELETED, 0) = 0 " +
"WHERE NVL(wr.IS_DELETED, 0) = 0 " +
"AND wr.TB_ID IN (SELECT tb.ID FROM ST_TB_B tb WHERE tb.TB_CODE = 'WQ_R' AND NVL(tb.IS_DELETED, 0) = 0) " +
"AND wr.SFGB = 'N' " +
"AND wr.BTM BETWEEN #{map.alarmPointStartTime} AND #{map.alarmPointEndTime} " +
"AND wq.RSTCD IS NOT NULL " +
"GROUP BY wr.STCD, wq.RSTCD";
}
private String buildAlarmPointLegendSql() {
return "SELECT EXPRESSION AS expression, NAME_EN AS nameEn " +
"FROM MS_MAPLEGEND_B " +
"WHERE LAYER_CODE = 'eng_alarm_point' " +
"AND IF_SHOW = 1 " +
"AND NVL(IS_DELETED, 0) = 0 " +
"AND EXPRESSION IS NOT NULL " +
"ORDER BY NVL(ORDER_INDEX, 999999), ID";
}
private void appendAiRstcdCommonFilterSql(StringBuilder sql, private void appendAiRstcdCommonFilterSql(StringBuilder sql,
String keyPrefix, String keyPrefix,
String aiAlias, String aiAlias,
@ -407,6 +533,166 @@ public class WarnDataServiceImpl implements WarnDataService {
} }
} }
private Map<String, Date> buildAlarmPointYearRange(String yearText) {
Date endTime = new Date();
String currentYear = String.valueOf(DateUtil.year(endTime));
Date startTime = DateUtil.parse(currentYear + "-01-01");
if (StrUtil.isNotBlank(yearText) && !currentYear.equals(yearText)) {
startTime = DateUtil.parse(yearText + "-01-01");
endTime = DateUtil.parse(yearText + "-12-31");
}
Map<String, Date> result = new HashMap<>();
result.put("startTime", startTime);
result.put("endTime", endTime);
return result;
}
private Map<String, Integer> buildAlarmPointQecCountMap(List<Map<String, Object>> countRows) {
Map<String, Integer> result = new HashMap<>();
if (CollUtil.isEmpty(countRows)) {
return result;
}
for (Map<String, Object> row : countRows) {
if (!"QEC".equalsIgnoreCase(safeString(firstPresentValue(row, "YS", "ys")))) {
continue;
}
String stcd = safeString(firstPresentValue(row, "RSTCD", "rstcd", "STCD", "stcd"));
if (StrUtil.isBlank(stcd)) {
continue;
}
result.put(stcd, toIntegerValue(firstPresentValue(row, "COUNT", "count")));
}
return result;
}
private Map<String, Integer> buildAlarmPointWqCountMap(List<Map<String, Object>> countRows) {
Map<String, Integer> result = new HashMap<>();
if (CollUtil.isEmpty(countRows)) {
return result;
}
for (Map<String, Object> row : countRows) {
if (!"WQ".equalsIgnoreCase(safeString(firstPresentValue(row, "YS", "ys")))) {
continue;
}
Integer count = toIntegerValue(firstPresentValue(row, "COUNT", "count"));
if (count == null) {
count = 0;
}
String rstcdText = safeString(firstPresentValue(row, "RSTCD", "rstcd"));
if (StrUtil.isBlank(rstcdText)) {
continue;
}
for (String rstcd : rstcdText.split(",")) {
String trimmed = StrUtil.trim(rstcd);
if (StrUtil.isBlank(trimmed)) {
continue;
}
result.put(trimmed, result.getOrDefault(trimmed, 0) + count);
}
}
return result;
}
private List<AlarmPointVo> mergeAlarmPointData(List<AlarmPointVo> points,
Map<String, Integer> qecCountMap,
Map<String, Integer> wqCountMap,
List<Map<String, Object>> expressionRows,
String yyyy) {
List<AlarmPointVo> result = new ArrayList<>();
if (CollUtil.isEmpty(points)) {
return result;
}
for (AlarmPointVo point : points) {
if (point == null || !isAlarmPointVisible(point.getAnchoPointState())) {
continue;
}
point.setAnchoPointState(normalizeAlarmPointState(point.getAnchoPointState()) + "_ALARM");
point.setStqCount(qecCountMap.getOrDefault(point.getStcd(), 0));
point.setWqCount(wqCountMap.getOrDefault(point.getStcd(), 0));
point.setZCount(0);
point.setWtCount(0);
point.setYyyy(yyyy);
point.setSttpCode("ENG");
int total = point.getStqCount() + point.getWqCount();
applyAlarmPointRange(point, total, expressionRows);
result.add(point);
}
return result;
}
private boolean isAlarmPointVisible(String state) {
return "large_eng_built".equals(state)
|| "mid_eng_built".equals(state)
|| "large_eng_ubuilt".equals(state)
|| "mid_eng_ubuilt".equals(state);
}
private String normalizeAlarmPointState(String state) {
if ("large_eng_ubuilt".equals(state)) {
return "large_eng_built";
}
if ("mid_eng_ubuilt".equals(state)) {
return "mid_eng_built";
}
return state;
}
private void applyAlarmPointRange(AlarmPointVo point, int total, List<Map<String, Object>> expressionRows) {
if (point == null || CollUtil.isEmpty(expressionRows)) {
return;
}
for (Map<String, Object> row : expressionRows) {
String expression = safeString(firstPresentValue(row, "EXPRESSION", "expression"));
if (!matchesAlarmExpression(expression, total)) {
continue;
}
String nameEn = safeString(firstPresentValue(row, "NAMEEN", "nameEn", "NAME_EN"));
if (StrUtil.isNotBlank(nameEn)) {
point.setAnchoPointState(point.getAnchoPointState() + "_" + nameEn);
point.setRange(nameEn);
}
return;
}
}
private boolean matchesAlarmExpression(String range, int value) {
if (StrUtil.isBlank(range)) {
return false;
}
if (range.matches("x=\\d+")) {
return value == Integer.parseInt(range.substring(2));
}
if (range.matches("x>\\d+")) {
return value > Integer.parseInt(range.substring(2));
}
if (range.matches("x>=\\d+")) {
return value >= Integer.parseInt(range.substring(3));
}
if (range.matches("x<\\d+")) {
return value < Integer.parseInt(range.substring(2));
}
if (range.matches("x<=\\d+")) {
return value <= Integer.parseInt(range.substring(3));
}
if (range.matches("\\d+<x<\\d+")) {
String[] split = range.split("<x<");
return value > Integer.parseInt(split[0]) && value < Integer.parseInt(split[1]);
}
if (range.matches("\\d+<=x<=\\d+")) {
String[] split = range.split("<=x<=");
return value >= Integer.parseInt(split[0]) && value <= Integer.parseInt(split[1]);
}
if (range.matches("\\d+<x<=\\d+")) {
String[] split = range.split("<x<=");
return value > Integer.parseInt(split[0]) && value <= Integer.parseInt(split[1]);
}
if (range.matches("\\d+<=x<\\d+")) {
String[] split = range.split("<=x<");
return value >= Integer.parseInt(split[0]) && value < Integer.parseInt(split[1]);
}
return false;
}
private void fillAiPfwStatus(List<AiRecordVo> list) { private void fillAiPfwStatus(List<AiRecordVo> list) {
if (CollUtil.isEmpty(list)) { if (CollUtil.isEmpty(list)) {
return; return;
@ -960,6 +1246,27 @@ public class WarnDataServiceImpl implements WarnDataService {
} }
} }
private BigDecimal toBigDecimalValue(Object value) {
if (value == null) {
return null;
}
if (value instanceof BigDecimal bigDecimal) {
return bigDecimal;
}
if (value instanceof Number number) {
return BigDecimal.valueOf(number.doubleValue());
}
String text = String.valueOf(value).trim();
if (StrUtil.isBlank(text)) {
return null;
}
try {
return new BigDecimal(text);
} catch (NumberFormatException ex) {
return null;
}
}
private Object normalizeAiValue(String field, Object value) { private Object normalizeAiValue(String field, Object value) {
if (value == null) { if (value == null) {
return null; return null;