diff --git a/backend/src/main/java/com/yfd/platform/config/SecurityConfig.java b/backend/src/main/java/com/yfd/platform/config/SecurityConfig.java index 58ec8889..c8c7cb72 100644 --- a/backend/src/main/java/com/yfd/platform/config/SecurityConfig.java +++ b/backend/src/main/java/com/yfd/platform/config/SecurityConfig.java @@ -65,6 +65,7 @@ public class SecurityConfig { .requestMatchers("/eq/**").permitAll() .requestMatchers("/env/**").permitAll() .requestMatchers("/warn/**").permitAll() + .requestMatchers("/overview/**").permitAll() .requestMatchers("/wt/**").permitAll() .requestMatchers("/fb/**").permitAll() .requestMatchers("/zq/**").permitAll() 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 f46f9a63..5e695eed 100644 --- a/backend/src/main/java/com/yfd/platform/config/SwaggerConfig.java +++ b/backend/src/main/java/com/yfd/platform/config/SwaggerConfig.java @@ -151,6 +151,15 @@ public class SwaggerConfig { .build(); } + @Bean + public GroupedOpenApi groupEnvOverviewApi() { + return GroupedOpenApi.builder() + .group("3.10 全过程-生态环保数据服务-首页(overview)") + .packagesToScan("com.yfd.platform.qgc_env.overview.controller") + .build(); + } + + diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/controller/SdEngInfoBHController.java b/backend/src/main/java/com/yfd/platform/qgc_base/controller/SdEngInfoBHController.java index b5c994ee..798ab6d7 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/controller/SdEngInfoBHController.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/controller/SdEngInfoBHController.java @@ -93,6 +93,14 @@ public class SdEngInfoBHController { return ResponseResult.successData(engInfoBHService.getVmsstbprptKendoList(dataSourceRequest)); } + @PostMapping("/stbprpData/GetKendoListCust") + @Operation(summary = "电站通用实时监测数据查询") + public ResponseResult getStbprpDataKendoListCust(@RequestBody DataSourceRequest dataSourceRequest, + @RequestParam("tbCode") String tbCode, + @RequestParam(value = "ignorePageLimit", required = false) Boolean ignorePageLimit) { + return ResponseResult.successData(engInfoBHService.getStbprpDataKendoListCust(dataSourceRequest, tbCode, ignorePageLimit)); + } + @Log(module = "电站管理", value = "新增电站") @PostMapping("/add") @Operation(summary = "新增电站") diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/domain/MsOperationLog.java b/backend/src/main/java/com/yfd/platform/qgc_base/domain/MsOperationLog.java index 277171ac..04d9e34a 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/domain/MsOperationLog.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/domain/MsOperationLog.java @@ -29,4 +29,11 @@ public class MsOperationLog implements Serializable { @TableField("REMARK") private String remark; + + @TableField("TABLE_NAME") + private String tableName; + + @TableField("RECORD_ID") + private String recordId; + } diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/domain/vo/EngStbprpDataVo.java b/backend/src/main/java/com/yfd/platform/qgc_base/domain/vo/EngStbprpDataVo.java new file mode 100644 index 00000000..afd9546c --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_base/domain/vo/EngStbprpDataVo.java @@ -0,0 +1,24 @@ +package com.yfd.platform.qgc_base.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; + +import java.io.Serializable; +import java.util.LinkedHashMap; +import java.util.Map; + +@Schema(description = "电站通用监测数据动态行") +public class EngStbprpDataVo extends LinkedHashMap implements Serializable { + + private static final long serialVersionUID = 1L; + + public EngStbprpDataVo() { + super(); + } + + public EngStbprpDataVo(Map source) { + super(); + if (source != null && !source.isEmpty()) { + putAll(source); + } + } +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/entity/vo/BatchDeleteAo.java b/backend/src/main/java/com/yfd/platform/qgc_base/entity/vo/BatchDeleteAo.java index 2fbb7069..f9bab6ca 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/entity/vo/BatchDeleteAo.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/entity/vo/BatchDeleteAo.java @@ -12,6 +12,9 @@ public class BatchDeleteAo implements Serializable { private static final long serialVersionUID = 1L; + @Schema(description = "数据来源") + private String source; + @Schema(description = "数据类型") private String dataType; diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/service/ISdEngInfoBHService.java b/backend/src/main/java/com/yfd/platform/qgc_base/service/ISdEngInfoBHService.java index e9128874..7d034512 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/service/ISdEngInfoBHService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/service/ISdEngInfoBHService.java @@ -84,4 +84,6 @@ public interface ISdEngInfoBHService extends IService { DataSourceResult getVmsstbprptKendoList(DataSourceRequest dataSourceRequest); DataSourceResult getOperatKendoList(DataSourceRequest dataSourceRequest); + + DataSourceResult getStbprpDataKendoListCust(DataSourceRequest dataSourceRequest, String tbCode, Boolean ignorePageLimit); } diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/MsOperationLogServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/MsOperationLogServiceImpl.java index 8e70e7fb..a915ff1d 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/MsOperationLogServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/MsOperationLogServiceImpl.java @@ -275,7 +275,7 @@ public class MsOperationLogServiceImpl implements IMsOperationLogService { if (engInfo == null) { return; } - MsOperationLog mainLog = buildMainLog("新增电站", source); + MsOperationLog mainLog = buildMainLog(null,"新增电站", source); msOperationLogMapper.insert(mainLog); List details = new ArrayList<>(); @@ -311,7 +311,7 @@ public class MsOperationLogServiceImpl implements IMsOperationLogService { return; } - MsOperationLog mainLog = buildMainLog("修改电站", source); + MsOperationLog mainLog = buildMainLog(before.getStcd(),"修改电站", source); msOperationLogMapper.insert(mainLog); List details = new ArrayList<>(); @@ -348,7 +348,7 @@ public class MsOperationLogServiceImpl implements IMsOperationLogService { if (engInfo == null) { return; } - MsOperationLog mainLog = buildMainLog("删除电站", source); + MsOperationLog mainLog = buildMainLog(engInfo.getStcd(),"删除电站", source); msOperationLogMapper.insert(mainLog); List details = new ArrayList<>(); @@ -378,10 +378,12 @@ public class MsOperationLogServiceImpl implements IMsOperationLogService { batchInsertDetails(details); } - private MsOperationLog buildMainLog(String remark, String source) { + private MsOperationLog buildMainLog(String recordId,String remark, String source) { MsOperationLog log = new MsOperationLog(); log.setOperator(resolveOperator()); log.setOperateTime(new Date()); + log.setTableName(ENG_TABLE_NAME); + log.setRecordId(recordId); log.setSource(StrUtil.trimToNull(source)); log.setRemark(remark); return log; diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdEngInfoBHServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdEngInfoBHServiceImpl.java index 315005fd..520e3752 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdEngInfoBHServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdEngInfoBHServiceImpl.java @@ -27,12 +27,14 @@ import com.yfd.platform.qgc_base.domain.SdEngInfoBHRequest; import com.yfd.platform.qgc_base.domain.vo.EngBaseInfoVo; import com.yfd.platform.qgc_base.domain.vo.EngEiaapprovalVo; import com.yfd.platform.qgc_base.domain.vo.EngOperatVo; +import com.yfd.platform.qgc_base.domain.vo.EngStbprpDataVo; import com.yfd.platform.qgc_base.domain.vo.EngStBaseInfoVo; import com.yfd.platform.qgc_base.domain.vo.EngStInfoResultVo; import com.yfd.platform.qgc_base.domain.vo.EngVmsstbprptVo; import com.yfd.platform.qgc_base.mapper.SdEngInfoBHMapper; import com.yfd.platform.qgc_base.service.IMsOperationLogService; import com.yfd.platform.qgc_base.service.ISdEngInfoBHService; +import com.yfd.platform.system.service.IAdminAuthService; import com.yfd.platform.utils.QgcQueryWrapperUtil; import com.yfd.platform.utils.SecurityUtils; import jakarta.annotation.Resource; @@ -41,15 +43,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; -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; +import java.util.*; import java.util.stream.Collectors; /** @@ -88,6 +82,9 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl queryPageList(Page page, String ennm, String rvcd, String baseId, String hycd) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); @@ -100,7 +97,7 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl authorizedStations = getUserAuthorizedStationCodes(); if (authorizedStations != null && !authorizedStations.isEmpty()) { wrapper.in(SdEngInfoBH::getStcd, authorizedStations); - }else if (!"admin".equals(SecurityUtils.getCurrentUsername())){ + }else if (!adminAuthService.isCurrentManagedAdmin()){ return page; } return this.page(page, wrapper); @@ -142,7 +139,7 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl authorizedStations = getUserAuthorizedStationCodes(); @@ -709,6 +706,59 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl result = new DataSourceResult<>(); + result.setAggregates(new HashMap<>()); + if (StrUtil.isBlank(tbCode)) { + result.setData(new ArrayList<>()); + result.setTotal(0L); + return result; + } + DataSourceRequest request = dataSourceRequest == null ? new DataSourceRequest() : dataSourceRequest; + if (!Boolean.TRUE.equals(ignorePageLimit) && request.getTake() == 0) { + request.setTake(2000); + } + + DataSourceLoadOptionsBase loadOptions = request.toDevRequest(); + List tableMetaList = queryStbprpTableMeta(tbCode); + if (CollUtil.isEmpty(tableMetaList)) { + return result; + } + + String firstTableName = tableMetaList.getFirst().tableName(); + String detailSql = buildStbprpDataDetailSql(request, tableMetaList); + Map paramMap = new HashMap<>(); + String filterSql = buildStbprpDataFilterCondition(request.getFilter(), paramMap, new int[]{0}, tableMetaList); + if (StrUtil.isNotBlank(filterSql)) { + detailSql = detailSql + " AND " + filterSql; + } + + if (CollUtil.isEmpty(request.getGroup())) { + String sql = detailSql + buildStbprpDataOrderBySql(request.getSort(), tableMetaList); + Page page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + List> rows = microservicDynamicSQLMapper.pageAllList(page, sql, paramMap); + List list = new ArrayList<>(); + for (Map row : rows) { + list.add(new EngStbprpDataVo(row)); + } + result.setData(list); + result.setTotal(page == null ? list.size() : page.getTotal()); + return result; + } + + GroupingInfo[] groupInfos = loadOptions == null ? new GroupingInfo[0] : loadOptions.getGroup(); + String groupSql = buildStbprpDataGroupSql(detailSql, request.getGroup(), tableMetaList); + List> rows = microservicDynamicSQLMapper.pageAllList(null, groupSql, paramMap); + if (Boolean.TRUE.equals(request.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((long) rows.size()); + return result; + } + private DataSourceResult queryOperatSummaryList(DataSourceRequest dataSourceRequest, DataSourceLoadOptionsBase loadOptions) { StringBuilder sql = new StringBuilder(); @@ -1039,6 +1089,7 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl "t.id"; case "sttp" -> "t.sttp"; case "sttpCode" -> "t.sttpCode"; + case "runState" -> "t.runState"; case "sttpName" -> "t.sttpName"; case "stcd" -> "t.stcd"; case "stnm", "ennm" -> "t.stnm"; @@ -1850,6 +1903,7 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl "t.hbrvcd"; case "hbrvcdName" -> "t.hbrvcdName"; case "rvcd" -> "t.rvcd"; + case "prsc" -> "t.prsc"; case "rvcdName" -> "t.rvcdName"; case "addvcdName" -> "t.addvcdName"; case "hynm" -> "t.hynm"; @@ -2303,4 +2357,311 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl null; }; } + + private List queryStbprpTableMeta(String tbCode) { + // 1. 解析参数 + List tbCodes = StrUtil.split(tbCode, ',') + .stream() + .map(StrUtil::trim) + .filter(StrUtil::isNotBlank) + .distinct() + .toList(); + + if (tbCodes.isEmpty()) { + return Collections.emptyList(); + } + + // 2. 构建 SQL 和参数 + Map paramMap = new HashMap<>(); + List placeholders = new ArrayList<>(); + for (int i = 0; i < tbCodes.size(); i++) { + String key = "tbCode" + i; + paramMap.put(key, tbCodes.get(i)); + placeholders.add("#{map." + key + "}"); + } + + String sql = "SELECT ID, TB, TB_CODE, STCD_MAPPING, TM_MAPPING " + + "FROM ST_TB_B " + + "WHERE NVL(IS_DELETED, 0) = 0 " + + "AND TB_CODE IN (" + StrUtil.join(", ", placeholders) + ") " + + "ORDER BY TB_CODE"; + + // 3. 执行查询 + List> rows = microservicDynamicSQLMapper.pageAllList(null, sql, paramMap); + + // 4. 转换结果 + List result = new ArrayList<>(); + for (Map row : rows) { + result.add(new StbprpTableMeta( + asString(row.get("ID")), + asString(row.get("TB")), + asString(row.get("TB_CODE")), + StrUtil.blankToDefault(asString(row.get("STCD_MAPPING")), "STCD"), + StrUtil.blankToDefault(asString(row.get("TM_MAPPING")), "TM") + )); + } + return result; + } + + /** + * 安全转为字符串 + */ + private String asString(Object obj) { + return obj == null ? null : obj.toString(); + } + + private String buildStbprpDataDetailSql(DataSourceRequest request, List tableMetaList) { + List selectItems = resolveStbprpSelectItems(request == null ? null : request.getSelect(), tableMetaList); + StringBuilder sql = new StringBuilder("SELECT "); + sql.append(String.join(", ", selectItems)).append(" FROM "); + for (int i = 0; i < tableMetaList.size(); i++) { + StbprpTableMeta meta = tableMetaList.get(i); + String alias = "t" + (i + 1); + if (i == 0) { + sql.append(meta.tableName()).append(" ").append(alias).append(" "); + } else { + StbprpTableMeta first = tableMetaList.getFirst(); + sql.append(" LEFT JOIN ").append(meta.tableName()).append(" ").append(alias) + .append(" ON t1.").append(first.stcdMapping()).append(" = ").append(alias).append(".").append(meta.stcdMapping()) + .append(" AND t1.").append(first.tmMapping()).append(" = ").append(alias).append(".").append(meta.tmMapping()).append(" "); + } + } + sql.append(" WHERE 1 = 1"); + return sql.toString(); + } + + private List resolveStbprpSelectItems(List selectFields, List tableMetaList) { + if (CollUtil.isEmpty(selectFields)) { + return List.of("t1.*"); + } + List items = new ArrayList<>(); + for (String field : selectFields) { + if (StrUtil.isBlank(field)) { + continue; + } + String mapped = mapStbprpField(field, tableMetaList); + if (StrUtil.isNotBlank(mapped)) { + items.add(mapped + " AS \"" + field.trim() + "\""); + } + } + if (items.isEmpty()) { + items.add("t1.*"); + } + return items; + } + + private String buildStbprpDataFilterCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder, + List tableMetaList) { + if (filter == null) { + return ""; + } + if (StrUtil.isNotBlank(filter.getField())) { + return buildStbprpDataLeafCondition(filter, paramMap, indexHolder, tableMetaList); + } + if (CollUtil.isEmpty(filter.getFilters())) { + return ""; + } + List childConditions = new ArrayList<>(); + for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) { + String childSql = buildStbprpDataFilterCondition(child, paramMap, indexHolder, tableMetaList); + if (StrUtil.isNotBlank(childSql)) { + childConditions.add("(" + childSql + ")"); + } + } + if (childConditions.isEmpty()) { + return ""; + } + String logic = "or".equalsIgnoreCase(filter.getLogic()) ? " OR " : " AND "; + return String.join(logic, childConditions); + } + + private String buildStbprpDataLeafCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder, + List tableMetaList) { + String column = mapStbprpField(filter.getField(), tableMetaList); + if (StrUtil.isBlank(column)) { + return ""; + } + String operator = StrUtil.blankToDefault(filter.getOperator(), "eq").toLowerCase(); + Object value = filter.getValue(); + if ("isnull".equals(operator)) { + return column + " IS NULL"; + } + if ("isnotnull".equals(operator)) { + return column + " IS NOT NULL"; + } + if ("isempty".equals(operator)) { + return "(" + column + " IS NULL OR " + column + " = '')"; + } + if ("isnotempty".equals(operator)) { + return "(" + column + " IS NOT NULL AND " + column + " <> '')"; + } + boolean dateField = isStbprpDateField(filter); + if ("in".equals(operator) || "ni".equals(operator)) { + List values = normalizeFilterValues(value); + if (values.isEmpty()) { + return ""; + } + List placeholders = new ArrayList<>(); + for (Object item : values) { + String key = "stbprpParam" + indexHolder[0]++; + paramMap.put(key, item); + placeholders.add(buildStbprpDataValueExpr(key, dateField, item)); + } + return column + ("ni".equals(operator) ? " NOT IN (" : " IN (") + String.join(", ", placeholders) + ")"; + } + if (value == null) { + return ""; + } + String key = "stbprpParam" + indexHolder[0]++; + String expr = buildStbprpDataValueExpr(key, dateField, value); + return switch (operator) { + case "eq" -> { + paramMap.put(key, value); + yield column + " = " + expr; + } + case "neq" -> { + paramMap.put(key, value); + yield column + " <> " + expr; + } + case "contains" -> { + paramMap.put(key, "%" + value + "%"); + yield column + " LIKE #{map." + key + "}"; + } + case "doesnotcontain" -> { + paramMap.put(key, "%" + value + "%"); + yield column + " NOT 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 + " > " + expr; + } + case "gte" -> { + paramMap.put(key, value); + yield column + " >= " + expr; + } + case "lt" -> { + paramMap.put(key, value); + yield column + " < " + expr; + } + case "lte" -> { + paramMap.put(key, value); + yield column + " <= " + expr; + } + default -> ""; + }; + } + + private String buildStbprpDataValueExpr(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 boolean isStbprpDateField(DataSourceRequest.FilterDescriptor filter) { + if (filter == null) { + return false; + } + if ("date".equalsIgnoreCase(filter.getDataType())) { + return true; + } + String field = StrUtil.blankToDefault(filter.getField(), "").trim().toLowerCase(); + if (field.contains(".")) { + field = field.substring(field.lastIndexOf('.') + 1); + } + return "tm".equals(field) || "dt".equals(field); + } + + private String buildStbprpDataOrderBySql(List sortList, List tableMetaList) { + if (CollUtil.isEmpty(sortList)) { + return ""; + } + List orderItems = new ArrayList<>(); + for (DataSourceRequest.SortDescriptor sort : sortList) { + if (sort == null || StrUtil.isBlank(sort.getField())) { + continue; + } + String column = mapStbprpField(sort.getField(), tableMetaList); + if (StrUtil.isBlank(column)) { + continue; + } + String dir = "desc".equalsIgnoreCase(sort.getDir()) || "des".equalsIgnoreCase(sort.getDir()) ? "DESC" : "ASC"; + orderItems.add(column + " " + dir); + } + if (orderItems.isEmpty()) { + return ""; + } + return " ORDER BY " + String.join(", ", orderItems); + } + + private String buildStbprpDataGroupSql(String detailSql, + List groups, + List tableMetaList) { + List selectItems = new ArrayList<>(); + List groupItems = new ArrayList<>(); + List orderItems = new ArrayList<>(); + for (DataSourceRequest.GroupDescriptor descriptor : groups) { + if (descriptor == null || StrUtil.isBlank(descriptor.getField())) { + continue; + } + String column = mapStbprpField(descriptor.getField(), tableMetaList); + if (StrUtil.isBlank(column)) { + continue; + } + String upperField = descriptor.getField().trim().toUpperCase(); + selectItems.add(column + " AS " + upperField); + selectItems.add("COUNT(*) AS COUNT_" + upperField); + groupItems.add(column); + String dir = "desc".equalsIgnoreCase(descriptor.getDir()) || "des".equalsIgnoreCase(descriptor.getDir()) ? "DESC" : "ASC"; + orderItems.add(column + " " + dir); + } + if (selectItems.isEmpty()) { + selectItems.add("t1.STCD AS STCD"); + selectItems.add("COUNT(*) AS COUNT_STCD"); + groupItems.add("t1.STCD"); + orderItems.add("t1.STCD ASC"); + } + return "SELECT " + String.join(", ", selectItems) + + " FROM (" + detailSql + ") t1 GROUP BY " + String.join(", ", groupItems) + + " ORDER BY " + String.join(", ", orderItems); + } + + private String mapStbprpField(String field, List tableMetaList) { + if (StrUtil.isBlank(field) || CollUtil.isEmpty(tableMetaList)) { + return null; + } + String normalized = field.trim(); + if (!normalized.contains(".")) { + return "t1." + normalized.toUpperCase(); + } + String[] parts = normalized.split("\\.", 2); + if (parts.length != 2) { + return null; + } + for (int i = 0; i < tableMetaList.size(); i++) { + if (StrUtil.equalsIgnoreCase(tableMetaList.get(i).tbCode(), parts[0])) { + return "t" + (i + 1) + "." + parts[1].toUpperCase(); + } + } + return null; + } + + private record StbprpTableMeta(String id, String tableName, String tbCode, String stcdMapping, String tmMapping) { + } } diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdFpssBHServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdFpssBHServiceImpl.java index ea8b2378..c85ffa59 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdFpssBHServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdFpssBHServiceImpl.java @@ -10,6 +10,7 @@ import com.yfd.platform.qgc_base.domain.SdFpssBH; import com.yfd.platform.qgc_base.mapper.SdEngInfoBHMapper; import com.yfd.platform.qgc_base.mapper.SdFpssBHMapper; import com.yfd.platform.qgc_base.service.ISdFpssBHService; +import com.yfd.platform.system.service.IAdminAuthService; import com.yfd.platform.utils.SecurityUtils; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; @@ -29,6 +30,9 @@ public class SdFpssBHServiceImpl extends ServiceImpl i @Resource private SdEngInfoBHMapper sdEngInfoBHMapper; + @Resource + private IAdminAuthService adminAuthService; + @Override public Page selectPage(String stcd, String sttp, String rstcd, Integer usfl, Page page) { @@ -50,7 +54,7 @@ public class SdFpssBHServiceImpl extends ServiceImpl i Set authorizedStations = getUserAuthorizedStationCodes(); if (authorizedStations != null && !authorizedStations.isEmpty()) { wrapper.in(SdFpssBH::getRstcd, authorizedStations); - }else if (!"admin".equals(SecurityUtils.getCurrentUsername())){ + }else if (!adminAuthService.isCurrentManagedAdmin()){ return page; } @@ -68,7 +72,7 @@ public class SdFpssBHServiceImpl extends ServiceImpl i @Override public List selectForDropdown(String rstcd, String stnm, String baseId,String rvcd,String reachcd) { // 管理员直接查询,无需权限过滤 - if ("admin".equals(SecurityUtils.getCurrentUsername())) { + if (adminAuthService.isCurrentManagedAdmin()) { return queryFpssList(rstcd, stnm, baseId,rvcd,reachcd); } @@ -196,4 +200,4 @@ public class SdFpssBHServiceImpl extends ServiceImpl i .eq(SdFpssBH::getSttp, sttp); return getOne(wrapper); } -} \ No newline at end of file +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdHbrvDicServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdHbrvDicServiceImpl.java index b897970b..5d58e2fe 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdHbrvDicServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdHbrvDicServiceImpl.java @@ -15,6 +15,9 @@ import com.yfd.platform.qgc_base.mapper.SdEngInfoBHMapper; import com.yfd.platform.qgc_base.mapper.SdHbrvDicMapper; import com.yfd.platform.qgc_base.mapper.SdHydrobaseMapper; import com.yfd.platform.qgc_base.service.ISdHbrvDicService; +import com.yfd.platform.system.service.IAdminAuthService; +import com.yfd.platform.utils.CodeToNameMetadataBo; +import com.yfd.platform.utils.DictCodeToNameConverter; import com.yfd.platform.utils.QgcQueryWrapperUtil; import com.yfd.platform.utils.SecurityUtils; import jakarta.annotation.Resource; @@ -46,7 +49,39 @@ public class SdHbrvDicServiceImpl extends ServiceImpl + * 每个模块的 ServiceImpl 中可按需定义自己的 codeToNameMetadataBoList, + * 在查询方法返回前调用 dictCodeToNameConverter.convertCodeToName(voList, codeToNameMetadataBoList) + * 即可自动将 code 字段转为对应的 name 字段。 + *

+ * + *
+     * 使用示例:
+     * // 在查询方法末尾调用:
+     * dictCodeToNameConverter.convertCodeToName(voList, CODE_TO_NAME_META_LIST);
+     * 
+ */ + private static final List CODE_TO_NAME_META_LIST = new ArrayList<>(); + +// static { +// +// CODE_TO_NAME_META_LIST.add(CodeToNameMetadataBo.builder().codeProperty("grd").modifyProperty("grdName").dictType("STATIC").dictSource("TEST").build()); +// CODE_TO_NAME_META_LIST.add(CodeToNameMetadataBo.builder().codeProperty("baseid").modifyProperty("basename").dictType("DYNAMIC").dictSource("SD_HYDROBASE").codeColumn("BASEID").nameColumn("BASENAME").filter("NVL(IS_DELETED, 0) = 0 ").build()); +// } + + @Override public Page queryPageList(Page page, String hbrvnm, String baseid) { return this.page(page, this.lambdaQuery() @@ -110,7 +145,7 @@ public class SdHbrvDicServiceImpl extends ServiceImpl authorizedStations = getUserAuthorizedStationCodes(); diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdHydrobaseServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdHydrobaseServiceImpl.java index 652d5d4d..9669eba8 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdHydrobaseServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdHydrobaseServiceImpl.java @@ -13,6 +13,7 @@ import com.yfd.platform.qgc_base.entity.vo.HydrobaseWbsVo; import com.yfd.platform.qgc_base.mapper.SdEngInfoBHMapper; import com.yfd.platform.qgc_base.mapper.SdHydrobaseMapper; import com.yfd.platform.qgc_base.service.ISdHydrobaseService; +import com.yfd.platform.system.service.IAdminAuthService; import com.yfd.platform.utils.SecurityUtils; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; @@ -39,6 +40,9 @@ public class SdHydrobaseServiceImpl extends ServiceImpl queryPageList(Page page, String basename, String pbaseid) { return this.page(page, this.lambdaQuery() @@ -91,7 +95,7 @@ public class SdHydrobaseServiceImpl extends ServiceImpl(); } - }else if (!"admin".equals(SecurityUtils.getCurrentUsername())){ + }else if (!adminAuthService.isCurrentManagedAdmin()){ return new ArrayList<>(); } // else { diff --git a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdRvcdDicServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdRvcdDicServiceImpl.java index 60446e27..ff89fa82 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdRvcdDicServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdRvcdDicServiceImpl.java @@ -11,6 +11,7 @@ import com.yfd.platform.qgc_base.mapper.SdRvcdDicMapper; import com.yfd.platform.qgc_base.service.ISdRvcdDicService; import com.yfd.platform.qgc_data.domain.SysUserDataScope; import com.yfd.platform.qgc_data.mapper.SysUserDataScopeMapper; +import com.yfd.platform.system.service.IAdminAuthService; import com.yfd.platform.utils.SecurityUtils; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; @@ -33,6 +34,9 @@ public class SdRvcdDicServiceImpl extends ServiceImpl queryPageList(Page page, String rvnm, String prvcd) { return this.page(page, this.lambdaQuery() @@ -120,7 +124,7 @@ public class SdRvcdDicServiceImpl extends ServiceImpl selectForDropdown(String rvnm, String rvcd) { List dropdownList = this.baseMapper.selectRegDropdown(rvnm, rvcd); - if("admin".equals(SecurityUtils.getCurrentUsername())){ + if(adminAuthService.isCurrentManagedAdmin()){ return dropdownList; } Set authorizedStations = getUserAuthorizedStationCodes(); diff --git a/backend/src/main/java/com/yfd/platform/qgc_eng/eq/service/impl/EngEqDataServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_eng/eq/service/impl/EngEqDataServiceImpl.java index 5a7a0cfc..d470ba6e 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_eng/eq/service/impl/EngEqDataServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_eng/eq/service/impl/EngEqDataServiceImpl.java @@ -5746,7 +5746,8 @@ public class EngEqDataServiceImpl implements EngEqDataService { } return switch (field) { case "id" -> "t.id"; - case "stcd" -> "t.stcd"; + case "rstcd" -> "t.stcd"; +// case "rstcd" -> "t.rstcd"; case "stnm", "ennm" -> "t.ennm"; case "baseId" -> "t.baseId"; case "baseName" -> "t.baseName"; diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/overview/controller/OverviewController.java b/backend/src/main/java/com/yfd/platform/qgc_env/overview/controller/OverviewController.java new file mode 100644 index 00000000..a3ed0a61 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/overview/controller/OverviewController.java @@ -0,0 +1,35 @@ +package com.yfd.platform.qgc_env.overview.controller; + +import com.yfd.platform.common.DataSourceRequest; +import com.yfd.platform.config.ResponseResult; +import com.yfd.platform.qgc_env.overview.service.OverviewService; +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("/overview") +@Tag(name = "首页概览") +@Validated +public class OverviewController { + + @Resource + private OverviewService overviewService; + + @PostMapping("/msstbprpt/GetKendoList") + @Operation(summary = "首页基础设施概览列表") + public ResponseResult getMsstbprptList(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(overviewService.getMsstbprptList(dataSourceRequest)); + } + + @PostMapping("/oped/GetKendoListCust") + @Operation(summary = "首页环保设施运行状况明细") + public ResponseResult getOpedList(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(overviewService.getOpedList(dataSourceRequest)); + } +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/overview/entity/vo/OverviewMsstbprptVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/overview/entity/vo/OverviewMsstbprptVo.java new file mode 100644 index 00000000..effa1e33 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/overview/entity/vo/OverviewMsstbprptVo.java @@ -0,0 +1,72 @@ +package com.yfd.platform.qgc_env.overview.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +@Schema(description = "首页基础设施概览列表") +public class OverviewMsstbprptVo implements Serializable { + + private static final long serialVersionUID = 1L; + + private String id; + private String stcd; + private String stnm; + private String sttp; + private String sttpCode; + private String sttpName; + private String sttpFullPath; + private Integer sttpTreeLevel; + private String blprdId; + private Double lgtd; + private Double lttd; + private Double dtmel; + private String stlc; + private Integer usfl; + private String rstcd; + private String ennm; + private String baseId; + private String baseName; + private String hbrvcd; + private String hbrvcdName; + private String rvcd; + private String rvcdName; + private String addvcd; + private String addvcdName; + private String country; + private String countryName; + private String stCode; + private String stName; + private Date stdsdt; + private Date pststdt; + private Date pesstdt; + private Date ststdt; + private Date jcdt; + private Date stwddt; + private String introduce; + private String precis; + private String logo; + private String inffile; + private Integer dtin; + private String dtinName; + private Date dtinTm; + private Integer bldsttCode; + private String bldsttCcode; + private String bldsttCcodeName; + private Double inv; + private Integer invinmn; + private String dsun; + private String jbtxcs; + private Integer dtfrqcy; + private String remark; + private String vlsr; + private Date vlsrTm; + private Integer orderIndex; + private Integer baseStepSort; + private Integer rvcdStepSort; + private Integer rstcdStepSort; + private Integer siteStepSort; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/overview/entity/vo/OverviewOpedVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/overview/entity/vo/OverviewOpedVo.java new file mode 100644 index 00000000..67a71e8a --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/overview/entity/vo/OverviewOpedVo.java @@ -0,0 +1,65 @@ +package com.yfd.platform.qgc_env.overview.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +@Data +@Schema(description = "首页环保设施运行状况明细") +public class OverviewOpedVo implements Serializable { + + private static final long serialVersionUID = 1L; + + private Map _tls = new HashMap<>(); + + private String id; + private String recordUser; + private Date recordTime; + private Date modifyTime; + private String displayRecordUser; + private String repCode; + private String pcode; + private String pname; + private String psttpName; + private String sttpName; + private String baseId; + private String stcd; + private String stnm; + private String sttpCode; + private String baseName; + private String rstcd; + private String ennm; + private String bldsttCcode; + private String bldsttCcodeName; + private Date dtinTm; + private Integer dtin; + private String dtinName; + private Integer runState; + private String runStateName; + private Integer stdState; + private String stdStateName; + private Integer stdSstate; + private String stdSstateName; + private Integer runSstate; + private String runSstateName; + private Integer mway; + private String mwayName; + private String hbrvcd; + private String hbrvcdName; + private String addvcdName; + private String rvcdName; + private Integer baseStepSort; + private Integer baseStepsort; + private Integer rvcdStepSort; + private Integer rstcdStepSort; + private Integer rstcdStepsort; + private Integer siteStepSort; + private Integer count; + private Date jcdt; + private String departmentId; + private String displayDepartment; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/overview/service/OverviewService.java b/backend/src/main/java/com/yfd/platform/qgc_env/overview/service/OverviewService.java new file mode 100644 index 00000000..481e665f --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/overview/service/OverviewService.java @@ -0,0 +1,13 @@ +package com.yfd.platform.qgc_env.overview.service; + +import com.yfd.platform.common.DataSourceRequest; +import com.yfd.platform.common.DataSourceResult; +import com.yfd.platform.qgc_env.overview.entity.vo.OverviewMsstbprptVo; +import com.yfd.platform.qgc_env.overview.entity.vo.OverviewOpedVo; + +public interface OverviewService { + + DataSourceResult getMsstbprptList(DataSourceRequest dataSourceRequest); + + DataSourceResult getOpedList(DataSourceRequest dataSourceRequest); +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/overview/service/impl/OverviewServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/overview/service/impl/OverviewServiceImpl.java new file mode 100644 index 00000000..79ec09ab --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/overview/service/impl/OverviewServiceImpl.java @@ -0,0 +1,1343 @@ +package com.yfd.platform.qgc_env.overview.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +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.qgc_env.overview.entity.vo.OverviewMsstbprptVo; +import com.yfd.platform.qgc_env.overview.entity.vo.OverviewOpedVo; +import com.yfd.platform.qgc_env.overview.service.OverviewService; +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.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.time.Year; + +@Service +public class OverviewServiceImpl implements OverviewService { + + @Resource + private MicroservicDynamicSQLMapper microservicDynamicSQLMapper; + + @Override + public DataSourceResult getMsstbprptList(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + List selectFields = resolveSelectFields(dataSourceRequest == null ? null : dataSourceRequest.getSelect()); + + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append(buildSelectSql(selectFields)) + .append(" FROM (") + .append(buildBaseSql()) + .append(") t WHERE 1 = 1 "); + + Map paramMap = new HashMap<>(); + String filterSql = buildFilterCondition(dataSourceRequest == null ? null : dataSourceRequest.getFilter(), paramMap, new int[]{0}); + if (StrUtil.isNotBlank(filterSql)) { + sql.append(" AND ").append(filterSql); + } + sql.append(buildOrderBySql(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, OverviewMsstbprptVo.class + ); + + DataSourceResult result = new DataSourceResult<>(); + result.setData(list); + result.setTotal(page == null ? list.size() : page.getTotal()); + result.setAggregates(new HashMap<>()); + return result; + } + + @Override + @SuppressWarnings("unchecked") + public DataSourceResult getOpedList(DataSourceRequest dataSourceRequest) { + DataSourceResult result = new DataSourceResult<>(); + result.setAggregates(new HashMap<>()); + if (dataSourceRequest == null) { + result.setData(new ArrayList<>()); + result.setTotal(0L); + return result; + } + + DataSourceLoadOptionsBase loadOptions = dataSourceRequest.toDevRequest(); + Map paramMap = new HashMap<>(); + paramMap.put("stateYear", resolveOpedStateYear()); + if (shouldQueryOpedSummary(dataSourceRequest)) { + return queryOpedSummaryList(dataSourceRequest, loadOptions, paramMap); + } + + String filterSql = buildOpedFilterCondition(dataSourceRequest.getFilter(), paramMap, new int[]{0}); + if (CollUtil.isNotEmpty(dataSourceRequest.getGroup())) { + GroupingInfo[] groupInfos = loadOptions == null ? null : loadOptions.getGroup(); + String groupSql = buildOpedGroupSql(buildOpedDetailSql(null, filterSql), groupInfos); + Page page = loadOptions == null ? null + : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + List> rows = microservicDynamicSQLMapper.pageAllList(page, groupSql, paramMap); + if (Boolean.TRUE.equals(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); + return result; + } + + String sql = buildOpedDetailSql(dataSourceRequest.getSelect(), filterSql) + + buildOpedOrderBySql(dataSourceRequest.getSort()); + Page page = loadOptions == null ? null + : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + List list = microservicDynamicSQLMapper.pageAllListWithResultType( + page, sql, paramMap, OverviewOpedVo.class + ); + result.setData(list); + result.setTotal(page == null ? list.size() : page.getTotal()); + return result; + } + + private DataSourceResult queryOpedSummaryList(DataSourceRequest dataSourceRequest, + DataSourceLoadOptionsBase loadOptions, + Map paramMap) { + String effectiveFilterSql = buildOpedEffectiveFilterCondition(dataSourceRequest.getFilter(), paramMap, new int[]{0}); + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append(buildOpedSummarySelectSql(dataSourceRequest.getSelect())) + .append(" FROM (") + .append(buildOpedCategorySql()) + .append(") cat ") + .append("LEFT JOIN (SELECT * FROM (") + .append(buildOpedBaseSql()) + .append(") t WHERE 1 = 1 "); + if (StrUtil.isNotBlank(effectiveFilterSql)) { + sql.append(" AND ").append(effectiveFilterSql); + } + sql.append(") src ON cat.repCode = src.repCode ") + .append("GROUP BY cat.repCode, cat.sttpName, cat.orderIndex ") + .append(buildOpedSummaryOrderBySql(dataSourceRequest.getSort())); + + Page page = loadOptions == null ? null + : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + List list = microservicDynamicSQLMapper.pageAllListWithResultType( + page, sql.toString(), paramMap, OverviewOpedVo.class + ); + + DataSourceResult result = new DataSourceResult<>(); + result.setData(list); + result.setTotal(page == null ? list.size() : page.getTotal()); + result.setAggregates(new HashMap<>()); + return result; + } + + private String buildBaseSql() { + return buildFbSql() + " UNION ALL " + buildDwSql() + " UNION ALL " + buildFpSql(); + } + + private String buildFbSql() { + return "SELECT " + + "fb.STCD AS id, " + + "fb.STCD AS stcd, " + + "fb.STNM AS stnm, " + + "fb.STTP AS sttp, " + + "fb.STTP AS sttpCode, " + + "sttp.STTP_NAME AS sttpName, " + + "sttp.FULL_PATH AS sttpFullPath, " + + "sttp.TREE_LEVEL AS sttpTreeLevel, " + + "CAST(fb.BLPRD AS VARCHAR2(64)) AS blprdId, " + + "fb.LGTD AS lgtd, " + + "fb.LTTD AS lttd, " + + "fb.ELEV AS dtmel, " + + "fb.STLC AS stlc, " + + "fb.USFL AS usfl, " + + "fb.RSTCD AS rstcd, " + + "eng.ENNM AS ennm, " + + "NVL(fb.BASE_ID, eng.BASE_ID) AS baseId, " + + "hb.BASENAME AS baseName, " + + "NVL(fb.HBRVCD, eng.HBRVCD) AS hbrvcd, " + + "hbrv.HBRVNM AS hbrvcdName, " + + "eng.RVCD AS rvcd, " + + "rv.RVNM AS rvcdName, " + + "eng.ADDVCD AS addvcd, " + + "addv.ADDVNM AS addvcdName, " + + "eng.COUNTRY AS country, " + + "country.COUNTRY_NAME AS countryName, " + + "CAST(NULL AS VARCHAR2(64)) AS stCode, " + + "CAST(NULL AS VARCHAR2(200)) AS stName, " + + "fb.STDSDT AS stdsdt, " + + "fb.PSTSTDT AS pststdt, " + + "fb.PESSTDT AS pesstdt, " + + "fb.SWDT AS ststdt, " + + "fb.JCDT AS jcdt, " + + "fb.WDDT AS stwddt, " + + "fb.INTRODUCE AS introduce, " + + "fb.INTRODUCE AS precis, " + + "fb.LOGO AS logo, " + + "fb.INFFILE AS inffile, " + + "fb.DTIN AS dtin, " + + "CASE WHEN NVL(fb.DTIN, 0) = 1 THEN '已接入' ELSE '未接入' END AS dtinName, " + + "fb.DTIN_TM AS dtinTm, " + + "fb.BLDSTT_CODE AS bldsttCode, " + + "CASE fb.BLDSTT_CODE WHEN 0 THEN '0' WHEN 1 THEN '1' WHEN 2 THEN '2' ELSE NULL END AS bldsttCcode, " + + "CASE fb.BLDSTT_CODE WHEN 0 THEN '未建/规划' WHEN 1 THEN '在建' WHEN 2 THEN '已建' ELSE NULL END AS bldsttCcodeName, " + + "fb.INV AS inv, " + + "fb.INVINMN AS invinmn, " + + "fb.DSUN AS dsun, " + + "fb.JBTXCS AS jbtxcs, " + + "fb.DTFRQCY AS dtfrqcy, " + + "fb.REMARK AS remark, " + + "fb.VLSR AS vlsr, " + + "fb.VLSR_TM AS vlsrTm, " + + "fb.ORDER_INDEX AS orderIndex, " + + "NVL(hb.ORDER_INDEX, 999999) AS baseStepSort, " + + "NVL(hbrv.ORDER_INDEX, 999999) AS rvcdStepSort, " + + "NVL(eng.ORDER_INDEX, 999999) AS rstcdStepSort, " + + "NVL(fb.ORDER_INDEX, 999999) AS siteStepSort " + + "FROM SD_FBRD_B_H fb " + + "LEFT JOIN SD_STTP_B sttp ON sttp.STTP_CODE = fb.STTP AND NVL(sttp.ENABLE, 1) = 1 " + + "LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fb.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = NVL(fb.BASE_ID, eng.BASE_ID) AND NVL(hb.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = NVL(fb.HBRVCD, eng.HBRVCD) AND hbrv.BASEID = NVL(fb.BASE_ID, 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 SD_ADDVCD_DIC addv ON addv.ADDVCD = eng.ADDVCD " + + "LEFT JOIN SD_COUNTRY_B country ON country.COUNTRY_ID = eng.COUNTRY AND NVL(country.ENABLED, 1) = 1 "; + } + + private String buildDwSql() { + return "SELECT " + + "dw.STCD AS id, " + + "dw.STCD AS stcd, " + + "dw.STNM AS stnm, " + + "dw.STTP AS sttp, " + + "dw.STTP AS sttpCode, " + + "sttp.STTP_NAME AS sttpName, " + + "sttp.FULL_PATH AS sttpFullPath, " + + "sttp.TREE_LEVEL AS sttpTreeLevel, " + + "CAST(NULL AS VARCHAR2(64)) AS blprdId, " + + "dw.LGTD AS lgtd, " + + "dw.LTTD AS lttd, " + + "dw.ELEV AS dtmel, " + + "dw.STLC AS stlc, " + + "dw.USFL AS usfl, " + + "dw.RSTCD AS rstcd, " + + "eng.ENNM AS ennm, " + + "NVL(dw.BASE_ID, eng.BASE_ID) AS baseId, " + + "hb.BASENAME AS baseName, " + + "NVL(dw.HBRVCD, eng.HBRVCD) AS hbrvcd, " + + "hbrv.HBRVNM AS hbrvcdName, " + + "eng.RVCD AS rvcd, " + + "rv.RVNM AS rvcdName, " + + "eng.ADDVCD AS addvcd, " + + "addv.ADDVNM AS addvcdName, " + + "eng.COUNTRY AS country, " + + "country.COUNTRY_NAME AS countryName, " + + "CAST(NULL AS VARCHAR2(64)) AS stCode, " + + "CAST(NULL AS VARCHAR2(200)) AS stName, " + + "dw.STDSDT AS stdsdt, " + + "dw.PSTSTDT AS pststdt, " + + "dw.PESSTDT AS pesstdt, " + + "dw.SWDT AS ststdt, " + + "dw.JCDT AS jcdt, " + + "dw.WDDT AS stwddt, " + + "dw.INTRODUCE AS introduce, " + + "dw.INTRODUCE AS precis, " + + "dw.LOGO AS logo, " + + "dw.INFFILE AS inffile, " + + "dw.DTIN AS dtin, " + + "CASE WHEN NVL(dw.DTIN, 0) = 1 THEN '已接入' ELSE '未接入' END AS dtinName, " + + "dw.DTIN_TM AS dtinTm, " + + "dw.BLDSTT_CODE AS bldsttCode, " + + "CASE dw.BLDSTT_CODE WHEN 0 THEN '0' WHEN 1 THEN '1' WHEN 2 THEN '2' ELSE NULL END AS bldsttCcode, " + + "CASE dw.BLDSTT_CODE WHEN 0 THEN '未建/规划' WHEN 1 THEN '在建' WHEN 2 THEN '已建' ELSE NULL END AS bldsttCcodeName, " + + "dw.INV AS inv, " + + "dw.INVINMN AS invinmn, " + + "CAST(NULL AS VARCHAR2(500)) AS dsun, " + + "dw.QTSSJBTX AS jbtxcs, " + + "dw.DTFRQCY AS dtfrqcy, " + + "dw.REMARK AS remark, " + + "dw.VLSR AS vlsr, " + + "dw.VLSR_TM AS vlsrTm, " + + "dw.ORDER_INDEX AS orderIndex, " + + "NVL(hb.ORDER_INDEX, 999999) AS baseStepSort, " + + "NVL(hbrv.ORDER_INDEX, 999999) AS rvcdStepSort, " + + "NVL(eng.ORDER_INDEX, 999999) AS rstcdStepSort, " + + "NVL(dw.ORDER_INDEX, 999999) AS siteStepSort " + + "FROM SD_DW_B_H dw " + + "LEFT JOIN SD_STTP_B sttp ON sttp.STTP_CODE = dw.STTP AND NVL(sttp.IS_DELETED, 0) = 0 AND NVL(sttp.ENABLE, 1) = 1 " + + "LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = dw.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = NVL(dw.BASE_ID, eng.BASE_ID) AND NVL(hb.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = NVL(dw.HBRVCD, eng.HBRVCD) AND hbrv.BASEID = NVL(dw.BASE_ID, 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 SD_ADDVCD_DIC addv ON addv.ADDVCD = eng.ADDVCD " + + "LEFT JOIN SD_COUNTRY_B country ON country.COUNTRY_ID = eng.COUNTRY AND NVL(country.ENABLED, 1) = 1 " + + "WHERE NVL(dw.IS_DELETED, 0) = 0 "; + } + + private String buildFpSql() { + return "SELECT " + + "fp.STCD AS id, " + + "fp.STCD AS stcd, " + + "fp.STNM AS stnm, " + + "fp.STTP AS sttp, " + + "fp.STTP AS sttpCode, " + + "sttp.STTP_NAME AS sttpName, " + + "sttp.FULL_PATH AS sttpFullPath, " + + "sttp.TREE_LEVEL AS sttpTreeLevel, " + + "CAST(fp.BLPRD AS VARCHAR2(64)) AS blprdId, " + + "fp.LGTD AS lgtd, " + + "fp.LTTD AS lttd, " + + "fp.ELEV AS dtmel, " + + "fp.STLC AS stlc, " + + "fp.USFL AS usfl, " + + "fp.RSTCD AS rstcd, " + + "eng.ENNM AS ennm, " + + "eng.BASE_ID AS baseId, " + + "hb.BASENAME AS baseName, " + + "eng.HBRVCD AS hbrvcd, " + + "hbrv.HBRVNM AS hbrvcdName, " + + "eng.RVCD AS rvcd, " + + "rv.RVNM AS rvcdName, " + + "eng.ADDVCD AS addvcd, " + + "addv.ADDVNM AS addvcdName, " + + "eng.COUNTRY AS country, " + + "country.COUNTRY_NAME AS countryName, " + + "CAST(NULL AS VARCHAR2(64)) AS stCode, " + + "CAST(NULL AS VARCHAR2(200)) AS stName, " + + "fp.STDSDT AS stdsdt, " + + "fp.PSTSTDT AS pststdt, " + + "fp.PESSTDT AS pesstdt, " + + "fp.SWDT AS ststdt, " + + "fp.JCDT AS jcdt, " + + "fp.WDDT AS stwddt, " + + "fp.INTRODUCE AS introduce, " + + "fp.INTRODUCE AS precis, " + + "fp.LOGO AS logo, " + + "fp.INFFILE AS inffile, " + + "fp.DTIN AS dtin, " + + "CASE WHEN NVL(fp.DTIN, 0) = 1 THEN '已接入' ELSE '未接入' END AS dtinName, " + + "fp.DTIN_TM AS dtinTm, " + + "fp.BLDSTT_CODE AS bldsttCode, " + + "CASE fp.BLDSTT_CODE WHEN 0 THEN '0' WHEN 1 THEN '1' WHEN 2 THEN '2' ELSE NULL END AS bldsttCcode, " + + "CASE fp.BLDSTT_CODE WHEN 0 THEN '未建/规划' WHEN 1 THEN '在建' WHEN 2 THEN '已建' ELSE NULL END AS bldsttCcodeName, " + + "fp.INV AS inv, " + + "fp.INVINMN AS invinmn, " + + "CAST(NULL AS VARCHAR2(500)) AS dsun, " + + "fp.JBTXCS AS jbtxcs, " + + "fp.DTFRQCY AS dtfrqcy, " + + "fp.REMARK AS remark, " + + "fp.VLSR AS vlsr, " + + "fp.VLSR_TM AS vlsrTm, " + + "fp.ORDER_INDEX AS orderIndex, " + + "NVL(hb.ORDER_INDEX, 999999) AS baseStepSort, " + + "NVL(hbrv.ORDER_INDEX, 999999) AS rvcdStepSort, " + + "NVL(eng.ORDER_INDEX, 999999) AS rstcdStepSort, " + + "NVL(fp.ORDER_INDEX, 999999) AS siteStepSort " + + "FROM SD_FPSS_B_H fp " + + "LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fp.RSTCD " + + "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_STTP_B sttp ON sttp.STTP_CODE = fp.STTP AND NVL(sttp.IS_DELETED, 0) = 0 AND NVL(sttp.ENABLE, 1) = 1 " + + "LEFT JOIN SD_RVCD_DIC rv ON rv.RVCD = eng.RVCD " + + "LEFT JOIN SD_ADDVCD_DIC addv ON addv.ADDVCD = eng.ADDVCD " + + "LEFT JOIN SD_COUNTRY_B country ON country.COUNTRY_ID = eng.COUNTRY AND NVL(country.ENABLED, 1) = 1 "; + } + + private List resolveSelectFields(List select) { + List fields = CollUtil.isEmpty(select) + ? new ArrayList<>(buildSelectMap().keySet()) + : new ArrayList<>(select); + LinkedHashSet uniqueFields = new LinkedHashSet<>(); + for (String field : fields) { + if (StrUtil.isNotBlank(field)) { + uniqueFields.add(field.trim()); + } + } + if (uniqueFields.isEmpty()) { + uniqueFields.add("stcd"); + } + return new ArrayList<>(uniqueFields); + } + + private String buildSelectSql(List selectFields) { + Map columnMap = buildSelectMap(); + List selectParts = new ArrayList<>(); + for (String field : selectFields) { + String column = columnMap.get(field); + if (StrUtil.isNotBlank(column)) { + selectParts.add(column); + } else { + selectParts.add("NULL AS \"" + field + "\""); + } + } + if (selectParts.isEmpty()) { + selectParts.add("t.stcd AS \"stcd\""); + } + return String.join(", ", selectParts); + } + + private Map buildSelectMap() { + Map columnMap = new LinkedHashMap<>(); + columnMap.put("id", "t.id AS \"id\""); + columnMap.put("stcd", "t.stcd AS \"stcd\""); + columnMap.put("stnm", "t.stnm AS \"stnm\""); + columnMap.put("sttp", "t.sttp AS \"sttp\""); + columnMap.put("sttpCode", "t.sttpCode AS \"sttpCode\""); + columnMap.put("sttpName", "t.sttpName AS \"sttpName\""); + columnMap.put("sttpFullPath", "t.sttpFullPath AS \"sttpFullPath\""); + columnMap.put("sttpTreeLevel", "t.sttpTreeLevel AS \"sttpTreeLevel\""); + columnMap.put("blprdId", "t.blprdId AS \"blprdId\""); + columnMap.put("lgtd", "t.lgtd AS \"lgtd\""); + columnMap.put("lttd", "t.lttd AS \"lttd\""); + columnMap.put("dtmel", "t.dtmel AS \"dtmel\""); + columnMap.put("stlc", "t.stlc AS \"stlc\""); + columnMap.put("usfl", "t.usfl AS \"usfl\""); + columnMap.put("rstcd", "t.rstcd AS \"rstcd\""); + columnMap.put("ennm", "t.ennm AS \"ennm\""); + columnMap.put("baseId", "t.baseId AS \"baseId\""); + columnMap.put("baseName", "t.baseName AS \"baseName\""); + columnMap.put("hbrvcd", "t.hbrvcd AS \"hbrvcd\""); + columnMap.put("hbrvcdName", "t.hbrvcdName AS \"hbrvcdName\""); + columnMap.put("rvcd", "t.rvcd AS \"rvcd\""); + columnMap.put("rvcdName", "t.rvcdName AS \"rvcdName\""); + columnMap.put("addvcd", "t.addvcd AS \"addvcd\""); + columnMap.put("addvcdName", "t.addvcdName AS \"addvcdName\""); + columnMap.put("country", "t.country AS \"country\""); + columnMap.put("countryName", "t.countryName AS \"countryName\""); + columnMap.put("stCode", "t.stCode AS \"stCode\""); + columnMap.put("stName", "t.stName AS \"stName\""); + columnMap.put("stdsdt", "t.stdsdt AS \"stdsdt\""); + columnMap.put("pststdt", "t.pststdt AS \"pststdt\""); + columnMap.put("pesstdt", "t.pesstdt AS \"pesstdt\""); + columnMap.put("ststdt", "t.ststdt AS \"ststdt\""); + columnMap.put("jcdt", "t.jcdt AS \"jcdt\""); + columnMap.put("stwddt", "t.stwddt AS \"stwddt\""); + columnMap.put("introduce", "t.introduce AS \"introduce\""); + columnMap.put("precis", "t.precis AS \"precis\""); + columnMap.put("logo", "t.logo AS \"logo\""); + columnMap.put("inffile", "t.inffile AS \"inffile\""); + columnMap.put("dtin", "t.dtin AS \"dtin\""); + columnMap.put("dtinName", "t.dtinName AS \"dtinName\""); + columnMap.put("dtinTm", "t.dtinTm AS \"dtinTm\""); + columnMap.put("bldsttCode", "t.bldsttCode AS \"bldsttCode\""); + columnMap.put("bldsttCcode", "t.bldsttCcode AS \"bldsttCcode\""); + columnMap.put("bldsttCcodeName", "t.bldsttCcodeName AS \"bldsttCcodeName\""); + columnMap.put("inv", "t.inv AS \"inv\""); + columnMap.put("invinmn", "t.invinmn AS \"invinmn\""); + columnMap.put("dsun", "t.dsun AS \"dsun\""); + columnMap.put("jbtxcs", "t.jbtxcs AS \"jbtxcs\""); + columnMap.put("dtfrqcy", "t.dtfrqcy AS \"dtfrqcy\""); + columnMap.put("remark", "t.remark AS \"remark\""); + columnMap.put("vlsr", "t.vlsr AS \"vlsr\""); + columnMap.put("vlsrTm", "t.vlsrTm AS \"vlsrTm\""); + columnMap.put("orderIndex", "t.orderIndex AS \"orderIndex\""); + columnMap.put("baseStepSort", "t.baseStepSort AS \"baseStepSort\""); + columnMap.put("rvcdStepSort", "t.rvcdStepSort AS \"rvcdStepSort\""); + columnMap.put("rstcdStepSort", "t.rstcdStepSort AS \"rstcdStepSort\""); + columnMap.put("siteStepSort", "t.siteStepSort AS \"siteStepSort\""); + return columnMap; + } + + private String buildFilterCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + if (filter == null) { + return ""; + } + if (StrUtil.isNotBlank(filter.getField())) { + return buildLeafCondition(filter, paramMap, indexHolder); + } + if (CollUtil.isEmpty(filter.getFilters())) { + return ""; + } + List conditions = new ArrayList<>(); + for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) { + String childSql = buildFilterCondition(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 buildLeafCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + String field = filter.getField(); + if (StrUtil.isBlank(field)) { + return ""; + } + String operator = StrUtil.blankToDefault(filter.getOperator(), "eq").toLowerCase(); + String column = mapFilterColumn(field); + if (StrUtil.isBlank(column)) { + return ""; + } + if ("isnull".equals(operator)) { + return column + " IS NULL"; + } + if ("isnotnull".equals(operator)) { + return column + " IS NOT NULL"; + } + if ("isempty".equals(operator)) { + return "(" + column + " IS NULL OR " + column + " = '')"; + } + if ("isnotempty".equals(operator)) { + return "(" + column + " IS NOT NULL AND " + column + " <> '')"; + } + if ("in".equals(operator) || "ni".equals(operator)) { + List values = normalizeValues(filter.getValue()); + if (values.isEmpty()) { + return ""; + } + List placeholders = new ArrayList<>(); + for (Object item : values) { + String key = "overviewP" + indexHolder[0]++; + paramMap.put(key, item); + placeholders.add("#{map." + key + "}"); + } + if (placeholders.isEmpty()) { + return ""; + } + return column + ("ni".equals(operator) ? " NOT IN (" : " IN (") + String.join(", ", placeholders) + ")"; + } + Object value = filter.getValue(); + if (value == null) { + return ""; + } + String key = "overviewP" + indexHolder[0]++; + return switch (operator) { + case "eq" -> { + paramMap.put(key, value); + yield column + " = #{map." + key + "}"; + } + case "neq" -> { + paramMap.put(key, value); + yield column + " <> #{map." + key + "}"; + } + case "contains" -> { + paramMap.put(key, "%" + value + "%"); + yield column + " LIKE #{map." + key + "}"; + } + case "doesnotcontain" -> { + paramMap.put(key, "%" + value + "%"); + yield column + " NOT 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 + " > #{map." + key + "}"; + } + case "gte" -> { + paramMap.put(key, value); + yield column + " >= #{map." + key + "}"; + } + case "lt" -> { + paramMap.put(key, value); + yield column + " < #{map." + key + "}"; + } + case "lte" -> { + paramMap.put(key, value); + yield column + " <= #{map." + key + "}"; + } + default -> ""; + }; + } + + private String mapFilterColumn(String field) { + if (StrUtil.isBlank(field)) { + return null; + } + return switch (field) { + case "id" -> "t.id"; + case "stcd" -> "t.stcd"; + case "stnm" -> "t.stnm"; + case "sttp" -> "t.sttp"; + case "sttpCode" -> "t.sttpCode"; + case "sttpName" -> "t.sttpName"; + case "sttpFullPath" -> "t.sttpFullPath"; + case "sttpTreeLevel" -> "t.sttpTreeLevel"; + case "blprdId" -> "t.blprdId"; + case "lgtd" -> "t.lgtd"; + case "lttd" -> "t.lttd"; + case "dtmel" -> "t.dtmel"; + case "stlc" -> "t.stlc"; + case "usfl" -> "t.usfl"; + case "rstcd" -> "t.rstcd"; + case "ennm" -> "t.ennm"; + case "baseId" -> "t.baseId"; + case "baseName" -> "t.baseName"; + case "hbrvcd" -> "t.hbrvcd"; + case "hbrvcdName" -> "t.hbrvcdName"; + case "rvcd" -> "t.rvcd"; + case "rvcdName" -> "t.rvcdName"; + case "addvcd" -> "t.addvcd"; + case "addvcdName" -> "t.addvcdName"; + case "country" -> "t.country"; + case "countryName" -> "t.countryName"; + case "stCode" -> "t.stCode"; + case "stName" -> "t.stName"; + case "introduce" -> "t.introduce"; + case "precis" -> "t.precis"; + case "logo" -> "t.logo"; + case "inffile" -> "t.inffile"; + case "dtin" -> "t.dtin"; + case "dtinName" -> "t.dtinName"; + case "dtinTm" -> "t.dtinTm"; + case "bldsttCode" -> "t.bldsttCode"; + case "bldsttCcode" -> "t.bldsttCcode"; + case "bldsttCcodeName" -> "t.bldsttCcodeName"; + case "inv" -> "t.inv"; + case "invinmn" -> "t.invinmn"; + case "dsun" -> "t.dsun"; + case "jbtxcs" -> "t.jbtxcs"; + case "dtfrqcy" -> "t.dtfrqcy"; + case "remark" -> "t.remark"; + case "vlsr" -> "t.vlsr"; + case "vlsrTm" -> "t.vlsrTm"; + case "orderIndex" -> "t.orderIndex"; + case "baseStepSort" -> "t.baseStepSort"; + case "rvcdStepSort" -> "t.rvcdStepSort"; + case "rstcdStepSort" -> "t.rstcdStepSort"; + case "siteStepSort" -> "t.siteStepSort"; + case "stdsdt" -> "t.stdsdt"; + case "pststdt" -> "t.pststdt"; + case "pesstdt" -> "t.pesstdt"; + case "ststdt" -> "t.ststdt"; + case "jcdt" -> "t.jcdt"; + case "stwddt" -> "t.stwddt"; + default -> null; + }; + } + + private String buildOrderBySql(List sortList) { + if (CollUtil.isEmpty(sortList)) { + return " ORDER BY t.baseStepSort ASC, t.rvcdStepSort ASC, t.rstcdStepSort ASC, t.siteStepSort ASC, t.stnm ASC"; + } + List orderItems = new ArrayList<>(); + for (DataSourceRequest.SortDescriptor sort : sortList) { + if (sort == null || StrUtil.isBlank(sort.getField())) { + continue; + } + String column = mapFilterColumn(sort.getField()); + if (StrUtil.isBlank(column)) { + continue; + } + String dir = "desc".equalsIgnoreCase(sort.getDir()) || "des".equalsIgnoreCase(sort.getDir()) ? "DESC" : "ASC"; + orderItems.add(column + " " + dir + " NULLS LAST"); + } + if (orderItems.isEmpty()) { + return " ORDER BY t.baseStepSort ASC, t.rvcdStepSort ASC, t.rstcdStepSort ASC, t.siteStepSort ASC, t.stnm ASC"; + } + return " ORDER BY " + String.join(", ", orderItems); + } + + private Integer resolveOpedStateYear() { + return Year.now().getValue(); + } + + private String buildOpedDetailSql(List selectFields, String filterSql) { + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append(buildOpedSelectSql(selectFields)) + .append(" FROM (") + .append(buildOpedBaseSql()) + .append(") t WHERE 1 = 1 "); + if (StrUtil.isNotBlank(filterSql)) { + sql.append(" AND ").append(filterSql); + } + return sql.toString(); + } + + private String buildOpedBaseSql() { + return "SELECT " + + "src.sttpCode AS repCode, " + + "src.sttpName AS sttpName, " + + "src.baseId AS baseId, " + + "src.stcd AS stcd, " + + "src.stnm AS stnm, " + + "src.sttpCode AS sttpCode, " + + "src.baseName AS baseName, " + + "src.rstcd AS rstcd, " + + "src.ennm AS ennm, " + + "CAST(NULL AS VARCHAR2(255)) AS addvcdName, " + + "CAST(NULL AS VARCHAR2(255)) AS rvcdName, " + + "src.bldsttCcode AS bldsttCcode, " + + "src.bldsttCcodeName AS bldsttCcodeName, " + + "src.dtinTm AS dtinTm, " + + "src.dtin AS dtin, " + + "src.dtinName AS dtinName, " + + "state.RUN_STATE AS runState, " + + "CASE WHEN state.RUN_STATE = 1 THEN '运行中' " + + "WHEN state.RUN_STATE IN (0, 2) THEN '未运行' ELSE NULL END AS runStateName, " + + "state.STD_STATE AS stdState, " + + "CASE WHEN state.STD_STATE = 1 THEN '达标' " + + "WHEN state.STD_STATE = 2 THEN '无数据' " + + "WHEN state.STD_STATE IN (0, 3) THEN '未达标' ELSE NULL END AS stdStateName, " + + "state.STD_SSTATE AS stdSstate, " + + "CASE WHEN state.STD_SSTATE = 1 THEN '正常运行' " + + "WHEN state.STD_SSTATE IN (0, 2) THEN '暂无数据' " + + "WHEN state.STD_SSTATE = 3 THEN '未正常运行' ELSE NULL END AS stdSstateName, " + + "state.STD_SSTATE AS runSstate, " + + "CASE WHEN state.STD_SSTATE = 1 THEN '正常运行' " + + "WHEN state.STD_SSTATE IN (0, 2) THEN '暂无数据' " + + "WHEN state.STD_SSTATE = 3 THEN '未正常运行' ELSE NULL END AS runSstateName, " + + "CAST(NULL AS NUMBER(10)) AS mway, " + + "CAST(NULL AS VARCHAR2(32)) AS mwayName, " + + "src.hbrvcd AS hbrvcd, " + + "src.hbrvcdName AS hbrvcdName, " + + "src.baseStepSort AS baseStepSort, " + +// "src.baseStepSort AS baseStepsort, " + + "src.rvcdStepSort AS rvcdStepSort, " + + "src.rstcdStepSort AS rstcdStepSort, " + +// "src.rstcdStepSort AS rstcdStepsort, " + + "src.siteStepSort AS siteStepSort " + +// "#{map.stateYear} AS yr " + + "FROM (" + buildOpedUnionSql() + ") src " + + "LEFT JOIN MS_STSTATE_T state ON state.STCD = src.stcd " + + "AND NVL(state.IS_DELETED, 0) = 0 " + + "AND state.YR = #{map.stateYear}"; + } + + private String buildOpedUnionSql() { + return buildOpedBranchSql( + "fb.STCD", "fb.STNM", "'FB'", "child.STTP_NAME", "NVL(fb.BASE_ID, eng.BASE_ID)", + "hb.BASENAME", "fb.RSTCD", "eng.ENNM", "NVL(fb.HBRVCD, eng.HBRVCD)", "hbrv.HBRVNM", + "CAST(fb.BLDSTT_CODE AS VARCHAR2(10))", buildBldsttNameExpr("fb.BLDSTT_CODE"), "fb.DTIN_TM", "fb.DTIN", + "CASE WHEN NVL(fb.DTIN, 0) = 1 THEN '已接入' ELSE '未接入' END", + "NVL(hb.ORDER_INDEX, 999999)", "NVL(hbrv.ORDER_INDEX, 999999)", "NVL(eng.ORDER_INDEX, 999999)", "NVL(fb.ORDER_INDEX, 999999)", + "SD_FBRD_B_H fb", + "LEFT JOIN SD_STTP_B child ON child.STTP_CODE = fb.STTP AND NVL(child.IS_DELETED, 0) = 0 AND NVL(child.ENABLE, 1) = 1 " + + "LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fb.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = NVL(fb.BASE_ID, eng.BASE_ID) AND NVL(hb.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = NVL(fb.HBRVCD, eng.HBRVCD) AND hbrv.BASEID = NVL(fb.BASE_ID, eng.BASE_ID) " + + "AND NVL(hbrv.IS_DELETED, 0) = 0 AND NVL(hbrv.ENABLED, 1) = 1", + "1 = 1" + ) + " UNION ALL " + + buildOpedBranchSql( + "vp.STCD", "vp.STNM", "'VP'", "child.STTP_NAME", "NVL(vp.BASE_ID, eng.BASE_ID)", + "hb.BASENAME", "vp.RSTCD", "eng.ENNM", "NVL(vp.HBRVCD, eng.HBRVCD)", "hbrv.HBRVNM", + "CAST(vp.BLDSTT_CODE AS VARCHAR2(10))", buildBldsttNameExpr("vp.BLDSTT_CODE"), "vp.DTIN_TM", "vp.DTIN", + "CASE WHEN NVL(vp.DTIN, 0) = 1 THEN '已接入' ELSE '未接入' END", + "NVL(hb.ORDER_INDEX, 999999)", "NVL(hbrv.ORDER_INDEX, 999999)", "NVL(eng.ORDER_INDEX, 999999)", "NVL(vp.ORDER_INDEX, 999999)", + "SD_VP_B_H vp", + "LEFT JOIN SD_STTP_B child ON child.STTP_CODE = vp.STTP AND NVL(child.IS_DELETED, 0) = 0 AND NVL(child.ENABLE, 1) = 1 " + + "LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = vp.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = NVL(vp.BASE_ID, eng.BASE_ID) AND NVL(hb.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = NVL(vp.HBRVCD, eng.HBRVCD) AND hbrv.BASEID = NVL(vp.BASE_ID, eng.BASE_ID) " + + "AND NVL(hbrv.IS_DELETED, 0) = 0 AND NVL(hbrv.ENABLED, 1) = 1", + "NVL(vp.IS_DELETED, 0) = 0" + ) + " UNION ALL " + + buildOpedBranchSql( + "va.STCD", "va.STNM", "'VA'", "child.STTP_NAME", "NVL(va.BASE_ID, eng.BASE_ID)", + "hb.BASENAME", "va.RSTCD", "eng.ENNM", "NVL(va.HBRVCD, eng.HBRVCD)", "hbrv.HBRVNM", + "CAST(va.BLDSTT_CODE AS VARCHAR2(10))", buildBldsttNameExpr("va.BLDSTT_CODE"), "va.DTIN_TM", "va.DTIN", + "CASE WHEN NVL(va.DTIN, 0) = 1 THEN '已接入' ELSE '未接入' END", + "NVL(hb.ORDER_INDEX, 999999)", "NVL(hbrv.ORDER_INDEX, 999999)", "NVL(eng.ORDER_INDEX, 999999)", "NVL(va.ORDER_INDEX, 999999)", + "SD_VA_B_H va", + "LEFT JOIN SD_STTP_B child ON child.STTP_CODE = va.STTP AND NVL(child.IS_DELETED, 0) = 0 AND NVL(child.ENABLE, 1) = 1 " + + "LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = va.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = NVL(va.BASE_ID, eng.BASE_ID) AND NVL(hb.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = NVL(va.HBRVCD, eng.HBRVCD) AND hbrv.BASEID = NVL(va.BASE_ID, eng.BASE_ID) " + + "AND NVL(hbrv.IS_DELETED, 0) = 0 AND NVL(hbrv.ENABLED, 1) = 1", + "NVL(va.IS_DELETED, 0) = 0" + ) + " UNION ALL " + + buildOpedBranchSql( + "fh.STCD", "fh.STNM", "'FH'", "child.STTP_NAME", "NVL(fh.BASE_ID, eng.BASE_ID)", + "hb.BASENAME", "fh.RSTCD", "eng.ENNM", "NVL(fh.HBRVCD, eng.HBRVCD)", "hbrv.HBRVNM", + "CAST(NULL AS VARCHAR2(10))", "CAST(NULL AS VARCHAR2(32))", "fh.DTIN_TM", "fh.DTIN", + "CASE WHEN NVL(fh.DTIN, 0) = 1 THEN '已接入' ELSE '未接入' END", + "NVL(hb.ORDER_INDEX, 999999)", "NVL(hbrv.ORDER_INDEX, 999999)", "NVL(eng.ORDER_INDEX, 999999)", "NVL(fh.ORDER_INDEX, 999999)", + "SD_FHBT_B_H fh", + "LEFT JOIN SD_STTP_B child ON child.STTP_CODE = 'FH' AND NVL(child.IS_DELETED, 0) = 0 AND NVL(child.ENABLE, 1) = 1 " + + "LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fh.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = NVL(fh.BASE_ID, eng.BASE_ID) AND NVL(hb.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = NVL(fh.HBRVCD, eng.HBRVCD) AND hbrv.BASEID = NVL(fh.BASE_ID, eng.BASE_ID) " + + "AND NVL(hbrv.IS_DELETED, 0) = 0 AND NVL(hbrv.ENABLED, 1) = 1", + "NVL(fh.IS_DELETED, 0) = 0" + ) + " UNION ALL " + + buildOpedBranchSql( + "dw.STCD", "dw.STNM", "'DW'", "child.STTP_NAME", "NVL(dw.BASE_ID, eng.BASE_ID)", + "hb.BASENAME", "dw.RSTCD", "eng.ENNM", "NVL(dw.HBRVCD, eng.HBRVCD)", "hbrv.HBRVNM", + "CAST(dw.BLDSTT_CODE AS VARCHAR2(10))", buildBldsttNameExpr("dw.BLDSTT_CODE"), "dw.DTIN_TM", "dw.DTIN", + "CASE WHEN NVL(dw.DTIN, 0) = 1 THEN '已接入' ELSE '未接入' END", + "NVL(hb.ORDER_INDEX, 999999)", "NVL(hbrv.ORDER_INDEX, 999999)", "NVL(eng.ORDER_INDEX, 999999)", "NVL(dw.ORDER_INDEX, 999999)", + "SD_DW_B_H dw", + "LEFT JOIN SD_STTP_B child ON child.STTP_CODE = dw.STTP AND NVL(child.IS_DELETED, 0) = 0 AND NVL(child.ENABLE, 1) = 1 " + + "LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = dw.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = NVL(dw.BASE_ID, eng.BASE_ID) AND NVL(hb.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = NVL(dw.HBRVCD, eng.HBRVCD) AND hbrv.BASEID = NVL(dw.BASE_ID, eng.BASE_ID) " + + "AND NVL(hbrv.IS_DELETED, 0) = 0 AND NVL(hbrv.ENABLED, 1) = 1", + "NVL(dw.IS_DELETED, 0) = 0" + ) + " UNION ALL " + + buildOpedBranchSql( + "fp.STCD", "fp.STNM", "'FP'", "child.STTP_NAME", "eng.BASE_ID", + "hb.BASENAME", "fp.RSTCD", "eng.ENNM", "eng.HBRVCD", "hbrv.HBRVNM", + "CAST(fp.BLDSTT_CODE AS VARCHAR2(10))", buildBldsttNameExpr("fp.BLDSTT_CODE"), "fp.DTIN_TM", "fp.DTIN", + "CASE WHEN NVL(fp.DTIN, 0) = 1 THEN '已接入' ELSE '未接入' END", + "NVL(hb.ORDER_INDEX, 999999)", "NVL(hbrv.ORDER_INDEX, 999999)", "NVL(eng.ORDER_INDEX, 999999)", "NVL(fp.ORDER_INDEX, 999999)", + "SD_FPSS_B_H fp", + "LEFT JOIN SD_STTP_B child ON child.STTP_CODE = fp.STTP AND NVL(child.IS_DELETED, 0) = 0 AND NVL(child.ENABLE, 1) = 1 " + + "LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fp.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", + "1 = 1 AND fp.STTP LIKE 'FP\\_%' ESCAPE '\\' " + ) + " UNION ALL " + + buildOpedBranchSql( + "eq.STCD", "eq.STNM", "'EQ'", "child.STTP_NAME", "NVL(eq.BASE_ID, eng.BASE_ID)", + "hb.BASENAME", "eq.RSTCD", "eng.ENNM", "NVL(eq.HBRVCD, eng.HBRVCD)", "hbrv.HBRVNM", + "CAST(eq.BLDSTT_CODE AS VARCHAR2(10))", buildBldsttNameExpr("eq.BLDSTT_CODE"), "eq.DTIN_TM", "eq.DTIN", + "CASE WHEN NVL(eq.DTIN, 0) = 1 THEN '已接入' ELSE '未接入' END", + "NVL(hb.ORDER_INDEX, 999999)", "NVL(hbrv.ORDER_INDEX, 999999)", "NVL(eng.ORDER_INDEX, 999999)", "NVL(eq.ORDER_INDEX, 999999)", + "SD_EQ_B_H eq", + "LEFT JOIN SD_STTP_B child ON child.STTP_CODE = eq.STTP AND NVL(child.IS_DELETED, 0) = 0 AND NVL(child.ENABLE, 1) = 1 " + + "LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = eq.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = NVL(eq.BASE_ID, eng.BASE_ID) AND NVL(hb.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = NVL(eq.HBRVCD, eng.HBRVCD) AND hbrv.BASEID = NVL(eq.BASE_ID, eng.BASE_ID) " + + "AND NVL(hbrv.IS_DELETED, 0) = 0 AND NVL(hbrv.ENABLED, 1) = 1", + "NVL(eq.IS_DELETED, 0) = 0" + ); + } + + private String buildOpedBranchSql(String stcdExpr, + String stnmExpr, + String sttpCodeExpr, + String sttpNameExpr, + String baseIdExpr, + String baseNameExpr, + String rstcdExpr, + String ennmExpr, + String hbrvcdExpr, + String hbrvcdNameExpr, + String bldsttExpr, + String bldsttNameExpr, + String dtinTmExpr, + String dtinExpr, + String dtinNameExpr, + String baseStepSortExpr, + String rvcdStepSortExpr, + String rstcdStepSortExpr, + String siteStepSortExpr, + String fromSql, + String joinSql, + String whereSql) { + return "SELECT " + + sttpNameExpr + " AS sttpName, " + + baseIdExpr + " AS baseId, " + + stcdExpr + " AS stcd, " + + stnmExpr + " AS stnm, " + + sttpCodeExpr + " AS sttpCode, " + + baseNameExpr + " AS baseName, " + + rstcdExpr + " AS rstcd, " + + ennmExpr + " AS ennm, " + + bldsttExpr + " AS bldsttCcode, " + + bldsttNameExpr + " AS bldsttCcodeName, " + + dtinTmExpr + " AS dtinTm, " + + dtinExpr + " AS dtin, " + + dtinNameExpr + " AS dtinName, " + + hbrvcdExpr + " AS hbrvcd, " + + hbrvcdNameExpr + " AS hbrvcdName, " + + baseStepSortExpr + " AS baseStepSort, " + + rvcdStepSortExpr + " AS rvcdStepSort, " + + rstcdStepSortExpr + " AS rstcdStepSort, " + + siteStepSortExpr + " AS siteStepSort " + + "FROM " + fromSql + " " + joinSql + " WHERE " + whereSql; + } + + private String buildBldsttNameExpr(String column) { + return "CASE " + column + " WHEN 0 THEN '未建/规划' WHEN 1 THEN '在建' WHEN 2 THEN '已建' ELSE NULL END"; + } + + private List resolveOpedSelectFields(List select) { + List fields = CollUtil.isEmpty(select) + ? new ArrayList<>(buildOpedSelectMap().keySet()) + : new ArrayList<>(select); + LinkedHashSet uniqueFields = new LinkedHashSet<>(); + for (String field : fields) { + if (StrUtil.isNotBlank(field)) { + uniqueFields.add(field.trim()); + } + } + if (uniqueFields.isEmpty()) { + uniqueFields.add("stcd"); + } + return new ArrayList<>(uniqueFields); + } + + private String buildOpedSelectSql(List selectFields) { + Map columnMap = buildOpedSelectMap(); + List selectParts = new ArrayList<>(); + for (String field : resolveOpedSelectFields(selectFields)) { + String column = columnMap.get(field); + if (StrUtil.isNotBlank(column)) { + selectParts.add(column); + } else { + selectParts.add("NULL AS \"" + field + "\""); + } + } + return String.join(", ", selectParts); + } + + private Map buildOpedSelectMap() { + Map columnMap = new LinkedHashMap<>(); + columnMap.put("repCode", "t.repCode AS \"repCode\""); + columnMap.put("sttpName", "t.sttpName AS \"sttpName\""); + columnMap.put("baseId", "t.baseId AS \"baseId\""); + columnMap.put("stcd", "t.stcd AS \"stcd\""); + columnMap.put("stnm", "t.stnm AS \"stnm\""); + columnMap.put("sttpCode", "t.sttpCode AS \"sttpCode\""); + columnMap.put("baseName", "t.baseName AS \"baseName\""); + columnMap.put("rstcd", "t.rstcd AS \"rstcd\""); + columnMap.put("ennm", "t.ennm AS \"ennm\""); + columnMap.put("addvcdName", "t.addvcdName AS \"addvcdName\""); + columnMap.put("rvcdName", "t.rvcdName AS \"rvcdName\""); + columnMap.put("bldsttCcode", "t.bldsttCcode AS \"bldsttCcode\""); + columnMap.put("bldsttCcodeName", "t.bldsttCcodeName AS \"bldsttCcodeName\""); + columnMap.put("dtinTm", "t.dtinTm AS \"dtinTm\""); + columnMap.put("dtin", "t.dtin AS \"dtin\""); + columnMap.put("dtinName", "t.dtinName AS \"dtinName\""); + columnMap.put("runState", "t.runState AS \"runState\""); + columnMap.put("runStateName", "t.runStateName AS \"runStateName\""); + columnMap.put("stdState", "t.stdState AS \"stdState\""); + columnMap.put("stdStateName", "t.stdStateName AS \"stdStateName\""); + columnMap.put("stdSstate", "t.stdSstate AS \"stdSstate\""); + columnMap.put("stdSstateName", "t.stdSstateName AS \"stdSstateName\""); + columnMap.put("runSstate", "t.runSstate AS \"runSstate\""); + columnMap.put("runSstateName", "t.runSstateName AS \"runSstateName\""); + columnMap.put("mway", "t.mway AS \"mway\""); + columnMap.put("mwayName", "t.mwayName AS \"mwayName\""); + columnMap.put("hbrvcd", "t.hbrvcd AS \"hbrvcd\""); + columnMap.put("hbrvcdName", "t.hbrvcdName AS \"hbrvcdName\""); + columnMap.put("baseStepSort", "t.baseStepSort AS \"baseStepSort\""); +// columnMap.put("baseStepsort", "t.baseStepsort AS \"baseStepsort\""); + columnMap.put("rvcdStepSort", "t.rvcdStepSort AS \"rvcdStepSort\""); + columnMap.put("rstcdStepSort", "t.rstcdStepSort AS \"rstcdStepSort\""); +// columnMap.put("rstcdStepsort", "t.rstcdStepsort AS \"rstcdStepsort\""); + columnMap.put("siteStepSort", "t.siteStepSort AS \"siteStepSort\""); +// columnMap.put("yr", "t.yr AS \"yr\""); + return columnMap; + } + + private String buildOpedFilterCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + if (filter == null) { + return ""; + } + if (StrUtil.isNotBlank(filter.getField())) { + return buildOpedLeafCondition(filter, paramMap, indexHolder); + } + if (CollUtil.isEmpty(filter.getFilters())) { + return ""; + } + List conditions = new ArrayList<>(); + for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) { + String childSql = buildOpedFilterCondition(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 buildOpedEffectiveFilterCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + if (filter == null) { + return ""; + } + if (StrUtil.isNotBlank(filter.getField())) { + if ("1".equals(StrUtil.trim(filter.getField()))) { + return ""; + } + return buildOpedLeafCondition(filter, paramMap, indexHolder); + } + if (CollUtil.isEmpty(filter.getFilters())) { + return ""; + } + List conditions = new ArrayList<>(); + for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) { + String childSql = buildOpedEffectiveFilterCondition(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 buildOpedLeafCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + String field = filter.getField(); + if (StrUtil.isBlank(field) || "yr".equals(field)) { + return ""; + } + String operator = StrUtil.blankToDefault(filter.getOperator(), "eq").toLowerCase(); + String column = mapOpedColumn(field); + if (StrUtil.isBlank(column)) { + return ""; + } + if ("isnull".equals(operator)) { + return column + " IS NULL"; + } + if ("isnotnull".equals(operator)) { + return column + " IS NOT NULL"; + } + if ("isempty".equals(operator)) { + return "(" + column + " IS NULL OR " + column + " = '')"; + } + if ("isnotempty".equals(operator)) { + return "(" + column + " IS NOT NULL AND " + column + " <> '')"; + } + if ("in".equals(operator) || "ni".equals(operator)) { + List values = normalizeValues(filter.getValue()); + if (values.isEmpty()) { + return ""; + } + List placeholders = new ArrayList<>(); + for (Object item : values) { + String key = "opedP" + indexHolder[0]++; + paramMap.put(key, item); + placeholders.add("#{map." + key + "}"); + } + return column + ("ni".equals(operator) ? " NOT IN (" : " IN (") + String.join(", ", placeholders) + ")"; + } + + Object value = filter.getValue(); + if (value == null) { + return ""; + } + String key = "opedP" + indexHolder[0]++; + boolean dateField = isOpedDateField(field); + String placeholder = dateField + ? "TO_DATE(#{map." + key + "}, 'YYYY-MM-DD HH24:MI:SS')" + : "#{map." + key + "}"; + paramMap.put(key, value); + return switch (operator) { + case "eq" -> column + " = " + placeholder; + case "neq" -> column + " <> " + placeholder; + case "contains" -> { + paramMap.put(key, "%" + value + "%"); + yield dateField + ? "TO_CHAR(" + column + ", 'YYYY-MM-DD HH24:MI:SS') LIKE #{map." + key + "}" + : column + " LIKE #{map." + key + "}"; + } + case "doesnotcontain" -> { + paramMap.put(key, "%" + value + "%"); + yield dateField + ? "TO_CHAR(" + column + ", 'YYYY-MM-DD HH24:MI:SS') NOT LIKE #{map." + key + "}" + : column + " NOT LIKE #{map." + key + "}"; + } + case "startswith" -> { + paramMap.put(key, value + "%"); + yield dateField + ? "TO_CHAR(" + column + ", 'YYYY-MM-DD HH24:MI:SS') LIKE #{map." + key + "}" + : column + " LIKE #{map." + key + "}"; + } + case "endswith" -> { + paramMap.put(key, "%" + value); + yield dateField + ? "TO_CHAR(" + column + ", 'YYYY-MM-DD HH24:MI:SS') LIKE #{map." + key + "}" + : column + " LIKE #{map." + key + "}"; + } + case "gt" -> column + " > " + placeholder; + case "gte" -> column + " >= " + placeholder; + case "lt" -> column + " < " + placeholder; + case "lte" -> column + " <= " + placeholder; + default -> ""; + }; + } + + private boolean isOpedDateField(String field) { + return "dtinTm".equals(field); + } + + private String mapOpedColumn(String field) { + if (StrUtil.isBlank(field)) { + return null; + } + return switch (field) { + case "sttpName" -> "t.sttpName"; + case "baseId" -> "t.baseId"; + case "stcd" -> "t.stcd"; + case "stnm" -> "t.stnm"; + case "sttpCode" -> "t.sttpCode"; + case "baseName" -> "t.baseName"; + case "rstcd" -> "t.rstcd"; + case "ennm" -> "t.ennm"; + case "bldsttCcode" -> "t.bldsttCcode"; + case "bldsttCcodeName" -> "t.bldsttCcodeName"; + case "dtinTm" -> "t.dtinTm"; + case "dtin" -> "t.dtin"; + case "dtinName" -> "t.dtinName"; + case "runState" -> "t.runState"; + case "runStateName" -> "t.runStateName"; + case "stdState" -> "t.stdState"; + case "stdStateName" -> "t.stdStateName"; + case "stdSstate" -> "t.stdSstate"; + case "stdSstateName" -> "t.stdSstateName"; + case "mway" -> "t.mway"; + case "mwayName" -> "t.mwayName"; + case "hbrvcd" -> "t.hbrvcd"; + case "hbrvcdName" -> "t.hbrvcdName"; + case "baseStepSort", "baseStepsort" -> "t.baseStepSort"; + case "rvcdStepSort" -> "t.rvcdStepSort"; + case "rstcdStepSort", "rstcdStepsort" -> "t.rstcdStepSort"; + case "siteStepSort" -> "t.siteStepSort"; + case "yr" -> "t.yr"; + default -> null; + }; + } + + private String buildOpedOrderBySql(List sortList) { + if (CollUtil.isEmpty(sortList)) { + return " ORDER BY t.baseStepSort ASC NULLS LAST, t.rvcdStepSort ASC NULLS LAST, " + + "t.rstcdStepSort ASC NULLS LAST, t.siteStepSort ASC NULLS LAST, t.stnm ASC"; + } + List orderItems = new ArrayList<>(); + for (DataSourceRequest.SortDescriptor sort : sortList) { + if (sort == null || StrUtil.isBlank(sort.getField())) { + continue; + } + String column = mapOpedColumn(sort.getField()); + if (StrUtil.isBlank(column)) { + continue; + } + String dir = "desc".equalsIgnoreCase(sort.getDir()) || "des".equalsIgnoreCase(sort.getDir()) ? "DESC" : "ASC"; + orderItems.add(column + " " + dir + " NULLS LAST"); + } + if (orderItems.isEmpty()) { + return " ORDER BY t.baseStepSort ASC NULLS LAST, t.rvcdStepSort ASC NULLS LAST, " + + "t.rstcdStepSort ASC NULLS LAST, t.siteStepSort ASC NULLS LAST, t.stnm ASC"; + } + return " ORDER BY " + String.join(", ", orderItems); + } + + private String buildOpedGroupSql(String detailSql, GroupingInfo[] groupInfos) { + if (groupInfos == null || groupInfos.length == 0) { + return detailSql; + } + List groupFields = new ArrayList<>(); + List selectItems = new ArrayList<>(); + List orderItems = new ArrayList<>(); + for (GroupingInfo item : groupInfos) { + if (item == null || StrUtil.isBlank(item.getSelector())) { + continue; + } + String selector = item.getSelector(); + String column = mapOpedColumn(selector); + if (StrUtil.isBlank(column)) { + continue; + } + groupFields.add(column); + selectItems.add(column + " AS " + selector); + selectItems.add("COUNT(*) AS count_" + selector); + orderItems.add(column + (item.getDesc() ? " DESC" : " ASC")); + } + if (groupFields.isEmpty()) { + return "SELECT * FROM (" + detailSql + ") t WHERE 1 = 0"; + } + return "SELECT " + String.join(", ", selectItems) + + " FROM (" + detailSql + ") t GROUP BY " + String.join(", ", groupFields) + + " ORDER BY " + String.join(", ", orderItems); + } + + private boolean shouldQueryOpedSummary(DataSourceRequest dataSourceRequest) { + return dataSourceRequest != null + && CollUtil.isEmpty(dataSourceRequest.getGroup()) + && hasOnlyDummyFilter(dataSourceRequest.getFilter()); + } + + private boolean hasOnlyDummyFilter(DataSourceRequest.FilterDescriptor filter) { + return hasDummyField(filter) && !hasRealField(filter); + } + + private boolean hasDummyField(DataSourceRequest.FilterDescriptor filter) { + if (filter == null) { + return false; + } + if ("1".equals(StrUtil.trim(filter.getField()))) { + return true; + } + if (CollUtil.isEmpty(filter.getFilters())) { + return false; + } + for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) { + if (hasDummyField(child)) { + return true; + } + } + return false; + } + + private boolean hasRealField(DataSourceRequest.FilterDescriptor filter) { + if (filter == null) { + return false; + } + String field = StrUtil.trim(filter.getField()); + if (StrUtil.isNotBlank(field) && !"1".equals(field)) { + return true; + } + if (CollUtil.isEmpty(filter.getFilters())) { + return false; + } + for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) { + if (hasRealField(child)) { + return true; + } + } + return false; + } + + private String buildOpedCategorySql() { + return "SELECT 'VA' AS repCode, '动物救助站' AS sttpName, 1 AS orderIndex FROM dual " + + "UNION ALL SELECT 'FP' AS repCode, '过鱼设施' AS sttpName, 2 AS orderIndex FROM dual " + + "UNION ALL SELECT 'FB' AS repCode, '鱼类增殖站' AS sttpName, 3 AS orderIndex FROM dual " + + "UNION ALL SELECT 'DW' AS repCode, '低温水减缓设施' AS sttpName, 4 AS orderIndex FROM dual " + + "UNION ALL SELECT 'VP' AS repCode, '珍稀植物园' AS sttpName, 5 AS orderIndex FROM dual " + + "UNION ALL SELECT 'FH' AS repCode, '鱼类栖息地' AS sttpName, 6 AS orderIndex FROM dual " + + "UNION ALL SELECT 'EQ' AS repCode, '生态流量泄放设施' AS sttpName, 7 AS orderIndex FROM dual"; + } + + private String buildOpedSummarySelectSql(List selectFields) { + Map columnMap = buildOpedSummarySelectMap(); + List fields = CollUtil.isEmpty(selectFields) + ? new ArrayList<>(columnMap.keySet()) + : new ArrayList<>(selectFields); + List selectItems = new ArrayList<>(); + for (String field : fields) { + if (StrUtil.isBlank(field)) { + continue; + } + String column = columnMap.get(field.trim()); + if (StrUtil.isNotBlank(column)) { + selectItems.add(column); + } + } + if (selectItems.isEmpty()) { + selectItems.addAll(columnMap.values()); + } + return String.join(", ", selectItems); + } + + private Map buildOpedSummarySelectMap() { + Map columnMap = new LinkedHashMap<>(); + columnMap.put("id", "CAST(NULL AS VARCHAR2(64)) AS \"id\""); + columnMap.put("recordUser", "CAST(NULL AS VARCHAR2(64)) AS \"recordUser\""); + columnMap.put("recordTime", "CAST(NULL AS DATE) AS \"recordTime\""); + columnMap.put("modifyTime", "CAST(NULL AS DATE) AS \"modifyTime\""); + columnMap.put("displayRecordUser", "CAST(NULL AS VARCHAR2(128)) AS \"displayRecordUser\""); + columnMap.put("repCode", "cat.repCode AS \"repCode\""); + columnMap.put("sttpCode", "CAST(NULL AS VARCHAR2(64)) AS \"sttpCode\""); + columnMap.put("pcode", "CAST(NULL AS VARCHAR2(64)) AS \"pcode\""); + columnMap.put("pname", "CAST(NULL AS VARCHAR2(128)) AS \"pname\""); + columnMap.put("psttpName", "CAST(NULL AS VARCHAR2(128)) AS \"psttpName\""); + columnMap.put("stcd", "CAST(NULL AS VARCHAR2(64)) AS \"stcd\""); + columnMap.put("ennm", "CAST(NULL AS VARCHAR2(255)) AS \"ennm\""); + columnMap.put("stnm", "CAST(NULL AS VARCHAR2(255)) AS \"stnm\""); + columnMap.put("addvcdName", "CAST(NULL AS VARCHAR2(255)) AS \"addvcdName\""); + columnMap.put("rvcdName", "CAST(NULL AS VARCHAR2(255)) AS \"rvcdName\""); + columnMap.put("sttpName", "cat.sttpName AS \"sttpName\""); + columnMap.put("baseId", "CAST(NULL AS VARCHAR2(64)) AS \"baseId\""); + columnMap.put("dtin", "CAST(NULL AS NUMBER(10)) AS \"dtin\""); + columnMap.put("dtinName", "CAST(NULL AS VARCHAR2(32)) AS \"dtinName\""); + columnMap.put("runState", "CAST(NULL AS NUMBER(10)) AS \"runState\""); + columnMap.put("runStateName", "CAST(NULL AS VARCHAR2(32)) AS \"runStateName\""); + columnMap.put("stdState", "CAST(NULL AS NUMBER(10)) AS \"stdState\""); + columnMap.put("stdStateName", "CAST(NULL AS VARCHAR2(32)) AS \"stdStateName\""); + columnMap.put("bldsttCcode", "CAST(NULL AS VARCHAR2(10)) AS \"bldsttCcode\""); + columnMap.put("bldsttCcodeName", "CAST(NULL AS VARCHAR2(32)) AS \"bldsttCcodeName\""); + columnMap.put("count", "COUNT(src.repCode) AS \"count\""); + columnMap.put("jcdt", "CAST(NULL AS DATE) AS \"jcdt\""); + columnMap.put("runSstate", "CAST(NULL AS NUMBER(10)) AS \"runSstate\""); + columnMap.put("runSstateName", "CAST(NULL AS VARCHAR2(32)) AS \"runSstateName\""); + columnMap.put("departmentId", "CAST(NULL AS VARCHAR2(64)) AS \"departmentId\""); + columnMap.put("displayDepartment", "CAST(NULL AS VARCHAR2(255)) AS \"displayDepartment\""); + return columnMap; + } + + private String buildOpedSummaryOrderBySql(List sortList) { + if (CollUtil.isEmpty(sortList)) { + return " ORDER BY cat.orderIndex ASC, cat.repCode ASC"; + } + List orderItems = new ArrayList<>(); + for (DataSourceRequest.SortDescriptor sort : sortList) { + if (sort == null || StrUtil.isBlank(sort.getField())) { + continue; + } + String column = switch (sort.getField()) { + case "repCode" -> "cat.repCode"; + case "sttpName" -> "cat.sttpName"; + case "count" -> "COUNT(src.repCode)"; + default -> null; + }; + if (StrUtil.isBlank(column)) { + continue; + } + String dir = "desc".equalsIgnoreCase(sort.getDir()) || "des".equalsIgnoreCase(sort.getDir()) ? "DESC" : "ASC"; + orderItems.add(column + " " + dir); + } + if (orderItems.isEmpty()) { + return " ORDER BY cat.orderIndex ASC, cat.repCode ASC"; + } + return " ORDER BY " + String.join(", ", orderItems); + } + + private List normalizeValues(Object value) { + List values = new ArrayList<>(); + collectValues(value, values); + return values; + } + + private void collectValues(Object value, List values) { + if (value == null) { + return; + } + if (value instanceof List list) { + for (Object item : list) { + collectValues(item, values); + } + return; + } + if (value instanceof Object[] array) { + for (Object item : array) { + collectValues(item, values); + } + return; + } + values.add(value); + } +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wq/controller/EnvWqDataController.java b/backend/src/main/java/com/yfd/platform/qgc_env/wq/controller/EnvWqDataController.java index 6d0a35b7..9a6709aa 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wq/controller/EnvWqDataController.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wq/controller/EnvWqDataController.java @@ -2,7 +2,9 @@ package com.yfd.platform.qgc_env.wq.controller; import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.config.ResponseResult; +import com.yfd.platform.annotation.Log; import com.yfd.platform.qgc_base.entity.vo.BatchDeleteAo; +import com.yfd.platform.qgc_env.wq.entity.vo.WqOperateRequest; import com.yfd.platform.qgc_env.wq.service.EnvWqDataService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -57,13 +59,18 @@ public class EnvWqDataController { return ResponseResult.successData(envWqDataService.getDrtpKendoListCust(dataSourceRequest)); } + @Log(module = "水质统计分析", value = "修改水质小时数据") @PostMapping("/updateWqRsData") @Operation(summary = "修改水质小时数据") - public ResponseResult updateWqRsData(@RequestBody Map updateData) { - envWqDataService.updateWqRsData(updateData); + public ResponseResult updateWqRsData(@RequestBody WqOperateRequest wqOperateRequest) { + envWqDataService.updateWqRsData( + wqOperateRequest == null ? null : wqOperateRequest.getUpdateData(), + wqOperateRequest == null ? null : wqOperateRequest.getSource() + ); return ResponseResult.success(); } + @Log(module = "水质统计分析", value = "删除水质小时/日/月数据") @PostMapping("/removeKendoByIds") @Operation(summary = "删除水质小时/日/月数据") public ResponseResult removeKendoByIds(@RequestBody BatchDeleteAo batchDeleteAo) { diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wq/entity/vo/WqOperateRequest.java b/backend/src/main/java/com/yfd/platform/qgc_env/wq/entity/vo/WqOperateRequest.java new file mode 100644 index 00000000..4b7d5050 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wq/entity/vo/WqOperateRequest.java @@ -0,0 +1,13 @@ +package com.yfd.platform.qgc_env.wq.entity.vo; + +import lombok.Data; + +import java.util.Map; + +@Data +public class WqOperateRequest { + + private String source; + + private Map updateData; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wq/service/EnvWqDataService.java b/backend/src/main/java/com/yfd/platform/qgc_env/wq/service/EnvWqDataService.java index f23a3931..6a55e1da 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wq/service/EnvWqDataService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wq/service/EnvWqDataService.java @@ -39,7 +39,7 @@ public interface EnvWqDataService { DataSourceResult getStTbYsBVoKendoListCust(DataSourceRequest dataSourceRequest); - boolean updateWqRsData(Map updateData); + boolean updateWqRsData(Map updateData, String source); boolean removeKendoByIds(BatchDeleteAo batchDeleteAo); } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wq/service/impl/EnvWqDataServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/wq/service/impl/EnvWqDataServiceImpl.java index 32f2c970..e041cf54 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wq/service/impl/EnvWqDataServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wq/service/impl/EnvWqDataServiceImpl.java @@ -1,12 +1,18 @@ package com.yfd.platform.qgc_env.wq.service.impl; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.yfd.platform.common.*; import com.yfd.platform.common.exception.BizException; +import com.yfd.platform.qgc_base.domain.MsOperationLog; +import com.yfd.platform.qgc_base.domain.MsOperationLogDetail; import com.yfd.platform.qgc_base.entity.vo.BatchDeleteAo; import com.yfd.platform.qgc_base.entity.vo.DataParam; +import com.yfd.platform.qgc_base.mapper.MsOperationLogDetailMapper; +import com.yfd.platform.qgc_base.mapper.MsOperationLogMapper; import com.yfd.platform.qgc_env.wq.entity.vo.*; import com.yfd.platform.qgc_env.wq.service.EnvWqDataService; import com.yfd.platform.qgc_env.wt.entity.vo.WbsbVo; @@ -36,12 +42,114 @@ import java.util.stream.Collectors; @Service public class EnvWqDataServiceImpl implements EnvWqDataService { + private static final String WQ_HOUR_TABLE_NAME = "SD_WQ_R"; + private static final String WQ_DAY_TABLE_NAME = "SD_WQDAY_S"; + private static final String WQ_MONTH_TABLE_NAME = "SD_WQDRTP_S"; + private static final String WQ_STATION_TABLE_NAME = "SD_WQ_B_H"; + + private static final LinkedHashMap WQ_UPDATE_COLUMN_MAP = new LinkedHashMap<>(); + private static final Map WQ_FIELD_MEANING_MAP = new LinkedHashMap<>(); + static { + WQ_UPDATE_COLUMN_MAP.put("wtmp", "WTMP"); + WQ_UPDATE_COLUMN_MAP.put("ph", "PH"); + WQ_UPDATE_COLUMN_MAP.put("dox", "DOX"); + WQ_UPDATE_COLUMN_MAP.put("codmn", "CODMN"); + WQ_UPDATE_COLUMN_MAP.put("codcr", "CODCR"); + WQ_UPDATE_COLUMN_MAP.put("bod5", "BOD5"); + WQ_UPDATE_COLUMN_MAP.put("nh3n", "NH3N"); + WQ_UPDATE_COLUMN_MAP.put("tp", "TP"); + WQ_UPDATE_COLUMN_MAP.put("tn", "TN"); + WQ_UPDATE_COLUMN_MAP.put("cu", "CU"); + WQ_UPDATE_COLUMN_MAP.put("zn", "ZN"); + WQ_UPDATE_COLUMN_MAP.put("f", "F"); + WQ_UPDATE_COLUMN_MAP.put("se", "SE"); + WQ_UPDATE_COLUMN_MAP.put("ars", "ARS"); + WQ_UPDATE_COLUMN_MAP.put("hg", "HG"); + WQ_UPDATE_COLUMN_MAP.put("cd", "CD"); + WQ_UPDATE_COLUMN_MAP.put("cr6", "CR6"); + WQ_UPDATE_COLUMN_MAP.put("pb", "PB"); + WQ_UPDATE_COLUMN_MAP.put("cn", "CN"); + WQ_UPDATE_COLUMN_MAP.put("vlph", "VLPH"); + WQ_UPDATE_COLUMN_MAP.put("oil", "OIL"); + WQ_UPDATE_COLUMN_MAP.put("las", "LAS"); + WQ_UPDATE_COLUMN_MAP.put("s2", "S2"); + WQ_UPDATE_COLUMN_MAP.put("fcg", "FCG"); + WQ_UPDATE_COLUMN_MAP.put("cl", "CL"); + WQ_UPDATE_COLUMN_MAP.put("so4", "SO4"); + WQ_UPDATE_COLUMN_MAP.put("no3", "NO3"); + WQ_UPDATE_COLUMN_MAP.put("thrd", "THRD"); + WQ_UPDATE_COLUMN_MAP.put("cond", "COND"); + WQ_UPDATE_COLUMN_MAP.put("fe", "FE"); + WQ_UPDATE_COLUMN_MAP.put("mn", "MN"); + WQ_UPDATE_COLUMN_MAP.put("al", "AL"); + WQ_UPDATE_COLUMN_MAP.put("chla", "CHLA"); + WQ_UPDATE_COLUMN_MAP.put("clarity", "CLARITY"); + WQ_UPDATE_COLUMN_MAP.put("tu", "TU"); + WQ_UPDATE_COLUMN_MAP.put("cyano", "CYANO"); + WQ_UPDATE_COLUMN_MAP.put("wqgrd", "WQGRD"); + WQ_UPDATE_COLUMN_MAP.put("sfdb", "SFDB"); + WQ_UPDATE_COLUMN_MAP.put("wqSfdbhnYs", "WQ_SFDBHN_YS"); + + WQ_FIELD_MEANING_MAP.put("STCD", "站点编码"); + WQ_FIELD_MEANING_MAP.put("TM", "监测时间"); + WQ_FIELD_MEANING_MAP.put("DT", "统计日期"); + WQ_FIELD_MEANING_MAP.put("DRTP", "统计类型"); + WQ_FIELD_MEANING_MAP.put("YEAR", "年份"); + WQ_FIELD_MEANING_MAP.put("MONTH", "月份"); + WQ_FIELD_MEANING_MAP.put("WTMP", "水温"); + WQ_FIELD_MEANING_MAP.put("PH", "酸碱度"); + WQ_FIELD_MEANING_MAP.put("DOX", "溶解氧"); + WQ_FIELD_MEANING_MAP.put("CODMN", "高锰酸盐指数"); + WQ_FIELD_MEANING_MAP.put("CODCR", "化学需氧量"); + WQ_FIELD_MEANING_MAP.put("BOD5", "五日生化需氧量"); + WQ_FIELD_MEANING_MAP.put("NH3N", "氨氮"); + WQ_FIELD_MEANING_MAP.put("TP", "总磷"); + WQ_FIELD_MEANING_MAP.put("TN", "总氮"); + WQ_FIELD_MEANING_MAP.put("CU", "铜"); + WQ_FIELD_MEANING_MAP.put("ZN", "锌"); + WQ_FIELD_MEANING_MAP.put("F", "氟化物"); + WQ_FIELD_MEANING_MAP.put("SE", "硒"); + WQ_FIELD_MEANING_MAP.put("ARS", "砷"); + WQ_FIELD_MEANING_MAP.put("HG", "汞"); + WQ_FIELD_MEANING_MAP.put("CD", "镉"); + WQ_FIELD_MEANING_MAP.put("CR6", "六价铬"); + WQ_FIELD_MEANING_MAP.put("PB", "铅"); + WQ_FIELD_MEANING_MAP.put("CN", "氰化物"); + WQ_FIELD_MEANING_MAP.put("VLPH", "挥发酚"); + WQ_FIELD_MEANING_MAP.put("OIL", "石油类"); + WQ_FIELD_MEANING_MAP.put("LAS", "阴离子表面活性剂"); + WQ_FIELD_MEANING_MAP.put("S2", "硫化物"); + WQ_FIELD_MEANING_MAP.put("FCG", "粪大肠菌群"); + WQ_FIELD_MEANING_MAP.put("CL", "氯化物"); + WQ_FIELD_MEANING_MAP.put("SO4", "硫酸盐"); + WQ_FIELD_MEANING_MAP.put("NO3", "硝酸盐"); + WQ_FIELD_MEANING_MAP.put("THRD", "总硬度"); + WQ_FIELD_MEANING_MAP.put("COND", "电导率"); + WQ_FIELD_MEANING_MAP.put("FE", "铁"); + WQ_FIELD_MEANING_MAP.put("MN", "锰"); + WQ_FIELD_MEANING_MAP.put("AL", "铝"); + WQ_FIELD_MEANING_MAP.put("CHLA", "叶绿素a"); + WQ_FIELD_MEANING_MAP.put("CLARITY", "透明度"); + WQ_FIELD_MEANING_MAP.put("TU", "浊度"); + WQ_FIELD_MEANING_MAP.put("CYANO", "蓝绿藻"); + WQ_FIELD_MEANING_MAP.put("WQGRD", "水质类别"); + WQ_FIELD_MEANING_MAP.put("WWQTG", "水功能区目标"); + WQ_FIELD_MEANING_MAP.put("SFDB", "是否达标"); + WQ_FIELD_MEANING_MAP.put("WQ_SFDBHN_YS", "是否达标湖内饮用水源"); + } + @Resource private MicroservicDynamicSQLMapper microservicDynamicSQLMapper; @Resource private JdbcTemplate jdbcTemplate; + @Resource + private MsOperationLogMapper msOperationLogMapper; + + @Resource + private MsOperationLogDetailMapper msOperationLogDetailMapper; + @Override public DataSourceResult processKendoList(DataSourceRequest dataSourceRequest) { boolean calculated = CommonConstant.CALCULATE_SUCCESS.equals( @@ -3671,15 +3779,18 @@ public class EnvWqDataServiceImpl implements EnvWqDataService { @Override @Transactional(rollbackFor = Exception.class) - public boolean updateWqRsData(Map updateData) { + public boolean updateWqRsData(Map updateData, String source) { if (updateData == null || updateData.isEmpty()) { return true; } - updateWqHourData(updateData); - updateWqTargetIfNeeded(updateData); - String stcd = asString(updateData.get("stcd")); String tm = asString(updateData.get("tm")); + Map beforeHour = queryWqHourRow(stcd, tm); + Map beforeStation = queryWqStationRow(stcd); + updateWqHourData(updateData); + updateWqTargetIfNeeded(updateData); + recordWqUpdateLog(beforeHour, beforeStation, updateData, source); + if (StrUtil.isNotBlank(stcd) && StrUtil.isNotBlank(tm) && tm.length() >= 10) { String dateStr = tm.substring(0, 10); statisticsDayDataFromHour(stcd, dateStr, dateStr); @@ -3704,17 +3815,24 @@ public class EnvWqDataServiceImpl implements EnvWqDataService { return true; } String dataType = StrUtil.blankToDefault(batchDeleteAo.getDataType(), "").toUpperCase(); + String source = batchDeleteAo == null ? null : batchDeleteAo.getSource(); int batchSize = 500; for (int i = 0; i < dataList.size(); i += batchSize) { List subList = dataList.subList(i, Math.min(i + batchSize, dataList.size())); if ("MON".equals(dataType)) { + List> beforeRows = queryWqMonthRows(subList); softDeleteWqMonthData(subList); + recordWqDeleteLog(beforeRows, WQ_MONTH_TABLE_NAME, "删除水质月数据", source); } if ("DATE".equals(dataType)) { + List> beforeRows = queryWqDayRows(subList); softDeleteWqDayData(subList); + recordWqDeleteLog(beforeRows, WQ_DAY_TABLE_NAME, "删除水质日数据", source); } if ("TIME".equals(dataType)) { + List> beforeRows = queryWqHourRows(subList); deleteWqHourData(subList); + recordWqDeleteLog(beforeRows, WQ_HOUR_TABLE_NAME, "删除水质小时数据", source); Map dateRangeMap = new HashMap<>(); Map monthRangeMap = new HashMap<>(); @@ -3765,50 +3883,9 @@ public class EnvWqDataServiceImpl implements EnvWqDataService { } private void updateWqHourData(Map updateData) { - LinkedHashMap columnMap = new LinkedHashMap<>(); - columnMap.put("wtmp", "WTMP"); - columnMap.put("ph", "PH"); - columnMap.put("dox", "DOX"); - columnMap.put("codmn", "CODMN"); - columnMap.put("codcr", "CODCR"); - columnMap.put("bod5", "BOD5"); - columnMap.put("nh3n", "NH3N"); - columnMap.put("tp", "TP"); - columnMap.put("tn", "TN"); - columnMap.put("cu", "CU"); - columnMap.put("zn", "ZN"); - columnMap.put("f", "F"); - columnMap.put("se", "SE"); - columnMap.put("ars", "ARS"); - columnMap.put("hg", "HG"); - columnMap.put("cd", "CD"); - columnMap.put("cr6", "CR6"); - columnMap.put("pb", "PB"); - columnMap.put("cn", "CN"); - columnMap.put("vlph", "VLPH"); - columnMap.put("oil", "OIL"); - columnMap.put("las", "LAS"); - columnMap.put("s2", "S2"); - columnMap.put("fcg", "FCG"); - columnMap.put("cl", "CL"); - columnMap.put("so4", "SO4"); - columnMap.put("no3", "NO3"); - columnMap.put("thrd", "THRD"); - columnMap.put("cond", "COND"); - columnMap.put("fe", "FE"); - columnMap.put("mn", "MN"); - columnMap.put("al", "AL"); - columnMap.put("chla", "CHLA"); - columnMap.put("clarity", "CLARITY"); - columnMap.put("tu", "TU"); - columnMap.put("cyano", "CYANO"); - columnMap.put("wqgrd", "WQGRD"); - columnMap.put("sfdb", "SFDB"); - columnMap.put("wqSfdbhnYs", "WQ_SFDBHN_YS"); - List setClauses = new ArrayList<>(); List params = new ArrayList<>(); - for (Map.Entry entry : columnMap.entrySet()) { + for (Map.Entry entry : WQ_UPDATE_COLUMN_MAP.entrySet()) { if (updateData.containsKey(entry.getKey())) { setClauses.add(entry.getValue() + " = ?"); params.add(updateData.get(entry.getKey())); @@ -3909,6 +3986,286 @@ public class EnvWqDataServiceImpl implements EnvWqDataService { jdbcTemplate.update(sql.toString(), params.toArray()); } + private Map queryWqHourRow(String stcd, String tm) { + if (StrUtil.isBlank(stcd) || StrUtil.isBlank(tm)) { + return new HashMap<>(); + } + String sql = "SELECT " + buildWqHourLogSelectColumns() + + " FROM SD_WQ_R WHERE STCD = ? AND TM = TO_DATE(?, 'YYYY-MM-DD HH24:MI:SS')"; + List> rows = jdbcTemplate.queryForList(sql, stcd, tm); + return rows.isEmpty() ? new HashMap<>() : normalizeLogRow(rows.getFirst()); + } + + private Map queryWqStationRow(String stcd) { + if (StrUtil.isBlank(stcd)) { + return new HashMap<>(); + } + String sql = "SELECT STCD, WWQTG FROM SD_WQ_B_H WHERE STCD = ? AND NVL(IS_DELETED, 0) = 0"; + List> rows = jdbcTemplate.queryForList(sql, stcd); + return rows.isEmpty() ? new HashMap<>() : normalizeLogRow(rows.getFirst()); + } + + private List> queryWqHourRows(List dataParamList) { + if (CollUtil.isEmpty(dataParamList)) { + return new ArrayList<>(); + } + StringBuilder sql = new StringBuilder("SELECT ") + .append(buildWqHourLogSelectColumns()) + .append(" FROM SD_WQ_R WHERE "); + List params = new ArrayList<>(); + appendHourRowConditions(sql, params, dataParamList); + return normalizeLogRows(jdbcTemplate.queryForList(sql.toString(), params.toArray())); + } + + private List> queryWqDayRows(List dataParamList) { + if (CollUtil.isEmpty(dataParamList)) { + return new ArrayList<>(); + } + StringBuilder sql = new StringBuilder("SELECT ") + .append(buildWqDayLogSelectColumns()) + .append(" FROM SD_WQDAY_S WHERE "); + List params = new ArrayList<>(); + for (int i = 0; i < dataParamList.size(); i++) { + if (i > 0) { + sql.append(" OR "); + } + sql.append("(STCD = ? AND DT = TO_DATE(?, 'YYYY-MM-DD HH24:MI:SS'))"); + DataParam item = dataParamList.get(i); + params.add(item == null ? null : item.getId()); + params.add(item == null ? null : item.getDt()); + } + return normalizeLogRows(jdbcTemplate.queryForList(sql.toString(), params.toArray())); + } + + private List> queryWqMonthRows(List dataParamList) { + if (CollUtil.isEmpty(dataParamList)) { + return new ArrayList<>(); + } + StringBuilder sql = new StringBuilder("SELECT ") + .append(buildWqMonthLogSelectColumns()) + .append(" FROM SD_WQDRTP_S WHERE "); + List params = new ArrayList<>(); + for (int i = 0; i < dataParamList.size(); i++) { + if (i > 0) { + sql.append(" OR "); + } + sql.append("(STCD = ? AND DRTP = ? AND YEAR = ? AND MONTH = ?)"); + DataParam item = dataParamList.get(i); + params.add(item == null ? null : item.getId()); + params.add(item == null ? null : item.getDrtp()); + params.add(item == null ? null : item.getYear()); + params.add(item == null ? null : item.getMonth()); + } + return normalizeLogRows(jdbcTemplate.queryForList(sql.toString(), params.toArray())); + } + + private void appendHourRowConditions(StringBuilder sql, List params, List dataParamList) { + for (int i = 0; i < dataParamList.size(); i++) { + if (i > 0) { + sql.append(" OR "); + } + sql.append("(STCD = ? AND TM = TO_DATE(?, 'YYYY-MM-DD HH24:MI:SS'))"); + DataParam item = dataParamList.get(i); + params.add(item == null ? null : item.getId()); + params.add(item == null ? null : item.getTm()); + } + } + + private String buildWqHourLogSelectColumns() { + return "ID,STCD, TO_CHAR(TM, 'YYYY-MM-DD HH24:MI:SS') AS TM, " + + "WTMP, PH, DOX, CODMN, CODCR, BOD5, NH3N, TP, TN, CU, ZN, F, SE, ARS, HG, CD, CR6, PB, CN, " + + "VLPH, OIL, LAS, S2, FCG, CL, SO4, NO3, THRD, COND, FE, MN, AL, CHLA, CLARITY, TU, CYANO, " + + "WQGRD, SFDB, WQ_SFDBHN_YS"; + } + + private String buildWqDayLogSelectColumns() { + return "STCD, TO_CHAR(DT, 'YYYY-MM-DD HH24:MI:SS') AS DT, " + + "WTMP, PH, DOX, CODMN, CODCR, BOD5, NH3N, TP, TN, CU, ZN, F, SE, ARS, HG, CD, CR6, PB, CN, " + + "VLPH, OIL, LAS, S2, FCG, CL, SO4, NO3, THRD, COND, FE, MN, AL, CHLA, CLARITY, TU, CYANO, " + + "WQGRD, SFDB, IS_DELETED"; + } + + private String buildWqMonthLogSelectColumns() { + return "STCD, DRTP, YEAR, MONTH, " + + "WTMP, PH, DOX, CODMN, CODCR, BOD5, NH3N, TP, TN, CU, ZN, F, SE, ARS, HG, CD, CR6, PB, CN, " + + "VLPH, OIL, LAS, S2, FCG, CL, SO4, NO3, THRD, COND, FE, MN, AL, CHLA, CLARITY, TU, CYANO, " + + "WQGRD, SFDB, IS_DELETED"; + } + + private List> normalizeLogRows(List> rows) { + List> result = new ArrayList<>(); + if (CollUtil.isEmpty(rows)) { + return result; + } + for (Map row : rows) { + result.add(normalizeLogRow(row)); + } + return result; + } + + private Map normalizeLogRow(Map row) { + Map normalized = new LinkedHashMap<>(); + if (row == null || row.isEmpty()) { + return normalized; + } + for (Map.Entry entry : row.entrySet()) { + normalized.put(entry.getKey() == null ? null : entry.getKey().toUpperCase(), entry.getValue()); + } + return normalized; + } + + private void recordWqUpdateLog(Map beforeHour, + Map beforeStation, + Map updateData, + String source) { + if (updateData == null || updateData.isEmpty()) { + return; + } + String stcd = asString(updateData.get("stcd")); + List details = new ArrayList<>(); + for (Map.Entry entry : WQ_UPDATE_COLUMN_MAP.entrySet()) { + if (!updateData.containsKey(entry.getKey())) { + continue; + } + String column = entry.getValue(); + Object oldValue = beforeHour == null ? null : beforeHour.get(column); + Object newValue = updateData.get(entry.getKey()); + if (StrUtil.equals(formatLogValue(oldValue), formatLogValue(newValue))) { + continue; + } + details.add(buildWqDetail(null, WQ_HOUR_TABLE_NAME, stcd, column, + oldValue, resolveWqDisplayValue(column, oldValue), + newValue, resolveWqDisplayValue(column, newValue), "修改字段值")); + } + if (updateData.containsKey("wwqtg")) { + Object oldValue = beforeStation == null ? null : beforeStation.get("WWQTG"); + Object newValue = updateData.get("wwqtg"); + if (!StrUtil.equals(formatLogValue(oldValue), formatLogValue(newValue))) { + details.add(buildWqDetail(null, WQ_STATION_TABLE_NAME, stcd, "WWQTG", + oldValue, resolveWqDisplayValue("WWQTG", oldValue), + newValue, resolveWqDisplayValue("WWQTG", newValue), "修改字段值")); + } + } + if (details.isEmpty()) { + return; + } + String recordId = ObjectUtil.isNotEmpty(beforeHour) && ObjectUtil.isNotEmpty(beforeHour.get("ID")) + ? beforeHour.get("ID").toString() + : null; MsOperationLog mainLog = buildWqMainLog(recordId,"修改水质小时数据", source); + msOperationLogMapper.insert(mainLog); + for (MsOperationLogDetail detail : details) { + detail.setMainId(mainLog.getId()); + } + batchInsertWqLogDetails(details); + } + + private void recordWqDeleteLog(List> rows, String tableName, String remark, String source) { + if (CollUtil.isEmpty(rows)) { + return; + } + List details = new ArrayList<>(); + for (Map row : rows) { + String stcd = asString(row.get("STCD")); + String recordId = asString(row.get("ID")); + MsOperationLog mainLog = buildWqMainLog(recordId,remark, source); + msOperationLogMapper.insert(mainLog); + for (Map.Entry entry : row.entrySet()) { + String fieldCode = entry.getKey(); + if (StrUtil.isBlank(fieldCode)) { + continue; + } + Object oldValue = entry.getValue(); + if (oldValue == null) { + continue; + } + details.add(buildWqDetail(mainLog.getId(), tableName, stcd, fieldCode, + oldValue, resolveWqDisplayValue(fieldCode, oldValue), + null, null, "删除字段值")); + } + } + batchInsertWqLogDetails(details); + } + + private MsOperationLog buildWqMainLog(String recordId,String remark, String source) { + MsOperationLog log = new MsOperationLog(); + log.setOperator(resolveLogOperator()); + log.setRecordId(recordId); + log.setOperateTime(new Date()); + log.setTableName(WQ_HOUR_TABLE_NAME); + log.setSource(StrUtil.trimToNull(source)); + log.setRemark(remark); + return log; + } + + private MsOperationLogDetail buildWqDetail(String mainId, + String tableName, + String stationCode, + String fieldCode, + Object oldValueCode, + Object oldValueName, + Object newValueCode, + Object newValueName, + String remark) { + MsOperationLogDetail detail = new MsOperationLogDetail(); + detail.setMainId(mainId); + detail.setTableName(tableName); + detail.setStationCode(stationCode); + detail.setFieldCode(fieldCode); + detail.setFieldMeaning(WQ_FIELD_MEANING_MAP.getOrDefault(fieldCode, fieldCode)); + detail.setOldValueCode(formatLogValue(oldValueCode)); + detail.setOldValueName(formatLogValue(oldValueName)); + detail.setNewValueCode(formatLogValue(newValueCode)); + detail.setNewValueName(formatLogValue(newValueName)); + detail.setRemark(remark); + return detail; + } + + private void batchInsertWqLogDetails(List details) { + if (CollUtil.isEmpty(details)) { + return; + } + for (MsOperationLogDetail detail : details) { + if (detail == null) { + continue; + } + msOperationLogDetailMapper.insert(detail); + } + } + + private Object resolveWqDisplayValue(String fieldCode, Object rawValue) { + String text = formatLogValue(rawValue); + if (StrUtil.isBlank(text)) { + return rawValue; + } + return switch (fieldCode) { + case "WQGRD", "WWQTG" -> getWqLevelName(text); + case "SFDB" -> parseInteger(text) == null ? text : getSfdbName(parseInteger(text)); + default -> text; + }; + } + + private String resolveLogOperator() { + try { + return SecurityUtils.getCurrentUsername(); + } catch (Exception ignored) { + try { + return SecurityUtils.getUserId(); + } catch (Exception ex) { + return null; + } + } + } + + private String formatLogValue(Object value) { + if (value == null) { + return null; + } + if (value instanceof Date date) { + return DateUtil.formatDateTime(date); + } + return String.valueOf(value); + } + private String getMonthEndDate(Integer year, Integer month) { Calendar calendar = Calendar.getInstance(); calendar.set(year, month - 1, 1); diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wt/controller/SdWTMonitorController.java b/backend/src/main/java/com/yfd/platform/qgc_env/wt/controller/SdWTMonitorController.java index 6dccdf94..8212bef8 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wt/controller/SdWTMonitorController.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wt/controller/SdWTMonitorController.java @@ -2,12 +2,14 @@ package com.yfd.platform.qgc_env.wt.controller; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.yfd.platform.annotation.Log; import com.yfd.platform.common.DataSourceLoadOptionsBase; import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.common.DataSourceResult; import com.yfd.platform.common.exception.BizException; import com.yfd.platform.config.ResponseResult; import com.yfd.platform.qgc_base.entity.vo.BatchDeleteAo; +import com.yfd.platform.qgc_env.wt.entity.vo.WtOperateRequest; import com.yfd.platform.qgc_env.wt.entity.vo.WtrvInfo; import com.yfd.platform.qgc_env.wt.entity.vo.WtrvAmendSaveVo; import com.yfd.platform.qgc_env.wt.service.*; @@ -54,10 +56,14 @@ public class SdWTMonitorController { return ResponseResult.successData(result); } + @Log(module = "水温监测", value = "修改表层水温日数据") @PostMapping("/alongDetail/updateWtrvRData") @Operation(summary = "修改表层水温日数据") - public ResponseResult updateWtrvRData(@RequestBody Map updateData) { - alongDetailService.updateWtrvRData(updateData); + public ResponseResult updateWtrvRData(@RequestBody WtOperateRequest wtOperateRequest) { + alongDetailService.updateWtrvRData( + wtOperateRequest == null ? null : wtOperateRequest.getUpdateData(), + wtOperateRequest == null ? null : wtOperateRequest.getSource() + ); return ResponseResult.success(); } @@ -75,6 +81,7 @@ public class SdWTMonitorController { return ResponseResult.successData(result); } + @Log(module = "水温监测", value = "删除出库水温周旬月季年数据") @PostMapping("/alongDetail/drtp/removeKendoByIds") @Operation(summary = "删除出库水温周旬月季年数据") public ResponseResult removeKendoByIds(@RequestBody BatchDeleteAo batchDeleteAo) { @@ -236,6 +243,7 @@ public class SdWTMonitorController { return ResponseResult.successData(sdWtMonitorService.getCxDetailList(dataSourceRequest)); } + @Log(module = "水温监测", value = "删除垂向水温数据") @PostMapping("/cxDetail/removeKendoByIds") @Operation(summary = "删除垂向水温数据") public ResponseResult removeCxDetailByIds(@RequestBody BatchDeleteAo batchDeleteAo) { @@ -243,10 +251,14 @@ public class SdWTMonitorController { return ResponseResult.success(); } + @Log(module = "水温监测", value = "修改垂向水温数据") @PostMapping("/cxDetail/updateWtvtRData") @Operation(summary = "修改垂向水温数据") - public ResponseResult updateWtvtRData(@RequestBody Map updateData) { - sdWtvtRService.updateWtvtRData(updateData); + public ResponseResult updateWtvtRData(@RequestBody WtOperateRequest wtOperateRequest) { + sdWtvtRService.updateWtvtRData( + wtOperateRequest == null ? null : wtOperateRequest.getUpdateData(), + wtOperateRequest == null ? null : wtOperateRequest.getSource() + ); return ResponseResult.success(); } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wt/entity/vo/WtOperateRequest.java b/backend/src/main/java/com/yfd/platform/qgc_env/wt/entity/vo/WtOperateRequest.java new file mode 100644 index 00000000..cdddcf9b --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wt/entity/vo/WtOperateRequest.java @@ -0,0 +1,13 @@ +package com.yfd.platform.qgc_env.wt.entity.vo; + +import lombok.Data; + +import java.util.Map; + +@Data +public class WtOperateRequest { + + private String source; + + private Map updateData; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/AlongDetailService.java b/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/AlongDetailService.java index 5465ec79..a4de4324 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/AlongDetailService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/AlongDetailService.java @@ -43,6 +43,6 @@ public interface AlongDetailService extends IService { boolean removeKendoByIds(BatchDeleteAo batchDeleteAo); - void updateWtrvRData(Map updateData); + void updateWtrvRData(Map updateData, String source); -} \ No newline at end of file +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/SdWtvtRService.java b/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/SdWtvtRService.java index 2b62f2b3..43c165a0 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/SdWtvtRService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/SdWtvtRService.java @@ -24,5 +24,5 @@ public interface SdWtvtRService { boolean removeKendoByIds(BatchDeleteAo batchDeleteAo); - void updateWtvtRData(Map updateData); + void updateWtvtRData(Map updateData, String source); } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/AlongDetailServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/AlongDetailServiceImpl.java index 009f7cf6..13596442 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/AlongDetailServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/AlongDetailServiceImpl.java @@ -8,6 +8,8 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.yfd.platform.common.*; import com.yfd.platform.common.exception.BizException; +import com.yfd.platform.qgc_base.domain.MsOperationLog; +import com.yfd.platform.qgc_base.domain.MsOperationLogDetail; import com.yfd.platform.qgc_env.wt.mapper.AlongDetailMapper; import com.yfd.platform.qgc_env.wt.mapper.SdWtrvdrtpSMapper; import com.yfd.platform.qgc_env.wt.service.AlongDetailService; @@ -17,6 +19,8 @@ import com.yfd.platform.qgc_env.wt.entity.vo.SdAlongDrtpDetailVO; import com.yfd.platform.qgc_env.wt.entity.vo.WtrvInfo; import com.yfd.platform.qgc_base.entity.vo.BatchDeleteAo; import com.yfd.platform.qgc_base.entity.vo.DataParam; +import com.yfd.platform.qgc_base.mapper.MsOperationLogDetailMapper; +import com.yfd.platform.qgc_base.mapper.MsOperationLogMapper; import com.yfd.platform.utils.CollectionExtUtils; import com.yfd.platform.utils.QgcQueryWrapperUtil; import com.yfd.platform.utils.SecurityUtils; @@ -37,6 +41,29 @@ import java.util.stream.Collectors; */ @Service public class AlongDetailServiceImpl extends ServiceImpl implements AlongDetailService { + private static final String WT_HOUR_TABLE_NAME = "SD_WTRV_R"; + private static final Map WT_UPDATE_COLUMN_MAP = new LinkedHashMap<>(); + private static final Map WT_FIELD_MEANING_MAP = new LinkedHashMap<>(); + + static { + WT_UPDATE_COLUMN_MAP.put("wt", "WT"); + + WT_FIELD_MEANING_MAP.put("ID", "主键ID"); + WT_FIELD_MEANING_MAP.put("STCD", "水温站编码"); + WT_FIELD_MEANING_MAP.put("TM", "数据时间"); + WT_FIELD_MEANING_MAP.put("WT", "水温"); + WT_FIELD_MEANING_MAP.put("REMARK", "备注"); + WT_FIELD_MEANING_MAP.put("FID", "附件ID"); + WT_FIELD_MEANING_MAP.put("WER_ID", "所属水生生态调查数据表ID"); + WT_FIELD_MEANING_MAP.put("RECORD_USER", "创建人"); + WT_FIELD_MEANING_MAP.put("RECORD_TIME", "创建时间"); + WT_FIELD_MEANING_MAP.put("MODIFY_USER", "更新人"); + WT_FIELD_MEANING_MAP.put("MODIFY_TIME", "更新时间"); + WT_FIELD_MEANING_MAP.put("IS_DELETED", "是否已删除"); + WT_FIELD_MEANING_MAP.put("DELETE_USER", "删除人"); + WT_FIELD_MEANING_MAP.put("DELETE_TIME", "删除时间"); + } + @Resource private DynamicSQLMapper dynamicSQLMapper; @Resource @@ -50,6 +77,12 @@ public class AlongDetailServiceImpl extends ServiceImpl filterResult, Page page) { DataSourceResult dataSourceResult = new DataSourceResult(); @@ -799,6 +832,7 @@ public class AlongDetailServiceImpl extends ServiceImpl dataList = batchDeleteAo.getDataList(); + String source = batchDeleteAo == null ? null : batchDeleteAo.getSource(); if(CollUtil.isEmpty(dataList)){ return true; } @@ -816,7 +850,9 @@ public class AlongDetailServiceImpl extends ServiceImpl> beforeRows = queryWtHourRows(subList); sdWtrvdrtpSMapper.deleteWtrvRData(subList, DateUtil.now(), SecurityUtils.getCurrentUsername()); + recordWtDeleteLog(beforeRows, "删除表层水温日数据", source); // 删除小时数据后,需要重新统计对应的日数据和月数据 Map dateRangeMap = new HashMap<>(); Map monthRangeMap = new HashMap<>(); @@ -1048,13 +1084,14 @@ public class AlongDetailServiceImpl extends ServiceImpl updateData) { + public void updateWtrvRData(Map updateData, String source) { + String stcd = asString(getValueIgnoreCase(updateData, "stcd")); + String tm = asString(getValueIgnoreCase(updateData, "dt")); + Map beforeRow = queryWtHourRow(stcd, tm); sdWtrvdrtpSMapper.updateWtrvRData(updateData); + recordWtUpdateLog(beforeRow, updateData, source); // 获取测站编码和时间 - String stcd = (String) updateData.get("stcd"); - String tm = (String) updateData.get("dt"); - if (StrUtil.isNotBlank(stcd) && StrUtil.isNotBlank(tm)) { // 提取日期部分(yyyy-MM-dd) String dateStr = tm.substring(0, 10); @@ -1074,4 +1111,204 @@ public class AlongDetailServiceImpl extends ServiceImpl queryWtHourRow(String stcd, String tm) { + if (StrUtil.isBlank(stcd) || StrUtil.isBlank(tm)) { + return new HashMap<>(); + } + String sql = "SELECT ID, STCD, TO_CHAR(TM, 'YYYY-MM-DD HH24:MI:SS') AS TM, WT, REMARK, FID, WER_ID, " + + "RECORD_USER, RECORD_TIME, MODIFY_USER, MODIFY_TIME, IS_DELETED, DELETE_USER, DELETE_TIME " + + "FROM SD_WTRV_R WHERE STCD = ? AND TM = TO_DATE(?, 'YYYY-MM-DD HH24:MI:SS')"; + List> rows = jdbcTemplate.queryForList(sql, stcd, tm); + return rows.isEmpty() ? new HashMap<>() : normalizeWtLogRow(rows.getFirst()); + } + + private List> queryWtHourRows(List dataParamList) { + if (CollUtil.isEmpty(dataParamList)) { + return new ArrayList<>(); + } + StringBuilder sql = new StringBuilder("SELECT ID, STCD, TO_CHAR(TM, 'YYYY-MM-DD HH24:MI:SS') AS TM, WT, REMARK, FID, WER_ID, ") + .append("RECORD_USER, RECORD_TIME, MODIFY_USER, MODIFY_TIME, IS_DELETED, DELETE_USER, DELETE_TIME ") + .append("FROM SD_WTRV_R WHERE "); + List params = new ArrayList<>(); + for (int i = 0; i < dataParamList.size(); i++) { + if (i > 0) { + sql.append(" OR "); + } + sql.append("(STCD = ? AND TM = TO_DATE(?, 'YYYY-MM-DD HH24:MI:SS'))"); + DataParam item = dataParamList.get(i); + params.add(item == null ? null : item.getId()); + params.add(item == null ? null : item.getDt()); + } + return normalizeWtLogRows(jdbcTemplate.queryForList(sql.toString(), params.toArray())); + } + + private List> normalizeWtLogRows(List> rows) { + List> result = new ArrayList<>(); + if (CollUtil.isEmpty(rows)) { + return result; + } + for (Map row : rows) { + result.add(normalizeWtLogRow(row)); + } + return result; + } + + private Map normalizeWtLogRow(Map row) { + Map normalized = new LinkedHashMap<>(); + if (row == null || row.isEmpty()) { + return normalized; + } + for (Map.Entry entry : row.entrySet()) { + normalized.put(entry.getKey() == null ? null : entry.getKey().toUpperCase(), entry.getValue()); + } + return normalized; + } + + private void recordWtUpdateLog(Map beforeRow, Map updateData, String source) { + if (updateData == null || updateData.isEmpty()) { + return; + } + String stcd = asString(getValueIgnoreCase(updateData, "stcd")); + String recordId = asString(getValueIgnoreCase(beforeRow, "id")); + List details = new ArrayList<>(); + for (Map.Entry entry : WT_UPDATE_COLUMN_MAP.entrySet()) { + if (!containsKeyIgnoreCase(updateData, entry.getKey())) { + continue; + } + String column = entry.getValue(); + Object oldValue = beforeRow == null ? null : beforeRow.get(column); + Object newValue = getValueIgnoreCase(updateData, entry.getKey()); + if (StrUtil.equals(formatWtLogValue(oldValue), formatWtLogValue(newValue))) { + continue; + } + details.add(buildWtDetail(null, stcd, column, + oldValue, resolveWtDisplayValue(column, oldValue), + newValue, resolveWtDisplayValue(column, newValue), "修改字段值")); + } + if (details.isEmpty()) { + return; + } + MsOperationLog mainLog = buildWtMainLog(recordId,"修改表层水温日数据", source); + msOperationLogMapper.insert(mainLog); + for (MsOperationLogDetail detail : details) { + detail.setMainId(mainLog.getId()); + } + batchInsertWtLogDetails(details); + } + + private void recordWtDeleteLog(List> rows, String remark, String source) { + if (CollUtil.isEmpty(rows)) { + return; + } + + List details = new ArrayList<>(); + for (Map row : rows) { + String stcd = asString(row.get("STCD")); + String recordId = asString(row.get("ID")); + MsOperationLog mainLog = buildWtMainLog(recordId,remark, source); + msOperationLogMapper.insert(mainLog); + for (Map.Entry entry : row.entrySet()) { + String fieldCode = entry.getKey(); + Object oldValue = entry.getValue(); + if (StrUtil.isBlank(fieldCode) || oldValue == null) { + continue; + } + details.add(buildWtDetail(mainLog.getId(), stcd, fieldCode, + oldValue, resolveWtDisplayValue(fieldCode, oldValue), + null, null, "删除字段值")); + } + } + batchInsertWtLogDetails(details); + } + + private MsOperationLog buildWtMainLog(String recordId,String remark, String source) { + MsOperationLog log = new MsOperationLog(); + log.setOperator(resolveWtLogOperator()); + log.setOperateTime(new Date()); + log.setRecordId(recordId); + log.setTableName(WT_HOUR_TABLE_NAME); + log.setSource(StrUtil.trimToNull(source)); + log.setRemark(remark); + return log; + } + + private MsOperationLogDetail buildWtDetail(String mainId, + String stationCode, + String fieldCode, + Object oldValueCode, + Object oldValueName, + Object newValueCode, + Object newValueName, + String remark) { + MsOperationLogDetail detail = new MsOperationLogDetail(); + detail.setMainId(mainId); + detail.setTableName(WT_HOUR_TABLE_NAME); + detail.setStationCode(stationCode); + detail.setFieldCode(fieldCode); + detail.setFieldMeaning(WT_FIELD_MEANING_MAP.getOrDefault(fieldCode, fieldCode)); + detail.setOldValueCode(formatWtLogValue(oldValueCode)); + detail.setOldValueName(formatWtLogValue(oldValueName)); + detail.setNewValueCode(formatWtLogValue(newValueCode)); + detail.setNewValueName(formatWtLogValue(newValueName)); + detail.setRemark(remark); + return detail; + } + + private void batchInsertWtLogDetails(List details) { + if (CollUtil.isEmpty(details)) { + return; + } + for (MsOperationLogDetail detail : details) { + if (detail == null) { + continue; + } + msOperationLogDetailMapper.insert(detail); + } + } + + private Object resolveWtDisplayValue(String fieldCode, Object rawValue) { + return formatWtLogValue(rawValue); + } + + private String resolveWtLogOperator() { + try { + return SecurityUtils.getCurrentUsername(); + } catch (Exception ignored) { + try { + return SecurityUtils.getUserId(); + } catch (Exception ex) { + return null; + } + } + } + + private String formatWtLogValue(Object value) { + if (value == null) { + return null; + } + if (value instanceof Date date) { + return DateUtil.formatDateTime(date); + } + return String.valueOf(value); + } + + private String asString(Object value) { + return value == null ? null : String.valueOf(value); + } + + private boolean containsKeyIgnoreCase(Map data, String key) { + if (data == null || StrUtil.isBlank(key)) { + return false; + } + if (data.containsKey(key)) { + return true; + } + for (String mapKey : data.keySet()) { + if (StrUtil.equalsIgnoreCase(mapKey, key)) { + return true; + } + } + return false; + } } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/SdWtvtRServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/SdWtvtRServiceImpl.java index c91fcda6..80a91b5a 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/SdWtvtRServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/SdWtvtRServiceImpl.java @@ -1,13 +1,18 @@ package com.yfd.platform.qgc_env.wt.service.impl; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 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_base.domain.MsOperationLog; +import com.yfd.platform.qgc_base.domain.MsOperationLogDetail; import com.yfd.platform.qgc_base.entity.vo.BatchDeleteAo; import com.yfd.platform.qgc_base.entity.vo.DataParam; +import com.yfd.platform.qgc_base.mapper.MsOperationLogDetailMapper; +import com.yfd.platform.qgc_base.mapper.MsOperationLogMapper; import com.yfd.platform.qgc_env.wt.entity.vo.SdWtvtYearVo; import com.yfd.platform.qgc_env.wt.mapper.SdWtvtRMapper; import com.yfd.platform.qgc_env.wt.service.SdWtvtRService; @@ -22,6 +27,7 @@ import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Calendar; +import java.util.Date; import java.util.HashSet; import java.util.HashMap; import java.util.List; @@ -37,6 +43,28 @@ import java.util.Set; */ @Service public class SdWtvtRServiceImpl extends ServiceImpl implements SdWtvtRService { + private static final String WT_CX_TABLE_NAME = "SD_WTVT_R"; + private static final Map WT_CX_FIELD_MEANING_MAP = new LinkedHashMap<>(); + + static { + WT_CX_FIELD_MEANING_MAP.put("ID", "主键ID"); + WT_CX_FIELD_MEANING_MAP.put("STCD", "垂向水温站编码"); + WT_CX_FIELD_MEANING_MAP.put("TM", "时间"); + WT_CX_FIELD_MEANING_MAP.put("WTHG", "水温深度"); + WT_CX_FIELD_MEANING_MAP.put("VWT", "水温"); + WT_CX_FIELD_MEANING_MAP.put("FID", "附件ID"); + WT_CX_FIELD_MEANING_MAP.put("RECORD_USER", "创建人"); + WT_CX_FIELD_MEANING_MAP.put("RECORD_TIME", "创建时间"); + WT_CX_FIELD_MEANING_MAP.put("MODIFY_USER", "更新人"); + WT_CX_FIELD_MEANING_MAP.put("MODIFY_TIME", "更新时间"); + WT_CX_FIELD_MEANING_MAP.put("IS_DELETED", "是否已删除"); + WT_CX_FIELD_MEANING_MAP.put("DELETE_USER", "删除人"); + WT_CX_FIELD_MEANING_MAP.put("DELETE_TIME", "删除时间"); + WT_CX_FIELD_MEANING_MAP.put("RZ", "坝前水位"); + WT_CX_FIELD_MEANING_MAP.put("HGT", "测点高程"); + WT_CX_FIELD_MEANING_MAP.put("REMARK", "备注"); + WT_CX_FIELD_MEANING_MAP.put("WER_ID", "所属水生生态调查数据表ID"); + } @Resource private SdWtvtRMapper sdWtvtRMapper; @@ -47,6 +75,12 @@ public class SdWtvtRServiceImpl extends ServiceImpl @Resource private JdbcTemplate jdbcTemplate; + @Resource + private MsOperationLogMapper msOperationLogMapper; + + @Resource + private MsOperationLogDetailMapper msOperationLogDetailMapper; + @Override public DataSourceResult getWtrvDefaultYear(DataSourceRequest dataSourceRequest) { DataSourceResult dataSourceResult = new DataSourceResult<>(); @@ -91,6 +125,7 @@ public class SdWtvtRServiceImpl extends ServiceImpl public boolean removeKendoByIds(BatchDeleteAo batchDeleteAo) { String dataType = batchDeleteAo == null ? null : batchDeleteAo.getDataType(); List dataList = batchDeleteAo == null ? null : batchDeleteAo.getDataList(); + String source = batchDeleteAo == null ? null : batchDeleteAo.getSource(); if (CollUtil.isEmpty(dataList)) { return true; } @@ -104,7 +139,9 @@ public class SdWtvtRServiceImpl extends ServiceImpl continue; } if ("TIME".equalsIgnoreCase(dataType)) { + List> beforeRows = queryWtvtRows(subList); deleteWtvtRData(subList); + recordWtvtDeleteLog(beforeRows, "删除垂向水温数据", source); Map dateRangeMap = new HashMap<>(); Map monthRangeMap = new HashMap<>(); for (DataParam param : subList) { @@ -160,7 +197,7 @@ public class SdWtvtRServiceImpl extends ServiceImpl @Override @Transactional(rollbackFor = Exception.class) - public void updateWtvtRData(Map updateData) { + public void updateWtvtRData(Map updateData, String source) { if (updateData == null || updateData.isEmpty()) { return; } @@ -171,7 +208,10 @@ public class SdWtvtRServiceImpl extends ServiceImpl return; } + Map> beforeRowMap = buildWtvtBeforeRowMap(stcd, dt); + List> dataList = new ArrayList<>(); + List logDetails = new ArrayList<>(); rawMap.forEach((wthgObj, vwtObj) -> { if (wthgObj == null) { return; @@ -192,12 +232,32 @@ public class SdWtvtRServiceImpl extends ServiceImpl // item.put("recordUser", "admin"); item.put("recordUser", SecurityUtils.getUserId()); dataList.add(item); + + String depthKey = buildWtvtDepthKey(item.get("wthg")); + Map beforeRow = beforeRowMap.get(depthKey); + Object oldValue = beforeRow == null ? null : beforeRow.get("VWT"); + Object newValue = item.get("vwt"); + if (StringUtils.equals(formatWtvtLogValue(oldValue), formatWtvtLogValue(newValue))) { + return; + } + logDetails.add(buildWtvtDetail(null, stcd, "VWT", + oldValue, resolveWtvtDisplayValue("VWT", oldValue), + newValue, resolveWtvtDisplayValue("VWT", newValue), + buildWtvtDepthRemark("修改字段值", item.get("wthg")))); }); if (dataList.isEmpty()) { return; } batchUpdateWtvtRData(dataList); + if (CollUtil.isNotEmpty(logDetails)) { + MsOperationLog mainLog = buildWtvtMainLog(null,"修改垂向水温数据", source); + msOperationLogMapper.insert(mainLog); + for (MsOperationLogDetail detail : logDetails) { + detail.setMainId(mainLog.getId()); + } + batchInsertWtvtLogDetails(logDetails); + } String dateStr = dt.substring(0, 10); statisticsDayDataFromHour(stcd, dateStr, dateStr); @@ -363,4 +423,163 @@ public class SdWtvtRServiceImpl extends ServiceImpl private String asString(Object value) { return value == null ? null : String.valueOf(value); } + + private List> queryWtvtRows(List dataParamList) { + if (CollUtil.isEmpty(dataParamList)) { + return new ArrayList<>(); + } + StringBuilder sql = new StringBuilder("SELECT ID, STCD, TO_CHAR(TM, 'YYYY-MM-DD HH24:MI:SS') AS TM, WTHG, VWT, FID, ") + .append("RECORD_USER, RECORD_TIME, MODIFY_USER, MODIFY_TIME, IS_DELETED, DELETE_USER, DELETE_TIME, RZ, HGT, REMARK, WER_ID ") + .append("FROM SD_WTVT_R WHERE "); + List params = new ArrayList<>(); + List conditions = new ArrayList<>(); + for (DataParam item : dataParamList) { + if (item == null || StringUtils.isBlank(item.getId()) || StringUtils.isBlank(item.getDt())) { + continue; + } + conditions.add("(STCD = ? AND TM = TO_DATE(SUBSTR(?, 1, 19), 'YYYY-MM-DD HH24:MI:SS'))"); + params.add(item.getId()); + params.add(item.getDt()); + } + if (conditions.isEmpty()) { + return new ArrayList<>(); + } + sql.append(String.join(" OR ", conditions)); + return normalizeWtvtRows(jdbcTemplate.queryForList(sql.toString(), params.toArray())); + } + + private Map> buildWtvtBeforeRowMap(String stcd, String dt) { + Map> result = new HashMap<>(); + if (StringUtils.isBlank(stcd) || StringUtils.isBlank(dt)) { + return result; + } + String sql = "SELECT ID, STCD, TO_CHAR(TM, 'YYYY-MM-DD HH24:MI:SS') AS TM, WTHG, VWT, FID, " + + "RECORD_USER, RECORD_TIME, MODIFY_USER, MODIFY_TIME, IS_DELETED, DELETE_USER, DELETE_TIME, RZ, HGT, REMARK, WER_ID " + + "FROM SD_WTVT_R WHERE WTHG IS NOT NULL AND VWT IS NOT NULL AND STCD = ? AND TM = TO_DATE(SUBSTR(?, 1, 19), 'YYYY-MM-DD HH24:MI:SS')"; + List> rows = normalizeWtvtRows(jdbcTemplate.queryForList(sql, stcd, dt)); + for (Map row : rows) { + + result.put(String.valueOf(Double.parseDouble(row.get("WTHG").toString())), row); + } + return result; + } + + private List> normalizeWtvtRows(List> rows) { + List> result = new ArrayList<>(); + if (CollUtil.isEmpty(rows)) { + return result; + } + for (Map row : rows) { + Map normalized = new LinkedHashMap<>(); + for (Map.Entry entry : row.entrySet()) { + normalized.put(entry.getKey() == null ? null : entry.getKey().toUpperCase(), entry.getValue()); + } + result.add(normalized); + } + return result; + } + + private void recordWtvtDeleteLog(List> rows, String remark, String source) { + if (CollUtil.isEmpty(rows)) { + return; + } + MsOperationLog mainLog = buildWtvtMainLog(null,remark, source); + msOperationLogMapper.insert(mainLog); + List details = new ArrayList<>(); + for (Map row : rows) { + String stcd = asString(row.get("STCD")); + Object depth = row.get("WTHG"); + for (Map.Entry entry : row.entrySet()) { + String fieldCode = entry.getKey(); + Object oldValue = entry.getValue(); + if (StringUtils.isBlank(fieldCode) || oldValue == null) { + continue; + } + details.add(buildWtvtDetail(mainLog.getId(), stcd, fieldCode, + oldValue, resolveWtvtDisplayValue(fieldCode, oldValue), + null, null, buildWtvtDepthRemark("删除字段值", depth))); + } + } + batchInsertWtvtLogDetails(details); + } + + private MsOperationLog buildWtvtMainLog(String recordId,String remark, String source) { + MsOperationLog log = new MsOperationLog(); + log.setOperator(resolveWtvtLogOperator()); + log.setOperateTime(new Date()); + log.setTableName(WT_CX_TABLE_NAME); + log.setRecordId(remark); + log.setSource(StringUtils.trimToNull(source)); + log.setRemark(remark); + return log; + } + + private MsOperationLogDetail buildWtvtDetail(String mainId, + String stationCode, + String fieldCode, + Object oldValueCode, + Object oldValueName, + Object newValueCode, + Object newValueName, + String remark) { + MsOperationLogDetail detail = new MsOperationLogDetail(); + detail.setMainId(mainId); + detail.setTableName(WT_CX_TABLE_NAME); + detail.setStationCode(stationCode); + detail.setFieldCode(fieldCode); + detail.setFieldMeaning(WT_CX_FIELD_MEANING_MAP.getOrDefault(fieldCode, fieldCode)); + detail.setOldValueCode(formatWtvtLogValue(oldValueCode)); + detail.setOldValueName(formatWtvtLogValue(oldValueName)); + detail.setNewValueCode(formatWtvtLogValue(newValueCode)); + detail.setNewValueName(formatWtvtLogValue(newValueName)); + detail.setRemark(remark); + return detail; + } + + private void batchInsertWtvtLogDetails(List details) { + if (CollUtil.isEmpty(details)) { + return; + } + for (MsOperationLogDetail detail : details) { + if (detail == null) { + continue; + } + msOperationLogDetailMapper.insert(detail); + } + } + + private Object resolveWtvtDisplayValue(String fieldCode, Object rawValue) { + return formatWtvtLogValue(rawValue); + } + + private String resolveWtvtLogOperator() { + try { + return SecurityUtils.getCurrentUsername(); + } catch (Exception ignored) { + try { + return SecurityUtils.getUserId(); + } catch (Exception ex) { + return null; + } + } + } + + private String formatWtvtLogValue(Object value) { + if (value == null) { + return null; + } + if (value instanceof Date date) { + return DateUtil.formatDateTime(date); + } + return String.valueOf(value); + } + + private String buildWtvtDepthKey(Object depth) { + return formatWtvtLogValue(depth); + } + + private String buildWtvtDepthRemark(String action, Object depth) { + String depthText = formatWtvtLogValue(depth); + return depthText == null ? action : action + "(深度:" + depthText + ")"; + } } 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 d9456491..b9a881bb 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 @@ -21,6 +21,12 @@ public class WeFishController { @Resource private WeFishService weFishService; + @PostMapping("/we/fisht/GetKendoListCust") + @Operation(summary = "条件过滤数据列表定制") + public ResponseResult getWeFishTKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(weFishService.getWeFishTKendoListCust(dataSourceRequest)); + } + @PostMapping("/we/fisht/qgc/GetKendoListCust") @Operation(summary = "全过程沿程鱼类变化情况") public ResponseResult getQgcWeFishTKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { @@ -57,6 +63,30 @@ public class WeFishController { return ResponseResult.successData(weFishService.getWvaList(dataSourceRequest)); } + @PostMapping("/wva/default/GetKendoListCust") + @Operation(summary = "野生动物监测默认数据") + public ResponseResult getWvaDefaultList(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(weFishService.getWvaDefaultList(dataSourceRequest)); + } + + @PostMapping("/we/compareBar/GetKendoListCust") + @Operation(summary = "水生生态调查对比(柱状图)") + public ResponseResult getWeCompareBarList(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(weFishService.getWeCompareBarList(dataSourceRequest)); + } + + @PostMapping("/we/fishPage/qgc/GetKendoListCust") + @Operation(summary = "环保部-水生生态调查二级页面") + public ResponseResult getQgcWeFishPageList(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(weFishService.getQgcWeFishPageList(dataSourceRequest)); + } + + @PostMapping("/base/evnmAutoMonitor/GetKendoListCust") + @Operation(summary = "环保自动监测开展情况") + public ResponseResult getEnvmAutoMonitorList(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(weFishService.getEnvmAutoMonitorList(dataSourceRequest)); + } + @PostMapping("/we/fisht/year/qgc/GetKendoListCust") @Operation(summary = "全过程沿程鱼类变化情况有数据的流域和年份") public ResponseResult getQgcFishStaticsYearList(@RequestBody DataSourceRequest dataSourceRequest) { @@ -69,12 +99,48 @@ public class WeFishController { return ResponseResult.successData(weFishService.getQgcWeFishStatics(dataSourceRequest)); } + @PostMapping("/we/fisht/statics/getWeStaticsSecond") + @Operation(summary = "水生生态调查概况二级页面") + public ResponseResult getWeStaticsSecond(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(weFishService.getWeStaticsSecond(dataSourceRequest)); + } + @PostMapping("/we/fisht/stat/qgc/GetKendoListCust") @Operation(summary = "环保部-沿程鱼类变化情况柱状图") public ResponseResult getQgcWeFishStatList(@RequestBody DataSourceRequest dataSourceRequest) { return ResponseResult.successData(weFishService.getQgcWeFishStatList(dataSourceRequest)); } + @PostMapping("/we/fisht/stat/GetKendoListCust") + @Operation(summary = "沿程鱼类变化情况柱状图") + public ResponseResult getWeFishStatList(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(weFishService.getWeFishStatList(dataSourceRequest)); + } + + @PostMapping("/we/fisht/qgcDetail/GetKendoListCust") + @Operation(summary = "沿程鱼类变化情况二级弹窗-按照新逻辑重写") + public ResponseResult getQgcWeFishDetailList(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(weFishService.getQgcWeFishDetailList(dataSourceRequest)); + } + + @PostMapping("/we/fisht/qgcDetail/qgc/GetKendoListCust") + @Operation(summary = "环保部-沿程鱼类变化情况二级弹窗") + public ResponseResult getHbbQgcWeFishDetailList(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(weFishService.getHbbQgcWeFishDetailList(dataSourceRequest)); + } + + @PostMapping("/we/fisht/detail/GetKendoListCust") + @Operation(summary = "沿程鱼类变化情况二级弹窗") + public ResponseResult getWeFishDetailList(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(weFishService.getWeFishDetailList(dataSourceRequest)); + } + + @PostMapping("/we/fisht/statTab/GetKendoListCust") + @Operation(summary = "沿程鱼类变化情况二级页面tab页签数据") + public ResponseResult getWeFishStatTabList(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(weFishService.getWeFishStatTabList(dataSourceRequest)); + } + @PostMapping("/we/fishList/stat/qgc/GetKendoListCust") @Operation(summary = "环保部-水生生态调查-水生生态面板") public ResponseResult getQgcFishListStat(@RequestBody DataSourceRequest dataSourceRequest) { diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeCompareBarHeadColumnVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeCompareBarHeadColumnVo.java new file mode 100644 index 00000000..7790311d --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeCompareBarHeadColumnVo.java @@ -0,0 +1,33 @@ +package com.yfd.platform.qgc_env.wte.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +@Data +@Accessors(chain = true) +@AllArgsConstructor +@Schema(description = "水生生态调查对比柱状图表头") +public class WeCompareBarHeadColumnVo { + + @Schema(description = "字段名") + private String dataIndex; + + @Schema(description = "标题") + private String title; + + @Schema(description = "是否可见") + private Boolean visible; + + @Schema(description = "键") + private String key; + + @Schema(description = "单位") + private boolean merge; + + @Schema(description = "子列") + private List children; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeCompareBarTableVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeCompareBarTableVo.java new file mode 100644 index 00000000..573d0f9c --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeCompareBarTableVo.java @@ -0,0 +1,22 @@ +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.util.List; + +@Data +@Accessors(chain = true) +@Schema(description = "水生生态调查对比柱状图表格") +public class WeCompareBarTableVo { + + @Schema(description = "表头") + private List columns; + + @Schema(description = "表格数据") + private Object dataSource; + + @Schema(description = "总数") + private Long total; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeCompareBarVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeCompareBarVo.java new file mode 100644 index 00000000..2999824c --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeCompareBarVo.java @@ -0,0 +1,29 @@ +package com.yfd.platform.qgc_env.wte.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +@Data +@Accessors(chain = true) +@Schema(description = "水生生态调查对比柱状图数据") +public class WeCompareBarVo { + + @Schema(description = "鱼类名称") + private String ftp; + + @Schema(description = "科属") + private String genus; + + @Schema(description = "调查批次") + private String dcpc; + + @Schema(description = "对比批次") + private String dcpc2; + + @Schema(description = "鱼类数量") + private Integer fcnt; + + @Schema(description = "对比鱼类数量") + private Integer fcnt2; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeEnvmAutoMonitorVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeEnvmAutoMonitorVo.java new file mode 100644 index 00000000..e84210c8 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeEnvmAutoMonitorVo.java @@ -0,0 +1,27 @@ +package com.yfd.platform.qgc_env.wte.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "环保自动监测开展情况") +public class WeEnvmAutoMonitorVo { + + @Schema(description = "数量") + private Integer cnt; + + @Schema(description = "功能序号") + private Integer orderInx; + + @Schema(description = "功能序号名称") + private String orderInxName; + + @Schema(description = "类型路径") + private String sttpFullPath; + + @Schema(description = "站点类型") + private String sttpCode; + + @Schema(description = "站点类型名称") + private String sttpName; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFishDetailVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFishDetailVo.java new file mode 100644 index 00000000..cae4f59b --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFishDetailVo.java @@ -0,0 +1,36 @@ +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.util.List; + +@Data +@Accessors(chain = true) +@Schema(description = "沿程鱼类变化情况二级弹窗") +public class WeFishDetailVo { + + @Schema(description = "电站编码") + private String rsctd; + + @Schema(description = "电站名称") + private String rsctdName; + + @Schema(description = "鱼类列表") + private List fishList; + + @Schema(description = "断面列表") + private List stcdList; + + @Data + @Accessors(chain = true) + @Schema(description = "断面信息") + public static class StationItem { + @Schema(description = "断面编码") + private String stcd; + + @Schema(description = "断面名称") + private String stnm; + } +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFishHbbQgcDetailVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFishHbbQgcDetailVo.java new file mode 100644 index 00000000..fc73c31a --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFishHbbQgcDetailVo.java @@ -0,0 +1,29 @@ +package com.yfd.platform.qgc_env.wte.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +@Data +@Accessors(chain = true) +@Schema(description = "环保部-沿程鱼类变化情况二级弹窗") +public class WeFishHbbQgcDetailVo { + + @Schema(description = "电站编码") + private String rstcd; + + @Schema(description = "电站名称") + private String rstcdName; + + @Schema(description = "断面编码") + private String stcd; + + @Schema(description = "断面名称") + private String stnm; + + @Schema(description = "鱼类名称") + private String name; + + @Schema(description = "鱼类对应ID") + private String id; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFishPageQgcVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFishPageQgcVo.java new file mode 100644 index 00000000..ad5c68b0 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFishPageQgcVo.java @@ -0,0 +1,37 @@ +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 WeFishPageQgcVo { + + @Schema(description = "鱼类名称") + private String ftp; + + @Schema(description = "科属") + private String genus; + + @Schema(description = "开始年份鱼类总量") + private Integer startFtpCnt; + + @Schema(description = "开始年份总量") + private Integer startCnt; + + @Schema(description = "开始年份占比") + private BigDecimal startYear; + + @Schema(description = "结束年份鱼类总量") + private Integer endFtpCnt; + + @Schema(description = "结束年份总量") + private Integer endCnt; + + @Schema(description = "结束年份占比") + private BigDecimal endYear; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFishPageTableVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFishPageTableVo.java new file mode 100644 index 00000000..99298e48 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFishPageTableVo.java @@ -0,0 +1,22 @@ +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.util.List; + +@Data +@Accessors(chain = true) +@Schema(description = "环保部-水生生态调查二级页面表格") +public class WeFishPageTableVo { + + @Schema(description = "表头") + private List columns; + + @Schema(description = "表格数据") + private Object dataSource; + + @Schema(description = "总数") + private Long total; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFishStatTabVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFishStatTabVo.java new file mode 100644 index 00000000..e5961f0e --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFishStatTabVo.java @@ -0,0 +1,20 @@ +package com.yfd.platform.qgc_env.wte.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +@Data +@Accessors(chain = true) +@Schema(description = "沿程鱼类变化情况二级页面tab页签数据") +public class WeFishStatTabVo { + + @Schema(description = "鱼类类型") + private String ty; + + @Schema(description = "鱼类类型名称") + private String tyName; + + @Schema(description = "鱼类数量") + private Long num; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeStaticsVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeStaticsVo.java index 2dd0928e..83a2e442 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeStaticsVo.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeStaticsVo.java @@ -4,11 +4,37 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.experimental.Accessors; +import java.util.Date; + @Data @Accessors(chain = true) @Schema(description = "水生生态调查概况") public class WeStaticsVo { + @Schema(description = "断面编码") + private String stcd; + + @Schema(description = "断面名称") + private String stnm; + + @Schema(description = "调查批次") + private String dcpc; + + @Schema(description = "调查鱼类") + private String ftp; + + @Schema(description = "调查鱼类名称") + private String ftpName; + + @Schema(description = "鱼类数量") + private Long fcnt; + + @Schema(description = "附件ID") + private String fid; + + @Schema(description = "调查时间") + private Date tm; + @Schema(description = "调查批次数量") private Long dcpcCount; diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeWvaDefaultVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeWvaDefaultVo.java new file mode 100644 index 00000000..d683b725 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeWvaDefaultVo.java @@ -0,0 +1,28 @@ +package com.yfd.platform.qgc_env.wte.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 WeWvaDefaultVo { + + @Schema(description = "站点编码") + private String stcd; + + @Schema(description = "站点名称") + private String stnm; + + @Schema(description = "站类编码") + private String sttpCode; + + @Schema(description = "站类名称") + private String sttpName; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "最新时间") + private Date tm; +} 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 9cf1c024..fe6da23e 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 @@ -4,13 +4,20 @@ import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.common.DataSourceResult; import com.yfd.platform.qgc_env.wte.entity.vo.WeFishListQgcVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeFishListStatQgcVo; +import com.yfd.platform.qgc_env.wte.entity.vo.WeCompareBarTableVo; +import com.yfd.platform.qgc_env.wte.entity.vo.WeEnvmAutoMonitorVo; +import com.yfd.platform.qgc_env.wte.entity.vo.WeFishDetailVo; +import com.yfd.platform.qgc_env.wte.entity.vo.WeFishHbbQgcDetailVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeMsstbprptVo; +import com.yfd.platform.qgc_env.wte.entity.vo.WeFishPageTableVo; 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.WeFishStatTabVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeFishTQgcVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeStaticsVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeTeSpecialAnimalVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeVmsstbprptVo; +import com.yfd.platform.qgc_env.wte.entity.vo.WeWvaDefaultVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeWvaQgcVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeWvaYearQgcVo; @@ -19,6 +26,8 @@ import java.util.Map; public interface WeFishService { + DataSourceResult getWeFishTKendoListCust(DataSourceRequest dataSourceRequest); + DataSourceResult getQgcWeFishTKendoListCust(DataSourceRequest dataSourceRequest); DataSourceResult getQgcWeFishList(DataSourceRequest dataSourceRequest); @@ -29,14 +38,34 @@ public interface WeFishService { DataSourceResult getWvaList(DataSourceRequest dataSourceRequest); + DataSourceResult getWvaDefaultList(DataSourceRequest dataSourceRequest); + DataSourceResult getWvaDefaultYearList(DataSourceRequest dataSourceRequest); + DataSourceResult getWeCompareBarList(DataSourceRequest dataSourceRequest); + + DataSourceResult getQgcWeFishPageList(DataSourceRequest dataSourceRequest); + + DataSourceResult getEnvmAutoMonitorList(DataSourceRequest dataSourceRequest); + DataSourceResult>> getQgcFishStaticsYearList(DataSourceRequest dataSourceRequest); DataSourceResult getQgcWeFishStatics(DataSourceRequest dataSourceRequest); + DataSourceResult getWeStaticsSecond(DataSourceRequest dataSourceRequest); + DataSourceResult getQgcWeFishStatList(DataSourceRequest dataSourceRequest); + DataSourceResult getWeFishStatList(DataSourceRequest dataSourceRequest); + + DataSourceResult getQgcWeFishDetailList(DataSourceRequest dataSourceRequest); + + DataSourceResult getHbbQgcWeFishDetailList(DataSourceRequest dataSourceRequest); + + DataSourceResult getWeFishDetailList(DataSourceRequest dataSourceRequest); + + DataSourceResult getWeFishStatTabList(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 fbaaf40c..d6fa20be 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 @@ -10,16 +10,26 @@ 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.qgc_env.wte.entity.vo.WeCompareBarHeadColumnVo; +import com.yfd.platform.qgc_env.wte.entity.vo.WeCompareBarTableVo; +import com.yfd.platform.qgc_env.wte.entity.vo.WeCompareBarVo; +import com.yfd.platform.qgc_env.wte.entity.vo.WeEnvmAutoMonitorVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeFishListQgcVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeFishListStatQgcVo; +import com.yfd.platform.qgc_env.wte.entity.vo.WeFishDetailVo; +import com.yfd.platform.qgc_env.wte.entity.vo.WeFishHbbQgcDetailVo; +import com.yfd.platform.qgc_env.wte.entity.vo.WeFishPageQgcVo; +import com.yfd.platform.qgc_env.wte.entity.vo.WeFishPageTableVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeMsstbprptVo; 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.WeFishStatTabVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeFishTQgcVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeRvcdYearVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeStaticsVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeTeSpecialAnimalVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeVmsstbprptVo; +import com.yfd.platform.qgc_env.wte.entity.vo.WeWvaDefaultVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeWvaQgcVo; import com.yfd.platform.qgc_env.wte.entity.vo.WeWvaYearQgcVo; import com.yfd.platform.qgc_env.wte.service.WeFishService; @@ -45,6 +55,57 @@ public class WeFishServiceImpl implements WeFishService { @Resource private MicroservicDynamicSQLMapper microservicDynamicSQLMapper; + @Override + public DataSourceResult getWeFishTKendoListCust(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + GroupingInfo[] groupInfos = loadOptions == null ? null : loadOptions.getGroup(); + Map paramMap = new HashMap<>(); + + String filterSql = buildWeFishQgcFilterCondition( + dataSourceRequest == null ? null : dataSourceRequest.getFilter(), + paramMap, + new int[]{0} + ); + + StringBuilder sql = new StringBuilder(); + sql.append("SELECT r.* FROM (") + .append(buildWeFishTDetailSql()) + .append(") r WHERE 1 = 1 "); + if (StrUtil.isNotBlank(filterSql)) { + sql.append(" AND ").append(filterSql).append(" "); + } + + DataSourceResult result = new DataSourceResult<>(); + if (CollUtil.isNotEmpty(dataSourceRequest == null ? null : dataSourceRequest.getGroup())) { + String groupedSql = buildWeFishQgcGroupSql(sql.toString(), groupInfos); + List> rows = microservicDynamicSQLMapper.getAllList(groupedSql, paramMap); + if (Boolean.TRUE.equals(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((long) rows.size()); + result.setAggregates(new HashMap<>()); + return result; + } + + sql.append(buildWeFishQgcOrderBySql(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, + WeFishTQgcVo.class + ); + fillWeFishDerivedFields(list); + + result.setData(list); + result.setTotal(page != null ? page.getTotal() : list.size()); + result.setAggregates(new HashMap<>()); + return result; + } + @Override public DataSourceResult getQgcWeFishTKendoListCust(DataSourceRequest dataSourceRequest) { DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); @@ -267,6 +328,64 @@ public class WeFishServiceImpl implements WeFishService { return result; } + @Override + public DataSourceResult getWvaDefaultList(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + Map innerParamMap = new HashMap<>(); + Map outerParamMap = new HashMap<>(); + + String innerFilterSql = buildWeWvaDefaultInnerFilterCondition( + dataSourceRequest == null ? null : dataSourceRequest.getFilter(), + innerParamMap, + new int[]{0} + ); + String outerFilterSql = buildWeWvaDefaultOuterFilterCondition( + dataSourceRequest == null ? null : dataSourceRequest.getFilter(), + outerParamMap, + new int[]{0} + ); + + StringBuilder sql = new StringBuilder(); + sql.append("SELECT t.stcd AS stcd, t.stnm AS stnm, t.tm AS tm, t.sttpCode AS sttpCode, t.sttpName AS sttpName ") + .append("FROM (") + .append("SELECT latest.stcd AS stcd, ai.STNM AS stnm, latest.tm AS tm, ai.STTP AS sttpCode, sttp.STTP_NAME AS sttpName, ") + .append("ai.RSTCD AS rstcd, ai.BASE_ID AS baseId, ai.HBRVCD AS hbrvcd ") + .append("FROM (SELECT src.STCD AS stcd, MAX(src.TM) AS tm FROM SD_WVA_R src WHERE NVL(src.IS_DELETED, 0) = 0 "); + if (StrUtil.isNotBlank(innerFilterSql)) { + sql.append("AND ").append(innerFilterSql).append(" "); + } + sql.append("GROUP BY src.STCD) latest ") + .append("INNER JOIN SD_AIMONITOR_B_H ai ON latest.stcd = ai.STCD ") + .append("AND NVL(ai.IS_DELETED, 0) = 0 ") + .append("AND ai.STTP = 'WVA' ") + .append("LEFT JOIN SD_STTP_B sttp ON ai.STTP = sttp.STTP_CODE ") + .append("AND NVL(sttp.IS_DELETED, 0) = 0 ") + .append(") t WHERE 1 = 1 "); + if (StrUtil.isNotBlank(outerFilterSql)) { + sql.append("AND ").append(outerFilterSql).append(" "); + } + sql.append(buildWeWvaDefaultOrderBySql(dataSourceRequest == null ? null : dataSourceRequest.getSort())); + + Map paramMap = new HashMap<>(); + paramMap.putAll(innerParamMap); + paramMap.putAll(outerParamMap); + + Page page = loadOptions == null ? null + : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + List list = microservicDynamicSQLMapper.pageAllListWithResultType( + page, + sql.toString(), + paramMap, + WeWvaDefaultVo.class + ); + + DataSourceResult result = new DataSourceResult<>(); + result.setData(list); + result.setTotal(page != null ? page.getTotal() : (long) list.size()); + result.setAggregates(new HashMap<>()); + return result; + } + @Override public DataSourceResult getWvaList(DataSourceRequest dataSourceRequest) { DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); @@ -311,6 +430,317 @@ public class WeFishServiceImpl implements WeFishService { return result; } + @Override + public DataSourceResult getWeCompareBarList(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + DataSourceRequest.FilterDescriptor filter = dataSourceRequest == null ? null : dataSourceRequest.getFilter(); + + String stcd = getFirstWeFishFilterText(filter, "stcd"); + String dcpc = getFirstWeFishFilterText(filter, "dcpc"); + String dcpc2 = getFirstWeFishFilterText(filter, "dcpc2"); + + List list = new ArrayList<>(); + long total = 0L; + if (StrUtil.isNotBlank(stcd) && StrUtil.isNotBlank(dcpc) && StrUtil.isNotBlank(dcpc2)) { + Map paramMap = new HashMap<>(); + paramMap.put("stcd", stcd); + paramMap.put("dcpc", dcpc); + paramMap.put("dcpc2", dcpc2); + + String sql = "SELECT dict.NAME AS ftp, " + + "MAX(NVL(dict.FAMILY, '') || NVL(dict.GENUS, '')) AS genus, " + + "#{map.dcpc} AS dcpc, " + + "#{map.dcpc2} AS dcpc2, " + + "SUM(CASE WHEN we.DCPC = #{map.dcpc} THEN NVL(fish.FCNT, 0) ELSE 0 END) AS fcnt, " + + "SUM(CASE WHEN we.DCPC = #{map.dcpc2} THEN NVL(fish.FCNT, 0) ELSE 0 END) AS fcnt2 " + + "FROM SD_WE_R we " + + "INNER JOIN SD_WEFISH_R fish ON we.ID = fish.WER_ID AND NVL(fish.IS_DELETED, 0) = 0 " + + "INNER JOIN SD_WE_B_H section ON section.STCD = we.STCD AND NVL(section.USFL, 0) = 1 " + + "INNER JOIN SD_FISHDICTORY_B dict ON dict.ID = fish.FTP AND NVL(dict.IS_DELETED, 0) = 0 " + + "WHERE NVL(we.IS_DELETED, 0) = 0 " + + "AND NVL(we.STATUS, 1) = 1 " + + "AND we.STCD = #{map.stcd} " + + "AND we.DCPC IN (#{map.dcpc}, #{map.dcpc2}) " + + "GROUP BY dict.NAME " + + "ORDER BY dict.NAME"; + + Page page = loadOptions == null ? null + : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + list = microservicDynamicSQLMapper.pageAllListWithResultType(page, sql, paramMap, WeCompareBarVo.class); + total = page != null ? page.getTotal() : list.size(); + } + + WeCompareBarTableVo tableVo = new WeCompareBarTableVo() + .setColumns(buildWeCompareBarColumns(dcpc, dcpc2)) + .setDataSource(list) + .setTotal(total); + + DataSourceResult result = new DataSourceResult<>(); + result.setData(Collections.singletonList(tableVo)); + result.setTotal(total); + result.setAggregates(new HashMap<>()); + return result; + } + + @Override + public DataSourceResult getQgcWeFishPageList(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + DataSourceRequest.FilterDescriptor filter = dataSourceRequest == null ? null : dataSourceRequest.getFilter(); + + String startYear = resolveWeFishStringFilterValue(dataSourceRequest, loadOptions, "startYear"); + String endYear = resolveWeFishStringFilterValue(dataSourceRequest, loadOptions, "endYear"); + if (StrUtil.isBlank(startYear)) { + throw new IllegalArgumentException("开始年份不能为空!"); + } + if (StrUtil.isBlank(endYear)) { + throw new IllegalArgumentException("结束年份(endYear)不能为空!"); + } + + String baseId = resolveWeFishStringFilterValue(dataSourceRequest, loadOptions, "baseId"); + String hbrvcd = resolveWeFishStringFilterValue(dataSourceRequest, loadOptions, "hbrvcd"); + String rstcd = resolveWeFishStringFilterValue(dataSourceRequest, loadOptions, "rstcd"); + String ftp = resolveWeFishStringFilterValue(dataSourceRequest, loadOptions, "ftp"); + + Map paramMap = new HashMap<>(); + paramMap.put("startYear", startYear); + paramMap.put("endYear", endYear); + + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ftp, genus, startFtpCnt, startCnt, startYear, endFtpCnt, endCnt, endYear ") + .append("FROM (") + .append("SELECT dict.NAME AS ftp, ") + .append("CONCAT(CONCAT(dict.FAMILY,'-'),dict.GENUS) as genus, ") + .append("agg.startYear AS startYear, agg.endYear AS endYear, ") + .append("agg.startCnt AS startCnt, agg.startFtpCnt AS startFtpCnt, ") + .append("agg.endCnt AS endCnt, agg.endFtpCnt AS endFtpCnt ") + .append("FROM (") + .append("SELECT ftp, hbrvcd, ") + .append("ROUND(MAX(startYear), 2) AS startYear, ") + .append("ROUND(MAX(endYear), 2) AS endYear, ") + .append("MAX(startCnt) AS startCnt, ") + .append("MAX(startFtpCnt) AS startFtpCnt, ") + .append("MAX(endCnt) AS endCnt, ") + .append("MAX(endFtpCnt) AS endFtpCnt ") + .append("FROM (") + .append("SELECT fishAgg.ftp AS ftp, fishAgg.hbrvcd AS hbrvcd, fishAgg.fcnt AS fcnt, ") + .append("CASE WHEN fishAgg.yr = #{map.startYear} ") + .append("THEN CASE WHEN NVL(totalAgg.fcnt, 0) = 0 THEN 0 ELSE 100 * fishAgg.fcnt / totalAgg.fcnt END END AS startYear, ") + .append("CASE WHEN fishAgg.yr = #{map.endYear} ") + .append("THEN CASE WHEN NVL(totalAgg.fcnt, 0) = 0 THEN 0 ELSE 100 * fishAgg.fcnt / totalAgg.fcnt END END AS endYear, ") + .append("CASE WHEN fishAgg.yr = #{map.startYear} THEN fishAgg.fcnt END AS startFtpCnt, ") + .append("CASE WHEN fishAgg.yr = #{map.startYear} THEN totalAgg.fcnt END AS startCnt, ") + .append("CASE WHEN fishAgg.yr = #{map.endYear} THEN fishAgg.fcnt END AS endFtpCnt, ") + .append("CASE WHEN fishAgg.yr = #{map.endYear} THEN totalAgg.fcnt END AS endCnt ") + .append("FROM (") + .append("SELECT fish.FTP AS ftp, section.HBRVCD AS hbrvcd, SUM(NVL(fish.FCNT, 0)) AS fcnt, TO_CHAR(we.TM, 'YYYY') AS yr ") + .append("FROM SD_WE_R we ") + .append("INNER JOIN SD_WEFISH_R fish ON we.ID = fish.WER_ID ") + .append(" AND NVL(fish.IS_DELETED, 0) = 0 ") + .append("INNER JOIN SD_WE_B_H section ON section.STCD = we.STCD ") + .append("INNER JOIN V_SD_FISHDICTORY_B dictFilter ON dictFilter.FISH_ID = fish.FTP ") + .append(" AND (section.HBRVCD = dictFilter.RVCD OR dictFilter.RVCD = 'ZY') ") + .append("WHERE NVL(we.STATUS, 1) = 1 ") + .append("AND NVL(we.IS_DELETED, 0) = 0 ") + .append("AND TO_CHAR(we.TM, 'YYYY') IN (#{map.startYear}, #{map.endYear}) "); + if (StrUtil.isNotBlank(baseId)) { + paramMap.put("fishPageBaseId", baseId); + sql.append("AND section.BASE_ID = #{map.fishPageBaseId} "); + } + if (StrUtil.isNotBlank(hbrvcd)) { + paramMap.put("fishPageHbrvcd", hbrvcd); + sql.append("AND section.HBRVCD = #{map.fishPageHbrvcd} "); + } + if (StrUtil.isNotBlank(rstcd)) { + paramMap.put("fishPageRstcd", rstcd); + sql.append("AND section.RSTCD = #{map.fishPageRstcd} "); + } + sql.append("GROUP BY fish.FTP, section.HBRVCD, TO_CHAR(we.TM, 'YYYY') ") + .append(") fishAgg ") + .append("LEFT JOIN (") + .append("SELECT SUM(NVL(fish.FCNT, 0)) AS fcnt, TO_CHAR(we.TM, 'YYYY') AS yr ") + .append("FROM SD_WE_R we ") + .append("INNER JOIN SD_WEFISH_R fish ON we.ID = fish.WER_ID ") + .append(" AND NVL(fish.IS_DELETED, 0) = 0 ") + .append("INNER JOIN SD_WE_B_H section ON section.STCD = we.STCD ") + .append("INNER JOIN V_SD_FISHDICTORY_B dictFilter ON dictFilter.FISH_ID = fish.FTP ") + .append(" AND (section.HBRVCD = dictFilter.RVCD OR dictFilter.RVCD = 'ZY') ") + .append("WHERE NVL(we.STATUS, 1) = 1 ") + .append("AND NVL(we.IS_DELETED, 0) = 0 ") + .append("AND TO_CHAR(we.TM, 'YYYY') IN (#{map.startYear}, #{map.endYear}) "); + if (StrUtil.isNotBlank(baseId)) { + sql.append("AND section.BASE_ID = #{map.fishPageBaseId} "); + } + if (StrUtil.isNotBlank(hbrvcd)) { + sql.append("AND section.HBRVCD = #{map.fishPageHbrvcd} "); + } + if (StrUtil.isNotBlank(rstcd)) { + sql.append("AND section.RSTCD = #{map.fishPageRstcd} "); + } + sql.append("GROUP BY TO_CHAR(we.TM, 'YYYY') ") + .append(") totalAgg ON totalAgg.yr = fishAgg.yr ") + .append(") temp ") + .append("GROUP BY ftp, hbrvcd ") + .append(") agg ") + .append("INNER JOIN V_SD_FISHDICTORY_B dict ON dict.FISH_ID = agg.ftp ") + .append(" AND (agg.HBRVCD = dict.RVCD OR dict.RVCD = 'ZY')") + .append(") r WHERE 1 = 1 "); + if (StrUtil.isNotBlank(ftp)) { + paramMap.put("fishPageFtp", "%" + ftp.trim() + "%"); + sql.append("AND r.ftp LIKE #{map.fishPageFtp} "); + } + sql.append(buildWeFishPageOrderBySql(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, + WeFishPageQgcVo.class + ); + long total = page != null ? page.getTotal() : list.size(); + + WeFishPageTableVo tableVo = new WeFishPageTableVo() + .setColumns(buildWeFishPageColumns(startYear, endYear)) + .setDataSource(list) + .setTotal(total); + + DataSourceResult result = new DataSourceResult<>(); + result.setData(Collections.singletonList(tableVo)); + result.setTotal(total); + result.setAggregates(new HashMap<>()); + return result; + } + + @Override + public DataSourceResult getEnvmAutoMonitorList(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + DataSourceRequest.FilterDescriptor filter = dataSourceRequest == null ? null : dataSourceRequest.getFilter(); + + String baseId = resolveWeFishStringFilterValue(dataSourceRequest, loadOptions, "baseId"); + Date startTime = toDateValue(resolveWeFishStringFilterValue(dataSourceRequest, loadOptions, "startTime")); + Date endTime = toDateValue(resolveWeFishStringFilterValue(dataSourceRequest, loadOptions, "endTime")); + if (startTime == null || endTime == null) { + startTime = null; + endTime = null; + } + + List rstcds = getWeFishFilterTexts(filter, "rstcd"); + List hbrvcds = getWeFishFilterTexts(filter, "hbrvcd"); + List rvcds = getWeFishFilterTexts(filter, "rvcd"); + List showIds = getWeFishFilterTexts(filter, "showIds"); + boolean ignoreFhRstcd = shouldIgnoreWeEnvmFhRstcd(rstcds); + + List rows = new ArrayList<>(); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmWtSql(baseId, rstcds)), + 1, null, "ENV,ENVM,WT,", "水温监测" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmGjWqSql(baseId, hbrvcds, rvcds)), + 2, "WQ", "ENV,ENVM,WQ,", "国家水质站" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmZjWqSql(baseId, rstcds)), + 3, "WQ", "ENV,ENVM,WQ,", "水质监测" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmStGjSql(baseId)), + 5, null, "ST,ZQ-ST,ZZ", "国家水文站" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmStZjSql(baseId, rstcds)), + 6, null, "ST,ZQ-ST,ZZ", "水文监测" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmEngQecSql(baseId, rstcds)), + 7, "ENG", "ENG", "生态流量" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmVdSql(baseId, rstcds)), + 8, null, "VD,VD", "视频监控" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmRiverWqSql(baseId, rstcds)), + 9, "WQ", "ENV,ENVM,WQ,", "河道水质监测" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmFbWqSql(baseId, rstcds)), + 10, "WQFB", "ENV,ENVM,WQFB,", "增殖站水质站" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmFhSql(baseId, rstcds, ignoreFhRstcd)), + 11, "FH", "ENV,ENVP,FH,", "栖息地" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmFhWqSql(baseId, rstcds, ignoreFhRstcd)), + 12, "WQ", "ENV,ENVM,WQ,", "栖息地水质监测" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmFhWtSql(baseId, rstcds, ignoreFhRstcd)), + 13, "WTRV", "ENV,ENVM,WT,WTRV,", "栖息地水温监测" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmFhStSql(baseId, rstcds, ignoreFhRstcd)), + 14, null, "ST,ZQ-ST,ZZ", "水文监测" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmWeSql(baseId, rstcds)), + 15, "WE", "ENV,ENVM,WE,", "水生态调查断面" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmWvaSql(baseId, rstcds, hbrvcds)), + 16, "WVA", "ENV,ENVM,WVA,", "野生动物监测" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmVdEqsSql(baseId, rstcds)), + 17, "VD_EQS", "VD,VD_EQS,", "生态流量视频站" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmRareFishSql(baseId, rstcds, startTime, endTime)), + 18, null, "WE_FISH", "土著珍稀鱼类" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmTeAnimalsSql()), + 20, "TE_ANIMALS", "TE_ANIMALS", "重点陆生动物" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmRgWqSql(baseId, rstcds)), + 21, "WQ", "ENV,ENVM,WQ,", "人工水质监测" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmWeFishStaticsSql(baseId, rstcds, startTime, endTime)), + 22, "WE", "WE_FISH_ST", "调查鱼类统计" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmFpStaticsSql(baseId, rstcds)), + 23, "FP", "ENV,ENVP,FP,", "过鱼设施" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmVdYljSql(baseId, rstcds)), + 24, null, "VD,VD", "视频监控" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmAiSql(baseId, rstcds, hbrvcds)), + 25, "AI", "AI,AI_", "AI盒子" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmWtrvSql(baseId, rstcds)), + 26, null, "ENV,ENVM,WT,", "表层水温监测" + )); + rows.add(buildWeEnvmAutoMonitorVo( + queryWeEnvmAutoMonitorCount(buildWeEnvmWtvtSql(baseId, rstcds)), + 27, null, "ENV,ENVM,WT,", "垂向水温监测" + )); + + List finalRows = reorderWeEnvmAutoMonitorRows(rows, showIds); + DataSourceResult result = new DataSourceResult<>(); + result.setData(finalRows); + result.setTotal((long) finalRows.size()); + result.setAggregates(new HashMap<>()); + return result; + } + @Override public DataSourceResult>> getQgcFishStaticsYearList(DataSourceRequest dataSourceRequest) { Map paramMap = new HashMap<>(); @@ -372,6 +802,174 @@ public class WeFishServiceImpl implements WeFishService { return result; } + @Override + public DataSourceResult getWeStaticsSecond(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + GroupingInfo[] groupInfos = loadOptions == null ? null : loadOptions.getGroup(); + Map paramMap = new HashMap<>(); + + String filterSql = buildWeFishQgcFilterCondition( + dataSourceRequest == null ? null : dataSourceRequest.getFilter(), + paramMap, + new int[]{0} + ); + + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append(buildWeStaticsSecondSelectSql(dataSourceRequest == null ? null : dataSourceRequest.getSelect())) + .append(" FROM (") + .append(buildWeFishQgcDetailSql()) + .append(") r WHERE 1 = 1 "); + if (StrUtil.isNotBlank(filterSql)) { + sql.append(" AND ").append(filterSql).append(" "); + } + + DataSourceResult result = new DataSourceResult<>(); + if (CollUtil.isNotEmpty(dataSourceRequest == null ? null : dataSourceRequest.getGroup())) { + String groupedSql = buildWeFishQgcGroupSql(sql.toString(), groupInfos); + List> rows = microservicDynamicSQLMapper.getAllList(groupedSql, paramMap); + if (Boolean.TRUE.equals(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((long) rows.size()); + result.setAggregates(new HashMap<>()); + return result; + } + + sql.append(buildWeFishQgcOrderBySql(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, + WeStaticsVo.class + ); + + result.setData(list); + result.setTotal(page != null ? page.getTotal() : list.size()); + result.setAggregates(new HashMap<>()); + return result; + } + + @Override + public DataSourceResult getWeFishStatList(DataSourceRequest dataSourceRequest) { + Map paramMap = new HashMap<>(); + DataSourceRequest.FilterDescriptor filter = dataSourceRequest == null ? null : dataSourceRequest.getFilter(); + + String baseId = getFirstWeFishFilterText(filter, "baseId"); + String hbrvcd = getFirstWeFishFilterText(filter, "hbrvcd"); + String yr = getFirstWeFishFilterText(filter, "yr"); + List rstcdList = getWeFishFilterTexts(filter, "rstcd"); + + String sql = buildWeFishStatSql(baseId, hbrvcd, yr, rstcdList, paramMap); + List> rows = microservicDynamicSQLMapper.getAllList(sql, paramMap); + return buildWeFishStatResult(rows); + } + + @Override + public DataSourceResult getQgcWeFishDetailList(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + Page page = loadOptions == null ? null + : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + Map paramMap = new HashMap<>(); + DataSourceRequest.FilterDescriptor filter = dataSourceRequest == null ? null : dataSourceRequest.getFilter(); + + String baseId = firstNonBlankWeFishFilter(filter, "baseId", "base_id"); + String rstcd = getFirstWeFishFilterText(filter, "stcd"); + String rvcd = firstNonBlankWeFishFilter(filter, "rvcd", "hbrvcd"); + String yr = getFirstWeFishFilterText(filter, "yr"); + String ty = getFirstWeFishFilterText(filter, "ty"); + + String sql = buildQgcWeFishDetailSql(baseId, rstcd, rvcd, yr, ty, paramMap); + List> rows = microservicDynamicSQLMapper.pageAllList(page, sql, paramMap); + + DataSourceResult result = new DataSourceResult<>(); + result.setData(buildQgcWeFishDetailResult(rows)); + result.setTotal(page != null ? page.getTotal() : (long) rows.size()); + result.setAggregates(new HashMap<>()); + return result; + } + + @Override + public DataSourceResult getHbbQgcWeFishDetailList(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + Page page = loadOptions == null ? null + : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + Map paramMap = new HashMap<>(); + DataSourceRequest.FilterDescriptor filter = dataSourceRequest == null ? null : dataSourceRequest.getFilter(); + + String baseId = firstNonBlankWeFishFilter(filter, "baseId", "base_id"); + String rstcd = getFirstWeFishFilterText(filter, "stcd"); + String rvcd = firstNonBlankWeFishFilter(filter, "rvcd", "hbrvcd"); + String yr = getFirstWeFishFilterText(filter, "yr"); + String ty = getFirstWeFishFilterText(filter, "ty"); + + String sql = buildHbbQgcWeFishDetailSql(baseId, rstcd, rvcd, yr, ty, paramMap); + List> rows = microservicDynamicSQLMapper.pageAllList(page, sql, paramMap); + + DataSourceResult result = new DataSourceResult<>(); + result.setData(buildHbbQgcWeFishDetailResult(rows)); + result.setTotal(page != null ? page.getTotal() : (long) rows.size()); + result.setAggregates(new HashMap<>()); + return result; + } + + @Override + public DataSourceResult getWeFishDetailList(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + Page page = loadOptions == null ? null + : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + Map paramMap = new HashMap<>(); + DataSourceRequest.FilterDescriptor filter = dataSourceRequest == null ? null : dataSourceRequest.getFilter(); + + String baseId = firstNonBlankWeFishFilter(filter, "baseId", "base_id"); + String rstcd = getFirstWeFishFilterText(filter, "stcd"); + String rvcd = firstNonBlankWeFishFilter(filter, "rvcd", "hbrvcd"); + String yr = getFirstWeFishFilterText(filter, "yr"); + String ty = getFirstWeFishFilterText(filter, "ty"); + + String sql = buildWeFishDetailSql(baseId, rstcd, rvcd, yr, ty, paramMap); + List> rows = microservicDynamicSQLMapper.pageAllList(page, sql, paramMap); + + DataSourceResult result = new DataSourceResult<>(); + result.setData(buildWeFishDetailResult(rows)); + result.setTotal(page != null ? page.getTotal() : (long) rows.size()); + result.setAggregates(new HashMap<>()); + return result; + } + + @Override + public DataSourceResult getWeFishStatTabList(DataSourceRequest dataSourceRequest) { + Map paramMap = new HashMap<>(); + DataSourceRequest.FilterDescriptor filter = dataSourceRequest == null ? null : dataSourceRequest.getFilter(); + + String baseId = firstNonBlankWeFishFilter(filter, "baseId", "base_id"); + String rstcd = getFirstWeFishFilterText(filter, "stcd"); + String rvcd = firstNonBlankWeFishFilter(filter, "rvcd", "hbrvcd"); + String yr = getFirstWeFishFilterText(filter, "yr"); + + String sql = buildWeFishStatTabSql(baseId, rstcd, rvcd, yr, paramMap); + List list = microservicDynamicSQLMapper.getAllListWithResultType( + sql, + paramMap, + WeFishStatTabVo.class + ); + if (CollUtil.isNotEmpty(list)) { + for (WeFishStatTabVo item : list) { + item.setTyName(resolveTyName(toWeFishIntegerValue(item.getTy()))); + } + } + + DataSourceResult result = new DataSourceResult<>(); + result.setData(list); + result.setTotal(list == null ? 0L : list.size()); + result.setAggregates(new HashMap<>()); + return result; + } + @Override public DataSourceResult getQgcWeFishStatList(DataSourceRequest dataSourceRequest) { Map paramMap = new HashMap<>(); @@ -679,14 +1277,15 @@ public class WeFishServiceImpl implements WeFishService { .append("FROM SD_WE_B_H section ") .append("INNER JOIN SD_WE_R we ON section.STCD = we.STCD ") .append(" AND NVL(we.IS_DELETED, 0) = 0 ") - .append(" AND NVL(we.STATUS, 1) = 1 ") +// .append(" AND NVL(we.STATUS, 1) = 1 ") .append("INNER JOIN SD_WEFISH_R fish ON we.ID = fish.WER_ID ") .append(" AND NVL(fish.IS_DELETED, 0) = 0 ") .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = section.RSTCD ") .append(" AND NVL(eng.IS_DELETED, 0) = 0 ") .append("LEFT JOIN V_SD_FISHDICTORY_B dict ON fish.FTP = dict.FISH_ID ") .append(" AND (section.HBRVCD = dict.RVCD OR dict.RVCD = 'ZY') ") - .append("WHERE NVL(section.USFL, 0) = 1 "); + .append("WHERE 1 = 1 "); +// .append("WHERE NVL(section.USFL, 0) = 1 "); if (StrUtil.isNotBlank(baseId)) { paramMap.put("weFishStatBaseId", baseId); @@ -740,6 +1339,478 @@ public class WeFishServiceImpl implements WeFishService { return sql.toString(); } + private String buildWeFishStatSql(String baseId, + String hbrvcd, + String yr, + List rstcdList, + Map paramMap) { + StringBuilder sql = new StringBuilder(); + sql.append("SELECT t.STCD AS stcd, t.STNM AS stnm, t.NUM AS num, t.TY AS ty, t2.SORT AS sort ") + .append("FROM (") + .append("SELECT section.RSTCD AS STCD, ") + .append("eng.ENNM AS STNM, ") + .append("COUNT(DISTINCT fish.FTP) AS NUM, ") + .append("CASE ") + .append("WHEN dict.SPEC_ORIGIN = 2 THEN '1' ") + .append("WHEN dict.SPEC_ORIGIN = 1 AND NVL(dict.PTYPE, -1) <> 6 THEN '2' ") + .append("WHEN dict.SPEC_ORIGIN = 1 AND dict.PTYPE = 6 THEN '3' ") + .append("END AS TY, ") + .append("TO_CHAR(we.TM, 'yyyy') AS YR ") + .append("FROM SD_WE_B_H section ") + .append("INNER JOIN SD_WE_R we ON section.STCD = we.STCD ") + .append(" AND NVL(we.IS_DELETED, 0) = 0 ") + .append(" AND NVL(we.STATUS, 1) = 1 ") + .append("INNER JOIN SD_WEFISH_R fish ON we.ID = fish.WER_ID ") + .append(" AND NVL(fish.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = section.RSTCD ") + .append(" AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN SD_FISHDICTORY_B dict ON fish.FTP = dict.ID ") + .append(" AND NVL(dict.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(section.USFL, 0) = 1 "); + + if (StrUtil.isNotBlank(baseId)) { + paramMap.put("weFishStatBaseId", baseId); + sql.append("AND section.BASE_ID = #{map.weFishStatBaseId} "); + } + if (StrUtil.isNotBlank(hbrvcd)) { + paramMap.put("weFishStatHbrvcd", hbrvcd); + sql.append("AND section.HBRVCD = #{map.weFishStatHbrvcd} "); + } + sql.append("AND section.RSTCD IS NOT NULL ") + .append("AND dict.SPEC_ORIGIN IS NOT NULL ") + .append("GROUP BY section.RSTCD, eng.ENNM, ") + .append("CASE ") + .append("WHEN dict.SPEC_ORIGIN = 2 THEN '1' ") + .append("WHEN dict.SPEC_ORIGIN = 1 AND NVL(dict.PTYPE, -1) <> 6 THEN '2' ") + .append("WHEN dict.SPEC_ORIGIN = 1 AND dict.PTYPE = 6 THEN '3' ") + .append("END, ") + .append("TO_CHAR(we.TM, 'yyyy') ") + .append(") t ") + .append("INNER JOIN (") + .append("SELECT det.STCD, det.SORT ") + .append("FROM MS_ALONG_B cfg ") + .append("INNER JOIN MS_ALONGDET_B det ON cfg.ID = det.ALONG_ID ") + .append("WHERE det.STTP = 'ENG' ") + .append(" AND cfg.CODE = 'common' ") + .append(" AND NVL(det.IS_DELETED, 0) = 0 ") + .append(" AND NVL(cfg.IS_DELETED, 0) = 0") + .append(") t2 ON t.STCD = t2.STCD ") + .append("WHERE t.TY IS NOT NULL "); + + if (StrUtil.isNotBlank(yr)) { + paramMap.put("weFishStatYr", yr); + sql.append("AND t.YR = #{map.weFishStatYr} "); + } + if (CollUtil.isNotEmpty(rstcdList)) { + List placeholders = new ArrayList<>(); + int index = 0; + for (String rstcd : rstcdList) { + if (StrUtil.isBlank(rstcd)) { + continue; + } + String key = "weFishStatRstcd" + index++; + paramMap.put(key, rstcd); + placeholders.add("#{map." + key + "}"); + } + if (CollUtil.isNotEmpty(placeholders)) { + sql.append("AND t.STCD IN (").append(String.join(", ", placeholders)).append(") "); + } + } + sql.append("ORDER BY t2.SORT ASC NULLS LAST"); + return sql.toString(); + } + + private DataSourceResult buildWeFishStatResult(List> rows) { + LinkedHashMap resultMap = new LinkedHashMap<>(); + for (Map row : rows) { + String stcd = safeWeFishString(firstPresentWeFishValue(row, "STCD", "stcd")); + if (StrUtil.isBlank(stcd)) { + continue; + } + WeFishStatQgcVo vo = resultMap.computeIfAbsent(stcd, key -> { + WeFishStatQgcVo item = new WeFishStatQgcVo(); + item.setStcd(key); + item.setStnm(safeWeFishString(firstPresentWeFishValue(row, "STNM", "stnm"))); + item.setSort(toWeFishIntegerValue(firstPresentWeFishValue(row, "SORT", "sort"))); + item.setTotal(0L); + item.setDetail(new LinkedHashMap<>()); + return item; + }); + Long num = toWeFishLongValue(firstPresentWeFishValue(row, "NUM", "num")); + if (num == null) { + num = 0L; + } + String ty = safeWeFishString(firstPresentWeFishValue(row, "TY", "ty")); + if (StrUtil.isNotBlank(ty)) { + vo.getDetail().put(ty, num); + } + vo.setTotal((vo.getTotal() == null ? 0L : vo.getTotal()) + num); + } + + DataSourceResult result = new DataSourceResult<>(); + result.setData(new ArrayList<>(resultMap.values())); + result.setTotal((long) resultMap.size()); + result.setAggregates(new HashMap<>()); + return result; + } + + private String buildQgcWeFishDetailSql(String baseId, + String rstcd, + String rvcd, + String yr, + String ty, + Map paramMap) { + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append("section.RSTCD AS rstcd, ") + .append("eng.ENNM AS rstcdName, ") + .append("TO_CHAR(WM_CONCAT(DISTINCT section.STCD)) AS stcd, ") + .append("TO_CHAR(WM_CONCAT(DISTINCT section.STNM)) AS stnm, ") + .append("TO_CHAR(WM_CONCAT(DISTINCT dict.ZY_FISH_ID)) AS id ") + .append("FROM SD_WE_B_H section ") + .append("INNER JOIN SD_WE_R we ON section.STCD = we.STCD ") + .append(" AND NVL(we.IS_DELETED, 0) = 0 ") + .append(" AND NVL(we.STATUS, 1) = 1 ") + .append("INNER JOIN SD_WEFISH_R fish ON we.ID = fish.WER_ID ") + .append(" AND NVL(fish.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON section.RSTCD = eng.STCD ") + .append(" AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN V_SD_FISHDICTORY_B dict ON fish.FTP = dict.FISH_ID ") + .append(" AND (section.HBRVCD = dict.RVCD OR dict.RVCD = 'ZY') ") + .append("WHERE NVL(section.USFL, 0) = 1 ") + .append("AND section.RSTCD IS NOT NULL ") + .append("AND dict.ZY_FISH_ID IS NOT NULL "); + + if (StrUtil.isNotBlank(baseId)) { + paramMap.put("qgcWeFishDetailBaseId", baseId); + sql.append("AND section.BASE_ID = #{map.qgcWeFishDetailBaseId} "); + } + if (StrUtil.isNotBlank(rstcd)) { + paramMap.put("qgcWeFishDetailRstcd", rstcd); + sql.append("AND section.RSTCD = #{map.qgcWeFishDetailRstcd} "); + } + if (StrUtil.isNotBlank(rvcd)) { + paramMap.put("qgcWeFishDetailRvcd", rvcd); + sql.append("AND section.HBRVCD = #{map.qgcWeFishDetailRvcd} "); + } + if (StrUtil.isNotBlank(yr)) { + paramMap.put("qgcWeFishDetailYr", yr); + sql.append("AND TO_CHAR(we.TM, 'yyyy') = #{map.qgcWeFishDetailYr} "); + } + if (StrUtil.isNotBlank(ty)) { + paramMap.put("qgcWeFishDetailTy", ty); + sql.append("AND CASE ") + .append("WHEN dict.SPEC_ORIGIN = 2 THEN '1' ") + .append("WHEN dict.SPEC_ORIGIN = 1 AND NVL(dict.PTYPE, -1) <> 6 THEN '2' ") + .append("WHEN dict.SPEC_ORIGIN = 1 AND dict.PTYPE = 6 THEN '3' ") + .append("END = #{map.qgcWeFishDetailTy} "); + } + + sql.append("GROUP BY section.RSTCD, eng.ENNM ") + .append("ORDER BY eng.ENNM ASC NULLS LAST"); + return sql.toString(); + } + + private String buildWeFishDetailSql(String baseId, + String rstcd, + String rvcd, + String yr, + String ty, + Map paramMap) { + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append("section.RSTCD AS rstcd, ") + .append("eng.ENNM AS rstcdName, ") + .append("TO_CHAR(WM_CONCAT(DISTINCT section.STCD)) AS stcd, ") + .append("TO_CHAR(WM_CONCAT(DISTINCT section.STNM)) AS stnm, ") + .append("TO_CHAR(WM_CONCAT(DISTINCT dict.NAME)) AS name ") + .append("FROM SD_WE_B_H section ") + .append("INNER JOIN SD_WE_R we ON section.STCD = we.STCD ") + .append(" AND NVL(we.IS_DELETED, 0) = 0 ") + .append(" AND NVL(we.STATUS, 1) = 1 ") + .append("INNER JOIN SD_WEFISH_R fish ON we.ID = fish.WER_ID ") + .append(" AND NVL(fish.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON section.RSTCD = eng.STCD ") + .append(" AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN SD_FISHDICTORY_B dict ON fish.FTP = dict.ID ") + .append(" AND NVL(dict.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(section.USFL, 0) = 1 ") + .append("AND section.RSTCD IS NOT NULL ") + .append("AND dict.NAME IS NOT NULL "); + + if (StrUtil.isNotBlank(baseId)) { + paramMap.put("weFishDetailBaseId", baseId); + sql.append("AND section.BASE_ID = #{map.weFishDetailBaseId} "); + } + if (StrUtil.isNotBlank(rstcd)) { + paramMap.put("weFishDetailRstcd", rstcd); + sql.append("AND section.RSTCD = #{map.weFishDetailRstcd} "); + } + if (StrUtil.isNotBlank(rvcd)) { + paramMap.put("weFishDetailRvcd", rvcd); + sql.append("AND section.HBRVCD = #{map.weFishDetailRvcd} "); + } + if (StrUtil.isNotBlank(yr)) { + paramMap.put("weFishDetailYr", yr); + sql.append("AND TO_CHAR(we.TM, 'yyyy') = #{map.weFishDetailYr} "); + } + if (StrUtil.isNotBlank(ty)) { + paramMap.put("weFishDetailTy", ty); + sql.append("AND CASE ") + .append("WHEN dict.SPEC_ORIGIN = 2 THEN '1' ") + .append("WHEN dict.SPEC_ORIGIN = 1 AND NVL(dict.PTYPE, -1) <> 6 THEN '2' ") + .append("WHEN dict.SPEC_ORIGIN = 1 AND dict.PTYPE = 6 THEN '3' ") + .append("END = #{map.weFishDetailTy} "); + } + + sql.append("GROUP BY section.RSTCD, eng.ENNM ") + .append("ORDER BY eng.ENNM ASC NULLS LAST"); + return sql.toString(); + } + + private String buildHbbQgcWeFishDetailSql(String baseId, + String rstcd, + String rvcd, + String yr, + String ty, + Map paramMap) { + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append("section.RSTCD AS rstcd, ") + .append("eng.ENNM AS rstcdName, ") + .append("section.STCD AS stcd, ") + .append("section.STNM AS stnm, ") + .append("dict.ZY_FISH_ID AS id ") + .append("FROM SD_WE_B_H section ") + .append("INNER JOIN SD_WE_R we ON section.STCD = we.STCD ") + .append(" AND NVL(we.IS_DELETED, 0) = 0 ") + .append(" AND NVL(we.STATUS, 1) = 1 ") + .append("INNER JOIN SD_WEFISH_R fish ON we.ID = fish.WER_ID ") + .append(" AND NVL(fish.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON section.RSTCD = eng.STCD ") + .append(" AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN V_SD_FISHDICTORY_B dict ON fish.FTP = dict.FISH_ID ") + .append(" AND (section.HBRVCD = dict.RVCD OR dict.RVCD = 'ZY') ") + .append("WHERE NVL(section.USFL, 0) = 1 ") + .append("AND section.RSTCD IS NOT NULL ") + .append("AND dict.ZY_FISH_ID IS NOT NULL "); + + if (StrUtil.isNotBlank(baseId)) { + paramMap.put("hbbQgcWeFishDetailBaseId", baseId); + sql.append("AND section.BASE_ID = #{map.hbbQgcWeFishDetailBaseId} "); + } + if (StrUtil.isNotBlank(rstcd)) { + paramMap.put("hbbQgcWeFishDetailRstcd", rstcd); + sql.append("AND section.RSTCD = #{map.hbbQgcWeFishDetailRstcd} "); + } + if (StrUtil.isNotBlank(rvcd)) { + paramMap.put("hbbQgcWeFishDetailRvcd", rvcd); + sql.append("AND section.HBRVCD = #{map.hbbQgcWeFishDetailRvcd} "); + } + if (StrUtil.isNotBlank(yr)) { + paramMap.put("hbbQgcWeFishDetailYr", yr); + sql.append("AND TO_CHAR(we.TM, 'yyyy') = #{map.hbbQgcWeFishDetailYr} "); + } + if (StrUtil.isNotBlank(ty)) { + paramMap.put("hbbQgcWeFishDetailTy", ty); + sql.append("AND CASE ") + .append("WHEN dict.SPEC_ORIGIN = 2 THEN '1' ") + .append("WHEN dict.SPEC_ORIGIN = 1 AND NVL(dict.PTYPE, -1) <> 6 THEN '2' ") + .append("WHEN dict.SPEC_ORIGIN = 1 AND dict.PTYPE = 6 THEN '3' ") + .append("END = #{map.hbbQgcWeFishDetailTy} "); + } + + sql.append("GROUP BY section.RSTCD, eng.ENNM, section.STCD, section.STNM,dict.ZY_FISH_ID ") + .append("ORDER BY eng.ENNM ASC NULLS LAST, section.STNM ASC NULLS LAST"); + return sql.toString(); + } + + private String buildWeFishStatTabSql(String baseId, + String rstcd, + String rvcd, + String yr, + Map paramMap) { + StringBuilder sql = new StringBuilder(); + sql.append("SELECT COUNT(DISTINCT fish.FTP) AS num, ") + .append("CASE ") + .append("WHEN dict.SPEC_ORIGIN = 2 THEN '1' ") + .append("WHEN dict.SPEC_ORIGIN = 1 AND NVL(dict.PTYPE, -1) <> 6 THEN '2' ") + .append("WHEN dict.SPEC_ORIGIN = 1 AND dict.PTYPE = 6 THEN '3' ") + .append("END AS ty ") + .append("FROM SD_WE_B_H section ") + .append("INNER JOIN SD_WE_R we ON section.STCD = we.STCD ") + .append(" AND NVL(we.IS_DELETED, 0) = 0 ") + .append(" AND NVL(we.STATUS, 1) = 1 ") + .append("INNER JOIN SD_WEFISH_R fish ON we.ID = fish.WER_ID ") + .append(" AND NVL(fish.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN SD_FISHDICTORY_B dict ON fish.FTP = dict.ID ") + .append(" AND NVL(dict.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(section.USFL, 0) = 1 "); + + if (StrUtil.isNotBlank(baseId)) { + paramMap.put("weFishStatTabBaseId", baseId); + sql.append("AND section.BASE_ID = #{map.weFishStatTabBaseId} "); + } + if (StrUtil.isNotBlank(rvcd)) { + paramMap.put("weFishStatTabRvcd", rvcd); + sql.append("AND section.HBRVCD = #{map.weFishStatTabRvcd} "); + } + if (StrUtil.isNotBlank(rstcd)) { + paramMap.put("weFishStatTabRstcd", rstcd); + sql.append("AND section.RSTCD = #{map.weFishStatTabRstcd} "); + } + if (StrUtil.isNotBlank(yr)) { + paramMap.put("weFishStatTabYr", yr); + sql.append("AND TO_CHAR(we.TM, 'yyyy') = #{map.weFishStatTabYr} "); + } + + sql.append("AND CASE ") + .append("WHEN dict.SPEC_ORIGIN = 2 THEN '1' ") + .append("WHEN dict.SPEC_ORIGIN = 1 AND NVL(dict.PTYPE, -1) <> 6 THEN '2' ") + .append("WHEN dict.SPEC_ORIGIN = 1 AND dict.PTYPE = 6 THEN '3' ") + .append("END IS NOT NULL ") + .append("GROUP BY CASE ") + .append("WHEN dict.SPEC_ORIGIN = 2 THEN '1' ") + .append("WHEN dict.SPEC_ORIGIN = 1 AND NVL(dict.PTYPE, -1) <> 6 THEN '2' ") + .append("WHEN dict.SPEC_ORIGIN = 1 AND dict.PTYPE = 6 THEN '3' ") + .append("END ") + .append("ORDER BY ty ASC"); + return sql.toString(); + } + + private List buildWeFishDetailResult(List> rows) { + List result = new ArrayList<>(); + if (CollUtil.isEmpty(rows)) { + return result; + } + for (Map row : rows) { + String stcd = safeWeFishString(firstPresentWeFishValue(row, "STCD", "stcd")); + String stnm = safeWeFishString(firstPresentWeFishValue(row, "STNM", "stnm")); + String fishNames = safeWeFishString(firstPresentWeFishValue(row, "NAME", "name")); + + WeFishDetailVo vo = new WeFishDetailVo() + .setRsctd(safeWeFishString(firstPresentWeFishValue(row, "RSTCD", "rstcd"))) + .setRsctdName(safeWeFishString(firstPresentWeFishValue(row, "RSTCDNAME", "rstcdName"))) + .setFishList(splitWeFishText(fishNames)) + .setStcdList(buildWeFishStationItems(stcd, stnm)); + result.add(vo); + } + return result; + } + + private List buildQgcWeFishDetailResult(List> rows) { + List result = new ArrayList<>(); + if (CollUtil.isEmpty(rows)) { + return result; + } + Map fishNameMap = loadWeFishNameMap(); + for (Map row : rows) { + String stcd = safeWeFishString(firstPresentWeFishValue(row, "STCD", "stcd")); + String stnm = safeWeFishString(firstPresentWeFishValue(row, "STNM", "stnm")); + String fishIds = safeWeFishString(firstPresentWeFishValue(row, "ID", "id")); + + WeFishDetailVo vo = new WeFishDetailVo() + .setRsctd(safeWeFishString(firstPresentWeFishValue(row, "RSTCD", "rstcd"))) + .setRsctdName(safeWeFishString(firstPresentWeFishValue(row, "RSTCDNAME", "rstcdName"))) + .setFishList(resolveWeFishNameList(fishIds, fishNameMap)) + .setStcdList(buildWeFishStationItems(stcd, stnm)); + result.add(vo); + } + return result; + } + + private List buildHbbQgcWeFishDetailResult(List> rows) { + List result = new ArrayList<>(); + if (CollUtil.isEmpty(rows)) { + return result; + } + Map fishNameMap = loadWeFishNameMap(); + for (Map row : rows) { + String fishIds = safeWeFishString(firstPresentWeFishValue(row, "ID", "id")); + result.add(new WeFishHbbQgcDetailVo() + .setRstcd(safeWeFishString(firstPresentWeFishValue(row, "RSTCD", "rstcd"))) + .setRstcdName(safeWeFishString(firstPresentWeFishValue(row, "RSTCDNAME", "rstcdName"))) + .setStcd(safeWeFishString(firstPresentWeFishValue(row, "STCD", "stcd"))) + .setStnm(safeWeFishString(firstPresentWeFishValue(row, "STNM", "stnm"))) + .setId(fishIds) + .setName(resolveWeFishNames(fishIds, fishNameMap))); + } + return result; + } + + private List buildWeFishStationItems(String stcdText, String stnmText) { + List result = new ArrayList<>(); + if (StrUtil.isBlank(stcdText) || StrUtil.isBlank(stnmText)) { + return result; + } + List stcdList = splitWeFishText(stcdText); + List stnmList = splitWeFishText(stnmText); + int size = Math.min(stcdList.size(), stnmList.size()); + for (int i = 0; i < size; i++) { + result.add(new WeFishDetailVo.StationItem() + .setStcd(stcdList.get(i)) + .setStnm(stnmList.get(i))); + } + return result; + } + + private List splitWeFishText(String text) { + if (StrUtil.isBlank(text)) { + return new ArrayList<>(); + } + String[] parts = text.split(","); + List result = new ArrayList<>(); + Set seen = new HashSet<>(); + for (String part : parts) { + String value = StrUtil.trim(part); + if (StrUtil.isBlank(value) || !seen.add(value)) { + continue; + } + result.add(value); + } + return result; + } + + private List resolveWeFishNameList(String idsText, Map fishNameMap) { + String names = resolveWeFishNames(idsText, fishNameMap); + return splitWeFishText(names); + } + + private List buildWeCompareBarColumns(String dcpc, String dcpc2) { + List columns = new ArrayList<>(); + columns.add(new WeCompareBarHeadColumnVo("ftp", "鱼种类", true, "ftp", false, new ArrayList<>())); + columns.add(new WeCompareBarHeadColumnVo("genus", "科属", true, "genus", false, new ArrayList<>())); + columns.add(new WeCompareBarHeadColumnVo("dcpc", StrUtil.isBlank(dcpc) ? "调查批次" : dcpc, true, "dcpc", false, new ArrayList<>())); + columns.add(new WeCompareBarHeadColumnVo("dcpc2", StrUtil.isBlank(dcpc2) ? "对比批次" : dcpc2, true, "dcpc2", false, new ArrayList<>())); + columns.add(new WeCompareBarHeadColumnVo("fcnt", "鱼类数量(尾)", true, "fnct", false, new ArrayList<>())); + columns.add(new WeCompareBarHeadColumnVo("fcnt2", "对比鱼类数量(尾)", true, "fcnt2", false, new ArrayList<>())); + return columns; + } + + private List buildWeFishPageColumns(String startYear, String endYear) { + List columns = new ArrayList<>(); + columns.add(new WeCompareBarHeadColumnVo("genus", "科属", true, "genus", true, new ArrayList<>())); + columns.add(new WeCompareBarHeadColumnVo("ftp", "鱼类名称", true, "ftp", false, new ArrayList<>())); + columns.add(new WeCompareBarHeadColumnVo("startFtpCnt", startYear + "鱼类总量(尾)", true, "startFtpCnt", false, new ArrayList<>())); + columns.add(new WeCompareBarHeadColumnVo("startYear", startYear + "占比(%)", true, "startYear", false, new ArrayList<>())); + columns.add(new WeCompareBarHeadColumnVo("endFtpCnt", endYear + "鱼类总量(尾)", true, "endFtpCnt", false, new ArrayList<>())); + columns.add(new WeCompareBarHeadColumnVo("endYear", endYear + "占比(%)", true, "endYear", false, new ArrayList<>())); + return columns; + } + + private String firstNonBlankWeFishFilter(DataSourceRequest.FilterDescriptor filter, String... fields) { + if (fields == null) { + return null; + } + for (String field : fields) { + String value = getFirstWeFishFilterText(filter, field); + if (StrUtil.isNotBlank(value)) { + return value; + } + } + return null; + } + private String buildWeFishListStatQgcDetailSql() { return "SELECT " + "dict.FISH_ID AS id, " + @@ -1177,6 +2248,207 @@ public class WeFishServiceImpl implements WeFishService { }; } + private String buildWeWvaDefaultInnerFilterCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + if (filter == null) { + return ""; + } + if (StrUtil.isNotBlank(filter.getField())) { + return buildWeWvaDefaultLeafCondition(filter, paramMap, indexHolder, true); + } + if (CollUtil.isEmpty(filter.getFilters())) { + return ""; + } + List conditions = new ArrayList<>(); + for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) { + String childSql = buildWeWvaDefaultInnerFilterCondition(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 buildWeWvaDefaultOuterFilterCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + if (filter == null) { + return ""; + } + if (StrUtil.isNotBlank(filter.getField())) { + return buildWeWvaDefaultLeafCondition(filter, paramMap, indexHolder, false); + } + if (CollUtil.isEmpty(filter.getFilters())) { + return ""; + } + List conditions = new ArrayList<>(); + for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) { + String childSql = buildWeWvaDefaultOuterFilterCondition(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 buildWeWvaDefaultLeafCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder, + boolean inner) { + String column = inner ? mapWeWvaDefaultInnerColumn(filter.getField()) : mapWeWvaDefaultOuterColumn(filter.getField()); + if (StrUtil.isBlank(column)) { + return ""; + } + String operator = StrUtil.blankToDefault(filter.getOperator(), "eq").toLowerCase(); + if ("isnull".equals(operator)) { + return column + " IS NULL"; + } + if ("isnotnull".equals(operator)) { + return column + " IS NOT NULL"; + } + if ("isempty".equals(operator)) { + return "(" + column + " IS NULL OR " + column + " = '')"; + } + if ("isnotempty".equals(operator)) { + return "(" + column + " IS NOT NULL AND " + column + " <> '')"; + } + if ("in".equals(operator) || "ni".equals(operator)) { + List values = normalizeWeWvaValues(filter.getValue()); + if (values.isEmpty()) { + return ""; + } + List placeholders = new ArrayList<>(); + for (Object value : values) { + Object normalizedValue = normalizeWeWvaDefaultValue(filter.getField(), value); + if (normalizedValue == null) { + continue; + } + String key = (inner ? "weWvaDefaultInnerP" : "weWvaDefaultOuterP") + indexHolder[0]++; + paramMap.put(key, normalizedValue); + placeholders.add(buildWeWvaDefaultValueExpr(key, "tm".equals(filter.getField()), normalizedValue)); + } + if (placeholders.isEmpty()) { + return ""; + } + return column + ("ni".equals(operator) ? " NOT IN (" : " IN (") + String.join(", ", placeholders) + ")"; + } + + Object normalizedValue = normalizeWeWvaDefaultValue(filter.getField(), filter.getValue()); + if (normalizedValue == null) { + return ""; + } + String key = (inner ? "weWvaDefaultInnerP" : "weWvaDefaultOuterP") + indexHolder[0]++; + paramMap.put(key, normalizedValue); + String valueExpr = buildWeWvaDefaultValueExpr(key, "tm".equals(filter.getField()), normalizedValue); + return switch (operator) { + case "eq" -> column + " = " + valueExpr; + case "neq" -> column + " <> " + valueExpr; + case "gt" -> column + " > " + valueExpr; + case "gte" -> column + " >= " + valueExpr; + case "lt" -> column + " < " + valueExpr; + case "lte" -> column + " <= " + valueExpr; + case "contains" -> { + paramMap.put(key, "%" + String.valueOf(normalizedValue).trim() + "%"); + yield column + " LIKE #{map." + key + "}"; + } + case "doesnotcontain" -> { + paramMap.put(key, "%" + String.valueOf(normalizedValue).trim() + "%"); + yield column + " NOT LIKE #{map." + key + "}"; + } + case "startswith" -> { + paramMap.put(key, String.valueOf(normalizedValue).trim() + "%"); + yield column + " LIKE #{map." + key + "}"; + } + case "endswith" -> { + paramMap.put(key, "%" + String.valueOf(normalizedValue).trim()); + yield column + " LIKE #{map." + key + "}"; + } + default -> ""; + }; + } + + private String mapWeWvaDefaultInnerColumn(String field) { + if (StrUtil.isBlank(field)) { + return null; + } + return switch (field) { + case "stcd" -> "src.STCD"; + case "tm" -> "src.TM"; + case "fid" -> "src.FID"; + default -> null; + }; + } + + private String mapWeWvaDefaultOuterColumn(String field) { + if (StrUtil.isBlank(field)) { + return null; + } + return switch (field) { + case "stcd" -> "t.stcd"; + case "stnm" -> "t.stnm"; + case "tm" -> "t.tm"; + case "sttpCode" -> "t.sttpCode"; + case "sttpName" -> "t.sttpName"; + case "rstcd" -> "t.rstcd"; + case "baseId" -> "t.baseId"; + case "hbrvcd" -> "t.hbrvcd"; + default -> null; + }; + } + + private Object normalizeWeWvaDefaultValue(String field, Object value) { + if (value == null) { + return null; + } + if ("tm".equals(field)) { + String text = String.valueOf(value).trim(); + return StrUtil.isBlank(text) ? null : text; + } + return value; + } + + private String buildWeWvaDefaultValueExpr(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 buildWeWvaDefaultOrderBySql(List sorts) { + if (CollUtil.isEmpty(sorts)) { + return ""; + } + List orderByParts = new ArrayList<>(); + for (DataSourceRequest.SortDescriptor sort : sorts) { + if (sort == null || StrUtil.isBlank(sort.getField())) { + continue; + } + String column = mapWeWvaDefaultOuterColumn(sort.getField()); + if (StrUtil.isBlank(column)) { + continue; + } + String direction = "desc".equalsIgnoreCase(sort.getDir()) ? "DESC" : "ASC"; + orderByParts.add(column + " " + direction + " NULLS LAST"); + } + if (orderByParts.isEmpty()) { + return ""; + } + return " ORDER BY " + String.join(", ", orderByParts); + } + private String buildWeMsstbprptViewSql() { return "SELECT " + "ai.STCD AS id, " + @@ -1894,6 +3166,61 @@ public class WeFishServiceImpl implements WeFishService { return vo; } + private String buildWeFishTDetailSql() { + return "SELECT " + + "section.STCD AS stcd, " + + "section.STNM AS stnm, " + + "eng.BASE_ID AS baseId, " + + "eng.BASE_NAME AS baseName, " + + "eng.RVCD AS rvcd, " + + "eng.RVCD_NAME AS rvcdName, " + + "eng.ADDVCD AS addvcd, " + + "eng.ADDVCD_NAME AS addvcdName, " + + "eng.HBRVCD AS hbrvcd, " + + "eng.HBRVCD_NAME AS hbrvcdName, " + + "we.DCPC AS dcpc, " + + "we.TM AS tm, " + + "we.FID AS werFid, " + + "fish.WER_ID AS werId, " + + "fish.FTP AS ftp, " + + "fish.FSZ AS fsz, " + + "fish.FCNT AS fcnt, " + + "fish.FWGH AS fwgh, " + + "fish.ST AS st, " + + "fish.PS AS ps, " + + "fish.AVG_FWGT AS avgFwgt, " + + "fish.AVG_FSZ AS avgFsz, " + + "fish.FID AS fid, " + + "fish.FILE_ID AS fileId, " + + "dict.ID AS id, " + + "dict.NAME AS name, " + + "dict.ALIAS AS alias, " + + "dict.GENUS AS genus, " + + "dict.FAMILY AS family, " + + "dict.SPECIES AS species, " + + "dict.TYPE AS type, " + + "dict.RARE AS rare, " + + "dict.SPEC_ORIGIN AS specOrigin, " + + "dict.PTYPE AS ptype, " + + "TO_CHAR(we.TM, 'yyyy') AS yr, " + + "CASE " + + "WHEN dict.SPEC_ORIGIN = 2 THEN 1 " + + "WHEN dict.SPEC_ORIGIN = 1 AND NVL(dict.PTYPE, -1) <> 6 THEN 2 " + + "WHEN dict.SPEC_ORIGIN = 1 AND dict.PTYPE = 6 THEN 3 " + + "END AS ty " + + "FROM SD_WE_R we " + + "INNER JOIN SD_WEFISH_R fish ON fish.WER_ID = we.ID " + + " AND NVL(fish.IS_DELETED, 0) = 0 " + + "INNER JOIN SD_WE_B_H section ON section.STCD = we.STCD " + + " AND NVL(section.USFL, 0) = 1 " + + "LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = section.RSTCD " + + " AND NVL(eng.IS_DELETED, 0) = 0 " + + "LEFT JOIN SD_FISHDICTORY_B dict ON dict.ID = fish.FTP " + + " AND NVL(dict.IS_DELETED, 0) = 0 " + + "WHERE NVL(we.IS_DELETED, 0) = 0 " + + "AND NVL(we.STATUS, 1) = 1 "; + } + private String buildWeFishQgcDetailSql() { return "SELECT " + "section.STCD AS stcd, " + @@ -1920,7 +3247,7 @@ public class WeFishServiceImpl implements WeFishService { "fish.AVG_FSZ AS avgFsz, " + "fish.FID AS fid, " + "fish.FILE_ID AS fileId, " + - "dict.FISH_ID AS id, " + + "dict.ID AS id, " + "dict.NAME AS name, " + "dict.ALIAS AS alias, " + "dict.GENUS AS genus, " + @@ -1940,14 +3267,14 @@ public class WeFishServiceImpl implements WeFishService { "INNER JOIN SD_WEFISH_R fish ON fish.WER_ID = we.ID " + " AND NVL(fish.IS_DELETED, 0) = 0 " + "INNER JOIN SD_WE_B_H section ON section.STCD = we.STCD " + - " AND NVL(section.USFL, 0) = 1 " + +// " AND NVL(section.USFL, 0) = 1 " + "LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = section.RSTCD " + " AND NVL(eng.IS_DELETED, 0) = 0 " + - "LEFT JOIN V_SD_FISHDICTORY_B dict ON dict.FISH_ID = fish.FTP " + - " AND (dict.RVCD = 'ZY' OR dict.RVCD = eng.HBRVCD) " + + "LEFT JOIN SD_FISHDICTORY_B dict ON dict.ID = fish.FTP " + +// " AND (dict.RVCD = 'ZY' OR dict.RVCD = eng.HBRVCD) " + "WHERE NVL(we.IS_DELETED, 0) = 0 " + // 旧库按 TASK_STATUS=Approved/null 过滤,新库改用 STATUS=1(完成) 承接审批通过口径 - "AND NVL(we.STATUS, 1) = 1 "; + "AND dict.IS_DELETED =0 "; } private String buildWeFishQgcFilterCondition(DataSourceRequest.FilterDescriptor filter, @@ -2084,9 +3411,11 @@ public class WeFishServiceImpl implements WeFishService { case "hbrvcdName" -> "r.hbrvcdName"; case "dcpc" -> "r.dcpc"; case "tm" -> "r.tm"; + case "year" -> "r.yr"; case "werFid" -> "r.werFid"; case "werId" -> "r.werId"; case "ftp" -> "r.ftp"; + case "ftpName" -> "r.name"; case "fsz" -> "r.fsz"; case "fcnt" -> "r.fcnt"; case "fwgh" -> "r.fwgh"; @@ -2142,6 +3471,66 @@ public class WeFishServiceImpl implements WeFishService { return " ORDER BY " + String.join(", ", orderByParts); } + private String buildWeFishPageOrderBySql(List sorts) { + if (CollUtil.isEmpty(sorts)) { + return " ORDER BY r.ftp ASC"; + } + Map columnMap = new LinkedHashMap<>(); + columnMap.put("ftp", "r.ftp"); + columnMap.put("genus", "r.genus"); + columnMap.put("startFtpCnt", "r.startFtpCnt"); + columnMap.put("startCnt", "r.startCnt"); + columnMap.put("startYear", "r.startYear"); + columnMap.put("endFtpCnt", "r.endFtpCnt"); + columnMap.put("endCnt", "r.endCnt"); + columnMap.put("endYear", "r.endYear"); + + List orderByParts = new ArrayList<>(); + for (DataSourceRequest.SortDescriptor sort : sorts) { + if (sort == null || StrUtil.isBlank(sort.getField())) { + continue; + } + String column = columnMap.get(sort.getField()); + if (StrUtil.isBlank(column)) { + continue; + } + String direction = "desc".equalsIgnoreCase(sort.getDir()) ? "DESC" : "ASC"; + orderByParts.add(column + " " + direction + " NULLS LAST"); + } + if (orderByParts.isEmpty()) { + return " ORDER BY r.ftp ASC"; + } + return " ORDER BY " + String.join(", ", orderByParts); + } + + private String buildWeStaticsSecondSelectSql(List selectFields) { + Map columns = new LinkedHashMap<>(); + columns.put("stcd", "r.stcd AS stcd"); + columns.put("stnm", "r.stnm AS stnm"); + columns.put("ftp", "r.ftp AS ftp"); + columns.put("ftpName", "r.name AS ftpName"); + columns.put("dcpc", "r.dcpc AS dcpc"); + columns.put("tm", "r.tm AS tm"); + columns.put("fcnt", "r.fcnt AS fcnt"); + columns.put("fid", "r.werFid AS fid"); + + 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 Object normalizeWeFishQgcValue(String field, Object value) { if (value == null) { return null; @@ -2172,6 +3561,12 @@ public class WeFishServiceImpl implements WeFishService { return values; } + private List normalizeWeWvaValues(Object value) { + List values = new ArrayList<>(); + appendWeFishQgcValues(values, value); + return values; + } + private String buildWeFishListStatFilterCondition(DataSourceRequest.FilterDescriptor filter, Map paramMap, int[] indexHolder) { @@ -2707,6 +4102,496 @@ public class WeFishServiceImpl implements WeFishService { } } + private WeEnvmAutoMonitorVo buildWeEnvmAutoMonitorVo(Integer cnt, + Integer orderInx, + String sttpCode, + String sttpFullPath, + String sttpName) { + WeEnvmAutoMonitorVo vo = new WeEnvmAutoMonitorVo(); + vo.setCnt(cnt == null ? 0 : cnt); + vo.setOrderInx(orderInx); + vo.setOrderInxName(sttpName); + vo.setSttpCode(sttpCode); + vo.setSttpFullPath(sttpFullPath); + vo.setSttpName(sttpName); + return vo; + } + + private List reorderWeEnvmAutoMonitorRows(List rows, List showIds) { + if (CollUtil.isEmpty(rows)) { + return new ArrayList<>(); + } + LinkedHashMap rowMap = new LinkedHashMap<>(); + for (WeEnvmAutoMonitorVo row : rows) { + if (row != null && row.getOrderInx() != null) { + rowMap.put(String.valueOf(row.getOrderInx()), row); + } + } + List result = new ArrayList<>(); + if (CollUtil.isNotEmpty(showIds)) { + for (String showId : showIds) { + WeEnvmAutoMonitorVo row = rowMap.get(showId); + if (row != null) { + result.add(row); + } + } + return result; + } + result.addAll(rowMap.values()); + result.sort((a, b) -> Integer.compare( + a == null || a.getOrderInx() == null ? Integer.MAX_VALUE : a.getOrderInx(), + b == null || b.getOrderInx() == null ? Integer.MAX_VALUE : b.getOrderInx() + )); + return result; + } + + private Integer queryWeEnvmAutoMonitorCount(SqlAndParams sqlAndParams) { + if (sqlAndParams == null || StrUtil.isBlank(sqlAndParams.sql())) { + return 0; + } + Map row = microservicDynamicSQLMapper.getOneBySql(sqlAndParams.sql(), sqlAndParams.params()); + return toWeFishIntegerValue(firstPresentWeFishValue(row, "CNT", "cnt")); + } + + private boolean shouldIgnoreWeEnvmFhRstcd(List rstcds) { + if (CollUtil.isEmpty(rstcds)) { + return false; + } + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(DISTINCT eng.STCD) AS cnt ") + .append("FROM SD_ENGINFO_B_H eng ") + .append("WHERE NVL(eng.IS_DELETED, 0) = 0 ") + .append("AND eng.HYCD = '10304' ") + .append("AND NVL(eng.BLDSTT_CODE, 0) IN (1, 2) "); + appendWeEnvmExactInCondition(sql, paramMap, "eng.STCD", "rstcd", rstcds); + Integer cnt = queryWeEnvmAutoMonitorCount(new SqlAndParams(sql.toString(), paramMap)); + return cnt != null && cnt == rstcds.size(); + } + + private SqlAndParams buildWeEnvmWtSql(String baseId, List rstcds) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt ") + .append("FROM SD_WT_B_H wt ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = wt.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(wt.IS_DELETED, 0) = 0 ") + .append("AND wt.STTP IN ('WTRV', 'WTVT') ") + .append("AND NVL(wt.MWAY, 0) = 2 "); + appendWeEnvmBaseIdCondition(sql, paramMap, "eng.BASE_ID", baseId); + appendWeEnvmLikeCondition(sql, paramMap, "wt.RSTCD", "rstcd", rstcds); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmGjWqSql(String baseId, List hbrvcds, List rvcds) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt ") + .append("FROM SD_WQ_B_H wq ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = wq.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(wq.IS_DELETED, 0) = 0 ") + .append("AND wq.STTP = 'WQ' ") + .append("AND NVL(wq.MWAY, 0) = 2 ") + .append("AND NVL(wq.DTIN_TYPE, 0) = 1 "); + appendWeEnvmBaseIdCondition(sql, paramMap, "eng.BASE_ID", baseId); + appendWeEnvmExactInCondition(sql, paramMap, "eng.HBRVCD", "hbrvcd", hbrvcds); + appendWeEnvmExactInCondition(sql, paramMap, "eng.RVCD", "rvcd", rvcds); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmZjWqSql(String baseId, List rstcds) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_WQ_B_H wq ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = wq.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(wq.IS_DELETED, 0) = 0 ") + .append("AND wq.STTP IN ('WQ', 'WQFB') ") + .append("AND NVL(wq.MWAY, 0) = 2 ") + .append("AND NVL(wq.DTIN_TYPE, 0) = 0 "); + appendWeEnvmBaseIdCondition(sql, paramMap, "eng.BASE_ID", baseId); + appendWeEnvmLikeCondition(sql, paramMap, "wq.RSTCD", "rstcd", rstcds); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmStGjSql(String baseId) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_RIVER_B_H river ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = river.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(river.IS_DELETED, 0) = 0 ") + .append("AND river.STTP IN ('ZQ', 'ZZ') ") + .append("AND NVL(river.MWAY, 0) = 2 ") + .append("AND NVL(river.DTIN_TYPE, 0) = 1 "); + appendWeEnvmBaseIdCondition(sql, paramMap, "eng.BASE_ID", baseId); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmStZjSql(String baseId, List rstcds) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_RIVER_B_H river ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = river.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(river.IS_DELETED, 0) = 0 ") + .append("AND river.STTP IN ('ZQ', 'ZZ') ") + .append("AND NVL(river.MWAY, 0) = 2 ") + .append("AND NVL(river.DTIN_TYPE, 0) = 0 "); + appendWeEnvmBaseIdCondition(sql, paramMap, "eng.BASE_ID", baseId); + appendWeEnvmLikeCondition(sql, paramMap, "river.RSTCD", "rstcd", rstcds); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmEngQecSql(String baseId, List rstcds) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_ENGINFO_B_H eng ") + .append("WHERE NVL(eng.IS_DELETED, 0) = 0 ") + .append("AND NVL(eng.DTIN, 0) = 1 ") + .append("AND NVL(eng.BLDSTT_CODE, 0) = 2 "); + if (CollUtil.isEmpty(rstcds)) { + sql.append("AND NVL(eng.RUN_STATE, 0) = 4 "); + } else { + sql.append("AND NVL(eng.PRSC, 0) IN (1, 2, 3) ") + .append("AND NVL(eng.COENVW_STATE, 0) = 1 "); + } + appendWeEnvmBaseIdCondition(sql, paramMap, "eng.BASE_ID", baseId); + appendWeEnvmExactInCondition(sql, paramMap, "eng.STCD", "rstcd", rstcds); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmVdSql(String baseId, List rstcds) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_VDINFO_B vd ") + .append("WHERE 1=1 ") + .append("AND vd.STTP LIKE 'VD%' ") + .append("AND NVL(vd.DTIN, 0) = 1 "); + appendWeEnvmBaseIdCondition(sql, paramMap, "vd.BASE_ID", baseId); + appendWeEnvmLikeCondition(sql, paramMap, "vd.RSTCD", "rstcd", rstcds); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmRiverWqSql(String baseId, List rstcds) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_WQ_B_H wq ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = wq.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(wq.IS_DELETED, 0) = 0 ") + .append("AND wq.STTP = 'WQ' ") + .append("AND NVL(wq.MWAY, 0) = 2 ") + .append("AND NVL(wq.DTIN_TYPE, 0) = 0 "); + appendWeEnvmBaseIdCondition(sql, paramMap, "eng.BASE_ID", baseId); + appendWeEnvmLikeCondition(sql, paramMap, "wq.RSTCD", "rstcd", rstcds); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmFbWqSql(String baseId, List rstcds) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_WQ_B_H wq ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = wq.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(wq.IS_DELETED, 0) = 0 ") + .append("AND wq.STTP = 'WQFB' ") + .append("AND NVL(wq.MWAY, 0) = 2 ") + .append("AND NVL(wq.DTIN_TYPE, 0) = 0 "); + appendWeEnvmBaseIdCondition(sql, paramMap, "eng.BASE_ID", baseId); + appendWeEnvmLikeCondition(sql, paramMap, "wq.RSTCD", "rstcd", rstcds); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmFhSql(String baseId, List rstcds, boolean ignoreRstcd) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_FHBT_B_H fh ") + .append("WHERE NVL(fh.IS_DELETED, 0) = 0 "); + appendWeEnvmBaseIdCondition(sql, paramMap, "fh.BASE_ID", baseId); + if (!ignoreRstcd) { + appendWeEnvmLikeCondition(sql, paramMap, "fh.RSTCD", "rstcd", rstcds); + } + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmFhWqSql(String baseId, List rstcds, boolean ignoreRstcd) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_WQ_B_H wq ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = wq.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(wq.IS_DELETED, 0) = 0 ") + .append("AND wq.STTP = 'WQ' "); + appendWeEnvmBaseIdCondition(sql, paramMap, "eng.BASE_ID", baseId); + if (!ignoreRstcd) { + appendWeEnvmLikeCondition(sql, paramMap, "wq.RSTCD", "rstcd", rstcds); + appendWeEnvmFhByRstcdCondition(sql, paramMap, "wq.FHSTCD", "fh_rstcd", rstcds); + } + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmFhWtSql(String baseId, List rstcds, boolean ignoreRstcd) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_WT_B_H wt ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = wt.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(wt.IS_DELETED, 0) = 0 ") + .append("AND wt.STTP = 'WTRV' ") + .append("AND NVL(wt.DTIN_TYPE, 0) = 0 "); + appendWeEnvmBaseIdCondition(sql, paramMap, "eng.BASE_ID", baseId); + if (!ignoreRstcd) { + appendWeEnvmLikeCondition(sql, paramMap, "wt.RSTCD", "rstcd", rstcds); + appendWeEnvmFhByRstcdCondition(sql, paramMap, "wt.FHSTCD", "fh_rstcd", rstcds); + } + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmFhStSql(String baseId, List rstcds, boolean ignoreRstcd) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_RIVER_B_H river ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = river.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(river.IS_DELETED, 0) = 0 ") + .append("AND river.STTP IN ('ZQ', 'ZZ') ") + .append("AND NVL(river.DTIN_TYPE, 0) = 0 "); + appendWeEnvmBaseIdCondition(sql, paramMap, "eng.BASE_ID", baseId); + if (!ignoreRstcd) { + appendWeEnvmLikeCondition(sql, paramMap, "river.RSTCD", "rstcd", rstcds); + appendWeEnvmFhByRstcdCondition(sql, paramMap, "river.FHSTCD", "fh_rstcd", rstcds); + } + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmWeSql(String baseId, List rstcds) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_WE_B_H weB ") + .append("WHERE 1=1 ") + .append("AND EXISTS (SELECT 1 FROM SD_WE_R we ") + .append("WHERE we.STCD = weB.STCD AND NVL(we.IS_DELETED, 0) = 0 AND NVL(we.STATUS, 1) = 1) "); + appendWeEnvmBaseIdCondition(sql, paramMap, "weB.BASE_ID", baseId); + appendWeEnvmLikeCondition(sql, paramMap, "weB.RSTCD", "rstcd", rstcds); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmWvaSql(String baseId, List rstcds, List hbrvcds) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_AIMONITOR_B_H ai ") + .append("WHERE NVL(ai.IS_DELETED, 0) = 0 ") + .append("AND ai.STTP = 'WVA' "); + appendWeEnvmBaseIdCondition(sql, paramMap, "ai.BASE_ID", baseId); + appendWeEnvmLikeCondition(sql, paramMap, "ai.RSTCD", "rstcd", rstcds); + appendWeEnvmExactInCondition(sql, paramMap, "ai.HBRVCD", "hbrvcd", hbrvcds); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmVdEqsSql(String baseId, List rstcds) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_VDINFO_B vd ") + .append("WHERE 1=1 ") + .append("AND vd.STTP = 'VD_EQS' "); + appendWeEnvmBaseIdCondition(sql, paramMap, "vd.BASE_ID", baseId); + appendWeEnvmLikeCondition(sql, paramMap, "vd.RSTCD", "rstcd", rstcds); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmRareFishSql(String baseId, List rstcds, Date startTime, Date endTime) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(DISTINCT fish.FTP) AS cnt ") + .append("FROM SD_WE_R we ") + .append("INNER JOIN SD_WEFISH_R fish ON we.ID = fish.WER_ID AND NVL(fish.IS_DELETED, 0) = 0 ") + .append("INNER JOIN SD_FISHDICTORY_B dict ON dict.ID = fish.FTP AND NVL(dict.IS_DELETED, 0) = 0 ") + .append("INNER JOIN SD_WE_B_H weB ON weB.STCD = we.STCD ") + .append("WHERE NVL(we.IS_DELETED, 0) = 0 ") + .append("AND NVL(we.STATUS, 1) = 1 ") + .append("AND NVL(dict.RARE, 0) = 1 ") + .append("AND NVL(dict.SPEC_ORIGIN, 0) = 1 "); + appendWeEnvmBaseIdCondition(sql, paramMap, "weB.BASE_ID", baseId); + appendWeEnvmLikeCondition(sql, paramMap, "weB.RSTCD", "rstcd", rstcds); + appendWeEnvmDateRangeCondition(sql, paramMap, "we.TM", startTime, endTime); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmTeAnimalsSql() { + String sql = "SELECT COUNT(1) AS cnt FROM (" + + "SELECT b.ID FROM MS_SPECANIMALS_B a " + + "INNER JOIN SD_VABASIC_B b ON a.ANIMAL_ID = b.ID " + + "WHERE NVL(a.IS_DELETED, 0) = 0 AND NVL(b.IS_DELETED, 0) = 0 AND NVL(b.ENABLE, 1) = 1 " + + "GROUP BY b.ID" + + ")"; + return new SqlAndParams(sql, new HashMap<>()); + } + + private SqlAndParams buildWeEnvmRgWqSql(String baseId, List rstcds) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_WQ_B_H wq ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = wq.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(wq.IS_DELETED, 0) = 0 ") + .append("AND wq.STTP = 'WQ' ") + .append("AND NVL(wq.MWAY, 0) = 1 ") + .append("AND NVL(wq.DTIN_TYPE, 0) = 2 "); + appendWeEnvmBaseIdCondition(sql, paramMap, "eng.BASE_ID", baseId); + appendWeEnvmLikeCondition(sql, paramMap, "wq.RSTCD", "rstcd", rstcds); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmWeFishStaticsSql(String baseId, List rstcds, Date startTime, Date endTime) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(DISTINCT fish.FTP) AS cnt ") + .append("FROM SD_WE_R we ") + .append("INNER JOIN SD_WEFISH_R fish ON we.ID = fish.WER_ID AND NVL(fish.IS_DELETED, 0) = 0 ") + .append("INNER JOIN SD_WE_B_H weB ON weB.STCD = we.STCD ") + .append("WHERE NVL(we.IS_DELETED, 0) = 0 ") + .append("AND NVL(we.STATUS, 1) = 1 "); + appendWeEnvmBaseIdCondition(sql, paramMap, "weB.BASE_ID", baseId); + appendWeEnvmLikeCondition(sql, paramMap, "weB.RSTCD", "rstcd", rstcds); + appendWeEnvmDateRangeCondition(sql, paramMap, "we.TM", startTime, endTime); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmFpStaticsSql(String baseId, List rstcds) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_FPSS_B_H fp ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fp.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(fp.IS_DELETED, 0) = 0 ") + .append("AND fp.LGTD IS NOT NULL "); + appendWeEnvmBaseIdCondition(sql, paramMap, "eng.BASE_ID", baseId); + appendWeEnvmExactInCondition(sql, paramMap, "fp.RSTCD", "rstcd", rstcds); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmVdYljSql(String baseId, List rstcds) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_VDINFO_B vd ") + .append("WHERE 1=1 ") + .append("AND vd.STTP LIKE 'VD%' ") + .append("AND vd.STTP <> 'VD_FH' ") + .append("AND NVL(vd.DTIN, 0) = 1 "); + appendWeEnvmBaseIdCondition(sql, paramMap, "vd.BASE_ID", baseId); + appendWeEnvmLikeCondition(sql, paramMap, "vd.RSTCD", "rstcd", rstcds); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmAiSql(String baseId, List rstcds, List hbrvcds) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_AIMONITOR_B_H ai ") + .append("WHERE NVL(ai.IS_DELETED, 0) = 0 ") + .append("AND ai.STTP LIKE 'AI%' "); +// .append("AND ai.STCD = ai.DTIN_SRC "); + appendWeEnvmBaseIdCondition(sql, paramMap, "ai.BASE_ID", baseId); + appendWeEnvmLikeCondition(sql, paramMap, "ai.RSTCD", "rstcd", rstcds); + appendWeEnvmExactInCondition(sql, paramMap, "ai.HBRVCD", "hbrvcd", hbrvcds); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmWtrvSql(String baseId, List rstcds) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_WT_B_H wt ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = wt.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(wt.IS_DELETED, 0) = 0 ") + .append("AND wt.STTP = 'WTRV' ") + .append("AND NVL(wt.MWAY, 0) = 2 "); + appendWeEnvmBaseIdCondition(sql, paramMap, "eng.BASE_ID", baseId); + appendWeEnvmLikeCondition(sql, paramMap, "wt.RSTCD", "rstcd", rstcds); + return new SqlAndParams(sql.toString(), paramMap); + } + + private SqlAndParams buildWeEnvmWtvtSql(String baseId, List rstcds) { + StringBuilder sql = new StringBuilder(); + Map paramMap = new HashMap<>(); + sql.append("SELECT COUNT(1) AS cnt FROM SD_WT_B_H wt ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = wt.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(wt.IS_DELETED, 0) = 0 ") + .append("AND wt.STTP = 'WTVT' ") + .append("AND NVL(wt.MWAY, 0) = 2 "); + appendWeEnvmBaseIdCondition(sql, paramMap, "eng.BASE_ID", baseId); + appendWeEnvmLikeCondition(sql, paramMap, "wt.RSTCD", "rstcd", rstcds); + return new SqlAndParams(sql.toString(), paramMap); + } + + private void appendWeEnvmBaseIdCondition(StringBuilder sql, Map paramMap, String column, String baseId) { + if (StrUtil.isBlank(baseId)) { + return; + } + sql.append("AND ").append(column).append(" = #{map.baseId} "); + paramMap.put("baseId", baseId); + } + + private void appendWeEnvmExactInCondition(StringBuilder sql, + Map paramMap, + String column, + String prefix, + List values) { + if (CollUtil.isEmpty(values)) { + return; + } + sql.append("AND ").append(column).append(" IN ("); + for (int i = 0; i < values.size(); i++) { + String key = prefix + i; + if (i > 0) { + sql.append(", "); + } + sql.append("#{map.").append(key).append("}"); + paramMap.put(key, values.get(i)); + } + sql.append(") "); + } + + private void appendWeEnvmLikeCondition(StringBuilder sql, + Map paramMap, + String column, + String prefix, + List values) { + if (CollUtil.isEmpty(values)) { + return; + } + sql.append("AND ("); + for (int i = 0; i < values.size(); i++) { + String key = prefix + i; + if (i > 0) { + sql.append(" OR "); + } + sql.append(column).append(" LIKE '%' || #{map.").append(key).append("} || '%'"); + paramMap.put(key, values.get(i)); + } + sql.append(") "); + } + + private void appendWeEnvmDateRangeCondition(StringBuilder sql, + Map paramMap, + String column, + Date startTime, + Date endTime) { + if (startTime == null || endTime == null) { + return; + } + sql.append("AND ").append(column).append(" BETWEEN #{map.startTime} AND #{map.endTime} "); + paramMap.put("startTime", startTime); + paramMap.put("endTime", endTime); + } + + private void appendWeEnvmFhByRstcdCondition(StringBuilder sql, + Map paramMap, + String column, + String prefix, + List rstcds) { + if (CollUtil.isEmpty(rstcds)) { + return; + } + sql.append("AND ").append(column).append(" IN (") + .append("SELECT fh.STCD FROM SD_FHBT_B_H fh ") + .append("WHERE NVL(fh.IS_DELETED, 0) = 0 "); + appendWeEnvmLikeCondition(sql, paramMap, "fh.RSTCD", prefix, rstcds); + sql.append(") "); + } + + private record SqlAndParams(String sql, Map params) { + } + private void fillWeFishDerivedFields(List list) { if (CollUtil.isEmpty(list)) { return; 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 91cd4c78..7629326f 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 @@ -1,8 +1,10 @@ package com.yfd.platform.qgc_env.zq.controller; +import com.yfd.platform.annotation.Log; import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.config.ResponseResult; import com.yfd.platform.qgc_base.entity.vo.BatchDeleteAo; +import com.yfd.platform.qgc_env.zq.entity.vo.ZqOperateRequest; import com.yfd.platform.qgc_env.zq.service.ZqMonitorService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -56,6 +58,7 @@ public class ZqMonitorController { return ResponseResult.successData(zqMonitorService.getRiverDrtpKendoListCust(dataSourceRequest)); } + @Log(module = "水文流量站监测", value = "删除流量站小时/日/月数据") @PostMapping("/river/removeKendoByIds") @Operation(summary = "删除流量站小时/日/月数据") public ResponseResult removeKendoByIds(@RequestBody BatchDeleteAo batchDeleteAo) { @@ -63,10 +66,14 @@ public class ZqMonitorController { return ResponseResult.success(); } + @Log(module = "水文流量站监测", value = "修改流量站小时数据") @PostMapping("/river/updateRiverRData") @Operation(summary = "修改流量站小时数据") - public ResponseResult updateRiverRData(@RequestBody Map updateData) { - zqMonitorService.updateRiverRData(updateData); + public ResponseResult updateRiverRData(@RequestBody ZqOperateRequest zqOperateRequest) { + zqMonitorService.updateRiverRData( + zqOperateRequest == null ? null : zqOperateRequest.getUpdateData(), + zqOperateRequest == null ? null : zqOperateRequest.getSource() + ); return ResponseResult.success(); } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/zq/entity/vo/ZqOperateRequest.java b/backend/src/main/java/com/yfd/platform/qgc_env/zq/entity/vo/ZqOperateRequest.java new file mode 100644 index 00000000..5073c1e7 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/zq/entity/vo/ZqOperateRequest.java @@ -0,0 +1,13 @@ +package com.yfd.platform.qgc_env.zq.entity.vo; + +import lombok.Data; + +import java.util.Map; + +@Data +public class ZqOperateRequest { + + private String source; + + private Map updateData; +} 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 8dcdd5c7..f2468d65 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 @@ -22,7 +22,7 @@ public interface ZqMonitorService { boolean removeKendoByIds(BatchDeleteAo batchDeleteAo); - boolean updateRiverRData(java.util.Map updateData); + boolean updateRiverRData(java.util.Map updateData, String source); 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 1bd2c665..923af1cd 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 @@ -10,8 +10,12 @@ 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_base.domain.MsOperationLog; +import com.yfd.platform.qgc_base.domain.MsOperationLogDetail; import com.yfd.platform.qgc_base.entity.vo.BatchDeleteAo; import com.yfd.platform.qgc_base.entity.vo.DataParam; +import com.yfd.platform.qgc_base.mapper.MsOperationLogDetailMapper; +import com.yfd.platform.qgc_base.mapper.MsOperationLogMapper; 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.ZqRiverDayDataVo; @@ -19,23 +23,58 @@ import com.yfd.platform.qgc_env.zq.entity.vo.ZqRiverDrtpDataVo; 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 com.yfd.platform.utils.SecurityUtils; import jakarta.annotation.Resource; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.jdbc.core.JdbcTemplate; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; +import java.util.Date; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @Service public class ZqMonitorServiceImpl implements ZqMonitorService { + private static final String ZQ_HOUR_TABLE_NAME = "SD_RIVER_R"; + private static final String ZQ_DAY_TABLE_NAME = "SD_RIVERDAY_S"; + private static final String ZQ_MONTH_TABLE_NAME = "SD_RIVERDRTP_S"; + private static final Map ZQ_UPDATE_COLUMN_MAP = new LinkedHashMap<>(); + private static final Map ZQ_FIELD_MEANING_MAP = new LinkedHashMap<>(); + + static { + ZQ_UPDATE_COLUMN_MAP.put("z", "Z"); + ZQ_UPDATE_COLUMN_MAP.put("q", "Q"); + ZQ_UPDATE_COLUMN_MAP.put("v", "V"); + + ZQ_FIELD_MEANING_MAP.put("ID", "主键ID"); + ZQ_FIELD_MEANING_MAP.put("STCD", "站码"); + ZQ_FIELD_MEANING_MAP.put("TM", "时间"); + ZQ_FIELD_MEANING_MAP.put("DT", "时间"); + ZQ_FIELD_MEANING_MAP.put("DRTP", "维度类型"); + ZQ_FIELD_MEANING_MAP.put("YEAR", "年"); + ZQ_FIELD_MEANING_MAP.put("MONTH", "月"); + ZQ_FIELD_MEANING_MAP.put("DR", "时段类型"); + ZQ_FIELD_MEANING_MAP.put("Z", "水位"); + ZQ_FIELD_MEANING_MAP.put("Q", "流量"); + ZQ_FIELD_MEANING_MAP.put("V", "流速"); + ZQ_FIELD_MEANING_MAP.put("MSQMT", "测流方法"); + ZQ_FIELD_MEANING_MAP.put("RECORD_USER", "创建人"); + ZQ_FIELD_MEANING_MAP.put("RECORD_TIME", "创建时间"); + ZQ_FIELD_MEANING_MAP.put("MODIFY_USER", "更新人"); + ZQ_FIELD_MEANING_MAP.put("MODIFY_TIME", "更新时间"); + ZQ_FIELD_MEANING_MAP.put("IS_DELETED", "是否已删除"); + ZQ_FIELD_MEANING_MAP.put("DELETE_USER", "删除人"); + ZQ_FIELD_MEANING_MAP.put("DELETE_TIME", "删除时间"); + ZQ_FIELD_MEANING_MAP.put("FID", "附件ID"); + ZQ_FIELD_MEANING_MAP.put("REMARK", "备注"); + } @Resource private MicroservicDynamicSQLMapper microservicDynamicSQLMapper; @@ -43,6 +82,12 @@ public class ZqMonitorServiceImpl implements ZqMonitorService { @Resource private JdbcTemplate jdbcTemplate; + @Resource + private MsOperationLogMapper msOperationLogMapper; + + @Resource + private MsOperationLogDetailMapper msOperationLogDetailMapper; + @Override public DataSourceResult getMsstbprptList(DataSourceRequest dataSourceRequest) { return getMsstbprptListInternal(dataSourceRequest, false); @@ -170,11 +215,14 @@ public class ZqMonitorServiceImpl implements ZqMonitorService { } String dataType = batchDeleteAo.getDataType(); List dataList = batchDeleteAo.getDataList(); + String source = batchDeleteAo.getSource(); int batchSize = 500; for (int i = 0; i < dataList.size(); i += batchSize) { List subList = dataList.subList(i, Math.min(i + batchSize, dataList.size())); if ("TIME".equals(dataType)) { + List> beforeRows = queryRiverHourRows(subList); deleteRiverRData(subList); + recordRiverDeleteLog(beforeRows, ZQ_HOUR_TABLE_NAME, "删除流量站小时数据", source); Map dateRangeMap = new HashMap<>(); Map monthRangeMap = new HashMap<>(); for (DataParam param : subList) { @@ -209,10 +257,14 @@ public class ZqMonitorServiceImpl implements ZqMonitorService { } } if ("DATE".equals(dataType)) { + List> beforeRows = queryRiverDayRows(subList); deleteRiverDayData(subList); + recordRiverDeleteLog(beforeRows, ZQ_DAY_TABLE_NAME, "删除流量站日数据", source); } if ("MON".equals(dataType)) { + List> beforeRows = queryRiverMonthRows(subList); deleteRiverMonthData(subList); + recordRiverDeleteLog(beforeRows, ZQ_MONTH_TABLE_NAME, "删除流量站月数据", source); } } return true; @@ -220,10 +272,12 @@ public class ZqMonitorServiceImpl implements ZqMonitorService { @Override @Transactional(rollbackFor = Exception.class) - public boolean updateRiverRData(Map updateData) { - updateRiverHourData(updateData); + public boolean updateRiverRData(Map updateData, String source) { String stcd = updateData == null ? null : asString(updateData.get("stcd")); String tm = updateData == null ? null : asString(updateData.get("tm")); + Map beforeRow = queryRiverHourRow(stcd, tm); + updateRiverHourData(updateData); + recordRiverUpdateLog(beforeRow, updateData, source); if (StrUtil.isNotBlank(stcd) && StrUtil.isNotBlank(tm) && tm.length() >= 10) { String dateStr = tm.substring(0, 10); statisticsDayDataFromHour(stcd, dateStr, dateStr); @@ -1612,6 +1666,273 @@ public class ZqMonitorServiceImpl implements ZqMonitorService { return value == null ? null : String.valueOf(value); } + private Map queryRiverHourRow(String stcd, String tm) { + if (StrUtil.isBlank(stcd) || StrUtil.isBlank(tm)) { + return new HashMap<>(); + } + String sql = "SELECT ID, STCD, TO_CHAR(TM, 'YYYY-MM-DD HH24:MI:SS') AS TM, Z, Q, V, MSQMT, RECORD_USER, " + + "RECORD_TIME, MODIFY_USER, MODIFY_TIME, IS_DELETED, DELETE_USER, DELETE_TIME, FID, REMARK " + + "FROM SD_RIVER_R WHERE STCD = ? AND TM = TO_DATE(?, 'YYYY-MM-DD HH24:MI:SS')"; + List> rows = jdbcTemplate.queryForList(sql, stcd, tm); + return rows.isEmpty() ? new HashMap<>() : normalizeRiverLogRow(rows.getFirst()); + } + + private List> queryRiverHourRows(List dataList) { + if (CollUtil.isEmpty(dataList)) { + return new ArrayList<>(); + } + StringBuilder sql = new StringBuilder("SELECT ID, STCD, TO_CHAR(TM, 'YYYY-MM-DD HH24:MI:SS') AS TM, Z, Q, V, MSQMT, RECORD_USER, ") + .append("RECORD_TIME, MODIFY_USER, MODIFY_TIME, IS_DELETED, DELETE_USER, DELETE_TIME, FID, REMARK ") + .append("FROM SD_RIVER_R WHERE "); + List args = new ArrayList<>(); + List conditions = new ArrayList<>(); + for (DataParam item : dataList) { + if (item == null || StrUtil.isBlank(item.getId()) || StrUtil.isBlank(item.getTm())) { + continue; + } + conditions.add("(STCD = ? AND TM = TO_DATE(?, 'YYYY-MM-DD HH24:MI:SS'))"); + args.add(item.getId()); + args.add(item.getTm()); + } + if (conditions.isEmpty()) { + return new ArrayList<>(); + } + sql.append(String.join(" OR ", conditions)); + return normalizeRiverLogRows(jdbcTemplate.queryForList(sql.toString(), args.toArray())); + } + + private List> queryRiverDayRows(List dataList) { + if (CollUtil.isEmpty(dataList)) { + return new ArrayList<>(); + } + StringBuilder sql = new StringBuilder("SELECT ID, STCD, TO_CHAR(DT, 'YYYY-MM-DD HH24:MI:SS') AS DT, Z, Q, V, MSQMT, RECORD_USER, ") + .append("RECORD_TIME, MODIFY_USER, MODIFY_TIME, IS_DELETED, DELETE_USER, DELETE_TIME ") + .append("FROM SD_RIVERDAY_S WHERE "); + List args = new ArrayList<>(); + List conditions = new ArrayList<>(); + for (DataParam item : dataList) { + if (item == null || StrUtil.isBlank(item.getId()) || StrUtil.isBlank(item.getDt())) { + continue; + } + conditions.add("(STCD = ? AND DT = TO_DATE(?, 'YYYY-MM-DD HH24:MI:SS'))"); + args.add(item.getId()); + args.add(item.getDt()); + } + if (conditions.isEmpty()) { + return new ArrayList<>(); + } + sql.append(String.join(" OR ", conditions)); + return normalizeRiverLogRows(jdbcTemplate.queryForList(sql.toString(), args.toArray())); + } + + private List> queryRiverMonthRows(List dataList) { + if (CollUtil.isEmpty(dataList)) { + return new ArrayList<>(); + } + StringBuilder sql = new StringBuilder("SELECT ID, STCD, TO_CHAR(TM, 'YYYY-MM-DD HH24:MI:SS') AS TM, DRTP, YEAR, MONTH, DR, Z, Q, V, MSQMT, ") + .append("RECORD_USER, RECORD_TIME, MODIFY_USER, MODIFY_TIME, IS_DELETED, DELETE_USER, DELETE_TIME ") + .append("FROM SD_RIVERDRTP_S WHERE "); + List args = new ArrayList<>(); + List conditions = new ArrayList<>(); + for (DataParam item : dataList) { + if (item == null || StrUtil.isBlank(item.getId()) || StrUtil.isBlank(item.getDrtp()) + || StrUtil.isBlank(item.getYear()) || StrUtil.isBlank(item.getMonth())) { + continue; + } + conditions.add("(STCD = ? AND DRTP = ? AND YEAR = ? AND MONTH = ?)"); + args.add(item.getId()); + args.add(item.getDrtp()); + args.add(Integer.parseInt(item.getYear())); + args.add(Integer.parseInt(item.getMonth())); + } + if (conditions.isEmpty()) { + return new ArrayList<>(); + } + sql.append(String.join(" OR ", conditions)); + return normalizeRiverLogRows(jdbcTemplate.queryForList(sql.toString(), args.toArray())); + } + + private List> normalizeRiverLogRows(List> rows) { + List> result = new ArrayList<>(); + if (CollUtil.isEmpty(rows)) { + return result; + } + for (Map row : rows) { + result.add(normalizeRiverLogRow(row)); + } + return result; + } + + private Map normalizeRiverLogRow(Map row) { + Map normalized = new LinkedHashMap<>(); + if (row == null || row.isEmpty()) { + return normalized; + } + for (Map.Entry entry : row.entrySet()) { + normalized.put(entry.getKey() == null ? null : entry.getKey().toUpperCase(), entry.getValue()); + } + return normalized; + } + + private void recordRiverUpdateLog(Map beforeRow, Map updateData, String source) { + if (updateData == null || updateData.isEmpty()) { + return; + } + String stcd = asString(updateData.get("stcd")); + String recordId = asString(beforeRow.get("ID")); + List details = new ArrayList<>(); + for (Map.Entry entry : ZQ_UPDATE_COLUMN_MAP.entrySet()) { + if (!containsKeyIgnoreCase(updateData, entry.getKey())) { + continue; + } + String column = entry.getValue(); + Object oldValue = beforeRow == null ? null : beforeRow.get(column); + Object newValue = getValueIgnoreCase(updateData, entry.getKey()); + if (StrUtil.equals(formatRiverLogValue(oldValue), formatRiverLogValue(newValue))) { + continue; + } + details.add(buildRiverLogDetail(null, ZQ_HOUR_TABLE_NAME, stcd, column, + oldValue, resolveRiverDisplayValue(column, oldValue), + newValue, resolveRiverDisplayValue(column, newValue), "修改字段值")); + } + if (details.isEmpty()) { + return; + } + MsOperationLog mainLog = buildRiverMainLog(recordId,"修改流量站小时数据", source); + msOperationLogMapper.insert(mainLog); + for (MsOperationLogDetail detail : details) { + detail.setMainId(mainLog.getId()); + } + batchInsertRiverLogDetails(details); + } + + private void recordRiverDeleteLog(List> rows, String tableName, String remark, String source) { + if (CollUtil.isEmpty(rows)) { + return; + } + + List details = new ArrayList<>(); + for (Map row : rows) { + String stcd = asString(row.get("STCD")); + String recordId = asString(row.get("ID")); + MsOperationLog mainLog = buildRiverMainLog(recordId,remark, source); + msOperationLogMapper.insert(mainLog); + for (Map.Entry entry : row.entrySet()) { + String fieldCode = entry.getKey(); + Object oldValue = entry.getValue(); + if (StrUtil.isBlank(fieldCode) || oldValue == null) { + continue; + } + details.add(buildRiverLogDetail(mainLog.getId(), tableName, stcd, fieldCode, + oldValue, resolveRiverDisplayValue(fieldCode, oldValue), + null, null, "删除字段值")); + } + } + batchInsertRiverLogDetails(details); + } + + private MsOperationLog buildRiverMainLog(String recordId,String remark, String source) { + MsOperationLog log = new MsOperationLog(); + log.setOperator(resolveRiverLogOperator()); + log.setOperateTime(new Date()); + log.setRecordId(recordId); + log.setTableName(ZQ_HOUR_TABLE_NAME); + log.setSource(StrUtil.trimToNull(source)); + log.setRemark(remark); + return log; + } + + private MsOperationLogDetail buildRiverLogDetail(String mainId, + String tableName, + String stationCode, + String fieldCode, + Object oldValueCode, + Object oldValueName, + Object newValueCode, + Object newValueName, + String remark) { + MsOperationLogDetail detail = new MsOperationLogDetail(); + detail.setMainId(mainId); + detail.setTableName(tableName); + detail.setStationCode(stationCode); + detail.setFieldCode(fieldCode); + detail.setFieldMeaning(ZQ_FIELD_MEANING_MAP.getOrDefault(fieldCode, fieldCode)); + detail.setOldValueCode(formatRiverLogValue(oldValueCode)); + detail.setOldValueName(formatRiverLogValue(oldValueName)); + detail.setNewValueCode(formatRiverLogValue(newValueCode)); + detail.setNewValueName(formatRiverLogValue(newValueName)); + detail.setRemark(remark); + return detail; + } + + private void batchInsertRiverLogDetails(List details) { + if (CollUtil.isEmpty(details)) { + return; + } + for (MsOperationLogDetail detail : details) { + if (detail == null) { + continue; + } + msOperationLogDetailMapper.insert(detail); + } + } + + private Object resolveRiverDisplayValue(String fieldCode, Object rawValue) { + return formatRiverLogValue(rawValue); + } + + private Object getValueIgnoreCase(Map data, String key) { + if (data == null || StrUtil.isBlank(key)) { + return null; + } + if (data.containsKey(key)) { + return data.get(key); + } + for (Map.Entry entry : data.entrySet()) { + if (StrUtil.equalsIgnoreCase(entry.getKey(), key)) { + return entry.getValue(); + } + } + return null; + } + + private boolean containsKeyIgnoreCase(Map data, String key) { + if (data == null || StrUtil.isBlank(key)) { + return false; + } + if (data.containsKey(key)) { + return true; + } + for (String mapKey : data.keySet()) { + if (StrUtil.equalsIgnoreCase(mapKey, key)) { + return true; + } + } + return false; + } + + private String resolveRiverLogOperator() { + try { + return SecurityUtils.getCurrentUsername(); + } catch (Exception ignored) { + try { + return SecurityUtils.getUserId(); + } catch (Exception ex) { + return null; + } + } + } + + private String formatRiverLogValue(Object value) { + if (value == null) { + return null; + } + if (value instanceof Date date) { + return cn.hutool.core.date.DateUtil.formatDateTime(date); + } + return String.valueOf(value); + } + private void statisticsDayDataFromHour(String stcd, String startDate, String endDate) { String deleteSql = "DELETE FROM SD_RIVERDAY_S T " + "WHERE T.STCD = ? " + diff --git a/backend/src/main/java/com/yfd/platform/system/service/IAdminAuthService.java b/backend/src/main/java/com/yfd/platform/system/service/IAdminAuthService.java new file mode 100644 index 00000000..ea25071d --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/service/IAdminAuthService.java @@ -0,0 +1,39 @@ +package com.yfd.platform.system.service; + +import java.util.List; +import java.util.Set; + +/** + * 超级管理员判断服务 + */ +public interface IAdminAuthService { + + /** + * 查询超级管理员用户名列表(SYS_USER.USERTYPE = 0) + * + * @return 超级管理员用户名列表 + */ + List getSuperAdminUsernames(); + + /** + * 查询统一管理的管理员用户名集合 + * + * @return 管理员用户名集合 + */ + Set getManagedAdminUsernames(); + + /** + * 判断指定用户名是否为超级管理员 + * + * @param username 用户名 + * @return 是否为超级管理员 + */ + boolean isManagedAdminUsername(String username); + + /** + * 判断当前登录用户是否为超级管理员 + * + * @return 是否为超级管理员 + */ + boolean isCurrentManagedAdmin(); +} diff --git a/backend/src/main/java/com/yfd/platform/system/service/IUserService.java b/backend/src/main/java/com/yfd/platform/system/service/IUserService.java index e5d970ac..4e9cdd62 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/IUserService.java +++ b/backend/src/main/java/com/yfd/platform/system/service/IUserService.java @@ -103,6 +103,13 @@ public interface IUserService extends IService { ************************************/ ResponseResult resetPassword(String id) throws Exception; + /** + * 查询超级管理员用户名列表(SYS_USER.USERTYPE = 0) + * + * @return 超级管理员用户名列表 + */ + List getSuperAdminUsernames(); + /*********************************** * 用途说明:设置账号状态(管理员) * 参数说明 diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/AdminAuthServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/AdminAuthServiceImpl.java new file mode 100644 index 00000000..046de510 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/AdminAuthServiceImpl.java @@ -0,0 +1,79 @@ +package com.yfd.platform.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.yfd.platform.system.domain.SysUser; +import com.yfd.platform.system.mapper.SysUserMapper; +import com.yfd.platform.system.service.IAdminAuthService; +import com.yfd.platform.system.service.IUserService; +import com.yfd.platform.utils.SecurityUtils; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.stereotype.Service; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 超级管理员判断服务实现 + */ +@Service +public class AdminAuthServiceImpl implements IAdminAuthService { + + private static final Set BUILT_IN_ADMIN_USERNAMES = + new LinkedHashSet<>(Collections.singletonList("admin")); + + @Resource + private SysUserMapper userMapper; + + @Override + public List getSuperAdminUsernames() { + + // 获取当前请求 + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysUser::getUsertype, 0).select(SysUser::getUsername); + //根据用户名称或手机号查询用户信息 + if (attributes != null) { + HttpServletRequest request = attributes.getRequest(); + String tenantId = request.getHeader("Tenant_Id"); + if(StrUtil.isNotBlank(tenantId)){ + queryWrapper.eq(SysUser::getTenantId, tenantId); + } + } + List userList = userMapper.selectList(queryWrapper); + if (CollUtil.isEmpty(userList)) { + return new ArrayList<>(); + } + return userList.stream() + .map(SysUser::getUsername) + .filter(StrUtil::isNotBlank) + .distinct() + .collect(Collectors.toList()); + } + + @Override + public Set getManagedAdminUsernames() { + LinkedHashSet usernames = new LinkedHashSet<>(BUILT_IN_ADMIN_USERNAMES); + usernames.addAll(getSuperAdminUsernames()); + return usernames; + } + + @Override + public boolean isManagedAdminUsername(String username) { + return StrUtil.isNotBlank(username) && getManagedAdminUsernames().contains(username); + } + + @Override + public boolean isCurrentManagedAdmin() { + return isManagedAdminUsername(SecurityUtils.getCurrentUsername()); + } +} diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java index 6e20d9dc..dcf3e8b6 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java @@ -11,6 +11,7 @@ import com.yfd.platform.system.domain.SysRole; import com.yfd.platform.system.domain.SysUser; import com.yfd.platform.system.mapper.SysOrganizationMapper; import com.yfd.platform.system.mapper.SysRoleMapper; +import com.yfd.platform.system.service.IAdminAuthService; import com.yfd.platform.system.service.ISysOrganizationService; import com.yfd.platform.system.service.IUserService; import com.yfd.platform.utils.ObjectConverterUtil; @@ -38,6 +39,9 @@ public class SysOrganizationServiceImpl extends ServiceImpl> getOrgScopeTree(String roleId, String tenantId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - if(!"admin".equals(SecurityUtils.getCurrentUsername())){ + if(!adminAuthService.isCurrentManagedAdmin()){ String userId = SecurityUtils.getUserId(); List roles = sysRoleMapper.getRoleByUserId(userId); List ids = new ArrayList<>(); diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/UserDetailsServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/UserDetailsServiceImpl.java index 6042beea..77506150 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/UserDetailsServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/UserDetailsServiceImpl.java @@ -1,18 +1,23 @@ package com.yfd.platform.system.service.impl; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.yfd.platform.datasource.DataSource; import com.yfd.platform.system.domain.LoginUser; import com.yfd.platform.system.domain.SysUser; import com.yfd.platform.system.mapper.SysMenuMapper; import com.yfd.platform.system.service.IUserService; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import jakarta.annotation.Resource; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + import java.util.List; /** @@ -35,9 +40,19 @@ public class UserDetailsServiceImpl implements UserDetailsService { @Override @DataSource(name = "master") public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + // 获取当前请求 + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); //根据用户名称或手机号查询用户信息 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.and(wrapper -> wrapper.eq("username", username).or().eq("phone", username)); + if (attributes != null) { + HttpServletRequest request = attributes.getRequest(); + String tenantId = request.getHeader("Tenant_Id"); + if(StrUtil.isNotBlank(tenantId)){ + queryWrapper.eq("TENANT_ID", tenantId); + } + } + SysUser user = userService.getOne(queryWrapper); if (ObjectUtil.isEmpty(user)) { throw new RuntimeException("用户账号不存在!"); diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java index 0e157cd4..5f11a266 100644 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java @@ -22,6 +22,7 @@ import com.yfd.platform.system.domain.SysRole; import com.yfd.platform.system.domain.SysUser; import com.yfd.platform.system.mapper.SysRoleMapper; import com.yfd.platform.system.mapper.SysUserMapper; +import com.yfd.platform.system.service.IAdminAuthService; import com.yfd.platform.system.service.IUserService; import com.yfd.platform.utils.FileUtil; import com.yfd.platform.utils.PasswordGenerator; @@ -80,6 +81,9 @@ public class UserServiceImpl extends ServiceImpl impleme @Resource private SysUserDataScopeMapper sysUserDataScopeMapper; + @Resource + private IAdminAuthService adminAuthService; + /********************************** * 用途说明:获取当前用户账号及名称 * 参数说明 @@ -162,7 +166,7 @@ public class UserServiceImpl extends ServiceImpl impleme //账号有效 sysUser.setStatus(1); //判断注册的登录账号是否存在 - if (isExistAccount(sysUser.getUsername())) { + if (isExistAccount(sysUser.getUsername(),sysUser.getTenantId() )) { //新增用户 boolean ok = this.save(sysUser); //新增用户分配权限 @@ -419,7 +423,7 @@ public class UserServiceImpl extends ServiceImpl impleme //账号头像存储地址 String imgName = fileSpaceProperties.getSystem() + File.separator + "user" + File.separator + sysUser.getAvatar(); - if ("admin".equals(sysUser.getUsername())) { + if (adminAuthService.isManagedAdminUsername(sysUser.getUsername())) { return false; } else { boolean isOk = this.removeById(id); @@ -446,31 +450,30 @@ public class UserServiceImpl extends ServiceImpl impleme ************************************/ @Override public ResponseResult resetPassword(String id) throws Exception { - //根据当前用户id 查询角色表的级别 currentUser.getUser() 获取当前用户id - String level = sysUserMapper.getMaxLevel(id); - //判断是否获取级别 - if ("admin".equals(SecurityUtils.getCurrentUsername()) || StrUtil.isNotEmpty(level)) { - //判断当前用户级别 管理员及以上权限 - if ("admin".equals(SecurityUtils.getCurrentUsername()) || Integer.parseInt(level) <= 2) { - SysUser sysUser = sysUserMapper.selectById(id); - UpdateWrapper updateWrapper = new UpdateWrapper<>(); - String password = PasswordGenerator.generateRandomPassword(sysUser.getUsername()); - //根据id 修改密码,密码修改时间,最近修改者,最近修改日期 将密码修改为 123456 - String cryptPassword = passwordEncoder.encode(password); - updateWrapper.eq("id", id).set("password", cryptPassword).set( - "pwdresettime", - new Timestamp(System.currentTimeMillis())).set( - "lastmodifydate", - new Timestamp(System.currentTimeMillis())).set( - "lastmodifier", getUsername()); - //是否修改成功 - this.update(updateWrapper); - return ResponseResult.successData(password); - } + if (hasAdminOperationPermission()) { + SysUser sysUser = sysUserMapper.selectById(id); + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + String password = PasswordGenerator.generateRandomPassword(sysUser.getUsername()); + //根据id 修改密码,密码修改时间,最近修改者,最近修改日期 + String cryptPassword = passwordEncoder.encode(password); + updateWrapper.eq("id", id).set("password", cryptPassword).set( + "pwdresettime", + new Timestamp(System.currentTimeMillis())).set( + "lastmodifydate", + new Timestamp(System.currentTimeMillis())).set( + "lastmodifier", getUsername()); + //是否修改成功 + this.update(updateWrapper); + return ResponseResult.successData(password); } return ResponseResult.error(); } + @Override + public List getSuperAdminUsernames() { + return adminAuthService.getSuperAdminUsernames(); + } + /*********************************** * 用途说明:设置账号状态(管理员) * 参数说明 @@ -481,10 +484,8 @@ public class UserServiceImpl extends ServiceImpl impleme @Override public boolean setStatus(String id, String status) { boolean isOk = false; - //根据当前用户id 查询角色表的级别 currentUser.getUser() 获取当前用户id - String level = sysUserMapper.getMaxLevel(id); //判断当前用户级别 管理员及以上权限 - if ("admin".equals(SecurityUtils.getCurrentUsername()) || Integer.parseInt(level) <= 2) { + if (hasAdminOperationPermission()) { UpdateWrapper updateWrapper = new UpdateWrapper<>(); //根据id修改用户状态,最近修改人,最近修改时间 updateWrapper.eq("id", id).set("status", status).set( @@ -497,6 +498,35 @@ public class UserServiceImpl extends ServiceImpl impleme return isOk; } + private boolean hasAdminOperationPermission() { + if (adminAuthService.isCurrentManagedAdmin()) { + return true; + } + String currentUserId = SecurityUtils.getUserId(); + String level = sysUserMapper.getMaxLevel(currentUserId); + Integer roleLevel = parseRoleLevel(level); + return roleLevel != null && roleLevel <= 2; + } + + private boolean isCurrentManagedAdmin() { + return adminAuthService.isCurrentManagedAdmin(); + } + + private boolean isManagedAdminUsername(String username) { + return adminAuthService.isManagedAdminUsername(username); + } + + private Set getManagedAdminUsernames() { + return adminAuthService.getManagedAdminUsernames(); + } + + private Integer parseRoleLevel(String level) { + if (StrUtil.isBlank(level) || !StrUtil.isNumeric(level)) { + return null; + } + return Integer.parseInt(level); + } + /*********************************** * 用途说明:上传用户头像 * 参数说明 @@ -864,9 +894,9 @@ public class UserServiceImpl extends ServiceImpl impleme * account 登录名称 * 返回值说明: 重复返回 false 否则返回 true ************************************/ - private boolean isExistAccount(String username) { + private boolean isExistAccount(String username,String tenantId) { QueryWrapper queryWrapper = new QueryWrapper<>(); - if (this.list(queryWrapper.eq("username", username)).size() > 0) { + if (this.list(queryWrapper.eq("username", username).eq("TENANT_ID", tenantId)).size() > 0) { //判断 查询登录账号 结果集是否为null 重复返回 false 否则返回 tree return false; } else { diff --git a/backend/src/main/java/com/yfd/platform/utils/CodeToNameMetadataBo.java b/backend/src/main/java/com/yfd/platform/utils/CodeToNameMetadataBo.java new file mode 100644 index 00000000..5f8ba742 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/utils/CodeToNameMetadataBo.java @@ -0,0 +1,94 @@ +package com.yfd.platform.utils; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 代码转名称元数据配置 + *

+ * 用于配置 VO 中某个 code 字段如何转换为对应的 name 字段, + * 支持静态字典(SYS_DICTIONARY / SYS_DICTIONARY_ITEMS)和动态字典(业务表)。 + *

+ * + *
+ * 使用示例:
+ * // 静态字典:将 vo.typeCode 转为 vo.typeName,字典编码为 "PROJECT_TYPE"
+ * CodeToNameMetadataBo.builder()
+ *     .codeProperty("typeCode")
+ *     .modifyProperty("typeName")
+ *     .dictType("STATIC")
+ *     .dictSource("PROJECT_TYPE")
+ *     .build();
+ *
+ * // 动态字典:将 vo.engCode 转为 vo.engName,查 SD_ENGINFO_B_H 表
+ * CodeToNameMetadataBo.builder()
+ *     .codeProperty("engCode")
+ *     .modifyProperty("engName")
+ *     .dictType("DYNAMIC")
+ *     .dictSource("SD_ENGINFO_B_H")
+ *     .codeColumn("STCD")
+ *     .nameColumn("ENNM")
+ *     .filter("NVL(IS_DELETED, 0) = 0")
+ *     .build();
+ * 
+ * + * @author Generated + * @since 2025-05-18 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CodeToNameMetadataBo implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 编码属性名(VO 中存放 code 的字段名) + */ + private String codeProperty; + + /** + * 名称属性名(VO 中需要设置 name 的字段名) + */ + private String modifyProperty; + + /** + * 字典类型:STATIC(静态字典)或 DYNAMIC(动态字典) + */ + private String dictType; + + /** + * 字典来源: + * - 静态字典:SYS_DICTIONARY 表中的 DICTCODE + * - 动态字典:业务表名 + */ + private String dictSource; + + /** + * 动态字典:表中编码列名(静态字典不需要) + */ + private String codeColumn; + + /** + * 动态字典:表中名称列名(静态字典不需要) + */ + private String nameColumn; + + /** + * 额外过滤条件(可选) + * - 静态字典:SYS_DICTIONARY_ITEMS 的额外 WHERE 条件 + * - 动态字典:业务表的额外 WHERE 条件 + */ + private String filter; + + /** + * 是否多选(code 值为逗号分隔的多个编码) + */ + @Builder.Default + private boolean isMulti = false; +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/utils/DictCodeToNameConverter.java b/backend/src/main/java/com/yfd/platform/utils/DictCodeToNameConverter.java new file mode 100644 index 00000000..363d4f92 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/utils/DictCodeToNameConverter.java @@ -0,0 +1,391 @@ +package com.yfd.platform.utils; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.yfd.platform.common.MicroservicDynamicSQLMapper; +import com.yfd.platform.system.domain.SysDictionary; +import com.yfd.platform.system.domain.SysDictionaryItems; +import com.yfd.platform.system.mapper.SysDictionaryItemsMapper; +import com.yfd.platform.system.mapper.SysDictionaryMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Field; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +/** + * 字典代码转名称转换器 + *

+ * 支持静态字典(SYS_DICTIONARY / SYS_DICTIONARY_ITEMS)和动态字典(业务表查询), + * 将 VO 中的 code 字段值转换为对应的 name 字段值。 + *

+ * + *

使用方式

+ *
+ * // 1. 在 ServiceImpl 中注入
+ * @Resource
+ * private DictCodeToNameConverter dictCodeToNameConverter;
+ *
+ * // 2. 定义元数据列表(通常放在 static 静态代码块中)
+ * private static final List<CodeToNameMetadataBo> CODE_TO_NAME_META_LIST = List.of(
+ *     CodeToNameMetadataBo.builder()
+ *         .codeProperty("stationType")
+ *         .modifyProperty("stationTypeName")
+ *         .dictType("STATIC")
+ *         .dictSource("STATION_TYPE")
+ *         .build(),
+ *     CodeToNameMetadataBo.builder()
+ *         .codeProperty("engCode")
+ *         .modifyProperty("engName")
+ *         .dictType("DYNAMIC")
+ *         .dictSource("SD_ENGINFO_B_H")
+ *         .codeColumn("STCD")
+ *         .nameColumn("ENNM")
+ *         .filter("NVL(IS_DELETED, 0) = 0")
+ *         .build()
+ * );
+ *
+ * // 3. 在查询方法中调用转换
+ * public DataSourceResult<MyVo> queryList(DataSourceRequest request) {
+ *     // ... 查询数据得到 voList ...
+ *     dictCodeToNameConverter.convertCodeToName(voList, CODE_TO_NAME_META_LIST);
+ *     // ... 返回结果 ...
+ * }
+ * 
+ * + * @author Generated + * @since 2025-05-18 + */ +@Slf4j +@Component +public class DictCodeToNameConverter { + + @Resource + private SysDictionaryMapper sysDictionaryMapper; + + @Resource + private SysDictionaryItemsMapper sysDictionaryItemsMapper; + + @Resource + private MicroservicDynamicSQLMapper microservicDynamicSQLMapper; + + /** + * 静态字典缓存:dictCode -> Map + */ + private final Map> staticDictCache = new ConcurrentHashMap<>(); + + /** + * 动态字典缓存:缓存key -> Map + */ + private final Map> dynamicDictCache = new ConcurrentHashMap<>(); + + /** + * 批量转换:根据元数据配置,将 VO 列表中的 code 字段转换为对应的 name 字段 + * + * @param voList VO 对象列表 + * @param metadataList 元数据配置列表 + * @param VO 类型 + */ + public void convertCodeToName(List voList, List metadataList) { + if (voList == null || voList.isEmpty() || metadataList == null || metadataList.isEmpty()) { + return; + } + + for (CodeToNameMetadataBo metadata : metadataList) { + try { + Map codeNameMap = loadCodeNameMap(metadata); + if (codeNameMap.isEmpty()) { + continue; + } + applyCodeToName(voList, metadata, codeNameMap); + } catch (Exception e) { + log.error("字典转换失败: codeProperty={}, dictSource={}", metadata.getCodeProperty(), metadata.getDictSource(), e); + } + } + } + + /** + * 分页结果转换:将 Page 中所有记录的 code 字段转换为对应的 name 字段 + * + *
+     * 使用示例:
+     * Page<SdHbrvDic> page = hbrvDicService.queryPageList(...);
+     * dictCodeToNameConverter.convertCodeToName(page, CODE_TO_NAME_META_LIST);
+     * 
+ * + * @param page 分页对象 + * @param metadataList 元数据配置列表 + * @param VO 类型 + */ + public void convertCodeToName(Page page, List metadataList) { + if (page == null || page.getRecords() == null || page.getRecords().isEmpty()) { + return; + } + convertCodeToName(page.getRecords(), metadataList); + } + + /** + * 单个对象转换:将单个对象的 code 字段转换为对应的 name 字段 + * + *
+     * 使用示例:
+     * SdHbrvDic hbrvDic = hbrvDicService.getById(hbrvcd);
+     * dictCodeToNameConverter.convertCodeToName(hbrvDic, CODE_TO_NAME_META_LIST);
+     * 
+ * + * @param obj 单个对象 + * @param metadataList 元数据配置列表 + * @param VO 类型 + */ + public void convertCodeToName(T obj, List metadataList) { + if (obj == null || metadataList == null || metadataList.isEmpty()) { + return; + } + convertCodeToName(Collections.singletonList(obj), metadataList); + } + + /** + * 加载静态字典映射 + * + * @param dictCode 字典编码 + * @return Map + */ + public Map loadStaticDictMap(String dictCode) { + return staticDictCache.computeIfAbsent(dictCode, key -> { + Map map = new LinkedHashMap<>(); + try { + SysDictionary dict = sysDictionaryMapper.selectOne( + new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper() + .eq(SysDictionary::getDictCode, key) + ); + if (dict == null) { + log.warn("静态字典未找到: dictCode={}", key); + return map; + } + List items = sysDictionaryItemsMapper.selectList( + new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper() + .eq(SysDictionaryItems::getDictId, dict.getId()) + .orderByAsc(SysDictionaryItems::getOrderNo) + ); + for (SysDictionaryItems item : items) { + if (StrUtil.isNotBlank(item.getItemCode())) { + map.put(item.getItemCode(), StrUtil.nullToDefault(item.getDictName(), item.getItemCode())); + } + } + } catch (Exception e) { + log.error("加载静态字典失败: dictCode={}", key, e); + } + return map; + }); + } + + /** + * 加载动态字典映射(从业务表查询) + * + * @param tableName 表名 + * @param codeColumn 编码列名 + * @param nameColumn 名称列名 + * @param filter 额外过滤条件 + * @return Map + */ + public Map loadDynamicDictMap(String tableName, String codeColumn, String nameColumn, String filter) { + String cacheKey = tableName + "|" + codeColumn + "|" + nameColumn + "|" + StrUtil.nullToDefault(filter, ""); + return dynamicDictCache.computeIfAbsent(cacheKey, key -> { + Map map = new LinkedHashMap<>(); + try { + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ").append(codeColumn).append(" AS code, ") + .append(nameColumn).append(" AS name ") + .append("FROM ").append(tableName) + .append(" WHERE 1=1 "); + if (StrUtil.isNotBlank(filter)) { + sql.append("AND ").append(filter).append(" "); + } + Map params = new HashMap<>(); + List> rows = microservicDynamicSQLMapper.getAllList(sql.toString(), params); + for (Map row : rows) { + String code = Objects.toString(row.get("CODE"), null); + String name = Objects.toString(row.get("NAME"), null); + if (StrUtil.isNotBlank(code)) { + map.put(code, StrUtil.nullToDefault(name, code)); + } + } + } catch (Exception e) { + log.error("加载动态字典失败: tableName={}", tableName, e); + } + return map; + }); + } + + /** + * 根据元数据加载 code->name 映射 + */ + private Map loadCodeNameMap(CodeToNameMetadataBo metadata) { + if ("STATIC".equalsIgnoreCase(metadata.getDictType())) { + return loadStaticDictMap(metadata.getDictSource()); + } else if ("DYNAMIC".equalsIgnoreCase(metadata.getDictType())) { + return loadDynamicDictMap( + metadata.getDictSource(), + metadata.getCodeColumn(), + metadata.getNameColumn(), + metadata.getFilter() + ); + } + log.warn("未知字典类型: dictType={}", metadata.getDictType()); + return Collections.emptyMap(); + } + + /** + * 将 code->name 映射应用到 VO 列表 + */ + private void applyCodeToName(List voList, CodeToNameMetadataBo metadata, Map codeNameMap) { + for (T vo : voList) { + try { + String codeValue = getFieldValue(vo, metadata.getCodeProperty()); + if (StrUtil.isBlank(codeValue)) { + continue; + } + + String nameValue; + if (metadata.isMulti()) { + // 多选:逗号分隔的多个code + nameValue = Arrays.stream(codeValue.split(",")) + .map(String::trim) + .filter(StrUtil::isNotBlank) + .map(c -> codeNameMap.getOrDefault(c, c)) + .collect(Collectors.joining(",")); + } else { + nameValue = codeNameMap.getOrDefault(codeValue.trim(), codeValue); + } + setFieldValue(vo, metadata.getModifyProperty(), nameValue); + } catch (Exception e) { + log.debug("字段转换跳过: vo={}, codeProperty={}", vo.getClass().getSimpleName(), metadata.getCodeProperty(), e); + } + } + } + + /** + * 清除所有缓存 + */ + public void clearCache() { + staticDictCache.clear(); + dynamicDictCache.clear(); + } + + /** + * 清除指定静态字典缓存 + */ + public void clearStaticDictCache(String dictCode) { + staticDictCache.remove(dictCode); + } + + /** + * 清除指定动态字典缓存 + */ + public void clearDynamicDictCache(String tableName, String codeColumn, String nameColumn, String filter) { + String cacheKey = tableName + "|" + codeColumn + "|" + nameColumn + "|" + StrUtil.nullToDefault(filter, ""); + dynamicDictCache.remove(cacheKey); + } + + // ==================== 反射工具方法 ==================== + + /** + * 通过反射获取对象的字段值(转为字符串),支持驼峰命名 + */ + private String getFieldValue(T obj, String fieldName) { + try { + Field field = findField(obj.getClass(), fieldName); + if (field == null) { + return null; + } + field.setAccessible(true); + Object value = field.get(obj); + return value != null ? value.toString() : null; + } catch (Exception e) { + return null; + } + } + + /** + * 通过反射设置对象的字段值,支持驼峰命名 + */ + private void setFieldValue(T obj, String fieldName, String value) { + try { + Field field = findField(obj.getClass(), fieldName); + if (field == null) { + return; + } + field.setAccessible(true); + field.set(obj, value); + } catch (Exception ignored) { + // 忽略设置失败 + } + } + + /** + * 查找字段(忽略大小写,支持驼峰和下划线变体),递归查找父类 + */ + private Field findField(Class clazz, String fieldName) { + if (clazz == null || clazz == Object.class) { + return null; + } + // 先精确匹配 + for (Field field : clazz.getDeclaredFields()) { + if (field.getName().equals(fieldName)) { + return field; + } + } + // 忽略大小写匹配 + for (Field field : clazz.getDeclaredFields()) { + if (field.getName().equalsIgnoreCase(fieldName)) { + return field; + } + } + // 驼峰-下划线互转匹配 + String camelName = underlineToCamel(fieldName); + String underlineName = camelToUnderline(fieldName); + for (Field field : clazz.getDeclaredFields()) { + String fName = field.getName(); + if (fName.equalsIgnoreCase(camelName) || fName.equalsIgnoreCase(underlineName)) { + return field; + } + } + return findField(clazz.getSuperclass(), fieldName); + } + + private String underlineToCamel(String str) { + if (StrUtil.isBlank(str) || !str.contains("_")) { + return str; + } + StringBuilder sb = new StringBuilder(); + boolean upper = false; + for (char c : str.toCharArray()) { + if (c == '_') { + upper = true; + } else { + sb.append(upper ? Character.toUpperCase(c) : c); + upper = false; + } + } + return sb.toString(); + } + + private String camelToUnderline(String str) { + if (StrUtil.isBlank(str)) { + return str; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (Character.isUpperCase(c)) { + sb.append('_').append(Character.toLowerCase(c)); + } else { + sb.append(c); + } + } + return sb.toString(); + } +} \ No newline at end of file