diff --git a/backend/src/main/java/com/yfd/platform/config/SwaggerConfig.java b/backend/src/main/java/com/yfd/platform/config/SwaggerConfig.java index 443e06a6..f0faacb1 100644 --- a/backend/src/main/java/com/yfd/platform/config/SwaggerConfig.java +++ b/backend/src/main/java/com/yfd/platform/config/SwaggerConfig.java @@ -122,11 +122,19 @@ public class SwaggerConfig { @Bean public GroupedOpenApi groupEnvFprApi() { return GroupedOpenApi.builder() - .group("3.5 全过程-生态环保数据服务-鱼类调查") + .group("3.6 全过程-生态环保数据服务-鱼类调查") .packagesToScan("com.yfd.platform.qgc_env.fpr.controller") .build(); } + @Bean + public GroupedOpenApi groupEnvFbApi() { + return GroupedOpenApi.builder() + .group("3.7 全过程-生态环保数据服务-鱼类调查") + .packagesToScan("com.yfd.platform.qgc_env.fb.controller") + .build(); + } + diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fb/controller/FbStationController.java b/backend/src/main/java/com/yfd/platform/qgc_env/fb/controller/FbStationController.java new file mode 100644 index 00000000..5ffb0de6 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fb/controller/FbStationController.java @@ -0,0 +1,29 @@ +package com.yfd.platform.qgc_env.fb.controller; + +import com.yfd.platform.common.DataSourceRequest; +import com.yfd.platform.config.ResponseResult; +import com.yfd.platform.qgc_env.fb.service.FbStationService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +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; + +@RestController +@RequestMapping("/fb/station") +@Tag(name = "鱼类增殖站概况") +@Validated +public class FbStationController { + + @Resource + private FbStationService fbStationService; + + @PostMapping("/qgcoverview/getOverviewSecond") + @Operation(summary = "全流域增殖站概况二级页面") + public ResponseResult getQgcOverviewSecond(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(fbStationService.getQgcOverviewSecond(dataSourceRequest)); + } +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fb/entity/vo/FbStationOverviewSecondVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/fb/entity/vo/FbStationOverviewSecondVo.java new file mode 100644 index 00000000..e39ace7a --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fb/entity/vo/FbStationOverviewSecondVo.java @@ -0,0 +1,53 @@ +package com.yfd.platform.qgc_env.fb.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +@Schema(description = "全流域增殖站概况二级页面") +public class FbStationOverviewSecondVo { + + @Schema(description = "增殖站编码") + private String stcd; + + @Schema(description = "增殖站名称") + private String stnm; + + @Schema(description = "服务电站") + private String ennm; + + @Schema(description = "增殖站总数") + private Integer count; + + @Schema(description = "鱼种类数") + private Integer ftpCount; + + @Schema(description = "总投资") + private BigDecimal totalInv; + + @Schema(description = "计划放流鱼种类") + private String planFtp; + + @Schema(description = "计划放流尾数") + private BigDecimal fcntjh; + + @Schema(description = "实际鱼种类数") + private Integer realftpCount; + + @Schema(description = "实际鱼种类") + private String realftp; + + @Schema(description = "实际放流尾数") + private BigDecimal realfcnt; + + @Schema(description = "实际放流尾数字符串") + private String realfcntStr; + + @Schema(description = "年份") + private String year; + + @Schema(description = "累计放鱼数量") + private Long totalFtpCount; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/FbStationService.java b/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/FbStationService.java new file mode 100644 index 00000000..600f6664 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/FbStationService.java @@ -0,0 +1,10 @@ +package com.yfd.platform.qgc_env.fb.service; + +import com.yfd.platform.common.DataSourceRequest; +import com.yfd.platform.common.DataSourceResult; +import com.yfd.platform.qgc_env.fb.entity.vo.FbStationOverviewSecondVo; + +public interface FbStationService { + + DataSourceResult getQgcOverviewSecond(DataSourceRequest dataSourceRequest); +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/impl/FbStationServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/impl/FbStationServiceImpl.java new file mode 100644 index 00000000..ee43e15e --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/impl/FbStationServiceImpl.java @@ -0,0 +1,284 @@ +package com.yfd.platform.qgc_env.fb.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.yfd.platform.common.DataSourceLoadOptionsBase; +import com.yfd.platform.common.DataSourceRequest; +import com.yfd.platform.common.DataSourceResult; +import com.yfd.platform.common.MicroservicDynamicSQLMapper; +import com.yfd.platform.qgc_env.fb.entity.vo.FbStationOverviewSecondVo; +import com.yfd.platform.qgc_env.fb.service.FbStationService; +import com.yfd.platform.utils.QgcQueryWrapperUtil; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Service +public class FbStationServiceImpl implements FbStationService { + + @Resource + private MicroservicDynamicSQLMapper microservicDynamicSQLMapper; + + @Override + public DataSourceResult getQgcOverviewSecond(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + String year = loadOptions == null ? null : QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "year"); + String baseId = loadOptions == null ? null : QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "baseId"); + String hbrvcd = loadOptions == null ? null : QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "hbrvcd"); + String stnm = loadOptions == null ? null : QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "stnm"); + List stcdList = resolveStcdList(dataSourceRequest, loadOptions); + + Map paramMap = new HashMap<>(); + String sql = buildQgcOverviewSecondSql(year, baseId, hbrvcd, stnm, stcdList, paramMap); + List list = microservicDynamicSQLMapper.pageAllListWithResultType( + null, sql, paramMap, FbStationOverviewSecondVo.class + ); + + DataSourceResult result = new DataSourceResult<>(); + result.setData(list); + result.setTotal(list.size()); + result.setAggregates(new HashMap<>()); + return result; + } + + private String buildQgcOverviewSecondSql(String year, + String baseId, + String hbrvcd, + String stnm, + List stcdList, + Map paramMap) { + StringBuilder sql = new StringBuilder(); + sql.append("SELECT fb.STCD AS stcd, ") + .append("fb.STNM AS stnm, ") + .append("eng.ENNM AS ennm, ") + .append("fb.INV AS totalInv, ") + .append("t.YEAR AS year, ") + .append("MAX(t.planFtp) AS planFtp, ") + .append("SUM(t.fcntjh) AS fcntjh, ") + .append("MAX(t.realftp) AS realftp, ") + .append("MAX(t.realfcnt) AS realfcntStr ") + .append("FROM SD_FBRD_B_H fb ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fb.RSTCD ") + .append(" AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN (") + .append(buildPlanUnionActualSql(year, stcdList, paramMap)) + .append(") t ON fb.STCD = t.rstcd ") + .append("WHERE 1 = 1 "); + + if (StrUtil.isNotBlank(stnm)) { + paramMap.put("stnm", "%" + stnm.trim() + "%"); + sql.append("AND fb.STNM LIKE #{map.stnm} "); + } + if (StrUtil.isNotBlank(baseId)) { + paramMap.put("baseId", baseId.trim()); + sql.append("AND fb.BASE_ID = #{map.baseId} "); + } + if (StrUtil.isNotBlank(hbrvcd)) { + paramMap.put("hbrvcd", hbrvcd.trim()); + sql.append("AND fb.HBRVCD = #{map.hbrvcd} "); + } + appendLikeAnyCondition(sql, paramMap, "NVL(fb.RENGCD, fb.RSTCD)", stcdList, "stationFilter"); + + sql.append("GROUP BY fb.STCD, fb.STNM, eng.ENNM, t.YEAR, fb.INV ") + .append("ORDER BY fb.STCD ASC"); + return sql.toString(); + } + + private String buildPlanUnionActualSql(String year, List stcdList, Map paramMap) { + return buildPlanSql(year, stcdList, paramMap) + " UNION ALL " + buildActualSql(year, stcdList, paramMap); + } + + private String buildPlanSql(String year, List stcdList, Map paramMap) { + String fishNameExpr = buildFishNameExpr("det.FTP"); + StringBuilder sql = new StringBuilder(); + sql.append("SELECT plan.RSTCD AS rstcd, ") + .append("fishAgg.NAME AS planFtp, ") + .append("SUM(fishAgg.FCNT) AS fcntjh, ") + .append("CAST(NULL AS VARCHAR2(4000)) AS realftp, ") + .append("CAST(NULL AS VARCHAR2(4000)) AS realfcnt, ") + .append("TO_CHAR(plan.PLANSD, 'YYYY') AS year ") + .append("FROM SD_ENGFRPLAN_B plan ") + .append("LEFT JOIN ( ") + .append(" SELECT det.RPJH_ID, ") + .append(" SUM(det.FCNT) AS FCNT, ") + .append(" LISTAGG(TO_CHAR(").append(fishNameExpr).append("), ', ') ") + .append(" WITHIN GROUP (ORDER BY ").append(fishNameExpr).append(") AS NAME ") + .append(" FROM SD_ENGFRPLANDET_B det ") + .append(" INNER JOIN SD_ENGFRPLAN_B planInner ON det.RPJH_ID = planInner.ID ") + .append(" INNER JOIN SD_FBRD_B_H fbPlan ON fbPlan.STCD = planInner.RSTCD ") + .append(buildFishJoinSql("det.FTP", "fbPlan.HBRVCD")) + .append(" WHERE NVL(det.IS_DELETED, 0) = 0 ") + .append(" AND det.FTP IS NOT NULL ") + .append(" GROUP BY det.RPJH_ID ") + .append(") fishAgg ON plan.ID = fishAgg.RPJH_ID ") + .append("WHERE NVL(plan.IS_DELETED, 0) = 0 "); + + if (StrUtil.isNotBlank(year)) { + paramMap.put("planYear", year.trim()); + sql.append("AND TO_CHAR(plan.PLANSD, 'YYYY') = #{map.planYear} "); + } + appendInCondition(sql, paramMap, "plan.STCD", stcdList, "planStcd"); + + sql.append("GROUP BY plan.RSTCD, fishAgg.NAME, TO_CHAR(plan.PLANSD, 'YYYY') "); + return sql.toString(); + } + + private String buildActualSql(String year, List stcdList, Map paramMap) { + String fishNameExpr = buildFishNameExpr("det.FTP"); + StringBuilder sql = new StringBuilder(); + sql.append("SELECT actualFish.RSTCD AS rstcd, ") + .append("CAST(NULL AS VARCHAR2(4000)) AS planFtp, ") + .append("CAST(NULL AS NUMBER(18, 2)) AS fcntjh, ") + .append("LISTAGG(TO_CHAR(actualFish.NAME), ', ') WITHIN GROUP (ORDER BY actualFish.NAME) AS realftp, ") + .append("LISTAGG(TO_CHAR(actualFish.FCNT), ', ') WITHIN GROUP (ORDER BY actualFish.NAME) AS realfcnt, ") + .append("actualFish.YR AS year ") + .append("FROM ( ") + .append(" SELECT run.RSTCD AS RSTCD, ") + .append(" TO_CHAR(run.TM, 'YYYY') AS YR, ") + .append(" ").append(fishNameExpr).append(" AS NAME, ") + .append(" SUM(det.FCNT) AS FCNT ") + .append(" FROM SD_ENGFR_R run ") + .append(" LEFT JOIN SD_RPIMNFISH_R det ON run.ID = det.RPIMN_ID ") + .append(" AND NVL(det.IS_DELETED, 0) = 0 ") + .append(" AND det.FTP IS NOT NULL ") + .append(" INNER JOIN SD_FBRD_B_H fbRun ON fbRun.STCD = run.RSTCD ") + .append(buildFishJoinSql("det.FTP", "fbRun.HBRVCD")) + .append(" WHERE NVL(run.IS_DELETED, 0) = 0 "); + + if (StrUtil.isNotBlank(year)) { + paramMap.put("actualYear", year.trim()); + sql.append("AND TO_CHAR(run.TM, 'YYYY') = #{map.actualYear} "); + } + appendInCondition(sql, paramMap, "run.STCD", stcdList, "actualStcd"); + + sql.append(" GROUP BY run.RSTCD, TO_CHAR(run.TM, 'YYYY'), ").append(fishNameExpr).append(" ") + .append(") actualFish ") + .append("GROUP BY actualFish.RSTCD, actualFish.YR "); + return sql.toString(); + } + + private String buildFishJoinSql(String fishFieldExpr, String hbrvcdFieldExpr) { + return " LEFT JOIN SD_FISHDICTORY_RLTN_B relRv ON relRv.FISH_ID = " + fishFieldExpr + + " AND relRv.RVCD = " + hbrvcdFieldExpr + + " AND NVL(relRv.IS_DELETED, 0) = 0 " + + " LEFT JOIN SD_FISHDICTORY_B fishRv ON fishRv.ID = NVL(relRv.ZY_FISH_ID, relRv.FISH_ID) " + + " AND NVL(fishRv.IS_DELETED, 0) = 0 " + + " AND NVL(fishRv.ENABLE, 1) = 1 " + + " LEFT JOIN SD_FISHDICTORY_RLTN_B relZy ON relZy.FISH_ID = " + fishFieldExpr + + " AND relZy.RVCD = 'ZY' " + + " AND NVL(relZy.IS_DELETED, 0) = 0 " + + " LEFT JOIN SD_FISHDICTORY_B fishZy ON fishZy.ID = NVL(relZy.ZY_FISH_ID, relZy.FISH_ID) " + + " AND NVL(fishZy.IS_DELETED, 0) = 0 " + + " AND NVL(fishZy.ENABLE, 1) = 1 " + + " LEFT JOIN SD_FISHDICTORY_B fishDirect ON fishDirect.ID = " + fishFieldExpr + + " AND NVL(fishDirect.IS_DELETED, 0) = 0 " + + " AND NVL(fishDirect.ENABLE, 1) = 1 "; + } + + private String buildFishNameExpr(String fishFieldExpr) { + return "COALESCE(fishRv.NAME, relRv.FISH_NAME, fishZy.NAME, relZy.FISH_NAME, fishDirect.NAME, " + fishFieldExpr + ")"; + } + + private void appendInCondition(StringBuilder sql, + Map paramMap, + String column, + List values, + String keyPrefix) { + if (CollUtil.isEmpty(values)) { + return; + } + List placeholders = new ArrayList<>(); + for (int i = 0; i < values.size(); i++) { + String key = keyPrefix + i; + paramMap.put(key, values.get(i)); + placeholders.add("#{map." + key + "}"); + } + sql.append("AND ").append(column).append(" IN (").append(String.join(", ", placeholders)).append(") "); + } + + private void appendLikeAnyCondition(StringBuilder sql, + Map paramMap, + String column, + List values, + String keyPrefix) { + if (CollUtil.isEmpty(values)) { + return; + } + List conditions = new ArrayList<>(); + for (int i = 0; i < values.size(); i++) { + String key = keyPrefix + i; + paramMap.put(key, "%" + values.get(i) + "%"); + conditions.add(column + " LIKE #{map." + key + "}"); + } + if (!conditions.isEmpty()) { + sql.append("AND (").append(String.join(" OR ", conditions)).append(") "); + } + } + + private List resolveStcdList(DataSourceRequest dataSourceRequest, DataSourceLoadOptionsBase loadOptions) { + Set values = new LinkedHashSet<>(); + String stcd = loadOptions == null ? null : QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "stcd"); + addFilterValue(values, stcd); + collectFilterValues(dataSourceRequest == null ? null : dataSourceRequest.getFilter(), "stcd", values); + return new ArrayList<>(values); + } + + private void collectFilterValues(DataSourceRequest.FilterDescriptor filter, String field, Set values) { + if (filter == null) { + return; + } + if (StrUtil.isNotBlank(filter.getField())) { + if (field.equalsIgnoreCase(filter.getField())) { + addFilterValue(values, filter.getValue()); + } + return; + } + if (CollUtil.isEmpty(filter.getFilters())) { + return; + } + for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) { + collectFilterValues(child, field, values); + } + } + + private void addFilterValue(Set values, Object value) { + if (value == null) { + return; + } + if (value instanceof List list) { + for (Object item : list) { + addFilterValue(values, item); + } + return; + } + if (value instanceof Object[] array) { + for (Object item : array) { + addFilterValue(values, item); + } + return; + } + String text = String.valueOf(value).trim() + .replace("[", "") + .replace("]", "") + .replace("\"", ""); + if (StrUtil.isBlank(text)) { + return; + } + if (text.contains(",")) { + for (String item : text.split(",")) { + String trimmed = StrUtil.trim(item); + if (StrUtil.isNotBlank(trimmed)) { + values.add(trimmed); + } + } + return; + } + values.add(text); + } +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/SdWtMonitorServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/SdWtMonitorServiceImpl.java index d737184a..0ed6baea 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/SdWtMonitorServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/SdWtMonitorServiceImpl.java @@ -700,8 +700,10 @@ public class SdWtMonitorServiceImpl implements SdWtMonitorService { .append("eng.DVTP AS dvtp, ") .append("CASE WHEN NVL(dw.DTIN, 0) = 1 THEN '已接入' ELSE '未接入' END AS dtinName, ") .append("CASE ") - .append("WHEN dw.BLDSTT_CODE IN ('1', '10', '11') THEN '已建' ") - .append("WHEN dw.BLDSTT_CODE IN ('2', '7', '8') THEN '在建' ") + .append("WHEN dw.BLDSTT_CODE = 2 THEN '已建' ") + .append("WHEN dw.BLDSTT_CODE = 1 THEN '在建' ") +// .append("WHEN dw.BLDSTT_CODE IN ('1', '10', '11') THEN '已建' ") +// .append("WHEN dw.BLDSTT_CODE IN ('2', '7', '8') THEN '在建' ") .append("ELSE '未建/规划' END AS bldsttCcodeName, ") .append("dw.BLDSTT_CODE AS bldsttCcode, ") .append("eng.HBRVCD AS hbrvcd ") @@ -733,8 +735,10 @@ public class SdWtMonitorServiceImpl implements SdWtMonitorService { .append("wt.STCD AS stcd, ") .append("wt.RSTCD AS rstcd, ") .append("CASE ") - .append("WHEN wt.BLDSTT_CODE IN ('1', '10', '11') THEN '已建' ") - .append("WHEN wt.BLDSTT_CODE IN ('2', '7', '8') THEN '在建' ") + .append("WHEN wt.BLDSTT_CODE = 2 THEN '已建' ") + .append("WHEN wt.BLDSTT_CODE = 1 THEN '在建' ") +// .append("WHEN wt.BLDSTT_CODE IN ('1', '10', '11') THEN '已建' ") +// .append("WHEN wt.BLDSTT_CODE IN ('2', '7', '8') THEN '在建' ") .append("ELSE '未建/规划' END AS bldsttCcodeName, ") .append("wt.BLDSTT_CODE AS bldsttCcode, ") .append("NULL AS stCode, ")