From 3f1c01461754156fedcdbff2452d1a9b7d6b42cf Mon Sep 17 00:00:00 2001 From: tangwei Date: Wed, 12 Aug 2026 17:25:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=8E=AF=E4=BF=9D=E9=83=A8-=E8=BF=87?= =?UTF-8?q?=E9=B1=BC=E6=80=BB=E9=87=8F-=E4=BA=8C=E7=BA=A7=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fp/controller/FishPassageController.java | 6 + .../fp/entity/vo/FpOverfishTotalVo.java | 84 ++++++ .../qgc_env/fp/service/FpRunService.java | 3 + .../fp/service/impl/FpRunServiceImpl.java | 253 ++++++++++++++++++ 4 files changed, 346 insertions(+) create mode 100644 backend/src/main/java/com/yfd/platform/qgc_env/fp/entity/vo/FpOverfishTotalVo.java 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 e5f1f215..aeaeca8d 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 @@ -136,4 +136,10 @@ public class FishPassageController { public ResponseResult getTreeStcdList(@RequestBody DataSourceRequest dataSourceRequest) { return ResponseResult.successData(fpRunService.getTreeStcdList(dataSourceRequest)); } + + @PostMapping("/query/qgc/getOverfishTotal") + @Operation(summary = "环保部-过鱼总量-二级弹窗列表(SD_FPSSRL_R + SD_FPSS_R 合并)") + public ResponseResult getQgcOverfishTotal(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(fpRunService.processQgcOverfishTotalKendoList(dataSourceRequest)); + } } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fp/entity/vo/FpOverfishTotalVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/fp/entity/vo/FpOverfishTotalVo.java new file mode 100644 index 00000000..49d32290 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fp/entity/vo/FpOverfishTotalVo.java @@ -0,0 +1,84 @@ +package com.yfd.platform.qgc_env.fp.entity.vo; + +import lombok.Data; + +import java.util.Date; + +/** + *

+ * 环保部-过鱼总量-二级弹窗列表 VO + *

+ *

对应旧系统 FpssrlRQueryVo.getQgcOverfishTotal,查询 SD_FPSSRL_R + SD_FPSS_R 合并数据

+ */ +@Data +public class FpOverfishTotalVo { + + /** 过鱼设施编码 */ + private String stcd; + + /** 设施名称 */ + private String stnm; + + /** 基地编码 */ + private String baseId; + + /** 基地名称 */ + private String baseName; + + /** 电站编码 */ + private String rstcd; + + /** 电站名称 */ + private String ennm; + + /** 时间 */ + private Date tm; + + /** 过鱼年份 */ + private String yr; + + /** 鱼类名称 */ + private String ftp; + + /** 鱼类编码 */ + private String fishId; + + /** 大小 */ + private String fsz; + + /** 鱼宽度 */ + private String width; + + /** 鱼速度 */ + private String fishspeed; + + /** 游向:0=上行 1=下行 */ + private String direction; + + /** 水温 */ + private String temperature; + + /** 流速 */ + private String speed; + + /** 过鱼通道 */ + private String channelno; + + /** 数量 */ + private String fcnt; + + /** 图片URL */ + private String firstimgurl; + + /** 视频URL */ + private String videourl; + + /** 监测方式:1=人工 2=自动 */ + private Integer mway; + + /** 人工过鱼 开始日期 */ + private Date strdt; + + /** 人工过鱼 结束日期 */ + private Date enddt; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/FpRunService.java b/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/FpRunService.java index 14e24b26..c6eea469 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/FpRunService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/FpRunService.java @@ -10,6 +10,7 @@ import com.yfd.platform.qgc_env.fp.entity.vo.FpSdfpssrVo; import com.yfd.platform.qgc_env.fp.entity.vo.FpTableVo; import com.yfd.platform.qgc_env.fp.entity.vo.FpTreeStcdGroupVo; import com.yfd.platform.qgc_env.fp.entity.vo.YearFpStatisticsVo; +import com.yfd.platform.qgc_env.fp.entity.vo.FpOverfishTotalVo; import com.yfd.platform.qgc_env.fp.entity.vo.FpRunPlanVo; import java.util.List; @@ -35,4 +36,6 @@ public interface FpRunService { List getYearFpStatic(String year,String stcd); DataSourceResult getTreeStcdList(DataSourceRequest dataSourceRequest); + + DataSourceResult processQgcOverfishTotalKendoList(DataSourceRequest dataSourceRequest); } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/impl/FpRunServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/impl/FpRunServiceImpl.java index 8baf1fd0..9c753d0a 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/impl/FpRunServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fp/service/impl/FpRunServiceImpl.java @@ -17,6 +17,7 @@ import com.yfd.platform.qgc_env.fp.entity.vo.FbFishRunVo; import com.yfd.platform.qgc_env.fp.entity.vo.FpFishSelectVo; import com.yfd.platform.qgc_env.fp.entity.vo.FpFpssrlQueryVo; import com.yfd.platform.qgc_env.fp.entity.vo.FpFtpStatisticsVo; +import com.yfd.platform.qgc_env.fp.entity.vo.FpOverfishTotalVo; import com.yfd.platform.qgc_env.fp.entity.vo.FpRunAnalysisHeadColumnVo; import com.yfd.platform.qgc_env.fp.entity.vo.FpRunAnalysisTableVo; import com.yfd.platform.qgc_env.fp.entity.vo.FpRunAnalysisVo; @@ -2838,5 +2839,257 @@ public class FpRunServiceImpl implements FpRunService { }; } + // ==================== 环保部-过鱼总量-二级弹窗列表 ==================== + + @Override + public DataSourceResult processQgcOverfishTotalKendoList(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + if (CollUtil.isEmpty(dataSourceRequest == null ? null : dataSourceRequest.getGroup())) { + return queryOverfishTotalDetailList(dataSourceRequest, loadOptions); + } + return queryOverfishTotalGroupList(dataSourceRequest, loadOptions); + } + + private DataSourceResult queryOverfishTotalDetailList(DataSourceRequest dataSourceRequest, + DataSourceLoadOptionsBase loadOptions) { + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append(buildOverfishTotalSelectSql(dataSourceRequest == null ? null : dataSourceRequest.getSelect())) + .append(" FROM (") + .append(buildOverfishTotalCoreSql()) + .append(") t WHERE 1 = 1 "); + + Map paramMap = new HashMap<>(); + String filterSql = QgcQueryWrapperUtil.buildFilterCondition( + dataSourceRequest == null ? null : dataSourceRequest.getFilter(), + paramMap, + new int[]{0}, + this::mapOverfishTotalColumn + ); + if (StrUtil.isNotBlank(filterSql)) { + sql.append(" AND ").append(filterSql).append(" "); + } + sql.append(buildOverfishTotalOrderBySql(dataSourceRequest == null ? null : dataSourceRequest.getSort())); + + Page page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + List list = microservicDynamicSQLMapper.pageAllListWithResultType( + page, sql.toString(), paramMap, FpOverfishTotalVo.class + ); + DataSourceResult result = new DataSourceResult<>(); + result.setData(list); + result.setTotal(page != null ? page.getTotal() : list.size()); + result.setAggregates(new HashMap<>()); + return result; + } + + private DataSourceResult queryOverfishTotalGroupList(DataSourceRequest dataSourceRequest, + DataSourceLoadOptionsBase loadOptions) { + List groups = dataSourceRequest.getGroup(); + GroupingInfo[] groupInfos = loadOptions == null ? new GroupingInfo[0] : loadOptions.getGroup(); + + List selectItems = new ArrayList<>(); + for (DataSourceRequest.GroupDescriptor descriptor : groups) { + if (descriptor == null || StrUtil.isBlank(descriptor.getField())) { + continue; + } + String column = mapOverfishTotalColumn(descriptor.getField()); + if (StrUtil.isBlank(column)) { + continue; + } + selectItems.add(column + " AS " + descriptor.getField().toUpperCase()); + selectItems.add("COUNT(*) AS COUNT_" + descriptor.getField().toUpperCase()); + if (CollUtil.isNotEmpty(descriptor.getAggregates())) { + for (DataSourceRequest.AggregateDescriptor aggregate : descriptor.getAggregates()) { + String aggregateColumn = mapOverfishTotalColumn(aggregate.getField()); + if (StrUtil.isBlank(aggregateColumn) || StrUtil.isBlank(aggregate.getAggregate())) { + continue; + } + selectItems.add(buildAggregateSql(aggregate.getAggregate(), aggregateColumn, aggregate.getField())); + } + } + } + if (selectItems.isEmpty()) { + selectItems.add("t.STCD AS STCD"); + selectItems.add("COUNT(*) AS COUNT_STCD"); + } + + StringBuilder sql = new StringBuilder("SELECT "); + sql.append(String.join(", ", selectItems)) + .append(" FROM (") + .append(buildOverfishTotalCoreSql()) + .append(") t WHERE 1 = 1 "); + + Map paramMap = new HashMap<>(); + String filterSql = QgcQueryWrapperUtil.buildFilterCondition( + dataSourceRequest == null ? null : dataSourceRequest.getFilter(), + paramMap, + new int[]{0}, + this::mapOverfishTotalColumn + ); + if (StrUtil.isNotBlank(filterSql)) { + sql.append(" AND ").append(filterSql).append(" "); + } + + List groupByColumns = new ArrayList<>(); + for (DataSourceRequest.GroupDescriptor descriptor : groups) { + if (descriptor == null || StrUtil.isBlank(descriptor.getField())) { + continue; + } + String column = mapOverfishTotalColumn(descriptor.getField()); + if (StrUtil.isNotBlank(column)) { + groupByColumns.add(column); + } + } + if (!groupByColumns.isEmpty()) { + sql.append(" GROUP BY ").append(String.join(", ", groupByColumns)).append(" "); + } + + List> rows = microservicDynamicSQLMapper.pageAllList(null, sql.toString(), paramMap); + DataSourceResult result = new DataSourceResult<>(); + if (dataSourceRequest.getGroupResultFlat() != null && dataSourceRequest.getGroupResultFlat()) { + result.setData((List) (List) new GroupHelper().faltGroup(rows, Arrays.asList(groupInfos))); + } else { + result.setData((List) (List) new GroupHelper().group(rows, Arrays.asList(groupInfos))); + } + result.setTotal(0L); + result.setAggregates(new HashMap<>()); + return result; + } + + /** + * 过鱼总量核心 SQL:SD_FPSSRL_R(自动)UNION ALL SD_FPSS_R(人工) + *

