diff --git a/backend/src/main/java/com/yfd/platform/PlatformApplication.java b/backend/src/main/java/com/yfd/platform/PlatformApplication.java index 94785cf1..9d7f55ed 100644 --- a/backend/src/main/java/com/yfd/platform/PlatformApplication.java +++ b/backend/src/main/java/com/yfd/platform/PlatformApplication.java @@ -23,7 +23,7 @@ import org.springframework.web.bind.annotation.RestController; @ServletComponentScan("com.yfd.platform.config") @MapperScan(basePackages = {"com.yfd.platform.*.mapper","com.yfd.platform.*.*.mapper", "com.yfd.platform.common"}) //@ComponentScan("com.zny.dec") -@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class, DataRedisAutoConfiguration.class}) +@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class}) //@SpringBootApplication @Import({DynamicDataSourceConfig.class}) @EnableCaching diff --git a/backend/src/main/java/com/yfd/platform/common/MicroservicDynamicSQLMapper.java b/backend/src/main/java/com/yfd/platform/common/MicroservicDynamicSQLMapper.java index 59e435bd..319f2ffd 100644 --- a/backend/src/main/java/com/yfd/platform/common/MicroservicDynamicSQLMapper.java +++ b/backend/src/main/java/com/yfd/platform/common/MicroservicDynamicSQLMapper.java @@ -5,6 +5,8 @@ import cn.hutool.core.bean.copier.CopyOptions; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.apache.ibatis.annotations.Mapper; + +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.ArrayList; @@ -49,6 +51,20 @@ public interface MicroservicDynamicSQLMapper { return convertList(allList, resultType); } + default List getSingleColumnList(String sql, Map paramMap) { + List> rows = getAllList(sql, paramMap); + if (rows == null || rows.isEmpty()) { + return Collections.emptyList(); + } + List result = new ArrayList<>(rows.size()); + for (Map row : rows) { + // 获取第一个值并转为字符串 + Object firstValue = row.values().iterator().next(); + result.add(firstValue == null ? null : firstValue.toString()); + } + return result; + } + @Select({"select count(1) count from ${sql} and ${ew.sqlSegment}"}) Integer count(@Param("select") String select, @Param("sql") String sql, @Param("ew") QueryWrapper queryWrapper); diff --git a/backend/src/main/java/com/yfd/platform/config/RedisConfig.java b/backend/src/main/java/com/yfd/platform/config/RedisConfig.java new file mode 100644 index 00000000..7f32bf5d --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/config/RedisConfig.java @@ -0,0 +1,117 @@ +package com.yfd.platform.config; + +import cn.hutool.crypto.digest.DigestUtil; +import cn.hutool.json.JSONUtil; +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.interceptor.KeyGenerator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializationContext; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +@Configuration +@EnableCaching +public class RedisConfig { + + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory); + + StringRedisSerializer stringSerializer = new StringRedisSerializer(); + + redisTemplate.setKeySerializer(stringSerializer); + redisTemplate.setHashKeySerializer(stringSerializer); + redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer()); + redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer()); + + redisTemplate.afterPropertiesSet(); + return redisTemplate; + } + + @Bean + public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { + StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(); + stringRedisTemplate.setConnectionFactory(redisConnectionFactory); + return stringRedisTemplate; + } + + @Bean + @Primary + public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { + RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig() + .prefixCacheNameWith("qgc:") + .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) + .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(genericJackson2JsonRedisSerializer())) + .entryTtl(Duration.ofMinutes(30)); + +// Map cacheConfigs = new HashMap<>(); +// cacheConfigs.put("dictCache", defaultConfig.entryTtl(Duration.ofHours(6))); +// cacheConfigs.put("dataCache", defaultConfig.entryTtl(Duration.ofMinutes(5))); +// cacheConfigs.put("engInfoCache", defaultConfig.entryTtl(Duration.ofHours(2))); + + return RedisCacheManager.builder(redisConnectionFactory) + .cacheDefaults(defaultConfig) +// .withInitialCacheConfigurations(cacheConfigs) + .build(); + } + + @Bean + public GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + // ✅ 关键:启用默认类型信息(必须添加) + objectMapper.activateDefaultTyping( + objectMapper.getPolymorphicTypeValidator(), + ObjectMapper.DefaultTyping.NON_FINAL, + JsonTypeInfo.As.PROPERTY + ); + + return new GenericJackson2JsonRedisSerializer(objectMapper); + } + + @Bean("customKeyGenerator") + public KeyGenerator customKeyGenerator() { + return (target, method, params) -> { + StringBuilder sb = new StringBuilder(); + sb.append(target.getClass().getSimpleName()); + sb.append(":"); + sb.append(method.getName()); + sb.append(":"); + for (Object param : params) { + sb.append(param != null ? param.toString() : "null"); + sb.append(","); + } + if (!sb.isEmpty() && sb.charAt(sb.length() - 1) == ',') { + sb.deleteCharAt(sb.length() - 1); + } + return sb.toString(); + }; + } + + @Bean("cacheKeyGenerator") + public KeyGenerator cacheKeyGenerator() { + return (target, method, params) -> target.getClass().getName() + "." + method.getName() + ":" + DigestUtil.md5Hex(JSONUtil.toJsonStr(params)); + } +} \ No newline at end of file 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..10ae42bf 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() @@ -76,6 +77,9 @@ public class SecurityConfig { .requestMatchers("/fpr/**").permitAll() .requestMatchers("/fh/**").permitAll() .requestMatchers("/data/**").permitAll() + .requestMatchers("/mapLayer/**").permitAll() + .requestMatchers("/mapmodule/**").permitAll() + .requestMatchers("/mapLegend/**").permitAll() .requestMatchers("/sms/**").permitAll() .requestMatchers(HttpMethod.GET, "/").permitAll() .requestMatchers(HttpMethod.GET, 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..85db8810 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(); + } + + @@ -172,4 +181,20 @@ public class SwaggerConfig { .packagesToScan("com.yfd.platform.qgc_eng.eq.controller") .build(); } + + @Bean + public GroupedOpenApi groupSysApi() { + return GroupedOpenApi.builder() + .group("5. 图层管理") + .packagesToScan("com.yfd.platform.qgc_sys.mapLayer.controller") + .build(); + } + + @Bean + public GroupedOpenApi groupSysMcfgApi() { + return GroupedOpenApi.builder() + .group("5.1 图例结构管理") + .packagesToScan("com.yfd.platform.qgc_sys.mapcfg.controller") + .build(); + } } \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/config/WebConfig.java b/backend/src/main/java/com/yfd/platform/config/WebConfig.java index 8356277c..1539d29b 100644 --- a/backend/src/main/java/com/yfd/platform/config/WebConfig.java +++ b/backend/src/main/java/com/yfd/platform/config/WebConfig.java @@ -7,12 +7,15 @@ import jakarta.annotation.Resource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import java.util.concurrent.TimeUnit; + @Configuration public class WebConfig implements WebMvcConfigurer { @Resource @@ -21,11 +24,28 @@ public class WebConfig implements WebMvcConfigurer { @Value("${app.zip-import.temp-dir}") private String platformPath; - + @Resource + private StringRedisTemplate stringRedisTemplate; @Bean public Cache loginuserCache() { - return CacheUtil.newLRUCache(200);//用户登录缓存数 缺省200 + return CacheUtil.newLRUCache(200); + } + + public void putLoginCache(String key, String value, long timeoutSeconds) { + stringRedisTemplate.opsForValue().set(key, value, timeoutSeconds, TimeUnit.SECONDS); + } + + public void putLoginCache(String key, String value) { + stringRedisTemplate.opsForValue().set(key, value); + } + + public String getLoginCache(String key) { + return stringRedisTemplate.opsForValue().get(key); + } + + public void removeLoginCache(String key) { + stringRedisTemplate.delete(key); } @Bean 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/controller/SdEngMonitorController.java b/backend/src/main/java/com/yfd/platform/qgc_base/controller/SdEngMonitorController.java index b0bf0bcf..9395ae94 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/controller/SdEngMonitorController.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/controller/SdEngMonitorController.java @@ -44,4 +44,10 @@ public class SdEngMonitorController { public ResponseResult getOperatKendoList(@RequestBody DataSourceRequest dataSourceRequest) { return ResponseResult.successData(engInfoBHService.getOperatKendoList(dataSourceRequest)); } + + @PostMapping("/point/GetKendoListCust") + @Operation(summary = "水电站-地图锚点") + public ResponseResult getEngPointKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(engInfoBHService.getEngPointKendoListCust(dataSourceRequest)); + } } 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/EngPointVo.java b/backend/src/main/java/com/yfd/platform/qgc_base/domain/vo/EngPointVo.java new file mode 100644 index 00000000..c693d44d --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_base/domain/vo/EngPointVo.java @@ -0,0 +1,102 @@ +package com.yfd.platform.qgc_base.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +@Data +@Schema(description = "水电站描点") +public class EngPointVo { + + @Schema(description = "站码") + private String stcd; + + @Schema(description = "站点名称") + private String stnm; + + @Schema(description = "电站名称") + private String ennm; + + @Schema(description = "电站图片") + private String logo; + + @Schema(description = "标题名称") + private String titleName; + + @Schema(description = "流域编码") + private String rvcd; + + @Schema(description = "行政区编码") + private String addvcd; + + @Schema(description = "经度") + private BigDecimal lgtd; + + @Schema(description = "纬度") + private BigDecimal lttd; + + @Schema(description = "多年平均流量") + private BigDecimal avq; + + @Schema(description = "装机容量(MW)") + private BigDecimal ttpwr; + + @Schema(description = "正常蓄水位") + private BigDecimal normz; + + @Schema(description = "多年平均发电量") + private BigDecimal yrge; + + @Schema(description = "所属基地编码") + private String baseId; + + @Schema(description = "建成日期") + private Date jcdt; + + @Schema(description = "所属行政区名称") + private String addvcdName; + + @Schema(description = "站点类型") + private String sttp; + + @Schema(description = "站点类型编码") + private String sttpCode; + + @Schema(description = "站点类型映射") + private String sttpMap; + + @Schema(description = "遥测方式") + private String dtmel; + + @Schema(description = "站点排序") + private Integer siteStepSort; + + @Schema(description = "流域沿程") + private Integer rvcdStepSort; + + @Schema(description = "电站沿程") + private Integer rstcdStepSort; + + @Schema(description = "是否电站专题电站") + private String ifEngSpecial; + + @Schema(description = "电站装机类型") + private Integer endInstalledType; + + @Schema(description = "描点状态") + private String anchoPointState; + + @Schema(description = "工程规模") + private Integer prsc; + + @Schema(description = "图标旋转角度") + private Integer iconRotate; + + @Schema(description = "建设状态") + private Integer bldsttCcode; + + @Schema(description = "基地排序") + private Integer baseStepSort; +} \ No newline at end of file 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..5082c0ee 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 @@ -9,6 +9,7 @@ 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.EngPointVo; import com.yfd.platform.qgc_base.domain.vo.EngStInfoResultVo; import com.yfd.platform.qgc_base.domain.vo.EngVmsstbprptVo; @@ -84,4 +85,8 @@ public interface ISdEngInfoBHService extends IService { DataSourceResult getVmsstbprptKendoList(DataSourceRequest dataSourceRequest); DataSourceResult getOperatKendoList(DataSourceRequest dataSourceRequest); + + DataSourceResult getStbprpDataKendoListCust(DataSourceRequest dataSourceRequest, String tbCode, Boolean ignorePageLimit); + + DataSourceResult getEngPointKendoListCust(DataSourceRequest dataSourceRequest); } 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..879347e6 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,29 +27,26 @@ 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.EngPointVo; +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; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; 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 +85,9 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl queryPageList(Page page, String ennm, String rvcd, String baseId, String hycd) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); @@ -100,28 +100,32 @@ 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); } @Override + @Cacheable(cacheNames = "engInfoCache#3600", keyGenerator = "cacheKeyGenerator") public List getByBaseId(String baseId) { return engInfoBHMapper.selectByBaseId(baseId); } @Override + @Cacheable(cacheNames = "engInfoCache#3600", keyGenerator = "cacheKeyGenerator") public List getByHycd(String hycd) { return engInfoBHMapper.selectByHycd(hycd); } @Override + @Cacheable(cacheNames = "engInfoCache#3600", keyGenerator = "cacheKeyGenerator") public List getByRvcd(String rvcd,String reachcd) { return engInfoBHMapper.selectByRvcd(rvcd,reachcd); } @Override + @Cacheable(cacheNames = "engInfoCache#3600", keyGenerator = "cacheKeyGenerator") public List selectForDropdown(SdEngInfoBHRequest sdEngInfoBHRequest) { String baseId = sdEngInfoBHRequest.getBaseId(); String hbrvcd = sdEngInfoBHRequest.getHbrvcd(); @@ -142,7 +146,7 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl authorizedStations = getUserAuthorizedStationCodes(); @@ -226,6 +230,7 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl ids, String source) { List stcdList = ids == null ? new ArrayList<>() : ids.stream() @@ -709,6 +716,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 +1099,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 +1913,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 +2367,565 @@ 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) { + } + + @Override + public DataSourceResult getEngPointKendoListCust(DataSourceRequest dataSourceRequest) { + DataSourceResult result = new DataSourceResult<>(); + result.setAggregates(new HashMap<>()); + + if (dataSourceRequest == null) { + result.setData(new ArrayList<>()); + result.setTotal(0L); + return result; + } + + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append("t.STCD AS stcd, ") + .append("t.STNM AS ennm, ") + .append("t.LOGO AS logo, ") + .append("t.STNM AS stnm, ") + .append("t.STNM AS titleName, ") + .append("t.RVCD AS rvcd, ") + .append("t.ADDVCD AS addvcd, ") + .append("t.LGTD AS lgtd, ") + .append("t.LTTD AS lttd, ") + .append("t.AVQ AS avq, ") + .append("t.YRGEB AS ttpwr, ") + .append("t.FSLTDZ AS normz, ") + .append("t.YRGEB AS yrge, ") + .append("t.BASE_ID AS baseId, ") + .append("t.JCDT AS jcdt, ") + .append("t.ADDVCD_NAME AS addvcdName, ") + .append("t.PRSC AS prsc, ") + .append("CAST(NULL AS NUMBER) AS iconRotate, ") + .append("t.BLDSTT_CODE AS bldsttCcode, ") + .append("'ENG' AS sttpMap, ") + .append("'ENG' AS sttp, ") + .append("'ENG' AS sttpCode, ") + .append("t.DTIN_ENV AS dtmel, ") + .append("NVL(siteSort.SORT, 999999) AS siteStepSort, ") + .append("NVL(along.ORDER_INDEX, 999999) AS rvcdStepSort, ") + .append("NVL(rstSort.SORT, 999999) AS rstcdStepSort, ") + .append("NVL(hb.ORDER_INDEX, 999999) AS baseStepSort, ") + .append("CASE WHEN elec.configCount > 0 THEN 'true' WHEN elec.configCount IS NULL THEN 'false' ELSE 'false' END AS ifEngSpecial, ") + .append("CASE ") + .append(" WHEN t.PRSC IN ('1','2') AND t.BLDSTT_CODE = 2 THEN 'large_eng_built' ") + .append(" WHEN t.PRSC IN ('1','2') AND t.BLDSTT_CODE = 1 THEN 'large_eng_ubuilt' ") + .append(" WHEN t.PRSC IN ('1','2') AND (t.BLDSTT_CODE = 0 OR t.BLDSTT_CODE IS NULL) THEN 'large_eng_nbuilt' ") + .append(" WHEN t.PRSC IN ('3') AND t.BLDSTT_CODE = 2 THEN 'mid_eng_built' ") + .append(" WHEN t.PRSC IN ('3') AND t.BLDSTT_CODE = 1 THEN 'mid_eng_ubuilt' ") + .append(" WHEN t.PRSC IN ('3') AND (t.BLDSTT_CODE = 0 OR t.BLDSTT_CODE IS NULL) THEN 'mid_eng_nbuilt' ") + .append(" END AS anchoPointState, ") + .append("CASE ") + .append(" WHEN t.PRSC IN ('1','2') THEN 1 ") + .append(" WHEN t.PRSC IN ('3') THEN 2 ") + .append(" END AS endInstalledType ") + .append("FROM SD_ENGINFO_B_H t ") + .append("LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = t.BASE_ID AND NVL(hb.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN MS_ALONG_B along ON along.RVCD = t.HBRVCD AND along.CODE = 'common' AND NVL(along.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN ( ") + .append(" SELECT det.SORT, cfg.RVCD, det.STCD ") + .append(" FROM MS_ALONGDET_B det ") + .append(" INNER JOIN MS_ALONG_B cfg ON det.ALONG_ID = cfg.ID ") + .append(" WHERE NVL(det.IS_DELETED, 0) = 0 AND NVL(cfg.IS_DELETED, 0) = 0 AND cfg.CODE = 'common' ") + .append(") rstSort ON rstSort.RVCD = t.HBRVCD AND rstSort.STCD = t.STCD ") + .append("LEFT JOIN ( ") + .append(" SELECT det.SORT, cfg.RVCD, det.STCD ") + .append(" FROM MS_ALONGDET_B det ") + .append(" INNER JOIN MS_ALONG_B cfg ON det.ALONG_ID = cfg.ID ") + .append(" WHERE NVL(det.IS_DELETED, 0) = 0 AND NVL(cfg.IS_DELETED, 0) = 0 AND cfg.CODE = 'common' ") + .append(") siteSort ON siteSort.RVCD = t.HBRVCD AND siteSort.STCD = t.STCD ") + .append("LEFT JOIN ( ") + .append(" SELECT STCD, COUNT(ID) AS configCount ") + .append(" FROM SD_EQ_B_H ") + .append(" WHERE NVL(IS_DELETED, 0) = 0 ") + .append(" GROUP BY STCD ") + .append(") elec ON t.STCD = elec.STCD ") + .append("WHERE NVL(t.IS_DELETED, 0) = 0 ") + .append("AND NVL(t.USFL, 1) = 1 ") + .append("AND t.LGTD IS NOT NULL ") + .append("AND t.LTTD IS NOT NULL "); + + Map paramMap = new HashMap<>(); + String filterSql = buildEngPointFilterCondition(dataSourceRequest.getFilter(), paramMap, new int[]{0}); + if (StrUtil.isNotBlank(filterSql)) { + sql.append(" AND ").append(filterSql); + } + + sql.append(buildEngPointOrderBySql(dataSourceRequest.getSort())); + + DataSourceLoadOptionsBase loadOptions = dataSourceRequest.toDevRequest(); + Page page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + List list = microservicDynamicSQLMapper.pageAllListWithResultType(page, sql.toString(), paramMap, EngPointVo.class); + + result.setData(list); + result.setTotal(page == null ? list.size() : page.getTotal()); + return result; + } + + private String buildEngPointFilterCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + if (filter == null) { + return ""; + } + if (CollUtil.isNotEmpty(filter.getFilters())) { + List childConditions = new ArrayList<>(); + for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) { + String childSql = buildEngPointFilterCondition(child, paramMap, indexHolder); + if (StrUtil.isNotBlank(childSql)) { + childConditions.add(childSql); + } + } + if (childConditions.isEmpty()) { + return ""; + } + String logic = "or".equalsIgnoreCase(filter.getLogic()) ? " OR " : " AND "; + return "(" + String.join(logic, childConditions) + ")"; + } + String column = mapEngPointColumn(filter.getField()); + 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 + " <> '')"; + } + 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 = "engPointParam" + indexHolder[0]++; + paramMap.put(key, item); + placeholders.add("#{map." + key + "}"); + } + return column + ("ni".equals(operator) ? " NOT IN (" : " IN (") + String.join(", ", placeholders) + ")"; + } + if (value == null) { + return ""; + } + String key = "engPointParam" + 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 mapEngPointColumn(String field) { + if (StrUtil.isBlank(field)) { + return null; + } + return switch (field) { + case "stcd" -> "t.STCD"; + case "stnm", "ennm", "titleName" -> "t.STNM"; + case "rvcd" -> "t.RVCD"; + case "addvcd" -> "t.ADDVCD"; + case "lgtd" -> "t.LGTD"; + case "lttd" -> "t.LTTD"; + case "avq" -> "t.AVQ"; + case "ttpwr" -> "t.YRGEB"; + case "normz" -> "t.FSLTDZ"; + case "yrge" -> "t.YRGEB"; + case "baseId" -> "t.BASE_ID"; + case "jcdt" -> "t.JCDT"; + case "addvcdName" -> "t.ADDVCD_NAME"; + case "prsc" -> "t.PRSC"; + case "iconRotate" -> "t.ICON_ROTATE"; + case "bldsttCcode" -> "t.BLDSTT_CODE"; + case "sttp" -> "'ENG'"; + case "sttpCode" -> "'ENG'"; + case "sttpMap" -> "'ENG'"; + case "dtmel" -> "t.DTIN_ENV"; + case "siteStepSort" -> "siteStepSort"; + case "rvcdStepSort" -> "rvcdStepSort"; + case "rstcdStepSort" -> "rstcdStepSort"; + case "baseStepSort" -> "baseStepSort"; + case "ifEngSpecial" -> "ifEngSpecial"; + case "anchoPointState" -> "anchoPointState"; + case "endInstalledType" -> "endInstalledType"; + default -> null; + }; + } + + private String buildEngPointOrderBySql(List sortList) { + if (CollUtil.isEmpty(sortList)) { + return " ORDER BY baseStepSort ASC, rvcdStepSort ASC, rstcdStepSort ASC, siteStepSort ASC, stnm ASC"; + } + List orderItems = new ArrayList<>(); + for (DataSourceRequest.SortDescriptor sortDescriptor : sortList) { + if (sortDescriptor == null || StrUtil.isBlank(sortDescriptor.getField())) { + continue; + } + String column = mapEngPointColumn(sortDescriptor.getField()); + if (StrUtil.isBlank(column)) { + continue; + } + String dir = "desc".equalsIgnoreCase(sortDescriptor.getDir()) || "des".equalsIgnoreCase(sortDescriptor.getDir()) ? "DESC" : "ASC"; + orderItems.add(column + " " + dir); + } + if (orderItems.isEmpty()) { + return " ORDER BY baseStepSort ASC, rvcdStepSort ASC, rstcdStepSort ASC, siteStepSort ASC, stnm ASC"; + } + return " ORDER BY " + String.join(", ", orderItems); + } } 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/SdHycdDicServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdHycdDicServiceImpl.java index 8d2fa828..5a5f3397 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdHycdDicServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_base/service/impl/SdHycdDicServiceImpl.java @@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.yfd.platform.qgc_base.domain.SdHycdDic; import com.yfd.platform.qgc_base.mapper.SdHycdDicMapper; import com.yfd.platform.qgc_base.service.ISdHycdDicService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.util.List; @@ -27,6 +29,7 @@ public class SdHycdDicServiceImpl extends ServiceImpl getByPhycd(String phycd) { return this.lambdaQuery() .eq(SdHycdDic::getPhycd, phycd) @@ -35,6 +38,7 @@ public class SdHycdDicServiceImpl extends ServiceImpl getRootList() { return this.lambdaQuery() .eq(SdHycdDic::getPhycd, "0") @@ -43,21 +47,25 @@ public class SdHycdDicServiceImpl extends ServiceImpl selectForDropdown(String hynm, Integer grd, Integer lx,String phycd) { return this.lambdaQuery() .like(hynm != null && !hynm.isEmpty(), SdHycdDic::getHynm, hynm) @@ -69,6 +77,7 @@ public class SdHycdDicServiceImpl extends ServiceImpl regDropdown(String hynm, Integer grd,Integer lx,String phycd) { return this.lambdaQuery() .like(hynm != null && !hynm.isEmpty(), SdHycdDic::getHynm, hynm) 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_data/service/impl/FishImportServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_data/service/impl/FishImportServiceImpl.java index f9629141..23f1728b 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_data/service/impl/FishImportServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_data/service/impl/FishImportServiceImpl.java @@ -1103,17 +1103,17 @@ public class FishImportServiceImpl implements IFishImportService { return null; } SdFishDictoryB exactMatch = findFirst(fishDictoryBMapper.selectList(new LambdaQueryWrapper() - .select(SdFishDictoryB::getCode, SdFishDictoryB::getName) + .select(SdFishDictoryB::getId, SdFishDictoryB::getName) .eq(SdFishDictoryB::getName, normalizedName))); if (exactMatch != null) { - return exactMatch.getCode(); + return exactMatch.getId(); } SdFishDictoryB fuzzyMatch = findFirst(fishDictoryBMapper.selectList(new LambdaQueryWrapper() - .select(SdFishDictoryB::getCode, SdFishDictoryB::getName) + .select(SdFishDictoryB::getId, SdFishDictoryB::getName) .and(wrapper -> wrapper.like(SdFishDictoryB::getName, normalizedName) .or() .like(SdFishDictoryB::getAlias, normalizedName)))); - return fuzzyMatch == null ? null : fuzzyMatch.getCode(); + return fuzzyMatch == null ? null : fuzzyMatch.getId(); } @Override @@ -1125,11 +1125,11 @@ public class FishImportServiceImpl implements IFishImportService { } if (StringUtils.hasText(normalizedCode)) { SdFishDictoryB exact = findFirst(fishDictoryBMapper.selectList(new LambdaQueryWrapper() - .select(SdFishDictoryB::getCode, SdFishDictoryB::getName) - .eq(SdFishDictoryB::getCode, normalizedCode))); + .select(SdFishDictoryB::getId, SdFishDictoryB::getName) + .eq(SdFishDictoryB::getId, normalizedCode))); // .eq(SdFishDictoryB::getName, normalizedName))); if (exact != null) { - return exact.getCode(); + return exact.getId(); } } // if (StringUtils.hasText(normalizedCode)) { diff --git a/backend/src/main/java/com/yfd/platform/qgc_eng/eq/controller/EngEqDataController.java b/backend/src/main/java/com/yfd/platform/qgc_eng/eq/controller/EngEqDataController.java index 66190642..962d0667 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_eng/eq/controller/EngEqDataController.java +++ b/backend/src/main/java/com/yfd/platform/qgc_eng/eq/controller/EngEqDataController.java @@ -16,11 +16,14 @@ import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqVmsstbprptVo; import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqRateCountVo; import com.yfd.platform.qgc_eng.eq.service.EngEqDataService; import com.yfd.platform.qgc_eng.eq.entity.vo.QgcQecStaticVo; +import com.yfd.platform.qgc_eng.eq.entity.vo.StcdInfoVo; import com.yfd.platform.utils.QgcQueryWrapperUtil; +import cn.hutool.core.util.StrUtil; 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.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -162,4 +165,20 @@ public class EngEqDataController { public ResponseResult getQecRateCount(@RequestBody DataSourceRequest dataSourceRequest) { return ResponseResult.successData(engEqDataService.qecRateCount(dataSourceRequest)); } + + @PostMapping("/operat/default/year") + @Operation(summary = "环保设施点击描点默认展示有数据的年份,不包含过鱼设施描点") + public ResponseResult getDefaultYear(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(engEqDataService.getDefaultYear(dataSourceRequest)); + } + + @GetMapping("/eq/base/msstbprpt/getStInfoByStcd") + @Operation(summary = "根据stcd编码获取所有关联站点的信息") + public ResponseResult getStInfoByStcd(String stcd) { + if (StrUtil.isBlank(stcd)) { + return ResponseResult.error("站点编码(stcd)不能为空"); + } + StcdInfoVo result = engEqDataService.getStInfoByStcd(stcd); + return ResponseResult.successData(result); + } } diff --git a/backend/src/main/java/com/yfd/platform/qgc_eng/eq/entity/vo/StBaseInfo.java b/backend/src/main/java/com/yfd/platform/qgc_eng/eq/entity/vo/StBaseInfo.java new file mode 100644 index 00000000..dbb6c429 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_eng/eq/entity/vo/StBaseInfo.java @@ -0,0 +1,31 @@ +package com.yfd.platform.qgc_eng.eq.entity.vo; + +import lombok.Data; + +@Data +public class StBaseInfo { + + private String stcd; + + private String stnm; + + private String sttpCode; + + private String sttpName; + + private String sttpFullPath; + + private Integer sttpTreeLevel; + + private String baseId; + + private String baseName; + + private String hbrvcd; + + private String hbrvcdName; + + private String rvcd; + + private String rvcdName; +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_eng/eq/entity/vo/StcdInfoVo.java b/backend/src/main/java/com/yfd/platform/qgc_eng/eq/entity/vo/StcdInfoVo.java new file mode 100644 index 00000000..c7244eaa --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_eng/eq/entity/vo/StcdInfoVo.java @@ -0,0 +1,13 @@ +package com.yfd.platform.qgc_eng.eq.entity.vo; + +import lombok.Data; + +import java.util.List; + +@Data +public class StcdInfoVo { + + private StBaseInfo stBaseInfo; + + private List relList; +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_eng/eq/service/EngEqDataService.java b/backend/src/main/java/com/yfd/platform/qgc_eng/eq/service/EngEqDataService.java index 7f0a0bf8..f2fbf60c 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_eng/eq/service/EngEqDataService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_eng/eq/service/EngEqDataService.java @@ -18,6 +18,8 @@ import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqRateCountVo; import com.yfd.platform.qgc_eng.eq.entity.vo.EngEqVmsstbprptVo; import com.yfd.platform.qgc_eng.eq.entity.vo.QgcQecStaticVo; import com.yfd.platform.qgc_eng.eq.entity.vo.SdEqMonitorCountVo; +import com.yfd.platform.qgc_eng.eq.entity.vo.StBaseInfo; +import com.yfd.platform.qgc_eng.eq.entity.vo.StcdInfoVo; import com.yfd.platform.qgc_eng.eq.entity.vo.WbsbVo; import java.util.List; @@ -59,4 +61,8 @@ public interface EngEqDataService { DataSourceResult getEvnmAutoMonitorList(DataSourceRequest dataSourceRequest); DataSourceResult qecRateCount(DataSourceRequest dataSourceRequest); + + DataSourceResult getDefaultYear(DataSourceRequest dataSourceRequest); + + StcdInfoVo getStInfoByStcd(String stcd); } 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..ce231794 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 @@ -33,6 +33,8 @@ import com.yfd.platform.qgc_eng.eq.entity.vo.QgcQecStaticVo; import com.yfd.platform.qgc_eng.eq.entity.vo.QgcQecVo; import com.yfd.platform.qgc_eng.eq.entity.vo.SdEqMonitorCountVo; import com.yfd.platform.qgc_eng.eq.entity.vo.WbsbVo; +import com.yfd.platform.qgc_eng.eq.entity.vo.StBaseInfo; +import com.yfd.platform.qgc_eng.eq.entity.vo.StcdInfoVo; import com.yfd.platform.qgc_eng.eq.service.EngEqDataService; import com.yfd.platform.utils.QgcQueryWrapperUtil; import jakarta.annotation.Resource; @@ -1131,6 +1133,44 @@ public class EngEqDataServiceImpl implements EngEqDataService { return result; } + @Override + public StcdInfoVo getStInfoByStcd(String stcd) { + if (StrUtil.isBlank(stcd)) { + throw new IllegalArgumentException("站点编码(stcd)不能为空"); + } + StcdInfoVo vo = new StcdInfoVo(); + Map paramMap = new HashMap<>(); + paramMap.put("stcd", stcd); + + StBaseInfo stBaseInfo = (StBaseInfo)microservicDynamicSQLMapper.getOneBySqlWithResultType( + "SELECT STCD AS stcd, STNM AS stnm, STTP_CODE AS sttpCode, STTP_NAME AS sttpName, " + + "STTP_FULL_PATH AS sttpFullPath, STTP_TREE_LEVEL AS sttpTreeLevel, " + + "BASE_ID AS baseId, BASE_NAME AS baseName, HBRVCD AS hbrvcd, " + + "HBRVCD_NAME AS hbrvcdName, RVCD AS rvcd, RVCD_NAME AS rvcdName " + + "FROM V_MS_STBPRP_T " + + "WHERE STCD = #{map.stcd} AND NVL(IS_DELETED, 0) = 0", + paramMap, + StBaseInfo.class + ); + vo.setStBaseInfo(stBaseInfo); + + List relList = microservicDynamicSQLMapper.getAllListWithResultType( + "SELECT STCD AS stcd, STNM AS stnm, STTP_CODE AS sttpCode, STTP_NAME AS sttpName, " + + "STTP_FULL_PATH AS sttpFullPath, STTP_TREE_LEVEL AS sttpTreeLevel, " + + "BASE_ID AS baseId, BASE_NAME AS baseName, HBRVCD AS hbrvcd, " + + "HBRVCD_NAME AS hbrvcdName, RVCD AS rvcd, RVCD_NAME AS rvcdName " + + "FROM V_MS_STBPRP_T " + + "WHERE NVL(IS_DELETED, 0) = 0 " + + "AND STCD != #{map.stcd} " + + "AND STTP_FULL_PATH LIKE CONCAT(CONCAT('%', #{map.stcd}), '%')", + paramMap, + StBaseInfo.class + ); + vo.setRelList(relList); + + return vo; + } + @Override public DataSourceResult qecRateCount(DataSourceRequest dataSourceRequest) { DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); @@ -3327,6 +3367,7 @@ public class EngEqDataServiceImpl implements EngEqDataService { "'ENG' AS sttpCode, " + "'电站' AS sttpName, " + "eng.STCD AS stcd, " + + "pbh.TTPWR AS ttpwr, " + "eng.ENNM AS stnm, " + "eng.ENNM AS ennm, " + "eng.BASE_ID AS baseId, " + @@ -3346,6 +3387,7 @@ public class EngEqDataServiceImpl implements EngEqDataService { "NVL(eng.ORDER_INDEX, 999999) AS rstcdStepSort, " + "NVL(eng.ORDER_INDEX, 999999) AS siteStepSort " + "FROM SD_ENGINFO_B_H eng " + + "INNER JOIN SD_PWR_B_H pbh ON pbh.STCD= eng.STCD " + "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 " + @@ -5440,6 +5482,7 @@ public class EngEqDataServiceImpl implements EngEqDataService { case "sttpCode" -> "t.sttpCode"; case "sttpName" -> "t.sttpName"; case "stcd" -> "t.stcd"; + case "ttpwr" -> "t.ttpwr"; case "stnm" -> "t.stnm"; case "ennm" -> "t.ennm"; case "baseId" -> "t.baseId"; @@ -5746,7 +5789,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"; @@ -5801,4 +5845,48 @@ public class EngEqDataServiceImpl implements EngEqDataService { default -> null; }; } + + @Override + public DataSourceResult getDefaultYear(DataSourceRequest dataSourceRequest) { + DataSourceResult dataSourceResult = new DataSourceResult<>(); + List resultList = new ArrayList<>(); + dataSourceResult.setData(resultList); + dataSourceResult.setTotal(resultList.size()); + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + String stcd = loadOptions == null ? null : QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "stcd"); + String sttpCode = loadOptions == null ? null : QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "sttpCode"); + if (StrUtil.isBlank(stcd) || StrUtil.isBlank(sttpCode)) { + return dataSourceResult; + } + + Map paramMap = new HashMap<>(); + paramMap.put("stcd", stcd); + + String sql = switch (sttpCode) { + case "DW" -> "SELECT MAX(TM) AS TM FROM SD_DW_R WHERE STCD = #{map.stcd} AND NVL(IS_DELETED, 0) = 0"; + case "EQ" -> "SELECT MAX(TM) AS TM FROM SD_EQ_R WHERE STCD = #{map.stcd} AND NVL(IS_DELETED, 0) = 0"; + case "FB" -> "SELECT MAX(TM) AS TM FROM SD_ENGFR_R WHERE STCD = #{map.stcd} AND NVL(IS_DELETED, 0) = 0"; + case "VA" -> "SELECT MAX(TM) AS TM FROM SD_VA_R WHERE STCD = #{map.stcd} AND NVL(IS_DELETED, 0) = 0"; + case "VP" -> "SELECT MAX(TM) AS TM FROM SD_VP_R WHERE STCD = #{map.stcd} AND NVL(IS_DELETED, 0) = 0"; + default -> ""; + }; + + if (StrUtil.isBlank(sql)) { + return dataSourceResult; + } + + List> allList = microservicDynamicSQLMapper.getAllList(sql, paramMap); + if (CollUtil.isEmpty(allList)) { + return dataSourceResult; + } + Map map = allList.get(0); + if (map == null) { + return dataSourceResult; + } + Object tm = map.getOrDefault("TM", ""); + if (tm != null && StrUtil.isNotBlank(tm.toString())) { + resultList.add(tm.toString()); + } + return dataSourceResult; + } } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fb/controller/FbStationController.java b/backend/src/main/java/com/yfd/platform/qgc_env/fb/controller/FbStationController.java index 9d05bd9f..7fa6c42f 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/fb/controller/FbStationController.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fb/controller/FbStationController.java @@ -132,4 +132,18 @@ public class FbStationController { public ResponseResult getResearchKendoList(@RequestBody DataSourceRequest dataSourceRequest) { return ResponseResult.successData(fbStationService.getResearchKendoList(dataSourceRequest)); } + + @PostMapping("/fishhatchrecr/fish/GetKendoListCust") + @Operation(summary = "(全过程)增殖站二级页面: 过程图-产卵和孵化") + public ResponseResult getFishhatchrecrFishKendoListCust( + @Parameter(description = "类型:1-鱼卵数量,2-出苗数量") @RequestParam("type") Integer type, + @RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(fbStationService.getFishhatchrecrFishKendoListCust(type, dataSourceRequest)); + } + + @PostMapping("/fishbreedr/fish/GetKendoListCust") + @Operation(summary = "(全过程)增殖站二级页面: 过程图-鱼苗") + public ResponseResult getFishbreedrFishKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(fbStationService.getFishbreedrFishKendoListCust(dataSourceRequest)); + } } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fb/entity/vo/FishbreedRVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/fb/entity/vo/FishbreedRVo.java new file mode 100644 index 00000000..1d184777 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fb/entity/vo/FishbreedRVo.java @@ -0,0 +1,15 @@ +package com.yfd.platform.qgc_env.fb.entity.vo; + +import lombok.Data; + +@Data +public class FishbreedRVo { + + private String tm; + + private String ftp; + + private String ftpName; + + private String counts; +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fb/entity/vo/FishhatchrecRVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/fb/entity/vo/FishhatchrecRVo.java new file mode 100644 index 00000000..9e767b51 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fb/entity/vo/FishhatchrecRVo.java @@ -0,0 +1,17 @@ +package com.yfd.platform.qgc_env.fb.entity.vo; + +import lombok.Data; + +@Data +public class FishhatchrecRVo { + + private String tm; + + private String ftp; + + private String ftpName; + + private String eggcount; + + private String outcount; +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fb/entity/vo/HeadColunmsVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/fb/entity/vo/HeadColunmsVo.java new file mode 100644 index 00000000..9093d280 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fb/entity/vo/HeadColunmsVo.java @@ -0,0 +1,52 @@ +package com.yfd.platform.qgc_env.fb.entity.vo; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class HeadColunmsVo { + + private String dataIndex; + + private String title; + + private Boolean visible = true; + + private String key; + + private String unit; + + private boolean merge; + + private String dataType; + + private String dataFormat; + + private List children; + + public HeadColunmsVo(String title, String dataIndex) { + this.title = title; + this.dataIndex = dataIndex; + } + + public HeadColunmsVo(String dataIndex, String title, Boolean visible, String key, boolean merge, List children) { + this.dataIndex = dataIndex; + this.title = title; + this.visible = visible; + this.key = key; + this.merge = merge; + this.children = children; + } + + public HeadColunmsVo setDataType(String dataType) { + this.dataType = dataType; + return this; + } + + public HeadColunmsVo setDataFormat(String dataFormat) { + this.dataFormat = dataFormat; + return this; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fb/entity/vo/TableVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/fb/entity/vo/TableVo.java new file mode 100644 index 00000000..5bd4141b --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fb/entity/vo/TableVo.java @@ -0,0 +1,27 @@ +package com.yfd.platform.qgc_env.fb.entity.vo; + +import lombok.Data; + +import java.util.List; + +@Data +public class TableVo { + + private List columns; + + private Object dataSource; + + private Long total; + + private Integer wtDeviceType; + + public TableVo() { + } + + public TableVo(List dataSource, Long total) { + this.dataSource = dataSource; + if (total != null) { + this.total = total; + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/FbStationService.java b/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/FbStationService.java index 1bada486..77cd39aa 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/FbStationService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/FbStationService.java @@ -16,6 +16,7 @@ import com.yfd.platform.qgc_env.fb.entity.vo.FbStInfoResultVo; import com.yfd.platform.qgc_env.fb.entity.vo.FbStationStaticsDataVo; import com.yfd.platform.qgc_env.fb.entity.vo.YearRpStatisticsVo; import com.yfd.platform.qgc_env.fb.entity.vo.FbStationOverviewSecondVo; +import com.yfd.platform.qgc_env.fb.entity.vo.TableVo; import java.util.List; import java.util.Map; @@ -57,4 +58,8 @@ public interface FbStationService { DataSourceResult getOverviewSecond(DataSourceRequest dataSourceRequest); DataSourceResult getQgcOverviewSecond(DataSourceRequest dataSourceRequest); + + DataSourceResult getFishhatchrecrFishKendoListCust(Integer type, DataSourceRequest dataSourceRequest); + + DataSourceResult getFishbreedrFishKendoListCust(DataSourceRequest dataSourceRequest); } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/impl/FbStationServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/impl/FbStationServiceImpl.java index a3e50842..d3df7885 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/impl/FbStationServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/fb/service/impl/FbStationServiceImpl.java @@ -30,6 +30,10 @@ import com.yfd.platform.qgc_env.fb.entity.vo.FbStInfoResultVo; import com.yfd.platform.qgc_env.fb.entity.vo.FbStationOverviewSecondVo; import com.yfd.platform.qgc_env.fb.entity.vo.FbStationStaticsDataVo; import com.yfd.platform.qgc_env.fb.entity.vo.FbStationStaticsRawVo; +import com.yfd.platform.qgc_env.fb.entity.vo.FishbreedRVo; +import com.yfd.platform.qgc_env.fb.entity.vo.FishhatchrecRVo; +import com.yfd.platform.qgc_env.fb.entity.vo.HeadColunmsVo; +import com.yfd.platform.qgc_env.fb.entity.vo.TableVo; import com.yfd.platform.qgc_env.fb.entity.vo.YearRpStatisticsVo; import com.yfd.platform.qgc_env.fb.service.FbStationService; import com.yfd.platform.utils.QgcQueryWrapperUtil; @@ -4103,4 +4107,469 @@ public class FbStationServiceImpl implements FbStationService { } values.add(text); } + + @Override + public DataSourceResult getFishhatchrecrFishKendoListCust(Integer type, DataSourceRequest dataSourceRequest) { + DataSourceResult dataSourceResult = new DataSourceResult<>(); + String unit = type == 1 ? "(万粒)" : "(万尾)"; + + Map paramMap = new HashMap<>(); + StringBuilder sql = new StringBuilder(); + sql.append("SELECT tm, ") + .append("LISTAGG(TO_CHAR(ftp), ',') WITHIN GROUP (ORDER BY ftp) AS ftp, ") + .append("LISTAGG(TO_CHAR(NAME), ',') WITHIN GROUP (ORDER BY ftp) AS ftpName, ") + .append("LISTAGG(eggcount, ',') WITHIN GROUP (ORDER BY ftp) AS eggcount, ") + .append("LISTAGG(outcount, ',') WITHIN GROUP (ORDER BY ftp) AS outcount ") + .append("FROM (") + .append("SELECT ") + .append("TO_CHAR(tm, 'YYYY-MM') AS tm, ftp, ") + .append("CASE WHEN NAME IS NULL THEN TO_NCHAR(ftp) ELSE NAME END AS NAME, ") + .append("CASE WHEN SUM(eggcount) IS NULL THEN '-' ELSE RTRIM(TO_CHAR(SUM(eggcount), 'FM999999999999990.99'), '.') END AS eggcount, ") + .append("CASE WHEN SUM(outcount) IS NULL THEN '-' ELSE RTRIM(TO_CHAR(SUM(outcount), 'FM999999999999990.99'), '.') END AS outcount ") + .append("FROM (") + .append("SELECT ") + .append("t.tm, ") + .append("CASE WHEN fishViewZy.ZY_FISH_ID IS NULL THEN t.ftp ELSE fishViewZy.ZY_FISH_ID END AS ftp, ") + .append("CASE WHEN fishViewZy.NAME IS NULL THEN fishViewRv.NAME ELSE fishViewZy.NAME END AS NAME, ") + .append("t.eggcount, ") + .append("t.outcount ") + .append("FROM SD_FBFISHHATCHREC_R t ") + .append("LEFT JOIN SD_FBRD_B_H fb ON t.stcd = fb.STCD ") + .append("LEFT JOIN V_SD_FISHDICTORY_B fishViewRv ON t.FTP = fishViewRv.FISH_ID AND fb.HBRVCD = fishViewRv.RVCD ") + .append("LEFT JOIN V_SD_FISHDICTORY_B fishViewZy ON t.FTP = fishViewZy.FISH_ID AND fishViewZy.RVCD = 'ZY' ") + .append("WHERE NVL(t.IS_DELETED, 0) = 0 "); + + appendFishhatchrecrFishFilterConditions(sql, dataSourceRequest, paramMap); + + sql.append(") GROUP BY TO_CHAR(tm, 'YYYY-MM'), ftp, NAME ") + .append(") GROUP BY tm ") + .append("ORDER BY tm DESC "); + + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + Page page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + List list = microservicDynamicSQLMapper.pageAllListWithResultType( + page, sql.toString(), paramMap, FishhatchrecRVo.class + ); + + long total = page != null ? page.getTotal() : list.size(); + TableVo tableVo = buildFishhatchrecrFishTableVo(list, total, type, unit); + dataSourceResult.setData(Collections.singletonList(tableVo)); + dataSourceResult.setTotal(total); + dataSourceResult.setAggregates(new HashMap<>()); + return dataSourceResult; + } + + private void appendFishhatchrecrFishFilterConditions(StringBuilder sql, + DataSourceRequest dataSourceRequest, + Map paramMap) { + if (dataSourceRequest == null || dataSourceRequest.getFilter() == null) { + return; + } + String filterSql = buildFishhatchrecrFishFilterCondition(dataSourceRequest.getFilter(), paramMap, new int[]{0}); + if (StrUtil.isNotBlank(filterSql)) { + sql.append(" AND ").append(filterSql).append(" "); + } + } + + private String buildFishhatchrecrFishFilterCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + if (filter == null) { + return ""; + } + if (StrUtil.isNotBlank(filter.getField())) { + return buildFishhatchrecrFishLeafCondition(filter, paramMap, indexHolder); + } + if (CollUtil.isEmpty(filter.getFilters())) { + return ""; + } + List conditions = new ArrayList<>(); + for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) { + String childSql = buildFishhatchrecrFishFilterCondition(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 buildFishhatchrecrFishLeafCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + String field = filter.getField(); + String column = mapFishhatchrecrFishColumn(field); + 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 ("in".equals(operator)) { + List values = normalizeQgcBsmfRValues(value); + if (values.isEmpty()) { + return ""; + } + List placeholders = new ArrayList<>(); + for (Object item : values) { + String key = "hatchFishP" + indexHolder[0]++; + paramMap.put(key, item); + placeholders.add("#{map." + key + "}"); + } + return column + " IN (" + String.join(", ", placeholders) + ")"; + } + if (value == null) { + return ""; + } + String key = "hatchFishP" + indexHolder[0]++; + Object normalizedValue = normalizeFishhatchrecrFishValue(field, value); + return switch (operator) { + case "eq" -> { + paramMap.put(key, normalizedValue); + yield column + " = #{map." + key + "}"; + } + case "neq" -> { + paramMap.put(key, normalizedValue); + yield column + " <> #{map." + key + "}"; + } + case "contains" -> { + paramMap.put(key, "%" + normalizedValue + "%"); + yield column + " LIKE #{map." + key + "}"; + } + case "startswith" -> { + paramMap.put(key, normalizedValue + "%"); + yield column + " LIKE #{map." + key + "}"; + } + case "endswith" -> { + paramMap.put(key, "%" + normalizedValue); + yield column + " LIKE #{map." + key + "}"; + } + case "gt" -> { + paramMap.put(key, normalizedValue); + yield column + " > #{map." + key + "}"; + } + case "gte" -> { + paramMap.put(key, normalizedValue); + yield column + " >= #{map." + key + "}"; + } + case "lt" -> { + paramMap.put(key, normalizedValue); + yield column + " < #{map." + key + "}"; + } + case "lte" -> { + paramMap.put(key, normalizedValue); + yield column + " <= #{map." + key + "}"; + } + default -> ""; + }; + } + + private String mapFishhatchrecrFishColumn(String field) { + return switch (field) { + case "stcd" -> "t.STCD"; + case "ftp" -> "t.FTP"; + case "fishsrc" -> "t.FISHSRC"; + case "tm" -> "t.TM"; + case "rstcd" -> "fb.RSTCD"; + case "baseId" -> "fb.BASE_ID"; + case "hbrvcd" -> "fb.HBRVCD"; + default -> ""; + }; + } + + private Object normalizeFishhatchrecrFishValue(String field, Object value) { + if (value == null) { + return null; + } + if ("tm".equalsIgnoreCase(field) && value instanceof String text) { + return parseDateTimeSafely(text); + } + return value; + } + + private TableVo buildFishhatchrecrFishTableVo(List list, long total, Integer type, String unit) { + TableVo tableVo = new TableVo(); + List> resultData = new ArrayList<>(); + List columns = new ArrayList<>(); + Map fishMap = new LinkedHashMap<>(); + + if (CollUtil.isNotEmpty(list)) { + for (FishhatchrecRVo vo : list) { + Map rowMap = new LinkedHashMap<>(); + rowMap.put("tm", vo.getTm()); + + List ftpList = splitCsv(vo.getFtp()); + List ftpNameList = splitCsv(vo.getFtpName()); + List eggCountList = splitCsv(vo.getEggcount()); + List outCountList = splitCsv(vo.getOutcount()); + + int size = Math.min(ftpList.size(), Math.min(ftpNameList.size(), + Math.min(eggCountList.size(), outCountList.size()))); + + for (int i = 0; i < size; i++) { + String ftp = ftpList.get(i); + String ftpName = ftpNameList.get(i); + String value = type == 1 ? eggCountList.get(i) : outCountList.get(i); + rowMap.put(ftp, "-".equals(value) ? null : value); + fishMap.putIfAbsent(ftp, ftpName); + } + resultData.add(rowMap); + } + } + + columns.add(new HeadColunmsVo("tm", "时间", true, "tm", false, new ArrayList<>()) + .setDataType("date") + .setDataFormat("yyyy-MM")); + for (Map.Entry entry : fishMap.entrySet()) { + columns.add(new HeadColunmsVo(entry.getKey(), entry.getValue() + unit, true, entry.getKey(), false, new ArrayList<>())); + } + + tableVo.setColumns(columns); + tableVo.setDataSource(resultData); + tableVo.setTotal(total); + return tableVo; + } + + @Override + public DataSourceResult getFishbreedrFishKendoListCust(DataSourceRequest dataSourceRequest) { + DataSourceResult dataSourceResult = new DataSourceResult<>(); + + Map paramMap = new HashMap<>(); + StringBuilder sql = new StringBuilder(); + sql.append("SELECT tm,\n") + .append("LISTAGG(TO_CHAR(ftp), ',') WITHIN GROUP (ORDER BY ftp) AS ftp,\n") + .append("LISTAGG(TO_CHAR(NAME), ',') WITHIN GROUP (ORDER BY ftp) AS ftpName,\n") + .append("LISTAGG(counts, ',') WITHIN GROUP (ORDER BY ftp) AS counts\n") + .append("FROM (\n") + .append("SELECT \n") + .append("to_CHAR(tm,'YYYY-MM') AS tm, ftp, CASE WHEN NAME IS NULL THEN TO_NCHAR(ftp) ELSE NAME END AS NAME, CASE WHEN SUM(counts) IS NULL THEN '-' ELSE TO_CHAR(SUM(counts)) END AS counts\n") + .append("FROM (\n") + .append("SELECT\n") + .append("\tt.tm,\n") + .append("\tCASE WHEN f.ZY_FISH_ID IS NULL THEN t.ftp ELSE f.ZY_FISH_ID END AS ftp,\n") + .append("\tCASE WHEN f.NAME IS NULL THEN TO_NCHAR(t.ftp) ELSE f.NAME END AS NAME,\n") + .append("\tt.counts\n") + .append("FROM\n") + .append("\t(\n") + .append("\tSELECT\n") + .append("\t\tstcd,\n") + .append("\t\tftp AS ftp,\n") + .append("\t\tcounts AS counts,\n") + .append("\t\ttm AS tm\n") + .append("\tFROM\n") + .append("\t\tSD_FBFISHBREED_R\n") + .append("\tWHERE\n") + .append("\t\tNVL(is_deleted, 0) = 0 "); + + appendFishbreedrFishFilterConditions(sql, dataSourceRequest, paramMap); + + sql.append(") t\n") + .append("LEFT JOIN SD_FBRD_B_H s ON\n") + .append("\tt.stcd = s.STCD\n") + .append("LEFT JOIN V_SD_FISHDICTORY_B f ON\n") + .append("\tt.FTP = f.FISH_ID\n") + .append("\tAND (s.HBRVCD = f.RVCD\n") + .append("\t\tOR f.RVCD = 'ZY')\n") + .append(") GROUP BY to_CHAR(tm,'YYYY-MM'), ftp, NAME\n") + .append(") GROUP BY tm\n") + .append("ORDER BY TM DESC"); + + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + Page page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + List list = microservicDynamicSQLMapper.pageAllListWithResultType( + page, sql.toString(), paramMap, FishbreedRVo.class + ); + + long total = page != null ? page.getTotal() : list.size(); + TableVo tableVo = buildFishbreedrFishTableVo(list, total); + dataSourceResult.setData(Collections.singletonList(tableVo)); + dataSourceResult.setTotal(total); + dataSourceResult.setAggregates(new HashMap<>()); + return dataSourceResult; + } + + private void appendFishbreedrFishFilterConditions(StringBuilder sql, + DataSourceRequest dataSourceRequest, + Map paramMap) { + if (dataSourceRequest == null || dataSourceRequest.getFilter() == null) { + return; + } + String filterSql = buildFishbreedrFishFilterCondition(dataSourceRequest.getFilter(), paramMap, new int[]{0}); + if (StrUtil.isNotBlank(filterSql)) { + sql.append(" AND ").append(filterSql).append(" "); + } + } + + private String buildFishbreedrFishFilterCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + if (filter == null) { + return ""; + } + if (StrUtil.isNotBlank(filter.getField())) { + return buildFishbreedrFishLeafCondition(filter, paramMap, indexHolder); + } + if (CollUtil.isEmpty(filter.getFilters())) { + return ""; + } + List conditions = new ArrayList<>(); + for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) { + String childSql = buildFishbreedrFishFilterCondition(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 buildFishbreedrFishLeafCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + String field = filter.getField(); + String column = mapFishbreedrFishColumn(field); + 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 ("in".equals(operator)) { + List values = normalizeQgcBsmfRValues(value); + if (values.isEmpty()) { + return ""; + } + List placeholders = new ArrayList<>(); + for (Object item : values) { + String key = "breedFishP" + indexHolder[0]++; + paramMap.put(key, item); + placeholders.add("#{map." + key + "}"); + } + return column + " IN (" + String.join(", ", placeholders) + ")"; + } + if (value == null) { + return ""; + } + String key = "breedFishP" + indexHolder[0]++; + Object normalizedValue = normalizeFishbreedrFishValue(field, value); + return switch (operator) { + case "eq" -> { + paramMap.put(key, normalizedValue); + yield column + " = #{map." + key + "}"; + } + case "neq" -> { + paramMap.put(key, normalizedValue); + yield column + " <> #{map." + key + "}"; + } + case "contains" -> { + paramMap.put(key, "%" + normalizedValue + "%"); + yield column + " LIKE #{map." + key + "}"; + } + case "startswith" -> { + paramMap.put(key, normalizedValue + "%"); + yield column + " LIKE #{map." + key + "}"; + } + case "endswith" -> { + paramMap.put(key, "%" + normalizedValue); + yield column + " LIKE #{map." + key + "}"; + } + case "gt" -> { + paramMap.put(key, normalizedValue); + yield column + " > #{map." + key + "}"; + } + case "gte" -> { + paramMap.put(key, normalizedValue); + yield column + " >= #{map." + key + "}"; + } + case "lt" -> { + paramMap.put(key, normalizedValue); + yield column + " < #{map." + key + "}"; + } + case "lte" -> { + paramMap.put(key, normalizedValue); + yield column + " <= #{map." + key + "}"; + } + default -> ""; + }; + } + + private String mapFishbreedrFishColumn(String field) { + return switch (field) { + case "stcd" -> "STCD"; + case "ftp" -> "t.FTP"; + case "counts" -> "t.COUNTS"; + case "tm" -> "TM"; + case "rstcd" -> "s.RSTCD"; + case "baseId" -> "s.BASE_ID"; + case "hbrvcd" -> "s.HBRVCD"; + default -> ""; + }; + } + + private Object normalizeFishbreedrFishValue(String field, Object value) { + if (value == null) { + return null; + } + if ("tm".equalsIgnoreCase(field) && value instanceof String text) { + return parseDateTimeSafely(text); + } + return value; + } + + private TableVo buildFishbreedrFishTableVo(List list, long total) { + TableVo tableVo = new TableVo(); + List> resultData = new ArrayList<>(); + List columns = new ArrayList<>(); + Map fishMap = new LinkedHashMap<>(); + + if (CollUtil.isNotEmpty(list)) { + for (FishbreedRVo vo : list) { + Map rowMap = new LinkedHashMap<>(); + rowMap.put("tm", vo.getTm()); + + List ftpList = splitCsv(vo.getFtp()); + List ftpNameList = splitCsv(vo.getFtpName()); + List countsList = splitCsv(vo.getCounts()); + + int size = Math.min(ftpList.size(), Math.min(ftpNameList.size(), countsList.size())); + + for (int i = 0; i < size; i++) { + String ftp = ftpList.get(i); + String ftpName = ftpNameList.get(i); + String countStr = countsList.get(i); + rowMap.put(ftp, "-".equals(countStr) ? null : countStr); + fishMap.putIfAbsent(ftp, ftpName); + } + resultData.add(rowMap); + } + } + + columns.add(new HeadColunmsVo("tm", "时间", true, "tm", false, new ArrayList<>()) + .setDataType("date") + .setDataFormat("yyyy-MM")); + for (Map.Entry entry : fishMap.entrySet()) { + columns.add(new HeadColunmsVo(entry.getKey(), entry.getValue() + "(尾)", true, entry.getKey(), false, new ArrayList<>())); + } + + tableVo.setColumns(columns); + tableVo.setDataSource(resultData); + tableVo.setTotal(total); + return tableVo; + } } 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/vap/controller/VapConstructionController.java b/backend/src/main/java/com/yfd/platform/qgc_env/vap/controller/VapConstructionController.java index ffa9a01e..ef34b630 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/vap/controller/VapConstructionController.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/vap/controller/VapConstructionController.java @@ -64,4 +64,16 @@ public class VapConstructionController { public ResponseResult getVarKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { return ResponseResult.successData(vpConstructionService.processVarKendoList(dataSourceRequest)); } + + @PostMapping("/var/year/GetKendoListCust") + @Operation(summary = "动物救助站数据年份列表") + public ResponseResult getVarYearKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(vpConstructionService.getVarYearList(dataSourceRequest)); + } + + @PostMapping("/vpr/year/GetKendoListCust") + @Operation(summary = "珍稀植物园数据年份列表") + public ResponseResult getVprYearKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(vpConstructionService.getVprYearList(dataSourceRequest)); + } } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/vap/service/VpConstructionService.java b/backend/src/main/java/com/yfd/platform/qgc_env/vap/service/VpConstructionService.java index 28de636f..0a362f81 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/vap/service/VpConstructionService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/vap/service/VpConstructionService.java @@ -23,4 +23,8 @@ public interface VpConstructionService { DataSourceResult processVacKendoList(DataSourceRequest dataSourceRequest); DataSourceResult processVarKendoList(DataSourceRequest dataSourceRequest); + + DataSourceResult getVarYearList(DataSourceRequest dataSourceRequest); + + DataSourceResult getVprYearList(DataSourceRequest dataSourceRequest); } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/vap/service/impl/VpConstructionServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/vap/service/impl/VpConstructionServiceImpl.java index fe46774a..e0bc4ccf 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/vap/service/impl/VpConstructionServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/vap/service/impl/VpConstructionServiceImpl.java @@ -1814,4 +1814,98 @@ public class VpConstructionServiceImpl implements VpConstructionService { } return " ORDER BY " + String.join(", ", orderItems); } + + @Override + public DataSourceResult getVarYearList(DataSourceRequest dataSourceRequest) { + DataSourceResult dataSourceResult = new DataSourceResult<>(); + DataSourceLoadOptionsBase loadOptionsBase = dataSourceRequest.toDevRequest(); + String baseId = QgcQueryWrapperUtil.getFilterFieldValue(loadOptionsBase, "baseId"); + String stcd = QgcQueryWrapperUtil.getFilterFieldValue(loadOptionsBase, "stcd"); + String rstcd = QgcQueryWrapperUtil.getFilterFieldValue(loadOptionsBase, "rstcd"); + + StringBuilder sql = new StringBuilder("SELECT TO_CHAR(r.TM, 'YYYY') year FROM SD_VA_R r " + + "LEFT JOIN SD_VABASIC_B svb ON r.TETP = svb.ID " + + "LEFT JOIN SD_VA_B_H a ON a.STCD = r.STCD WHERE NVL(r.IS_DELETED, 0) = 0 "); + + if (StrUtil.isNotBlank(baseId)) { + sql.append(" AND a.BASE_ID = #{map.baseId} "); + } + if (StrUtil.isNotBlank(stcd)) { + sql.append(" AND a.STCD = #{map.stcd} "); + } + if (StrUtil.isNotBlank(rstcd)) { + sql.append(" AND a.RSTCD = #{map.rstcd} "); + } + sql.append(" GROUP BY TO_CHAR(r.TM, 'YYYY') ORDER BY TO_CHAR(r.TM, 'YYYY') DESC "); + + Map paramMap = new HashMap<>(); + if (StrUtil.isNotBlank(baseId)) { + paramMap.put("baseId", baseId); + } + if (StrUtil.isNotBlank(stcd)) { + paramMap.put("stcd", stcd); + } + if (StrUtil.isNotBlank(rstcd)) { + paramMap.put("rstcd", rstcd); + } + + Page page = KendoUtil.getPage(dataSourceRequest); + List> list = microservicDynamicSQLMapper.pageAllList(page, sql.toString(), paramMap); + List yList = new ArrayList<>(); + for (Map it : list) { + if (it.get("YEAR") != null && StrUtil.isNotBlank(it.get("YEAR").toString())) { + yList.add(it.get("YEAR").toString()); + } + } + dataSourceResult.setData(yList); + dataSourceResult.setTotal(page != null ? page.getTotal() : (long) yList.size()); + return dataSourceResult; + } + + @Override + public DataSourceResult getVprYearList(DataSourceRequest dataSourceRequest) { + DataSourceResult dataSourceResult = new DataSourceResult<>(); + DataSourceLoadOptionsBase loadOptionsBase = dataSourceRequest.toDevRequest(); + String baseId = QgcQueryWrapperUtil.getFilterFieldValue(loadOptionsBase, "baseId"); + String stcd = QgcQueryWrapperUtil.getFilterFieldValue(loadOptionsBase, "stcd"); + String rstcd = QgcQueryWrapperUtil.getFilterFieldValue(loadOptionsBase, "rstcd"); + + StringBuilder sql = new StringBuilder("SELECT TO_CHAR(r.TM, 'YYYY') year FROM SD_VP_R r " + + "LEFT JOIN SD_VPBASIC_B svb ON r.PLANT_ID = svb.ID " + + "LEFT JOIN SD_VP_B_H a ON a.STCD = r.STCD WHERE NVL(r.IS_DELETED, 0) = 0 "); + + if (StrUtil.isNotBlank(baseId)) { + sql.append(" AND a.BASE_ID = #{map.baseId} "); + } + if (StrUtil.isNotBlank(stcd)) { + sql.append(" AND a.STCD = #{map.stcd} "); + } + if (StrUtil.isNotBlank(rstcd)) { + sql.append(" AND a.RSTCD = #{map.rstcd} "); + } + sql.append(" GROUP BY TO_CHAR(r.TM, 'YYYY') ORDER BY TO_CHAR(r.TM, 'YYYY') DESC "); + + Map paramMap = new HashMap<>(); + if (StrUtil.isNotBlank(baseId)) { + paramMap.put("baseId", baseId); + } + if (StrUtil.isNotBlank(stcd)) { + paramMap.put("stcd", stcd); + } + if (StrUtil.isNotBlank(rstcd)) { + paramMap.put("rstcd", rstcd); + } + + Page page = KendoUtil.getPage(dataSourceRequest); + List> list = microservicDynamicSQLMapper.pageAllList(page, sql.toString(), paramMap); + List yList = new ArrayList<>(); + for (Map it : list) { + if (it.get("YEAR") != null && StrUtil.isNotBlank(it.get("YEAR").toString())) { + yList.add(it.get("YEAR").toString()); + } + } + dataSourceResult.setData(yList); + dataSourceResult.setTotal(page != null ? page.getTotal() : (long) yList.size()); + return dataSourceResult; + } } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/warn/controller/WarnDataController.java b/backend/src/main/java/com/yfd/platform/qgc_env/warn/controller/WarnDataController.java index 00421006..ebb0f33c 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/warn/controller/WarnDataController.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/warn/controller/WarnDataController.java @@ -74,4 +74,10 @@ public class WarnDataController { public ResponseResult getWarnStcdKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { return ResponseResult.successData(warnDataService.getWarnStcdKendoListCust(dataSourceRequest)); } + + @PostMapping("/ai/com/qgc/aiFile/GetKendoListCust") + @Operation(summary = "全过程AI识别监测日历表(文件)") + public ResponseResult getAiFileKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(warnDataService.getAiFileKendoListCust(dataSourceRequest)); + } } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/warn/entity/vo/AiFileVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/warn/entity/vo/AiFileVo.java new file mode 100644 index 00000000..c4d2abce --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/warn/entity/vo/AiFileVo.java @@ -0,0 +1,43 @@ +package com.yfd.platform.qgc_env.warn.entity.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.util.Date; + +/** + * AI文件列表VO - 全过程AI识别监测日历表(文件) + * + * @author Generated + * @since 2025-07-01 + */ +@Data +public class AiFileVo { + + private String stcd; + + private String stnm; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date tm; + + private String fid; + + private String rstcd; + + private String ennm; + + private String stCode; + + private String stName; + + private Integer baseStepSort; + + private Integer rvcdStepSort; + + private Integer rstcdStepSort; + + private Integer siteStepSort; + + private Integer dataType; +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/warn/service/WarnDataService.java b/backend/src/main/java/com/yfd/platform/qgc_env/warn/service/WarnDataService.java index eccdcb72..66f942ff 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/warn/service/WarnDataService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/warn/service/WarnDataService.java @@ -8,6 +8,7 @@ import com.yfd.platform.qgc_env.warn.entity.vo.AiProtectVo; import com.yfd.platform.qgc_env.warn.entity.vo.AiDmRunVo; import com.yfd.platform.qgc_env.warn.entity.vo.AiComListVo; import com.yfd.platform.qgc_env.warn.entity.vo.AiRstcdVo; +import com.yfd.platform.qgc_env.warn.entity.vo.AiFileVo; import com.yfd.platform.qgc_env.warn.entity.vo.EngWarnCountVo; import com.yfd.platform.qgc_env.warn.entity.vo.StcdWarnStateVo; @@ -32,4 +33,6 @@ public interface WarnDataService { DataSourceResult getAlarmPointKendoListCust(DataSourceRequest dataSourceRequest); DataSourceResult getWarnStcdKendoListCust(DataSourceRequest dataSourceRequest); + + DataSourceResult getAiFileKendoListCust(DataSourceRequest dataSourceRequest); } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/warn/service/impl/WarnDataServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/warn/service/impl/WarnDataServiceImpl.java index efd22964..ac9bf4e7 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/warn/service/impl/WarnDataServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/warn/service/impl/WarnDataServiceImpl.java @@ -13,6 +13,7 @@ import com.yfd.platform.common.MicroservicDynamicSQLMapper; import com.yfd.platform.qgc_env.warn.entity.vo.AlarmPointVo; import com.yfd.platform.qgc_env.warn.entity.vo.AiComListVo; import com.yfd.platform.qgc_env.warn.entity.vo.AiDmRunVo; +import com.yfd.platform.qgc_env.warn.entity.vo.AiFileVo; import com.yfd.platform.qgc_env.warn.entity.vo.AiProtectVo; import com.yfd.platform.qgc_env.warn.entity.vo.AiRecordVo; import com.yfd.platform.qgc_env.warn.entity.vo.AiRstcdVo; @@ -157,6 +158,7 @@ public class WarnDataServiceImpl implements WarnDataService { .append("ai.RSTCD AS rstcd, ") .append("eng.ENNM AS ennm, ") .append("ai.BASE_ID AS baseId, ") + .append("hb.BASENAME AS baseName, ") .append("ai.HBRVCD AS hbrvcd, ") .append("ai.RVCD AS rvcd, ") .append("rec.TM AS tm, ") @@ -172,6 +174,7 @@ public class WarnDataServiceImpl implements WarnDataService { .append("FROM SD_AICOM_R rec ") .append("LEFT JOIN SD_AIMONITOR_B_H ai ON ai.STCD = rec.STCD AND NVL(ai.IS_DELETED, 0) = 0 ") .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = ai.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = ai.BASE_ID AND hb.IS_DELETED = 0 ") .append("WHERE NVL(rec.IS_DELETED, 0) = 0 "); String filterSql = buildAiComFilterCondition(dataSourceRequest == null ? null : dataSourceRequest.getFilter(), paramMap, new int[]{0}); @@ -356,6 +359,254 @@ public class WarnDataServiceImpl implements WarnDataService { return result; } + @Override + public DataSourceResult getAiFileKendoListCust(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + String baseId = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "baseId"); + String tm = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "tm"); + String rstcd = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "rstcd"); + String stcd = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "stcd"); + String type = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "type"); + String dataType = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "dataType"); + + Date startTime = null, endTime = null; + if (StrUtil.isNotBlank(tm)) { + String[] ll = tm.split(","); + if (ll.length == 2) { + startTime = DateUtil.parse(ll[0]); + endTime = DateUtil.parse(ll[1]); + if (startTime.after(endTime)) { + Date tmp = startTime; + startTime = endTime; + endTime = tmp; + } + } + } + + if (StrUtil.isNotBlank(rstcd)) { + rstcd = rstcd.replace("[", "").replace("]", "").replaceAll("\"", "'"); + } + + Map paramMap = new HashMap<>(); + + StringBuilder sql = new StringBuilder(); + sql.append("SELECT * FROM ("); + sql.append(buildAiFileHeartbeatSql(baseId, type, rstcd, stcd, startTime, endTime, paramMap, "hb")); + sql.append(" UNION "); + sql.append(buildAiFileComSql(baseId, type, rstcd, stcd, startTime, endTime, paramMap, "ac")); + sql.append(") WHERE 1=1 "); + + if (StrUtil.isNotBlank(dataType)) { + paramMap.put("dataType", Integer.parseInt(dataType)); + sql.append("AND DATA_TYPE = #{map.dataType} "); + } + + sql.append(buildAiFileOrderBySql(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, + AiFileVo.class + ); + + DataSourceResult result = new DataSourceResult<>(); + result.setData(list); + result.setTotal(page == null ? list.size() : page.getTotal()); + result.setAggregates(new HashMap<>()); + return result; + } + + private String buildAiFileHeartbeatSql(String baseId, String type, String rstcd, String stcd, + Date startTime, Date endTime, Map paramMap, String keyPrefix) { + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append("a.STCD AS STCD, ") + .append("b.RSTCD AS RSTCD, ") + .append("eng.ENNM AS ENNM, ") + .append("b.STCD AS STCODE, ") + .append("b.STNM AS STNAME, ") + .append("hb.ORDER_INDEX AS BASESTEPSORT, ") + .append("along.ORDER_INDEX AS RVCDSTEPSORT, ") + .append("rstSort.SORT AS RSTCDSTEPSORT, ") + .append("siteSort.SORT AS SITESTEPSORT, ") + .append("b.STNM AS STNM, ") + .append("a.TM AS TM, "); + + if (StrUtil.isNotBlank(type)) { + if ("AI_5001".equals(type) || "AI_50011".equals(type)) { + sql.append("3 AS DATA_TYPE, "); + } else { + sql.append("1 AS DATA_TYPE, "); + } + } else { + sql.append("1 AS DATA_TYPE, "); + } + + sql.append("REGEXP_SUBSTR(a.FID, '[^,]+', 1, LEVEL) AS FID "); + sql.append("FROM SD_AIHEARTBEAT_R a "); + sql.append("INNER JOIN SD_AIMONITOR_B_H b ON a.STCD = b.STCD AND NVL(b.IS_DELETED, 0) = 0 AND b.STTP LIKE 'AI_%' "); + sql.append("LEFT JOIN SD_ENGINFO_B_H eng ON b.RSTCD = eng.STCD AND NVL(eng.IS_DELETED, 0) = 0 "); + sql.append("LEFT JOIN SD_HYDROBASE hb ON b.BASE_ID = hb.BASEID AND NVL(hb.IS_DELETED, 0) = 0 "); + sql.append("LEFT JOIN MS_ALONG_B along ON b.HBRVCD = along.RVCD AND along.CODE = 'common' AND NVL(along.IS_DELETED, 0) = 0 "); + sql.append("LEFT JOIN (SELECT det.SORT, cfg.RVCD, det.STCD FROM MS_ALONGDET_B det INNER JOIN MS_ALONG_B cfg ON det.ALONG_ID = cfg.ID WHERE NVL(det.IS_DELETED, 0) = 0 AND NVL(cfg.IS_DELETED, 0) = 0 AND cfg.CODE = 'common') rstSort ON rstSort.RVCD = b.HBRVCD AND rstSort.STCD = b.RSTCD "); + sql.append("LEFT JOIN (SELECT det.SORT, cfg.RVCD, det.STCD FROM MS_ALONGDET_B det INNER JOIN MS_ALONG_B cfg ON det.ALONG_ID = cfg.ID WHERE NVL(det.IS_DELETED, 0) = 0 AND NVL(cfg.IS_DELETED, 0) = 0 AND cfg.CODE = 'common') siteSort ON siteSort.RVCD = b.HBRVCD AND siteSort.STCD = b.STCD "); + sql.append("WHERE NVL(a.IS_DELETED, 0) = 0 "); + sql.append("AND a.FID NOT LIKE '%ORA-%' AND a.FID NOT LIKE '%Out%' "); + + if (StrUtil.isNotBlank(type)) { + if ("AI_50011".equals(type)) { + sql.append("AND b.STTP = 'AI_5001' "); + } else { + sql.append("AND b.STTP = '").append(type).append("' "); + } + } + if (StrUtil.isNotBlank(baseId)) { + paramMap.put(keyPrefix + "BaseId", baseId); + sql.append("AND b.BASE_ID = #{map.").append(keyPrefix).append("BaseId} "); + } + if (StrUtil.isNotBlank(stcd)) { + paramMap.put(keyPrefix + "Stcd", stcd); + sql.append("AND b.STCD = #{map.").append(keyPrefix).append("Stcd} "); + } + if (StrUtil.isNotBlank(rstcd)) { + sql.append("AND b.RSTCD IN (").append(rstcd).append(") "); + } + if (startTime != null) { + paramMap.put(keyPrefix + "StartTime", startTime); + sql.append("AND a.TM >= #{map.").append(keyPrefix).append("StartTime} "); + } + if (endTime != null) { + paramMap.put(keyPrefix + "EndTime", endTime); + sql.append("AND a.TM <= #{map.").append(keyPrefix).append("EndTime} "); + } + + sql.append("CONNECT BY REGEXP_SUBSTR(a.FID, '[^,]+', 1, LEVEL) IS NOT NULL "); + sql.append("AND PRIOR a.ID = a.ID "); + sql.append("AND PRIOR DBMS_RANDOM.VALUE IS NOT NULL"); + + return sql.toString(); + } + + private String buildAiFileComSql(String baseId, String type, String rstcd, String stcd, + Date startTime, Date endTime, Map paramMap, String keyPrefix) { + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append("a.STCD AS STCD, ") + .append("b.RSTCD AS RSTCD, ") + .append("eng.ENNM AS ENNM, ") + .append("b.STCD AS STCODE, ") + .append("b.STNM AS STNAME, ") + .append("hb.ORDER_INDEX AS BASESTEPSORT, ") + .append("along.ORDER_INDEX AS RVCDSTEPSORT, ") + .append("rstSort.SORT AS RSTCDSTEPSORT, ") + .append("siteSort.SORT AS SITESTEPSORT, ") + .append("b.STNM AS STNM, ") + .append("a.TM AS TM, "); + + if (StrUtil.isNotBlank(type)) { + if ("AI_5001".equals(type) || "AI_50011".equals(type)) { + sql.append("(CASE WHEN a.TYPE = 'AI_5001' AND (a.IS_BIG_DEBRIS_AREA IS NULL OR a.IS_BIG_DEBRIS_AREA = 0) THEN 4 WHEN a.TYPE = 'AI_5001' AND a.IS_BIG_DEBRIS_AREA > 0 THEN 5 END) AS DATA_TYPE, "); + } else { + sql.append("2 AS DATA_TYPE, "); + } + } else { + sql.append("2 AS DATA_TYPE, "); + } + + sql.append("REGEXP_SUBSTR(a.FID, '[^,]+', 1, LEVEL) AS FID "); + sql.append("FROM SD_AICOM_R a "); + sql.append("INNER JOIN SD_AIMONITOR_B_H b ON a.STCD = b.STCD AND NVL(b.IS_DELETED, 0) = 0 AND b.STTP LIKE 'AI_%' "); + sql.append("LEFT JOIN SD_ENGINFO_B_H eng ON b.RSTCD = eng.STCD AND NVL(eng.IS_DELETED, 0) = 0 "); + sql.append("LEFT JOIN SD_HYDROBASE hb ON b.BASE_ID = hb.BASEID AND NVL(hb.IS_DELETED, 0) = 0 "); + sql.append("LEFT JOIN MS_ALONG_B along ON b.HBRVCD = along.RVCD AND along.CODE = 'common' AND NVL(along.IS_DELETED, 0) = 0 "); + sql.append("LEFT JOIN (SELECT det.SORT, cfg.RVCD, det.STCD FROM MS_ALONGDET_B det INNER JOIN MS_ALONG_B cfg ON det.ALONG_ID = cfg.ID WHERE NVL(det.IS_DELETED, 0) = 0 AND NVL(cfg.IS_DELETED, 0) = 0 AND cfg.CODE = 'common') rstSort ON rstSort.RVCD = b.HBRVCD AND rstSort.STCD = b.RSTCD "); + sql.append("LEFT JOIN (SELECT det.SORT, cfg.RVCD, det.STCD FROM MS_ALONGDET_B det INNER JOIN MS_ALONG_B cfg ON det.ALONG_ID = cfg.ID WHERE NVL(det.IS_DELETED, 0) = 0 AND NVL(cfg.IS_DELETED, 0) = 0 AND cfg.CODE = 'common') siteSort ON siteSort.RVCD = b.HBRVCD AND siteSort.STCD = b.STCD "); + sql.append("WHERE NVL(a.IS_DELETED, 0) = 0 "); + sql.append("AND (a.TASK_STATUS IS NULL OR a.TASK_STATUS = 'Approved') "); + sql.append("AND a.FID NOT LIKE '%ORA-%' AND a.FID NOT LIKE '%Out%' "); + + if (StrUtil.isNotBlank(type)) { + if ("AI_50011".equals(type)) { + paramMap.put(keyPrefix + "Type", "AI_5001"); + sql.append("AND a.TYPE = #{map.").append(keyPrefix).append("Type} "); + } else { + paramMap.put(keyPrefix + "Type", type); + sql.append("AND a.TYPE = #{map.").append(keyPrefix).append("Type} "); + } + } + if (StrUtil.isNotBlank(baseId)) { + paramMap.put(keyPrefix + "BaseId", baseId); + sql.append("AND b.BASE_ID = #{map.").append(keyPrefix).append("BaseId} "); + } + if (StrUtil.isNotBlank(stcd)) { + paramMap.put(keyPrefix + "Stcd", stcd); + sql.append("AND b.STCD = #{map.").append(keyPrefix).append("Stcd} "); + } + if (StrUtil.isNotBlank(rstcd)) { + sql.append("AND b.RSTCD IN (").append(rstcd).append(") "); + } + if (startTime != null) { + paramMap.put(keyPrefix + "StartTime", startTime); + sql.append("AND a.TM >= #{map.").append(keyPrefix).append("StartTime} "); + } + if (endTime != null) { + paramMap.put(keyPrefix + "EndTime", endTime); + sql.append("AND a.TM <= #{map.").append(keyPrefix).append("EndTime} "); + } + + sql.append("CONNECT BY REGEXP_SUBSTR(a.FID, '[^,]+', 1, LEVEL) IS NOT NULL "); + sql.append("AND PRIOR a.ID = a.ID "); + sql.append("AND PRIOR DBMS_RANDOM.VALUE IS NOT NULL"); + + return sql.toString(); + } + + private String buildAiFileOrderBySql(List sortList) { + if (CollUtil.isEmpty(sortList)) { + return " ORDER BY STCD, TM DESC "; + } + List orderItems = new ArrayList<>(); + for (DataSourceRequest.SortDescriptor item : sortList) { + if (item == null || StrUtil.isBlank(item.getField())) { + continue; + } + String column = mapAiFileColumn(item.getField()); + if (StrUtil.isBlank(column)) { + continue; + } + String dir = "desc".equalsIgnoreCase(item.getDir()) ? "DESC" : "ASC"; + orderItems.add(column + " " + dir); + } + if (orderItems.isEmpty()) { + return " ORDER BY STCD, TM DESC "; + } + return " ORDER BY " + String.join(", ", orderItems); + } + + private String mapAiFileColumn(String field) { + if (StrUtil.isBlank(field)) { + return null; + } + return switch (field) { + case "stcd" -> "STCD"; + case "stnm" -> "STNM"; + case "tm" -> "TM"; + case "fid" -> "FID"; + case "rstcd" -> "RSTCD"; + case "ennm" -> "ENNM"; + case "stCode" -> "STCODE"; + case "stName" -> "STNAME"; + case "baseStepSort" -> "BASESTEPSORT"; + case "rvcdStepSort" -> "RVCDSTEPSORT"; + case "rstcdStepSort" -> "RSTCDSTEPSORT"; + case "siteStepSort" -> "SITESTEPSORT"; + case "dataType" -> "DATA_TYPE"; + default -> null; + }; + } + private AiDmRunVo buildAiDmRunVo(Map row) { if (row == null || row.isEmpty()) { return null; @@ -1624,6 +1875,7 @@ public class WarnDataServiceImpl implements WarnDataService { case "rstcd" -> "ai.RSTCD"; case "ennm", "stnmEng" -> "eng.ENNM"; case "baseId" -> "ai.BASE_ID"; + case "baseName" -> "hb.BASENAME"; case "hbrvcd" -> "ai.HBRVCD"; case "rvcd" -> "ai.RVCD"; case "tm" -> "rec.TM"; @@ -1653,6 +1905,7 @@ public class WarnDataServiceImpl implements WarnDataService { case "rstcd" -> alias + ".rstcd"; case "ennm", "stnmEng" -> alias + ".ennm"; case "baseId" -> alias + ".baseId"; + case "baseName" -> alias + ".baseName"; case "hbrvcd" -> alias + ".hbrvcd"; case "rvcd" -> alias + ".rvcd"; case "tm" -> alias + ".tm"; 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..e3f9247b 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) { @@ -149,4 +156,10 @@ public class EnvWqDataController { public ResponseResult getRuleKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { return ResponseResult.successData(envWqDataService.getWqWarRuleList(dataSourceRequest)); } + + @PostMapping("/anchorPoint/GetKendoListCust") + @Operation(summary = "水质锚点") + public ResponseResult getAnchorPointKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(envWqDataService.getAnchorPointKendoListCust(dataSourceRequest)); + } } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wq/entity/vo/EnvWqAnchorPointVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wq/entity/vo/EnvWqAnchorPointVo.java new file mode 100644 index 00000000..12aa666b --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wq/entity/vo/EnvWqAnchorPointVo.java @@ -0,0 +1,228 @@ +package com.yfd.platform.qgc_env.wq.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; +import java.util.Map; + +@Data +@Schema(description = "水质锚点VO") +public class EnvWqAnchorPointVo { + + @Schema(description = "断面") + private String stcd; + + @Schema(description = "断面名称") + private String stnm; + + @Schema(description = "电站名称") + private String ennm; + + @Schema(description = "数据接入类型:0=自建 1=国家建 2=人工") + private Integer dtinType; + + @Schema(description = "所在位置") + private String stlc; + + @Schema(description = "水质要求") + private String wwqtg; + + @Schema(description = "水质要求名称") + private String wwqtgName; + + @Schema(description = "水质是否达标") + private Integer sfdb; + + @Schema(description = "数据时间") + private Date tm; + + @Schema(description = "水质类别:监测结果") + private String wqGrd; + + @Schema(description = "水质类别名称") + private String wqGrdName; + + @Schema(description = "站点类型 - 用于锚点弹框显示") + private String sttp; + + @Schema(description = "经度") + private BigDecimal lgtd; + + @Schema(description = "纬度") + private BigDecimal lttd; + + @Schema(description = "高程") + private BigDecimal dtmel; + + @Schema(description = "描点状态 - 用于图例") + private String anchoPointState; + + @Schema(description = "锚点类型 - 用于锚点浮框显示") + private String sttpMap; + + @Schema(description = "弹框站点名称") + private String titleName; + + @Schema(description = "基地id") + private String baseId; + + @Schema(description = "栖息地名称") + private String fhstnm; + + @Schema(description = "栖息地编码") + private String fhstcd; + + private String addvcdName; + private String baseName; + private String hbrvcd; + private String hbrvcdName; + private String rvcdName; + private String rstcd; + private Integer rstcdStepSort; + private Integer siteStepSort; + private Integer baseStepSort; + private Integer rvcdStepSort; + + @Schema(description = "地图避让") + private Integer distance; + + private String sttpCode; + private String value; + private String alias; + + @Schema(description = "水温") + private BigDecimal wtmp; + + @Schema(description = "PH") + private BigDecimal ph; + + @Schema(description = "溶解氧") + private BigDecimal dox; + + @Schema(description = "高锰酸盐指数") + private BigDecimal codmn; + + @Schema(description = "化学需氧量") + private BigDecimal codcr; + + @Schema(description = "五日生化需氧量") + private BigDecimal bod5; + + @Schema(description = "氨氮") + private BigDecimal nh3n; + + @Schema(description = "总磷") + private BigDecimal tp; + + @Schema(description = "总氮") + private BigDecimal tn; + + @Schema(description = "铜") + private BigDecimal cu; + + @Schema(description = "锌") + private BigDecimal zn; + + @Schema(description = "氟化物") + private BigDecimal f; + + @Schema(description = "硒") + private BigDecimal se; + + @Schema(description = "砷") + private BigDecimal ars; + + @Schema(description = "汞") + private BigDecimal hg; + + @Schema(description = "镉") + private BigDecimal cd; + + @Schema(description = "铬(六价)") + private BigDecimal cr6; + + @Schema(description = "铅") + private BigDecimal pb; + + @Schema(description = "氰化物") + private BigDecimal cn; + + @Schema(description = "挥发酚") + private BigDecimal vlph; + + @Schema(description = "石油类") + private BigDecimal oil; + + @Schema(description = "阴离子表面活性剂") + private BigDecimal las; + + @Schema(description = "硫化物") + private BigDecimal s2; + + @Schema(description = "粪大肠菌群") + private BigDecimal fcg; + + @Schema(description = "氯化物") + private BigDecimal cl; + + @Schema(description = "硫酸盐") + private BigDecimal so4; + + @Schema(description = "硝酸盐氮") + private BigDecimal no3; + + @Schema(description = "总硬度") + private BigDecimal thrd; + + @Schema(description = "电导率") + private BigDecimal cond; + + @Schema(description = "铁") + private BigDecimal fe; + + @Schema(description = "锰") + private BigDecimal mn; + + @Schema(description = "铝") + private BigDecimal al; + + @Schema(description = "叶绿素a") + private BigDecimal chla; + + @Schema(description = "透明度") + private BigDecimal clarity; + + @Schema(description = "浊度") + private BigDecimal tu; + + @Schema(description = "总氧/总需氧量") + private BigDecimal tod; + + @Schema(description = "蓝绿藻") + private BigDecimal cyano; + + @Schema(description = "水质要素最小限值集合") + private List> min; + + @Schema(description = "水质要素最大限值集合") + private List> max; + + @Schema(description = "排序") + private Integer orderIndex; + + private String engLctn1Code; + private String engLctn3Code; + + public void setWqGrd(String wqGrd) { + this.wqGrd = wqGrd; + this.value = wqGrd; + } + + public void setWqGrdName(String wqGrdName) { + this.wqGrdName = wqGrdName; + this.alias = wqGrdName; + } +} \ No newline at end of file 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..f2ff1e22 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 @@ -4,6 +4,7 @@ import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.common.DataSourceResult; import com.yfd.platform.qgc_base.entity.vo.BatchDeleteAo; import com.yfd.platform.qgc_env.wq.entity.vo.WqBaseInfoVo; +import com.yfd.platform.qgc_env.wq.entity.vo.EnvWqAnchorPointVo; import java.util.Map; @@ -39,7 +40,9 @@ public interface EnvWqDataService { DataSourceResult getStTbYsBVoKendoListCust(DataSourceRequest dataSourceRequest); - boolean updateWqRsData(Map updateData); + boolean updateWqRsData(Map updateData, String source); boolean removeKendoByIds(BatchDeleteAo batchDeleteAo); + + DataSourceResult getAnchorPointKendoListCust(DataSourceRequest dataSourceRequest); } 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..cbc2bb8b 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,15 +1,22 @@ 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; +import com.yfd.platform.qgc_env.wt.utils.SiteAvoidanceUtils; import com.yfd.platform.utils.KendoUtil; import com.yfd.platform.utils.QgcQueryWrapperUtil; import com.yfd.platform.utils.RequestHolder; @@ -31,17 +38,121 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; +import org.apache.commons.collections4.CollectionUtils; @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 +3782,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 +3818,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 +3886,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 +3989,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); @@ -4182,4 +4542,205 @@ public class EnvWqDataServiceImpl implements EnvWqDataService { ")"; jdbcTemplate.update(mergeSql, stcd, startDate, endDate); } + + @Override + public DataSourceResult getAnchorPointKendoListCust(DataSourceRequest dataSourceRequest) { + DataSourceResult dataSourceResult = new DataSourceResult<>(); + dataSourceResult.setAggregates(new HashMap<>()); + + if (dataSourceRequest == null) { + dataSourceResult.setData(new ArrayList<>()); + dataSourceResult.setTotal(0L); + return dataSourceResult; + } + + DataSourceLoadOptionsBase loadOptionsBase = dataSourceRequest.toDevRequest(); + String sttpCode = QgcQueryWrapperUtil.getFilterFieldValue(loadOptionsBase, "sttpCode"); + String time = QgcQueryWrapperUtil.getFilterFieldValue(loadOptionsBase, "tm"); + String fhFlag = QgcQueryWrapperUtil.getFilterFieldValue(loadOptionsBase, "fhFlag"); + + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append("t.STCD AS stcd, ") + .append("t.STNM AS stnm, ") + .append("t.STTP AS sttp, ") + .append("t.STTP AS sttpCode, ") + .append("t.LGTD AS lgtd, ") + .append("t.LTTD AS lttd, ") + .append("t.ELEV AS dtmel, ") + .append("t.STLC AS stlc, ") + .append("t.WWQTG AS wwqtg, ") + .append("t.DTIN_TYPE AS dtinType, ") + .append("t.RSTCD AS rstcd, ") + .append("t.FHSTCD AS fhstcd, ") + .append("t.ORDER_INDEX AS orderIndex, ") + .append("eng.ENNM AS ennm, ") + .append("hb.BASE_NAME AS baseName, ") + .append("hb.BASEID AS baseId, ") + .append("eng.HBRVCD AS hbrvcd, ") + .append("NVL(hbrv.NAME, '') AS hbrvcdName, ") + .append("NVL(rvcd.NAME, '') AS rvcdName, ") + .append("NVL(addvcd.NAME, '') AS addvcdName, ") + .append("NVL(along.ORDER_INDEX, 999999) AS rvcdStepSort, ") + .append("NVL(rstSort.SORT, 999999) AS rstcdStepSort, ") + .append("NVL(siteSort.SORT, 999999) AS siteStepSort, ") + .append("NVL(hb.ORDER_INDEX, 999999) AS baseStepSort, ") + .append("'' AS engLctn1Code, ") + .append("'' AS engLctn3Code ") + .append("FROM SD_WQ_B_H t ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = t.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = eng.BASE_ID AND NVL(hb.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.CODE = eng.HBRVCD AND NVL(hbrv.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN SD_RVCD_DIC rvcd ON rvcd.CODE = eng.RVCD AND NVL(rvcd.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN SD_ADDVCD_DIC addvcd ON addvcd.CODE = eng.ADDVCD AND NVL(addvcd.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN MS_ALONG_B along ON along.RVCD = eng.HBRVCD AND along.CODE = 'common' AND NVL(along.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN ( ") + .append(" SELECT det.SORT, cfg.RVCD, det.STCD ") + .append(" FROM MS_ALONGDET_B det ") + .append(" INNER JOIN MS_ALONG_B cfg ON det.ALONG_ID = cfg.ID ") + .append(" WHERE NVL(det.IS_DELETED, 0) = 0 AND NVL(cfg.IS_DELETED, 0) = 0 AND cfg.CODE = 'common' ") + .append(") rstSort ON rstSort.RVCD = eng.HBRVCD AND rstSort.STCD = t.RSTCD ") + .append("LEFT JOIN ( ") + .append(" SELECT det.SORT, cfg.RVCD, det.STCD ") + .append(" FROM MS_ALONGDET_B det ") + .append(" INNER JOIN MS_ALONG_B cfg ON det.ALONG_ID = cfg.ID ") + .append(" WHERE NVL(det.IS_DELETED, 0) = 0 AND NVL(cfg.IS_DELETED, 0) = 0 AND cfg.CODE = 'common' ") + .append(") siteSort ON siteSort.RVCD = eng.HBRVCD AND siteSort.STCD = t.STCD ") + .append("WHERE NVL(t.IS_DELETED, 0) = 0 ") + .append("AND NVL(t.USFL, 1) = 1 ") + .append("AND t.LGTD IS NOT NULL ") + .append("AND t.LTTD IS NOT NULL "); + + DataSourceLoadOptionsBase loadOptions = dataSourceRequest.toDevRequest(); + Page page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + List wqVoList = microservicDynamicSQLMapper.pageAllListWithResultType(page, sql.toString(), new HashMap<>(), EnvWqAnchorPointVo.class); + + if (CollectionUtils.isNotEmpty(wqVoList)) { + List stcdList = wqVoList.stream() + .filter(w -> StrUtil.isNotBlank(w.getStcd())) + .map(w -> w.getStcd().trim()) + .distinct() + .collect(Collectors.toList()); + + String wqDataSql = "SELECT STCD, TM, WQGRD, SFDB, 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, TOD " + + "FROM ( " + + " SELECT t.*, ROW_NUMBER() OVER (PARTITION BY t.STCD ORDER BY t.TM DESC) AS rn " + + " FROM SD_WQ_R t " + + " WHERE t.STCD IN (" + String.join(",", stcdList.stream().map(s -> "'" + s + "'").collect(Collectors.toList())) + ") " + + " AND NVL(t.IS_DELETED, 0) = 0 " + + ") WHERE rn = 1"; + + List wqDataList = microservicDynamicSQLMapper.getAllListWithResultType(wqDataSql, new HashMap<>(), EnvWqDataVo.class); + Map wqDataMap = wqDataList.stream() + .collect(Collectors.toMap(EnvWqDataVo::getStcd, Function.identity(), (oldValue, newValue) -> newValue)); + + for (EnvWqAnchorPointVo anchorPointVo : wqVoList) { + EnvWqDataVo wqData = wqDataMap.get(anchorPointVo.getStcd()); + if (wqData != null) { + anchorPointVo.setTm(wqData.getTm()); + anchorPointVo.setWqGrd(wqData.getWqgrd()); + anchorPointVo.setSfdb(wqData.getSfdb()); + anchorPointVo.setWtmp(wqData.getWtmp()); + anchorPointVo.setPh(wqData.getPh()); + anchorPointVo.setDox(wqData.getDox()); + anchorPointVo.setCodmn(wqData.getCodmn()); + anchorPointVo.setCodcr(wqData.getCodcr()); + anchorPointVo.setBod5(wqData.getBod5()); + anchorPointVo.setNh3n(wqData.getNh3n()); + anchorPointVo.setTp(wqData.getTp()); + anchorPointVo.setTn(wqData.getTn()); + anchorPointVo.setCu(wqData.getCu()); + anchorPointVo.setZn(wqData.getZn()); + anchorPointVo.setF(wqData.getF()); + anchorPointVo.setSe(wqData.getSe()); + anchorPointVo.setArs(wqData.getArs()); + anchorPointVo.setHg(wqData.getHg()); + anchorPointVo.setCd(wqData.getCd()); + anchorPointVo.setCr6(wqData.getCr6()); + anchorPointVo.setPb(wqData.getPb()); + anchorPointVo.setCn(wqData.getCn()); + anchorPointVo.setVlph(wqData.getVlph()); + anchorPointVo.setOil(wqData.getOil()); + anchorPointVo.setLas(wqData.getLas()); + anchorPointVo.setS2(wqData.getS2()); + anchorPointVo.setFcg(wqData.getFcg()); + anchorPointVo.setCl(wqData.getCl()); + anchorPointVo.setSo4(wqData.getSo4()); + anchorPointVo.setNo3(wqData.getNo3()); + anchorPointVo.setThrd(wqData.getThrd()); + anchorPointVo.setCond(wqData.getCond()); + anchorPointVo.setFe(wqData.getFe()); + anchorPointVo.setMn(wqData.getMn()); + anchorPointVo.setAl(wqData.getAl()); + anchorPointVo.setChla(wqData.getChla()); + anchorPointVo.setClarity(wqData.getClarity()); + anchorPointVo.setTu(wqData.getTu()); + anchorPointVo.setCyano(wqData.getCyano()); + anchorPointVo.setTod(wqData.getTod()); + } + } + } + + for (EnvWqAnchorPointVo anchorPointVo : wqVoList) { + anchorPointVo.setSttpMap(anchorPointVo.getSttp()); + anchorPointVo.setTitleName(anchorPointVo.getStnm()); + anchorPointVo.setAnchoPointState(getAnchorPoint(anchorPointVo)); + + if (StrUtil.isNotBlank(sttpCode) && "WQFB".equals(sttpCode)) { + anchorPointVo.setAnchoPointState("wqfb_legend"); + } + if (StrUtil.isNotBlank(fhFlag)) { + anchorPointVo.setAnchoPointState("fhwq_legend"); + } + } + + SiteAvoidanceUtils.calcSiteMapLev(wqVoList, + EnvWqAnchorPointVo::getStcd, + EnvWqAnchorPointVo::getLgtd, + EnvWqAnchorPointVo::getLttd, + EnvWqAnchorPointVo::getAnchoPointState, + EnvWqAnchorPointVo::setDistance); + + dataSourceResult.setData(wqVoList); + dataSourceResult.setTotal(page == null ? wqVoList.size() : page.getTotal()); + return dataSourceResult; + } + + private String getAnchorPoint(EnvWqAnchorPointVo anchorPointVo) { + Integer dtinType = anchorPointVo.getDtinType(); + Integer sfdb = anchorPointVo.getSfdb(); + + if (dtinType == null) { + dtinType = 2; + } + if (sfdb == null) { + sfdb = 2; + } + + if (dtinType == 0) { + if (sfdb == 0) { + return "wq_station_4"; + } else if (sfdb == 1) { + return "wq_station_3"; + } else { + return "wq_station_8"; + } + } else if (dtinType == 1) { + if (sfdb == 0) { + return "wq_station_2"; + } else if (sfdb == 1) { + return "wq_station_1"; + } else { + return "wq_station_7"; + } + } else { + if (sfdb == 0) { + return "wq_station_6"; + } else if (sfdb == 1) { + return "wq_station_5"; + } else { + return "wq_station_9"; + } + } + } } 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..828e4caf 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(); } @@ -309,4 +321,10 @@ public class SdWTMonitorController { public ResponseResult getOneLevelListCust(@RequestBody DataSourceRequest dataSourceRequest) { return ResponseResult.successData(sdDzChuiXiangListService.processKendoList(dataSourceRequest)); } + + @PostMapping("/getFacilityPointList/GetKendoListCust") + @Operation(summary = "低温水减缓设施描点") + public ResponseResult getFacilityPointKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(sdWtMonitorService.getFacilityPointKendoListCust(dataSourceRequest)); + } } diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wt/entity/vo/DwSlowFacilityMapVO.java b/backend/src/main/java/com/yfd/platform/qgc_env/wt/entity/vo/DwSlowFacilityMapVO.java new file mode 100644 index 00000000..f4033274 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wt/entity/vo/DwSlowFacilityMapVO.java @@ -0,0 +1,83 @@ +package com.yfd.platform.qgc_env.wt.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +@Schema(description = "低温水减缓设施描点VO") +public class DwSlowFacilityMapVO { + + @Schema(description = "站点编码") + private String stcd; + + @Schema(description = "关联电站编码") + private String rstcd; + + @Schema(description = "关联电站编码(冗余)") + private String rstcds; + + @Schema(description = "站名") + private String stnm; + + @Schema(description = "标题名称") + private String titleName; + + @Schema(description = "站点类型编码") + private String sttpCode; + + @Schema(description = "站点类型映射") + private String sttpMap; + + @Schema(description = "描点状态") + private String anchoPointState; + + @Schema(description = "地图避让") + private Integer distance; + + @Schema(description = "建设状态 0=规划,1=在建,2=已建") + private String bldstt; + + @Schema(description = "经度") + private BigDecimal lgtd; + + @Schema(description = "纬度") + private BigDecimal lttd; + + @Schema(description = "遥测方式") + private String dtmel; + + @Schema(description = "流域编码") + private String rvcd; + + @Schema(description = "行政区编码") + private String addvcd; + + @Schema(description = "基地编码") + private String baseId; + + @Schema(description = "关联电站名称") + private String ennm; + + @Schema(description = "运行状态") + private String status; + + @Schema(description = "站点类型") + private String sttp; + + @Schema(description = "设施类型") + private String dwtp; + + @Schema(description = "设施类型名称") + private String dwtpName; + + @Schema(description = "站点类型名称") + private String sttpName; + + @Schema(description = "是否接入:0=未接入 1=已接入") + private Integer dtin; + + @Schema(description = "达标状态子类型(1=正常运行,2=暂无数据,3=未正常运行)") + private Integer stdSstate; +} \ No newline at end of file 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/SdWtMonitorService.java b/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/SdWtMonitorService.java index c6d44008..ba092d0a 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/SdWtMonitorService.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/SdWtMonitorService.java @@ -13,6 +13,7 @@ import com.yfd.platform.qgc_env.wt.entity.vo.WtBaseInfoVo; import com.yfd.platform.qgc_env.wt.entity.vo.WtrvAmendSaveVo; import com.yfd.platform.qgc_env.wt.entity.vo.WtrvVo; import com.yfd.platform.qgc_env.wt.entity.vo.WtrvAmendResultVo; +import com.yfd.platform.qgc_env.wt.entity.vo.DwSlowFacilityMapVO; import java.util.List; @@ -51,4 +52,6 @@ public interface SdWtMonitorService { DataSourceResult getMonthDetailList(DataSourceRequest dataSourceRequest); List getWtvtDefaultTreeStcd(DataSourceRequest dataSourceRequest); + + DataSourceResult getFacilityPointKendoListCust(DataSourceRequest dataSourceRequest); } 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/SdWtMonitorServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/SdWtMonitorServiceImpl.java index fa485604..b6ce2afd 100644 --- a/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/SdWtMonitorServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wt/service/impl/SdWtMonitorServiceImpl.java @@ -20,7 +20,9 @@ import com.yfd.platform.qgc_env.wt.entity.vo.WtTreeStcdVo; import com.yfd.platform.qgc_env.wt.entity.vo.WtrvAmendResultVo; import com.yfd.platform.qgc_env.wt.entity.vo.WtrvAmendSaveVo; import com.yfd.platform.qgc_env.wt.entity.vo.WtrvVo; +import com.yfd.platform.qgc_env.wt.entity.vo.DwSlowFacilityMapVO; import com.yfd.platform.qgc_env.wt.mapper.SdWtMonitorMapper; +import com.yfd.platform.qgc_env.wt.utils.SiteAvoidanceUtils; import com.yfd.platform.qgc_env.wt.service.SdWtMonitorService; import com.yfd.platform.utils.QgcQueryWrapperUtil; import jakarta.annotation.Resource; @@ -2830,4 +2832,93 @@ public class SdWtMonitorServiceImpl implements SdWtMonitorService { private String ennm; } + @Override + public DataSourceResult getFacilityPointKendoListCust(DataSourceRequest dataSourceRequest) { + DataSourceResult dataSourceResult = new DataSourceResult<>(); + dataSourceResult.setAggregates(new HashMap<>()); + + if (dataSourceRequest == null) { + dataSourceResult.setData(new ArrayList<>()); + dataSourceResult.setTotal(0L); + return dataSourceResult; + } + + DataSourceLoadOptionsBase devRequest = dataSourceRequest.toDevRequest(); + String bldsttCcode = QgcQueryWrapperUtil.getFilterFieldValue(devRequest, "bldsttCcode"); + + StringBuilder sql = new StringBuilder(); + sql.append("SELECT ") + .append("t.STCD AS stcd, ") + .append("t.RSTCD AS rstcd, ") + .append("t.RSTCD AS rstcds, ") + .append("t.STNM AS stnm, ") + .append("t.STNM AS titleName, ") + .append("t.STTP AS sttpCode, ") + .append("t.STTP AS sttpMap, ") + .append("t.STTP AS anchoPointState, ") + .append("t.BLDSTT_CODE AS bldstt, ") + .append("t.LGTD AS lgtd, ") + .append("t.LTTD AS lttd, ") + .append("CAST(NULL AS NUMBER) AS dtmel, ") + .append("eng.RVCD AS rvcd, ") + .append("eng.ADDVCD AS addvcd, ") + .append("eng.BASE_ID AS baseId, ") + .append("eng.ENNM AS ennm, ") + .append("NULL AS status, ") + .append("t.STTP AS sttp, ") + .append("t.STTP AS dwtp, ") + .append("sttp.STTP_NAME AS dwtpName, ") + .append("sttp.STTP_NAME AS sttpName, ") + .append("t.DTIN AS dtin, ") + .append("NULL AS stdSstate ") + .append("FROM SD_DFLTKW_B_H t ") + .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = t.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ") + .append("LEFT JOIN SD_STTP_B sttp ON sttp.STTP_CODE = t.STTP AND NVL(sttp.IS_DELETED, 0) = 0 ") + .append("WHERE NVL(t.IS_DELETED, 0) = 0 ") + .append("AND NVL(t.USFL, 1) = 1 ") + .append("AND t.LGTD IS NOT NULL ") + .append("AND t.LTTD IS NOT NULL "); + + if (StrUtil.isNotEmpty(bldsttCcode)) { + sql.append(" AND t.BLDSTT_CODE = #{map.bldsttCcode} "); + } + + Map paramMap = new HashMap<>(); + if (StrUtil.isNotEmpty(bldsttCcode)) { + paramMap.put("bldsttCcode", bldsttCcode); + } + + DataSourceLoadOptionsBase loadOptions = dataSourceRequest.toDevRequest(); + Page page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + List resultList = microservicDynamicSQLMapper.pageAllListWithResultType(page, sql.toString(), paramMap, DwSlowFacilityMapVO.class); + + for (DwSlowFacilityMapVO vo : resultList) { + String sttpCode = vo.getSttpCode(); + String bldstt = vo.getBldstt(); + boolean isBuilt = "2".equals(bldstt); + + if ("DW_2".equals(sttpCode)) { + vo.setAnchoPointState(isBuilt ? "dws_1" : "dws_1_incomplete"); + } else if ("DW_5".equals(sttpCode)) { + vo.setAnchoPointState(isBuilt ? "dws_2" : "dws_2_incomplete"); + } else if ("DW_6".equals(sttpCode)) { + vo.setAnchoPointState(isBuilt ? "dws_3" : "dws_3_incomplete"); + } else { + vo.setAnchoPointState(isBuilt ? "dws_4" : "dws_4_incomplete"); + } + vo.setSttpCode("DW"); + } + + SiteAvoidanceUtils.calcSiteMapLev(resultList, + DwSlowFacilityMapVO::getStcd, + DwSlowFacilityMapVO::getLgtd, + DwSlowFacilityMapVO::getLttd, + DwSlowFacilityMapVO::getAnchoPointState, + DwSlowFacilityMapVO::setDistance); + + dataSourceResult.setData(resultList); + dataSourceResult.setTotal(page == null ? resultList.size() : page.getTotal()); + return dataSourceResult; + } + } 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/wt/utils/SiteAvoidanceUtils.java b/backend/src/main/java/com/yfd/platform/qgc_env/wt/utils/SiteAvoidanceUtils.java new file mode 100644 index 00000000..33491f5d --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wt/utils/SiteAvoidanceUtils.java @@ -0,0 +1,282 @@ +package com.yfd.platform.qgc_env.wt.utils; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.Function; + +public class SiteAvoidanceUtils { + + private final static int DEFAULT_LEVEL = 50000000; + private final static int LEVEL1 = 1500000; + private final static double LEVEL1_DISTANCE = 1.2; + private final static int LEVEL2 = 800000; + private final static double LEVEL2_DISTANCE = 0.8; + private final static int LEVEL3 = 400000; + private final static double LEVEL3_DISTANCE = 0.4; + private final static int LEVEL4 = 50000; + private final static double LEVEL4_DISTANCE = 0.1; + + public static List calcSiteMapLev(List vos, Function stcdGetter, Function lgtdGetter, + Function lttdGetter, Function anchoPointStateGetter, + BiConsumer valueSetter) { + return calcSiteMapLev(vos, null, stcdGetter, lgtdGetter, lttdGetter, anchoPointStateGetter, valueSetter); + } + + public static List calcSiteMapLev(List vos, BaseAnchoPointAo ao, Function stcdGetter, + Function lgtdGetter, Function lttdGetter, + Function anchoPointStateGetter, BiConsumer valueSetter) { + if (ao == null) { + ao = new BaseAnchoPointAo(); + } + if (ao.getDefaultLevel() == null) { + ao.setDefaultLevel(DEFAULT_LEVEL); + } + if (ao.getLevel1() == null) { + ao.setLevel1(LEVEL1); + } + if (ao.getLevel1Distance() == null) { + ao.setLevel1Distance(LEVEL1_DISTANCE); + } + if (ao.getLevel2() == null) { + ao.setLevel2(LEVEL2); + } + if (ao.getLevel2Distance() == null) { + ao.setLevel2Distance(LEVEL2_DISTANCE); + } + if (ao.getLevel3() == null) { + ao.setLevel3(LEVEL3); + } + if (ao.getLevel3Distance() == null) { + ao.setLevel3Distance(LEVEL3_DISTANCE); + } + if (ao.getLevel4() == null) { + ao.setLevel4(LEVEL4); + } + if (ao.getLevel4Distance() == null) { + ao.setLevel4Distance(LEVEL4_DISTANCE); + } + if (ao.getCategory() == null) { + ao.setCategory(true); + } + + if (ao.getMinX() != null && ao.getMinY() != null && ao.getMaxX() != null && ao.getMaxY() != null) { + List filterVos = new ArrayList<>(vos.size()); + for (T vo : vos) { + if (lgtdGetter.apply(vo) == null || lgtdGetter.apply(vo).doubleValue() < ao.getMinX() || lgtdGetter.apply(vo).doubleValue() > ao.getMaxX()) { + continue; + } + if (lttdGetter.apply(vo) == null || lttdGetter.apply(vo).doubleValue() < ao.getMinY() || lttdGetter.apply(vo).doubleValue() > ao.getMaxY()) { + continue; + } + filterVos.add(vo); + } + if (filterVos.isEmpty()) { + return new ArrayList<>(); + } + vos = filterVos; + } + + Set meterMapData = new HashSet<>(); + for (int i = 0; i < vos.size(); i++) { + fori(vos, i, meterMapData, ao, stcdGetter, lgtdGetter, lttdGetter, anchoPointStateGetter, valueSetter); + } + return vos; + } + + private static void fori(List partitionLayerMeterList, int i, Set meterMapData, BaseAnchoPointAo ao, + Function stcdGetter, Function lgtdGetter, + Function lttdGetter, Function anchoPointStateGetter, + BiConsumer valueSetter) { + T siteAvoidanceDto = partitionLayerMeterList.get(i); + + String category = anchoPointStateGetter.apply(siteAvoidanceDto); + if (!ao.getCategory()) { + category = null; + } + String stcd = stcdGetter.apply(siteAvoidanceDto); + BigDecimal x1 = lgtdGetter.apply(siteAvoidanceDto); + BigDecimal y1 = lttdGetter.apply(siteAvoidanceDto); + if (meterMapData.contains(stcd + category)) { + return; + } + valueSetter.accept(siteAvoidanceDto, ao.getDefaultLevel()); + for (int j = i + 1; j < partitionLayerMeterList.size(); j++) { + forj(j, partitionLayerMeterList, meterMapData, category, stcd, x1, y1, ao, stcdGetter, lgtdGetter, lttdGetter, anchoPointStateGetter, valueSetter); + } + } + + private static void forj(int j, List partitionLayerMeterList, Set meterMapData, String category, + String stcd, BigDecimal x1, BigDecimal y1, BaseAnchoPointAo ao, + Function stcdGetter, Function lgtdGetter, + Function lttdGetter, Function anchoPointStateGetter, + BiConsumer valueSetter) { + T baseAnchoPointVo = partitionLayerMeterList.get(j); + String category2 = anchoPointStateGetter.apply(baseAnchoPointVo); + if (!ao.getCategory()) { + category = null; + } + String stcd2 = stcdGetter.apply(baseAnchoPointVo); + BigDecimal x2 = lgtdGetter.apply(baseAnchoPointVo); + BigDecimal y2 = lttdGetter.apply(baseAnchoPointVo); + if (!ao.getCategory()) { + category = null; + } + if (meterMapData.contains(stcd2 + category2)) { + return; + } + if (x1 == null || x2 == null || y1 == null || y2 == null) { + return; + } + if (!(stcd + category).equals(stcd2 + category2)) { + double dx = Math.abs(x1.doubleValue() - x2.doubleValue()); + double dy = Math.abs(y1.doubleValue() - y2.doubleValue()); + double distance = Math.sqrt(dx * dx + dy * dy); + if (distance < ao.getLevel4Distance()) { + valueSetter.accept(baseAnchoPointVo, ao.getLevel4()); + meterMapData.add(stcd2 + category2); + } else if (distance < ao.getLevel3Distance()) { + valueSetter.accept(baseAnchoPointVo, ao.getLevel3()); + meterMapData.add(stcd2 + category2); + } else if (distance < ao.getLevel2Distance()) { + valueSetter.accept(baseAnchoPointVo, ao.getLevel2()); + meterMapData.add(stcd2 + category2); + } else if (distance < ao.getLevel1Distance()) { + valueSetter.accept(baseAnchoPointVo, ao.getLevel1()); + meterMapData.add(stcd2 + category2); + } + } + } + + public static class BaseAnchoPointAo { + private Integer defaultLevel; + private Integer level1; + private Double level1Distance; + private Integer level2; + private Double level2Distance; + private Integer level3; + private Double level3Distance; + private Integer level4; + private Double level4Distance; + private Boolean category; + private Double minX; + private Double minY; + private Double maxX; + private Double maxY; + + public Integer getDefaultLevel() { + return defaultLevel; + } + + public void setDefaultLevel(Integer defaultLevel) { + this.defaultLevel = defaultLevel; + } + + public Integer getLevel1() { + return level1; + } + + public void setLevel1(Integer level1) { + this.level1 = level1; + } + + public Double getLevel1Distance() { + return level1Distance; + } + + public void setLevel1Distance(Double level1Distance) { + this.level1Distance = level1Distance; + } + + public Integer getLevel2() { + return level2; + } + + public void setLevel2(Integer level2) { + this.level2 = level2; + } + + public Double getLevel2Distance() { + return level2Distance; + } + + public void setLevel2Distance(Double level2Distance) { + this.level2Distance = level2Distance; + } + + public Integer getLevel3() { + return level3; + } + + public void setLevel3(Integer level3) { + this.level3 = level3; + } + + public Double getLevel3Distance() { + return level3Distance; + } + + public void setLevel3Distance(Double level3Distance) { + this.level3Distance = level3Distance; + } + + public Integer getLevel4() { + return level4; + } + + public void setLevel4(Integer level4) { + this.level4 = level4; + } + + public Double getLevel4Distance() { + return level4Distance; + } + + public void setLevel4Distance(Double level4Distance) { + this.level4Distance = level4Distance; + } + + public Boolean getCategory() { + return category; + } + + public void setCategory(Boolean category) { + this.category = category; + } + + public Double getMinX() { + return minX; + } + + public void setMinX(Double minX) { + this.minX = minX; + } + + public Double getMinY() { + return minY; + } + + public void setMinY(Double minY) { + this.minY = minY; + } + + public Double getMaxX() { + return maxX; + } + + public void setMaxX(Double maxX) { + this.maxX = maxX; + } + + public Double getMaxY() { + return maxY; + } + + public void setMaxY(Double maxY) { + this.maxY = maxY; + } + } +} \ No newline at end of file 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..d5f145ee 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 @@ -7,10 +7,7 @@ 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; +import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/wte") @@ -21,6 +18,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 +60,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 +96,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) { @@ -92,4 +155,34 @@ public class WeFishController { public ResponseResult getTeSpecialAnimalList(@RequestBody DataSourceRequest dataSourceRequest) { return ResponseResult.successData(weFishService.getTeSpecialAnimalList(dataSourceRequest)); } + + @GetMapping("/we/wer/getWeDefaultData") + @Operation(summary = "查询水生生态断面的年份及是否鱼类,水温,水质,流速数据") + public ResponseResult getWeDefaultData(@RequestParam("stcd") String stcd) { + return ResponseResult.successData(weFishService.getWeDefaultData(stcd)); + } + + @GetMapping("/we/wer/getWeYr") + @Operation(summary = "查询水生生态断面有数据的年份") + public ResponseResult getWeYr(@RequestParam("stcd") String stcd) { + return ResponseResult.successData(weFishService.getWeYr(stcd)); + } + + @PostMapping("/we/wewtr/GetKendoListCust") + @Operation(summary = "水生生态调查-水温数据列表") + public ResponseResult getWeWtR(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(weFishService.getWeWtR(dataSourceRequest)); + } + + @PostMapping("/we/wewqr/GetKendoListCust") + @Operation(summary = "水生生态调查-水质数据列表") + public ResponseResult getWeWqR(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(weFishService.getWeWqR(dataSourceRequest)); + } + + @PostMapping("/we/fvR/GetKendoListCust") + @Operation(summary = "水生生态调查-流速数据列表") + public ResponseResult getWeFvR(@RequestBody DataSourceRequest dataSourceRequest) { + return ResponseResult.successData(weFishService.getWeFvR(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/WeDefaultDataVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeDefaultDataVo.java new file mode 100644 index 00000000..afaafca0 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeDefaultDataVo.java @@ -0,0 +1,16 @@ +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 WeDefaultDataVo { + + private String yr; + private Integer hasFtp; + private Integer hasFv; + private Integer hasWq; + private Integer hasWt; + +} 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/WeFvVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFvVo.java new file mode 100644 index 00000000..0db148d6 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeFvVo.java @@ -0,0 +1,15 @@ +package com.yfd.platform.qgc_env.wte.entity.vo; + +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +@Data +public class WeFvVo { + private String dcpc; + private String stcd; + private Date tm; + private BigDecimal flowrate; + private String fid; +} \ No newline at end of file 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/WeWqVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeWqVo.java new file mode 100644 index 00000000..6600e9c2 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeWqVo.java @@ -0,0 +1,51 @@ +package com.yfd.platform.qgc_env.wte.entity.vo; + +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +@Data +public class WeWqVo { + private String stcd; + private String dcpc; + private String name; + private Date tm; + private BigDecimal ph; + private BigDecimal dox; + private BigDecimal codmn; + private BigDecimal codcr; + private BigDecimal bod5; + private BigDecimal nh3n; + private BigDecimal tp; + private BigDecimal tn; + private BigDecimal cu; + private BigDecimal zn; + private BigDecimal f; + private BigDecimal se; + private BigDecimal ars; + private BigDecimal hg; + private BigDecimal cd; + private BigDecimal cr6; + private BigDecimal pb; + private BigDecimal cn; + private BigDecimal vlph; + private BigDecimal oil; + private BigDecimal las; + private BigDecimal s2; + private BigDecimal fcg; + private BigDecimal cl; + private BigDecimal so4; + private BigDecimal no3; + private BigDecimal thrd; + private BigDecimal cond; + private BigDecimal fe; + private BigDecimal mn; + private BigDecimal al; + private BigDecimal chla; + private BigDecimal clarity; + private BigDecimal tu; + private BigDecimal cyano; + private String fid; + private Integer parameter; +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeWtVo.java b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeWtVo.java new file mode 100644 index 00000000..70bffdb7 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_env/wte/entity/vo/WeWtVo.java @@ -0,0 +1,18 @@ +package com.yfd.platform.qgc_env.wte.entity.vo; + +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +@Data +public class WeWtVo { + + private String dcpc; + + private String stcd; + + private Date tm; + + private BigDecimal wt; +} \ No newline at end of file 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..ba33bd32 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 @@ -2,23 +2,15 @@ package com.yfd.platform.qgc_env.wte.service; import com.yfd.platform.common.DataSourceRequest; import com.yfd.platform.common.DataSourceResult; -import com.yfd.platform.qgc_env.wte.entity.vo.WeFishListQgcVo; -import com.yfd.platform.qgc_env.wte.entity.vo.WeFishListStatQgcVo; -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.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.WeWvaQgcVo; -import com.yfd.platform.qgc_env.wte.entity.vo.WeWvaYearQgcVo; +import com.yfd.platform.qgc_env.wte.entity.vo.*; import java.util.List; import java.util.Map; public interface WeFishService { + DataSourceResult getWeFishTKendoListCust(DataSourceRequest dataSourceRequest); + DataSourceResult getQgcWeFishTKendoListCust(DataSourceRequest dataSourceRequest); DataSourceResult getQgcWeFishList(DataSourceRequest dataSourceRequest); @@ -29,17 +21,47 @@ 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); DataSourceResult getTeSpecialAnimalList(DataSourceRequest dataSourceRequest); + + List getWeDefaultData(String stcd); + + DataSourceResult getWeYr(String stcd); + + DataSourceResult getWeWtR(DataSourceRequest dataSourceRequest); + + DataSourceResult getWeWqR(DataSourceRequest dataSourceRequest); + + DataSourceResult getWeFvR(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..35996aa1 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,19 +10,9 @@ 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.WeFishListQgcVo; -import com.yfd.platform.qgc_env.wte.entity.vo.WeFishListStatQgcVo; -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.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.WeWvaQgcVo; -import com.yfd.platform.qgc_env.wte.entity.vo.WeWvaYearQgcVo; +import com.yfd.platform.qgc_env.wte.entity.vo.*; import com.yfd.platform.qgc_env.wte.service.WeFishService; +import com.yfd.platform.utils.KendoUtil; import com.yfd.platform.utils.QgcQueryWrapperUtil; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; @@ -45,6 +35,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 +308,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 +410,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 +782,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<>(); @@ -525,6 +1103,585 @@ public class WeFishServiceImpl implements WeFishService { return result; } + @Override + public List getWeDefaultData(String stcd) { + String sql = "SELECT\n" + + "\ta.stcd,\n" + + "\tTO_CHAR( a.TM, 'yyyy' ) AS yr,\n" + + "CASE\n" + + "\t\t\n" + + "\t\tWHEN COUNT( b.ID ) > 0 THEN\n" + + "\t\t1 ELSE 0 \n" + + "\tEND AS hasFtp,\n" + + "CASE\n" + + "\t\t\n" + + "\t\tWHEN COUNT( c.ID ) > 0 THEN\n" + + "\t\t1 ELSE 0 \n" + + "\tEND AS hasFv,\n" + + "CASE\n" + + "\t\t\n" + + "\t\tWHEN COUNT( d.ID ) > 0 THEN\n" + + "\t\t1 ELSE 0 \n" + + "\tEND AS hasWq,\n" + + "CASE\n" + + "\t\t\n" + + "\t\tWHEN COUNT( e.ID ) > 0 THEN\n" + + "\t\t1 ELSE 0 \n" + + "\tEND AS hasWt \n" + + "FROM\n" + + "\tSD_WE_R a\n" + + "\tLEFT JOIN SD_WEFISH_R b ON a.ID = b.WER_ID \n" + + "\tAND b.IS_DELETED = 0\n" + + "\tLEFT JOIN SD_WEFV_R c ON a.ID = c.WER_ID \n" + + "\tAND c.IS_DELETED = 0\n" + + "\tLEFT JOIN SD_WEWQ_R d ON a.ID = d.WER_ID \n" + + "\tAND d.IS_DELETED = 0\n" + + "\tLEFT JOIN SD_WEWT_R e ON a.ID = e.WER_ID \n" + + "\tAND e.IS_DELETED = 0 \n" + + "WHERE\n" + + "\t1 = 1 \n" + + "\tAND a.IS_DELETED = 0 \n" + + "\tAND a.stcd = #{map.stcd} \n" + + "GROUP BY\n" + + "\ta.stcd,\n" + + "\tTO_CHAR( a.TM, 'yyyy' ) \n" + + "ORDER BY\n" + + "\tTO_CHAR( a.TM, 'yyyy' ) DESC,\n" + + "\ta.stcd\n" + + "\n"; + Map paramMap = new HashMap<>(); + paramMap.put("stcd", stcd); + List oneBySqlWithResultType = microservicDynamicSQLMapper.getAllListWithResultType(sql, paramMap, WeDefaultDataVo.class); + return oneBySqlWithResultType; + } + + @Override + public DataSourceResult getWeYr(String stcd) { + DataSourceResult dataSourceResult = new DataSourceResult(); + StringBuilder sql = new StringBuilder(); + sql.append("SELECT TO_CHAR(TM, 'yyyy') AS yr FROM SD_WE_R ") + .append("WHERE NVL(IS_DELETED, 0) = 0 AND NVL(STATUS, 1) = 1 "); + if (StrUtil.isNotBlank(stcd)) { + sql.append("AND STCD = #{map.stcd} "); + } + sql.append("GROUP BY TO_CHAR(TM, 'yyyy') ") + .append("ORDER BY TO_CHAR(TM, 'yyyy') DESC"); + + Map paramMap = new HashMap<>(); + if (StrUtil.isNotBlank(stcd)) { + paramMap.put("stcd", stcd); + } + List yrList = microservicDynamicSQLMapper.getSingleColumnList(sql.toString(), paramMap); + dataSourceResult.setData(yrList); + dataSourceResult.setTotal(yrList == null ? 0L : yrList.size()); + return dataSourceResult; + } + + @Override + public DataSourceResult getWeWtR(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + GroupingInfo[] groupInfos = loadOptions == null ? null : loadOptions.getGroup(); + Map paramMap = new HashMap<>(); + + StringBuilder sql = new StringBuilder(); + sql.append("SELECT t.DCPC, t.STCD, t1.WT AS wt, t.TM FROM SD_WE_R t ") + .append("INNER JOIN SD_WEWT_R t1 ON t.ID = t1.WER_ID ") + .append("WHERE NVL(t.IS_DELETED, 0) = 0 AND NVL(t1.IS_DELETED, 0) = 0 "); + + String filterSql = buildWeWtFilterCondition( + dataSourceRequest == null ? null : dataSourceRequest.getFilter(), + paramMap, + new int[]{0} + ); + if (StrUtil.isNotBlank(filterSql)) { + sql.append("AND ").append(filterSql).append(" "); + } + + DataSourceResult result = new DataSourceResult<>(); + if (CollUtil.isNotEmpty(dataSourceRequest == null ? null : dataSourceRequest.getGroup())) { + String groupBy = KendoUtil.getGroupBy(dataSourceRequest); + if (StrUtil.isNotBlank(groupBy)) { + List groupFields = new ArrayList<>(); + for (GroupingInfo item : groupInfos) { + if (item != null && StrUtil.isNotBlank(item.getSelector())) { + groupFields.add(item.getSelector()); + } + } + StringBuilder temp = new StringBuilder(); + temp.append("SELECT ").append(String.join(",", groupFields)).append(", count(*) as "); + if (groupInfos.length > 1) { + temp.append("count"); + } else { + temp.append("count_").append(String.join("_", groupFields)); + } + String groupedSql = temp.append(" FROM ( ").append(sql).append(" ) ").append(groupBy).toString(); + 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(buildWeWtOrderBySql(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, WeWtVo.class); + + result.setData(list); + result.setTotal(page != null ? page.getTotal() : list.size()); + result.setAggregates(new HashMap<>()); + return result; + } + + private String buildWeWtFilterCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + if (filter == null) { + return ""; + } + if (StrUtil.isNotBlank(filter.getField())) { + return buildWeWtLeafCondition(filter, paramMap, indexHolder); + } + if (CollUtil.isEmpty(filter.getFilters())) { + return ""; + } + List conditions = new ArrayList<>(); + for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) { + String childSql = buildWeWtFilterCondition(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 buildWeWtLeafCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + String column = mapWeWtColumn(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 = normalizeWeFishQgcValues(filter.getValue()); + if (values.isEmpty()) { + return ""; + } + List placeholders = new ArrayList<>(); + boolean isDateField = "t.tm".equals(column); + for (Object value : values) { + String paramKey = "weWtParam" + indexHolder[0]++; + paramMap.put(paramKey, value); + if (isDateField) { + String text = String.valueOf(value).trim(); + if (text.length() <= 10) { + placeholders.add("TO_DATE(#{map." + paramKey + "}, 'YYYY-MM-DD')"); + } else { + placeholders.add("TO_DATE(#{map." + paramKey + "}, 'YYYY-MM-DD HH24:MI:SS')"); + } + } else { + placeholders.add("#{map." + paramKey + "}"); + } + } + String prefix = "ni".equals(operator) ? "NOT " : ""; + return column + " " + prefix + "IN (" + String.join(", ", placeholders) + ")"; + } + String paramKey = "weWtParam" + indexHolder[0]++; + paramMap.put(paramKey, filter.getValue()); + boolean isDateField = "t.tm".equals(column); + String valueExpr; + if (isDateField) { + String text = String.valueOf(filter.getValue()).trim(); + if (text.length() <= 10) { + valueExpr = "TO_DATE(#{map." + paramKey + "}, 'YYYY-MM-DD')"; + } else { + valueExpr = "TO_DATE(#{map." + paramKey + "}, 'YYYY-MM-DD HH24:MI:SS')"; + } + } else { + valueExpr = "#{map." + paramKey + "}"; + } + return switch (operator) { + case "lt", "lessthan" -> column + " < " + valueExpr; + case "lte", "lessthanorequals" -> column + " <= " + valueExpr; + case "gt", "greaterthan" -> column + " > " + valueExpr; + case "gte", "greaterthanorequals" -> column + " >= " + valueExpr; + case "ne", "notequals" -> column + " <> " + valueExpr; + case "contains", "doesnotcontain", "startswith", "endswith" -> { + String pattern = switch (operator) { + case "contains" -> "%#{map." + paramKey + "}%"; + case "doesnotcontain" -> "%#{map." + paramKey + "}%"; + case "startswith" -> "#{map." + paramKey + "}%"; + case "endswith" -> "%#{map." + paramKey + "}"; + default -> "%#{map." + paramKey + "}%"; + }; + String likePrefix = "doesnotcontain".equals(operator) ? "NOT " : ""; + yield column + " " + likePrefix + "LIKE " + pattern; + } + default -> column + " = " + valueExpr; + }; + } + + private String mapWeWtColumn(String field) { + if (StrUtil.isBlank(field)) { + return null; + } + return switch (field.toLowerCase()) { + case "dcpc" -> "t.dcpc"; + case "stcd" -> "t.stcd"; + case "wt" -> "t1.wt"; + case "tm" -> "t.tm"; + default -> null; + }; + } + + private String buildWeWtOrderBySql(List sorts) { + if (CollUtil.isEmpty(sorts)) { + return " ORDER BY t.tm DESC NULLS LAST, t.stcd ASC"; + } + List orderByParts = new ArrayList<>(); + for (DataSourceRequest.SortDescriptor sort : sorts) { + if (sort == null || StrUtil.isBlank(sort.getField())) { + continue; + } + String column = mapWeWtColumn(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 t.tm DESC NULLS LAST, t.stcd ASC"; + } + return " ORDER BY " + String.join(", ", orderByParts); + } + + @Override + public DataSourceResult getWeWqR(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + GroupingInfo[] groupInfos = loadOptions == null ? null : loadOptions.getGroup(); + Map paramMap = new HashMap<>(); + + StringBuilder sql = new StringBuilder(); + sql.append("SELECT t.DCPC, t.STCD, t1.TM, t1.NAME, t1.PH, t1.DOX, t1.CODMN, t1.CODCR, t1.BOD5, t1.NH3N ") + .append(", t1.TP, t1.TN, t1.CU, t1.ZN, t1.F, t1.SE, t1.ARS, t1.HG, t1.CD, t1.CR6, t1.PB, t1.CN, t1.VLPH, t1.OIL ") + .append(", t1.LAS, t1.S2, t1.FCG, t1.CL, t1.SO4, t1.NO3, t1.THRD, t1.COND, t1.FE, t1.MN, t1.AL, t1.CHLA ") + .append(", t1.CLARITY, t1.TU, t1.CYANO, t1.FID, t1.PARAMETER ") + .append("FROM SD_WE_R t ") + .append("INNER JOIN SD_WEWQ_R t1 ON t.ID = t1.WER_ID ") + .append("WHERE NVL(t.IS_DELETED, 0) = 0 AND NVL(t1.IS_DELETED, 0) = 0 "); + + String filterSql = buildWeWqFilterCondition( + dataSourceRequest == null ? null : dataSourceRequest.getFilter(), + paramMap, + new int[]{0} + ); + if (StrUtil.isNotBlank(filterSql)) { + sql.append("AND ").append(filterSql).append(" "); + } + + DataSourceResult result = new DataSourceResult<>(); + if (CollUtil.isNotEmpty(dataSourceRequest == null ? null : dataSourceRequest.getGroup())) { + String groupBy = KendoUtil.getGroupBy(dataSourceRequest); + if (StrUtil.isNotBlank(groupBy)) { + List groupFields = new ArrayList<>(); + for (GroupingInfo item : groupInfos) { + if (item != null && StrUtil.isNotBlank(item.getSelector())) { + groupFields.add(item.getSelector()); + } + } + StringBuilder temp = new StringBuilder(); + temp.append("SELECT ").append(String.join(",", groupFields)).append(", count(*) as "); + if (groupInfos.length > 1) { + temp.append("count"); + } else { + temp.append("count_").append(String.join("_", groupFields)); + } + String groupedSql = temp.append(" FROM ( ").append(sql).append(" ) ").append(groupBy).toString(); + 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(buildWeWqOrderBySql(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, WeWqVo.class); + + result.setData(list); + result.setTotal(page != null ? page.getTotal() : list.size()); + result.setAggregates(new HashMap<>()); + return result; + } + + private String buildWeWqFilterCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + if (filter == null) { + return ""; + } + List conditions = new ArrayList<>(); + List filters = filter.getFilters(); + if (CollUtil.isNotEmpty(filters)) { + for (DataSourceRequest.FilterDescriptor child : filters) { + String condition = buildWeWqFilterCondition(child, paramMap, indexHolder); + if (StrUtil.isNotBlank(condition)) { + conditions.add(condition); + } + } + } else { + String leafCondition = buildWeWqLeafCondition(filter, paramMap, indexHolder); + if (StrUtil.isNotBlank(leafCondition)) { + conditions.add(leafCondition); + } + } + if (conditions.isEmpty()) { + return ""; + } + String logic = "or".equalsIgnoreCase(filter.getLogic()) ? " OR " : " AND "; + return "(" + String.join(logic, conditions) + ")"; + } + + private String buildWeWqLeafCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder) { + String column = mapWeWqColumn(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 = normalizeWeFishQgcValues(filter.getValue()); + if (values.isEmpty()) { + return ""; + } + List placeholders = new ArrayList<>(); + boolean isDateField = "t1.tm".equals(column); + for (Object value : values) { + String paramKey = "weWqParam" + indexHolder[0]++; + paramMap.put(paramKey, value); + if (isDateField) { + String text = String.valueOf(value).trim(); + if (text.length() <= 10) { + placeholders.add("TO_DATE(#{map." + paramKey + "}, 'YYYY-MM-DD')"); + } else { + placeholders.add("TO_DATE(#{map." + paramKey + "}, 'YYYY-MM-DD HH24:MI:SS')"); + } + } else { + placeholders.add("#{map." + paramKey + "}"); + } + } + String prefix = "ni".equals(operator) ? "NOT " : ""; + return column + " " + prefix + "IN (" + String.join(", ", placeholders) + ")"; + } + String paramKey = "weWqParam" + indexHolder[0]++; + paramMap.put(paramKey, filter.getValue()); + boolean isDateField = "t1.tm".equals(column); + String valueExpr; + if (isDateField) { + String text = String.valueOf(filter.getValue()).trim(); + if (text.length() <= 10) { + valueExpr = "TO_DATE(#{map." + paramKey + "}, 'YYYY-MM-DD')"; + } else { + valueExpr = "TO_DATE(#{map." + paramKey + "}, 'YYYY-MM-DD HH24:MI:SS')"; + } + } else { + valueExpr = "#{map." + paramKey + "}"; + } + return switch (operator) { + case "lt", "lessthan" -> column + " < " + valueExpr; + case "lte", "lessthanorequals" -> column + " <= " + valueExpr; + case "gt", "greaterthan" -> column + " > " + valueExpr; + case "gte", "greaterthanorequals" -> column + " >= " + valueExpr; + case "ne", "notequals" -> column + " <> " + valueExpr; + case "contains", "doesnotcontain", "startswith", "endswith" -> { + String pattern = switch (operator) { + case "contains" -> "%#{map." + paramKey + "}%"; + case "doesnotcontain" -> "%#{map." + paramKey + "}%"; + case "startswith" -> "#{map." + paramKey + "}%"; + case "endswith" -> "%#{map." + paramKey + "}"; + default -> "%#{map." + paramKey + "}%"; + }; + String likePrefix = "doesnotcontain".equals(operator) ? "NOT " : ""; + yield column + " " + likePrefix + "LIKE " + pattern; + } + default -> column + " = " + valueExpr; + }; + } + + private String mapWeWqColumn(String field) { + if (StrUtil.isBlank(field)) { + return null; + } + return switch (field.toLowerCase()) { + case "dcpc" -> "t.dcpc"; + case "stcd" -> "t.stcd"; + case "name" -> "t1.name"; + case "tm" -> "t1.tm"; + case "ph" -> "t1.ph"; + case "dox" -> "t1.dox"; + case "codmn" -> "t1.codmn"; + case "codcr" -> "t1.codcr"; + case "bod5" -> "t1.bod5"; + case "nh3n" -> "t1.nh3n"; + case "tp" -> "t1.tp"; + case "tn" -> "t1.tn"; + case "cu" -> "t1.cu"; + case "zn" -> "t1.zn"; + case "f" -> "t1.f"; + case "se" -> "t1.se"; + case "ars" -> "t1.ars"; + case "hg" -> "t1.hg"; + case "cd" -> "t1.cd"; + case "cr6" -> "t1.cr6"; + case "pb" -> "t1.pb"; + case "cn" -> "t1.cn"; + case "vlph" -> "t1.vlph"; + case "oil" -> "t1.oil"; + case "las" -> "t1.las"; + case "s2" -> "t1.s2"; + case "fcg" -> "t1.fcg"; + case "cl" -> "t1.cl"; + case "so4" -> "t1.so4"; + case "no3" -> "t1.no3"; + case "thrd" -> "t1.thrd"; + case "cond" -> "t1.cond"; + case "fe" -> "t1.fe"; + case "mn" -> "t1.mn"; + case "al" -> "t1.al"; + case "chla" -> "t1.chla"; + case "clarity" -> "t1.clarity"; + case "tu" -> "t1.tu"; + case "cyano" -> "t1.cyano"; + case "fid" -> "t1.fid"; + case "parameter" -> "t1.parameter"; + default -> null; + }; + } + + private String buildWeWqOrderBySql(List sorts) { + if (CollUtil.isEmpty(sorts)) { + return " ORDER BY t1.tm DESC NULLS LAST, t.stcd ASC"; + } + List orderByParts = new ArrayList<>(); + for (DataSourceRequest.SortDescriptor sort : sorts) { + if (sort == null || StrUtil.isBlank(sort.getField())) { + continue; + } + String column = mapWeWqColumn(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 t1.tm DESC NULLS LAST, t.stcd ASC"; + } + return " ORDER BY " + String.join(", ", orderByParts); + } + + @Override + public DataSourceResult getWeFvR(DataSourceRequest dataSourceRequest) { + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + Map paramMap = new HashMap<>(); + + StringBuilder sql = new StringBuilder(); + sql.append("SELECT t.DCPC, t.STCD, t1.TM, t1.FLOW_RATE AS flowrate, t1.FID ") + .append("FROM SD_WE_R t ") + .append("INNER JOIN SD_WEFV_R t1 ON t.ID = t1.WER_ID ") + .append("WHERE NVL(t.IS_DELETED, 0) = 0 AND NVL(t1.IS_DELETED, 0) = 0 "); + + String filterSql = QgcQueryWrapperUtil.buildFilterCondition( + dataSourceRequest == null ? null : dataSourceRequest.getFilter(), + paramMap, + new int[]{0}, + this::mapWeFvColumn + ); + if (StrUtil.isNotBlank(filterSql)) { + sql.append("AND ").append(filterSql).append(" "); + } + + DataSourceResult result = new DataSourceResult<>(); + String groupSql = QgcQueryWrapperUtil.buildGroupSql(dataSourceRequest, sql); + if (StrUtil.isNotBlank(groupSql)) { + List> rows = microservicDynamicSQLMapper.getAllList(groupSql, paramMap); + return QgcQueryWrapperUtil.buildGroupResult(dataSourceRequest, rows); + } + + sql.append(QgcQueryWrapperUtil.buildOrderBySql( + dataSourceRequest == null ? null : dataSourceRequest.getSort(), + this::mapWeFvColumn, + "t1.TM DESC NULLS LAST, t.STCD ASC" + )); + + Page page = loadOptions == null ? null + : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + List list = microservicDynamicSQLMapper.pageAllListWithResultType(page, sql.toString(), paramMap, WeFvVo.class); + + result.setData(list); + result.setTotal(page != null ? page.getTotal() : list.size()); + result.setAggregates(new HashMap<>()); + return result; + } + + private String mapWeFvColumn(String field) { + if (StrUtil.isBlank(field)) { + return null; + } + return switch (field.toLowerCase()) { + case "dcpc" -> "t.dcpc"; + case "stcd" -> "t.stcd"; + case "tm" -> "t1.tm"; + case "flowrate" -> "t1.flow_rate"; + case "fid" -> "t1.fid"; + default -> null; + }; + } + private String buildWeFishQgcGroupSql(String baseSql, GroupingInfo[] groupInfos) { if (groupInfos == null || groupInfos.length == 0) { return baseSql; @@ -679,14 +1836,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 +1898,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 +2807,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 +3725,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 +3806,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 +3826,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 +3970,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 +4030,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 +4120,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 +4661,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..a573ce04 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,59 @@ 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.cache.annotation.Cacheable; +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,12 +83,20 @@ public class ZqMonitorServiceImpl implements ZqMonitorService { @Resource private JdbcTemplate jdbcTemplate; + @Resource + private MsOperationLogMapper msOperationLogMapper; + + @Resource + private MsOperationLogDetailMapper msOperationLogDetailMapper; + @Override + @Cacheable(cacheNames = "zqCache#7200", keyGenerator = "cacheKeyGenerator") public DataSourceResult getMsstbprptList(DataSourceRequest dataSourceRequest) { return getMsstbprptListInternal(dataSourceRequest, false); } @Override + @Cacheable(cacheNames = "zqCache#7200", keyGenerator = "cacheKeyGenerator") public DataSourceResult getEngMsstbprptList(DataSourceRequest dataSourceRequest) { DataSourceRequest request = dataSourceRequest == null ? new DataSourceRequest() : dataSourceRequest; request.setSelect(Arrays.asList("stcd", "stnm", "wtDeviceType", "dtinType", "mway")); @@ -63,13 +111,13 @@ public class ZqMonitorServiceImpl implements ZqMonitorService { .append(buildMsstbprptDetailSelectSql(dataSourceRequest == null ? null : dataSourceRequest.getSelect())) .append(" FROM SD_RIVER_B_H t ") .append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = t.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ") - .append("LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = eng.BASE_ID AND NVL(hb.IS_DELETED, 0) = 0 ") - .append("LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = eng.HBRVCD ") - .append(" AND hbrv.BASEID = eng.BASE_ID ") - .append(" AND hbrv.IS_DELETED = 0 ") - .append(" AND hbrv.ENABLED = 1 ") - .append("LEFT JOIN SD_RVCD_DIC rv ON rv.RVCD = eng.RVCD ") - .append("LEFT JOIN SD_ADDVCD_DIC addv ON addv.ADDVCD = eng.ADDVCD ") +// .append("LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = eng.BASE_ID AND NVL(hb.IS_DELETED, 0) = 0 ") +// .append("LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = eng.HBRVCD ") +// .append(" AND hbrv.BASEID = eng.BASE_ID ") +// .append(" AND hbrv.IS_DELETED = 0 ") +// .append(" AND hbrv.ENABLED = 1 ") +// .append("LEFT JOIN SD_RVCD_DIC rv ON rv.RVCD = eng.RVCD ") +// .append("LEFT JOIN SD_ADDVCD_DIC addv ON addv.ADDVCD = eng.ADDVCD ") .append("WHERE t.IS_DELETED = 0 "); if (onlyZq) { sql.append("AND t.STTP = 'ZQ' "); @@ -170,11 +218,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 +260,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 +275,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 +1669,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/qgc_sys/mapLayer/controller/MapLayerController.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/controller/MapLayerController.java new file mode 100644 index 00000000..84c0ef86 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/controller/MapLayerController.java @@ -0,0 +1,90 @@ +package com.yfd.platform.qgc_sys.mapLayer.controller; + +import cn.hutool.core.util.StrUtil; +import com.yfd.platform.common.DataSourceResult; +import com.yfd.platform.common.exception.BizException; +import com.yfd.platform.config.ResponseResult; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaplayerB; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaplegendB; +import com.yfd.platform.qgc_sys.mapLayer.entity.vo.MapLayerAo; +import com.yfd.platform.qgc_sys.mapLayer.service.IMapLayerBizService; +import com.yfd.platform.qgc_sys.mapLayer.service.IMapLayerService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 地图图层管理 + * + * @author migration + */ +@RestController +@RequestMapping("/mapLayer") +@Tag(name = "地图图层管理") +public class MapLayerController { + + @Resource + private IMapLayerBizService mapLayerBizService; + + @Resource + private IMapLayerService layerService; + + /** + * 地图图层管理图层树(所有) + */ + @Operation(summary = "地图图层管理图层树(所有)") + @PostMapping("/getAllMapLayerTree") + public ResponseResult getAllMapLayerTree(@RequestBody MapLayerAo flag) { + List tree = mapLayerBizService.getMapLayerTree(flag); + // 构建 Kendo 数据源结果 + DataSourceResult dataSourceResult = new DataSourceResult<>(); + dataSourceResult.setData(tree); + // 计算总节点数 + long total = countTreeNodes(tree); + dataSourceResult.setTotal(tree.size()); + return ResponseResult.successData(dataSourceResult); + } + private long countTreeNodes(List nodes) { + if (nodes == null) return 0; + long count = 0; + for (MsMaplayerB node : nodes) { + count++; // 当前节点 + if (node.getChildren() != null && !node.getChildren().isEmpty()) { + count += countTreeNodes(node.getChildren()); + } + } + return count; + } + + /** + * 图层新增修改 + */ + @Operation(summary = "图层新增修改") + @PostMapping("/save") + public ResponseResult addLayer(@RequestBody MsMaplayerB layer) { + if (layer == null) { + return ResponseResult.error("图层信息不能为空."); + } + if (StrUtil.isBlank(layer.getCode())) { + throw new BizException("图层编码(code)不能为空."); + } + if (StrUtil.isBlank(layer.getTitle())) { + throw new BizException("图层名称(title)不能为空."); + } + layerService.saveOrUpdate(layer); + return ResponseResult.success("保存成功."); + } + + /** + * 图层删除 + */ + @Operation(summary = "图层删除") + @PostMapping("/delete") + public ResponseResult deleteLayer(@RequestBody List ids) { + layerService.delelteByIds(ids); + return ResponseResult.success("删除成功."); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/controller/MapLegendController.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/controller/MapLegendController.java new file mode 100644 index 00000000..87e3187a --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/controller/MapLegendController.java @@ -0,0 +1,209 @@ +package com.yfd.platform.qgc_sys.mapLayer.controller; + + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +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_sys.mapLayer.domain.MsMaplayerB; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaplegendB; +import com.yfd.platform.qgc_sys.mapLayer.mapper.MsMaplayerBMapper; +import com.yfd.platform.qgc_sys.mapLayer.service.IMapLayerService; +import com.yfd.platform.qgc_sys.mapLayer.service.IMapLegendService; +import com.yfd.platform.qgc_sys.mapLayer.entity.vo.MapLegendVo; +import com.yfd.platform.qgc_sys.mapLayer.service.IMapLegendBizService; +import com.yfd.platform.utils.DataSourceRequestUtil; +import com.yfd.platform.utils.SecurityUtils; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 地图图例管理 + * + * @author migration + */ +@RestController +@RequestMapping("/mapLegend") +@Tag(name = "地图图例管理") +public class MapLegendController { + + @Resource + private IMapLegendService mapLegendService; + + @Resource + private IMapLegendBizService mapLegendBizService; + + @Resource + private MsMaplayerBMapper msMaplayerBMapper; // 新增注入 + /** + * 条件过滤数据列表(Kendo UI 数据源) + */ + @Operation(summary = "条件过滤数据列表") + @PostMapping("/GetKendoList") + public ResponseResult getKendoList(@RequestBody DataSourceRequest dataSourceRequest) { + // 构建查询条件 + QueryWrapper wrapper = DataSourceRequestUtil.buildQueryWrapper( + dataSourceRequest, MsMaplegendB.class); + + // 执行分页查询 + Page page = DataSourceRequestUtil.getPage(dataSourceRequest); + Page resultPage; + if (page != null) { + resultPage = mapLegendService.page(page, wrapper); + } else { + List list = mapLegendService.list(wrapper); + resultPage = new Page<>(); + resultPage.setRecords(list); + resultPage.setTotal(list.size()); + } + + List records = resultPage.getRecords(); + if (records != null && !records.isEmpty()) { + // ---------- 2. 批量获取父级信息(用于 parentCode、parentName)---------- + Set parentIds = records.stream() + .filter(e -> e.getDataType() != null && e.getDataType() == 2) // 只处理图例数据 + .map(MsMaplegendB::getParentId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + Map parentMap = new HashMap<>(); + if (!parentIds.isEmpty()) { + List parents = mapLegendService.listByIds(parentIds); + parentMap = parents.stream() + .collect(Collectors.toMap(MsMaplegendB::getId, Function.identity())); + } + + // ---------- 3. 批量获取图层名称(根据 layerCode 查 MS_MAPLAYER_B)---------- + Set layerCodes = records.stream() + .map(MsMaplegendB::getLayerCode) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + Map layerCodeNameMap = new HashMap<>(); + if (!layerCodes.isEmpty()) { + // 使用 Mapper 查询 + List layerList = msMaplayerBMapper.selectList( + new LambdaQueryWrapper() + .in(MsMaplayerB::getCode, layerCodes) + ); + layerCodeNameMap = layerList.stream() + .collect(Collectors.toMap(MsMaplayerB::getCode, MsMaplayerB::getTitle)); + } + + // ---------- 4. 遍历记录,填充三个额外字段 ---------- + for (MsMaplegendB entity : records) { + // 4.1 填充 parentCode / parentName(仅 dataType=2) + if (entity.getDataType() != null && entity.getDataType() == 2) { + String parentId = entity.getParentId(); + if (parentId != null && parentMap.containsKey(parentId)) { + MsMaplegendB parent = parentMap.get(parentId); + entity.setParentCode(parent.getCode()); + entity.setParentName(parent.getName()); + } else { + entity.setParentCode(null); + entity.setParentName(null); + } + } else { + // 非 dataType=2 的记录,这两个字段置空 + entity.setParentCode(null); + entity.setParentName(null); + } + + // 4.2 填充 layerCodeName(所有记录均可填充,如果图层不存在则置空) + String layerCode = entity.getLayerCode(); + if (layerCode != null && layerCodeNameMap.containsKey(layerCode)) { + entity.setLayerCodeName(layerCodeNameMap.get(layerCode)); + } else { + entity.setLayerCodeName(null); + } + } + } + + // 构建 Kendo 数据源结果 + DataSourceResult dataSourceResult = new DataSourceResult<>(); + dataSourceResult.setData(resultPage.getRecords()); + dataSourceResult.setTotal(resultPage.getTotal()); + + return ResponseResult.successData(dataSourceResult); + } + + /** + * 图例新增修改 + */ + @Operation(summary = "图例新增修改") + @PostMapping("/save") + public ResponseResult addLayer(@RequestBody MsMaplegendB legend) { + if (legend == null) { + return ResponseResult.error("图例信息不能为空."); + } + if (StrUtil.isBlank(legend.getCode())) { + throw new BizException("图例类型(code: pointLayer=用于锚点,baseLayer=地图GIS)不能为空."); + } + if (StrUtil.isBlank(legend.getName())) { + throw new BizException("图例名称(name)不能为空."); + } + if (StrUtil.isBlank(legend.getNameEn())) { + throw new BizException("图例编码(nameEn)不能为空."); + } + if (legend.getDataType() == null) { + throw new BizException("图例数据类型(dataType: 1=结构,2=数据)不能为空."); + } + if (legend.getDataType() == 2 && StrUtil.isBlank(legend.getLayerCode())) { + throw new BizException("关联的图层编码(layerCode)不能为空."); + } + if (StrUtil.isNotBlank(legend.getName())){ + if(StrUtil.isBlank(legend.getGroupName())){ + legend.setGroupName(legend.getName()); + } + if(StrUtil.isBlank(legend.getParentName())){ + legend.setGroupName(legend.getName()); + } + } + legend.setRecordUser(SecurityUtils.getUserId()); + mapLegendService.saveOrUpdate(legend); + return ResponseResult.success("保存成功."); + } + + /** + * 图例删除 + */ + @Operation(summary = "图例删除") + @PostMapping("/delete") + public ResponseResult deleteLayer(@RequestBody List ids) { + mapLegendService.delelteByIds(ids); + return ResponseResult.success("删除成功."); + } + + /** + * 地图图例管理图层树(下拉选) + */ + @Operation(summary = "地图图例管理图层树(下拉选)") + @GetMapping("/getAllMapLegendTree") + public ResponseResult getAllMapLayerTree(Integer flag) { + List tree = mapLegendBizService.getMapLegendTree(flag); + return ResponseResult.successData(tree); + } + + /** + * 地图图例列表 + */ + @Operation(summary = "地图图例列表") + @GetMapping("/getModuleMapLegendList") + public ResponseResult getModuleMapLegendList(@RequestParam(required = false) String moduleId) { + List list = mapLegendBizService.getModuleMapLegendList(moduleId); + return ResponseResult.successData(list); + } +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/domain/MsMaplayerB.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/domain/MsMaplayerB.java new file mode 100644 index 00000000..0e5740eb --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/domain/MsMaplayerB.java @@ -0,0 +1,195 @@ +package com.yfd.platform.qgc_sys.mapLayer.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + * 地图图层表 + * + * @author migration + */ +@Data +@TableName("MS_MAPLAYER_B") +public class MsMaplayerB implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_UUID) + private String id; + + /** 类型 */ + @TableField("TYPE") + private String type; + + /** 标识字段 */ + @TableField("KEY") + private String key; + + /** 编码 */ + @TableField("CODE") + private String code; + + /** 名称 */ + @TableField("TITLE") + private String title; + + /** 名称英文 */ + @TableField("TITLE_EN") + private String titleEn; + + /** 所属父节点 */ + @TableField("PARENT_ID") + private String parentId; + + /** 树全路径 */ + @TableField("FULL_PATH") + private String fullPath; + + /** 层级 */ + @TableField("TREE_LEVEL") + private Integer treeLevel; + + /** 是否有子集:0=否 1=有 */ + @TableField("HAS_CHILDREN") + private Integer hasChildren; + + /** 对应锚点接口 */ + @TableField("URL") + private String url; + + /** 对应三维锚点接口 */ + @TableField("URL_THD") + private String urlThd; + + /** 参数设置 */ + @TableField("OPTIONS") + private String options; + + /** 访问令牌 */ + @TableField("TOKEN") + private String token; + + /** 用户名 */ + @TableField("USERNAME") + private String username; + + /** 密码 */ + @TableField("PASSWORD") + private String password; + + /** 地图中心点经度 */ + @TableField("CENTER_LGTD") + private BigDecimal centerLgtd; + + /** 地图中心点纬度 */ + @TableField("CENTER_LTTD") + private BigDecimal centerLttd; + + /** 默认缩放级别 */ + @TableField("DEFAULT_ZOOM") + private String defaultZoom; + + /** 所属国家 */ + @TableField("COUNTRY") + private String country; + + /** 图标 */ + @TableField("ICON") + private String icon; + + /** 是否可选择:0=否 1=是 */ + @TableField("CHECKABLE") + private Integer checkable; + + /** 图层上下层层级关系 */ + @TableField("Z_INDEX") + private String zIndex; + + /** 各类站点图层对应类型 */ + @TableField("STTP_TYPE") + private String sttpType; + + /** 图层展示数据格式 */ + @TableField("LAYERS") + private String layers; + + /** 图层透明度 */ + @TableField("OPACITY") + private BigDecimal opacity; + + /** 额外参数 */ + @TableField("PARAMJSON") + private String paramJson; + + /** 备注 */ + @TableField("DESCRIPTION") + private String description; + + /** 是否启用:0=禁用 1=启用 */ + @TableField("ENABLE") + private Integer enable; + + /** 排序 */ + @TableField("ORDER_INDEX") + private Integer orderIndex; + + /** 过滤内容 */ + @TableField("FILTER_CONTENT") + private String filterContent; + + /** 创建人 */ + @TableField("RECORD_USER") + private String recordUser; + + /** 创建时间 */ + @TableField("RECORD_TIME") + private Date recordTime; + + /** 更新人 */ + @TableField("MODIFY_USER") + private String modifyUser; + + /** 更新时间 */ + @TableField("MODIFY_TIME") + private Date modifyTime; + + /** 是否已删除:0=未删除 1=已删除 */ + @TableField("IS_DELETED") + private Integer isDeleted; + + /** 删除人 */ + @TableField("DELETE_USER") + private String deleteUser; + + /** 删除时间 */ + @TableField("DELETE_TIME") + private Date deleteTime; + + /** 数据类型:1=结构,2=数据 */ + @TableField("DATA_TYPE") + private Integer dataType; + + /** 标签层级 */ + @TableField("LABEL_LEVEL") + private Integer labelLevel; + + /** 标签层级 */ + @TableField("ANCHOR_PARAM_JSON") + private String anchorParamJson; + + /** 子级集合(非数据库字段) */ + @TableField(exist = false) + private List children; + + /** 创建人名称(非数据库字段) */ + @TableField(exist = false) + private String displayRecordUser; +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/domain/MsMaplegendB.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/domain/MsMaplegendB.java new file mode 100644 index 00000000..3e2151d7 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/domain/MsMaplegendB.java @@ -0,0 +1,140 @@ +package com.yfd.platform.qgc_sys.mapLayer.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 地图图例表 + * + * @author migration + */ +@Data +@TableName("MS_MAPLEGEND_B") +public class MsMaplegendB implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_UUID) + private String id; + + @TableField("NAME") + private String name; + + @TableField("NAME_EN") + private String nameEn; + + @TableField("CODE") + private String code; + + @TableField("ICON") + private String icon; + + @TableField("GROUP_NAME") + private String groupName; + + @TableField("PARENT_NAME") + private String parentName; + + @TableField("LAYER_CODE") + private String layerCode; + + @TableField("MIN_ZOOM") + private Integer minZoom; + + @TableField("MAX_ZOOM") + private Integer maxZoom; + + @TableField("MIN_HEIGHT_THD") + private BigDecimal minHeightThd; + + @TableField("MAX_HEIGHT_THD") + private BigDecimal maxHeightThd; + + @TableField("DESCRIPTION") + private String description; + + @TableField("ENABLE") + private Integer enable; + + @TableField("INTERNAL") + private Integer internal; + + @TableField("ORDER_INDEX") + private Integer orderIndex; + + @TableField("FILTER_CONTENT") + private String filterContent; + + @TableField("RECORD_USER") + private String recordUser; + + @TableField("RECORD_TIME") + private Date recordTime; + + @TableField("MODIFY_USER") + private String modifyUser; + + @TableField("MODIFY_TIME") + private Date modifyTime; + + @TableField("IS_DELETED") + private Integer isDeleted; + + @TableField("DELETE_USER") + private String deleteUser; + + @TableField("DELETE_TIME") + private Date deleteTime; + + @TableField("IF_SHOW") + private Integer ifShow; + + @TableField("EXPRESSION") + private String expression; + + @TableField("EXT") + private String ext; + + @TableField("DATA_TYPE") + private Integer dataType; + + @TableField("PARENT_ID") + private String parentId; + + @TableField("FULL_PATH") + private String fullPath; + + @TableField("TREE_LEVEL") + private Integer treeLevel; + + @TableField("HAS_CHILDREN") + private Integer hasChildren; + + @TableField("COLOR") + private String color; + + @TableField("SHAPE") + private String shape; + + @TableField("MIN_VAL") + private BigDecimal minVal; + + @TableField("MAX_VAL") + private BigDecimal maxVal; + + @TableField("IS_FILTER") + private Integer isFilter; + + @TableField(exist = false) + private String layerCodeName; + + @TableField(exist = false) + private String parentCode; +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/domain/MsMapmoduleB.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/domain/MsMapmoduleB.java new file mode 100644 index 00000000..84c2f75d --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/domain/MsMapmoduleB.java @@ -0,0 +1,98 @@ +package com.yfd.platform.qgc_sys.mapLayer.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 地图与菜单映射表 + * + * @author migration + */ +@Data +@TableName("MS_MAPMODULE_B") +public class MsMapmoduleB implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_UUID) + private String id; + + @TableField("MODULE_ID") + private String moduleId; + + @TableField("RES_TYPE") + private String resType; + + @TableField("RES_ID") + private String resId; + + @TableField("CHILD_NODE") + private Integer childNode; + + @TableField("MULTI_SELECT") + private Integer multiSelect; + + @TableField("CAN_BE_CHECKED") + private Integer canBeChecked; + + @TableField("CHECKED") + private Integer checked; + + @TableField("DESCRIPTION") + private String description; + + @TableField("ENABLE") + private Integer enable; + + @TableField("ORDER_INDEX") + private Integer orderIndex; + + @TableField("FILTER_CONTENT") + private String filterContent; + + @TableField("RECORD_USER") + private String recordUser; + + @TableField("RECORD_TIME") + private Date recordTime; + + @TableField("MODIFY_USER") + private String modifyUser; + + @TableField("MODIFY_TIME") + private Date modifyTime; + + @TableField("IS_DELETED") + private Integer isDeleted; + + @TableField("DELETE_USER") + private String deleteUser; + + @TableField("DELETE_TIME") + private Date deleteTime; + + @TableField("TEMPLATE_ID") + private String templateId; + + @TableField("SYSTEM_ID") + private String systemId; + + /** + * 归属的系统ID(非数据库字段,用于字典翻译) + */ + @TableField(exist = false) + private String systemName; + + /** + * 菜单名称(非数据库字段,用于字典翻译) + */ + @TableField(exist = false) + private String moduleName; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/domain/MsMaptoolboxB.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/domain/MsMaptoolboxB.java new file mode 100644 index 00000000..1439c017 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/domain/MsMaptoolboxB.java @@ -0,0 +1,186 @@ +package com.yfd.platform.qgc_sys.mapLayer.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 地图工具箱表 + * + * @author migration + */ +@Data +@TableName("MS_MAPTOOLBOX_B") +public class MsMaptoolboxB implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_UUID) + private String id; + + /** + * 名称 + */ + @TableField("NAME") + private String name; + + /** + * 名称(英文) + */ + @TableField("NAME_EN") + private String nameEn; + + /** + * 编码 + */ + @TableField("CODE") + private String code; + + /** + * 地图模式 + */ + @TableField("MAP_MODEL") + private String mapModel; + + /** + * 所属父节点 + */ + @TableField("PATENT_ID") + private String patentId; + + /** + * 树全路径 + */ + @TableField("FULL_PATH") + private String fullPath; + + /** + * 层级 + */ + @TableField("TREE_LEVEL") + private Integer treeLevel; + + /** + * 是否有子集 + */ + @TableField("HAS_CHILDREN") + private Integer hasChildren; + + /** + * 图标 + */ + @TableField("ICON") + private String icon; + + /** + * 备注 + */ + @TableField("DESCRIPTION") + private String description; + + /** + * 是否启用 + */ + @TableField("ENABLE") + private Integer enable; + + /** + * 系统内置项 + */ + @TableField("INTERNAL") + private Integer internal; + + /** + * 排序 + */ + @TableField("ORDER_INDEX") + private Integer orderIndex; + + /** + * 过滤内容 + */ + @TableField("FILTER_CONTENT") + private String filterContent; + + /** + * 创建人 + */ + @TableField("RECORD_USER") + private String recordUser; + + /** + * 创建时间 + */ + @TableField("RECORD_TIME") + private Date recordTime; + + /** + * 更新人 + */ + @TableField("MODIFY_USER") + private String modifyUser; + + /** + * 更新时间 + */ + @TableField("MODIFY_TIME") + private Date modifyTime; + + /** + * 是否已删除 + */ + @TableField("IS_DELETED") + private Integer isDeleted; + + /** + * 删除人 + */ + @TableField("DELETE_USER") + private String deleteUser; + + /** + * 删除时间 + */ + @TableField("DELETE_TIME") + private Date deleteTime; + + /** + * 类型:0-功能区 1-地形 2-图例 + */ + @TableField("TOOL_TYPE") + private Integer toolType; + + /** + * 归属的系统ID(非数据库字段,来自MS_MAPMODULE_B关联) + */ + @TableField(exist = false) + private String systemId; + + /** + * 是否默认勾选(非数据库字段,来自MS_MAPMODULE_B关联) + */ + @TableField(exist = false) + private Integer checked; + + /** + * 是否可勾选(非数据库字段,来自MS_MAPMODULE_B关联) + */ + @TableField(exist = false) + private Integer canBeChecked; + + /** + * 是否多选(非数据库字段,来自MS_MAPMODULE_B关联) + */ + @TableField(exist = false) + private Integer multiSelect; + + /** 子级集合(非数据库字段) */ + @TableField(exist = false) + private List children; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/entity/vo/MapLayerAo.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/entity/vo/MapLayerAo.java new file mode 100644 index 00000000..9d8e38ae --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/entity/vo/MapLayerAo.java @@ -0,0 +1,15 @@ +package com.yfd.platform.qgc_sys.mapLayer.entity.vo; + +import lombok.Data; + +/** + * 地图图层查询参数 + * + * @author migration + */ +@Data +public class MapLayerAo { + + /** 图层名称(模糊查询) */ + private String title; +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/entity/vo/MapLayerVo.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/entity/vo/MapLayerVo.java new file mode 100644 index 00000000..e3925657 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/entity/vo/MapLayerVo.java @@ -0,0 +1,83 @@ +package com.yfd.platform.qgc_sys.mapLayer.entity.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +/** + * 地图图层管理封装VO + * + * @author migration + */ +@Data +@Schema(description = "地图图层管理封装VO") +public class MapLayerVo { + + @Schema(description = "主键") + private String id; + + @Schema(description = "父id") + private String parentId; + + @Schema(description = "标题名称") + private String title; + + @Schema(description = "图层标识") + @JsonProperty(value = "key") + private String code; + + @Schema(description = "标签层级") + @JsonProperty(value = "labelLevel") + private Integer labelLevel; + + @Schema(description = "是否可以选择:0=否 1=是") + private Integer checkable; + + @Schema(description = "图层分类") + private String type; + + @Schema(description = "图层上下层层级关系") + @JsonProperty(value = "zIndex") + private String zIndex; + + @Schema(description = "各类站点图层对应类型") + private String sttpType; + + @Schema(description = "图层展示数据格式") + private String layers; + + @Schema(description = "url地址") + private String url; + + @Schema(description = "3D url地址") + private String urlThd; + + @Schema(description = "图层透明度") + private BigDecimal opacity; + + @Schema(description = "子级集合") + private List children; + + @Schema(description = "参数json") + private String paramJson; + + @Schema(description = "参数ANCHOR_PARAM_JSON") + private String anchorParamJson; + + @Schema(description = "排序") + private String orderIndex; + + @Schema(description = "是否默认勾选:0=否 1=是") + private Integer checked; + + @Schema(description = "是否可勾选:0=否 1=是") + private Integer canBeChecked; + + @Schema(description = "是否多选:0=否 1=是") + private Integer multiSelect; + @Schema(description = "参数设置:steady=静态 dynamic=动态") + private String options; +} diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/entity/vo/MapLegendVo.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/entity/vo/MapLegendVo.java new file mode 100644 index 00000000..03d26c78 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/entity/vo/MapLegendVo.java @@ -0,0 +1,100 @@ +package com.yfd.platform.qgc_sys.mapLayer.entity.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +/** + * 地图图例VO + * + * @author migration + */ +@Data +@Schema(description = "地图图例VO") +public class MapLegendVo { + + @Schema(description = "图例id") + private String id; + + @Schema(description = "父级id") + private String parentId; + + @Schema(description = "分组名") + private String groupName; + + @Schema(description = "层级名称") + private String parentName; + + @Schema(description = "图例名") + private String name; + + @Schema(description = "图例code") + private String code; + + @Schema(description = "图例icon") + private String icon; + + @Schema(description = "图例英文(对应描点数据中的状态)") + private String nameEn; + + @Schema(description = "图层code") + private String layerCode; + + @Schema(description = "是否多选;0=否;1=是") + private Integer multiSelect; + + @Schema(description = "是否默认勾选;0=否;1=是") + private Integer checked; + + @Schema(description = "0=否;1=是") + private Integer enable; + + @Schema(description = "是否可勾选;0=否;1=是") + private Integer canBeChecked; + + @Schema(description = "子排序") + private Integer orderIndex; + + @Schema(description = "父排序") + private Integer pSort; + + @Schema(description = "最小缩放等级") + private Integer minZoom; + + @Schema(description = "最大缩放等级") + private Integer maxZoom; + + @Schema(description = "最小高程-三维") + private BigDecimal minHeightThd; + + @Schema(description = "最大高程-三维") + private BigDecimal maxHeightThd; + + @Schema(description = "是否显示;0=否;1=是") + private Integer ifShow; + + @Schema(description = "是否过滤;0=否;1=是") + private Integer isFilter; + + @JsonProperty(value = "color") + @Schema(description = "图例颜色") + private String color; + + @JsonProperty(value = "shape") + @Schema(description = "图例形状") + private String shape; + + @JsonProperty(value = "minVal") + @Schema(description = "区间最小值") + private BigDecimal minVal; + + @JsonProperty(value = "maxVal") + @Schema(description = "区间最大值") + private BigDecimal maxVal; + + @Schema(description = "子级") + private List childrenList; +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/mapper/MsMaplayerBMapper.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/mapper/MsMaplayerBMapper.java new file mode 100644 index 00000000..50a275ec --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/mapper/MsMaplayerBMapper.java @@ -0,0 +1,14 @@ +package com.yfd.platform.qgc_sys.mapLayer.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaplayerB; +import org.apache.ibatis.annotations.Mapper; + +/** + * 地图图层表 Mapper 接口 + * + * @author migration + */ +@Mapper +public interface MsMaplayerBMapper extends BaseMapper { +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/mapper/MsMaplegendBMapper.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/mapper/MsMaplegendBMapper.java new file mode 100644 index 00000000..d6df58bc --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/mapper/MsMaplegendBMapper.java @@ -0,0 +1,14 @@ +package com.yfd.platform.qgc_sys.mapLayer.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaplegendB; +import org.apache.ibatis.annotations.Mapper; + +/** + * 地图图例表 Mapper 接口 + * + * @author migration + */ +@Mapper +public interface MsMaplegendBMapper extends BaseMapper { +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/mapper/MsMapmoduleBMapper.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/mapper/MsMapmoduleBMapper.java new file mode 100644 index 00000000..ee8da0e4 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/mapper/MsMapmoduleBMapper.java @@ -0,0 +1,114 @@ +package com.yfd.platform.qgc_sys.mapLayer.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMapmoduleB; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaptoolboxB; +import com.yfd.platform.qgc_sys.mapLayer.entity.vo.MapLayerVo; +import com.yfd.platform.qgc_sys.mapLayer.entity.vo.MapLegendVo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + * 地图与菜单映射表 Mapper 接口 + * + * @author migration + */ +@Mapper +public interface MsMapmoduleBMapper extends BaseMapper { + + /** + * 查询地图图层树(关联MS_MAPMODULE_B与MS_MAPLAYER_B) + */ + @Select("") + List getMapLayerTree(@Param("moduleId") String moduleId, @Param("sid") String sid, + @Param("templateId") String templateId); + + /** + * 查询地图工具箱(关联MS_MAPMODULE_B与MS_MAPTOOLBOX_B) + */ + @Select("") + List getMapToolBox(@Param("moduleId") String moduleId, @Param("sid") String sid, + @Param("templateId") String templateId); + + /** + * 查询模块关联的图例列表(关联MS_MAPMODULE_B与MS_MAPLEGEND_B) + */ + @Select("") + List getModuleMapLegendList(@Param("moduleId") String moduleId, @Param("sid") String sid, + @Param("templateId") String templateId); + + + /** + * 查询模块关联的图例列表(单参数版本,用于地图图例管理页面) + */ + @Select("") + List getModuleMapLegendList(@Param("moduleId") String moduleId); + +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/mapper/MsMaptoolboxBMapper.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/mapper/MsMaptoolboxBMapper.java new file mode 100644 index 00000000..cff67cc6 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/mapper/MsMaptoolboxBMapper.java @@ -0,0 +1,15 @@ +package com.yfd.platform.qgc_sys.mapLayer.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaptoolboxB; +import org.apache.ibatis.annotations.Mapper; + +/** + * 地图工具箱表 Mapper 接口 + * + * @author migration + */ +@Mapper +public interface MsMaptoolboxBMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/IMapLayerBizService.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/IMapLayerBizService.java new file mode 100644 index 00000000..6705b7df --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/IMapLayerBizService.java @@ -0,0 +1,34 @@ +package com.yfd.platform.qgc_sys.mapLayer.service; + +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaplayerB; +import com.yfd.platform.qgc_sys.mapLayer.entity.vo.MapLayerAo; +import com.yfd.platform.qgc_sys.mapLayer.entity.vo.MapLayerVo; + +import java.util.List; + +/** + * 地图图层业务服务接口 + * + * @author migration + */ +public interface IMapLayerBizService { + + /** + * 获取所有地图图层树 + * + * @param flag 查询参数 + * @return 图层树列表 + */ + List getMapLayerTree(MapLayerAo flag); + + /** + * 根据模块ID、系统ID、模板ID获取地图图层树(关联MS_MAPMODULE_B) + * + * @param moduleId 模块ID + * @param systemId 系统ID + * @param templateId 模板ID + * @return 图层树列表 + */ + List getMapLayerTree(String moduleId, String systemId, String templateId); + +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/IMapLayerService.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/IMapLayerService.java new file mode 100644 index 00000000..7aff13e5 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/IMapLayerService.java @@ -0,0 +1,28 @@ +package com.yfd.platform.qgc_sys.mapLayer.service; + +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaplayerB; + +import java.util.List; + +/** + * 地图图层基础服务接口 + * + * @author migration + */ +public interface IMapLayerService { + + /** + * 新增或修改图层 + * + * @param layer 图层实体 + * @return 是否成功 + */ + boolean saveOrUpdate(MsMaplayerB layer); + + /** + * 根据ID列表删除图层 + * + * @param ids 图层ID列表 + */ + void delelteByIds(List ids); +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/IMapLegendBizService.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/IMapLegendBizService.java new file mode 100644 index 00000000..23874190 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/IMapLegendBizService.java @@ -0,0 +1,42 @@ +package com.yfd.platform.qgc_sys.mapLayer.service; + +import com.yfd.platform.qgc_sys.mapLayer.entity.vo.MapLegendVo; + +import java.util.List; + +/** + * 地图图例业务服务接口 + * + * @author migration + */ +public interface IMapLegendBizService { + + /** + * 获取地图图例树(下拉选) + * + * @param flag 数据类型过滤:null=全部, 1=结构, 2=数据 + * @return 图例树 + */ + List getMapLegendTree(Integer flag); + + + /** + * 根据模块ID、系统ID、模板ID获取模块关联的图例列表 + * + * @param moduleId 模块ID + * @param systemId 系统ID + * @param templateId 模板ID + * @return 图例列表 + */ + List getModuleMapLegendList(String moduleId, String systemId, String templateId); + + /** + * 根据模块ID获取模块关联的图例列表(单参数版本) + * + * @param moduleId 模块ID + * @return 图例列表 + */ + List getModuleMapLegendList(String moduleId); + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/IMapLegendService.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/IMapLegendService.java new file mode 100644 index 00000000..273398ae --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/IMapLegendService.java @@ -0,0 +1,22 @@ +package com.yfd.platform.qgc_sys.mapLayer.service; + + +import com.baomidou.mybatisplus.extension.service.IService; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaplegendB; + +import java.util.List; + +/** + * 地图图例基础服务接口 + * + * @author migration + */ +public interface IMapLegendService extends IService { + + /** + * 根据ID列表删除图例 + * + * @param ids 图例ID列表 + */ + void delelteByIds(List ids); +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/impl/MapLayerBizServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/impl/MapLayerBizServiceImpl.java new file mode 100644 index 00000000..0bab5095 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/impl/MapLayerBizServiceImpl.java @@ -0,0 +1,214 @@ +package com.yfd.platform.qgc_sys.mapLayer.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaplayerB; +import com.yfd.platform.qgc_sys.mapLayer.entity.vo.MapLayerAo; +import com.yfd.platform.qgc_sys.mapLayer.entity.vo.MapLayerVo; +import com.yfd.platform.qgc_sys.mapLayer.mapper.MsMaplayerBMapper; +import com.yfd.platform.qgc_sys.mapLayer.mapper.MsMapmoduleBMapper; +import com.yfd.platform.qgc_sys.mapLayer.service.IMapLayerBizService; +import com.yfd.platform.system.domain.SysDictionary; +import com.yfd.platform.system.domain.SysDictionaryItems; +import com.yfd.platform.system.domain.SysUser; +import com.yfd.platform.system.mapper.SysDictionaryItemsMapper; +import com.yfd.platform.system.mapper.SysDictionaryMapper; +import com.yfd.platform.system.mapper.SysUserMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 地图图层业务服务实现 + * + * @author migration + */ +@Service +public class MapLayerBizServiceImpl implements IMapLayerBizService { + + @Resource + private MsMaplayerBMapper msMaplayerBMapper; + + @Resource + private SysDictionaryMapper sysDictionaryMapper; + + @Resource + private SysDictionaryItemsMapper sysDictionaryItemsMapper; + + @Resource + private SysUserMapper sysUserMapper; + + @Resource + private MsMapmoduleBMapper msMapmoduleBMapper; + + @Override + public List getMapLayerTree(MapLayerAo flag) { + // 1. 查询字典 "DTZJLX" 获取需要排除的图层类型 + Set excludeTypes = getExcludeTypes(); + + // 2. 查询所有未删除的图层数据,排除特殊类型,支持按名称模糊查询 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(MsMaplayerB::getIsDeleted, 0); + + // 排除特殊类型 + if (!excludeTypes.isEmpty()) { + wrapper.and(w -> w.notIn(MsMaplayerB::getType, excludeTypes).or().isNull(MsMaplayerB::getType)); + } + + // 按名称模糊查询 + if (StrUtil.isNotBlank(flag.getTitle())) { + wrapper.like(MsMaplayerB::getTitle, flag.getTitle()); + } + + List mapLayers = msMaplayerBMapper.selectList(wrapper); + + // 3. 当按名称过滤时,补充缺失的父级节点 + if (StrUtil.isNotBlank(flag.getTitle()) && !mapLayers.isEmpty()) { + Set hasKeys = mapLayers.stream() + .filter(it -> StrUtil.isNotBlank(it.getKey())) + .map(MsMaplayerB::getKey) + .collect(Collectors.toSet()); + + Set idList = new HashSet<>(); + for (MsMaplayerB layer : mapLayers) { + if (StrUtil.isNotBlank(layer.getFullPath()) && StrUtil.isNotBlank(layer.getKey())) { + String[] ids = layer.getFullPath().replace(layer.getKey() + ",", "").split(","); + for (String id : ids) { + if (StrUtil.isNotBlank(id) && !hasKeys.contains(id)) { + idList.add(id); + } + } + } + } + + if (!idList.isEmpty()) { + LambdaQueryWrapper parentWrapper = new LambdaQueryWrapper<>(); + parentWrapper.eq(MsMaplayerB::getIsDeleted, 0) + .in(MsMaplayerB::getKey, idList); + List parentLayers = msMaplayerBMapper.selectList(parentWrapper); + if (!parentLayers.isEmpty()) { + mapLayers.addAll(parentLayers); + } + } + } + + // 4. 填充创建人名称 + if (!mapLayers.isEmpty()) { + LambdaQueryWrapper userWrapper = new LambdaQueryWrapper<>(); + List users = sysUserMapper.selectList(userWrapper); + Map userMap = users.stream() + .collect(Collectors.toMap(SysUser::getId, SysUser::getNickname, (v1, v2) -> v1)); + + for (MsMaplayerB layer : mapLayers) { + if (StrUtil.isNotBlank(layer.getRecordUser())) { + layer.setDisplayRecordUser(userMap.get(layer.getRecordUser())); + } + } + } + + // 5. 构建树结构:取第一级 + List parents = mapLayers.stream() + .filter(p -> StrUtil.isBlank(p.getParentId())) + .sorted(Comparator.comparing(MsMaplayerB::getRecordTime, Comparator.nullsLast(Comparator.reverseOrder()))) + .collect(Collectors.toList()); + + // 通过父级id分组子节点 + Map> childrenMap = mapLayers.stream() + .filter(p -> StrUtil.isNotBlank(p.getParentId())) + .collect(Collectors.groupingBy(MsMaplayerB::getParentId)); + + // 递归构建树 + convertTree(parents, childrenMap); + + return parents; + } + + /** + * 查询字典 "DTZJLX" 中需要排除的图层类型值 + */ + private Set getExcludeTypes() { + Set excludeTypes = new HashSet<>(); + try { + LambdaQueryWrapper dictWrapper = new LambdaQueryWrapper<>(); + dictWrapper.eq(SysDictionary::getDictCode, "DTZJLX"); + SysDictionary dictionary = sysDictionaryMapper.selectOne(dictWrapper); + if (dictionary != null) { + LambdaQueryWrapper itemWrapper = new LambdaQueryWrapper<>(); + itemWrapper.eq(SysDictionaryItems::getDictId, dictionary.getId()); + List items = sysDictionaryItemsMapper.selectList(itemWrapper); + if (items != null) { + excludeTypes = items.stream() + .map(SysDictionaryItems::getDictName) + .filter(StrUtil::isNotBlank) + .collect(Collectors.toSet()); + } + } + } catch (Exception e) { + // 字典查询失败时不中断主流程 + } + return excludeTypes; + } + + /** + * 递归转换图层数据为树结构 + */ + private void convertTree(List parents, Map> childrenMap) { + if (parents == null || parents.isEmpty()) { + return; + } + for (MsMaplayerB parent : parents) { + String id = parent.getId(); + List children = childrenMap.get(id); + if (children != null && !children.isEmpty()) { + parent.setChildren(children); + convertTree(children, childrenMap); + }else { + // 当没有子节点时,显式设置为空列表,保证 JSON 输出为 [] 而不是 null + parent.setChildren(new ArrayList<>()); + } + } + } + + @Override + public List getMapLayerTree(String moduleId, String systemId, String templateId) { + // 通过 JOIN 查询 MS_MAPLAYER_B 和 MS_MAPMODULE_B + List allLayers = msMapmoduleBMapper.getMapLayerTree(moduleId, systemId, templateId); + + if (allLayers == null || allLayers.isEmpty()) { + return new ArrayList<>(); + } + + // 取第一级 + List parents = allLayers.stream() + .filter(p -> StrUtil.isBlank(p.getParentId())) + .collect(Collectors.toList()); + + // 通过父级id分组子节点 + Map> childrenMap = allLayers.stream() + .filter(p -> StrUtil.isNotBlank(p.getParentId())) + .collect(Collectors.groupingBy(MapLayerVo::getParentId)); + + // 递归构建树 + convertLayerVoTree(parents, childrenMap); + return parents; + } + + /** + * 递归转换图层VO为树结构 + */ + private void convertLayerVoTree(List parents, Map> childrenMap) { + if (parents == null || parents.isEmpty()) { + return; + } + for (MapLayerVo parent : parents) { + String id = parent.getId(); + List children = childrenMap.get(id); + if (children != null && !children.isEmpty()) { + parent.setChildren(children); + convertLayerVoTree(children, childrenMap); + } + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/impl/MapLayerServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/impl/MapLayerServiceImpl.java new file mode 100644 index 00000000..fbe64e5b --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/impl/MapLayerServiceImpl.java @@ -0,0 +1,256 @@ +package com.yfd.platform.qgc_sys.mapLayer.service.impl; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.yfd.platform.common.exception.BizException; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaplegendB; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaplayerB; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMapmoduleB; +import com.yfd.platform.qgc_sys.mapLayer.mapper.MsMaplegendBMapper; +import com.yfd.platform.qgc_sys.mapLayer.mapper.MsMaplayerBMapper; +import com.yfd.platform.qgc_sys.mapLayer.mapper.MsMapmoduleBMapper; +import com.yfd.platform.qgc_sys.mapLayer.service.IMapLayerService; +import com.yfd.platform.utils.SecurityUtils; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 地图图层基础服务实现 + * + * @author migration + */ +@Service +public class MapLayerServiceImpl implements IMapLayerService { + + @Resource + private MsMaplayerBMapper msMaplayerBMapper; + + @Resource + private MsMaplegendBMapper msMaplegendBMapper; + + @Resource + private MsMapmoduleBMapper msMapmoduleBMapper; + + @Override + public boolean saveOrUpdate(MsMaplayerB layer) { + // 校验编码唯一性 + if (hasSameCode(layer)) { + throw new BizException("存在相同编码的数据"); + } + + // 当type等于SLDT/DXDT/YXDT,校验地图json格式 + String paramJson = layer.getParamJson(); + String type = layer.getType(); + if (("SLDT".equals(type) || "DXDT".equals(type) || "YXDT".equals(type)) + && StrUtil.isNotBlank(paramJson)) { + try { + JSONUtil.toBean(paramJson, HashMap.class); + } catch (Exception e) { + throw new BizException("请检查地图json格式"); + } + } + + if (StrUtil.isNotBlank(layer.getId())) { + // 修改 + msMaplayerBMapper.updateById(layer); + + // 判断是否启用且有子级,则子数据都要设置为启用状态 + if (layer.getEnable() != null && layer.getEnable() == 1 + && layer.getHasChildren() != null && layer.getHasChildren() == 1) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(MsMaplayerB::getIsDeleted, 0) + .like(MsMaplayerB::getFullPath, layer.getId() + ","); + List children = msMaplayerBMapper.selectList(wrapper); + for (MsMaplayerB child : children) { + MsMaplayerB temp = new MsMaplayerB(); + temp.setId(child.getId()); + temp.setEnable(1); + msMaplayerBMapper.updateById(temp); + } + } + } else { + // 新增 + String id = IdUtil.fastSimpleUUID(); + layer.setId(id); + + // 获取同级子节点,计算最大排序号 + List subList = getSubList(layer.getParentId()); + Integer maxOrderIndex = getMaxOrderIndex(subList); + layer.setOrderIndex(maxOrderIndex + 1); + + MsMaplayerB parentLayer = null; + if (StrUtil.isNotBlank(layer.getParentId())) { + // 获取父级信息 + parentLayer = msMaplayerBMapper.selectById(layer.getParentId()); + if (parentLayer == null) { + throw new BizException("获取父级图层信息失败.请检查父级图层(parentId)是否存在."); + } + // 设置key + layer.setKey(parentLayer.getKey() + "-" + layer.getOrderIndex()); + // 设置fullPath + layer.setFullPath(parentLayer.getFullPath() + layer.getKey() + ","); + // 设置treeLevel + layer.setTreeLevel(parentLayer.getTreeLevel() + 1); + // 设置hasChildren + layer.setHasChildren(0); + } else { + // 无父级,则为创建的顶级图层 + layer.setTreeLevel(1); + layer.setKey("0-" + layer.getOrderIndex()); + layer.setFullPath(layer.getKey() + ","); + layer.setHasChildren(0); + } + + // 设置可选 + layer.setCheckable(0); + // 设置不可用 + layer.setEnable(0); + + String userId = getCurrentUserId(); + layer.setRecordUser(userId); + layer.setModifyUser(userId); + layer.setRecordTime(new Date()); + + msMaplayerBMapper.insert(layer); + + // 新增完成后,设置父级hasChildren为1 + if (parentLayer != null) { + MsMaplayerB temp = new MsMaplayerB(); + temp.setId(parentLayer.getId()); + temp.setHasChildren(1); + msMaplayerBMapper.updateById(temp); + } + } + return true; + } + + @Override + public void delelteByIds(List ids) { + if (ids == null || ids.isEmpty()) { + return; + } + for (String id : ids) { + // 根据id查询是否有子级数据 + MsMaplayerB layer = msMaplayerBMapper.selectById(id); + if (layer == null) { + continue; + } + + LambdaQueryWrapper childWrapper = new LambdaQueryWrapper<>(); + childWrapper.eq(MsMaplayerB::getParentId, id); + List children = msMaplayerBMapper.selectList(childWrapper); + if (!children.isEmpty()) { + throw new BizException("有子级图层,无法删除."); + } + + // 判断是否启用 + if (layer.getEnable() != null && layer.getEnable() == 1) { + throw new BizException("无法删除已启用的图层."); + } + + // 判断是否已经关联了图例 + QueryWrapper legendWrapper = new QueryWrapper<>(); + legendWrapper.eq("LAYER_CODE", layer.getCode()); + legendWrapper.eq("IS_DELETED", 0); + List legendList = msMaplegendBMapper.selectList(legendWrapper); + if (!legendList.isEmpty()) { + throw new BizException("图层关联了图例,无法删除."); + } + + // 判断父级是否存在 + if (StrUtil.isBlank(layer.getParentId())) { + // 逻辑删除 + msMaplayerBMapper.deleteById(id); + } else { + MsMaplayerB parent = msMaplayerBMapper.selectById(layer.getParentId()); + // 逻辑删除 + msMaplayerBMapper.deleteById(id); + + // 判断父级下是否只有一个子级,如果是当前图层,则设置父级hasChildren为0 + if (parent != null) { + LambdaQueryWrapper siblingWrapper = new LambdaQueryWrapper<>(); + siblingWrapper.eq(MsMaplayerB::getParentId, parent.getId()); + List siblings = msMaplayerBMapper.selectList(siblingWrapper); + if (siblings.size() == 1 && id.equals(siblings.get(0).getId())) { + MsMaplayerB temp = new MsMaplayerB(); + temp.setId(parent.getId()); + temp.setHasChildren(0); + msMaplayerBMapper.updateById(temp); + } + } + } + + // 判断是否关联菜单,删除关联 + QueryWrapper moduleWrapper = new QueryWrapper<>(); + moduleWrapper.eq("RES_TYPE", "layer"); + moduleWrapper.eq("IS_DELETED", 0); + moduleWrapper.eq("RES_ID", id); + List moduleList = msMapmoduleBMapper.selectList(moduleWrapper); + if (!moduleList.isEmpty()) { + Set moduleIds = moduleList.stream() + .map(MsMapmoduleB::getId) + .collect(Collectors.toSet()); + msMapmoduleBMapper.deleteBatchIds(moduleIds); + } + } + } + + /** + * 获取当前用户ID + */ + private String getCurrentUserId() { + try { + return SecurityUtils.getUserId(); + } catch (Exception e) { + return null; + } + } + + /** + * 根据父级编码查询子一级数据 + */ + private List getSubList(String parentId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + if (StrUtil.isNotBlank(parentId)) { + wrapper.eq(MsMaplayerB::getParentId, parentId); + } else { + wrapper.eq(MsMaplayerB::getTreeLevel, 1); + } + wrapper.orderByAsc(MsMaplayerB::getOrderIndex); + return msMaplayerBMapper.selectList(wrapper); + } + + /** + * 获取最大排序号 + */ + private Integer getMaxOrderIndex(List list) { + if (list.isEmpty()) { + return 0; + } + return list.stream() + .sorted(Comparator.comparing(MsMaplayerB::getOrderIndex, Comparator.nullsLast(Comparator.reverseOrder()))) + .collect(Collectors.toList()) + .get(0) + .getOrderIndex(); + } + + /** + * 判断同级下是否有编码一样的数据 + */ + private boolean hasSameCode(MsMaplayerB layer) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(MsMaplayerB::getCode, layer.getCode()) + .eq(MsMaplayerB::getIsDeleted, 0); + List list = msMaplayerBMapper.selectList(wrapper); + if (list.isEmpty()) { + return false; + } + return !list.get(0).getId().equals(layer.getId()); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/impl/MapLegendBizServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/impl/MapLegendBizServiceImpl.java new file mode 100644 index 00000000..5ca81ae0 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/impl/MapLegendBizServiceImpl.java @@ -0,0 +1,212 @@ +package com.yfd.platform.qgc_sys.mapLayer.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaplegendB; +import com.yfd.platform.qgc_sys.mapLayer.entity.vo.MapLegendVo; +import com.yfd.platform.qgc_sys.mapLayer.mapper.MsMapmoduleBMapper; +import com.yfd.platform.qgc_sys.mapLayer.service.IMapLegendBizService; +import com.yfd.platform.qgc_sys.mapLayer.service.IMapLegendService; +import jakarta.annotation.Resource; +import cn.hutool.core.collection.CollectionUtil; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 地图图例业务服务实现类 + * + * @author migration + */ +@Service +public class MapLegendBizServiceImpl implements IMapLegendBizService { + + @Resource + private IMapLegendService legendService; + @Resource + private MsMapmoduleBMapper msMapmoduleBMapper; + /** + * 数据类型枚举:1=结构 + */ + private static final int DATA_TYPE_STRUCT = 1; + /** + * 数据类型枚举:2=数据 + */ + private static final int DATA_TYPE_DATA = 2; + + @Override + public List getMapLegendTree(Integer flag) { + // 查询所有数据 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(MsMaplegendB::getIsDeleted, 0); + if (flag != null) { + if (flag == DATA_TYPE_STRUCT) { + wrapper.eq(MsMaplegendB::getDataType, DATA_TYPE_STRUCT); + } else if (flag == DATA_TYPE_DATA) { + wrapper.eq(MsMaplegendB::getDataType, DATA_TYPE_DATA); + } + } + List legendList = legendService.list(wrapper); + + // 转换为VO + List list = new ArrayList<>(); + for (MsMaplegendB legend : legendList) { + MapLegendVo vo = new MapLegendVo(); + BeanUtil.copyProperties(legend, vo); + list.add(vo); + } + + // 取第一级 + List parents = list.stream() + .filter(p -> StringUtils.isBlank(p.getParentId())) + .sorted(Comparator.comparing(MapLegendVo::getOrderIndex, Comparator.nullsLast(Integer::compareTo))) + .collect(Collectors.toList()); + + // 通过父级id分组 + Map> mapList = list.stream() + .filter(p -> StringUtils.isNotBlank(p.getParentId())) + .collect(Collectors.groupingBy(MapLegendVo::getParentId)); + + // 递归转换数据为树结构 + convertTree(parents, mapList); + return parents; + } + + /** + * 递归转换树结构 + */ + private void convertTree(List parents, Map> subList) { + if (parents == null || parents.isEmpty()) { + return; + } + for (MapLegendVo p : parents) { + String id = p.getId(); + for (Map.Entry> entry : subList.entrySet()) { + String pid = entry.getKey(); + List children = entry.getValue(); + if (id.equals(pid)) { + p.setChildrenList(children); + convertTree(children, subList); + } + } + } + } + + + @Override + public List getModuleMapLegendList(String moduleId, String systemId, String templateId) { + List list = new ArrayList<>(); + // 通过 JOIN 查询 MS_MAPLEGEND_B 和 MS_MAPMODULE_B + List bbiMapLegendList = msMapmoduleBMapper.getModuleMapLegendList(moduleId, systemId, templateId); + + if (bbiMapLegendList == null || bbiMapLegendList.isEmpty()) { + return list; + } + + // 按父级分组 + Map> collect = bbiMapLegendList.stream() + .collect(Collectors.groupingBy(MapLegendVo::getParentName)); + + // 遍历 + collect.forEach((str, mapLegendVoList) -> { + MapLegendVo mapLegendVo = new MapLegendVo(); + mapLegendVo.setName(str); + mapLegendVo.setPSort(mapLegendVoList.get(0).getPSort()); + // 按子级分组名分组 + Map> collect1 = mapLegendVoList.stream() + .collect(Collectors.groupingBy(MapLegendVo::getGroupName)); + List childrenList = new ArrayList<>(); + for (String groupNameStr : collect1.keySet()) { + List list1 = collect1.get(groupNameStr); + // 如果子级和父级名称相同,则不用子级 + if (groupNameStr.equalsIgnoreCase(str)) { + childrenList = list1; + } else { + MapLegendVo mapLegendVoChild = new MapLegendVo(); + mapLegendVoChild.setName(groupNameStr); + if (null != list1 && list1.size() > 0) { + mapLegendVoChild.setPSort(list1.get(0).getPSort()); + } + mapLegendVoChild.setChildrenList(list1); + childrenList.add(mapLegendVoChild); + } + } + List collect2 = childrenList.stream() + .sorted(Comparator.comparing(MapLegendVo::getPSort, Comparator.nullsLast(Integer::compareTo))) + .collect(Collectors.toList()); + mapLegendVo.setChildrenList(collect2); + list.add(mapLegendVo); + }); + return list.stream() + .sorted(Comparator.comparing(MapLegendVo::getPSort, Comparator.nullsLast(Integer::compareTo))) + .collect(Collectors.toList()); + } + + @Override + public List getModuleMapLegendList(String moduleId) { + List list = new ArrayList<>(); + // 通过 JOIN 查询 MS_MAPLEGEND_B 和 MS_MAPMODULE_B(单参数版本) + List bbiMapLegendList = msMapmoduleBMapper.getModuleMapLegendList(moduleId); + + if (bbiMapLegendList == null || bbiMapLegendList.isEmpty()) { + return list; + } + + // 收集父级ID,查询父级图例的layerCode + Set parentIdList = bbiMapLegendList.stream() + .map(MapLegendVo::getParentId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + Map layerCodeMap = new HashMap<>(); + if (CollectionUtil.isNotEmpty(parentIdList)) { + List parentLegendList = legendService.lambdaQuery() + .in(MsMaplegendB::getId, parentIdList) + .list(); + layerCodeMap = parentLegendList.stream() + .filter(item -> item.getLayerCode() != null) + .collect(Collectors.toMap(MsMaplegendB::getId, MsMaplegendB::getLayerCode, (v1, v2) -> v1)); + } + + // 按父级分组 + Map> collect = bbiMapLegendList.stream() + .collect(Collectors.groupingBy(MapLegendVo::getParentName)); + + // 遍历 + Map finalLayerCodeMap = layerCodeMap; + collect.forEach((str, mapLegendVoList) -> { + MapLegendVo mapLegendVo = new MapLegendVo(); + mapLegendVo.setName(str); + mapLegendVo.setPSort(mapLegendVoList.get(0).getPSort()); + mapLegendVo.setLayerCode(finalLayerCodeMap.get(mapLegendVoList.get(0).getParentId())); + // 按子级分组名分组 + Map> collect1 = mapLegendVoList.stream() + .collect(Collectors.groupingBy(MapLegendVo::getGroupName)); + List childrenList = new ArrayList<>(); + for (String groupNameStr : collect1.keySet()) { + List list1 = collect1.get(groupNameStr); + // 如果子级和父级名称相同,则不用子级 + if (groupNameStr.equalsIgnoreCase(str)) { + childrenList = list1; + } else { + MapLegendVo mapLegendVoChild = new MapLegendVo(); + mapLegendVoChild.setName(groupNameStr); + if (null != list1 && list1.size() > 0) { + mapLegendVoChild.setPSort(list1.get(0).getPSort()); + } + mapLegendVoChild.setChildrenList(list1); + childrenList.add(mapLegendVoChild); + } + } + List collect2 = childrenList.stream() + .sorted(Comparator.comparing(MapLegendVo::getPSort, Comparator.nullsLast(Integer::compareTo))) + .collect(Collectors.toList()); + mapLegendVo.setChildrenList(collect2); + list.add(mapLegendVo); + }); + return list.stream() + .sorted(Comparator.comparing(MapLegendVo::getPSort, Comparator.nullsLast(Integer::compareTo))) + .collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/impl/MapLegendServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/impl/MapLegendServiceImpl.java new file mode 100644 index 00000000..5152e819 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapLayer/service/impl/MapLegendServiceImpl.java @@ -0,0 +1,97 @@ +package com.yfd.platform.qgc_sys.mapLayer.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yfd.platform.common.exception.BizException; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaplegendB; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMapmoduleB; +import com.yfd.platform.qgc_sys.mapLayer.mapper.MsMaplegendBMapper; +import com.yfd.platform.qgc_sys.mapLayer.mapper.MsMapmoduleBMapper; +import com.yfd.platform.qgc_sys.mapLayer.service.IMapLegendService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 地图图例基础服务实现 + * + * @author migration + */ +@Service +public class MapLegendServiceImpl extends ServiceImpl + implements IMapLegendService { + + @Resource + private MsMapmoduleBMapper msMapmoduleBMapper; + + @Override + public void delelteByIds(List ids) { + if (CollectionUtil.isEmpty(ids)) { + return; + } + for (String id : ids) { + // 根据id查询是否有数据或者子级数据 + MsMaplegendB legend = this.getById(id); + if (legend == null) { + continue; + } + + LambdaQueryWrapper childWrapper = new LambdaQueryWrapper<>(); + childWrapper.eq(MsMaplegendB::getParentId, id) + .eq(MsMaplegendB::getIsDeleted, 0); + List children = this.list(childWrapper); + if (!children.isEmpty()) { + throw new BizException("有子级图例,无法删除."); + } + + // 判断是否内置的数据 + if (legend.getInternal() != null && legend.getInternal() == 1) { + throw new BizException("无法删除系统内置的图例."); + } + + // 判断是否启用 + if (legend.getEnable() != null && legend.getEnable() == 1) { + throw new BizException("无法删除已启用的图例."); + } + + // 判断图例是否关联了菜单 + QueryWrapper moduleWrapper = new QueryWrapper<>(); + moduleWrapper.eq("IS_DELETED", 0); + moduleWrapper.eq("RES_TYPE", "legend"); + moduleWrapper.eq("RES_ID", id); + List moduleList = msMapmoduleBMapper.selectList(moduleWrapper); + if (!moduleList.isEmpty()) { + throw new BizException("无法删除:图例关联了菜单."); + } + + // 判断父级是否存在 + if (StrUtil.isBlank(legend.getParentId())) { + this.removeById(id); // 逻辑删除 + return; + } + + // 删除数据 + this.removeById(id); // 逻辑删除 + + if (StrUtil.isNotBlank(legend.getParentId())) { + // 判断父级下是否只有一个子级,如果只有一个子级并且是当前图例,则需要设置父级的hasChildren为0 + MsMaplegendB parent = this.getById(legend.getParentId()); + if (parent != null) { + LambdaQueryWrapper siblingWrapper = new LambdaQueryWrapper<>(); + siblingWrapper.eq(MsMaplegendB::getParentId, parent.getId()); + List siblings = this.list(siblingWrapper); + if (siblings.size() == 1 && id.equals(siblings.get(0).getId())) { + MsMaplegendB updateParent = new MsMaplegendB(); + updateParent.setId(parent.getId()); + updateParent.setHasChildren(0); + this.updateById(updateParent); + } + } + } + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapcfg/controller/MapmoduleBController.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapcfg/controller/MapmoduleBController.java new file mode 100644 index 00000000..dc0d0a9f --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapcfg/controller/MapmoduleBController.java @@ -0,0 +1,210 @@ +package com.yfd.platform.qgc_sys.mapcfg.controller; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +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.config.ResponseResult; +import com.yfd.platform.common.exception.BizException; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaplegendB; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaplayerB; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMapmoduleB; +import com.yfd.platform.qgc_sys.mapLayer.mapper.MsMaplayerBMapper; +import com.yfd.platform.qgc_sys.mapLayer.service.IMapLegendService; +import com.yfd.platform.qgc_sys.mapcfg.service.IMapmoduleBService; +import com.yfd.platform.qgc_sys.mapcfg.entity.MapmoduleVo; +import com.yfd.platform.system.domain.SysMenu; +import com.yfd.platform.system.mapper.SysMenuMapper; +import com.yfd.platform.utils.DataSourceRequestUtil; +import com.yfd.platform.utils.QgcQueryWrapperUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 地图菜单配置控制层 + * + * @author migration + */ +@RestController +@RequestMapping("/mapmodule") +@Tag(name = "地图菜单配置") +public class MapmoduleBController { + + @Resource + private IMapmoduleBService mapmoduleBService; + + @Resource + private SysMenuMapper sysMenuMapper; + + @Resource + private IMapLegendService mapLegendService; + + @Resource + private MsMaplayerBMapper msMaplayerBMapper; + + /** + * 条件过滤数据列表(Kendo UI 数据源) + */ + @Operation(summary = "条件过滤数据列表") + @PostMapping("/GetKendoList") + public ResponseResult getKendoList(@RequestBody DataSourceRequest dataSourceRequest) { + // 1. 构建查询条件 + QueryWrapper wrapper = DataSourceRequestUtil.buildQueryWrapper( + dataSourceRequest, MsMapmoduleB.class); + + // 2. 分页参数处理(与 getMsstbprptList 完全一致) + DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest(); + Page page = loadOptions == null ? null + : (Page) QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake()); + + // 3. 执行分页查询 + Page resultPage; + if (page != null) { + resultPage = mapmoduleBService.page(page, wrapper); + } else { + List list = mapmoduleBService.list(wrapper); + resultPage = new Page<>(); + resultPage.setRecords(list); + resultPage.setTotal(list.size()); + } + + // 4. 构建 Kendo 数据源结果 + DataSourceResult dataSourceResult = new DataSourceResult<>(); + List dataList = resultPage.getRecords(); + dataSourceResult.setData(dataList); + dataSourceResult.setTotal(resultPage.getTotal()); + + // 5. 翻译与额外字段填充(原有逻辑保持不变) + if (dataList != null && !dataList.isEmpty()) { + mapmoduleBService.translateDict(dataList); + + Set needQueryIds = dataList.stream() + .map(MsMapmoduleB::getModuleId) + .filter(id -> id != null && !"tycd".equals(id)) + .collect(Collectors.toSet()); + + Map menuNameMap = new HashMap<>(); + if (!needQueryIds.isEmpty()) { + List menus = sysMenuMapper.selectList( + new LambdaQueryWrapper() + .in(SysMenu::getId, needQueryIds) + ); + menuNameMap = menus.stream() + .collect(Collectors.toMap( + menu -> String.valueOf(menu.getId()), + SysMenu::getName + )); + } + + for (MsMapmoduleB entity : dataList) { + // 填充 moduleName + String moduleId = entity.getModuleId(); + if (moduleId == null) { + entity.setModuleName(null); + } else if ("tycd".equals(moduleId)) { + entity.setModuleName("通用菜单"); + entity.setChecked(1); + } else { + entity.setModuleName(menuNameMap.get(moduleId)); + } + + // 特殊 systemName + if ("qgc".equals(entity.getSystemId())) { + entity.setSystemName("qgc"); + } + } + } + + return ResponseResult.successData(dataSourceResult); + } + + /** + * 地图图例关联系统及菜单 + */ + @Operation(summary = "地图图例关联系统及菜单") + @PostMapping("/save") + public ResponseResult saveOrUpdate(@RequestBody MsMapmoduleB mapmoduleB) { + if (mapmoduleB == null) { + throw new BizException("对象不能为空."); + } + if (StrUtil.isBlank(mapmoduleB.getModuleId())) { + throw new BizException("关联菜单(moduleId)不能为空."); + } + if (StrUtil.isBlank(mapmoduleB.getSystemId())) { + throw new BizException("关联系统(systemId)不能为空."); + } + if (StrUtil.isBlank(mapmoduleB.getResType())) { + throw new BizException("资源类型(resType: layer=图层,legend=图例,mapbox=地图)不能为空"); + } + if (StrUtil.isBlank(mapmoduleB.getResId())) { + throw new BizException("资源(resId)不能为空."); + } + + if ("legend".equals(mapmoduleB.getResType())) { + MsMaplegendB maplegendB = mapLegendService.getById(mapmoduleB.getResId()); + if (maplegendB != null && StrUtil.isNotBlank(maplegendB.getLayerCode())) { + LambdaQueryWrapper layerWrapper = new LambdaQueryWrapper<>(); + layerWrapper.eq(MsMaplayerB::getCode, maplegendB.getLayerCode()); + layerWrapper.eq(MsMaplayerB::getIsDeleted, 0); + MsMaplayerB layer = msMaplayerBMapper.selectOne(layerWrapper); + if (layer != null) { + LambdaQueryWrapper moduleWrapper = new LambdaQueryWrapper<>(); + moduleWrapper.eq(MsMapmoduleB::getModuleId, mapmoduleB.getModuleId()); + moduleWrapper.eq(MsMapmoduleB::getSystemId, mapmoduleB.getSystemId()); + moduleWrapper.eq(MsMapmoduleB::getResType, "layer"); + moduleWrapper.eq(MsMapmoduleB::getResId, layer.getId()); + moduleWrapper.eq(MsMapmoduleB::getIsDeleted, 0); + long count = mapmoduleBService.count(moduleWrapper); + + if (count <= 0) { + MsMapmoduleB layerModule = new MsMapmoduleB(); + layerModule.setModuleId(mapmoduleB.getModuleId()); + layerModule.setSystemId(mapmoduleB.getSystemId()); + layerModule.setResType("layer"); + layerModule.setResId(layer.getId()); + layerModule.setChildNode(mapmoduleB.getChildNode()); + layerModule.setMultiSelect(mapmoduleB.getMultiSelect()); + layerModule.setCanBeChecked(mapmoduleB.getCanBeChecked()); + layerModule.setChecked(mapmoduleB.getChecked()); + layerModule.setDescription(mapmoduleB.getDescription()); + layerModule.setEnable(mapmoduleB.getEnable()); + layerModule.setOrderIndex(mapmoduleB.getOrderIndex()); + layerModule.setFilterContent(mapmoduleB.getFilterContent()); + mapmoduleBService.saveOrUpdate(layerModule); + } + } + } + } + + return ResponseResult.successData(mapmoduleBService.saveOrUpdate(mapmoduleB)); + } + + /** + * 图例与系统菜单关联关系删除 + */ + @Operation(summary = "图例与系统菜单关联关系删除") + @PostMapping("/delete") + public ResponseResult deleteData(@RequestBody List ids) { + mapmoduleBService.delelteByIds(ids); + return ResponseResult.success("删除成功."); + } + + + /** + * 地图图层管理数据 + */ + @Operation(summary = "地图图层管理数据") + @PostMapping("/getMapData") + public ResponseResult getMapData(@RequestBody MsMapmoduleB mapmoduleB) { + MapmoduleVo result = mapmoduleBService.getMapData(mapmoduleB); + return ResponseResult.successData(result); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapcfg/entity/MapmoduleVo.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapcfg/entity/MapmoduleVo.java new file mode 100644 index 00000000..30134555 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapcfg/entity/MapmoduleVo.java @@ -0,0 +1,47 @@ +package com.yfd.platform.qgc_sys.mapcfg.entity; + +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaptoolboxB; +import com.yfd.platform.qgc_sys.mapLayer.entity.vo.MapLayerVo; +import com.yfd.platform.qgc_sys.mapLayer.entity.vo.MapLegendVo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * 地图与菜单查询返回实体类 + * + * @author migration + */ +@Data +@Schema(description = "地图菜单配置实体类") +public class MapmoduleVo { + + /** GIS地图多功能区 */ + @Schema(description = "GIS地图多功能区") + private List maptoolbox; + + /** GIS默认数据加载 - 地形 */ + @Schema(description = "GIS默认数据加载 - 地形") + private List terrain; + + /** GIS默认数据加载 - 图例 */ + @Schema(description = "GIS默认数据加载 - 图例") + private List legend; + + /** GIS默认数据加载 - 内容模块 */ + @Schema(description = "GIS默认数据加载 - 内容模块") + private List content; + + /** GIS默认数据加载 - 环保监测 */ + @Schema(description = "GIS默认数据加载 - 环保监测") + private List hbcj; + + /** GIS图层区 */ + @Schema(description = "GIS图层区") + private List mapLayerVos; + + /** 地图图例 */ + @Schema(description = "地图图例") + private List mapLegendVos; +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapcfg/service/IMapmoduleBService.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapcfg/service/IMapmoduleBService.java new file mode 100644 index 00000000..c6dcf69c --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapcfg/service/IMapmoduleBService.java @@ -0,0 +1,45 @@ +package com.yfd.platform.qgc_sys.mapcfg.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMapmoduleB; +import com.yfd.platform.qgc_sys.mapcfg.entity.MapmoduleVo; + +import java.util.List; + +/** + * 地图菜单配置服务接口 + * + * @author migration + */ +public interface IMapmoduleBService extends IService { + + /** + * 新增或修改 + * + * @param entity 实体 + * @return 是否成功 + */ + boolean saveOrUpdate(MsMapmoduleB entity); + + /** + * 翻译字典值(菜单名称) + * + * @param list 数据列表 + */ + void translateDict(List list); + + /** + * 根据ID列表删除关联关系 + * + * @param ids ID列表 + */ + void delelteByIds(List ids); + + /** + * 获取地图数据(图层树、图例、工具箱) + * + * @param mapmoduleB 查询参数 + * @return 地图数据 + */ + MapmoduleVo getMapData(MsMapmoduleB mapmoduleB); +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/qgc_sys/mapcfg/service/impl/MapmoduleBServiceImpl.java b/backend/src/main/java/com/yfd/platform/qgc_sys/mapcfg/service/impl/MapmoduleBServiceImpl.java new file mode 100644 index 00000000..1b7b5098 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/qgc_sys/mapcfg/service/impl/MapmoduleBServiceImpl.java @@ -0,0 +1,183 @@ +package com.yfd.platform.qgc_sys.mapcfg.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMapmoduleB; +import com.yfd.platform.qgc_sys.mapLayer.domain.MsMaptoolboxB; +import com.yfd.platform.qgc_sys.mapLayer.mapper.MsMapmoduleBMapper; +import com.yfd.platform.qgc_sys.mapLayer.service.IMapLayerBizService; +import com.yfd.platform.qgc_sys.mapLayer.service.IMapLegendBizService; +import com.yfd.platform.qgc_sys.mapcfg.service.IMapmoduleBService; +import com.yfd.platform.qgc_sys.mapLayer.entity.vo.MapLayerVo; +import com.yfd.platform.qgc_sys.mapLayer.entity.vo.MapLegendVo; +import com.yfd.platform.qgc_sys.mapcfg.entity.MapmoduleVo; + +import com.yfd.platform.system.domain.SysMenu; +import com.yfd.platform.system.mapper.SysMenuMapper; +import com.yfd.platform.utils.SecurityUtils; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 地图菜单配置服务实现类 + * + * @author migration + */ +@Service +public class MapmoduleBServiceImpl extends ServiceImpl + implements IMapmoduleBService { + + @Resource + private SysMenuMapper sysMenuMapper; + + @Resource + private IMapLayerBizService mapLayerBizService; + + @Resource + private IMapLegendBizService mapLegendBizService; + + + + @Override + public boolean saveOrUpdate(MsMapmoduleB entity) { + if (StrUtil.isBlank(entity.getId())) { + // 新增 + entity.setRecordUser(SecurityUtils.getUserId()); + this.baseMapper.insert(entity); + } else { + // 修改 + this.baseMapper.updateById(entity); + } + return true; + } + + @Override + public void delelteByIds(List ids) { + if (ids != null) { + for (String id : ids) { + this.baseMapper.deleteById(id); + } + } + } + + @Override + public void translateDict(List list) { + if (list == null || list.isEmpty()) { + return; + } + // 收集所有 moduleId + List moduleIds = list.stream() + .filter(it -> StrUtil.isNotBlank(it.getModuleId())) + .map(MsMapmoduleB::getModuleId) + .distinct() + .collect(Collectors.toList()); + + if (moduleIds.isEmpty()) { + return; + } + + // 查询本地菜单表获取名称 + LambdaQueryWrapper menuWrapper = new LambdaQueryWrapper<>(); + menuWrapper.in(SysMenu::getId, moduleIds); + List menus = sysMenuMapper.selectList(menuWrapper); + + Map menuMap = new HashMap<>(); + menuMap.put("common", "通用菜单"); + for (SysMenu menu : menus) { + menuMap.put(menu.getId(), menu.getName()); + } + + // 设置菜单名称 + for (MsMapmoduleB item : list) { + if (StrUtil.isNotBlank(item.getModuleId())) { + String name = menuMap.get(item.getModuleId()); + if (name != null) { + item.setModuleName(name); + } + } + } + } + + + @Override + public MapmoduleVo getMapData(MsMapmoduleB mapmoduleB) { + // 模板ID:暂时不使用MS_TEMPLATE_B表,直接取传入的templateId + String templateId = mapmoduleB.getTemplateId(); + + // ========== 以下代码预留:后续启用MS_TEMPLATE_B表时使用 ========== + // String templateId = null; + // // getDescription用于区分是在模块页面中还是在系统配置中调用该接口 + // if (StrUtil.isBlank(mapmoduleB.getTemplateId()) && StrUtil.isNotBlank(mapmoduleB.getDescription())) { + // // 如果用户没有该模块的模板权限,但该模块有指定默认模板,则返回默认模板数据。 + // LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); + // lambdaQueryWrapper.eq(MsTemplateB::getIsDefault, 1); + // lambdaQueryWrapper.eq(MsTemplateB::getIsDeleted, 0); + // lambdaQueryWrapper.eq(MsTemplateB::getModuleId, mapmoduleB.getModuleId()); + // MsTemplateB msTemplateB = msTemplateBMapper.selectOne(lambdaQueryWrapper); + // if (msTemplateB != null) { + // templateId = msTemplateB.getId(); + // } + // } else { + // templateId = mapmoduleB.getTemplateId(); + // } + // ========== 预留代码结束 ========== + + MapmoduleVo mapmoduleVo = new MapmoduleVo(); + + // 1. GIS图层区 + List layer = mapLayerBizService.getMapLayerTree( + mapmoduleB.getModuleId(), mapmoduleB.getSystemId(), templateId); + mapmoduleVo.setMapLayerVos(layer); + + // 2. 地图图例 + List legend = mapLegendBizService.getModuleMapLegendList( + mapmoduleB.getModuleId(), mapmoduleB.getSystemId(), templateId); + mapmoduleVo.setMapLegendVos(legend); + + // 3. 地图工具箱 + List mapToolBox = baseMapper.getMapToolBox( + mapmoduleB.getModuleId(), mapmoduleB.getSystemId(), templateId); + + // 按toolType分组 + Map> groupedByType = mapToolBox.stream() + .collect(Collectors.groupingBy(MsMaptoolboxB::getToolType)); + + // 图例(toolType=2) + mapmoduleVo.setLegend(groupedByType.get(2)); + + // 内容模块(toolType=3) + List contentLayerTree = getContentLayerTree(groupedByType); + mapmoduleVo.setContent(contentLayerTree); + + // 环保监测(toolType=4) + mapmoduleVo.setHbcj(groupedByType.get(4)); + + return mapmoduleVo; + } + + /** + * 获取内容模块图层树 + */ + private List getContentLayerTree(Map> groupedByType) { + List msMaptoolboxBList = new java.util.ArrayList<>(); + List contentToolBoxList = groupedByType.get(3); + if (contentToolBoxList != null) { + for (MsMaptoolboxB msMaptoolboxB : contentToolBoxList) { + if (StrUtil.isNotBlank(msMaptoolboxB.getPatentId())) { + // 如果内容模块没有进行配置,则默认全部勾选 + if (msMaptoolboxB.getChecked() == null) { + msMaptoolboxB.setChecked(1); + } + msMaptoolboxBList.add(msMaptoolboxB); + } + } + } + return msMaptoolboxBList; + } +} \ No newline at end of file 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 diff --git a/backend/src/main/java/com/yfd/platform/utils/QgcQueryWrapperUtil.java b/backend/src/main/java/com/yfd/platform/utils/QgcQueryWrapperUtil.java index 3554573d..62a60bab 100644 --- a/backend/src/main/java/com/yfd/platform/utils/QgcQueryWrapperUtil.java +++ b/backend/src/main/java/com/yfd/platform/utils/QgcQueryWrapperUtil.java @@ -37,6 +37,11 @@ public class QgcQueryWrapperUtil { return FIELDNULL.contains(columName) ? "00000000-0000-0000-0000-000000000000" : null; } + @FunctionalInterface + public interface ColumnMapper { + String apply(String field); + } + public static String getFilterFieldValue(DataSourceLoadOptionsBase loadOptions, String fieldName) { try { JsonElement jsonElement = (new JsonParser()).parse(JSONUtil.toJsonStr(loadOptions.getFilter())); @@ -702,6 +707,239 @@ public class QgcQueryWrapperUtil { } + + + public static String buildFilterCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder, + ColumnMapper columnMapper) { + if (filter == null) { + return ""; + } + List conditions = new ArrayList<>(); + List filters = filter.getFilters(); + if (CollectionUtil.isNotEmpty(filters)) { + for (DataSourceRequest.FilterDescriptor child : filters) { + String condition = buildFilterCondition(child, paramMap, indexHolder, columnMapper); + if (StrUtil.isNotBlank(condition)) { + conditions.add(condition); + } + } + } else { + String leafCondition = buildLeafCondition(filter, paramMap, indexHolder, columnMapper); + if (StrUtil.isNotBlank(leafCondition)) { + conditions.add(leafCondition); + } + } + if (conditions.isEmpty()) { + return ""; + } + String logic = "or".equalsIgnoreCase(filter.getLogic()) ? " OR " : " AND "; + return "(" + String.join(logic, conditions) + ")"; + } + + private static String buildLeafCondition(DataSourceRequest.FilterDescriptor filter, + Map paramMap, + int[] indexHolder, + ColumnMapper columnMapper) { + String column = columnMapper.apply(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 = normalizeValues(filter.getValue()); + if (values.isEmpty()) { + return ""; + } + List placeholders = new ArrayList<>(); + boolean isDateField = isDateColumn(column); + for (Object value : values) { + String paramKey = "param" + indexHolder[0]++; + paramMap.put(paramKey, value); + if (isDateField) { + String text = String.valueOf(value).trim(); + if (text.length() <= 10) { + placeholders.add("TO_DATE(#{map." + paramKey + "}, 'YYYY-MM-DD')"); + } else { + placeholders.add("TO_DATE(#{map." + paramKey + "}, 'YYYY-MM-DD HH24:MI:SS')"); + } + } else { + placeholders.add("#{map." + paramKey + "}"); + } + } + String prefix = "ni".equals(operator) ? "NOT " : ""; + return column + " " + prefix + "IN (" + String.join(", ", placeholders) + ")"; + } + String paramKey = "param" + indexHolder[0]++; + paramMap.put(paramKey, filter.getValue()); + boolean isDateField = isDateColumn(column); + String valueExpr; + if (isDateField) { + String text = String.valueOf(filter.getValue()).trim(); + if (text.length() <= 10) { + valueExpr = "TO_DATE(#{map." + paramKey + "}, 'YYYY-MM-DD')"; + } else { + valueExpr = "TO_DATE(#{map." + paramKey + "}, 'YYYY-MM-DD HH24:MI:SS')"; + } + } else { + valueExpr = "#{map." + paramKey + "}"; + } + return switch (operator) { + case "lt", "lessthan" -> column + " < " + valueExpr; + case "lte", "lessthanorequals" -> column + " <= " + valueExpr; + case "gt", "greaterthan" -> column + " > " + valueExpr; + case "gte", "greaterthanorequals" -> column + " >= " + valueExpr; + case "ne", "notequals" -> column + " <> " + valueExpr; + case "contains", "doesnotcontain", "startswith", "endswith" -> { + String pattern = switch (operator) { + case "contains" -> "%#{map." + paramKey + "}%"; + case "doesnotcontain" -> "%#{map." + paramKey + "}%"; + case "startswith" -> "#{map." + paramKey + "}%"; + case "endswith" -> "%#{map." + paramKey + "}"; + default -> "%#{map." + paramKey + "}%"; + }; + String likePrefix = "doesnotcontain".equals(operator) ? "NOT " : ""; + yield column + " " + likePrefix + "LIKE " + pattern; + } + default -> column + " = " + valueExpr; + }; + } + + private static List normalizeValues(Object value) { + List result = new ArrayList<>(); + if (value == null) { + return result; + } + if (value instanceof List) { + for (Object item : (List) value) { + if (item != null && StrUtil.isNotBlank(item.toString())) { + result.add(item); + } + } + } else if (StrUtil.isNotBlank(value.toString())) { + result.add(value); + } + return result; + } + + private static boolean isDateColumn(String column) { + if (StrUtil.isBlank(column)) { + return false; + } + String lowerColumn = column.toLowerCase(); + return lowerColumn.contains(".tm") || lowerColumn.contains(".time") || lowerColumn.contains(".date"); + } + + public static String buildOrderBySql(List sorts, + ColumnMapper columnMapper, + String defaultOrderBy) { + if (CollectionUtil.isEmpty(sorts)) { + return StrUtil.isNotBlank(defaultOrderBy) ? " ORDER BY " + defaultOrderBy : ""; + } + List orderByParts = new ArrayList<>(); + for (DataSourceRequest.SortDescriptor sort : sorts) { + if (sort == null || StrUtil.isBlank(sort.getField())) { + continue; + } + String column = columnMapper.apply(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 StrUtil.isNotBlank(defaultOrderBy) ? " ORDER BY " + defaultOrderBy : ""; + } + return " ORDER BY " + String.join(", ", orderByParts); + } + + public static String buildGroupSql(DataSourceRequest dataSourceRequest, StringBuilder sql) { + if (CollectionUtil.isEmpty(dataSourceRequest.getGroup())) { + return null; + } + String groupBy = KendoUtil.getGroupBy(dataSourceRequest); + if (StrUtil.isBlank(groupBy)) { + return null; + } + List groupFields = new ArrayList<>(); + for (DataSourceRequest.GroupDescriptor item : dataSourceRequest.getGroup()) { + if (item != null && StrUtil.isNotBlank(item.getField())) { + groupFields.add(item.getField()); + } + } + StringBuilder temp = new StringBuilder(); + temp.append("SELECT ").append(String.join(",", groupFields)).append(", count(*) as "); + if (groupFields.size() > 1) { + temp.append("count"); + } else { + temp.append("count_").append(String.join("_", groupFields)); + } + return temp.append(" FROM ( ").append(sql).append(" ) ").append(groupBy).toString(); + } + + public static DataSourceResult buildGroupResult(DataSourceRequest dataSourceRequest, + List> rows) { + DataSourceResult result = new DataSourceResult<>(); + List groupingInfos = convertToGroupingInfo(dataSourceRequest.getGroup()); + if (Boolean.TRUE.equals(dataSourceRequest.getGroupResultFlat())) { + result.setData((List) (List) new GroupHelper().faltGroup(rows, groupingInfos)); + } else { + result.setData((List) (List) new GroupHelper().group(rows, groupingInfos)); + } + result.setTotal((long) rows.size()); + result.setAggregates(new HashMap<>()); + return result; + } + + private static List convertToGroupingInfo(List groupDescriptors) { + List groupingInfos = new ArrayList<>(); + if (CollectionUtil.isEmpty(groupDescriptors)) { + return groupingInfos; + } + for (DataSourceRequest.GroupDescriptor groupDescriptor : groupDescriptors) { + GroupingInfo groupingInfo = new GroupingInfo(); + groupingInfo.setSelector(groupDescriptor.getField()); + String dir = groupDescriptor.getDir(); + String normalizedDir = StrUtil.isBlank(dir) ? "" : dir.toLowerCase(); + if ("des".equals(normalizedDir)) { + normalizedDir = "desc"; + } + if (StrUtil.isBlank(normalizedDir)) { + groupingInfo.setDesc(false); + } else if (normalizedDir.equals("asc")) { + groupingInfo.setDesc(false); + } else if (normalizedDir.equals("desc")) { + groupingInfo.setDesc(true); + } + groupingInfo.setNeedSortFlag(groupDescriptor.getNeedSortFlag()); + List aggregateDescriptors = groupDescriptor.getAggregates(); + if (CollectionUtil.isNotEmpty(aggregateDescriptors)) { + for (DataSourceRequest.AggregateDescriptor aggregateDescriptor : aggregateDescriptors) { + SummaryInfo summaryInfo = new SummaryInfo(); + summaryInfo.setSelector(aggregateDescriptor.getField()); + summaryInfo.setSummaryType(aggregateDescriptor.getAggregate()); + groupingInfo.getSummaryInfos().add(summaryInfo); + } + } + groupingInfos.add(groupingInfo); + } + return groupingInfos; + } + static { FIELDNULL.add("parentId"); } diff --git a/backend/src/main/java/com/yfd/platform/utils/RedisCacheUtil.java b/backend/src/main/java/com/yfd/platform/utils/RedisCacheUtil.java new file mode 100644 index 00000000..2640763f --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/utils/RedisCacheUtil.java @@ -0,0 +1,227 @@ +package com.yfd.platform.utils; + +import jakarta.annotation.Resource; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +@Component +public class RedisCacheUtil { + + @Resource + private RedisTemplate redisTemplate; + + @Resource + private StringRedisTemplate stringRedisTemplate; + + public void set(String key, Object value) { + redisTemplate.opsForValue().set(key, value); + } + + public void set(String key, Object value, long timeout, TimeUnit unit) { + redisTemplate.opsForValue().set(key, value, timeout, unit); + } + + public void set(String key, Object value, long timeoutSeconds) { + redisTemplate.opsForValue().set(key, value, timeoutSeconds, TimeUnit.SECONDS); + } + + @SuppressWarnings("unchecked") + public T get(String key, Class clazz) { + Object value = redisTemplate.opsForValue().get(key); + if (value == null) { + return null; + } + return (T) value; + } + + public Object get(String key) { + return redisTemplate.opsForValue().get(key); + } + + public String getString(String key) { + return stringRedisTemplate.opsForValue().get(key); + } + + public void setString(String key, String value) { + stringRedisTemplate.opsForValue().set(key, value); + } + + public void setString(String key, String value, long timeoutSeconds) { + stringRedisTemplate.opsForValue().set(key, value, timeoutSeconds, TimeUnit.SECONDS); + } + + public void setString(String key, String value, long timeout, TimeUnit unit) { + stringRedisTemplate.opsForValue().set(key, value, timeout, unit); + } + + public Boolean delete(String key) { + return redisTemplate.delete(key); + } + + public Long delete(Collection keys) { + return redisTemplate.delete(keys); + } + + public Boolean exists(String key) { + return redisTemplate.hasKey(key); + } + + public Boolean expire(String key, long timeout, TimeUnit unit) { + return redisTemplate.expire(key, timeout, unit); + } + + public Boolean expire(String key, long timeoutSeconds) { + return redisTemplate.expire(key, timeoutSeconds, TimeUnit.SECONDS); + } + + public Long getExpire(String key) { + return redisTemplate.getExpire(key, TimeUnit.SECONDS); + } + + public Long increment(String key, long delta) { + return redisTemplate.opsForValue().increment(key, delta); + } + + public Long increment(String key) { + return redisTemplate.opsForValue().increment(key, 1); + } + + public Long decrement(String key, long delta) { + return redisTemplate.opsForValue().decrement(key, delta); + } + + public Long decrement(String key) { + return redisTemplate.opsForValue().decrement(key, 1); + } + + public void hSet(String key, String hashKey, Object value) { + redisTemplate.opsForHash().put(key, hashKey, value); + } + + @SuppressWarnings("unchecked") + public T hGet(String key, String hashKey, Class clazz) { + Object value = redisTemplate.opsForHash().get(key, hashKey); + if (value == null) { + return null; + } + return (T) value; + } + + public Object hGet(String key, String hashKey) { + return redisTemplate.opsForHash().get(key, hashKey); + } + + public Map hGetAll(String key) { + return redisTemplate.opsForHash().entries(key); + } + + public void hSetAll(String key, Map map) { + redisTemplate.opsForHash().putAll(key, map); + } + + public void hDelete(String key, Object... hashKeys) { + redisTemplate.opsForHash().delete(key, hashKeys); + } + + public Boolean hExists(String key, String hashKey) { + return redisTemplate.opsForHash().hasKey(key, hashKey); + } + + public Long hSize(String key) { + return redisTemplate.opsForHash().size(key); + } + + public Set hKeys(String key) { + return redisTemplate.opsForHash().keys(key); + } + + public List hValues(String key) { + return redisTemplate.opsForHash().values(key); + } + + public Long lPush(String key, Object... values) { + return redisTemplate.opsForList().leftPushAll(key, values); + } + + public Long rPush(String key, Object... values) { + return redisTemplate.opsForList().rightPushAll(key, values); + } + + public Object lPop(String key) { + return redisTemplate.opsForList().leftPop(key); + } + + public Object rPop(String key) { + return redisTemplate.opsForList().rightPop(key); + } + + public List lRange(String key, long start, long end) { + return redisTemplate.opsForList().range(key, start, end); + } + + public Long lSize(String key) { + return redisTemplate.opsForList().size(key); + } + + public void lTrim(String key, long start, long end) { + redisTemplate.opsForList().trim(key, start, end); + } + + public Long sAdd(String key, Object... values) { + return redisTemplate.opsForSet().add(key, values); + } + + public Set sMembers(String key) { + return redisTemplate.opsForSet().members(key); + } + + public Boolean sIsMember(String key, Object value) { + return redisTemplate.opsForSet().isMember(key, value); + } + + public Long sRemove(String key, Object... values) { + return redisTemplate.opsForSet().remove(key, values); + } + + public Long sSize(String key) { + return redisTemplate.opsForSet().size(key); + } + + public boolean zAdd(String key, Object value, double score) { + return redisTemplate.opsForZSet().add(key, value, score); + } + + public Set zRange(String key, long start, long end) { + return redisTemplate.opsForZSet().range(key, start, end); + } + + public Double zScore(String key, Object value) { + return redisTemplate.opsForZSet().score(key, value); + } + + public Long zRemove(String key, Object... values) { + return redisTemplate.opsForZSet().remove(key, values); + } + + public Long zSize(String key) { + return redisTemplate.opsForZSet().size(key); + } + + public Set keys(String pattern) { + return redisTemplate.keys(pattern); + } + +// public void flushDb() { +// redisTemplate.execute((connection) -> { +// connection.flushDb(); +// return null; +// }); +// } +} \ No newline at end of file diff --git a/backend/src/main/resources/application-dev.yml b/backend/src/main/resources/application-dev.yml index 0b53e07c..ccbcb104 100644 --- a/backend/src/main/resources/application-dev.yml +++ b/backend/src/main/resources/application-dev.yml @@ -22,6 +22,18 @@ spring: mvc: pathmatch: matching-strategy: ant_path_matcher + data: + redis: + host: ${REDIS_HOST:localhost} + port: ${REDIS_PORT:6379} + password: ${REDIS_PASSWORD:} + timeout: 10000ms + lettuce: + pool: + max-active: 8 + max-idle: 8 + min-idle: 2 + max-wait: 10000ms servlet: multipart: max-file-size: 300MB @@ -98,3 +110,9 @@ task: keep-alive-seconds: 60 # 队列容量 queue-capacity: 50 + +attachment: + token: ${ATTACHMENT_TOKEN:qgcBkod25ngBa4wu8BtfCPYsJ7lQGVDoexH} + upload-url: ${ATTACHMENT_UPLOAD_URL:http://172.16.31.185:18200/upload} + video-url: ${ATTACHMENT_VIDEO_URL:http://172.16.31.185:18200/upload} + delete-url: ${ATTACHMENT_DELETE_URL:http://172.16.31.185:18200/delete} diff --git a/backend/src/main/resources/application-prod.yml b/backend/src/main/resources/application-prod.yml index b125d232..294c61ea 100644 --- a/backend/src/main/resources/application-prod.yml +++ b/backend/src/main/resources/application-prod.yml @@ -109,6 +109,18 @@ spring: mvc: pathmatch: matching-strategy: ant_path_matcher + data: + redis: + host: ${REDIS_HOST:localhost} + port: ${REDIS_PORT:6379} + password: ${REDIS_PASSWORD:} + timeout: 10000ms + lettuce: + pool: + max-active: 8 + max-idle: 8 + min-idle: 2 + max-wait: 10000ms servlet: multipart: max-file-size: 300MB diff --git a/frontend/.env.development b/frontend/.env.development index 0a810935..40dff0cf 100644 --- a/frontend/.env.development +++ b/frontend/.env.development @@ -7,7 +7,7 @@ VITE_APP_TITLE = '水电水利建设项目全过程环境管理信息平台' VITE_APP_PORT = 3000 VITE_APP_BASE_API = '/dev-api' # 本地环境 -VITE_APP_BASE_URL = 'http://localhost:8093' +# VITE_APP_BASE_URL = 'http://10.84.121.122:8093' # 测试环境 # VITE_APP_BASE_URL = 'http://172.16.21.142:8093' # VITE_APP_BASE_URL = 'http://172.16.21.142:8096' diff --git a/frontend/src/api/home/index.ts b/frontend/src/api/home/index.ts index 0ead2e2c..6c3732c4 100644 --- a/frontend/src/api/home/index.ts +++ b/frontend/src/api/home/index.ts @@ -8,3 +8,102 @@ export function getBaseWbsb(data: any) { data: data }); } + +// 水电开发及环境监测 - 获取列表数据 +export function getVmsstbprptKendoList(data: any) { + return request({ + url: '/api/dec-lygk-base-server/base/vmsstbprpt/GetKendoList', + method: 'post', + data: data + }); +} + +// 环保设施建设情况 +export function environmentalProtectionConstruction(data: any) { + return request({ + url: '/api/wmp-env-server/env/operat/GetKendoListCust', + method: 'post', + data: data + }); +} + +// 环保设施弹框表格 +export function envOpdGetKendoListCust(data: any) { + return request({ + url: '/api/wmp-env-server/env/oped/GetKendoListCust', + method: 'post', + data: data + }); +} + +// 获取基地列表 +export function getBaseList(data: any) { + return request({ + url: '/api/dec-lygk-base-server/base/wbsb/GetKendoList', + method: 'post', + data: data + }); +} + +// 获取设施介绍列表 +export function getMsstbprptKendoList(data: any) { + return request({ + url: '/api/dec-lygk-base-server/base/msstbprpt/GetKendoList', + method: 'post', + data: data + }); +} + +// 环保自动监测工作开展情况 +export function baseEvnmAutoMonitorGetKendoListCust(data: any) { + return request({ + url: '/api/dec-lygk-base-server/base/evnmAutoMonitor/GetKendoListCust', + method: 'post', + data: data + }); +} + +// 环保自动监测弹窗列表 +export function vmsstbprptGetKendoList(data: any) { + return request({ + url: '/api/dec-lygk-base-server/base/vmsstbprpt/GetKendoList', + method: 'post', + data: data + }); +} + +// 获取基本信息 +export function baseMsstbprptGetKendoList(data: any) { + return request({ + url: '/api/dec-lygk-base-server/base/msstbprpt/GetKendoList', + method: 'post', + data: data + }); +} + +// 降水量实时数据 +export function getBaseStbprpDataPPTNR(data: any) { + return request({ + url: '/api/dec-lygk-base-server/base/stbprpData/GetKendoListCust?tbCode=PPTN_R', + method: 'post', + data: data + }); +} + +// 气温气压实时数据 +export function getBaseStbprpDataTMPR(data: any) { + return request({ + url: '/api/dec-lygk-base-server/base/stbprpData/GetKendoListCust?tbCode=TMP_R', + method: 'post', + data: data + }); +} + +// 风速风向实时数据 +export function getBaseStbprpDataWNDR(data: any) { + return request({ + url: '/api/dec-lygk-base-server/base/stbprpData/GetKendoListCust?tbCode=WND_R', + method: 'post', + data: data + }); +} diff --git a/frontend/src/api/stdc/index.ts b/frontend/src/api/stdc/index.ts index ce9c8d6e..db86bca5 100644 --- a/frontend/src/api/stdc/index.ts +++ b/frontend/src/api/stdc/index.ts @@ -3,16 +3,16 @@ import request from '@/utils/request'; //水生生态调查情况-下拉选择框 export function wbsbGetKendoList(data: any) { return request({ - url: '/api/dec-lygk-base-server/base/wbsb/GetKendoList', + url: '/eq/wbsb/GetKendoList', method: 'post', data }); } -// 水生生态调查情况-获取默认年份 +// 水生生态调查情况-获取默认年份 export function getDftYear(data: any) { return request({ - url: '/api/wmp-env-server/env/we/fisht/year/qgc/GetKendoListCust', + url: '/wte/we/fisht/year/qgc/GetKendoListCust', method: 'post', data }); @@ -21,7 +21,7 @@ export function getDftYear(data: any) { // 水生生态调查情况-获取统计数据 export function getWeFisht(data: any) { return request({ - url: '/api/wmp-env-server/env/we/fisht/statics/GetKendoListCust', + url: '/wte/we/fisht/statics/GetKendoListCust', method: 'post', data }); @@ -30,7 +30,7 @@ export function getWeFisht(data: any) { // 水生生态调查概况-表格数据接口 export function getWeStaticsSecond(data: any) { return request({ - url: '/api/wmp-env-server/env/we/fisht/statics/getWeStaticsSecond', + url: '/wte/we/fisht/statics/getWeStaticsSecond', method: 'post', data }); @@ -39,7 +39,7 @@ export function getWeStaticsSecond(data: any) { // 沿程鱼类变化-图表数据接口 export function fishChanges2(data: any) { return request({ - url: '/api/wmp-env-server/env/we/fisht/stat/GetKendoListCust', + url: '/wte/we/fisht/stat/GetKendoListCust', method: 'post', data }); @@ -48,7 +48,7 @@ export function fishChanges2(data: any) { // 沿程鱼类变化-详情表格接口 export function fishDetail(data: any) { return request({ - url: '/api/wmp-env-server/env/we/fisht/detail/GetKendoListCust', + url: '/wte/we/fisht/detail/GetKendoListCust', method: 'post', data }); @@ -57,7 +57,7 @@ export function fishDetail(data: any) { // 沿程鱼类变化-Tab数量统计接口 export function getTabNum(data: any) { return request({ - url: '/api/wmp-env-server/env/we/fisht/statTab/GetKendoListCust', + url: '/wte/we/fisht/statTab/GetKendoListCust', method: 'post', data }); @@ -66,11 +66,11 @@ export function getTabNum(data: any) { // 沿程鱼类变化-获取断面列表 export function getStcdList(data: any) { return request({ - url: '/api/dec-lygk-base-server/base/vmsstbprpt/noWqDtinType0Auth/GetKendoList', + url: '/eq/base/vmsstbprpt/GetKendoList', method: 'post', data: { filter: data, - orders: JSON.stringify({ siteStepSort: 'asc' }) + orders: { siteStepSort: 'asc' } } }); } @@ -78,7 +78,16 @@ export function getStcdList(data: any) { // 沿程鱼类变化-基地模式详情表格接口 export function fishQgcDetail(data: any) { return request({ - url: '/api/wmp-env-server/env/we/fisht/qgcDetail/GetKendoListCust', + url: '/wte/we/fisht/qgcDetail/GetKendoListCust', + method: 'post', + data + }); +} + +// 水生生态调查-鱼类列表统计 +export function getFishListStat(data: any) { + return request({ + url: '/wte/we/fishList/stat/qgc/GetKendoListCust', method: 'post', data }); @@ -87,7 +96,7 @@ export function fishQgcDetail(data: any) { // 陆生生态监测情况-获取统计数据 export function getEvnmAutoMonitor(data: any) { return request({ - url: '/api/dec-lygk-base-server/base/evnmAutoMonitor/GetKendoListCust', + url: '/wte/base/evnmAutoMonitor/GetKendoListCust', method: 'post', data }); @@ -96,7 +105,7 @@ export function getEvnmAutoMonitor(data: any) { // 陆生生态监测-红外相机信息表格 export function getVmsstbprptList(data: any) { return request({ - url: '/api/dec-lygk-base-server/base/vmsstbprpt/GetKendoList', + url: '/wte/vmsstbprpt/GetKendoList', method: 'post', data }); @@ -105,7 +114,7 @@ export function getVmsstbprptList(data: any) { // 陆生生态监测-重点陆生动物表格 export function getTetSpecList(data: any) { return request({ - url: '/api/wmp-env-server/te/tet/spec/GetKendoListCust', + url: '/wte/te/tet/spec/GetKendoListCust', method: 'post', data }); @@ -114,7 +123,7 @@ export function getTetSpecList(data: any) { // 野生动物监测-获取运行数据 export function getWvaData(data: any) { return request({ - url: '/api/wmp-env-server/env/wva/GetKendoListCust', + url: '/wte/wva/GetKendoListCust', method: 'post', data }); @@ -123,7 +132,7 @@ export function getWvaData(data: any) { // 野生动物监测-获取默认数据 export function getWvaDftData(data: any) { return request({ - url: '/api/wmp-env-server/env/wva/default/GetKendoListCust', + url: '/wte/wva/default/GetKendoListCust', method: 'post', data }); @@ -132,7 +141,25 @@ export function getWvaDftData(data: any) { // 野生动物监测-获取默认年份列表 export function getWvaDftTm(data: any) { return request({ - url: '/api/wmp-env-server/env/wva/year/GetKendoListCust', + url: '/wte/wva/year/GetKendoListCust', + method: 'post', + data + }); +} + +// 水生生态调查对比-获取断面和批次列表 +export function getFishtKendoList(data: any) { + return request({ + url: '/wte/we/fisht/GetKendoListCust', + method: 'post', + data + }); +} + +// 水生生态调查对比-获取对比柱状图数据 +export function getCompareBar(data: any) { + return request({ + url: '/wte/we/compareBar/GetKendoListCust', method: 'post', data }); diff --git a/frontend/src/api/stll/index.ts b/frontend/src/api/stll/index.ts index 58db464a..bfa8ced7 100644 --- a/frontend/src/api/stll/index.ts +++ b/frontend/src/api/stll/index.ts @@ -39,6 +39,13 @@ export function vmsstbprptGetKendoList(queryParams: any) { data: queryParams }); } +export function vmsstbprptGetKendoList1(queryParams: any) { + return request({ + url: '/eq/vmsstbprpt/GetKendoList', + method: 'post', + data: queryParams + }); +} //生态流量达标情况 export function eqqecRateCount(queryParams: any) { return request({ diff --git a/frontend/src/api/yldc/index.ts b/frontend/src/api/yldc/index.ts index 4643b2f1..3282a2ac 100644 --- a/frontend/src/api/yldc/index.ts +++ b/frontend/src/api/yldc/index.ts @@ -15,6 +15,13 @@ export function msstbprptGetKendoList(data: any) { data }); } +export function VDmsstbprptGetKendoList(data: any) { + return request({ + url: '/vd/msstbprpt/GetKendoList', + method: 'post', + data + }); +} //获取鱼类介绍 export function fishDicGetKendoList(data: any) { return request({ diff --git a/frontend/src/api/zngj/index.ts b/frontend/src/api/zngj/index.ts new file mode 100644 index 00000000..c7b1bc6b --- /dev/null +++ b/frontend/src/api/zngj/index.ts @@ -0,0 +1,91 @@ +import request from '@/utils/request'; + +// AI识别大坝环境-获取统计数据(Tab数量) +export function getAisbdbyxList(data: any) { + return request({ + url: '/api/wmp-env-server/env/ai/com/qgcDmRun/GetKendoListCust', + method: 'post', + data + }); +} + +// AI识别大坝环境-获取饼图+表格数据 +export function getAiChartTable(data: any) { + return request({ + url: '/api/wmp-env-server/env/ai/com/GetKendoListCust', + method: 'post', + data + }); +} + +// AI识别大坝环境-获取电站列表 +export function getAiRstcd(data: any) { + return request({ + url: '/api/wmp-env-server/env/ai/com/qgc/aiRstcd/GetKendoListCust', + method: 'post', + data + }); +} + +// AI识别过鱼设施运行-获取统计数据 +export function getAiGyssList(data: any) { + return request({ + url: '/api/wmp-env-server/env/ai/com/qgcProtect/GetKendoListCust', + method: 'post', + data + }); +} + +// 生态流量低于限值告警-获取统计数据 +export function getStllGaojingList(data: any) { + return request({ + url: '/api/wmp-env-server/env/warn/stcd/eng/GetKendoListCust', + method: 'post', + data + }); +} + +// 生态流量低于限值告警-获取表格详情数据 +export function getStllGaojingDetail(data: any) { + return request({ + url: '/api/wmp-env-server/env/warn/stcd/GetKendoListCust', + method: 'post', + data + }); +} + +// 水质监测数据告警-获取统计数据 +export function getShuizhiGaojingList(data: any) { + return request({ + url: '/api/dec-lygk-base-server/base/msstbprpt/GetKendoList', + method: 'post', + data + }); +} + +// AI识别大坝环境-获取漂浮物/清漂日历数据 +export function getAiPfwRecord(data: any) { + return request({ + url: '/api/wmp-env-server/env/ai/com/qgc/aiPfwRecord/GetKendoListCust', + method: 'post', + data + }); +} + +// AI识别大坝环境-获取叠梁门日历数据 +export function getAiRecord(data: any) { + return request({ + url: '/api/wmp-env-server/env/ai/com/qgc/aiRecord/GetKendoListCust', + method: 'post', + data + }); +} + +// AI识别大坝环境-获取日历详情视频数据 +export function getAiFile(data: any) { + return request({ + url: '/api/wmp-env-server/env/ai/com/qgc/aiFile/GetKendoListCust', + method: 'post', + data + }); +} diff --git a/frontend/src/assets/svg/diwenshuijianhuan.svg b/frontend/src/assets/svg/diwenshuijianhuan.svg new file mode 100644 index 00000000..334378b6 --- /dev/null +++ b/frontend/src/assets/svg/diwenshuijianhuan.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/guojiashuiwenzhan.svg b/frontend/src/assets/svg/guojiashuiwenzhan.svg new file mode 100644 index 00000000..ac788c8e --- /dev/null +++ b/frontend/src/assets/svg/guojiashuiwenzhan.svg @@ -0,0 +1,16 @@ + + + guojiashuiwenzhan + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/guojiashuizhizhan.svg b/frontend/src/assets/svg/guojiashuizhizhan.svg new file mode 100644 index 00000000..8244b65f --- /dev/null +++ b/frontend/src/assets/svg/guojiashuizhizhan.svg @@ -0,0 +1,13 @@ + + + guojiashuizhizhan + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/liuliangjiancezhan.svg b/frontend/src/assets/svg/liuliangjiancezhan.svg new file mode 100644 index 00000000..8575ff7b --- /dev/null +++ b/frontend/src/assets/svg/liuliangjiancezhan.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/qixiangzhan.svg b/frontend/src/assets/svg/qixiangzhan.svg new file mode 100644 index 00000000..35374b96 --- /dev/null +++ b/frontend/src/assets/svg/qixiangzhan.svg @@ -0,0 +1,16 @@ + + + qixiangzhan + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/qixidi.svg b/frontend/src/assets/svg/qixidi.svg new file mode 100644 index 00000000..ea3b599c --- /dev/null +++ b/frontend/src/assets/svg/qixidi.svg @@ -0,0 +1,9 @@ + + + qixidi + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/shipinjiankongshebei.svg b/frontend/src/assets/svg/shipinjiankongshebei.svg new file mode 100644 index 00000000..74cbd7ce --- /dev/null +++ b/frontend/src/assets/svg/shipinjiankongshebei.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/shuizhijiancezhan.svg b/frontend/src/assets/svg/shuizhijiancezhan.svg new file mode 100644 index 00000000..0925a2c4 --- /dev/null +++ b/frontend/src/assets/svg/shuizhijiancezhan.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/zengzhizhanshuizhizhan.svg b/frontend/src/assets/svg/zengzhizhanshuizhizhan.svg new file mode 100644 index 00000000..7632b476 --- /dev/null +++ b/frontend/src/assets/svg/zengzhizhanshuizhizhan.svg @@ -0,0 +1,9 @@ + + + zengzhizhanshuizhizhan + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/zijianshuiwenzhan.svg b/frontend/src/assets/svg/zijianshuiwenzhan.svg new file mode 100644 index 00000000..9114c677 --- /dev/null +++ b/frontend/src/assets/svg/zijianshuiwenzhan.svg @@ -0,0 +1,16 @@ + + + zijianshuiwenzhan + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/components/MapModal/column.config.ts b/frontend/src/components/MapModal/column.config.ts index e4e1b39d..f40cef4d 100644 --- a/frontend/src/components/MapModal/column.config.ts +++ b/frontend/src/components/MapModal/column.config.ts @@ -3288,6 +3288,45 @@ const DwSixPointColumns: Array = [ url: '' } ]; +//DW +const DwPointColumnsyuan: Array = [ + { + name: '基本属性', + visible: false, + ruleTips: '', + type: '', + url: '' + }, + { + name: '设施名称', + filed: 'stnm', + visible: true, + type: 'input', + url: '' + }, + + { + name: '站址', + filed: 'stlc', + visible: true, + type: 'select', + url: '' + }, + { + name: '所属流域', + filed: 'hbrvcdName', + visible: true, + type: 'select', + url: '' + }, + { + name: '所属电站', + filed: 'ennm', + visible: true, + type: 'select', + url: '' + }, +]; //夹岩双层取水 const DwOnePointColumns: Array = [ { @@ -4145,8 +4184,7 @@ const EQPointColumns7: Array = [ visible: true, type: 'select', url: '' - }, - + } ]; //阶段属性 const basicFilterColumns: Array = [ @@ -4831,6 +4869,58 @@ const tableColumns5: Array = [ setting: {} } ]; +//气象监测 +const MMColumns: Array = [ + { + name: '基本属性', + visible: false, + ruleTips: '', + type: '', + url: '' + }, { + name: '测站名称', + filed: 'stnm', + visible: true, + type: 'input', + url: '' + }, + { + name: '测站类型', + filed: 'sttpName', + visible: true, + type: 'select', + url: '' + }, + { + name: '站址', + filed: 'addvcdName', + visible: true, + type: 'input', + url: '' + }, + { + name: '所属流域', + filed: 'hbrvcdName', + visible: true, + type: 'select', + url: '' + }, + { + name: '所在水系', + filed: 'addvcdName', + visible: true, + type: 'input', + url: '' + }, + { + name: '建成日期', + filed: 'jcdt', + visible: true, + type: 'date', + format: 'YYYY-MM-DD', + url: '' + }, +]; //生态流量 const EcologicalFlowColumns: Array = []; @@ -4873,6 +4963,7 @@ export { DwFivePointColumns, DwSixPointColumns, DwOnePointColumns, + DwPointColumnsyuan, EQPointColumns2, EQPointColumns5, EQPointColumns3, @@ -4886,5 +4977,6 @@ export { tableColumns2, tableColumns3, tableColumns4, - tableColumns5 + tableColumns5, + MMColumns }; diff --git a/frontend/src/components/MapModal/components/BasicInfo.vue b/frontend/src/components/MapModal/components/BasicInfo.vue index fcdaa8ef..c66884fa 100644 --- a/frontend/src/components/MapModal/components/BasicInfo.vue +++ b/frontend/src/components/MapModal/components/BasicInfo.vue @@ -142,6 +142,8 @@ import { DwFivePointColumns, DwSixPointColumns, DwOnePointColumns, + DwPointColumnsyuan, + MMColumns, StinfoAiVidoPointColumns } from '../column.config'; import { useModelStore } from '@/store/modules/model'; @@ -318,6 +320,14 @@ const columnsConfig = ref([ { type: 'ZQ', columns: FhZQPointColumns + }, + { + type: 'DW', + columns: DwPointColumnsyuan + }, + { + type:'MM', + columns:MMColumns } //DW_1 diff --git a/frontend/src/components/MapModal/setting.config.ts b/frontend/src/components/MapModal/setting.config.ts index aeea96a7..a8231528 100644 --- a/frontend/src/components/MapModal/setting.config.ts +++ b/frontend/src/components/MapModal/setting.config.ts @@ -199,14 +199,14 @@ const ENGEQTabs: Array = [ ].filter(Boolean); // // 水电站生态流量 - 江局单独看 √ -// const ENGEQTabsJuangJu: Array = [ -// { -// name: '生态流量', -// key: 'EcologicalFlow', -// type: 'EcologicalFlow' -// }, - -// ].filter(Boolean) +const ENGEQTabsJuangJu: Array = [ + { + name: '生态流量', + key: 'EcologicalFlow', + type: 'EcologicalFlow', + default: true + } +].filter(Boolean); // //生态流量泄放设施 √ const EQTabs: Array = [ { @@ -310,9 +310,8 @@ const FPTabs1: Array = [ name: '基础信息', key: 'basicInfo', type: 'basic', - default: true, // 默认显示 - url: '/api/dec-lygk-base-server/base/msstbprpt/getStcdInfo', - + default: true, // 默认显示 + url: '/api/dec-lygk-base-server/base/msstbprpt/getStcdInfo' }, { name: '实时视频', @@ -956,15 +955,23 @@ const CommonTabs: any = [ } ]; -// // 气象站 -// const WeatherTabs: any = [ -// { -// name: '基础信息', -// key: 'basicInfo', -// type: 'basic', -// url: '/bbi/siteBipc/getSiteBasicInfo' -// } -// ] +// 气象站 +const WeatherTabs: any = [ + { + name: '基础信息', + key: 'basicInfo', + type: 'basic', + url: '/api/dec-lygk-base-server/base/msstbprpt/getStcdInfo', + default: true // 默认显示 + }, + { + name: '监测数据', + key: '', + type: '', + url: '' + }, + +] // const WaterQualityMonitoring: any = [ // { @@ -1033,6 +1040,8 @@ const handleTabs = (modaldata: any) => { const sttp = modaldata?.sttp ? modaldata?.sttp.toUpperCase() : ''; console.log('sttp', sttp); switch (sttp) { + case 'ENGJJ': + return ENGEQTabsJuangJu; case 'ENG': if (modaldata?.eqtp == 'QEC') { return ENGEQTabs; @@ -1223,8 +1232,8 @@ const handleTabs = (modaldata: any) => { // } // case 'WE': // return WETabs - // case 'MM': - // return WeatherTabs + case 'MM': + return WeatherTabs // case 'WARN': // return WaterQualityMonitoring // case 'AI': diff --git a/frontend/src/components/SidePanelItem/index.vue b/frontend/src/components/SidePanelItem/index.vue index abbfc6d5..e8dd8708 100644 --- a/frontend/src/components/SidePanelItem/index.vue +++ b/frontend/src/components/SidePanelItem/index.vue @@ -47,7 +47,6 @@
-
@@ -78,7 +77,7 @@ >
-
+
@@ -190,6 +189,7 @@ interface SelectConfig { value?: string | undefined; options?: SelectProps['options']; width?: string; + minWidth?: string; } // 定义组件名(便于调试和递归) @@ -248,7 +248,8 @@ const props = defineProps({ show: false, value: undefined, options: [], - width: '' + width: '', + minWidth: '' }) }, moreSelect: { @@ -661,7 +662,7 @@ const handleTreeSelect = (selectedKeys: string | string[], info: any) => { } moreSelectValue.value = selectedValue; - // + // // 保存选中节点的额外属性(如 lgtd、lttd 等) if (info && typeof info === 'object') { selectedNodeExtra.value = { @@ -690,7 +691,6 @@ const handleTreeExpand = (keys: string[]) => { // 下拉选择框事件处理 const handleChange = (value: string) => { - // Handle change }; diff --git a/frontend/src/components/developStatusChart/index.vue b/frontend/src/components/developStatusChart/index.vue index 5b0fd9fb..235a8a25 100644 --- a/frontend/src/components/developStatusChart/index.vue +++ b/frontend/src/components/developStatusChart/index.vue @@ -1,49 +1,29 @@ - + \ No newline at end of file + diff --git a/frontend/src/components/engEnvironmentData/index.vue b/frontend/src/components/engEnvironmentData/index.vue index f95868b1..77bc1cd0 100644 --- a/frontend/src/components/engEnvironmentData/index.vue +++ b/frontend/src/components/engEnvironmentData/index.vue @@ -1,9 +1,6 @@ \ No newline at end of file + const baseFilters: any[] = [ + { field: 'sttpCode', operator: 'eq', dataType: 'string', value: 'ENG' }, + { field: 'bldsttCcode', operator: 'in', dataType: 'string', value: ['1', '2'] } + ]; + if (baseid.value !== 'all') { + baseFilters.unshift({ field: 'baseId', operator: 'eq', dataType: 'string', value: baseid.value }); + } + + const params1 = { + filter: { + logic: 'and', + filters: [ + ...baseFilters, + { field: 'prsc', operator: 'in', dataType: 'string', value: ['1', '2', '3'] } + ] + } + }; + + const params2 = { + filter: { + logic: 'and', + filters: [ + ...baseFilters, + { field: 'runState', operator: 'eq', dataType: 'number', value: 4 }, + { field: 'dtin', operator: 'eq', dataType: 'number', value: 1 } + ] + } + }; + + const params3 = { + filter: { + logic: 'and', + filters: [ + ...baseFilters, + { field: 'prsc', operator: 'in', dataType: 'string', value: ['1', '2', '3'] }, + { field: 'dtinEnv', operator: 'in', dataType: 'string', value: ['2'] } + ] + } + }; + + try { + dataLoading.value = true; + const [res1, res2, res3] = await Promise.all([ + getVmsstbprptKendoList(params1), + getVmsstbprptKendoList(params2), + getVmsstbprptKendoList(params3) + ]); + + const record = { one: 0, two: 0, three: 0 }; + const responses = [res1, res2, res3]; + responses.forEach((res, index) => { + const total = res?.data?.total ?? 0; + switch (index) { + case 0: + record.one = total; + break; + case 1: + record.two = total; + break; + case 2: + record.three = total; + break; + } + }); + data.value = record; + // debugger + } catch (error) { + console.error('EngEnvironmentData getData error:', error); + } finally { + dataLoading.value = false; + } +}; + +const handleItemClick = (name: string) => { + emit('item-click', { name }); +}; + +watch( + () => JidiSelectEventStore.selectedItem, + newVal => { + if (newVal && newVal.wbsCode) { + baseid.value = newVal.wbsCode; + getData(); + } + }, + { deep: true, immediate: true } +); + diff --git a/frontend/src/modules/alongFishMod/TwoLayers/Yanchengyulei.vue b/frontend/src/modules/alongFishMod/TwoLayers/Yanchengyulei.vue index 8d7f6e9f..6b43cfe6 100644 --- a/frontend/src/modules/alongFishMod/TwoLayers/Yanchengyulei.vue +++ b/frontend/src/modules/alongFishMod/TwoLayers/Yanchengyulei.vue @@ -3,15 +3,22 @@
- - + + + > + + {{ opt.label }} + + @@ -20,21 +27,35 @@ v-model:value="formState.rvcd" placeholder="请选择" style="width: 150px" - :options="lyOptions" @change="handleRvcdChange" - /> + > + + {{ opt.label }} + + - + @@ -57,11 +78,20 @@ - - + +
- + -