diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fp/controller/FishPassageController.java b/backend/src/main/java/com/yfd/platform/qgc_env/fp/controller/FishPassageController.java index 21dedacf..a256f281 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/fp/controller/FishPassageController.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fp/controller/FishPassageController.java @@ -106,6 +106,12 @@ public class FishPassageController { return ResponseResult.successData(fpBuildService.getStInfoByStcd(stcd)); } + @PostMapping("/point/qgc/GetKendoListCust") + @Operation(summary = "环保部-过鱼设施描点接口") + public ResponseResult getQgcFpPointKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(fpBuildService.getQgcFpPointKendoListCust(dataSourceRequest)); + } + @PostMapping("/point/built/GetKendoListCust") @Operation(summary = "过鱼设施地图描点接口(仅查询在建状态的)") public ResponseResult getFpBuiltPointKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fp/entity/vo/FpAnchoPointVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/fp/entity/vo/FpAnchoPointVo.java index f803e21c..60add6c6 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/fp/entity/vo/FpAnchoPointVo.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fp/entity/vo/FpAnchoPointVo.java @@ -15,6 +15,9 @@ public class FpAnchoPointVo { @Schema(description = "站名") private String stnm; + @Schema(description = "站点图片") + private String logo; + @Schema(description = "弹框站点名称") private String titleName; @@ -45,6 +48,9 @@ public class FpAnchoPointVo { @Schema(description = "运行状态") private String run; + @Schema(description = "运行状态名称") + private String runName; + @Schema(description = "设施类型") private String dwtp; @@ -78,12 +84,24 @@ public class FpAnchoPointVo { @Schema(description = "达标状态子类型") private Integer stdSstate; + @Schema(description = "达标状态子类型名称") + private String stdSstateName; + @Schema(description = "地图避让") private Integer distance; + @Schema(description = "澜沧江运行状态") + private Integer lcjStatus; + + @Schema(description = "澜沧江运行状态名称") + private String lcjStatusName; + + @Schema(description = "年份") + private String yr; + @Schema(description = "过鱼种类") private Integer ftpTypeCount; @Schema(description = "过鱼数量") private Integer ftpCount; -} \ No newline at end of file +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fp/entity/vo/FpFishStatisticsVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/fp/entity/vo/FpFishStatisticsVo.java new file mode 100644 index 00000000..bbe35610 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fp/entity/vo/FpFishStatisticsVo.java @@ -0,0 +1,21 @@ +package com.yfd.platform.qgc_env.fp.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "过鱼设施鱼类统计") +public class FpFishStatisticsVo { + + @Schema(description = "站点编码") + private String stcd; + + @Schema(description = "鱼类名称") + private String ftp; + + @Schema(description = "鱼编码") + private String fishId; + + @Schema(description = "数量") + private Integer count; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/FpBuildService.java b/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/FpBuildService.java index 67e8973d..bd6dca95 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/FpBuildService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/FpBuildService.java @@ -21,5 +21,7 @@ public interface FpBuildService { FpVmsstbprptVo getStInfoByStcd(String stcd); + DataSourceResult getQgcFpPointKendoListCust(DataSourceRequest dataSourceRequest); + DataSourceResult getFpBuiltPointKendoListCust(DataSourceRequest dataSourceRequest); } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/impl/FpBuildServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/impl/FpBuildServiceImpl.java index 51c18d63..6aadcfd6 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/impl/FpBuildServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/impl/FpBuildServiceImpl.java @@ -14,6 +14,7 @@ import com.yfd.platform.common.exception.BizException; import com.yfd.platform.qgc_env.fp.entity.vo.FpAnchoPointVo; import com.yfd.platform.qgc_env.fp.entity.vo.FpConstructionSituationVo; import com.yfd.platform.qgc_env.fp.entity.vo.FpFishDicVo; +import com.yfd.platform.qgc_env.fp.entity.vo.FpFishStatisticsVo; import com.yfd.platform.qgc_env.fp.entity.vo.FpVmsstbprptVo; import com.yfd.platform.qgc_env.wt.utils.SiteAvoidanceUtils; import com.yfd.platform.qgc_env.fp.service.FpBuildService; @@ -28,6 +29,8 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; @Service public class FpBuildServiceImpl implements FpBuildService { @@ -214,6 +217,99 @@ public class FpBuildServiceImpl implements FpBuildService { return list.getFirst(); } + @Override + public DataSourceResult getQgcFpPointKendoListCust(DataSourceRequest dataSourceRequest) { + DataSourceResult dataSourceResult = new DataSourceResult<>(); + dataSourceResult.setAggregates(new HashMap<>()); + if (dataSourceRequest == null) { + dataSourceResult.setData(new ArrayList<>()); + dataSourceResult.setTotal(0L); + return dataSourceResult; + } + + StringBuilder sql = new StringBuilder("SELECT " + + "fp.STCD AS stcd, " + + "fp.STNM AS stnm, " + + "fp.LOGO AS logo, " + + "fp.STNM AS titleName, " + + "fp.BLDSTT_CODE AS bldsttCcode, " + + "fp.BLDSTT_CODE AS bldstt, " + + "fp.LTTD AS lttd, " + + "fp.LGTD AS lgtd, " + + "fp.ELEV AS dtmel, " + + "fp.RSTCD AS rstcds, " + + "eng.ENNM AS ennm, " + + "'FP' AS sttpCode, " + + "state.RUN_STATE AS run, " + + "CASE WHEN state.RUN_STATE = 1 THEN '运行中' WHEN state.RUN_STATE IN (0, 2) THEN '未运行' ELSE NULL END AS runName, " + + "fp.STTP AS dwtp, " + + "CASE " + + "WHEN fp.STTP = 'FP_1' THEN '鱼道' " + + "WHEN fp.STTP = 'FP_2' THEN '仿自然通道' " + + "WHEN fp.STTP = 'FP_3' THEN '集运鱼系统' " + + "WHEN fp.STTP = 'FP_4' THEN '升鱼机' " + + "ELSE '其它' END AS dwtpName, " + + "fp.STTP AS sttpMap, " + + "eng.RVCD AS rvcd, " + + "eng.ADDVCD AS addvcd, " + + "eng.BASE_ID AS baseId, " + + "fp.STTP AS sttp, " + + "CASE " + + "WHEN fp.STTP = 'FP_1' THEN 'GY_1' " + + "WHEN fp.STTP = 'FP_2' THEN 'GY_2' " + + "WHEN fp.STTP = 'FP_3' THEN 'GY_3' " + + "WHEN fp.STTP = 'FP_4' THEN 'GY_4' " + + "ELSE 'GY_5' END AS anchoPointState, " + + "fp.MWAY AS mway, " + + "fp.DTIN AS dtin, " + + "state.STD_SSTATE AS stdSstate, " + + "CASE WHEN state.STD_SSTATE = 1 THEN '正常运行' " + + "WHEN state.STD_SSTATE IN (0, 2) THEN '暂无数据' " + + "WHEN state.STD_SSTATE = 3 THEN '未正常运行' ELSE NULL END AS stdSstateName, " + + "CASE WHEN recent.STCD IS NULL THEN 2 ELSE 1 END AS lcjStatus, " + + "CASE WHEN recent.STCD IS NULL THEN '暂无数据' ELSE '正常运行' END AS lcjStatusName, " + + "fp.ORDER_INDEX AS orderIndex " + + "FROM SD_FPSS_B_H fp " + + "LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fp.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " + + "LEFT JOIN (SELECT s.STCD, s.RUN_STATE, s.STD_SSTATE " + + " FROM MS_STSTATE_T s " + + " INNER JOIN (SELECT STCD, MAX(YR) AS YR FROM MS_STSTATE_T WHERE NVL(IS_DELETED, 0) = 0 GROUP BY STCD) latest " + + " ON latest.STCD = s.STCD AND latest.YR = s.YR " + + " WHERE NVL(s.IS_DELETED, 0) = 0) state ON state.STCD = fp.STCD " + + "LEFT JOIN (SELECT STCD FROM SD_FPSSRL_R WHERE NVL(IS_DELETED, 0) = 0 AND TM BETWEEN ADD_MONTHS(SYSDATE, -12) AND SYSDATE GROUP BY STCD " + + " UNION " + + " SELECT STCD FROM SD_FPSS_R WHERE NVL(IS_DELETED, 0) = 0 AND STRDT >= ADD_MONTHS(SYSDATE, -12) AND NVL(ENDDT, STRDT) <= SYSDATE GROUP BY STCD) recent " + + "ON recent.STCD = fp.STCD " + + "WHERE NVL(fp.IS_DELETED, 0) = 0 "); + + Map paramMap = new HashMap<>(); + DataSourceLoadOptionsBase loadOptions = dataSourceRequest.toDevRequest(); + String filterSql = buildFpPointFilterCondition(dataSourceRequest.getFilter(), paramMap, new int[]{0}); + if (StrUtil.isNotBlank(filterSql)) { + sql.append(" AND ").append(filterSql).append(" "); + } + sql.append(buildFpPointOrderBySql(dataSourceRequest.getSort())); + + Page page = QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + List resultList = microservicDynamicSQLMapper.pageAllListWithResultType( + page, sql.toString(), paramMap, FpAnchoPointVo.class); + + if (CollUtil.isNotEmpty(resultList)) { + fillQgcFpPointStatistics(resultList); + applyFpPointLegend(resultList); + SiteAvoidanceUtils.calcSiteMapLev(resultList, + FpAnchoPointVo::getStcd, + FpAnchoPointVo::getLgtd, + FpAnchoPointVo::getLttd, + FpAnchoPointVo::getAnchoPointState, + FpAnchoPointVo::setDistance); + } + + dataSourceResult.setData(resultList); + dataSourceResult.setTotal(page == null ? resultList.size() : page.getTotal()); + return dataSourceResult; + } + private String buildFishDicBaseSql() { return "SELECT " + "src.ID AS id, " + @@ -1232,6 +1328,193 @@ public class FpBuildServiceImpl implements FpBuildService { return dataSourceResult; } + private void fillQgcFpPointStatistics(List pointList) { + List stcdList = pointList.stream() + .map(FpAnchoPointVo::getStcd) + .filter(StrUtil::isNotBlank) + .distinct() + .collect(Collectors.toList()); + if (CollUtil.isEmpty(stcdList)) { + return; + } + + String year = queryLatestFpYear(stcdList); + List manualList = queryQgcFpManualFishStatistics(stcdList, year); + Set manualStcdSet = manualList.stream() + .map(FpFishStatisticsVo::getStcd) + .filter(StrUtil::isNotBlank) + .collect(Collectors.toSet()); + List autoQueryStcdList = stcdList.stream() + .filter(stcd -> !manualStcdSet.contains(stcd)) + .collect(Collectors.toList()); + List autoList = queryQgcFpAutoFishStatistics(autoQueryStcdList, year); + if (CollUtil.isNotEmpty(autoList)) { + manualList.addAll(autoList); + } + Map> stcdDataMap = manualList.stream() + .collect(Collectors.groupingBy(FpFishStatisticsVo::getStcd)); + for (FpAnchoPointVo vo : pointList) { + vo.setYr(year); + List fishStatistics = stcdDataMap.get(vo.getStcd()); + if (CollUtil.isEmpty(fishStatistics)) { + continue; + } + vo.setFtpTypeCount(fishStatistics.size()); + vo.setFtpCount(fishStatistics.stream() + .filter(item -> item.getCount() != null) + .mapToInt(FpFishStatisticsVo::getCount) + .sum()); + } + } + + private String queryLatestFpYear(List stcdList) { + Map paramMap = new HashMap<>(); + StringBuilder sql = new StringBuilder("SELECT MAX(t.YR) AS yr FROM (" + + "SELECT TO_CHAR(STRDT, 'yyyy') AS YR, STCD FROM SD_FPSS_R WHERE NVL(IS_DELETED, 0) = 0 " + + "UNION ALL " + + "SELECT TO_CHAR(TM, 'yyyy') AS YR, STCD FROM SD_FPSSRL_R WHERE NVL(IS_DELETED, 0) = 0) t WHERE 1 = 1 "); + appendInCondition(sql, paramMap, "t.STCD", stcdList, "fpYear"); + List list = microservicDynamicSQLMapper.getAllListWithResultType(sql.toString(), paramMap, FpAnchoPointVo.class); + if (CollUtil.isEmpty(list) || StrUtil.isBlank(list.getFirst().getYr())) { + return String.valueOf(java.time.LocalDate.now().getYear()); + } + return list.getFirst().getYr(); + } + + private List queryQgcFpManualFishStatistics(List stcdList, String year) { + if (CollUtil.isEmpty(stcdList)) { + return new ArrayList<>(); + } + Map paramMap = new HashMap<>(); + StringBuilder sql = new StringBuilder("SELECT data.STCD AS stcd, data.FTP AS fishId, dict.NAME AS ftp, SUM(data.FCNT) AS count " + + "FROM (SELECT t.STCD, t.FTP, t.FCNT, eng.HBRVCD " + + " FROM SD_FPSS_R t " + + " INNER JOIN SD_FPSS_B_H fp ON fp.STCD = t.STCD AND NVL(fp.IS_DELETED, 0) = 0 " + + " LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fp.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " + + " WHERE NVL(t.IS_DELETED, 0) = 0 "); + paramMap.put("manualYear", year); + sql.append(" AND TO_CHAR(t.STRDT, 'yyyy') = #{map.manualYear}) data ") + .append("INNER JOIN (SELECT DISTINCT rel.FISH_ID, rel.RVCD, dic.NAME " + + " FROM SD_FISHDICTORY_RLTN_B rel " + + " LEFT JOIN SD_FISHDICTORY_B dic ON dic.ID = rel.ZY_FISH_ID " + + " WHERE NVL(rel.IS_DELETED, 0) = 0 AND NVL(dic.IS_DELETED, 0) = 0 " + + " AND (rel.FISH_ID <> rel.ZY_FISH_ID OR rel.RVCD = 'ZY')) dict " + + "ON dict.FISH_ID = data.FTP AND (dict.RVCD = data.HBRVCD OR dict.RVCD = 'ZY') WHERE 1 = 1 "); + appendInCondition(sql, paramMap, "data.STCD", stcdList, "fpManual"); + sql.append(" GROUP BY data.STCD, data.FTP, dict.NAME"); + return microservicDynamicSQLMapper.getAllListWithResultType(sql.toString(), paramMap, FpFishStatisticsVo.class); + } + + private List queryQgcFpAutoFishStatistics(List stcdList, String year) { + if (CollUtil.isEmpty(stcdList)) { + return new ArrayList<>(); + } + Map paramMap = new HashMap<>(); + StringBuilder sql = new StringBuilder("SELECT data.STCD AS stcd, data.FTP AS fishId, dict.NAME AS ftp, SUM(data.FCNT) AS count " + + "FROM (SELECT t.STCD, t.FTP, t.FCNT, eng.HBRVCD " + + " FROM SD_FPSSRL_R t " + + " INNER JOIN SD_FPSS_B_H fp ON fp.STCD = t.STCD AND NVL(fp.IS_DELETED, 0) = 0 " + + " LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fp.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " + + " WHERE NVL(t.IS_DELETED, 0) = 0 "); + paramMap.put("autoYear", year); + sql.append(" AND TO_CHAR(t.TM, 'yyyy') = #{map.autoYear}) data ") + .append("INNER JOIN (SELECT DISTINCT rel.FISH_ID, rel.RVCD, dic.NAME " + + " FROM SD_FISHDICTORY_RLTN_B rel " + + " LEFT JOIN SD_FISHDICTORY_B dic ON dic.ID = rel.ZY_FISH_ID " + + " WHERE NVL(rel.IS_DELETED, 0) = 0 AND NVL(dic.IS_DELETED, 0) = 0 " + + " AND (rel.FISH_ID <> rel.ZY_FISH_ID OR rel.RVCD = 'ZY')) dict " + + "ON dict.FISH_ID = data.FTP AND (dict.RVCD = data.HBRVCD OR dict.RVCD = 'ZY') WHERE 1 = 1 "); + appendInCondition(sql, paramMap, "data.STCD", stcdList, "fpAuto"); + sql.append(" GROUP BY data.STCD, data.FTP, dict.NAME"); + return microservicDynamicSQLMapper.getAllListWithResultType(sql.toString(), paramMap, FpFishStatisticsVo.class); + } + + private void applyFpPointLegend(List voList) { + for (FpAnchoPointVo pointVo : voList) { + if (!"2".equals(pointVo.getBldstt())) { + if ("FP_1".equals(pointVo.getSttp())) { + pointVo.setAnchoPointState("GY_1_INCOMPLETE"); + } else if ("FP_2".equals(pointVo.getSttp())) { + pointVo.setAnchoPointState("GY_2_INCOMPLETE"); + } else if ("FP_3".equals(pointVo.getSttp())) { + pointVo.setAnchoPointState("GY_3_INCOMPLETE"); + } else if ("FP_4".equals(pointVo.getSttp())) { + pointVo.setAnchoPointState("GY_4_INCOMPLETE"); + } else { + pointVo.setAnchoPointState("GY_5_INCOMPLETE"); + } + } + } + } + + private void appendInCondition(StringBuilder sql, + Map paramMap, + String column, + List values, + String prefix) { + if (CollUtil.isEmpty(values)) { + return; + } + List placeholders = new ArrayList<>(); + int index = 0; + for (String value : values) { + if (StrUtil.isBlank(value)) { + continue; + } + String key = prefix + index++; + paramMap.put(key, value); + placeholders.add("#{map." + key + "}"); + } + if (CollUtil.isEmpty(placeholders)) { + return; + } + sql.append(" AND ").append(column).append(" IN (") + .append(String.join(", ", placeholders)) + .append(") "); + } + + private String buildFpPointOrderBySql(List sorts) { + if (CollUtil.isEmpty(sorts)) { + return " ORDER BY fp.ORDER_INDEX ASC NULLS LAST, fp.STCD ASC"; + } + List orderItems = new ArrayList<>(); + for (DataSourceRequest.SortDescriptor sort : sorts) { + if (sort == null || StrUtil.isBlank(sort.getField())) { + continue; + } + String column = mapFpPointOrderColumn(sort.getField()); + if (StrUtil.isBlank(column)) { + continue; + } + String direction = "desc".equalsIgnoreCase(sort.getDir()) || "des".equalsIgnoreCase(sort.getDir()) ? "DESC" : "ASC"; + orderItems.add(column + " " + direction + " NULLS LAST"); + } + if (orderItems.isEmpty()) { + return " ORDER BY fp.ORDER_INDEX ASC NULLS LAST, fp.STCD ASC"; + } + return " ORDER BY " + String.join(", ", orderItems); + } + + private String mapFpPointOrderColumn(String field) { + if (StrUtil.isBlank(field)) { + return null; + } + return switch (field) { + case "stcd" -> "fp.STCD"; + case "stnm", "titleName" -> "fp.STNM"; + case "bldsttCcode", "bldstt" -> "fp.BLDSTT_CODE"; + case "lgtd" -> "fp.LGTD"; + case "lttd" -> "fp.LTTD"; + case "ennm" -> "eng.ENNM"; + case "baseId" -> "eng.BASE_ID"; + case "rvcd" -> "eng.RVCD"; + case "addvcd" -> "eng.ADDVCD"; + case "run" -> "state.RUN_STATE"; + case "stdSstate" -> "state.STD_SSTATE"; + default -> null; + }; + } + private String mapFpColumn(String field) { if (StrUtil.isBlank(field)) { return null; @@ -1240,7 +1523,6 @@ public class FpBuildServiceImpl implements FpBuildService { case "bldsttccode" -> "fp.BLDSTT_CODE"; case "lgtd" -> "fp.LGTD"; case "lttd" -> "fp.LTTD"; - case "fhstcd" -> "fp.FHSTCD"; default -> null; }; } @@ -1285,6 +1567,12 @@ public class FpBuildServiceImpl implements FpBuildService { case "rvcd" -> "eng.RVCD"; case "addvcd" -> "eng.ADDVCD"; case "sttp" -> "fp.STTP"; + case "bldsttCcode", "bldstt" -> "fp.BLDSTT_CODE"; + case "lgtd" -> "fp.LGTD"; + case "lttd" -> "fp.LTTD"; + case "run" -> "state.RUN_STATE"; + case "stdSstate" -> "state.STD_SSTATE"; + case "lcjStatus" -> "CASE WHEN recent.STCD IS NULL THEN 2 ELSE 1 END"; default -> null; }; if (column == null) {