diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wte/controller/WeFishController.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/controller/WeFishController.java index b9a2ca69..d1e3f90f 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wte/controller/WeFishController.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/controller/WeFishController.java @@ -50,4 +50,10 @@ public class WeFishController { public ResponseResult getQgcFishListStat(@RequestBody DataSourceRequest dataSourceRequest) { return ResponseResult.successData(weFishService.getQgcFishListStat(dataSourceRequest)); } + + @PostMapping("/we/fishPoint/qgc/GetKendoListCust") + @Operation(summary = "环保部-水生生态调查-鱼类分布锚点") + public ResponseResult getQgcWeFishPoint(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(weFishService.getQgcWeFishPoint(dataSourceRequest)); + } } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFishPointQgcVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFishPointQgcVo.java new file mode 100644 index 00000000..5de853ca --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFishPointQgcVo.java @@ -0,0 +1,64 @@ +package com.yfd.platform.qgc_env.wte.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 WeFishPointQgcVo { + + @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 stnm; + + @Schema(description = "电站名称") + private String ennm; + + @Schema(description = "调查鱼类列表") + private String ftp; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wte/service/WeFishService.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/service/WeFishService.java index 20c4baa5..5d68201f 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wte/service/WeFishService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/service/WeFishService.java @@ -3,6 +3,7 @@ package com.yfd.platform.qgc_env.wte.service; import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.common.DataSourceResult; import com.yfd.platform.qgc_env.wte.entity.vo.WeFishListStatQgcVo; +import com.yfd.platform.qgc_env.wte.entity.vo.WeFishPointQgcVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeFishStatQgcVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeFishTQgcVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeStaticsVo; @@ -21,4 +22,6 @@ public interface WeFishService { DataSourceResult getQgcWeFishStatList(DataSourceRequest dataSourceRequest); DataSourceResult getQgcFishListStat(DataSourceRequest dataSourceRequest); + + DataSourceResult getQgcWeFishPoint(DataSourceRequest dataSourceRequest); } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wte/service/impl/WeFishServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/service/impl/WeFishServiceImpl.java index 80ae39d5..b7814813 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wte/service/impl/WeFishServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/service/impl/WeFishServiceImpl.java @@ -11,6 +11,7 @@ import com.yfd.platform.common.GroupHelper; import com.yfd.platform.common.GroupingInfo; import com.yfd.platform.common.MicroservicDynamicSQLMapper; import com.yfd.platform.qgc_env.wte.entity.vo.WeFishListStatQgcVo; +import com.yfd.platform.qgc_env.wte.entity.vo.WeFishPointQgcVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeFishStatQgcVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeFishTQgcVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeRvcdYearVo; @@ -20,14 +21,17 @@ import com.yfd.platform.utils.QgcQueryWrapperUtil; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; @Service public class WeFishServiceImpl implements WeFishService { @@ -230,6 +234,38 @@ public class WeFishServiceImpl implements WeFishService { return result; } + @Override + public DataSourceResult getQgcWeFishPoint(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + String stcd = resolveWeFishStringFilterValue(dataSourceRequest, loadOptions, "stcd"); + String baseId = resolveWeFishStringFilterValue(dataSourceRequest, loadOptions, "baseId"); + String startTime = resolveWeFishStringFilterValue(dataSourceRequest, loadOptions, "startTime"); + String endTime = resolveWeFishStringFilterValue(dataSourceRequest, loadOptions, "endTime"); + List fishList = getWeFishFilterTexts(dataSourceRequest == null ? null : dataSourceRequest.getFilter(), "fishList"); + + Map paramMap = new HashMap<>(); + String sql = buildWeFishPointQgcSql(stcd, baseId, startTime, endTime, fishList, paramMap); + Page page = loadOptions == null ? null + : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + List> rows = microservicDynamicSQLMapper.pageAllList(page, sql, paramMap); + + Map fishNameMap = loadWeFishNameMap(); + List list = new ArrayList<>(); + for (Map row : rows) { + WeFishPointQgcVo vo = buildWeFishPointQgcVo(row, fishNameMap); + if (vo != null) { + list.add(vo); + } + } + applyWeFishPointMapDistance(list); + + DataSourceResult result = new DataSourceResult<>(); + result.setData(list); + result.setTotal(page != null ? page.getTotal() : list.size()); + result.setAggregates(new HashMap<>()); + return result; + } + private String buildWeFishQgcGroupSql(String baseSql, GroupingInfo[] groupInfos) { if (groupInfos == null || groupInfos.length == 0) { return baseSql; @@ -474,6 +510,96 @@ public class WeFishServiceImpl implements WeFishService { "AND NVL(we.STATUS, 1) = 1 "; } + private String buildWeFishPointQgcSql(String stcd, + String baseId, + String startTime, + String endTime, + List fishList, + Map paramMap) { + Date start = null; + Date end = null; + if (StrUtil.isNotBlank(startTime) && StrUtil.isNotBlank(endTime)) { + start = parseDateTimeSafely(startTime); + end = parseDateTimeSafely(endTime); + } + StringBuilder sql = new StringBuilder(); + sql.append("SELECT agg.ftp AS ftp, section.STCD AS stcd, section.RSTCD AS rstcds, ") + .append("section.STNM AS stnm, eng.ENNM AS ennm, ") + .append("section.LGTD AS lgtd, section.LTTD AS lttd, ") + .append("'ylfb' AS sttp, 'ylfb' AS sttpMap, ") + .append("section.RVCD AS rvcd, section.ADDVCD AS addvcd, section.BASE_ID AS baseId, ") + .append("'WE' AS sttpCode, 'ylfb' AS anchoPointState, '鱼类分布' AS titleName, ") + .append("eng.ELEV AS dtmel ") + .append("FROM (") + .append("SELECT LISTAGG(TO_CHAR(t.ID), ',') WITHIN GROUP (ORDER BY t.ID) AS ftp, t.stcd ") + .append("FROM (") + .append("SELECT dict.ZY_FISH_ID AS ID, we.STCD AS stcd ") + .append("FROM SD_WE_R we ") + .append("INNER JOIN SD_WE_B_H section ON we.STCD = section.STCD ") + .append(" AND NVL(section.USFL, 0) = 1 ") + .append("INNER JOIN SD_WEFISH_R fish ON we.ID = fish.WER_ID ") + .append(" AND NVL(fish.IS_DELETED, 0) = 0 ") + .append("INNER JOIN V_SD_FISHDICTORY_B dict ON dict.FISH_ID = fish.FTP ") + .append(" AND (section.HBRVCD = dict.RVCD OR dict.RVCD = 'ZY') ") + .append("WHERE NVL(we.IS_DELETED, 0) = 0 ") + .append("AND NVL(we.STATUS, 1) = 1 "); + + if (StrUtil.isNotBlank(stcd)) { + paramMap.put("weFishPointStcd", stcd); + sql.append("AND we.STCD = #{map.weFishPointStcd} "); + } + if (start != null && end != null) { + paramMap.put("weFishPointStartTime", start); + paramMap.put("weFishPointEndTime", end); + sql.append("AND we.TM BETWEEN #{map.weFishPointStartTime} AND #{map.weFishPointEndTime} "); + } + if (CollUtil.isNotEmpty(fishList)) { + List placeholders = new ArrayList<>(); + int index = 0; + for (String fishId : fishList) { + if (StrUtil.isBlank(fishId)) { + continue; + } + String key = "weFishPointFish" + index++; + paramMap.put(key, fishId); + placeholders.add("#{map." + key + "}"); + } + if (CollUtil.isNotEmpty(placeholders)) { + sql.append("AND we.STCD IN (") + .append("SELECT a.STCD ") + .append("FROM SD_WE_R a ") + .append("INNER JOIN SD_WE_B_H section2 ON a.STCD = section2.STCD ") + .append(" AND NVL(section2.USFL, 0) = 1 ") + .append("INNER JOIN SD_WEFISH_R b ON a.ID = b.WER_ID ") + .append(" AND NVL(b.IS_DELETED, 0) = 0 ") + .append("INNER JOIN V_SD_FISHDICTORY_B c ON c.FISH_ID = b.FTP ") + .append(" AND (section2.HBRVCD = c.RVCD OR c.RVCD = 'ZY') ") + .append("WHERE NVL(a.IS_DELETED, 0) = 0 ") + .append("AND NVL(a.STATUS, 1) = 1 "); + if (start != null && end != null) { + sql.append("AND a.TM BETWEEN #{map.weFishPointStartTime} AND #{map.weFishPointEndTime} "); + } + sql.append("AND c.FISH_ID IN (").append(String.join(", ", placeholders)).append(")") + .append(") "); + } + } + + sql.append("GROUP BY we.STCD, dict.ZY_FISH_ID") + .append(") t GROUP BY t.stcd") + .append(") agg ") + .append("INNER JOIN SD_WE_B_H section ON agg.stcd = section.STCD ") + .append(" AND NVL(section.USFL, 0) = 1 ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = section.RSTCD ") + .append(" AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("WHERE 1 = 1 "); + if (StrUtil.isNotBlank(baseId)) { + paramMap.put("weFishPointBaseId", baseId); + sql.append("AND section.BASE_ID = #{map.weFishPointBaseId} "); + } + sql.append("ORDER BY section.STCD ASC"); + return sql.toString(); + } + private String buildWeFishStaticsSql(String baseId, String hbrvcd, String yr, @@ -997,6 +1123,152 @@ public class WeFishServiceImpl implements WeFishService { .setFcnt(toWeFishLongValue(firstPresentWeFishValue(row, "FCNT", "fcnt"))); } + private WeFishPointQgcVo buildWeFishPointQgcVo(Map row, Map fishNameMap) { + if (row == null || row.isEmpty()) { + return null; + } + return new WeFishPointQgcVo() + .setFtp(resolveWeFishNames(firstPresentWeFishValue(row, "FTP", "ftp"), fishNameMap)) + .setStcd(safeWeFishString(firstPresentWeFishValue(row, "STCD", "stcd"))) + .setRstcds(safeWeFishString(firstPresentWeFishValue(row, "RSTCDS", "rstcds"))) + .setStnm(safeWeFishString(firstPresentWeFishValue(row, "STNM", "stnm"))) + .setEnnm(safeWeFishString(firstPresentWeFishValue(row, "ENNM", "ennm"))) + .setLgtd(toWeFishBigDecimalValue(firstPresentWeFishValue(row, "LGTD", "lgtd"))) + .setLttd(toWeFishBigDecimalValue(firstPresentWeFishValue(row, "LTTD", "lttd"))) + .setSttp(safeWeFishString(firstPresentWeFishValue(row, "STTP", "sttp"))) + .setSttpMap(safeWeFishString(firstPresentWeFishValue(row, "STTPMAP", "sttpMap"))) + .setRvcd(safeWeFishString(firstPresentWeFishValue(row, "RVCD", "rvcd"))) + .setAddvcd(safeWeFishString(firstPresentWeFishValue(row, "ADDVCD", "addvcd"))) + .setBaseId(safeWeFishString(firstPresentWeFishValue(row, "BASEID", "baseId"))) + .setSttpCode(safeWeFishString(firstPresentWeFishValue(row, "STTPCODE", "sttpCode"))) + .setAnchoPointState(safeWeFishString(firstPresentWeFishValue(row, "ANCHOPOINTSTATE", "anchoPointState"))) + .setTitleName(safeWeFishString(firstPresentWeFishValue(row, "TITLENAME", "titleName"))) + .setDtmel(toWeFishBigDecimalValue(firstPresentWeFishValue(row, "DTMEL", "dtmel"))); + } + + private Map loadWeFishNameMap() { + List> rows = microservicDynamicSQLMapper.getAllList( + "SELECT ID AS id, NAME AS name FROM SD_FISHDICTORY_B WHERE NVL(IS_DELETED, 0) = 0", + new HashMap<>() + ); + Map fishNameMap = new LinkedHashMap<>(); + for (Map row : rows) { + String id = safeWeFishString(firstPresentWeFishValue(row, "ID", "id")); + String name = safeWeFishString(firstPresentWeFishValue(row, "NAME", "name")); + if (StrUtil.isNotBlank(id) && StrUtil.isNotBlank(name)) { + fishNameMap.put(id, name); + } + } + return fishNameMap; + } + + private String resolveWeFishNames(Object ftpValue, Map fishNameMap) { + String ftp = safeWeFishString(ftpValue); + if (StrUtil.isBlank(ftp)) { + return ""; + } + String[] ids = ftp.split(","); + List names = new ArrayList<>(); + for (String id : ids) { + String trimId = StrUtil.trim(id); + if (StrUtil.isBlank(trimId)) { + continue; + } + String name = fishNameMap.get(trimId); + if (StrUtil.isNotBlank(name)) { + names.add(name); + } + } + return names.isEmpty() ? "" : String.join(",", names); + } + + private void applyWeFishPointMapDistance(List points) { + if (CollUtil.isEmpty(points)) { + return; + } + int defaultLevel = 50000000; + int level1 = 1500000; + double level1Distance = 1.2D; + int level2 = 800000; + double level2Distance = 0.8D; + int level3 = 400000; + double level3Distance = 0.4D; + int level4 = 50000; + double level4Distance = 0.1D; + + Set marked = new HashSet<>(); + for (int i = 0; i < points.size(); i++) { + WeFishPointQgcVo current = points.get(i); + String category = current.getAnchoPointState(); + String currentKey = StrUtil.nullToEmpty(current.getStcd()) + StrUtil.nullToEmpty(category); + if (marked.contains(currentKey)) { + continue; + } + current.setDistance(defaultLevel); + BigDecimal x1 = current.getLgtd(); + BigDecimal y1 = current.getLttd(); + if (x1 == null || y1 == null) { + continue; + } + for (int j = i + 1; j < points.size(); j++) { + WeFishPointQgcVo target = points.get(j); + String targetCategory = target.getAnchoPointState(); + String targetKey = StrUtil.nullToEmpty(target.getStcd()) + StrUtil.nullToEmpty(targetCategory); + if (marked.contains(targetKey)) { + continue; + } + BigDecimal x2 = target.getLgtd(); + BigDecimal y2 = target.getLttd(); + if (x2 == null || y2 == null || currentKey.equals(targetKey)) { + continue; + } + double dx = Math.abs(x1.doubleValue() - x2.doubleValue()); + double dy = Math.abs(y1.doubleValue() - y2.doubleValue()); + double distance = Math.sqrt(dx * dx + dy * dy); + if (distance < level4Distance) { + target.setDistance(level4); + marked.add(targetKey); + } else if (distance < level3Distance) { + target.setDistance(level3); + marked.add(targetKey); + } else if (distance < level2Distance) { + target.setDistance(level2); + marked.add(targetKey); + } else if (distance < level1Distance) { + target.setDistance(level1); + marked.add(targetKey); + } + } + } + } + + private java.math.BigDecimal toWeFishBigDecimalValue(Object value) { + if (value == null) { + return null; + } + if (value instanceof java.math.BigDecimal decimal) { + return decimal; + } + if (value instanceof Number number) { + return java.math.BigDecimal.valueOf(number.doubleValue()); + } + try { + return new java.math.BigDecimal(String.valueOf(value).trim()); + } catch (Exception ex) { + return null; + } + } + + private String resolveWeFishStringFilterValue(DataSourceRequest dataSourceRequest, + DataSourceLoadOptionsBase loadOptions, + String field) { + String value = getFirstWeFishFilterText(dataSourceRequest == null ? null : dataSourceRequest.getFilter(), field); + if (StrUtil.isBlank(value) && loadOptions != null) { + value = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, field); + } + return StrUtil.trim(value); + } + private Date toDateValue(Object value) { if (value == null) { return null;