diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/vap/controller/VpConstructionController.java b/backend/src/main/java/com/yfd/platform/qgc_env/vap/controller/VapConstructionController.java similarity index 86% rename from backend/src/main/java/com/yfd/platform/qgc_env/vap/controller/VpConstructionController.java rename to backend/src/main/java/com/yfd/platform/qgc_env/vap/controller/VapConstructionController.java index e9f4b4f3..65bc8883 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/vap/controller/VpConstructionController.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/vap/controller/VapConstructionController.java @@ -18,7 +18,7 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping("/vap") @Tag(name = "珍稀植物园建设及接入情况") @Validated -public class VpConstructionController { +public class VapConstructionController { @Resource private VpConstructionService vpConstructionService; @@ -46,4 +46,10 @@ public class VpConstructionController { public ResponseResult basinVpIntDetail(@RequestBody DataSourceRequest dataSourceRequest) { return ResponseResult.successData(vpConstructionService.basinVpIntDetail(dataSourceRequest)); } + + @PostMapping("/wva/GetKendoListCust") + @Operation(summary = "野生动物监测情况") + public ResponseResult getWvaKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(vpConstructionService.processWvaKendoList(dataSourceRequest)); + } } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/vap/entity/vo/VpWvaRunVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/vap/entity/vo/VpWvaRunVo.java new file mode 100644 index 00000000..8858d34c --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/vap/entity/vo/VpWvaRunVo.java @@ -0,0 +1,88 @@ +package com.yfd.platform.qgc_env.vap.entity.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.Date; + +@Data +@Schema(description = "野生动物监测情况") +public class VpWvaRunVo { + + @Schema(description = "站点编码") + private String stcd; + + @Schema(description = "站点名称") + private String stnm; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "时间") + private Date tm; + + @Schema(description = "显示名称") + private String flnm; + + @Schema(description = "图片路径") + private String imgPath; + + @Schema(description = "视频路径") + private String flpth; + + @Schema(description = "附件ID") + private String fid; + + @Schema(description = "备注") + private String description; + + @Schema(description = "平台ID") + private String platformId; + + @Schema(description = "部门ID") + private String departmentId; + + @Schema(description = "是否暂存") + private Long isTempStorage; + + @Schema(description = "站类编码") + private String sttpCode; + + @Schema(description = "站类名称") + private String sttpName; + + @Schema(description = "所属基地编码") + private String baseId; + + @Schema(description = "所属基地名称") + private String baseName; + + @Schema(description = "所属电站编码") + private String rstcd; + + @Schema(description = "所属电站名称") + private String ennm; + + @Schema(description = "所属基地流域编码") + private String hbrvcd; + + @Schema(description = "所属基地流域名称") + private String hbrvcdName; + + @Schema(description = "建设状态编码") + private String bldsttCcode; + + @Schema(description = "建设状态名称") + private String bldsttCcodeName; + + @Schema(description = "动物类型") + private String tetp; + + @Schema(description = "救助数量") + private Integer tecnt; + + @Schema(description = "放生地点") + private String stlc; + + @Schema(description = "原始照片路径") + private String fpth; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/vap/service/VpConstructionService.java b/backend/src/main/java/com/yfd/platform/qgc_env/vap/service/VpConstructionService.java index 2f073631..5e02dbd8 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/vap/service/VpConstructionService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/vap/service/VpConstructionService.java @@ -4,6 +4,7 @@ import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.common.DataSourceResult; import com.yfd.platform.qgc_env.vap.entity.vo.VpBasinIntDetailVo; import com.yfd.platform.qgc_env.vap.entity.vo.VpStInfoResultVo; +import com.yfd.platform.qgc_env.vap.entity.vo.VpWvaRunVo; public interface VpConstructionService { @@ -14,4 +15,6 @@ public interface VpConstructionService { VpStInfoResultVo getStInfoByStcd(String stcd); DataSourceResult basinVpIntDetail(DataSourceRequest dataSourceRequest); + + DataSourceResult processWvaKendoList(DataSourceRequest dataSourceRequest); } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/vap/service/impl/VpConstructionServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/vap/service/impl/VpConstructionServiceImpl.java index ee55fc10..4b1e1aa7 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/vap/service/impl/VpConstructionServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/vap/service/impl/VpConstructionServiceImpl.java @@ -14,6 +14,7 @@ import com.yfd.platform.qgc_env.vap.entity.vo.VpConstructionSituationVo; import com.yfd.platform.qgc_env.vap.entity.vo.VpStBaseInfoVo; import com.yfd.platform.qgc_env.vap.entity.vo.VpStInfoResultVo; import com.yfd.platform.qgc_env.vap.entity.vo.VpVmsstbprptVo; +import com.yfd.platform.qgc_env.vap.entity.vo.VpWvaRunVo; import com.yfd.platform.qgc_env.vap.service.VpConstructionService; import com.yfd.platform.utils.KendoUtil; import com.yfd.platform.utils.QgcQueryWrapperUtil; @@ -171,6 +172,309 @@ public class VpConstructionServiceImpl implements VpConstructionService { return result; } + @Override + public DataSourceResult processWvaKendoList(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + PageInfo pageInfo = loadOptions == null ? new PageInfo() : QgcQueryWrapperUtil.getPageInfo(loadOptions); + Page page = pageInfo.getHasPageInfo() ? pageInfo.getPage() : null; + + Map paramMap = new HashMap<>(); + StringBuilder sql = new StringBuilder(buildWvaBaseSql()); + String filterSql = buildWvaFilterCondition(dataSourceRequest == null ? null : dataSourceRequest.getFilter(), + paramMap, new int[]{0}); + if (StrUtil.isNotBlank(filterSql)) { + sql.append(" AND ").append(filterSql); + } + + String groupBy = dataSourceRequest == null ? null : KendoUtil.getGroupBy(dataSourceRequest); + GroupingInfo[] groupInfos = loadOptions == null ? null : loadOptions.getGroup(); + if (StrUtil.isNotBlank(groupBy) && groupInfos != null && groupInfos.length > 0) { + String groupedSql = buildWvaGroupSql(sql.toString(), groupInfos); + List> rows = microservicDynamicSQLMapper.pageAllList(null, groupedSql, paramMap); + DataSourceResult result = new DataSourceResult(); + if (Boolean.TRUE.equals(dataSourceRequest.getGroupResultFlat())) { + result.setData(new GroupHelper().faltGroup(rows, Arrays.asList(groupInfos))); + } else { + result.setData(new GroupHelper().group(rows, Arrays.asList(groupInfos))); + } + result.setTotal(0L); + result.setAggregates(new HashMap<>()); + return result; + } + + sql.append(buildWvaOrderBySql(dataSourceRequest == null ? null : dataSourceRequest.getSort())); + List list = microservicDynamicSQLMapper.pageAllListWithResultType( + page, sql.toString(), paramMap, VpWvaRunVo.class + ); + DataSourceResult result = new DataSourceResult<>(); + result.setData(list); + result.setTotal(page != null ? page.getTotal() : list.size()); + result.setAggregates(new HashMap<>()); + return result; + } + + private String buildWvaBaseSql() { + return "SELECT " + + "va.STCD AS stcd, " + + "vb.STNM AS stnm, " + + "va.TM AS tm, " + + "vb.STNM || ' ' || TO_CHAR(va.TM, 'yyyy-MM-dd HH24') AS flnm, " + + "va.FPTH AS imgPath, " + + "va.FPTH AS flpth, " + + "va.FID AS fid, " + + "va.DESCRIPTION AS description, " + + "CAST(NULL AS VARCHAR2(36)) AS platformId, " + + "CAST(NULL AS VARCHAR2(36)) AS departmentId, " + + "CAST(NULL AS NUMBER(1,0)) AS isTempStorage, " + + "vb.STTP AS sttpCode, " + + "sttp.STTP_NAME AS sttpName, " + + "vb.BASE_ID AS baseId, " + + "hb.BASENAME AS baseName, " + + "vb.RSTCD AS rstcd, " + + "eng.ENNM AS ennm, " + + "vb.HBRVCD AS hbrvcd, " + + "hbrv.HBRVNM AS hbrvcdName, " + + "TO_CHAR(vb.BLDSTT_CODE) AS bldsttCcode, " + + "CASE WHEN vb.BLDSTT_CODE IN (1, 10, 11) THEN '已建' " + + "WHEN vb.BLDSTT_CODE IN (2, 7, 8) THEN '在建' ELSE '未建/规划' END AS bldsttCcodeName, " + + "va.TETP AS tetp, " + + "va.TECNT AS tecnt, " + + "va.STLC AS stlc, " + + "va.FPTH AS fpth, " + + "NVL(hb.ORDER_INDEX, 999999) AS baseStepSort, " + + "NVL(hbrv.ORDER_INDEX, 999999) AS rvcdStepSort, " + + "NVL(eng.ORDER_INDEX, 999999) AS rstcdStepSort, " + + "NVL(vb.ORDER_INDEX, 999999) AS siteStepSort " + + "FROM SD_VA_R va " + + "INNER JOIN SD_VA_B_H vb ON vb.STCD = va.STCD AND NVL(vb.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = vb.BASE_ID AND NVL(hb.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = vb.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = vb.HBRVCD " + + "AND (hbrv.BASEID = vb.BASE_ID OR vb.BASE_ID IS NULL) " + + "AND NVL(hbrv.IS_DELETED, 0) = 0 AND NVL(hbrv.ENABLED, 1) = 1 " + + "LEFT JOIN SD_STTP_B sttp ON sttp.STTP_CODE = vb.STTP " + + "AND NVL(sttp.IS_DELETED, 0) = 0 AND NVL(sttp.ENABLE, 1) = 1 " + + "WHERE NVL(va.IS_DELETED, 0) = 0 "; + } + + private String buildWvaFilterCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + if (filter == null) { + return ""; + } + if (StrUtil.isNotBlank(filter.getField())) { + return buildWvaLeafCondition(filter, paramMap, indexHolder); + } + if (CollectionUtils.isEmpty(filter.getFilters())) { + return ""; + } + List conditions = new ArrayList<>(); + for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) { + String childSql = buildWvaFilterCondition(child, paramMap, indexHolder); + if (StrUtil.isNotBlank(childSql)) { + conditions.add("(" + childSql + ")"); + } + } + if (conditions.isEmpty()) { + return ""; + } + return String.join("or".equalsIgnoreCase(filter.getLogic()) ? " OR " : " AND ", conditions); + } + + private String buildWvaLeafCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + String field = filter.getField(); + Object value = filter.getValue(); + String operator = StrUtil.blankToDefault(filter.getOperator(), "eq").toLowerCase(); + + if ("keyword".equals(field)) { + if (value == null || StrUtil.isBlank(String.valueOf(value))) { + return ""; + } + String paramKey = "wvaParam" + indexHolder[0]++; + paramMap.put(paramKey, "%" + value + "%"); + return "(vb.STNM LIKE #{map." + paramKey + "} OR hb.BASENAME LIKE #{map." + paramKey + "} " + + "OR eng.ENNM LIKE #{map." + paramKey + "} OR va.TETP LIKE #{map." + paramKey + "} " + + "OR va.DESCRIPTION LIKE #{map." + paramKey + "})"; + } + + String column = mapWvaColumn(field); + if (StrUtil.isBlank(column)) { + return ""; + } + if ("isnull".equals(operator)) { + return column + " IS NULL"; + } + if ("isnotnull".equals(operator)) { + return column + " IS NOT NULL"; + } + if ("in".equals(operator)) { + List values = normalizeValues(value); + if (values.isEmpty()) { + return ""; + } + List placeholders = new ArrayList<>(); + for (Object item : values) { + String paramKey = "wvaParam" + indexHolder[0]++; + paramMap.put(paramKey, item); + placeholders.add("#{map." + paramKey + "}"); + } + return column + " IN (" + String.join(", ", placeholders) + ")"; + } + if (value == null) { + return ""; + } + + String paramKey = "wvaParam" + indexHolder[0]++; + switch (operator) { + case "eq": + paramMap.put(paramKey, value); + return column + " = #{map." + paramKey + "}"; + case "neq": + paramMap.put(paramKey, value); + return column + " <> #{map." + paramKey + "}"; + case "contains": + paramMap.put(paramKey, "%" + value + "%"); + return column + " LIKE #{map." + paramKey + "}"; + case "startswith": + paramMap.put(paramKey, value + "%"); + return column + " LIKE #{map." + paramKey + "}"; + case "endswith": + paramMap.put(paramKey, "%" + value); + return column + " LIKE #{map." + paramKey + "}"; + case "gt": + paramMap.put(paramKey, value); + return column + " > #{map." + paramKey + "}"; + case "gte": + paramMap.put(paramKey, value); + return column + " >= #{map." + paramKey + "}"; + case "lt": + paramMap.put(paramKey, value); + return column + " < #{map." + paramKey + "}"; + case "lte": + paramMap.put(paramKey, value); + return column + " <= #{map." + paramKey + "}"; + default: + return ""; + } + } + + private String buildWvaGroupSql(String detailSql, GroupingInfo[] groupInfos) { + List groupFields = new ArrayList<>(); + List orderItems = new ArrayList<>(); + StringBuilder sql = new StringBuilder("SELECT "); + boolean first = true; + for (GroupingInfo item : groupInfos) { + if (item == null || StrUtil.isBlank(item.getSelector())) { + continue; + } + String selector = item.getSelector(); + if (!isWvaGroupSupported(selector)) { + continue; + } + if (!first) { + sql.append(", "); + } + sql.append("t.").append(selector).append(" AS ").append(selector) + .append(", COUNT(*) AS count_").append(selector); + groupFields.add("t." + selector); + orderItems.add("t." + selector + (item.getDesc() ? " DESC" : " ASC")); + first = false; + } + if (groupFields.isEmpty()) { + return "SELECT * FROM (" + detailSql + ") t WHERE 1 = 0"; + } + sql.append(" FROM (").append(detailSql).append(") t GROUP BY ") + .append(String.join(", ", groupFields)); + if (!orderItems.isEmpty()) { + sql.append(" ORDER BY ").append(String.join(", ", orderItems)); + } + return sql.toString(); + } + + private boolean isWvaGroupSupported(String selector) { + return "stcd".equals(selector) + || "stnm".equals(selector) + || "sttpCode".equals(selector) + || "sttpName".equals(selector) + || "baseId".equals(selector) + || "baseName".equals(selector) + || "rstcd".equals(selector) + || "ennm".equals(selector) + || "hbrvcd".equals(selector) + || "hbrvcdName".equals(selector) + || "bldsttCcode".equals(selector) + || "bldsttCcodeName".equals(selector) + || "tetp".equals(selector) + || "stlc".equals(selector); + } + + private String mapWvaColumn(String field) { + if (StrUtil.isBlank(field)) { + return null; + } + Map columnMap = new HashMap<>(); + columnMap.put("stcd", "va.STCD"); + columnMap.put("stnm", "vb.STNM"); + columnMap.put("tm", "va.TM"); + columnMap.put("flnm", "vb.STNM || ' ' || TO_CHAR(va.TM, 'yyyy-MM-dd HH24')"); + columnMap.put("imgPath", "va.FPTH"); + columnMap.put("flpth", "va.FPTH"); + columnMap.put("fid", "va.FID"); + columnMap.put("description", "va.DESCRIPTION"); + columnMap.put("sttpCode", "vb.STTP"); + columnMap.put("sttpName", "sttp.STTP_NAME"); + columnMap.put("baseId", "vb.BASE_ID"); + columnMap.put("baseName", "hb.BASENAME"); + columnMap.put("rstcd", "vb.RSTCD"); + columnMap.put("ennm", "eng.ENNM"); + columnMap.put("hbrvcd", "vb.HBRVCD"); + columnMap.put("hbrvcdName", "hbrv.HBRVNM"); + columnMap.put("bldsttCcode", "vb.BLDSTT_CODE"); + columnMap.put("bldsttCcodeName", + "CASE WHEN vb.BLDSTT_CODE IN (1, 10, 11) THEN '已建' WHEN vb.BLDSTT_CODE IN (2, 7, 8) THEN '在建' ELSE '未建/规划' END"); + columnMap.put("tetp", "va.TETP"); + columnMap.put("tecnt", "va.TECNT"); + columnMap.put("stlc", "va.STLC"); + columnMap.put("fpth", "va.FPTH"); + return columnMap.get(field); + } + + private String buildWvaOrderBySql(List sorts) { + if (sorts == null || sorts.isEmpty()) { + return " ORDER BY NVL(hb.ORDER_INDEX, 999999) ASC, NVL(hbrv.ORDER_INDEX, 999999) ASC, " + + "NVL(eng.ORDER_INDEX, 999999) ASC, NVL(vb.ORDER_INDEX, 999999) ASC, va.TM ASC, va.STCD ASC"; + } + List orderItems = new ArrayList<>(); + for (DataSourceRequest.SortDescriptor sort : sorts) { + if (sort == null || StrUtil.isBlank(sort.getField())) { + continue; + } + String column = mapWvaColumn(sort.getField()); + if (StrUtil.isBlank(column)) { + column = switch (sort.getField()) { + case "baseStepSort" -> "hb.ORDER_INDEX"; + case "rvcdStepSort" -> "hbrv.ORDER_INDEX"; + case "rstcdStepSort" -> "eng.ORDER_INDEX"; + case "siteStepSort" -> "vb.ORDER_INDEX"; + default -> null; + }; + } + 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 NVL(hb.ORDER_INDEX, 999999) ASC, NVL(hbrv.ORDER_INDEX, 999999) ASC, " + + "NVL(eng.ORDER_INDEX, 999999) ASC, NVL(vb.ORDER_INDEX, 999999) ASC, va.TM DESC, va.STCD ASC"; + } + return " ORDER BY " + String.join(", ", orderItems); + } + private String buildBaseSql(boolean botanicalGarden, boolean nationwide) { String baseIdExpr = botanicalGarden ? "CASE WHEN vp.BASE_ID IS NULL THEN 'null' ELSE vp.BASE_ID END"