使用 V_MS_STBPRP_T 替代旧系统 MS_STBPRP_T,V_SD_FISHDICTORY_B 替代旧版鱼类字典

+ */ + private String buildOverfishTotalCoreSql() { + return "SELECT t.STCD, t.STNM, t.BASE_ID, t.BASE_NAME, " + + "t.RSTCD, t.ENNM, t.TM, t.YR, t.FTP, t.FISHID, t.FSZ, " + + "t.WIDTH, t.FISHSPEED, t.DIRECTION, t.TEMPERATURE, t.SPEED, " + + "t.CHANNELNO, t.FCNT, t.FIRSTIMGURL, t.VIDEOURL, " + + "t.MWAY, t.STRDT, t.ENDDT " + + "FROM ( " + + // ---- 自动监测 SD_FPSSRL_R ---- + " SELECT a.STCD, msb.STNM, msb.BASE_ID, msb.BASE_NAME, msb.RSTCD, msb.ENNM, " + + " a.TM, TO_CHAR(a.TM, 'YYYY') AS YR, dict.NAME AS FTP, a.FTP AS FISHID, a.FSZ, " + + " TO_CHAR(a.WIDTH) AS WIDTH, TO_CHAR(a.FISHSPEED) AS FISHSPEED, " + + " TO_CHAR(a.DIRECTION) AS DIRECTION, TO_CHAR(a.TEMPERATURE) AS TEMPERATURE, " + + " TO_CHAR(a.SPEED) AS SPEED, a.CHANNELNO, TO_CHAR(a.FCNT) AS FCNT, " + + " a.FIRSTIMGURL, a.VIDEOURL, msb.MWAY, NULL AS STRDT, NULL AS ENDDT " + + " FROM SD_FPSSRL_R a " + + " INNER JOIN V_MS_STBPRP_T msb ON a.STCD = msb.STCD AND msb.DATA_SOURCE = 'SD_FPSS_B_H' " + + " INNER JOIN V_SD_FISHDICTORY_B dict ON a.FTP = dict.FISH_ID " + + " AND (msb.HBRVCD = dict.RVCD OR dict.RVCD = 'ZY') " + + " WHERE NVL(a.IS_DELETED, 0) = 0 " + + " UNION ALL " + + // ---- 人工监测 SD_FPSS_R ---- + " SELECT a.STCD, msb.STNM, msb.BASE_ID, msb.BASE_NAME, msb.RSTCD, msb.ENNM, " + + " a.STRDT AS TM, TO_CHAR(a.STRDT, 'YYYY') AS YR, dict.NAME AS FTP, a.FTP AS FISHID, " + + " MIN(a.FSZ) AS FSZ, NULL AS WIDTH, NULL AS FISHSPEED, " + + " TO_CHAR(MIN(a.DIRECTION)) AS DIRECTION, NULL AS TEMPERATURE, NULL AS SPEED, " + + " NULL AS CHANNELNO, TO_CHAR(SUM(a.FCNT)) AS FCNT, " + + " NULL AS FIRSTIMGURL, NULL AS VIDEOURL, 1 AS MWAY, a.STRDT, a.ENDDT " + + " FROM SD_FPSS_R a " + + " INNER JOIN V_MS_STBPRP_T msb ON a.STCD = msb.STCD AND msb.DATA_SOURCE = 'SD_FPSS_B_H' " + + " INNER JOIN V_SD_FISHDICTORY_B dict ON a.FTP = dict.FISH_ID " + + " AND (msb.HBRVCD = dict.RVCD OR dict.RVCD = 'ZY') " + + " WHERE 1=1 " + + " AND NVL(a.IS_DELETED, 0) = 0 " + + " GROUP BY a.STCD, msb.STNM, msb.BASE_ID, msb.BASE_NAME, msb.RSTCD, msb.ENNM, " + + " a.STRDT, a.ENDDT, TO_CHAR(a.STRDT, 'YYYY'), dict.NAME, a.FTP " + + ") t WHERE 1 = 1 "; + } + + private String buildOverfishTotalSelectSql(List selectFields) { + Map columns = new LinkedHashMap<>(); + columns.put("stcd", "t.STCD AS stcd"); + columns.put("stnm", "t.STNM AS stnm"); + columns.put("baseId", "t.BASE_ID AS baseId"); + columns.put("baseName", "t.BASE_NAME AS baseName"); + columns.put("rstcd", "t.RSTCD AS rstcd"); + columns.put("ennm", "t.ENNM AS ennm"); + columns.put("tm", "t.TM AS tm"); + columns.put("yr", "t.YR AS yr"); + columns.put("ftp", "t.FTP AS ftp"); + columns.put("fishId", "t.FISHID AS fishId"); + columns.put("fsz", "t.FSZ AS fsz"); + columns.put("width", "t.WIDTH AS width"); + columns.put("fishspeed", "t.FISHSPEED AS fishspeed"); + columns.put("direction", "t.DIRECTION AS direction"); + columns.put("temperature", "t.TEMPERATURE AS temperature"); + columns.put("speed", "t.SPEED AS speed"); + columns.put("channelno", "t.CHANNELNO AS channelno"); + columns.put("fcnt", "t.FCNT AS fcnt"); + columns.put("firstimgurl", "t.FIRSTIMGURL AS firstimgurl"); + columns.put("videourl", "t.VIDEOURL AS videourl"); + columns.put("mway", "t.MWAY AS mway"); + columns.put("strdt", "t.STRDT AS strdt"); + columns.put("enddt", "t.ENDDT AS enddt"); + + List selected = new ArrayList<>(); + if (CollUtil.isEmpty(selectFields)) { + selected.addAll(columns.values()); + } else { + for (String field : selectFields) { + String column = columns.get(field); + if (StrUtil.isNotBlank(column)) { + selected.add(column); + } + } + if (selected.isEmpty()) { + selected.addAll(columns.values()); + } + } + return String.join(", ", selected); + } + + private String mapOverfishTotalColumn(String field) { + if (StrUtil.isBlank(field)) { + return null; + } + return switch (field.toLowerCase()) { + case "stcd" -> "t.STCD"; + case "stnm" -> "t.STNM"; + case "baseid" -> "t.BASE_ID"; + case "basename" -> "t.BASE_NAME"; + case "rstcd" -> "t.RSTCD"; + case "ennm" -> "t.ENNM"; + case "tm" -> "t.TM"; + case "yr" -> "t.YR"; + case "ftp" -> "t.FTP"; + case "fishid" -> "t.FISHID"; + case "fsz" -> "t.FSZ"; + case "width" -> "t.WIDTH"; + case "fishspeed" -> "t.FISHSPEED"; + case "direction" -> "t.DIRECTION"; + case "temperature" -> "t.TEMPERATURE"; + case "speed" -> "t.SPEED"; + case "channelno" -> "t.CHANNELNO"; + case "fcnt" -> "t.FCNT"; + case "mway" -> "t.MWAY"; + case "strdt" -> "t.STRDT"; + case "enddt" -> "t.ENDDT"; + case "firstimgurl" -> "t.FIRSTIMGURL"; + case "videourl" -> "t.VIDEOURL"; + default -> null; + }; + } + + private String buildOverfishTotalOrderBySql(List sortList) { + if (CollUtil.isEmpty(sortList)) { + return " ORDER BY t.TM DESC"; + } + List orders = new ArrayList<>(); + for (DataSourceRequest.SortDescriptor sort : sortList) { + if (sort == null || StrUtil.isBlank(sort.getField())) { + continue; + } + String column = mapOverfishTotalColumn(sort.getField()); + if (StrUtil.isBlank(column)) { + continue; + } + String dir = "desc".equalsIgnoreCase(sort.getDir()) ? "DESC" : "ASC"; + orders.add(column + " " + dir); + } + return orders.isEmpty() ? " ORDER BY t.TM DESC" : " ORDER BY " + String.join(", ", orders); + } }