diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/zq/controller/ZqMonitorController.java b/backend/src/main/java/com/yfd/platform/qgc_env/zq/controller/ZqMonitorController.java index c38ec14b..534b6b8b 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/zq/controller/ZqMonitorController.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/zq/controller/ZqMonitorController.java @@ -29,6 +29,12 @@ public class ZqMonitorController { return ResponseResult.successData(zqMonitorService.getMsstbprptList(dataSourceRequest)); } + @PostMapping("/river/GetKendoListCust") + @Operation(summary = "查询流量站实时数据") + public ResponseResult getRiverKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(zqMonitorService.getRiverKendoListCust(dataSourceRequest)); + } + @GetMapping("/msstbprpt/getStcdInfo") @Operation(summary = "根据站码查询单条水文站基础数据") public ResponseResult getStcdInfo(@RequestParam String stcd) { diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/zq/entity/vo/ZqRiverDataVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/zq/entity/vo/ZqRiverDataVo.java new file mode 100644 index 00000000..56c59541 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/zq/entity/vo/ZqRiverDataVo.java @@ -0,0 +1,87 @@ +package com.yfd.platform.qgc_env.zq.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +@Data +@Schema(description = "流量站实时数据") +public class ZqRiverDataVo { + + @Schema(description = "流量") + private BigDecimal q; + + @Schema(description = "站码") + private String stcd; + + @Schema(description = "站名") + private String stnm; + + @Schema(description = "流速") + private BigDecimal v; + + @Schema(description = "所属电站名称") + private String ennm; + + @Schema(description = "时间") + private Date tm; + + @Schema(description = "水位") + private BigDecimal z; + + @Schema(description = "基地编码") + private String baseId; + + @Schema(description = "基地名称") + private String baseName; + + @Schema(description = "站址") + private String stlc; + + @Schema(description = "所属电站编码") + private String rstcd; + + @Schema(description = "流域编码") + private String rvcd; + + @Schema(description = "流域名称") + private String rvcdName; + + @Schema(description = "基地流域编码") + private String hbrvcd; + + @Schema(description = "基地流域名称") + private String hbrvcdName; + + @Schema(description = "建设状态分类") + private Integer bldsttCcode; + + @Schema(description = "视频站编码聚合") + private String vdid; + + @Schema(description = "水位视频名称") + private String rzVideo; + + @Schema(description = "流速视频名称") + private String speedVideo; + + @Schema(description = "水位视频路径") + private String rzVideoPath; + + @Schema(description = "流速视频路径") + private String speedVideoPath; + + @Schema(description = "基地排序") + private Integer baseStepSort; + + @Schema(description = "流域排序") + private Integer rvcdStepSort; + + @Schema(description = "电站排序") + private Integer rstcdStepSort; + + @Schema(description = "站点排序") + private Integer siteStepSort; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/zq/service/ZqMonitorService.java b/backend/src/main/java/com/yfd/platform/qgc_env/zq/service/ZqMonitorService.java index fd576538..1eff40a1 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/zq/service/ZqMonitorService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/zq/service/ZqMonitorService.java @@ -3,10 +3,13 @@ package com.yfd.platform.qgc_env.zq.service; import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.common.DataSourceResult; import com.yfd.platform.qgc_env.zq.entity.vo.ZqBaseInfoVo; +import com.yfd.platform.qgc_env.zq.entity.vo.ZqRiverDataVo; public interface ZqMonitorService { DataSourceResult getMsstbprptList(DataSourceRequest dataSourceRequest); + DataSourceResult getRiverKendoListCust(DataSourceRequest dataSourceRequest); + ZqBaseInfoVo getStcdInfo(String stcd); } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/zq/service/impl/ZqMonitorServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/zq/service/impl/ZqMonitorServiceImpl.java index b8704f59..21e5cd7e 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/zq/service/impl/ZqMonitorServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/zq/service/impl/ZqMonitorServiceImpl.java @@ -6,15 +6,20 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.yfd.platform.common.DataSourceLoadOptionsBase; import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.common.DataSourceResult; +import com.yfd.platform.common.GroupHelper; +import com.yfd.platform.common.GroupingInfo; import com.yfd.platform.common.MicroservicDynamicSQLMapper; import com.yfd.platform.common.exception.BizException; +import com.yfd.platform.qgc_env.fh.entity.vo.HabitatVo; import com.yfd.platform.qgc_env.zq.entity.vo.ZqBaseInfoVo; +import com.yfd.platform.qgc_env.zq.entity.vo.ZqRiverDataVo; import com.yfd.platform.qgc_env.zq.service.ZqMonitorService; import com.yfd.platform.utils.QgcQueryWrapperUtil; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedHashMap; import java.util.HashMap; import java.util.List; @@ -101,6 +106,15 @@ public class ZqMonitorServiceImpl implements ZqMonitorService { return result; } + @Override + public DataSourceResult getRiverKendoListCust(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + if (CollUtil.isEmpty(dataSourceRequest == null ? null : dataSourceRequest.getGroup())) { + return queryRiverDetailList(dataSourceRequest, loadOptions); + } + return queryRiverGroupList(dataSourceRequest, loadOptions); + } + @Override public ZqBaseInfoVo getStcdInfo(String stcd) { if (StrUtil.isBlank(stcd)) { @@ -176,6 +190,472 @@ public class ZqMonitorServiceImpl implements ZqMonitorService { return list.get(0); } + private DataSourceResult queryRiverDetailList(DataSourceRequest dataSourceRequest, + DataSourceLoadOptionsBase loadOptions) { + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append(buildRiverDetailSelectSql(dataSourceRequest == null ? null : dataSourceRequest.getSelect())) + .append(" FROM (") + .append(buildRiverCoreSql()) + .append(") t WHERE 1 = 1 "); + + Map paramMap = new HashMap<>(); + String filterSql = buildRiverFilterCondition(dataSourceRequest == null ? null : dataSourceRequest.getFilter(), paramMap, new int[]{0}); + if (StrUtil.isNotBlank(filterSql)) { + sql.append(" AND ").append(filterSql).append(" "); + } + sql.append(buildRiverOrderBySql(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, ZqRiverDataVo.class); + DataSourceResult result = new DataSourceResult<>(); + result.setData(list); + result.setTotal(page != null ? page.getTotal() : list.size()); + result.setAggregates(new HashMap<>()); + return result; + } + + private DataSourceResult queryRiverGroupList(DataSourceRequest dataSourceRequest, + DataSourceLoadOptionsBase loadOptions) { + List groups = dataSourceRequest.getGroup(); + GroupingInfo[] groupInfos = loadOptions == null ? new GroupingInfo[0] : loadOptions.getGroup(); + + StringBuilder sql = new StringBuilder("SELECT "); + List selectItems = new ArrayList<>(); + for (DataSourceRequest.GroupDescriptor descriptor : groups) { + if (descriptor == null || StrUtil.isBlank(descriptor.getField())) { + continue; + } + String column = mapRiverColumn(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 = mapRiverColumn(aggregate.getField()); + if (StrUtil.isBlank(aggregateColumn) || StrUtil.isBlank(aggregate.getAggregate())) { + continue; + } + selectItems.add(buildRiverAggregateSql(aggregate.getAggregate(), aggregateColumn, aggregate.getField())); + } + } + } + if (selectItems.isEmpty()) { + selectItems.add("t.STCD AS STCD"); + selectItems.add("COUNT(*) AS COUNT_STCD"); + } + sql.append(String.join(", ", selectItems)) + .append(" FROM (") + .append(buildRiverCoreSql()) + .append(") t WHERE 1 = 1 "); + + Map paramMap = new HashMap<>(); + String filterSql = buildRiverFilterCondition(dataSourceRequest == null ? null : dataSourceRequest.getFilter(), paramMap, new int[]{0}); + 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 = mapRiverColumn(descriptor.getField()); + if (StrUtil.isNotBlank(column)) { + groupByColumns.add(column); + } + } + if (!groupByColumns.isEmpty()) { + sql.append(" GROUP BY ").append(String.join(", ", groupByColumns)).append(" "); + } + sql.append(buildRiverGroupOrderBySql(groups)); + + List> rows = microservicDynamicSQLMapper.pageAllList(null, sql.toString(), paramMap); + DataSourceResult result = new DataSourceResult(); + if (dataSourceRequest.getGroupResultFlat() != null && 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; + } + + private String buildRiverCoreSql() { + return "SELECT " + + "rr.Q AS q, " + + "rr.STCD AS stcd, " + + "rb.STNM AS stnm, " + + "rr.V AS v, " + + "eng.ENNM AS ennm, " + + "rr.TM AS tm, " + + "rr.Z AS z, " + + "eng.BASE_ID AS baseId, " + + "hb.BASENAME AS baseName, " + + "rb.STLC AS stlc, " + + "rb.RSTCD AS rstcd, " + + "eng.RVCD AS rvcd, " + + "rv.RVNM AS rvcdName, " + + "eng.HBRVCD AS hbrvcd, " + + "hbrv.HBRVNM AS hbrvcdName, " + + "rb.BLDSTT_CODE AS bldsttCcode, " + + "LISTAGG(vdb.STCD, ',') WITHIN GROUP(ORDER BY vdb.STCD) AS vdid, " + + "CASE " + + " WHEN INSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), ',') > 0 " + + " THEN CASE WHEN INSTR(SUBSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), INSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), ',') + 1), '水位') > 0 " + + " THEN SUBSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), INSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), ',') + 1) " + + " ELSE SUBSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), 1, INSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), ',') - 1) END " + + " ELSE CASE WHEN INSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), '水位') > 0 THEN LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD) END " + + "END AS rzVideo, " + + "CASE " + + " WHEN INSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), ',') > 0 " + + " THEN CASE WHEN INSTR(SUBSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), INSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), ',') + 1), '流速') > 0 " + + " THEN SUBSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), INSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), ',') + 1) " + + " ELSE SUBSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), 1, INSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), ',') - 1) END " + + " ELSE CASE WHEN INSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), '流速') > 0 THEN LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD) END " + + "END AS speedVideo, " + + "CASE " + + " WHEN INSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), ',') > 0 " + + " THEN CASE WHEN INSTR(SUBSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), INSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), ',') + 1), '水位') > 0 " + + " THEN SUBSTR(LISTAGG(vdr.FLPTH, ',') WITHIN GROUP(ORDER BY vdb.STCD), INSTR(LISTAGG(vdr.FLPTH, ',') WITHIN GROUP(ORDER BY vdb.STCD), ',') + 1) " + + " ELSE SUBSTR(LISTAGG(vdr.FLPTH, ',') WITHIN GROUP(ORDER BY vdb.STCD), 1, INSTR(LISTAGG(vdr.FLPTH, ',') WITHIN GROUP(ORDER BY vdb.STCD), ',') - 1) END " + + " ELSE CASE WHEN INSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), '水位') > 0 THEN LISTAGG(vdr.FLPTH, ',') WITHIN GROUP(ORDER BY vdb.STCD) END " + + "END AS rzVideoPath, " + + "CASE " + + " WHEN INSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), ',') > 0 " + + " THEN CASE WHEN INSTR(SUBSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), INSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), ',') + 1), '流速') > 0 " + + " THEN SUBSTR(LISTAGG(vdr.FLPTH, ',') WITHIN GROUP(ORDER BY vdb.STCD), INSTR(LISTAGG(vdr.FLPTH, ',') WITHIN GROUP(ORDER BY vdb.STCD), ',') + 1) " + + " ELSE SUBSTR(LISTAGG(vdr.FLPTH, ',') WITHIN GROUP(ORDER BY vdb.STCD), 1, INSTR(LISTAGG(vdr.FLPTH, ',') WITHIN GROUP(ORDER BY vdb.STCD), ',') - 1) END " + + " ELSE CASE WHEN INSTR(LISTAGG(vdr.FLNM, ',') WITHIN GROUP(ORDER BY vdb.STCD), '流速') > 0 THEN LISTAGG(vdr.FLPTH, ',') WITHIN GROUP(ORDER BY vdb.STCD) END " + + "END AS speedVideoPath, " + + "NVL(hb.ORDER_INDEX, 999999) AS baseStepSort, " + + "NVL(along.ORDER_INDEX, 999999) AS rvcdStepSort, " + + "NVL(rstSort.SORT, 999999) AS rstcdStepSort, " + + "NVL(siteSort.SORT, 999999) AS siteStepSort " + + "FROM SD_RIVER_R rr " + + "INNER JOIN SD_RIVER_B_H rb ON rb.STCD = rr.STCD AND rb.STTP = 'ZQ' AND NVL(rb.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = rb.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = eng.BASE_ID AND NVL(hb.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = eng.HBRVCD AND hbrv.BASEID = eng.BASE_ID " + + " AND NVL(hbrv.IS_DELETED, 0) = 0 AND NVL(hbrv.ENABLED, 1) = 1 " + + "LEFT JOIN SD_RVCD_DIC rv ON rv.RVCD = eng.RVCD " + + "LEFT JOIN MS_ALONG_B along ON along.RVCD = eng.HBRVCD AND along.CODE = 'common' AND NVL(along.IS_DELETED, 0) = 0 " + + "LEFT JOIN ( " + + " SELECT det.SORT, cfg.RVCD, det.STCD " + + " FROM MS_ALONGDET_B det " + + " INNER JOIN MS_ALONG_B cfg ON det.ALONG_ID = cfg.ID " + + " WHERE NVL(det.IS_DELETED, 0) = 0 AND NVL(cfg.IS_DELETED, 0) = 0 AND cfg.CODE = 'common' " + + ") rstSort ON rstSort.RVCD = eng.HBRVCD AND rstSort.STCD = rb.RSTCD " + + "LEFT JOIN ( " + + " SELECT det.SORT, cfg.RVCD, det.STCD " + + " FROM MS_ALONGDET_B det " + + " INNER JOIN MS_ALONG_B cfg ON det.ALONG_ID = cfg.ID " + + " WHERE NVL(det.IS_DELETED, 0) = 0 AND NVL(cfg.IS_DELETED, 0) = 0 AND cfg.CODE = 'common' " + + ") siteSort ON siteSort.RVCD = eng.HBRVCD AND siteSort.STCD = rb.STCD " + + "LEFT JOIN SD_VDINFO_B vdb ON vdb.CSTCD = rr.STCD AND NVL(vdb.USFL, 1) = 1 " + + "LEFT JOIN SD_VDINFO_R vdr ON vdr.STCD = vdb.STCD AND vdr.TM = rr.TM AND NVL(vdr.IS_DELETED, 0) = 0 " + + "WHERE NVL(rr.IS_DELETED, 0) = 0 " + + "GROUP BY rr.Q, rr.STCD, rb.STNM, rr.V, eng.ENNM, rr.TM, rr.Z, eng.BASE_ID, hb.BASENAME, rb.STLC, rb.RSTCD, " + + "eng.RVCD, rv.RVNM, eng.HBRVCD, hbrv.HBRVNM, rb.BLDSTT_CODE, hb.ORDER_INDEX, along.ORDER_INDEX, rstSort.SORT, siteSort.SORT"; + } + + private String buildRiverFilterCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + if (filter == null) { + return ""; + } + if (StrUtil.isNotBlank(filter.getField())) { + return buildRiverLeafCondition(filter, paramMap, indexHolder); + } + if (CollUtil.isEmpty(filter.getFilters())) { + return ""; + } + List conditions = new ArrayList<>(); + for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) { + String childSql = buildRiverFilterCondition(child, paramMap, indexHolder); + if (StrUtil.isNotBlank(childSql)) { + conditions.add("(" + childSql + ")"); + } + } + if (conditions.isEmpty()) { + return ""; + } + String logic = "or".equalsIgnoreCase(filter.getLogic()) ? " OR " : " AND "; + return String.join(logic, conditions); + } + + private String buildRiverLeafCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + String field = filter.getField(); + String operator = StrUtil.blankToDefault(filter.getOperator(), "eq").toLowerCase(); + Object value = filter.getValue(); + if ("vdid".equalsIgnoreCase(field)) { + return buildRiverVdidCondition(operator, value, paramMap, indexHolder); + } + + String column = mapRiverColumn(field); + if (StrUtil.isBlank(column)) { + return ""; + } + if ("isnull".equals(operator)) { + return column + " IS NULL"; + } + if ("isnotnull".equals(operator)) { + return column + " IS NOT NULL"; + } + boolean dateField = "tm".equalsIgnoreCase(field); + if ("in".equals(operator)) { + List values = normalizeRiverValues(value); + if (values.isEmpty()) { + return ""; + } + List placeholders = new ArrayList<>(); + for (Object item : values) { + String key = "zqRiverP" + indexHolder[0]++; + paramMap.put(key, item); + placeholders.add(buildRiverValueExpr(key, dateField, item)); + } + return column + " IN (" + String.join(", ", placeholders) + ")"; + } + if (value == null) { + return ""; + } + + String key = "zqRiverP" + indexHolder[0]++; + String valueExpr = buildRiverValueExpr(key, dateField, value); + return switch (operator) { + case "eq" -> { + paramMap.put(key, value); + yield column + " = " + valueExpr; + } + case "neq" -> { + paramMap.put(key, value); + yield column + " <> " + valueExpr; + } + case "contains" -> { + paramMap.put(key, "%" + value + "%"); + yield column + " LIKE #{map." + key + "}"; + } + case "startswith" -> { + paramMap.put(key, value + "%"); + yield column + " LIKE #{map." + key + "}"; + } + case "endswith" -> { + paramMap.put(key, "%" + value); + yield column + " LIKE #{map." + key + "}"; + } + case "gt" -> { + paramMap.put(key, value); + yield column + " > " + valueExpr; + } + case "gte" -> { + paramMap.put(key, value); + yield column + " >= " + valueExpr; + } + case "lt" -> { + paramMap.put(key, value); + yield column + " < " + valueExpr; + } + case "lte" -> { + paramMap.put(key, value); + yield column + " <= " + valueExpr; + } + default -> ""; + }; + } + + private String buildRiverVdidCondition(String operator, + Object value, + Map paramMap, + int[] indexHolder) { + List values; + if ("in".equals(operator)) { + values = normalizeRiverValues(value); + } else if (value == null) { + return ""; + } else { + values = List.of(value); + } + if (values.isEmpty()) { + return ""; + } + List placeholders = new ArrayList<>(); + for (Object item : values) { + String key = "zqRiverP" + indexHolder[0]++; + paramMap.put(key, item); + placeholders.add("#{map." + key + "}"); + } + if ("neq".equals(operator)) { + return " NOT EXISTS (SELECT 1 FROM SD_VDINFO_B vdb WHERE vdb.CSTCD = t.STCD AND vdb.STCD IN (" + String.join(", ", placeholders) + "))"; + } + return " EXISTS (SELECT 1 FROM SD_VDINFO_B vdb WHERE vdb.CSTCD = t.STCD AND vdb.STCD IN (" + String.join(", ", placeholders) + "))"; + } + + private List normalizeRiverValues(Object value) { + if (value == null) { + return new ArrayList<>(); + } + if (value instanceof List list) { + return new ArrayList<>(list); + } + String text = String.valueOf(value).trim(); + if (StrUtil.isBlank(text)) { + return new ArrayList<>(); + } + if (text.startsWith("[") && text.endsWith("]")) { + text = text.substring(1, text.length() - 1); + } + List values = new ArrayList<>(); + for (String item : text.split(",")) { + String trimmed = StrUtil.trim(item); + if (StrUtil.isNotBlank(trimmed)) { + values.add(StrUtil.removeAll(trimmed, "\"")); + } + } + return values; + } + + private String buildRiverValueExpr(String paramKey, boolean dateField, Object value) { + if (!dateField || value == null) { + return "#{map." + paramKey + "}"; + } + String text = String.valueOf(value).trim(); + if (text.length() <= 10) { + return "TO_DATE(#{map." + paramKey + "}, 'YYYY-MM-DD')"; + } + return "TO_DATE(#{map." + paramKey + "}, 'YYYY-MM-DD HH24:MI:SS')"; + } + + private String mapRiverColumn(String field) { + if (StrUtil.isBlank(field)) { + return null; + } + return switch (field) { + case "q" -> "t.Q"; + case "stcd" -> "t.STCD"; + case "stnm" -> "t.STNM"; + case "v" -> "t.V"; + case "ennm" -> "t.ENNM"; + case "tm" -> "t.TM"; + case "z" -> "t.Z"; + case "baseId" -> "t.BASEID"; + case "baseName" -> "t.BASENAME"; + case "stlc" -> "t.STLC"; + case "rstcd" -> "t.RSTCD"; + case "rvcd" -> "t.RVCD"; + case "rvcdName" -> "t.RVCDNAME"; + case "hbrvcd" -> "t.HBRVCD"; + case "hbrvcdName" -> "t.HBRVCDNAME"; + case "bldsttCcode" -> "t.BLDSTTCCODE"; + case "rzVideo" -> "t.RZVIDEO"; + case "speedVideo" -> "t.SPEEDVIDEO"; + case "baseStepSort" -> "t.BASESTEPSORT"; + case "rvcdStepSort" -> "t.RVCDSTEPSORT"; + case "rstcdStepSort" -> "t.RSTCDSTEPSORT"; + case "siteStepSort" -> "t.SITESTEPSORT"; + default -> null; + }; + } + + private String buildRiverDetailSelectSql(List selectFields) { + Map selectMap = new LinkedHashMap<>(); + selectMap.put("q", "t.Q AS q"); + selectMap.put("stcd", "t.STCD AS stcd"); + selectMap.put("stnm", "t.STNM AS stnm"); + selectMap.put("v", "t.V AS v"); + selectMap.put("ennm", "t.ENNM AS ennm"); + selectMap.put("tm", "t.TM AS tm"); + selectMap.put("z", "t.Z AS z"); + selectMap.put("baseId", "t.BASEID AS baseId"); + selectMap.put("baseName", "t.BASENAME AS baseName"); + selectMap.put("stlc", "t.STLC AS stlc"); + selectMap.put("rstcd", "t.RSTCD AS rstcd"); + selectMap.put("rvcd", "t.RVCD AS rvcd"); + selectMap.put("rvcdName", "t.RVCDNAME AS rvcdName"); + selectMap.put("hbrvcd", "t.HBRVCD AS hbrvcd"); + selectMap.put("hbrvcdName", "t.HBRVCDNAME AS hbrvcdName"); + selectMap.put("bldsttCcode", "t.BLDSTTCCODE AS bldsttCcode"); + selectMap.put("vdid", "t.VDID AS vdid"); + selectMap.put("rzVideo", "t.RZVIDEO AS rzVideo"); + selectMap.put("speedVideo", "t.SPEEDVIDEO AS speedVideo"); + selectMap.put("rzVideoPath", "t.RZVIDEOPATH AS rzVideoPath"); + selectMap.put("speedVideoPath", "t.SPEEDVIDEOPATH AS speedVideoPath"); + selectMap.put("baseStepSort", "t.BASESTEPSORT AS baseStepSort"); + selectMap.put("rvcdStepSort", "t.RVCDSTEPSORT AS rvcdStepSort"); + selectMap.put("rstcdStepSort", "t.RSTCDSTEPSORT AS rstcdStepSort"); + selectMap.put("siteStepSort", "t.SITESTEPSORT AS siteStepSort"); + + if (CollUtil.isEmpty(selectFields)) { + return String.join(", ", selectMap.values()); + } + List actualColumns = new ArrayList<>(); + for (String selectField : selectFields) { + String column = selectMap.get(selectField); + if (StrUtil.isNotBlank(column)) { + actualColumns.add(column); + } + } + if (actualColumns.isEmpty()) { + actualColumns.addAll(selectMap.values()); + } + return String.join(", ", actualColumns); + } + + private String buildRiverOrderBySql(List sortList) { + if (CollUtil.isEmpty(sortList)) { + return " ORDER BY t.BASESTEPSORT ASC, t.RVCDSTEPSORT ASC, t.RSTCDSTEPSORT ASC, t.SITESTEPSORT ASC, t.STCD ASC, t.TM DESC"; + } + List orderColumns = new ArrayList<>(); + for (DataSourceRequest.SortDescriptor sortDescriptor : sortList) { + if (sortDescriptor == null || StrUtil.isBlank(sortDescriptor.getField())) { + continue; + } + String column = mapRiverColumn(sortDescriptor.getField()); + if (StrUtil.isBlank(column)) { + continue; + } + String dir = "desc".equalsIgnoreCase(sortDescriptor.getDir()) || "des".equalsIgnoreCase(sortDescriptor.getDir()) ? "DESC" : "ASC"; + orderColumns.add(column + " " + dir + " NULLS LAST"); + } + if (orderColumns.isEmpty()) { + return " ORDER BY t.BASESTEPSORT ASC, t.RVCDSTEPSORT ASC, t.RSTCDSTEPSORT ASC, t.SITESTEPSORT ASC, t.STCD ASC, t.TM DESC"; + } + return " ORDER BY " + String.join(", ", orderColumns); + } + + private String buildRiverGroupOrderBySql(List groups) { + if (CollUtil.isEmpty(groups)) { + return ""; + } + List orders = new ArrayList<>(); + for (DataSourceRequest.GroupDescriptor descriptor : groups) { + if (descriptor == null || StrUtil.isBlank(descriptor.getField())) { + continue; + } + String column = mapRiverColumn(descriptor.getField()); + if (StrUtil.isBlank(column)) { + continue; + } + String dir = "desc".equalsIgnoreCase(descriptor.getDir()) || "des".equalsIgnoreCase(descriptor.getDir()) ? "DESC" : "ASC"; + orders.add(column + " " + dir); + } + return orders.isEmpty() ? "" : " ORDER BY " + String.join(", ", orders); + } + + private String buildRiverAggregateSql(String aggregate, String column, String field) { + String normalized = aggregate == null ? "" : aggregate.toLowerCase(); + return switch (normalized) { + case "sum", "min", "max", "avg", "count" -> + normalized.toUpperCase() + "(" + column + ") AS " + normalized + "_" + field; + default -> ""; + }; + } + private String buildMsstbprptFilterCondition(DataSourceRequest.FilterDescriptor filter, Map paramMap, int[] indexHolder) {