This commit is contained in:
扈兆增 2026-07-09 14:58:39 +08:00
commit b708a53b46
74 changed files with 4165 additions and 213 deletions

View File

@ -1,5 +1,8 @@
package com.yfd.platform.config;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springdoc.core.models.GroupedOpenApi;
@ -10,15 +13,55 @@ import io.swagger.v3.oas.models.info.Contact;
@Configuration
public class SwaggerConfig {
// @Bean
// public OpenAPI projectOpenAPI() {
// return new OpenAPI()
// .info(new Info()
// .title("项目API 接口文档")
// .version("3.0")
// .description("")
// .contact(new Contact().name("郑顺利").email("13910913995@163.com"))
// );
// }
@Bean
public OpenAPI projectOpenAPI() {
// 1. 定义第一个 Headertoken
SecurityScheme tokenScheme = new SecurityScheme()
.type(SecurityScheme.Type.APIKEY)
.in(SecurityScheme.In.HEADER)
.name("token")
.description("用户认证 Token");
// 2. 定义第二个 Header租户ID示例
SecurityScheme tenantScheme = new SecurityScheme()
.type(SecurityScheme.Type.APIKEY)
.in(SecurityScheme.In.HEADER)
.name("Tenant_Id")
.description("租户标识");
// 3. 将两个安全方案注册到 Components
Components components = new Components()
.addSecuritySchemes("tokenAuth", tokenScheme)
.addSecuritySchemes("tenantAuth", tenantScheme);
// 4. 创建 SecurityRequirement同时要求两个 Header 都必须提供
SecurityRequirement securityRequirement = new SecurityRequirement()
.addList("tokenAuth") // 引用 token 方案
.addList("tenantAuth"); // 引用 tenant 方案
return new OpenAPI()
.info(new Info()
.title("项目API 接口文档")
.version("3.0")
.description("")
.contact(new Contact().name("郑顺利").email("13910913995@163.com"))
);
)
.components(components)
.addSecurityItem(securityRequirement); // 一次性添加
}
// @Bean

View File

@ -52,9 +52,27 @@ public class SdEngMonitorController {
return ResponseResult.successData(engInfoBHService.getEngPointKendoListCust(dataSourceRequest));
}
@PostMapping("/alarmPoint/GetKendoListCust")
@Operation(summary = "电站告警描点列表")
public ResponseResult getAlarmPointKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(engInfoBHService.getAlarmPointKendoListCust(dataSourceRequest));
}
@PostMapping("/rsvrcscdb/GetKendoList")
@Operation(summary = "条件过滤数据列表")
public ResponseResult getRsvrcscdBKendoList(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(engInfoBHService.getRsvrcscdBKendoList(dataSourceRequest));
}
@PostMapping("/rsvrcscdb/rvcd")
@Operation(summary = "查询梯级流域")
public ResponseResult getRsvrcscdBRvcdList(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(engInfoBHService.getRsvrcscdBRvcdList(dataSourceRequest));
}
@PostMapping("/rsvrcscdb/getQgcRvcd")
@Operation(summary = "查询梯级流域图流域")
public ResponseResult getQgcRvcdList(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(engInfoBHService.getQgcRvcdList(dataSourceRequest));
}
}

View File

@ -0,0 +1,31 @@
package com.yfd.platform.qgc_base.domain.vo;
import lombok.Data;
import java.io.Serializable;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* 当前登录用户的数据权限范围
*/
@Data
public class CurrentUserDataScopeVo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 是否为统一管理的超级管理员
*/
private boolean managedAdmin;
/**
* 当前用户有权限的电站编码
*/
private Set<String> stationCodes = new LinkedHashSet<>();
/**
* 当前用户有权限的流域编码
*/
private Set<String> rvcdCodes = new LinkedHashSet<>();
}

View File

@ -0,0 +1,29 @@
package com.yfd.platform.qgc_base.domain.vo;
import lombok.Data;
import java.io.Serializable;
/**
* 数据权限条件应用结果
*/
@Data
public class DataScopeApplyResult implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 当前用户是否为管理员
*/
private boolean managedAdmin;
/**
* 当前权限是否命中空结果
*/
private boolean emptyResult;
/**
* 是否已向查询中追加权限条件
*/
private boolean conditionApplied;
}

View File

@ -0,0 +1,101 @@
package com.yfd.platform.qgc_base.domain.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Data
@Schema(description = "电站告警描点")
public class EngAlarmPointVo {
@Schema(description = "站点类型")
private String sttp;
@Schema(description = "站点编码")
private String stcd;
@Schema(description = "经度")
private BigDecimal lgtd;
@Schema(description = "纬度")
private BigDecimal lttd;
@Schema(description = "高程")
private BigDecimal dtmel;
@Schema(description = "描点状态")
private String anchoPointState;
@Schema(description = "锚点类型")
private String sttpMap;
@Schema(description = "弹框站点名称")
private String titleName;
@Schema(description = "地图避让")
private Integer distance;
@Schema(description = "流域编码")
private String rvcd;
@Schema(description = "行政编码")
private String addvcd;
@Schema(description = "基地编码")
private String baseId;
@Schema(description = "关联电站编码")
private String rstcds;
@Schema(description = "设施类型")
private String sttpCode;
@Schema(description = "电站名称")
private String ennm;
@Schema(description = "流域名称")
private String rvnm;
@Schema(description = "电站装机类型")
private Integer endInstalledType;
@Schema(description = "生态流量告警数")
private Integer stqCount;
@Schema(description = "水质告警数")
private Integer wqCount;
@Schema(description = "水位告警数")
private Integer zCount;
@Schema(description = "水温告警数")
private Integer wtCount;
@Schema(description = "年份")
private String yyyy;
@Schema(description = "告警区间范围")
private String range;
@Schema(description = "装机容量")
private BigDecimal ttpwr;
@Schema(description = "基地名称")
private String baseName;
@Schema(description = "电站编码")
private String rstcd;
@Schema(description = "流域沿程")
private Integer rvcdStepSort;
@Schema(description = "电站沿程")
private Integer rstcdStepSort;
@Schema(description = "站点沿程")
private Integer siteStepSort;
@Schema(description = "电站图片")
private String logo;
}

View File

@ -0,0 +1,11 @@
package com.yfd.platform.qgc_base.domain.vo;
import lombok.Data;
@Data
public class EngQgcRvcdVo {
private String rvcd;
private String rvnm;
}

View File

@ -0,0 +1,16 @@
package com.yfd.platform.qgc_base.domain.vo;
import lombok.Data;
@Data
public class EngRsvrcscdRvcdVo {
private String wbsCode;
private String wbsName;
/**
* 旧口径对应上级/关联对象编码新库这里映射为基地编码
*/
private String objId;
}

View File

@ -0,0 +1,26 @@
package com.yfd.platform.qgc_base.service;
import com.yfd.platform.qgc_base.domain.vo.CurrentUserDataScopeVo;
import java.util.Set;
/**
* 当前登录用户数据权限公共服务
*/
public interface ICurrentUserDataScopeService {
/**
* 获取当前用户完整的数据权限范围
*/
CurrentUserDataScopeVo getCurrentUserDataScope();
/**
* 获取当前用户有权限的电站编码
*/
Set<String> getCurrentUserAuthorizedStationCodes();
/**
* 获取当前用户有权限的流域编码
*/
Set<String> getCurrentUserAuthorizedRvcdCodes();
}

View File

@ -0,0 +1,33 @@
package com.yfd.platform.qgc_base.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.yfd.platform.qgc_base.domain.vo.DataScopeApplyResult;
import java.util.Map;
/**
* 当前用户数据权限过滤公共服务
*/
public interface IDataScopeFilterService {
/**
* 追加当前用户电站权限 SQL 条件
*/
DataScopeApplyResult appendCurrentUserStationScope(StringBuilder sql, Map<String, Object> paramMap, String columnName);
/**
* 追加当前用户流域权限 SQL 条件
*/
DataScopeApplyResult appendCurrentUserRvcdScope(StringBuilder sql, Map<String, Object> paramMap, String columnName);
/**
* 追加当前用户电站权限 Wrapper 条件
*/
<T> DataScopeApplyResult applyCurrentUserStationScope(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> column);
/**
* 追加当前用户流域权限 Wrapper 条件
*/
<T> DataScopeApplyResult applyCurrentUserRvcdScope(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> column);
}

View File

@ -7,9 +7,12 @@ import com.yfd.platform.common.DataSourceResult;
import com.yfd.platform.qgc_base.domain.SdEngInfoBH;
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.EngAlarmPointVo;
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.EngQgcRvcdVo;
import com.yfd.platform.qgc_base.domain.vo.EngRsvrcscdBVo;
import com.yfd.platform.qgc_base.domain.vo.EngRsvrcscdRvcdVo;
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;
@ -91,5 +94,11 @@ public interface ISdEngInfoBHService extends IService<SdEngInfoBH> {
DataSourceResult<EngPointVo> getEngPointKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<EngAlarmPointVo> getAlarmPointKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<EngRsvrcscdBVo> getRsvrcscdBKendoList(DataSourceRequest dataSourceRequest);
DataSourceResult<EngRsvrcscdRvcdVo> getRsvrcscdBRvcdList(DataSourceRequest dataSourceRequest);
DataSourceResult<EngQgcRvcdVo> getQgcRvcdList(DataSourceRequest dataSourceRequest);
}

View File

@ -0,0 +1,161 @@
package com.yfd.platform.qgc_base.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yfd.platform.qgc_base.domain.SdEngInfoBH;
import com.yfd.platform.qgc_base.domain.vo.CurrentUserDataScopeVo;
import com.yfd.platform.qgc_base.mapper.SdEngInfoBHMapper;
import com.yfd.platform.qgc_base.service.ICurrentUserDataScopeService;
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;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
/**
* 当前登录用户数据权限公共服务实现
*/
@Service
public class CurrentUserDataScopeServiceImpl implements ICurrentUserDataScopeService {
private static final int QUERY_BATCH_SIZE = 500;
@Resource
private SysUserDataScopeMapper sysUserDataScopeMapper;
@Resource
private SdEngInfoBHMapper sdEngInfoBHMapper;
@Resource
private IAdminAuthService adminAuthService;
@Override
public CurrentUserDataScopeVo getCurrentUserDataScope() {
CurrentUserDataScopeVo scopeVo = new CurrentUserDataScopeVo();
if (adminAuthService.isCurrentManagedAdmin()) {
scopeVo.setManagedAdmin(true);
return scopeVo;
}
String userId = SecurityUtils.getUserId();
if (!StringUtils.hasText(userId)) {
return scopeVo;
}
List<SysUserDataScope> validPermissions = sysUserDataScopeMapper.selectValidPermissions(userId);
if (validPermissions == null || validPermissions.isEmpty()) {
return scopeVo;
}
Set<String> directStationCodes = collectOrgIdsByType(validPermissions, "STATION");
Set<String> directRvcdCodes = collectOrgIdsByType(validPermissions, "RVCD");
Set<String> stationCodes = new LinkedHashSet<>();
Set<String> rvcdCodes = new LinkedHashSet<>();
if (!directStationCodes.isEmpty()) {
List<SdEngInfoBH> stationList = listStationsByStcds(directStationCodes);
stationCodes.addAll(extractStationCodes(stationList));
rvcdCodes.addAll(extractLegacyBasinCodes(stationList));
}
if (!directRvcdCodes.isEmpty()) {
List<SdEngInfoBH> stationList = listStationsByReachcds(directRvcdCodes);
stationCodes.addAll(extractStationCodes(stationList));
rvcdCodes.addAll(extractLegacyBasinCodes(stationList));
}
scopeVo.setStationCodes(stationCodes);
scopeVo.setRvcdCodes(rvcdCodes);
return scopeVo;
}
@Override
public Set<String> getCurrentUserAuthorizedStationCodes() {
return getCurrentUserDataScope().getStationCodes();
}
@Override
public Set<String> getCurrentUserAuthorizedRvcdCodes() {
return getCurrentUserDataScope().getRvcdCodes();
}
private Set<String> collectOrgIdsByType(List<SysUserDataScope> scopes, String orgType) {
Set<String> orgIds = new LinkedHashSet<>();
for (SysUserDataScope scope : scopes) {
if (scope == null || !orgType.equalsIgnoreCase(scope.getOrgType())) {
continue;
}
if (StringUtils.hasText(scope.getOrgId())) {
orgIds.add(scope.getOrgId());
}
}
return orgIds;
}
private List<SdEngInfoBH> listStationsByStcds(Set<String> stationCodes) {
return listStationsByColumn(stationCodes, QueryDimension.STATION);
}
private List<SdEngInfoBH> listStationsByReachcds(Set<String> rvcdCodes) {
return listStationsByColumn(rvcdCodes, QueryDimension.REACH);
}
private List<SdEngInfoBH> listStationsByColumn(Set<String> codes, QueryDimension queryDimension) {
List<SdEngInfoBH> result = new ArrayList<>();
if (codes == null || codes.isEmpty()) {
return result;
}
List<String> codeList = new ArrayList<>(codes);
for (int i = 0; i < codeList.size(); i += QUERY_BATCH_SIZE) {
int end = Math.min(i + QUERY_BATCH_SIZE, codeList.size());
List<String> batchCodes = codeList.subList(i, end);
LambdaQueryWrapper<SdEngInfoBH> wrapper = new LambdaQueryWrapper<SdEngInfoBH>()
.select(SdEngInfoBH::getStcd, SdEngInfoBH::getReachcd, SdEngInfoBH::getEnnm);
if (queryDimension == QueryDimension.STATION) {
wrapper.in(SdEngInfoBH::getStcd, batchCodes);
} else {
wrapper.in(SdEngInfoBH::getReachcd, batchCodes);
}
result.addAll(sdEngInfoBHMapper.selectList(wrapper));
}
return result;
}
private Set<String> extractStationCodes(List<SdEngInfoBH> stationList) {
Set<String> stationCodes = new LinkedHashSet<>();
if (stationList == null || stationList.isEmpty()) {
return stationCodes;
}
for (SdEngInfoBH station : stationList) {
if (station != null && StringUtils.hasText(station.getStcd())) {
stationCodes.add(station.getStcd());
}
}
return stationCodes;
}
private Set<String> extractLegacyBasinCodes(List<SdEngInfoBH> stationList) {
Set<String> rvcdCodes = new LinkedHashSet<>();
if (stationList == null || stationList.isEmpty()) {
return rvcdCodes;
}
for (SdEngInfoBH station : stationList) {
if (station != null && StringUtils.hasText(station.getEnnm()) && StringUtils.hasText(station.getReachcd())) {
rvcdCodes.add(station.getReachcd());
}
}
return rvcdCodes;
}
private enum QueryDimension {
STATION,
REACH
}
}

View File

@ -0,0 +1,154 @@
package com.yfd.platform.qgc_base.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.yfd.platform.qgc_base.domain.vo.CurrentUserDataScopeVo;
import com.yfd.platform.qgc_base.domain.vo.DataScopeApplyResult;
import com.yfd.platform.qgc_base.service.ICurrentUserDataScopeService;
import com.yfd.platform.qgc_base.service.IDataScopeFilterService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 当前用户数据权限过滤公共服务实现
*/
@Service
public class DataScopeFilterServiceImpl implements IDataScopeFilterService {
private static final int IN_BATCH_SIZE = 900;
@Resource
private ICurrentUserDataScopeService currentUserDataScopeService;
@Override
public DataScopeApplyResult appendCurrentUserStationScope(StringBuilder sql, Map<String, Object> paramMap, String columnName) {
CurrentUserDataScopeVo scopeVo = currentUserDataScopeService.getCurrentUserDataScope();
return appendScopeCondition(sql, paramMap, columnName, scopeVo, scopeVo.getStationCodes(), "stationScope");
}
@Override
public DataScopeApplyResult appendCurrentUserRvcdScope(StringBuilder sql, Map<String, Object> paramMap, String columnName) {
CurrentUserDataScopeVo scopeVo = currentUserDataScopeService.getCurrentUserDataScope();
return appendScopeCondition(sql, paramMap, columnName, scopeVo, scopeVo.getRvcdCodes(), "rvcdScope");
}
@Override
public <T> DataScopeApplyResult applyCurrentUserStationScope(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> column) {
CurrentUserDataScopeVo scopeVo = currentUserDataScopeService.getCurrentUserDataScope();
return applyScopeCondition(wrapper, column, scopeVo, scopeVo.getStationCodes());
}
@Override
public <T> DataScopeApplyResult applyCurrentUserRvcdScope(LambdaQueryWrapper<T> wrapper, SFunction<T, ?> column) {
CurrentUserDataScopeVo scopeVo = currentUserDataScopeService.getCurrentUserDataScope();
return applyScopeCondition(wrapper, column, scopeVo, scopeVo.getRvcdCodes());
}
private DataScopeApplyResult appendScopeCondition(StringBuilder sql,
Map<String, Object> paramMap,
String columnName,
CurrentUserDataScopeVo scopeVo,
Set<String> scopeValues,
String paramPrefix) {
DataScopeApplyResult result = initResult(scopeVo, scopeValues);
if (result.isManagedAdmin() || result.isEmptyResult()) {
return result;
}
if (!StringUtils.hasText(columnName)) {
return result;
}
List<List<String>> batches = splitValues(scopeValues);
if (batches.isEmpty()) {
result.setEmptyResult(true);
return result;
}
sql.append(" AND (");
for (int i = 0; i < batches.size(); i++) {
if (i > 0) {
sql.append(" OR ");
}
List<String> batch = batches.get(i);
List<String> placeholders = new ArrayList<>();
for (int j = 0; j < batch.size(); j++) {
String key = buildParamKey(paramMap, paramPrefix, i, j);
paramMap.put(key, batch.get(j));
placeholders.add("#{map." + key + "}");
}
sql.append(columnName).append(" IN (").append(String.join(", ", placeholders)).append(")");
}
sql.append(") ");
result.setConditionApplied(true);
return result;
}
private <T> DataScopeApplyResult applyScopeCondition(LambdaQueryWrapper<T> wrapper,
SFunction<T, ?> column,
CurrentUserDataScopeVo scopeVo,
Set<String> scopeValues) {
DataScopeApplyResult result = initResult(scopeVo, scopeValues);
if (result.isManagedAdmin() || result.isEmptyResult()) {
return result;
}
List<List<String>> batches = splitValues(scopeValues);
if (batches.isEmpty()) {
result.setEmptyResult(true);
return result;
}
wrapper.and(innerWrapper -> {
for (int i = 0; i < batches.size(); i++) {
if (i > 0) {
innerWrapper.or();
}
innerWrapper.in(column, batches.get(i));
}
});
result.setConditionApplied(true);
return result;
}
private DataScopeApplyResult initResult(CurrentUserDataScopeVo scopeVo, Collection<String> scopeValues) {
DataScopeApplyResult result = new DataScopeApplyResult();
if (scopeVo != null && scopeVo.isManagedAdmin()) {
result.setManagedAdmin(true);
return result;
}
if (CollectionUtils.isEmpty(scopeValues)) {
result.setEmptyResult(true);
}
return result;
}
private List<List<String>> splitValues(Collection<String> values) {
List<List<String>> batches = new ArrayList<>();
if (CollectionUtils.isEmpty(values)) {
return batches;
}
List<String> valueList = new ArrayList<>(values);
for (int i = 0; i < valueList.size(); i += IN_BATCH_SIZE) {
int end = Math.min(i + IN_BATCH_SIZE, valueList.size());
batches.add(valueList.subList(i, end));
}
return batches;
}
private String buildParamKey(Map<String, Object> paramMap, String paramPrefix, int batchIndex, int itemIndex) {
String key = paramPrefix + "_" + batchIndex + "_" + itemIndex;
while (paramMap.containsKey(key)) {
key = key + "_n";
}
return key;
}
}

View File

@ -3,6 +3,7 @@ package com.yfd.platform.qgc_base.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
@ -23,17 +24,22 @@ import com.yfd.platform.common.MicroservicDynamicSQLMapper;
import com.yfd.platform.qgc_data.domain.SysUserDataScope;
import com.yfd.platform.qgc_data.mapper.SysUserDataScopeMapper;
import com.yfd.platform.qgc_base.domain.SdEngInfoBH;
import com.yfd.platform.qgc_base.domain.vo.DataScopeApplyResult;
import com.yfd.platform.qgc_base.domain.SdEngInfoBHRequest;
import com.yfd.platform.qgc_base.domain.vo.EngAlarmPointVo;
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.EngQgcRvcdVo;
import com.yfd.platform.qgc_base.domain.vo.EngRsvrcscdBVo;
import com.yfd.platform.qgc_base.domain.vo.EngRsvrcscdRvcdVo;
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.IDataScopeFilterService;
import com.yfd.platform.qgc_base.service.IMsOperationLogService;
import com.yfd.platform.qgc_base.service.ISdEngInfoBHService;
import com.yfd.platform.system.service.IAdminAuthService;
@ -60,6 +66,9 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl<SdEngInfoBHMapper, SdEng
private static final Map<String, String> ENG_CODE_NAME_FIELD_MAP = new LinkedHashMap<>();
@Resource
private IDataScopeFilterService dataScopeFilterService;
static {
ENG_CODE_NAME_FIELD_MAP.put("baseId", "baseName");
ENG_CODE_NAME_FIELD_MAP.put("hbrvcd", "hbrvcdName");
@ -126,8 +135,26 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl<SdEngInfoBHMapper, SdEng
}
@Override
@Cacheable(cacheNames = "engInfoCache#3600", keyGenerator = "cacheKeyGenerator")
public List<SdEngInfoBH> selectForDropdown(SdEngInfoBHRequest sdEngInfoBHRequest) {
List<SdEngInfoBH> allData = this.selectForDropdownCached(sdEngInfoBHRequest);
if (adminAuthService.isCurrentManagedAdmin()) {
return allData;
}
Set<String> authorizedStations = getUserAuthorizedStationCodes();
if (authorizedStations != null && !authorizedStations.isEmpty()) {
return allData.stream()
.filter(item -> authorizedStations.contains(item.getStcd()))
.collect(Collectors.toList());
}
return new ArrayList<>();
}
/**
* 纯数据库查询可缓存不包含权限过滤逻辑
*/
@Cacheable(cacheNames = "engInfoCache#3600", keyGenerator = "cacheKeyGenerator")
public List<SdEngInfoBH> selectForDropdownCached(SdEngInfoBHRequest sdEngInfoBHRequest) {
String baseId = sdEngInfoBHRequest.getBaseId();
String hbrvcd = sdEngInfoBHRequest.getHbrvcd();
String ennm = sdEngInfoBHRequest.getEnnm();
@ -138,28 +165,15 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl<SdEngInfoBHMapper, SdEng
LambdaQueryWrapper<SdEngInfoBH> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(StringUtils.hasText(baseId), SdEngInfoBH::getBaseId, baseId)
.eq(StringUtils.hasText(hbrvcd), SdEngInfoBH::getHbrvcd, hbrvcd)
.eq(StrUtil.isNotBlank(reachcd), SdEngInfoBH::getRvcd, reachcd)
.eq(StrUtil.isNotBlank(rvcd), SdEngInfoBH::getReachcd, rvcd)
.eq(StrUtil.isNotBlank(rvcd), SdEngInfoBH::getReachcd, rvcd)
.eq(StrUtil.isNotBlank(reachcd), SdEngInfoBH::getReachcd, reachcd)
.eq(StrUtil.isNotBlank(rvcd), SdEngInfoBH::getRvcd, rvcd)
.in(rvcds != null && !rvcds.isEmpty(), SdEngInfoBH::getReachcd, rvcds)
.in(hbrvcds != null && !hbrvcds.isEmpty(), SdEngInfoBH::getHbrvcd, hbrvcds)
.like(StringUtils.hasText(ennm), SdEngInfoBH::getEnnm, ennm)
.select(SdEngInfoBH::getStcd, SdEngInfoBH::getEnnm, SdEngInfoBH::getReachcdName, SdEngInfoBH::getYrgeb, SdEngInfoBH::getBaseId)
.orderByAsc(SdEngInfoBH::getBaseId,SdEngInfoBH::getOrderIndex);
if(adminAuthService.isCurrentManagedAdmin()){
.orderByAsc(SdEngInfoBH::getBaseId, SdEngInfoBH::getOrderIndex);
return this.list(wrapper);
}
Set<String> authorizedStations = getUserAuthorizedStationCodes();
if (authorizedStations != null && !authorizedStations.isEmpty()) {
List<SdEngInfoBH> list = this.list(wrapper);
return list.stream()
.filter(item -> authorizedStations.contains(item.getStcd()))
.collect(Collectors.toList());
}else{
return new ArrayList<>();
}
}
@Override
public Set<String> getUserAuthorizedStationCodes() {
String userId = SecurityUtils.getUserId();
@ -2754,8 +2768,13 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl<SdEngInfoBHMapper, SdEng
.append("AND NVL(t.USFL, 1) = 1 ")
.append("AND t.LGTD IS NOT NULL ")
.append("AND t.LTTD IS NOT NULL ");
Map<String, Object> paramMap = new HashMap<>();
DataScopeApplyResult scopeApplyResult = dataScopeFilterService.appendCurrentUserStationScope(sql, paramMap, "t.STCD");
if (scopeApplyResult.isEmptyResult()) {
result.setData(new ArrayList<>());
result.setTotal(0L);
return result;
}
String filterSql = buildEngPointFilterCondition(dataSourceRequest.getFilter(), paramMap, new int[]{0});
if (StrUtil.isNotBlank(filterSql)) {
sql.append(" AND ").append(filterSql);
@ -2772,6 +2791,353 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl<SdEngInfoBHMapper, SdEng
return result;
}
@Override
public DataSourceResult<EngAlarmPointVo> getAlarmPointKendoListCust(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
String startTimeText = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "startTime");
String endTimeText = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "endTime");
Date startTime;
Date endTime;
String yyyy = null;
if (StrUtil.isNotBlank(startTimeText) && StrUtil.isNotBlank(endTimeText)) {
startTime = parseAlarmPointTime(startTimeText);
endTime = parseAlarmPointTime(endTimeText);
} else {
yyyy = String.valueOf(DateUtil.year(new Date()));
Map<String, Date> yearRange = buildAlarmPointYearRange(yyyy);
startTime = yearRange.get("startTime");
endTime = yearRange.get("endTime");
}
Map<String, Object> pointParamMap = new HashMap<>();
StringBuilder pointSql = new StringBuilder(buildAlarmPointBaseSql());
// DataScopeApplyResult scopeApplyResult = dataScopeFilterService.appendCurrentUserStationScope(pointSql, pointParamMap, "eng.STCD");
List<EngAlarmPointVo> points= microservicDynamicSQLMapper.getAllListWithResultType(
pointSql.toString(),
pointParamMap,
EngAlarmPointVo.class
);
// if (scopeApplyResult.isEmptyResult()) {
// points = new ArrayList<>();
// } else {
// points = microservicDynamicSQLMapper.getAllListWithResultType(
// pointSql.toString(),
// pointParamMap,
// EngAlarmPointVo.class
// );
// }
Map<String, Object> countParamMap = new HashMap<>();
countParamMap.put("alarmPointStartTime", startTime);
countParamMap.put("alarmPointEndTime", endTime);
List<Map<String, Object>> countRows = microservicDynamicSQLMapper.getAllList(buildAlarmPointCountSql(), countParamMap);
Map<String, Integer> qecCountMap = buildAlarmPointQecCountMap(countRows);
Map<String, Integer> wqCountMap = buildAlarmPointWqCountMap(countRows);
List<Map<String, Object>> expressionRows = microservicDynamicSQLMapper.getAllList(buildAlarmPointLegendSql(), new HashMap<>());
List<EngAlarmPointVo> resultList = mergeAlarmPointData(points, qecCountMap, wqCountMap, expressionRows, yyyy);
DataSourceResult<EngAlarmPointVo> result = new DataSourceResult<>();
result.setData(resultList);
result.setTotal(resultList.size());
result.setAggregates(new HashMap<>());
return result;
}
private String buildAlarmPointBaseSql() {
return "SELECT " +
"eng.STCD AS stcd, " +
"'ENG' AS sttp, " +
"eng.ENNM AS ennm, " +
"eng.ENNM AS titleName, " +
"eng.LOGO AS logo, " +
"eng.RVCD AS rvcd, " +
"eng.RVCD_NAME AS rvnm, " +
"eng.ADDVCD AS addvcd, " +
"eng.BASE_ID AS baseId, " +
"NVL(eng.BASE_NAME, hb.BASENAME) AS baseName, " +
"eng.LGTD AS lgtd, " +
"eng.LTTD AS lttd, " +
"eng.ELEV AS dtmel, " +
"eng.YRGEB AS ttpwr, " +
"'ENG' AS sttpMap, " +
"CASE WHEN eng.PRSC IN (1, 2) THEN 1 WHEN eng.PRSC = 3 THEN 2 END AS endInstalledType, " +
"CASE " +
" WHEN eng.PRSC IN (1, 2) AND NVL(eng.BLDSTT_CODE, 0) = 2 THEN 'large_eng_built' " +
" WHEN eng.PRSC IN (1, 2) AND NVL(eng.BLDSTT_CODE, 0) = 1 THEN 'large_eng_ubuilt' " +
" WHEN eng.PRSC IN (1, 2) THEN 'large_eng_nbuilt' " +
" WHEN eng.PRSC = 3 AND NVL(eng.BLDSTT_CODE, 0) = 2 THEN 'mid_eng_built' " +
" WHEN eng.PRSC = 3 AND NVL(eng.BLDSTT_CODE, 0) = 1 THEN 'mid_eng_ubuilt' " +
" WHEN eng.PRSC = 3 THEN 'mid_eng_nbuilt' " +
" ELSE NULL END AS anchoPointState, " +
"eng.STCD AS rstcd, " +
"eng.STCD AS rstcds, " +
"'ENG' AS sttpCode, " +
"NVL(along.ORDER_INDEX, 999999) AS rvcdStepSort, " +
"NVL(rstSort.SORT, 999999) AS rstcdStepSort, " +
"NVL(siteSort.SORT, 999999) AS siteStepSort " +
"FROM SD_ENGINFO_B_H eng " +
"LEFT JOIN SD_HYDROBASE hb ON hb.BASEID = eng.BASE_ID AND NVL(hb.IS_DELETED, 0) = 0 " +
"LEFT JOIN MS_ALONG_B along ON along.RVCD = eng.HBRVCD AND along.CODE = 'common' AND NVL(along.IS_DELETED, 0) = 0 " +
"LEFT JOIN ( " +
" SELECT det.SORT, cfg.RVCD, det.STCD " +
" FROM MS_ALONGDET_B det " +
" INNER JOIN MS_ALONG_B cfg ON det.ALONG_ID = cfg.ID " +
" WHERE NVL(det.IS_DELETED, 0) = 0 AND NVL(cfg.IS_DELETED, 0) = 0 AND cfg.CODE = 'common' " +
") rstSort ON rstSort.RVCD = eng.HBRVCD AND rstSort.STCD = eng.STCD " +
"LEFT JOIN ( " +
" SELECT det.SORT, cfg.RVCD, det.STCD " +
" FROM MS_ALONGDET_B det " +
" INNER JOIN MS_ALONG_B cfg ON det.ALONG_ID = cfg.ID " +
" WHERE NVL(det.IS_DELETED, 0) = 0 AND NVL(cfg.IS_DELETED, 0) = 0 AND cfg.CODE = 'common' " +
") siteSort ON siteSort.RVCD = eng.HBRVCD AND siteSort.STCD = eng.STCD " +
"WHERE NVL(eng.IS_DELETED, 0) = 0 " +
"AND NVL(eng.USFL, 0) = 1 " +
"AND eng.LGTD IS NOT NULL " +
"AND eng.LTTD IS NOT NULL ";
}
private String buildAlarmPointCountSql() {
return "SELECT wr.STCD AS stcd, wr.STCD AS rstcd, COUNT(wr.STCD) AS count, 'QEC' AS ys " +
"FROM MS_WARN_RECORD_W wr " +
"WHERE NVL(wr.IS_DELETED, 0) = 0 " +
"AND wr.TB_ID IN (SELECT tb.ID FROM ST_TB_B tb WHERE tb.TB_CODE = 'QEC_R' AND NVL(tb.IS_DELETED, 0) = 0) " +
"AND wr.YS = 'QEC' " +
"AND wr.SFGB = 'N' " +
"AND wr.BTM BETWEEN #{map.alarmPointStartTime} AND #{map.alarmPointEndTime} " +
"GROUP BY wr.STCD " +
"UNION ALL " +
"SELECT wr.STCD AS stcd, wq.RSTCD AS rstcd, COUNT(wr.STCD) AS count, 'WQ' AS ys " +
"FROM MS_WARN_RECORD_W wr " +
"LEFT JOIN SD_WQ_B_H wq ON wr.STCD = wq.STCD AND NVL(wq.IS_DELETED, 0) = 0 " +
"WHERE NVL(wr.IS_DELETED, 0) = 0 " +
"AND wr.TB_ID IN (SELECT tb.ID FROM ST_TB_B tb WHERE tb.TB_CODE = 'WQ_R' AND NVL(tb.IS_DELETED, 0) = 0) " +
"AND wr.SFGB = 'N' " +
"AND wr.BTM BETWEEN #{map.alarmPointStartTime} AND #{map.alarmPointEndTime} " +
"AND wq.RSTCD IS NOT NULL " +
"GROUP BY wr.STCD, wq.RSTCD";
}
private String buildAlarmPointLegendSql() {
return "SELECT EXPRESSION AS expression, NAME_EN AS nameEn " +
"FROM MS_MAPLEGEND_B " +
"WHERE LAYER_CODE = 'eng_alarm_point' " +
"AND IF_SHOW = 1 " +
"AND NVL(IS_DELETED, 0) = 0 " +
"AND EXPRESSION IS NOT NULL " +
"ORDER BY NVL(ORDER_INDEX, 999999), ID";
}
private Map<String, Date> buildAlarmPointYearRange(String yearText) {
Date endTime = new Date();
String currentYear = String.valueOf(DateUtil.year(endTime));
Date startTime = DateUtil.parse(currentYear + "-01-01");
if (StrUtil.isNotBlank(yearText) && !currentYear.equals(yearText)) {
startTime = DateUtil.parse(yearText + "-01-01");
endTime = DateUtil.parse(yearText + "-12-31");
}
Map<String, Date> result = new HashMap<>();
result.put("startTime", startTime);
result.put("endTime", endTime);
return result;
}
private Map<String, Integer> buildAlarmPointQecCountMap(List<Map<String, Object>> countRows) {
Map<String, Integer> result = new HashMap<>();
if (CollUtil.isEmpty(countRows)) {
return result;
}
for (Map<String, Object> row : countRows) {
if (!"QEC".equalsIgnoreCase(safeAlarmValue(firstPresentAlarmValue(row, "YS", "ys")))) {
continue;
}
String stcd = safeAlarmValue(firstPresentAlarmValue(row, "RSTCD", "rstcd", "STCD", "stcd"));
if (StrUtil.isBlank(stcd)) {
continue;
}
result.put(stcd, toAlarmIntegerValue(firstPresentAlarmValue(row, "COUNT", "count")));
}
return result;
}
private Map<String, Integer> buildAlarmPointWqCountMap(List<Map<String, Object>> countRows) {
Map<String, Integer> result = new HashMap<>();
if (CollUtil.isEmpty(countRows)) {
return result;
}
for (Map<String, Object> row : countRows) {
if (!"WQ".equalsIgnoreCase(safeAlarmValue(firstPresentAlarmValue(row, "YS", "ys")))) {
continue;
}
Integer count = toAlarmIntegerValue(firstPresentAlarmValue(row, "COUNT", "count"));
if (count == null) {
count = 0;
}
String rstcdText = safeAlarmValue(firstPresentAlarmValue(row, "RSTCD", "rstcd"));
if (StrUtil.isBlank(rstcdText)) {
continue;
}
for (String rstcd : rstcdText.split(",")) {
String trimmed = StrUtil.trim(rstcd);
if (StrUtil.isBlank(trimmed)) {
continue;
}
result.put(trimmed, result.getOrDefault(trimmed, 0) + count);
}
}
return result;
}
private List<EngAlarmPointVo> mergeAlarmPointData(List<EngAlarmPointVo> points,
Map<String, Integer> qecCountMap,
Map<String, Integer> wqCountMap,
List<Map<String, Object>> expressionRows,
String yyyy) {
List<EngAlarmPointVo> result = new ArrayList<>();
if (CollUtil.isEmpty(points)) {
return result;
}
for (EngAlarmPointVo point : points) {
if (point == null || !isAlarmPointVisible(point.getAnchoPointState())) {
continue;
}
point.setAnchoPointState(normalizeAlarmPointState(point.getAnchoPointState()) + "_ALARM");
point.setStqCount(qecCountMap.getOrDefault(point.getStcd(), 0));
point.setWqCount(wqCountMap.getOrDefault(point.getStcd(), 0));
point.setZCount(0);
point.setWtCount(0);
point.setYyyy(yyyy);
point.setSttpCode("ENG");
int total = point.getStqCount() + point.getWqCount();
applyAlarmPointRange(point, total, expressionRows);
result.add(point);
}
return result;
}
private boolean isAlarmPointVisible(String state) {
return "large_eng_built".equals(state)
|| "mid_eng_built".equals(state)
|| "large_eng_ubuilt".equals(state)
|| "mid_eng_ubuilt".equals(state);
}
private String normalizeAlarmPointState(String state) {
if ("large_eng_ubuilt".equals(state)) {
return "large_eng_built";
}
if ("mid_eng_ubuilt".equals(state)) {
return "mid_eng_built";
}
return state;
}
private void applyAlarmPointRange(EngAlarmPointVo point, int total, List<Map<String, Object>> expressionRows) {
if (point == null || CollUtil.isEmpty(expressionRows)) {
return;
}
for (Map<String, Object> row : expressionRows) {
String expression = safeAlarmValue(firstPresentAlarmValue(row, "EXPRESSION", "expression"));
if (!matchesAlarmExpression(expression, total)) {
continue;
}
String nameEn = safeAlarmValue(firstPresentAlarmValue(row, "NAMEEN", "nameEn", "NAME_EN"));
if (StrUtil.isNotBlank(nameEn)) {
point.setAnchoPointState(point.getAnchoPointState() + "_" + nameEn);
point.setRange(nameEn);
}
return;
}
}
private boolean matchesAlarmExpression(String range, int value) {
if (StrUtil.isBlank(range)) {
return false;
}
if (range.matches("x=\\d+")) {
return value == Integer.parseInt(range.substring(2));
}
if (range.matches("x>\\d+")) {
return value > Integer.parseInt(range.substring(2));
}
if (range.matches("x>=\\d+")) {
return value >= Integer.parseInt(range.substring(3));
}
if (range.matches("x<\\d+")) {
return value < Integer.parseInt(range.substring(2));
}
if (range.matches("x<=\\d+")) {
return value <= Integer.parseInt(range.substring(3));
}
if (range.matches("\\d+<x<\\d+")) {
String[] split = range.split("<x<");
return value > Integer.parseInt(split[0]) && value < Integer.parseInt(split[1]);
}
if (range.matches("\\d+<=x<=\\d+")) {
String[] split = range.split("<=x<=");
return value >= Integer.parseInt(split[0]) && value <= Integer.parseInt(split[1]);
}
if (range.matches("\\d+<x<=\\d+")) {
String[] split = range.split("<x<=");
return value > Integer.parseInt(split[0]) && value <= Integer.parseInt(split[1]);
}
if (range.matches("\\d+<=x<\\d+")) {
String[] split = range.split("<=x<");
return value >= Integer.parseInt(split[0]) && value < Integer.parseInt(split[1]);
}
return false;
}
private Date parseAlarmPointTime(String timeText) {
if (StrUtil.isBlank(timeText)) {
return null;
}
String value = timeText.trim();
if (value.length() <= 10) {
return DateUtil.parse(value, "yyyy-MM-dd");
}
return DateUtil.parse(value, "yyyy-MM-dd HH:mm:ss");
}
private Object firstPresentAlarmValue(Map<String, Object> row, String... keys) {
if (row == null || keys == null) {
return null;
}
for (String key : keys) {
if (row.containsKey(key)) {
return row.get(key);
}
}
return null;
}
private Integer toAlarmIntegerValue(Object value) {
if (value == null) {
return null;
}
if (value instanceof Number number) {
return number.intValue();
}
String text = String.valueOf(value).trim();
if (StrUtil.isBlank(text)) {
return null;
}
try {
return Integer.parseInt(text);
} catch (NumberFormatException ex) {
try {
return Double.valueOf(text).intValue();
} catch (NumberFormatException ignore) {
return null;
}
}
}
private String safeAlarmValue(Object value) {
return value == null ? "" : String.valueOf(value).trim();
}
private String buildEngPointFilterCondition(DataSourceRequest.FilterDescriptor filter,
Map<String, Object> paramMap,
int[] indexHolder) {
@ -2983,6 +3349,60 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl<SdEngInfoBHMapper, SdEng
return result;
}
@Override
public DataSourceResult<EngRsvrcscdRvcdVo> getRsvrcscdBRvcdList(DataSourceRequest dataSourceRequest) {
DataSourceResult<EngRsvrcscdRvcdVo> result = new DataSourceResult<>();
result.setAggregates(new HashMap<>());
Map<String, Object> paramMap = new HashMap<>();
StringBuilder sql = new StringBuilder();
sql.append("SELECT DISTINCT ")
.append("dic.HBRVCD AS wbsCode, ")
.append("dic.HBRVNM AS wbsName, ")
.append("dic.BASEID AS objId, ")
.append("NVL(dic.BASEID, 'ZZZZZZZZ') AS baseOrder, ")
.append("NVL(dic.ORDER_INDEX, 999999) AS orderIndex ")
.append("FROM SD_HBRV_DIC dic ")
.append("INNER JOIN SD_RSVRCSCD_B r ON r.RVCD = dic.HBRVCD AND NVL(r.IS_DELETED, 0) = 0 ")
.append("WHERE NVL(dic.IS_DELETED, 0) = 0 ")
.append("AND NVL(dic.ENABLED, 1) = 1 ");
// 动态过滤条件原有代码
appendRsvrcscdRvcdPresetFilters(dataSourceRequest == null ? null : dataSourceRequest.getFilter(), sql, paramMap, new int[]{0});
// 使用别名排序
sql.append(" ORDER BY baseOrder ASC, orderIndex ASC, wbsCode ASC");
List<EngRsvrcscdRvcdVo> list = microservicDynamicSQLMapper.getAllListWithResultType(
sql.toString(), paramMap, EngRsvrcscdRvcdVo.class);
result.setData(list);
result.setTotal(list.size());
return result;
}
@Override
public DataSourceResult<EngQgcRvcdVo> getQgcRvcdList(DataSourceRequest dataSourceRequest) {
DataSourceResult<EngQgcRvcdVo> result = new DataSourceResult<>();
result.setAggregates(new HashMap<>());
StringBuilder sql = new StringBuilder();
sql.append("SELECT DISTINCT ")
.append("rv.RVCD AS rvcd, ")
.append("rv.RVNM AS rvnm, ")
.append("NVL(rv.ORDER_INDEX, 999999) AS order_index ")
.append("FROM SD_RVCD_DIC rv ")
.append("INNER JOIN MS_LYSXJGX_B rel ON rel.QGC_RVCD = rv.RVCD AND NVL(rel.IS_DELETED, 0) = 0 ")
.append("WHERE NVL(rv.IS_DELETED, 0) = 0 ")
.append("AND NVL(rv.ENABLED, 1) = 1 ")
.append("ORDER BY order_index ASC, rv.RVCD ASC");
List<EngQgcRvcdVo> list = microservicDynamicSQLMapper.getAllListWithResultType(
sql.toString(), new HashMap<>(), EngQgcRvcdVo.class);
result.setData(list);
result.setTotal(list.size());
return result;
}
private String buildRsvrcscdBFilterCondition(DataSourceRequest.FilterDescriptor filter,
Map<String, Object> paramMap,
int[] indexHolder) {
@ -3123,4 +3543,125 @@ public class SdEngInfoBHServiceImpl extends ServiceImpl<SdEngInfoBHMapper, SdEng
}
return " ORDER BY " + String.join(", ", orderItems);
}
private void appendRsvrcscdRvcdPresetFilters(DataSourceRequest.FilterDescriptor filter,
StringBuilder sql,
Map<String, Object> paramMap,
int[] indexHolder) {
if (filter == null) {
return;
}
if (StringUtils.hasText(filter.getField())) {
String field = filter.getField();
String operator = filter.getOperator() == null ? "eq" : filter.getOperator().toLowerCase();
Object value = filter.getValue();
if (!StringUtils.hasText(operator)) {
operator = "eq";
}
if ("baseId".equals(field)) {
appendRsvrcscdRvcdLeafCondition(sql, "dic.BASEID", operator, value, paramMap, indexHolder);
return;
}
if ("treeLevel".equals(field)) {
appendRsvrcscdRvcdLeafCondition(sql, "dic.GRD", operator, value, paramMap, indexHolder);
return;
}
if ("wbsType".equals(field)) {
// 旧口径走 SD_WBS_B.WBS_TYPE这里已固定替换成 SD_HBRV_DIC保留参数但不参与过滤
return;
}
if ("wbsCode".equals(field)) {
appendRsvrcscdRvcdLeafCondition(sql, "dic.HBRVCD", operator, value, paramMap, indexHolder);
return;
}
if ("wbsName".equals(field)) {
appendRsvrcscdRvcdLeafCondition(sql, "dic.HBRVNM", operator, value, paramMap, indexHolder);
return;
}
return;
}
if (filter.getFilters() == null || filter.getFilters().isEmpty()) {
return;
}
for (DataSourceRequest.FilterDescriptor child : filter.getFilters()) {
appendRsvrcscdRvcdPresetFilters(child, sql, paramMap, indexHolder);
}
}
private void appendRsvrcscdRvcdLeafCondition(StringBuilder sql,
String column,
String operator,
Object value,
Map<String, Object> paramMap,
int[] indexHolder) {
if (!StringUtils.hasText(column)) {
return;
}
if ("isnull".equals(operator)) {
sql.append(" AND ").append(column).append(" IS NULL ");
return;
}
if ("isnotnull".equals(operator)) {
sql.append(" AND ").append(column).append(" IS NOT NULL ");
return;
}
if ("in".equals(operator)) {
List<Object> values = normalizeFilterValues(value);
if (values.isEmpty()) {
return;
}
List<String> placeholders = new ArrayList<>();
for (Object item : values) {
String key = "rsvrcdRvcdParam" + indexHolder[0]++;
paramMap.put(key, item);
placeholders.add("#{map." + key + "}");
}
sql.append(" AND ").append(column).append(" IN (").append(String.join(", ", placeholders)).append(") ");
return;
}
if (value == null) {
return;
}
String key = "rsvrcdRvcdParam" + indexHolder[0]++;
switch (operator) {
case "eq" -> {
paramMap.put(key, value);
sql.append(" AND ").append(column).append(" = #{map.").append(key).append("} ");
}
case "neq" -> {
paramMap.put(key, value);
sql.append(" AND ").append(column).append(" <> #{map.").append(key).append("} ");
}
case "contains" -> {
paramMap.put(key, "%" + value + "%");
sql.append(" AND ").append(column).append(" LIKE #{map.").append(key).append("} ");
}
case "startswith" -> {
paramMap.put(key, value + "%");
sql.append(" AND ").append(column).append(" LIKE #{map.").append(key).append("} ");
}
case "endswith" -> {
paramMap.put(key, "%" + value);
sql.append(" AND ").append(column).append(" LIKE #{map.").append(key).append("} ");
}
case "gt" -> {
paramMap.put(key, value);
sql.append(" AND ").append(column).append(" > #{map.").append(key).append("} ");
}
case "gte" -> {
paramMap.put(key, value);
sql.append(" AND ").append(column).append(" >= #{map.").append(key).append("} ");
}
case "lt" -> {
paramMap.put(key, value);
sql.append(" AND ").append(column).append(" < #{map.").append(key).append("} ");
}
case "lte" -> {
paramMap.put(key, value);
sql.append(" AND ").append(column).append(" <= #{map.").append(key).append("} ");
}
default -> {
}
}
}
}

View File

@ -5939,7 +5939,7 @@ public class EngEqDataServiceImpl implements EngEqDataService {
.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 = a.STCD ")
.append("WHERE NVL(a.IS_DELETED, 0) = 0 ")
.append("AND NVL(a.USFL, 1) = 1 ")
// .append("AND NVL(a.USFL, 1) = 1 ")
.append("AND a.LGTD IS NOT NULL ")
.append("AND a.LTTD IS NOT NULL ")
.append("AND a.STTP IN (SELECT STTP_CODE FROM SD_STTP_B WHERE DESCRIPTION = 'EQ') ")

View File

@ -152,4 +152,10 @@ public class FbStationController {
public ResponseResult getFbPointKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(fbStationService.getFbPointKendoListCust(dataSourceRequest));
}
@PostMapping("/point/built/GetKendoListCust")
@Operation(summary = "增殖站地图描点接口(仅查询在建状态的)")
public ResponseResult getFbBuiltPointKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(fbStationService.getFbBuiltPointKendoListCust(dataSourceRequest));
}
}

View File

@ -65,4 +65,6 @@ public interface FbStationService {
DataSourceResult<TableVo> getFishbreedrFishKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<FbTracingPointVo> getFbPointKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<FbTracingPointVo> getFbBuiltPointKendoListCust(DataSourceRequest dataSourceRequest);
}

View File

@ -4577,6 +4577,15 @@ public class FbStationServiceImpl implements FbStationService {
@Override
public DataSourceResult<FbTracingPointVo> getFbPointKendoListCust(DataSourceRequest dataSourceRequest) {
return queryFbPointKendoListCust(dataSourceRequest, false);
}
@Override
public DataSourceResult<FbTracingPointVo> getFbBuiltPointKendoListCust(DataSourceRequest dataSourceRequest) {
return queryFbPointKendoListCust(dataSourceRequest, true);
}
private DataSourceResult<FbTracingPointVo> queryFbPointKendoListCust(DataSourceRequest dataSourceRequest, boolean builtMode) {
DataSourceResult<FbTracingPointVo> dataSourceResult = new DataSourceResult<>();
dataSourceResult.setAggregates(new HashMap<>());
@ -4589,6 +4598,9 @@ public class FbStationServiceImpl implements FbStationService {
DataSourceLoadOptionsBase devRequest = dataSourceRequest.toDevRequest();
String rstcd = QgcQueryWrapperUtil.getFilterFieldValue(devRequest, "rstcd");
String sttp = QgcQueryWrapperUtil.getFilterFieldValue(devRequest, "sttp");
if(StrUtil.isBlank(sttp)){
sttp= QgcQueryWrapperUtil.getFilterFieldValue(devRequest, "sttpCode");
}
String bldsttCcode = QgcQueryWrapperUtil.getFilterFieldValue(devRequest, "bldsttCcode");
if (StrUtil.isEmpty(sttp)) {
@ -4648,7 +4660,7 @@ public class FbStationServiceImpl implements FbStationService {
.append(" AND t.TM BETWEEN ADD_MONTHS(SYSDATE, -12) AND SYSDATE ")
.append(" GROUP BY t.RSTCD ")
.append(") b ON a.STCD = b.stcd ")
.append("WHERE NVL(a.USFL, 1) = 1 ")
.append("WHERE 1 = 1 ")
.append("AND a.LGTD IS NOT NULL ")
.append("AND a.LTTD IS NOT NULL ");
@ -4670,7 +4682,7 @@ public class FbStationServiceImpl implements FbStationService {
String filterSql = QgcQueryWrapperUtil.buildFilterCondition(
dataSourceRequest == null ? null : dataSourceRequest.getFilter(),
dataSourceRequest.getFilter(),
paramMap,
new int[]{0},
this::mapWeFvColumn
@ -4683,7 +4695,12 @@ public class FbStationServiceImpl implements FbStationService {
Page<?> page = devRequest == null ? null : QgcQueryWrapperUtil.buildPage(devRequest, devRequest.getSkip(), devRequest.getTake());
List<FbTracingPointVo> list = microservicDynamicSQLMapper.pageAllListWithResultType(page, sql.toString(), paramMap, FbTracingPointVo.class);
if (builtMode) {
enrichFbBuiltPointYearStatistics(list, sttp);
list = getBuiltPointLegend(list);
} else {
list = getPointLegend(list);
}
SiteAvoidanceUtils.calcSiteMapLev(list,
FbTracingPointVo::getStcd,
@ -4697,6 +4714,53 @@ public class FbStationServiceImpl implements FbStationService {
return dataSourceResult;
}
private void enrichFbBuiltPointYearStatistics(List<FbTracingPointVo> list, String sttp) {
if (CollUtil.isEmpty(list) || !"FB".equalsIgnoreCase(sttp)) {
return;
}
String currentYear = String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
Map<String, Object> planParamMap = new HashMap<>();
planParamMap.put("yr", currentYear);
String planSql = "SELECT plan.RSTCD AS stcd, SUM(det.FCNT) AS fcnt "
+ "FROM SD_ENGFRPLAN_B plan "
+ "INNER JOIN SD_ENGFRPLANDET_B det ON plan.ID = det.RPJH_ID "
+ "WHERE NVL(plan.IS_DELETED, 0) = 0 "
+ "AND NVL(det.IS_DELETED, 0) = 0 "
+ "AND TO_CHAR(plan.PLANSD, 'YYYY') = #{map.yr} "
+ "GROUP BY plan.RSTCD";
List<FbPointCountVo> planList = microservicDynamicSQLMapper.getAllListWithResultType(planSql, planParamMap, FbPointCountVo.class);
Map<String, Object> actualParamMap = new HashMap<>();
actualParamMap.put("yr", currentYear);
String actualSql = "SELECT run.RSTCD AS stcd, SUM(det.FCNT) AS fcnt "
+ "FROM SD_ENGFR_R run "
+ "INNER JOIN SD_RPIMNFISH_R det ON run.ID = det.RPIMN_ID "
+ "WHERE NVL(run.IS_DELETED, 0) = 0 "
+ "AND NVL(det.IS_DELETED, 0) = 0 "
+ "AND TO_CHAR(run.TM, 'YYYY') = #{map.yr} "
+ "GROUP BY run.RSTCD";
List<FbPointCountVo> actualList = microservicDynamicSQLMapper.getAllListWithResultType(actualSql, actualParamMap, FbPointCountVo.class);
Map<String, Long> planMap = planList.stream()
.filter(item -> StrUtil.isNotBlank(item.getStcd()))
.collect(Collectors.toMap(FbPointCountVo::getStcd, FbPointCountVo::getFcnt, (left, right) -> left));
Map<String, Long> actualMap = actualList.stream()
.filter(item -> StrUtil.isNotBlank(item.getStcd()))
.collect(Collectors.toMap(FbPointCountVo::getStcd, FbPointCountVo::getFcnt, (left, right) -> left));
list.forEach(item -> {
Long planCount = planMap.get(item.getStcd());
Long actualCount = actualMap.get(item.getStcd());
item.setYr(currentYear);
item.setJhCnt(planCount);
item.setFished(actualCount);
if (planCount != null) {
item.setUnfished(actualCount == null ? planCount : Math.max(planCount - actualCount, 0L));
}
});
}
private String mapWeFvColumn(String field) {
if (StrUtil.isBlank(field)) {
return null;
@ -4705,6 +4769,7 @@ public class FbStationServiceImpl implements FbStationService {
case "rstcd" -> "a.RSTCD";
case "stcd" -> "a.STCD";
case "sttp" -> "a.STTP";
case "sttpcode" -> "a.STTP";
case "bldsttccode" -> "a.BLDSTT_CODE";
case "lgtd" -> "a.LGTD";
default -> null;
@ -4727,4 +4792,41 @@ public class FbStationServiceImpl implements FbStationService {
}
return voList;
}
private List<FbTracingPointVo> getBuiltPointLegend(List<FbTracingPointVo> voList) {
for (FbTracingPointVo pointVo : voList) {
Integer bldstt = pointVo.getBldstt();
String sttp = pointVo.getSttp();
if (bldstt != null && bldstt == 1) {
if ("FB".equals(sttp)) {
pointVo.setAnchoPointState("fb_built");
}
if ("SG".equals(sttp)) {
pointVo.setAnchoPointState("sg_built");
}
}
}
return voList;
}
private static class FbPointCountVo {
private String stcd;
private Long fcnt;
public String getStcd() {
return stcd;
}
public void setStcd(String stcd) {
this.stcd = stcd;
}
public Long getFcnt() {
return fcnt;
}
public void setFcnt(Long fcnt) {
this.fcnt = fcnt;
}
}
}

View File

@ -1955,13 +1955,13 @@ public class FhHabitatServiceImpl implements FhHabitatService {
.append("t.DTIN AS dtin ")
.append("FROM ( ")
.append(" SELECT STCD, STNM, 'FH' AS STTP_CODE, RSTCD, BASE_ID, HBRVCD, LGTD, LTTD, BLPRD AS BLDSTT_CCODE, ELEV, DTIN ")
.append(" FROM SD_FHBT_B_H WHERE NVL(IS_DELETED, 0) = 0 AND USFL = 1 ")
.append(" FROM SD_FHBT_B_H WHERE NVL(IS_DELETED, 0) = 0 ")
.append(" UNION ALL ")
.append(" SELECT STCD, STNM, STTP AS STTP_CODE, RSTCD, BASE_ID, HBRVCD, LGTD, LTTD, BLDSTT_CODE AS BLDSTT_CCODE, ELEV, DTIN ")
.append(" FROM SD_VA_B_H WHERE NVL(IS_DELETED, 0) = 0 AND USFL = 1 ")
.append(" FROM SD_VA_B_H WHERE NVL(IS_DELETED, 0) = 0 ")
.append(" UNION ALL ")
.append(" SELECT STCD, STNM, STTP AS STTP_CODE, RSTCD, BASE_ID, HBRVCD, LGTD, LTTD, BLDSTT_CODE AS BLDSTT_CCODE, ELEV, DTIN ")
.append(" FROM SD_VP_B_H WHERE NVL(IS_DELETED, 0) = 0 AND USFL = 1 ")
.append(" FROM SD_VP_B_H WHERE NVL(IS_DELETED, 0) = 0 ")
.append(") 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 = NVL(t.BASE_ID, eng.BASE_ID) AND NVL(hb.IS_DELETED, 0) = 0 ")

View File

@ -106,6 +106,12 @@ public class FishPassageController {
return ResponseResult.successData(fpBuildService.getStInfoByStcd(stcd));
}
@PostMapping("/point/qgc/GetKendoListCust")
@Operation(summary = "环保部-过鱼设施描点接口")
public ResponseResult getQgcFpPointKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(fpBuildService.getQgcFpPointKendoListCust(dataSourceRequest));
}
@PostMapping("/point/built/GetKendoListCust")
@Operation(summary = "过鱼设施地图描点接口(仅查询在建状态的)")
public ResponseResult getFpBuiltPointKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) {

View File

@ -15,6 +15,9 @@ public class FpAnchoPointVo {
@Schema(description = "站名")
private String stnm;
@Schema(description = "站点图片")
private String logo;
@Schema(description = "弹框站点名称")
private String titleName;
@ -45,6 +48,9 @@ public class FpAnchoPointVo {
@Schema(description = "运行状态")
private String run;
@Schema(description = "运行状态名称")
private String runName;
@Schema(description = "设施类型")
private String dwtp;
@ -78,9 +84,21 @@ public class FpAnchoPointVo {
@Schema(description = "达标状态子类型")
private Integer stdSstate;
@Schema(description = "达标状态子类型名称")
private String stdSstateName;
@Schema(description = "地图避让")
private Integer distance;
@Schema(description = "澜沧江运行状态")
private Integer lcjStatus;
@Schema(description = "澜沧江运行状态名称")
private String lcjStatusName;
@Schema(description = "年份")
private String yr;
@Schema(description = "过鱼种类")
private Integer ftpTypeCount;

View File

@ -0,0 +1,21 @@
package com.yfd.platform.qgc_env.fp.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "过鱼设施鱼类统计")
public class FpFishStatisticsVo {
@Schema(description = "站点编码")
private String stcd;
@Schema(description = "鱼类名称")
private String ftp;
@Schema(description = "鱼编码")
private String fishId;
@Schema(description = "数量")
private Integer count;
}

View File

@ -21,5 +21,7 @@ public interface FpBuildService {
FpVmsstbprptVo getStInfoByStcd(String stcd);
DataSourceResult<FpAnchoPointVo> getQgcFpPointKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<FpAnchoPointVo> getFpBuiltPointKendoListCust(DataSourceRequest dataSourceRequest);
}

View File

@ -14,6 +14,7 @@ import com.yfd.platform.common.exception.BizException;
import com.yfd.platform.qgc_env.fp.entity.vo.FpAnchoPointVo;
import com.yfd.platform.qgc_env.fp.entity.vo.FpConstructionSituationVo;
import com.yfd.platform.qgc_env.fp.entity.vo.FpFishDicVo;
import com.yfd.platform.qgc_env.fp.entity.vo.FpFishStatisticsVo;
import com.yfd.platform.qgc_env.fp.entity.vo.FpVmsstbprptVo;
import com.yfd.platform.qgc_env.wt.utils.SiteAvoidanceUtils;
import com.yfd.platform.qgc_env.fp.service.FpBuildService;
@ -28,6 +29,8 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@Service
public class FpBuildServiceImpl implements FpBuildService {
@ -214,6 +217,99 @@ public class FpBuildServiceImpl implements FpBuildService {
return list.getFirst();
}
@Override
public DataSourceResult<FpAnchoPointVo> getQgcFpPointKendoListCust(DataSourceRequest dataSourceRequest) {
DataSourceResult<FpAnchoPointVo> dataSourceResult = new DataSourceResult<>();
dataSourceResult.setAggregates(new HashMap<>());
if (dataSourceRequest == null) {
dataSourceResult.setData(new ArrayList<>());
dataSourceResult.setTotal(0L);
return dataSourceResult;
}
StringBuilder sql = new StringBuilder("SELECT " +
"fp.STCD AS stcd, " +
"fp.STNM AS stnm, " +
"fp.LOGO AS logo, " +
"fp.STNM AS titleName, " +
"fp.BLDSTT_CODE AS bldsttCcode, " +
"fp.BLDSTT_CODE AS bldstt, " +
"fp.LTTD AS lttd, " +
"fp.LGTD AS lgtd, " +
"fp.ELEV AS dtmel, " +
"fp.RSTCD AS rstcds, " +
"eng.ENNM AS ennm, " +
"'FP' AS sttpCode, " +
"state.RUN_STATE AS run, " +
"CASE WHEN state.RUN_STATE = 1 THEN '运行中' WHEN state.RUN_STATE IN (0, 2) THEN '未运行' ELSE NULL END AS runName, " +
"fp.STTP AS dwtp, " +
"CASE " +
"WHEN fp.STTP = 'FP_1' THEN '鱼道' " +
"WHEN fp.STTP = 'FP_2' THEN '仿自然通道' " +
"WHEN fp.STTP = 'FP_3' THEN '集运鱼系统' " +
"WHEN fp.STTP = 'FP_4' THEN '升鱼机' " +
"ELSE '其它' END AS dwtpName, " +
"fp.STTP AS sttpMap, " +
"eng.RVCD AS rvcd, " +
"eng.ADDVCD AS addvcd, " +
"eng.BASE_ID AS baseId, " +
"fp.STTP AS sttp, " +
"CASE " +
"WHEN fp.STTP = 'FP_1' THEN 'GY_1' " +
"WHEN fp.STTP = 'FP_2' THEN 'GY_2' " +
"WHEN fp.STTP = 'FP_3' THEN 'GY_3' " +
"WHEN fp.STTP = 'FP_4' THEN 'GY_4' " +
"ELSE 'GY_5' END AS anchoPointState, " +
"fp.MWAY AS mway, " +
"fp.DTIN AS dtin, " +
"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, " +
"CASE WHEN recent.STCD IS NULL THEN 2 ELSE 1 END AS lcjStatus, " +
"CASE WHEN recent.STCD IS NULL THEN '暂无数据' ELSE '正常运行' END AS lcjStatusName, " +
"fp.ORDER_INDEX AS orderIndex " +
"FROM SD_FPSS_B_H fp " +
"LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fp.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " +
"LEFT JOIN (SELECT s.STCD, s.RUN_STATE, s.STD_SSTATE " +
" FROM MS_STSTATE_T s " +
" INNER JOIN (SELECT STCD, MAX(YR) AS YR FROM MS_STSTATE_T WHERE NVL(IS_DELETED, 0) = 0 GROUP BY STCD) latest " +
" ON latest.STCD = s.STCD AND latest.YR = s.YR " +
" WHERE NVL(s.IS_DELETED, 0) = 0) state ON state.STCD = fp.STCD " +
"LEFT JOIN (SELECT STCD FROM SD_FPSSRL_R WHERE NVL(IS_DELETED, 0) = 0 AND TM BETWEEN ADD_MONTHS(SYSDATE, -12) AND SYSDATE GROUP BY STCD " +
" UNION " +
" SELECT STCD FROM SD_FPSS_R WHERE NVL(IS_DELETED, 0) = 0 AND STRDT >= ADD_MONTHS(SYSDATE, -12) AND NVL(ENDDT, STRDT) <= SYSDATE GROUP BY STCD) recent " +
"ON recent.STCD = fp.STCD " +
"WHERE NVL(fp.IS_DELETED, 0) = 0 AND fp.STTP !='FPQ'");
Map<String, Object> paramMap = new HashMap<>();
DataSourceLoadOptionsBase loadOptions = dataSourceRequest.toDevRequest();
String filterSql = buildFpPointFilterCondition(dataSourceRequest.getFilter(), paramMap, new int[]{0});
if (StrUtil.isNotBlank(filterSql)) {
sql.append(" AND ").append(filterSql).append(" ");
}
sql.append(buildFpPointOrderBySql(dataSourceRequest.getSort()));
Page<?> page = QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
List<FpAnchoPointVo> resultList = microservicDynamicSQLMapper.pageAllListWithResultType(
page, sql.toString(), paramMap, FpAnchoPointVo.class);
if (CollUtil.isNotEmpty(resultList)) {
fillQgcFpPointStatistics(resultList);
applyFpPointLegend(resultList);
SiteAvoidanceUtils.calcSiteMapLev(resultList,
FpAnchoPointVo::getStcd,
FpAnchoPointVo::getLgtd,
FpAnchoPointVo::getLttd,
FpAnchoPointVo::getAnchoPointState,
FpAnchoPointVo::setDistance);
}
dataSourceResult.setData(resultList);
dataSourceResult.setTotal(page == null ? resultList.size() : page.getTotal());
return dataSourceResult;
}
private String buildFishDicBaseSql() {
return "SELECT " +
"src.ID AS id, " +
@ -1185,12 +1281,17 @@ public class FpBuildServiceImpl implements FpBuildService {
" fp.DTIN AS dtin\n" +
"FROM SD_FPSS_B_H fp\n" +
"LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fp.RSTCD AND NVL(eng.IS_DELETED, 0) = 0\n" +
"WHERE NVL(fp.IS_DELETED, 0) = 0 AND fp.BLDSTT_CODE = 1 AND fp.LGTD IS NOT NULL AND fp.LTTD IS NOT NULL ");
"WHERE NVL(fp.IS_DELETED, 0) = 0 ");
Map<String, Object> paramMap = new HashMap<>();
DataSourceLoadOptionsBase loadOptions = dataSourceRequest.toDevRequest();
String filterSql = buildFpPointFilterCondition(dataSourceRequest.getFilter(), paramMap, new int[]{0});
String filterSql = QgcQueryWrapperUtil.buildFilterCondition(
dataSourceRequest.getFilter(),
paramMap,
new int[]{0},
this::mapFpColumn
);
// String filterSql = buildFpPointFilterCondition(dataSourceRequest.getFilter(), paramMap, new int[]{0});
if (StrUtil.isNotBlank(filterSql)) {
sql.append(" AND ").append(filterSql).append(" ");
}
@ -1227,6 +1328,205 @@ public class FpBuildServiceImpl implements FpBuildService {
return dataSourceResult;
}
private void fillQgcFpPointStatistics(List<FpAnchoPointVo> pointList) {
List<String> stcdList = pointList.stream()
.map(FpAnchoPointVo::getStcd)
.filter(StrUtil::isNotBlank)
.distinct()
.collect(Collectors.toList());
if (CollUtil.isEmpty(stcdList)) {
return;
}
String year = queryLatestFpYear(stcdList);
List<FpFishStatisticsVo> manualList = queryQgcFpManualFishStatistics(stcdList, year);
Set<String> manualStcdSet = manualList.stream()
.map(FpFishStatisticsVo::getStcd)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toSet());
List<String> autoQueryStcdList = stcdList.stream()
.filter(stcd -> !manualStcdSet.contains(stcd))
.collect(Collectors.toList());
List<FpFishStatisticsVo> autoList = queryQgcFpAutoFishStatistics(autoQueryStcdList, year);
if (CollUtil.isNotEmpty(autoList)) {
manualList.addAll(autoList);
}
Map<String, List<FpFishStatisticsVo>> stcdDataMap = manualList.stream()
.collect(Collectors.groupingBy(FpFishStatisticsVo::getStcd));
for (FpAnchoPointVo vo : pointList) {
vo.setYr(year);
List<FpFishStatisticsVo> fishStatistics = stcdDataMap.get(vo.getStcd());
if (CollUtil.isEmpty(fishStatistics)) {
continue;
}
vo.setFtpTypeCount(fishStatistics.size());
vo.setFtpCount(fishStatistics.stream()
.filter(item -> item.getCount() != null)
.mapToInt(FpFishStatisticsVo::getCount)
.sum());
}
}
private String queryLatestFpYear(List<String> stcdList) {
Map<String, Object> paramMap = new HashMap<>();
StringBuilder sql = new StringBuilder("SELECT MAX(t.YR) AS yr FROM (" +
"SELECT TO_CHAR(STRDT, 'yyyy') AS YR, STCD FROM SD_FPSS_R WHERE NVL(IS_DELETED, 0) = 0 " +
"UNION ALL " +
"SELECT TO_CHAR(TM, 'yyyy') AS YR, STCD FROM SD_FPSSRL_R WHERE NVL(IS_DELETED, 0) = 0) t WHERE 1 = 1 ");
appendInCondition(sql, paramMap, "t.STCD", stcdList, "fpYear");
List<FpAnchoPointVo> list = microservicDynamicSQLMapper.getAllListWithResultType(sql.toString(), paramMap, FpAnchoPointVo.class);
if (CollUtil.isEmpty(list) || StrUtil.isBlank(list.getFirst().getYr())) {
return String.valueOf(java.time.LocalDate.now().getYear());
}
return list.getFirst().getYr();
}
private List<FpFishStatisticsVo> queryQgcFpManualFishStatistics(List<String> stcdList, String year) {
if (CollUtil.isEmpty(stcdList)) {
return new ArrayList<>();
}
Map<String, Object> paramMap = new HashMap<>();
StringBuilder sql = new StringBuilder("SELECT data.STCD AS stcd, data.FTP AS fishId, dict.NAME AS ftp, SUM(data.FCNT) AS count " +
"FROM (SELECT t.STCD, t.FTP, t.FCNT, eng.HBRVCD " +
" FROM SD_FPSS_R t " +
" INNER JOIN SD_FPSS_B_H fp ON fp.STCD = t.STCD AND NVL(fp.IS_DELETED, 0) = 0 " +
" LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fp.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " +
" WHERE NVL(t.IS_DELETED, 0) = 0 ");
paramMap.put("manualYear", year);
sql.append(" AND TO_CHAR(t.STRDT, 'yyyy') = #{map.manualYear}) data ")
.append("INNER JOIN (SELECT DISTINCT rel.FISH_ID, rel.RVCD, dic.NAME " +
" FROM SD_FISHDICTORY_RLTN_B rel " +
" LEFT JOIN SD_FISHDICTORY_B dic ON dic.ID = rel.ZY_FISH_ID " +
" WHERE NVL(rel.IS_DELETED, 0) = 0 AND NVL(dic.IS_DELETED, 0) = 0 " +
" AND (rel.FISH_ID <> rel.ZY_FISH_ID OR rel.RVCD = 'ZY')) dict " +
"ON dict.FISH_ID = data.FTP AND (dict.RVCD = data.HBRVCD OR dict.RVCD = 'ZY') WHERE 1 = 1 ");
appendInCondition(sql, paramMap, "data.STCD", stcdList, "fpManual");
sql.append(" GROUP BY data.STCD, data.FTP, dict.NAME");
return microservicDynamicSQLMapper.getAllListWithResultType(sql.toString(), paramMap, FpFishStatisticsVo.class);
}
private List<FpFishStatisticsVo> queryQgcFpAutoFishStatistics(List<String> stcdList, String year) {
if (CollUtil.isEmpty(stcdList)) {
return new ArrayList<>();
}
Map<String, Object> paramMap = new HashMap<>();
StringBuilder sql = new StringBuilder("SELECT data.STCD AS stcd, data.FTP AS fishId, dict.NAME AS ftp, SUM(data.FCNT) AS count " +
"FROM (SELECT t.STCD, t.FTP, t.FCNT, eng.HBRVCD " +
" FROM SD_FPSSRL_R t " +
" INNER JOIN SD_FPSS_B_H fp ON fp.STCD = t.STCD AND NVL(fp.IS_DELETED, 0) = 0 " +
" LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = fp.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " +
" WHERE NVL(t.IS_DELETED, 0) = 0 ");
paramMap.put("autoYear", year);
sql.append(" AND TO_CHAR(t.TM, 'yyyy') = #{map.autoYear}) data ")
.append("INNER JOIN (SELECT DISTINCT rel.FISH_ID, rel.RVCD, dic.NAME " +
" FROM SD_FISHDICTORY_RLTN_B rel " +
" LEFT JOIN SD_FISHDICTORY_B dic ON dic.ID = rel.ZY_FISH_ID " +
" WHERE NVL(rel.IS_DELETED, 0) = 0 AND NVL(dic.IS_DELETED, 0) = 0 " +
" AND (rel.FISH_ID <> rel.ZY_FISH_ID OR rel.RVCD = 'ZY')) dict " +
"ON dict.FISH_ID = data.FTP AND (dict.RVCD = data.HBRVCD OR dict.RVCD = 'ZY') WHERE 1 = 1 ");
appendInCondition(sql, paramMap, "data.STCD", stcdList, "fpAuto");
sql.append(" GROUP BY data.STCD, data.FTP, dict.NAME");
return microservicDynamicSQLMapper.getAllListWithResultType(sql.toString(), paramMap, FpFishStatisticsVo.class);
}
private void applyFpPointLegend(List<FpAnchoPointVo> voList) {
for (FpAnchoPointVo pointVo : voList) {
if (!"2".equals(pointVo.getBldstt())) {
if ("FP_1".equals(pointVo.getSttp())) {
pointVo.setAnchoPointState("GY_1_INCOMPLETE");
} else if ("FP_2".equals(pointVo.getSttp())) {
pointVo.setAnchoPointState("GY_2_INCOMPLETE");
} else if ("FP_3".equals(pointVo.getSttp())) {
pointVo.setAnchoPointState("GY_3_INCOMPLETE");
} else if ("FP_4".equals(pointVo.getSttp())) {
pointVo.setAnchoPointState("GY_4_INCOMPLETE");
} else {
pointVo.setAnchoPointState("GY_5_INCOMPLETE");
}
}
}
}
private void appendInCondition(StringBuilder sql,
Map<String, Object> paramMap,
String column,
List<String> values,
String prefix) {
if (CollUtil.isEmpty(values)) {
return;
}
List<String> placeholders = new ArrayList<>();
int index = 0;
for (String value : values) {
if (StrUtil.isBlank(value)) {
continue;
}
String key = prefix + index++;
paramMap.put(key, value);
placeholders.add("#{map." + key + "}");
}
if (CollUtil.isEmpty(placeholders)) {
return;
}
sql.append(" AND ").append(column).append(" IN (")
.append(String.join(", ", placeholders))
.append(") ");
}
private String buildFpPointOrderBySql(List<DataSourceRequest.SortDescriptor> sorts) {
if (CollUtil.isEmpty(sorts)) {
return " ORDER BY fp.ORDER_INDEX ASC NULLS LAST, fp.STCD ASC";
}
List<String> orderItems = new ArrayList<>();
for (DataSourceRequest.SortDescriptor sort : sorts) {
if (sort == null || StrUtil.isBlank(sort.getField())) {
continue;
}
String column = mapFpPointOrderColumn(sort.getField());
if (StrUtil.isBlank(column)) {
continue;
}
String direction = "desc".equalsIgnoreCase(sort.getDir()) || "des".equalsIgnoreCase(sort.getDir()) ? "DESC" : "ASC";
orderItems.add(column + " " + direction + " NULLS LAST");
}
if (orderItems.isEmpty()) {
return " ORDER BY fp.ORDER_INDEX ASC NULLS LAST, fp.STCD ASC";
}
return " ORDER BY " + String.join(", ", orderItems);
}
private String mapFpPointOrderColumn(String field) {
if (StrUtil.isBlank(field)) {
return null;
}
return switch (field) {
case "stcd" -> "fp.STCD";
case "stnm", "titleName" -> "fp.STNM";
case "bldsttCcode", "bldstt" -> "fp.BLDSTT_CODE";
case "lgtd" -> "fp.LGTD";
case "lttd" -> "fp.LTTD";
case "ennm" -> "eng.ENNM";
case "baseId" -> "eng.BASE_ID";
case "rvcd" -> "eng.RVCD";
case "addvcd" -> "eng.ADDVCD";
case "run" -> "state.RUN_STATE";
case "stdSstate" -> "state.STD_SSTATE";
default -> null;
};
}
private String mapFpColumn(String field) {
if (StrUtil.isBlank(field)) {
return null;
}
return switch (field.toLowerCase()) {
case "bldsttccode" -> "fp.BLDSTT_CODE";
case "lgtd" -> "fp.LGTD";
case "lttd" -> "fp.LTTD";
default -> null;
};
}
private String buildFpPointFilterCondition(DataSourceRequest.FilterDescriptor filter,
Map<String, Object> paramMap,
int[] indexHolder) {
@ -1267,6 +1567,12 @@ public class FpBuildServiceImpl implements FpBuildService {
case "rvcd" -> "eng.RVCD";
case "addvcd" -> "eng.ADDVCD";
case "sttp" -> "fp.STTP";
case "bldsttCcode", "bldstt" -> "fp.BLDSTT_CODE";
case "lgtd" -> "fp.LGTD";
case "lttd" -> "fp.LTTD";
case "run" -> "state.RUN_STATE";
case "stdSstate" -> "state.STD_SSTATE";
case "lcjStatus" -> "CASE WHEN recent.STCD IS NULL THEN 2 ELSE 1 END";
default -> null;
};
if (column == null) {

View File

@ -89,8 +89,15 @@ public class FprMonitorController {
@PostMapping("/sdFprdR/point/getFprdPointList")
@Operation(summary = "鱼类调查装置锚点信息")
public ResponseResult getFprdPointList(@RequestBody FprdRunDataAo ao) {
List<FprdPointInfoVo> result = fprMonitorService.getFprdInfoList(ao);
public ResponseResult getFprdPointList(@RequestBody DataSourceRequest dataSourceRequest) {
List<FprdPointInfoVo> result = fprMonitorService.getFprdPointList(dataSourceRequest);
return ResponseResult.successData(result);
}
@PostMapping("/point/getFprdPointList")
@Operation(summary = "鱼类调查装置锚点信息(AO入参)")
public ResponseResult getFprdPointListByAo(@RequestBody FprdRunDataAo ao) {
List<FprdPointInfoVo> result = fprMonitorService.getFprdPointList(ao);
return ResponseResult.successData(result);
}

View File

@ -31,5 +31,7 @@ public interface FprMonitorService {
List<String> getFishInfo();
List<FprdPointInfoVo> getFprdInfoList(FprdRunDataAo ao);
List<FprdPointInfoVo> getFprdPointList(FprdRunDataAo ao);
List<FprdPointInfoVo> getFprdPointList(DataSourceRequest dataSourceRequest);
}

View File

@ -129,11 +129,24 @@ public class FprMonitorServiceImpl implements FprMonitorService {
}
@Override
public List<FprdPointInfoVo> getFprdInfoList(FprdRunDataAo ao) {
validateFprdRunDataAo(ao);
public List<FprdPointInfoVo> getFprdPointList(FprdRunDataAo ao) {
validateFprdPointAo(ao);
return listFprdPointInfo(ao.getBaseId(), ao.getHbrvcd(), ao.getStcd());
}
@Override
public List<FprdPointInfoVo> getFprdPointList(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
String baseId = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "baseId");
String hbrvcd = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "hbrvcd");
String stcd = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "stcd");
validateFprdPointRequest(baseId);
return listFprdPointInfo(baseId, hbrvcd, stcd);
}
private List<FprdPointInfoVo> listFprdPointInfo(String baseId, String hbrvcd, String stcd) {
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("baseId", ao.getBaseId());
StringBuilder sql = new StringBuilder("SELECT ")
.append("aim.STCD AS stcd, ")
@ -143,17 +156,17 @@ public class FprMonitorServiceImpl implements FprMonitorService {
.append("TO_CHAR(aim.BLDSTT_CODE) AS bldstt, ")
.append("aim.LTTD AS lttd, ")
.append("aim.LGTD AS lgtd, ")
.append("aim.DTMEL AS dtmel, ")
// .append("aim.DTMEL AS dtmel, ")
.append("aim.RSTCD AS rstcds, ")
.append("eng.ENNM AS ennm, ")
.append("aim.STTP AS sttpCode, ")
.append("aim.DWTP AS dwtp, ")
.append("aim.DWTP AS dwtpName, ")
// .append("aim.DWTP AS dwtp, ")
// .append("aim.DWTP AS dwtpName, ")
.append("aim.STTP AS sttpMap, ")
.append("aim.RVCD AS rvcd, ")
.append("rv.RVNM AS rvcdName, ")
.append("aim.ADDVCD AS addvcd, ")
.append("addv.ADDVCD_NAME AS addvcdName, ")
// .append("aim.ADDVCD AS addvcd, ")
// .append("addv.ADDVCD_NAME AS addvcdName, ")
.append("aim.HBRVCD AS hbrvcd, ")
.append("hbrv.HBRVNM AS hbrvcdName, ")
.append("aim.BASE_ID AS baseId, ")
@ -163,7 +176,7 @@ public class FprMonitorServiceImpl implements FprMonitorService {
.append("'' AS anchoPointState, ")
.append("aim.MWAY AS mway, ")
.append("aim.DTIN AS dtin, ")
.append("aim.STDSSTATE AS stdSstate, ")
// .append("aim.STDSSTATE AS stdSstate, ")
.append("aim.STLC AS stlc ")
.append("FROM SD_AIMONITOR_B_H aim ")
.append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = aim.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ")
@ -173,23 +186,26 @@ public class FprMonitorServiceImpl implements FprMonitorService {
.append(" AND NVL(hbrv.IS_DELETED, 0) = 0 ")
.append(" AND NVL(hbrv.ENABLED, 1) = 1 ")
.append("LEFT JOIN SD_RVCD_DIC rv ON rv.RVCD = aim.RVCD ")
.append("LEFT JOIN SD_ADDVCD_DIC addv ON addv.ADDVCD = aim.ADDVCD ")
// .append("LEFT JOIN SD_ADDVCD_DIC addv ON addv.ADDVCD = aim.ADDVCD ")
.append("LEFT JOIN SD_STTP_B sttp ON sttp.STTP_CODE = aim.STTP ")
.append(" AND NVL(sttp.IS_DELETED, 0) = 0 ")
.append(" AND NVL(sttp.ENABLE, 1) = 1 ")
.append("WHERE NVL(aim.IS_DELETED, 0) = 0 ")
.append(" AND aim.STTP = 'FPRD' ")
.append(" AND aim.LGTD IS NOT NULL ")
.append(" AND aim.BASE_ID = #{map.baseId}");
.append(" AND aim.LGTD IS NOT NULL ");
if (StrUtil.isNotBlank(ao.getHbrvcd())) {
if (StrUtil.isNotBlank(baseId)) {
sql.append(" AND aim.BASE_ID = #{map.baseId}");
}
paramMap.put("baseId", baseId);
if (StrUtil.isNotBlank(hbrvcd)) {
sql.append(" AND aim.HBRVCD = #{map.hbrvcd}");
paramMap.put("hbrvcd", ao.getHbrvcd());
paramMap.put("hbrvcd", hbrvcd);
}
if (StrUtil.isNotBlank(ao.getStcd())) {
if (StrUtil.isNotBlank(stcd)) {
sql.append(" AND aim.STCD = #{map.stcd}");
paramMap.put("stcd", ao.getStcd());
paramMap.put("stcd", stcd);
}
List<FprdPointInfoVo> resultList = microservicDynamicSQLMapper.getAllListWithResultType(
@ -691,6 +707,19 @@ public class FprMonitorServiceImpl implements FprMonitorService {
}
}
private void validateFprdPointRequest(String baseId) {
// if (StrUtil.isBlank(baseId)) {
// throw new BizException("基地编码(baseId)不能为空.");
// }
}
private void validateFprdPointAo(FprdRunDataAo ao) {
if (ao == null) {
throw new BizException("请求参数不能为空.");
}
validateFprdPointRequest(ao.getBaseId());
}
private String buildFishDicBaseSql() {
return "SELECT " +
"src.ID AS id, " +

View File

@ -1948,7 +1948,7 @@ public class VpConstructionServiceImpl implements VpConstructionService {
" t.STTP AS sttp,\n" +
" t.DTIN AS dtin\n" +
"FROM (\n" +
" SELECT STCD, STNM, STTP, LGTD, LTTD, ELEV, RSTCD, BASE_ID, RVCD, ADDVCD, BLDSTT_CODE, DTIN\n" +
" SELECT STCD, STNM, STTP, LGTD, LTTD, ELEV, RSTCD, BASE_ID,NULL RVCD,NULL ADDVCD, BLDSTT_CODE, DTIN\n" +
" FROM SD_VP_B_H\n" +
" WHERE NVL(IS_DELETED, 0) = 0 AND BLDSTT_CODE = 1 AND LGTD IS NOT NULL AND LTTD IS NOT NULL\n" +
" UNION ALL\n" +
@ -1960,10 +1960,16 @@ public class VpConstructionServiceImpl implements VpConstructionService {
" FROM SD_FHBT_B_H\n" +
" WHERE NVL(IS_DELETED, 0) = 0 AND LGTD IS NOT NULL AND LTTD IS NOT NULL\n" +
") t\n" +
"LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = t.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ");
"LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = t.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 WHERE 1=1");
Map<String, Object> paramMap = new HashMap<>();
String filterSql = buildFhvapPointFilterCondition(dataSourceRequest.getFilter(), paramMap, new int[]{0});
String filterSql = QgcQueryWrapperUtil.buildFilterCondition(
dataSourceRequest.getFilter(),
paramMap,
new int[]{0},
this::mapVpColumn
);
// String filterSql = buildFhvapPointFilterCondition(dataSourceRequest.getFilter(), paramMap, new int[]{0});
if (StrUtil.isNotBlank(filterSql)) {
sql.append(" AND ").append(filterSql);
}
@ -1991,6 +1997,26 @@ public class VpConstructionServiceImpl implements VpConstructionService {
return dataSourceResult;
}
private String mapVpColumn(String field) {
if (StrUtil.isBlank(field)) {
return null;
}
Map<String, String> columnMap = new HashMap<>();
columnMap.put("stcd", "t.STCD");
columnMap.put("stnm", "t.STNM");
columnMap.put("sttpcode", "t.STTP");
columnMap.put("bldsttccode", "t.BLDSTT_CODE");
columnMap.put("lgtd", "t.LGTD");
columnMap.put("lttd", "t.LTTD");
columnMap.put("baseId", "t.BASE_ID");
columnMap.put("rvcd", "t.RVCD");
columnMap.put("addvcd", "t.ADDVCD");
columnMap.put("rstcds", "t.RSTCD");
columnMap.put("ennm", "eng.ENNM");
return columnMap.get(field.toLowerCase());
}
private String buildFhvapPointFilterCondition(DataSourceRequest.FilterDescriptor filter,
Map<String, Object> paramMap,
int[] indexHolder) {
@ -2149,19 +2175,25 @@ public class VpConstructionServiceImpl implements VpConstructionService {
" we.ELEV AS dtmel,\n" +
" we.RSTCD AS rstcds,\n" +
" eng.ENNM AS ennm,\n" +
" 'WVA' AS sttpMap,\n" +
" we.STTP AS sttpMap,\n" +
" we.RVCD AS rvcd,\n" +
" we.ADDVCD AS addvcd,\n" +
// " we.ADDVCD AS addvcd,\n" +
" we.BASE_ID AS baseId,\n" +
" 'WVA' AS sttp,\n" +
" we.STTP AS sttp,\n" +
" 'wild_animal_legend' AS anchoPointState,\n" +
" 'WVA' AS sttpCode\n" +
"FROM SD_WE_B_H we\n" +
" we.STTP AS sttpCode\n" +
"FROM SD_AIMONITOR_B_H we\n" +
"LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = we.RSTCD AND NVL(eng.IS_DELETED, 0) = 0\n" +
"WHERE we.LGTD IS NOT NULL AND we.LTTD IS NOT NULL ");
Map<String, Object> paramMap = new HashMap<>();
String filterSql = buildWvaPointFilterCondition(dataSourceRequest.getFilter(), paramMap, new int[]{0});
String filterSql = QgcQueryWrapperUtil.buildFilterCondition(
dataSourceRequest.getFilter(),
paramMap,
new int[]{0},
this::mapVapWvaColumn
);
// String filterSql = buildWvaPointFilterCondition(dataSourceRequest.getFilter(), paramMap, new int[]{0});
if (StrUtil.isNotBlank(filterSql)) {
sql.append(" AND ").append(filterSql);
}
@ -2176,6 +2208,26 @@ public class VpConstructionServiceImpl implements VpConstructionService {
return dataSourceResult;
}
private String mapVapWvaColumn(String field) {
if (StrUtil.isBlank(field)) {
return null;
}
Map<String, String> columnMap = new HashMap<>();
columnMap.put("stcd", "we.STCD");
columnMap.put("stnm", "we.STNM");
columnMap.put("sttpcode", "we.STTP");
columnMap.put("bldsttccode", "we.BLDSTT_CODE");
columnMap.put("lgtd", "we.LGTD");
columnMap.put("lttd", "we.LTTD");
columnMap.put("baseId", "we.BASE_ID");
columnMap.put("rvcd", "we.RVCD");
columnMap.put("addvcd", "we.ADDVCD");
columnMap.put("rstcds", "weRSTCD");
columnMap.put("ennm", "eng.ENNM");
return columnMap.get(field.toLowerCase());
}
private String buildWvaPointFilterCondition(DataSourceRequest.FilterDescriptor filter,
Map<String, Object> paramMap,
int[] indexHolder) {

View File

@ -65,6 +65,12 @@ public class VdMonitorController {
return ResponseResult.successData(vdMonitorService.getVdPointKendoListCust(dataSourceRequest));
}
@PostMapping("/aiPoint/GetKendoListCust")
@Operation(summary = "视频站AI设施锚点")
public ResponseResult getVdAiPointKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(vdMonitorService.getVdAiPointKendoListCust(dataSourceRequest));
}
@PostMapping("/runData/GetKendoListCust")
@Operation(summary = "查询视频监控运行数据")
public ResponseResult getRunDataKendoListCust(@RequestBody DataSourceRequest dataSourceRequest) {

View File

@ -0,0 +1,107 @@
package com.yfd.platform.qgc_env.vd.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
@Data
@Schema(description = "视频站AI设施锚点信息")
public class VdAiPointVo implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "锚点状态")
private String anchoPointState;
@Schema(description = "地图站类标识")
private String sttpMap;
@Schema(description = "锚点站类")
private String sttp;
@Schema(description = "视频站编码")
private String stcd;
@Schema(description = "视频站名称")
private String stnm;
@Schema(description = "经度")
private BigDecimal lgtd;
@Schema(description = "纬度")
private BigDecimal lttd;
@Schema(description = "流域编码")
private String rvcd;
@Schema(description = "行政区编码")
private String addvcd;
@Schema(description = "流域名称")
private String rvnm;
@Schema(description = "基地编码")
private String baseId;
@Schema(description = "所属电站编码")
private String rstcds;
@Schema(description = "所属电站编码")
private String rstcd;
@Schema(description = "高程")
private BigDecimal dtmel;
@Schema(description = "标题")
private String titleName;
@Schema(description = "电站名称")
private String ennm;
@Schema(description = "站类名称")
private String sttpName;
@Schema(description = "站点排序")
private Integer siteStepSort;
@Schema(description = "站类编码")
private String sttpCode;
@Schema(description = "栖息地编码")
private String fhstcd;
@Schema(description = "栖息地名称")
private String fhstnm;
@Schema(description = "基地流域编码")
private String hbrvcd;
@Schema(description = "基地流域名称")
private String hbrvcdName;
@Schema(description = "播放地址")
private String url;
@Schema(description = "站址")
private String stlc;
@Schema(description = "AI是否启用")
private Integer aiEnabled;
@Schema(description = "AI外部站码")
private String aiExtCode;
@Schema(description = "AI外部站名")
private String aiExtName;
@Schema(description = "AI频率")
private String aiFrequency;
@Schema(description = "AI站类编码")
private String aiSttpCode;
@Schema(description = "AI站类名称")
private String aiSttpName;
}

View File

@ -2,6 +2,7 @@ package com.yfd.platform.qgc_env.vd.service;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.common.DataSourceResult;
import com.yfd.platform.qgc_env.vd.entity.vo.VdAiPointVo;
import com.yfd.platform.qgc_env.vd.entity.vo.VdTreeNodeVo;
import com.yfd.platform.qgc_env.vd.entity.vo.VdRunDataVo;
import com.yfd.platform.qgc_env.vd.entity.vo.VdVmsstbprptVo;
@ -20,5 +21,7 @@ public interface VdMonitorService {
DataSourceResult<?> getVdPointKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<VdAiPointVo> getVdAiPointKendoListCust(DataSourceRequest dataSourceRequest);
DataSourceResult<VdRunDataVo> getRunDataKendoListCust(DataSourceRequest dataSourceRequest);
}

View File

@ -9,6 +9,7 @@ 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.vd.entity.vo.VdAiPointVo;
import com.yfd.platform.qgc_env.vd.entity.vo.VdPointVo;
import com.yfd.platform.qgc_env.vd.entity.vo.VdRunDataVo;
import com.yfd.platform.qgc_env.vd.entity.vo.VdTreeNodeVo;
@ -229,6 +230,72 @@ public class VdMonitorServiceImpl implements VdMonitorService {
return queryVdPointDetailList(dataSourceRequest, loadOptions);
}
@Override
public DataSourceResult<VdAiPointVo> getVdAiPointKendoListCust(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
Page<?> page = loadOptions == null ? null : QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
String baseId = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "baseId");
String rstcd = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "rstcd");
String hbrvcd = QgcQueryWrapperUtil.getFilterFieldValue(loadOptions, "hbrvcd");
StringBuilder sql = new StringBuilder();
sql.append("SELECT ")
.append("t.stcd AS stcd, ")
.append("t.stnm AS stnm, ")
.append("t.anchoPointState AS anchoPointState, ")
.append("t.sttpMap AS sttpMap, ")
.append("t.sttp AS sttp, ")
.append("t.lgtd AS lgtd, ")
.append("t.lttd AS lttd, ")
.append("t.rvcd AS rvcd, ")
.append("t.addvcd AS addvcd, ")
.append("t.rvnm AS rvnm, ")
.append("t.baseId AS baseId, ")
.append("t.rstcds AS rstcds, ")
.append("t.rstcd AS rstcd, ")
.append("t.dtmel AS dtmel, ")
.append("t.titleName AS titleName, ")
.append("t.ennm AS ennm, ")
.append("t.sttpName AS sttpName, ")
.append("t.siteStepSort AS siteStepSort, ")
.append("t.sttpCode AS sttpCode, ")
.append("t.fhstcd AS fhstcd, ")
.append("t.fhstnm AS fhstnm, ")
.append("t.hbrvcd AS hbrvcd, ")
.append("t.hbrvcdName AS hbrvcdName, ")
.append("t.url AS url, ")
.append("t.stlc AS stlc, ")
.append("t.aiEnabled AS aiEnabled, ")
.append("t.aiExtCode AS aiExtCode, ")
.append("t.aiExtName AS aiExtName, ")
.append("t.aiFrequency AS aiFrequency, ")
.append("t.aiSttpCode AS aiSttpCode, ")
.append("t.aiSttpName AS aiSttpName ")
.append("FROM (")
.append(buildVdAiPointCoreSql())
.append(") t WHERE 1 = 1 ");
Map<String, Object> paramMap = new HashMap<>();
if (StrUtil.isNotBlank(baseId)) {
paramMap.put("vdAiBaseId", baseId);
sql.append(" AND t.baseId = #{map.vdAiBaseId} ");
}
if (StrUtil.isNotBlank(hbrvcd)) {
paramMap.put("vdAiHbrvcd", hbrvcd);
sql.append(" AND t.hbrvcd = #{map.vdAiHbrvcd} ");
}
appendVdAiRstcdCondition(sql, paramMap, parseArrayLikeValues(rstcd));
sql.append(" ORDER BY t.siteStepSort ASC NULLS LAST, t.stcd ASC");
List<VdAiPointVo> list = microservicDynamicSQLMapper.pageAllListWithResultType(
page, sql.toString(), paramMap, VdAiPointVo.class);
DataSourceResult<VdAiPointVo> result = new DataSourceResult<>();
result.setData(list);
result.setTotal(page != null ? page.getTotal() : list.size());
result.setAggregates(new HashMap<>());
return result;
}
@Override
public DataSourceResult<VdRunDataVo> getRunDataKendoListCust(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
@ -703,6 +770,68 @@ public class VdMonitorServiceImpl implements VdMonitorService {
" AND NVL(sttp.IS_DELETED, 0) = 0 AND NVL(sttp.ENABLE, 1) = 1 ";
}
private String buildVdAiPointCoreSql() {
return "SELECT " +
"src.STCD AS stcd, " +
"src.STNM AS stnm, " +
"'aispjk' AS anchoPointState, " +
"'AIVD' AS sttpMap, " +
"src.STTP AS sttp, " +
"src.LGTD AS lgtd, " +
"src.LTTD AS lttd, " +
"NVL(eng.RVCD, src.RVCD) AS rvcd, " +
"NVL(eng.ADDVCD, src.ADDVCD) AS addvcd, " +
"rv.RVNM AS rvnm, " +
"NVL(eng.BASE_ID, src.BASE_ID) AS baseId, " +
"src.RSTCD AS rstcds, " +
"src.RSTCD AS rstcd, " +
"src.ELEV AS dtmel, " +
"src.STNM AS titleName, " +
"eng.ENNM AS ennm, " +
"vdSttp.STTP_NAME AS sttpName, " +
"NVL(siteSort.SORT, 999999) AS siteStepSort, " +
"'AIVD' AS sttpCode, " +
"src.FHSTCD AS fhstcd, " +
"fh.STNM AS fhstnm, " +
"NVL(eng.HBRVCD, src.HBRVCD) AS hbrvcd, " +
"hbrv.HBRVNM AS hbrvcdName, " +
"src.URL AS url, " +
"src.STLC AS stlc, " +
"src.AI_ENABLED AS aiEnabled, " +
"src.AI_EXT_CODE AS aiExtCode, " +
"src.AI_EXT_NAME AS aiExtName, " +
"src.AI_FREQUENCY AS aiFrequency, " +
"(SELECT LISTAGG(ai.STTP, ',') WITHIN GROUP (ORDER BY ai.STTP) " +
" FROM SD_AIMONITOR_B_H ai " +
" WHERE NVL(ai.IS_DELETED, 0) = 0 " +
" AND ai.STTP LIKE 'AI_%' " +
" AND INSTR(',' || src.AI_EXT_CODE || ',', ',' || ai.STCD || ',') > 0) AS aiSttpCode, " +
"(SELECT LISTAGG(sttp.STTP_NAME, ',') WITHIN GROUP (ORDER BY ai.STTP) " +
" FROM SD_AIMONITOR_B_H ai " +
" LEFT JOIN SD_STTP_B sttp ON sttp.STTP_CODE = ai.STTP " +
" AND NVL(sttp.IS_DELETED, 0) = 0 AND NVL(sttp.ENABLE, 1) = 1 " +
" WHERE NVL(ai.IS_DELETED, 0) = 0 " +
" AND ai.STTP LIKE 'AI_%' " +
" AND INSTR(',' || src.AI_EXT_CODE || ',', ',' || ai.STCD || ',') > 0) AS aiSttpName " +
"FROM SD_VDINFO_B src " +
"LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = src.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 " +
"LEFT JOIN SD_FHBT_B_H fh ON fh.STCD = src.FHSTCD AND NVL(fh.IS_DELETED, 0) = 0 " +
"LEFT JOIN SD_RVCD_DIC rv ON rv.RVCD = NVL(eng.RVCD, src.RVCD) " +
"LEFT JOIN SD_HBRV_DIC hbrv ON hbrv.HBRVCD = NVL(eng.HBRVCD, src.HBRVCD) " +
" AND hbrv.BASEID = NVL(eng.BASE_ID, src.BASE_ID) " +
" AND NVL(hbrv.IS_DELETED, 0) = 0 AND NVL(hbrv.ENABLED, 1) = 1 " +
"LEFT JOIN SD_STTP_B vdSttp ON vdSttp.STTP_CODE = src.STTP " +
" AND NVL(vdSttp.IS_DELETED, 0) = 0 AND NVL(vdSttp.ENABLE, 1) = 1 " +
"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 = NVL(eng.HBRVCD, src.HBRVCD) AND siteSort.STCD = src.STCD " +
"WHERE src.STTP LIKE 'VD%' " +
"AND src.AI_EXT_CODE IS NOT NULL " +
"AND src.LGTD IS NOT NULL " +
"AND src.LTTD IS NOT NULL ";
}
private String buildRunDataCoreSql() {
return "SELECT " +
"run.ID AS id, " +
@ -1183,6 +1312,44 @@ public class VdMonitorServiceImpl implements VdMonitorService {
return values;
}
private List<String> parseArrayLikeValues(String value) {
List<String> values = new ArrayList<>();
if (StrUtil.isBlank(value)) {
return values;
}
String trimmed = value.trim();
if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
trimmed = trimmed.substring(1, trimmed.length() - 1);
}
if (StrUtil.isBlank(trimmed)) {
return values;
}
for (String item : trimmed.split(",")) {
String normalized = StrUtil.trim(item.replace("\"", "").replace("'", ""));
if (StrUtil.isNotBlank(normalized)) {
values.add(normalized);
}
}
return values;
}
private void appendVdAiRstcdCondition(StringBuilder sql,
Map<String, Object> paramMap,
List<String> rstcdList) {
if (CollUtil.isEmpty(rstcdList)) {
return;
}
List<String> placeholders = new ArrayList<>();
for (int i = 0; i < rstcdList.size(); i++) {
String key = "vdAiRstcd" + i;
paramMap.put(key, rstcdList.get(i));
placeholders.add("#{map." + key + "}");
}
sql.append(" AND t.rstcds IN (")
.append(String.join(", ", placeholders))
.append(") ");
}
private void appendNormalizedValues(List<Object> values, Object value) {
if (value == null) {
return;

View File

@ -9,10 +9,12 @@ 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.domain.vo.DataScopeApplyResult;
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_base.service.IDataScopeFilterService;
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;
@ -45,6 +47,9 @@ import org.apache.commons.collections4.CollectionUtils;
@Service
public class EnvWqDataServiceImpl implements EnvWqDataService {
@Resource
private IDataScopeFilterService dataScopeFilterService;
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";
@ -4610,6 +4615,13 @@ public class EnvWqDataServiceImpl implements EnvWqDataService {
.append("AND NVL(t.USFL, 1) = 1 ");
Map<String, Object> paramMap = new HashMap<>();
DataScopeApplyResult scopeApplyResult = dataScopeFilterService.appendCurrentUserStationScope(sql, paramMap, "t.RSTCD");
if (scopeApplyResult.isEmptyResult()) {
dataSourceResult.setData(new ArrayList<>());
dataSourceResult.setTotal(0L);
return dataSourceResult;
}
String filterSql = buildWqPointFilterCondition(dataSourceRequest.getFilter(), paramMap, new int[]{0});
if (StrUtil.isNotBlank(filterSql)) {
sql.append(" AND ").append(filterSql);

View File

@ -5,6 +5,8 @@ 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.vo.DataScopeApplyResult;
import com.yfd.platform.qgc_base.service.IDataScopeFilterService;
import com.yfd.platform.qgc_env.wt.entity.vo.DfltkwFacilityCountVo;
import com.yfd.platform.qgc_env.wt.entity.vo.FishSpawnVo;
import com.yfd.platform.qgc_env.wt.entity.vo.RstcdTreeInfoVo;
@ -58,6 +60,9 @@ public class SdWtMonitorServiceImpl implements SdWtMonitorService {
@Resource
private JdbcTemplate jdbcTemplate;
@Resource
private IDataScopeFilterService dataScopeFilterService;
@Override
public DataSourceResult getEvnmAutoMonitorList(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
@ -2886,6 +2891,14 @@ public class SdWtMonitorServiceImpl implements SdWtMonitorService {
}
Map<String, Object> paramMap = new HashMap<>();
DataScopeApplyResult scopeApplyResult = dataScopeFilterService.appendCurrentUserStationScope(sql, paramMap, "t.RSTCD");
if (scopeApplyResult.isEmptyResult()) {
dataSourceResult.setData(new ArrayList<>());
dataSourceResult.setTotal(0L);
return dataSourceResult;
}
// Map<String, Object> paramMap = new HashMap<>();
if (StrUtil.isNotEmpty(bldsttCcode)) {
paramMap.put("bldsttCcode", bldsttCcode);
}

View File

@ -150,6 +150,12 @@ public class WeFishController {
return ResponseResult.successData(weFishService.getQgcWeFishPoint(dataSourceRequest));
}
@PostMapping("/we/point/qgc/GetKendoListCust")
@Operation(summary = "环保部-水生生态调查-地图锚点")
public ResponseResult getQgcWePoint(@RequestBody DataSourceRequest dataSourceRequest) {
return ResponseResult.successData(weFishService.getQgcWePoint(dataSourceRequest));
}
@PostMapping("/te/tet/spec/GetKendoListCust")
@Operation(summary = "重点陆生动物二级页面")
public ResponseResult getTeSpecialAnimalList(@RequestBody DataSourceRequest dataSourceRequest) {

View File

@ -0,0 +1,18 @@
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 WePointFishStatVo {
@Schema(description = "断面编码")
private String stcd;
@Schema(description = "鱼类名称")
private String fishName;
@Schema(description = "数量")
private Integer count;
}

View File

@ -0,0 +1,72 @@
package com.yfd.platform.qgc_env.wte.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
@Schema(description = "环保部-水生生态调查-锚点")
public class WePointQgcVo {
@Schema(description = "站点编码")
private String stcd;
@Schema(description = "断面名称")
private String stnm;
@Schema(description = "经度")
private BigDecimal lgtd;
@Schema(description = "纬度")
private BigDecimal lttd;
@Schema(description = "高程")
private BigDecimal dtmel;
@Schema(description = "关联电站编码冗余")
private String rstcds;
@Schema(description = "电站名称")
private String ennm;
@Schema(description = "最新调查时间")
private String tm;
@Schema(description = "描点状态")
private String anchoPointState;
@Schema(description = "锚点类型")
private String sttpMap;
@Schema(description = "站点类型")
private String sttp;
@Schema(description = "设施类型")
private String sttpCode;
@Schema(description = "弹框标题")
private String titleName;
@Schema(description = "流域编码")
private String rvcd;
@Schema(description = "行政编码")
private String addvcd;
@Schema(description = "基地编码")
private String baseId;
@Schema(description = "关联电站编码")
private String rstcd;
@Schema(description = "沿程排序")
private Integer siteStepSort;
@Schema(description = "地图避让")
private Integer distance;
@Schema(description = "调查鱼类列表")
private List<WePointFishStatVo> fishList;
}

View File

@ -53,6 +53,8 @@ public interface WeFishService {
DataSourceResult<WeFishPointQgcVo> getQgcWeFishPoint(DataSourceRequest dataSourceRequest);
DataSourceResult<WePointQgcVo> getQgcWePoint(DataSourceRequest dataSourceRequest);
DataSourceResult<WeTeSpecialAnimalVo> getTeSpecialAnimalList(DataSourceRequest dataSourceRequest);
List<WeDefaultDataVo> getWeDefaultData(String stcd);

View File

@ -10,6 +10,7 @@ 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.wt.utils.SiteAvoidanceUtils;
import com.yfd.platform.qgc_env.wte.entity.vo.*;
import com.yfd.platform.qgc_env.wte.service.WeFishService;
import com.yfd.platform.utils.KendoUtil;
@ -1065,6 +1066,170 @@ public class WeFishServiceImpl implements WeFishService {
return result;
}
@Override
public DataSourceResult<WePointQgcVo> getQgcWePoint(DataSourceRequest dataSourceRequest) {
DataSourceResult<WePointQgcVo> result = new DataSourceResult<>();
result.setAggregates(new HashMap<>());
if (dataSourceRequest == null) {
result.setData(new ArrayList<>());
result.setTotal(0L);
return result;
}
DataSourceLoadOptionsBase loadOptions = dataSourceRequest.toDevRequest();
String stcd = resolveWeFishStringFilterValue(dataSourceRequest, loadOptions, "stcd");
String startTime = resolveWeFishStringFilterValue(dataSourceRequest, loadOptions, "startTime");
String endTime = resolveWeFishStringFilterValue(dataSourceRequest, loadOptions, "endTime");
Map<String, Object> paramMap = new HashMap<>();
StringBuilder sql = new StringBuilder();
sql.append("SELECT ")
.append("section.STCD AS stcd, ")
.append("section.STNM AS stnm, ")
.append("section.LGTD AS lgtd, ")
.append("section.LTTD AS lttd, ")
.append("section.ELEV AS dtmel, ")
.append("section.RSTCD AS rstcds, ")
.append("eng.ENNM AS ennm, ")
.append("TO_CHAR(latest.TM, 'yyyy-mm-dd hh24:mi:ss') AS tm, ")
.append("'WE' AS anchoPointState, ")
.append("'WE' AS sttpMap, ")
.append("'WE' AS sttp, ")
.append("'WE' AS sttpCode, ")
.append("section.STNM AS titleName, ")
.append("section.RVCD AS rvcd, ")
.append("section.ADDVCD AS addvcd, ")
.append("section.BASE_ID AS baseId, ")
.append("section.RSTCD AS rstcd, ")
.append("siteSort.SORT AS siteStepSort ")
.append("FROM SD_WE_B_H section ")
.append("LEFT JOIN SD_ENGINFO_B_H eng ON eng.STCD = section.RSTCD AND NVL(eng.IS_DELETED, 0) = 0 ")
.append("LEFT JOIN ( ")
.append(" SELECT STCD, MAX(TM) AS TM ")
.append(" FROM SD_WE_R ")
.append(" WHERE NVL(IS_DELETED, 0) = 0 AND STATUS = 1 ")
.append(" GROUP BY STCD ")
.append(") latest ON latest.STCD = section.STCD ")
.append("LEFT JOIN MS_ALONG_B along ON along.RVCD = section.HBRVCD ")
.append(" 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 ")
.append(" AND NVL(cfg.IS_DELETED, 0) = 0 ")
.append(" AND cfg.CODE = 'common' ")
.append(") siteSort ON siteSort.RVCD = section.HBRVCD AND siteSort.STCD = section.STCD ")
.append("WHERE NVL(section.USFL, 1) = 1 ");
String filterSql = buildWePointFilterCondition(dataSourceRequest.getFilter(), paramMap, new int[]{0});
if (StrUtil.isNotBlank(filterSql)) {
sql.append("AND ").append(filterSql).append(" ");
}
sql.append(buildWePointOrderBySql(dataSourceRequest.getSort()));
Page<?> page = loadOptions == null ? null
: QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
List<WePointQgcVo> list = microservicDynamicSQLMapper.pageAllListWithResultType(
page,
sql.toString(),
paramMap,
WePointQgcVo.class
);
if (CollUtil.isEmpty(list)) {
result.setData(list);
result.setTotal(page != null ? page.getTotal() : 0L);
return result;
}
Map<String, List<WePointFishStatVo>> fishMap = queryWePointFishMap(
list.stream().map(WePointQgcVo::getStcd).filter(StrUtil::isNotBlank).distinct().toList(),
stcd,
startTime,
endTime
);
for (WePointQgcVo vo : list) {
vo.setFishList(fishMap.get(vo.getStcd()));
}
SiteAvoidanceUtils.calcSiteMapLev(list,
WePointQgcVo::getStcd,
WePointQgcVo::getLgtd,
WePointQgcVo::getLttd,
WePointQgcVo::getAnchoPointState,
WePointQgcVo::setDistance);
result.setData(list);
result.setTotal(page != null ? page.getTotal() : list.size());
return result;
}
private Map<String, List<WePointFishStatVo>> queryWePointFishMap(List<String> stcdList,
String stcd,
String startTime,
String endTime) {
Map<String, List<WePointFishStatVo>> result = new LinkedHashMap<>();
if (CollUtil.isEmpty(stcdList)) {
return result;
}
Map<String, Object> paramMap = new HashMap<>();
StringBuilder sql = new StringBuilder();
sql.append("SELECT ")
.append("we.STCD AS stcd, ")
.append("dict.NAME AS fishName, ")
.append("SUM(fish.FCNT) AS count ")
.append("FROM SD_WE_R we ")
.append("INNER JOIN SD_WEFISH_R fish ON fish.WER_ID = we.ID ")
.append(" AND NVL(fish.IS_DELETED, 0) = 0 ")
.append("INNER JOIN SD_WE_B_H section ON section.STCD = we.STCD ")
.append(" AND NVL(section.USFL, 1) = 1 ")
.append("INNER JOIN ( ")
.append(" SELECT STCD, MAX(TM) AS TM ")
.append(" FROM SD_WE_R ")
.append(" WHERE NVL(IS_DELETED, 0) = 0 AND STATUS = 1 ")
.append(" GROUP BY STCD ")
.append(") latest ON latest.STCD = we.STCD AND latest.TM = we.TM ")
.append("LEFT JOIN ( ")
.append(" SELECT DISTINCT rel.FISH_ID, rel.RVCD, dic.NAME ")
.append(" FROM SD_FISHDICTORY_RLTN_B rel ")
.append(" LEFT JOIN SD_FISHDICTORY_B dic ON rel.ZY_FISH_ID = dic.ID ")
.append(" WHERE NVL(rel.IS_DELETED, 0) = 0 ")
.append(" AND NVL(dic.IS_DELETED, 0) = 0 ")
.append(" AND (rel.FISH_ID <> rel.ZY_FISH_ID OR rel.RVCD = 'ZY') ")
.append(") dict ON fish.FTP = dict.FISH_ID AND (section.HBRVCD = dict.RVCD OR dict.RVCD = 'ZY') ")
.append("WHERE fish.FCNT IS NOT NULL ")
.append("AND NVL(we.IS_DELETED, 0) = 0 ")
.append("AND NVL(we.STATUS, 1) = 1 ");
appendWePointInCondition(sql, paramMap, "we.STCD", stcdList, "stcdList");
if (StrUtil.isNotBlank(stcd)) {
paramMap.put("filterStcd", stcd);
sql.append("AND we.STCD = #{map.filterStcd} ");
}
if (StrUtil.isNotBlank(startTime) && StrUtil.isNotBlank(endTime)) {
paramMap.put("startTime", startTime);
paramMap.put("endTime", endTime);
sql.append("AND we.TM BETWEEN TO_DATE(#{map.startTime}, 'yyyy-mm-dd hh24:mi:ss') ")
.append("AND TO_DATE(#{map.endTime}, 'yyyy-mm-dd hh24:mi:ss') ");
}
sql.append("GROUP BY we.STCD, dict.NAME ORDER BY SUM(fish.FCNT)");
List<WePointFishStatVo> rows = microservicDynamicSQLMapper.getAllListWithResultType(
sql.toString(),
paramMap,
WePointFishStatVo.class
);
for (WePointFishStatVo row : rows) {
if (row == null || StrUtil.isBlank(row.getStcd())) {
continue;
}
result.computeIfAbsent(row.getStcd(), key -> new ArrayList<>()).add(row);
}
return result;
}
@Override
public DataSourceResult<WeTeSpecialAnimalVo> getTeSpecialAnimalList(DataSourceRequest dataSourceRequest) {
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
@ -2489,6 +2654,96 @@ public class WeFishServiceImpl implements WeFishService {
return sql.toString();
}
private String buildWePointFilterCondition(DataSourceRequest.FilterDescriptor filter,
Map<String, Object> paramMap,
int[] indexHolder) {
return QgcQueryWrapperUtil.buildFilterCondition(filter, paramMap, indexHolder, this::mapWePointColumn);
}
private String mapWePointColumn(String field) {
if (StrUtil.isBlank(field)) {
return null;
}
return switch (field) {
case "stcd" -> "section.STCD";
case "lgtd" -> "section.LGTD";
case "stnm", "titleName" -> "section.STNM";
case "ennm" -> "eng.ENNM";
case "rvcd" -> "section.RVCD";
case "addvcd" -> "section.ADDVCD";
case "baseId" -> "section.BASE_ID";
case "rstcd", "rstcds" -> "section.RSTCD";
case "tm" -> "latest.TM";
default -> null;
};
}
private String buildWePointOrderBySql(List<DataSourceRequest.SortDescriptor> sorts) {
if (CollUtil.isEmpty(sorts)) {
return " ORDER BY siteSort.SORT NULLS LAST";
}
List<String> orderByParts = new ArrayList<>();
for (DataSourceRequest.SortDescriptor sort : sorts) {
if (sort == null || StrUtil.isBlank(sort.getField())) {
continue;
}
String column = mapWePointSortColumn(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 siteSort.SORT NULLS LAST";
}
return " ORDER BY " + String.join(", ", orderByParts);
}
private String mapWePointSortColumn(String field) {
if (StrUtil.isBlank(field)) {
return null;
}
return switch (field) {
case "stcd" -> "section.STCD";
case "stnm", "titleName" -> "section.STNM";
case "ennm" -> "eng.ENNM";
case "tm" -> "latest.TM";
case "rvcd" -> "section.RVCD";
case "addvcd" -> "section.ADDVCD";
case "baseId" -> "section.BASE_ID";
case "siteStepSort" -> "siteSort.SORT";
default -> null;
};
}
private void appendWePointInCondition(StringBuilder sql,
Map<String, Object> paramMap,
String column,
List<String> values,
String paramPrefix) {
if (CollUtil.isEmpty(values) || StrUtil.isBlank(column)) {
return;
}
List<String> placeholders = new ArrayList<>();
int index = 0;
for (String value : values) {
if (StrUtil.isBlank(value)) {
continue;
}
String key = paramPrefix + "_" + index++;
paramMap.put(key, value);
placeholders.add("#{map." + key + "}");
}
if (CollUtil.isEmpty(placeholders)) {
return;
}
sql.append("AND ").append(column).append(" IN (")
.append(String.join(", ", placeholders))
.append(") ");
}
private String buildTeSpecialAnimalDetailSql() {
return "SELECT DISTINCT " +
"b.ID AS id, " +

View File

@ -2425,7 +2425,13 @@ public class ZqMonitorServiceImpl implements ZqMonitorService {
Map<String, Object> paramMap = new HashMap<>();
DataSourceLoadOptionsBase loadOptions = dataSourceRequest.toDevRequest();
String filterSql = buildMsstbprptFilterCondition(dataSourceRequest == null ? null : dataSourceRequest.getFilter(), paramMap, new int[]{0});
String filterSql = QgcQueryWrapperUtil.buildFilterCondition(
dataSourceRequest.getFilter(),
paramMap,
new int[]{0},
this::mapZqColumn
);
// String filterSql = buildMsstbprptFilterCondition(dataSourceRequest == null ? null : dataSourceRequest.getFilter(), paramMap, new int[]{0});
if (StrUtil.isNotBlank(filterSql)) {
sql.append(" AND ").append(filterSql).append(" ");
}
@ -2446,4 +2452,16 @@ public class ZqMonitorServiceImpl implements ZqMonitorService {
dataSourceResult.setTotal(page == null ? resultList.size() : page.getTotal());
return dataSourceResult;
}
private String mapZqColumn(String field) {
if (StrUtil.isBlank(field)) {
return null;
}
return switch (field.toLowerCase()) {
case "dtintype" -> "rb.DTIN_TYPE";
case "lgtd" -> "rb.LGTD";
default -> null;
};
}
}

View File

@ -41,6 +41,34 @@ public interface MsMapmoduleBMapper extends BaseMapper<MsMapmoduleB> {
List<MapLayerVo> getMapLayerTree(@Param("moduleId") String moduleId, @Param("sid") String sid,
@Param("templateId") String templateId);
/**
* 按模块ID集合查询地图图层树用于非管理员按用户菜单权限取图层
*/
@Select("<script>"
+ "SELECT DISTINCT BML.ID,BML.ANCHOR_PARAM_JSON, BML.PARENT_ID AS parentId, BML.TITLE, BML.CODE, BML.LABEL_LEVEL AS labelLevel, "
+ "BML.CHECKABLE, BML.TYPE, BML.Z_INDEX AS zIndex, BML.STTP_TYPE AS sttpType, BML.LAYERS, "
+ "BML.PARAMJSON AS paramJson, BML.URL, BML.URL_THD AS urlThd, BML.OPACITY, BML.SYSTEM_ID AS systemId, "
+ "BML.OPTIONS, BMM.MULTI_SELECT AS multiSelect, BMM.CAN_BE_CHECKED AS canBeChecked, "
+ "CASE WHEN BMM.CHECKED IS NULL THEN 0 ELSE BMM.CHECKED END AS checked, BML.ORDER_INDEX "
+ "FROM MS_MAPLAYER_B BML INNER JOIN MS_MAPMODULE_B BMM ON BML.ID = BMM.RES_ID "
+ "WHERE BMM.IS_DELETED = 0 AND BMM.RES_TYPE = 'layer' "
+ "<if test=\"moduleIds != null and moduleIds.size() > 0\">"
+ " AND BMM.MODULE_ID IN "
+ "<foreach collection=\"moduleIds\" item=\"moduleId\" open=\"(\" separator=\",\" close=\")\">"
+ "#{moduleId}"
+ "</foreach>"
+ "</if>"
+ "<if test=\"sid != null and sid != ''\"> AND BMM.SYSTEM_ID = #{sid}</if>"
+ "<choose>"
+ "<when test=\"templateId != null and templateId != ''\"> AND BMM.TEMPLATE_ID = #{templateId}</when>"
+ "<otherwise> AND (BMM.TEMPLATE_ID IS NULL OR BMM.TEMPLATE_ID = '00000000-0000-0000-0000-000000000000')</otherwise>"
+ "</choose>"
+ " AND BML.ENABLE = 1 AND BML.IS_DELETED = 0 AND (BML.TYPE NOT IN ('YXDT','DXDT','SLDT') OR BML.TYPE IS NULL) "
+ "ORDER BY BML.ORDER_INDEX"
+ "</script>")
List<MapLayerVo> getMapLayerTreeByModuleIds(@Param("moduleIds") List<String> moduleIds, @Param("sid") String sid,
@Param("templateId") String templateId);
/**
* 查询地图工具箱关联MS_MAPMODULE_B与MS_MAPTOOLBOX_B
*/

View File

@ -2,18 +2,23 @@ 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.MsMapmoduleB;
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.SysMenu;
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.SysMenuMapper;
import com.yfd.platform.system.mapper.SysUserMapper;
import com.yfd.platform.system.service.IAdminAuthService;
import com.yfd.platform.utils.SecurityUtils;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@ -43,6 +48,12 @@ public class MapLayerBizServiceImpl implements IMapLayerBizService {
@Resource
private MsMapmoduleBMapper msMapmoduleBMapper;
@Resource
private SysMenuMapper sysMenuMapper;
@Resource
private IAdminAuthService adminAuthService;
@Override
public List<MsMaplayerB> getMapLayerTree(MapLayerAo flag) {
// 1. 查询字典 "DTZJLX" 获取需要排除的图层类型
@ -173,12 +184,27 @@ public class MapLayerBizServiceImpl implements IMapLayerBizService {
@Override
public List<MapLayerVo> getMapLayerTree(String moduleId, String systemId, String templateId) {
// 通过 JOIN 查询 MS_MAPLAYER_B MS_MAPMODULE_B
List<MapLayerVo> allLayers = msMapmoduleBMapper.getMapLayerTree(moduleId, systemId, templateId);
if (allLayers == null || allLayers.isEmpty()) {
List<MapLayerVo> allLayers;
boolean currentManagedAdmin = adminAuthService.isCurrentManagedAdmin();
if (currentManagedAdmin) {
allLayers = msMapmoduleBMapper.getMapLayerTree(moduleId, systemId, templateId);
} else {
List<String> currentUserModuleIds = getCurrentUserModuleIds();
if (currentUserModuleIds.isEmpty()) {
return new ArrayList<>();
}
allLayers = msMapmoduleBMapper.getMapLayerTreeByModuleIds(currentUserModuleIds, systemId, templateId);
allLayers = supplementMissingParentLayers(allLayers);
allLayers = deduplicateMapLayers(allLayers);
}
if (allLayers.isEmpty()) {
return new ArrayList<>();
}
if (!currentManagedAdmin) {
Set<String> checkedLayerIds = getCurrentModuleCheckedLayerIds(moduleId, systemId, templateId);
resetCheckedStatus(allLayers, checkedLayerIds);
}
allLayers = sortMapLayerVos(allLayers);
// 取第一级
List<MapLayerVo> parents = allLayers.stream()
@ -211,4 +237,177 @@ public class MapLayerBizServiceImpl implements IMapLayerBizService {
}
}
}
private List<String> getCurrentUserModuleIds() {
String userId = SecurityUtils.getUserId();
if (StrUtil.isBlank(userId)) {
return new ArrayList<>();
}
List<SysMenu> userMenus = sysMenuMapper.selectMenuByUserId(userId, null);
if (userMenus == null || userMenus.isEmpty()) {
return new ArrayList<>();
}
return userMenus.stream()
.map(SysMenu::getId)
.filter(StrUtil::isNotBlank)
.distinct()
.collect(Collectors.toList());
}
private List<MapLayerVo> supplementMissingParentLayers(List<MapLayerVo> layers) {
if (layers == null || layers.isEmpty()) {
return new ArrayList<>();
}
List<MapLayerVo> result = new ArrayList<>(layers);
Set<String> existingIds = result.stream()
.map(MapLayerVo::getId)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toCollection(LinkedHashSet::new));
Set<String> pendingParentIds = result.stream()
.map(MapLayerVo::getParentId)
.filter(StrUtil::isNotBlank)
.filter(parentId -> !existingIds.contains(parentId))
.collect(Collectors.toCollection(LinkedHashSet::new));
while (!pendingParentIds.isEmpty()) {
LambdaQueryWrapper<MsMaplayerB> wrapper = new LambdaQueryWrapper<>();
wrapper.in(MsMaplayerB::getId, pendingParentIds)
.eq(MsMaplayerB::getIsDeleted, 0)
.eq(MsMaplayerB::getEnable, 1)
.and(w -> w.notIn(MsMaplayerB::getType, "YXDT", "DXDT", "SLDT").or().isNull(MsMaplayerB::getType))
.orderByAsc(MsMaplayerB::getOrderIndex);
List<MsMaplayerB> parentLayers = msMaplayerBMapper.selectList(wrapper);
if (parentLayers == null || parentLayers.isEmpty()) {
break;
}
Set<String> nextParentIds = new LinkedHashSet<>();
for (MsMaplayerB parentLayer : parentLayers) {
if (parentLayer == null || StrUtil.isBlank(parentLayer.getId()) || existingIds.contains(parentLayer.getId())) {
continue;
}
result.add(toMapLayerVo(parentLayer));
existingIds.add(parentLayer.getId());
if (StrUtil.isNotBlank(parentLayer.getParentId()) && !existingIds.contains(parentLayer.getParentId())) {
nextParentIds.add(parentLayer.getParentId());
}
}
pendingParentIds = nextParentIds;
}
return result;
}
private List<MapLayerVo> sortMapLayerVos(List<MapLayerVo> layers) {
return layers.stream()
.sorted(Comparator
.comparingInt((MapLayerVo item) -> parseOrderIndex(item.getOrderIndex()))
.thenComparing(item -> StrUtil.nullToDefault(item.getId(), "")))
.collect(Collectors.toList());
}
private int parseOrderIndex(String orderIndex) {
if (StrUtil.isBlank(orderIndex)) {
return Integer.MAX_VALUE;
}
try {
return Integer.parseInt(orderIndex);
} catch (NumberFormatException ex) {
return Integer.MAX_VALUE;
}
}
private MapLayerVo toMapLayerVo(MsMaplayerB layer) {
MapLayerVo vo = new MapLayerVo();
vo.setId(layer.getId());
vo.setParentId(layer.getParentId());
vo.setTitle(layer.getTitle());
vo.setCode(layer.getCode());
vo.setLabelLevel(layer.getLabelLevel());
vo.setCheckable(layer.getCheckable());
vo.setType(layer.getType());
vo.setZIndex(layer.getZIndex());
vo.setSttpType(layer.getSttpType());
vo.setLayers(layer.getLayers());
vo.setUrl(layer.getUrl());
vo.setUrlThd(layer.getUrlThd());
vo.setOpacity(layer.getOpacity());
vo.setParamJson(layer.getParamJson());
vo.setAnchorParamJson(layer.getAnchorParamJson());
vo.setOptions(layer.getOptions());
vo.setOrderIndex(layer.getOrderIndex() == null ? null : String.valueOf(layer.getOrderIndex()));
vo.setChecked(0);
vo.setCanBeChecked(0);
vo.setMultiSelect(1);
return vo;
}
private List<MapLayerVo> deduplicateMapLayers(List<MapLayerVo> layers) {
Map<String, MapLayerVo> uniqueMap = new LinkedHashMap<>();
for (MapLayerVo layer : layers) {
if (layer == null || StrUtil.isBlank(layer.getId())) {
continue;
}
uniqueMap.putIfAbsent(layer.getId(), layer);
}
return new ArrayList<>(uniqueMap.values());
}
private Set<String> getCurrentModuleCheckedLayerIds(String moduleId, String systemId, String templateId) {
if (StrUtil.isBlank(moduleId)) {
return Collections.emptySet();
}
LambdaQueryWrapper<MsMapmoduleB> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(MsMapmoduleB::getModuleId, moduleId)
.eq(MsMapmoduleB::getResType, "layer")
.eq(MsMapmoduleB::getIsDeleted, 0)
.select(MsMapmoduleB::getResId);
if (StrUtil.isNotBlank(systemId)) {
wrapper.eq(MsMapmoduleB::getSystemId, systemId);
}
if (StrUtil.isNotBlank(templateId)) {
wrapper.eq(MsMapmoduleB::getTemplateId, templateId);
} else {
wrapper.and(w -> w.isNull(MsMapmoduleB::getTemplateId)
.or()
.eq(MsMapmoduleB::getTemplateId, "00000000-0000-0000-0000-000000000000"));
}
List<MsMapmoduleB> moduleLayers = msMapmoduleBMapper.selectList(wrapper);
if (moduleLayers == null || moduleLayers.isEmpty()) {
return Collections.emptySet();
}
Set<String> checkedIds = moduleLayers.stream()
.map(MsMapmoduleB::getResId)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toCollection(LinkedHashSet::new));
if (checkedIds.isEmpty()) {
return Collections.emptySet();
}
Set<String> pendingParentIds = new LinkedHashSet<>(checkedIds);
while (!pendingParentIds.isEmpty()) {
LambdaQueryWrapper<MsMaplayerB> wrapperParent = new LambdaQueryWrapper<>();
wrapperParent.in(MsMaplayerB::getId, pendingParentIds)
.eq(MsMaplayerB::getIsDeleted, 0)
.select(MsMaplayerB::getId, MsMaplayerB::getParentId);
List<MsMaplayerB> currentLayers = msMaplayerBMapper.selectList(wrapperParent);
if (currentLayers == null || currentLayers.isEmpty()) {
break;
}
Set<String> nextParentIds = new LinkedHashSet<>();
for (MsMaplayerB currentLayer : currentLayers) {
if (StrUtil.isNotBlank(currentLayer.getParentId()) && checkedIds.add(currentLayer.getParentId())) {
nextParentIds.add(currentLayer.getParentId());
}
}
pendingParentIds = nextParentIds;
}
return checkedIds;
}
private void resetCheckedStatus(List<MapLayerVo> layers, Set<String> checkedLayerIds) {
if (layers == null || layers.isEmpty()) {
return;
}
Set<String> normalizedCheckedIds = checkedLayerIds == null ? Collections.emptySet() : checkedLayerIds;
for (MapLayerVo layer : layers) {
layer.setChecked(normalizedCheckedIds.contains(layer.getId()) ? 1 : 0);
}
}
}

View File

@ -19,9 +19,12 @@ import com.yfd.platform.utils.SecurityUtils;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
@ -134,7 +137,8 @@ public class MapmoduleBServiceImpl extends ServiceImpl<MsMapmoduleBMapper, MsMap
// 1. GIS图层区
List<MapLayerVo> layer = mapLayerBizService.getMapLayerTree(
mapmoduleB.getModuleId(), mapmoduleB.getSystemId(), templateId);
mapmoduleB.getModuleId(), mapmoduleB.getSystemId(), templateId);;
mapmoduleVo.setMapLayerVos(layer);
// 2. 地图图例
@ -182,4 +186,23 @@ public class MapmoduleBServiceImpl extends ServiceImpl<MsMapmoduleBMapper, MsMap
}
return msMaptoolboxBList;
}
private boolean hasCurrentUserModulePermission(String moduleId) {
if (StrUtil.isBlank(moduleId) || StrUtil.equalsIgnoreCase(moduleId, "common")) {
return true;
}
String userId = SecurityUtils.getUserId();
if (StrUtil.isBlank(userId)) {
return false;
}
List<SysMenu> userMenus = sysMenuMapper.selectMenuByUserId(userId, null);
if (userMenus == null || userMenus.isEmpty()) {
return false;
}
Set<String> menuIds = userMenus.stream()
.map(SysMenu::getId)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toCollection(HashSet::new));
return menuIds.contains(moduleId);
}
}

View File

@ -0,0 +1,124 @@
package com.yfd.platform.system.controller;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.system.domain.PushConfig;
import com.yfd.platform.system.domain.PushConfigTargetRequest;
import com.yfd.platform.system.domain.PushHistory;
import com.yfd.platform.system.domain.PushHistoryDetail;
import com.yfd.platform.system.service.IPushConfigService;
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.GetMapping;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@RestController
@RequestMapping("/system/pushConfig")
@Tag(name = "推送配置")
public class PushConfigController {
@Resource
private IPushConfigService pushConfigService;
@Operation(summary = "查询推送配置列表")
@GetMapping("/getPushConfigList")
public ResponseResult getPushConfigList(Page<PushConfig> page,
String categoryName,
String messageType,
Integer targetType,
Integer status) {
return ResponseResult.successData(pushConfigService.getPushConfigPage(page, categoryName, messageType, targetType, status));
}
@Operation(summary = "根据ID查询推送配置")
@GetMapping("/getPushConfigById")
public ResponseResult getPushConfigById(@RequestParam String id) {
return ResponseResult.successData(pushConfigService.getById(id));
}
@Log(module = "推送配置", value = "新增推送配置")
@Operation(summary = "新增推送配置")
@PostMapping("/addPushConfig")
public ResponseResult addPushConfig(@RequestBody PushConfig pushConfig) {
return pushConfigService.addPushConfig(pushConfig) ? ResponseResult.success() : ResponseResult.error("新增失败");
}
@Log(module = "推送配置", value = "修改推送配置")
@Operation(summary = "修改推送配置")
@PostMapping("/updatePushConfig")
public ResponseResult updatePushConfig(@RequestBody PushConfig pushConfig) {
return pushConfigService.updatePushConfig(pushConfig) ? ResponseResult.success() : ResponseResult.error("修改失败");
}
@Log(module = "推送配置", value = "删除推送配置")
@Operation(summary = "删除推送配置")
@PostMapping("/deletePushConfig")
public ResponseResult deletePushConfig(@RequestParam String ids) {
return pushConfigService.deletePushConfig(ids) ? ResponseResult.success() : ResponseResult.error("删除失败");
}
@Log(module = "推送配置", value = "设置推送配置状态")
@Operation(summary = "设置推送配置状态")
@PostMapping("/setPushConfigStatus")
public ResponseResult setPushConfigStatus(@RequestParam String id, @RequestParam Integer status) {
return pushConfigService.setPushConfigStatus(id, status) ? ResponseResult.success() : ResponseResult.error("设置失败");
}
@Log(module = "推送配置", value = "设置短信推送开关")
@Operation(summary = "设置短信推送开关")
@PostMapping("/setPushConfigSmsSwitch")
public ResponseResult setPushConfigSmsSwitch(@RequestParam String id, @RequestParam Integer isSms) {
return pushConfigService.setPushConfigSmsSwitch(id, isSms) ? ResponseResult.success() : ResponseResult.error("设置失败");
}
@Log(module = "推送配置", value = "保存推送目标")
@Operation(summary = "保存推送目标")
@PostMapping("/savePushTargets")
public ResponseResult savePushTargets(@RequestBody PushConfigTargetRequest request) {
return pushConfigService.savePushTargets(request) ? ResponseResult.success() : ResponseResult.error("保存失败");
}
@Operation(summary = "查询推送目标")
@GetMapping("/getPushTargets")
public ResponseResult getPushTargets(@RequestParam String configId) {
return ResponseResult.successData(pushConfigService.getPushTargets(configId));
}
@Log(module = "推送配置", value = "立即执行推送配置")
@Operation(summary = "立即执行推送配置")
@PostMapping("/execution")
public ResponseResult execution(@RequestParam String configId) {
return pushConfigService.executeNow(configId) ? ResponseResult.success() : ResponseResult.error("执行失败");
}
@Operation(summary = "查询推送历史主表")
@GetMapping("/getPushHistoryList")
public ResponseResult getPushHistoryList(Page<PushHistory> page,
String configId,
Integer status,
String messageTypeCode,
String startTime,
String endTime) {
Date start = StrUtil.isBlank(startTime) ? null : DateUtil.parse(startTime);
Date end = StrUtil.isBlank(endTime) ? null : DateUtil.parse(endTime);
return ResponseResult.successData(pushConfigService.getPushHistoryPage(page, configId, status, messageTypeCode, start, end));
}
@Operation(summary = "查询推送历史明细")
@GetMapping("/getPushHistoryDetailList")
public ResponseResult getPushHistoryDetailList(Page<PushHistoryDetail> page,
String historyId,
Integer status) {
return ResponseResult.successData(pushConfigService.getPushHistoryDetailPage(page, historyId, status));
}
}

View File

@ -78,7 +78,7 @@ public class SmsVerifyCodeController {
*/
@PostMapping("/sendCode")
@Operation(summary = "发送验证码")
public ResponseResult sendVerifyCode(@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
public ResponseResult sendVerifyCode(@RequestHeader(value = "Tenant_id", required = false) String tenantId,@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
String phone = smsVerifyCodeRequest.getPhone();
Integer type = smsVerifyCodeRequest.getType();
@ -91,21 +91,21 @@ public class SmsVerifyCodeController {
// 1. 注册验证码校验
if (type.equals(SmsVerifyCode.TYPE_REGISTER)) {
SysUser existUser = userService.getUserByPhone(phone);
SysUser existUser = userService.getUserByPhone(phone,tenantId);
if (existUser != null) {
return ResponseResult.error("该手机号已注册");
}
}
// 2. 找回密码验证码校验
else if (type.equals(SmsVerifyCode.TYPE_FIND_PASSWORD)) {
SysUser existUser = userService.getUserByPhone(phone);
SysUser existUser = userService.getUserByPhone(phone,tenantId);
if (existUser == null) {
return ResponseResult.error("该手机号未注册");
}
}
// 3. 登录验证码校验新增
else if (type.equals(SmsVerifyCode.TYPE_LOGIN)) {
SysUser existUser = userService.getUserByPhone(phone);
SysUser existUser = userService.getUserByPhone(phone,tenantId);
if (existUser == null) {
return ResponseResult.error("该手机号未注册,请先注册");
}
@ -118,7 +118,7 @@ public class SmsVerifyCodeController {
return ResponseResult.error("类型错误1-注册 2-找回密码 3-登录");
}
String code = smsVerifyCodeService.sendVerifyCode(phone, type);
String code = smsVerifyCodeService.sendVerifyCode(phone, type,tenantId);
if (code == null) {
return ResponseResult.error("验证码发送失败,请稍后重试");
}
@ -132,7 +132,7 @@ public class SmsVerifyCodeController {
*/
@PostMapping("/batchSendContent")
@Operation(summary = "批量发送短信")
public ResponseResult batchSendContent(@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
public ResponseResult batchSendContent(@RequestHeader(value = "Tenant_id", required = false) String tenantId,@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
List<String> phoneList = smsVerifyCodeRequest.getPhoneList();
if(phoneList==null){
@ -148,7 +148,7 @@ public class SmsVerifyCodeController {
*/
@PostMapping("/batchUrgeContent")
@Operation(summary = "催促")
public ResponseResult batchUrgeContent(@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
public ResponseResult batchUrgeContent(@RequestHeader(value = "Tenant_id", required = false) String tenantId,@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
List<String> userIds = smsVerifyCodeRequest.getUserIds();
String content = smsVerifyCodeRequest.getContent();
@ -161,7 +161,7 @@ public class SmsVerifyCodeController {
}
try {
int successCount = smsVerifyCodeService.urgeByUserIds(userIds, content);
int successCount = smsVerifyCodeService.urgeByUserIds(tenantId,userIds, content);
Map<String, Object> result = new HashMap<>();
// result.put("successCount", successCount);
result.put("totalCount", userIds.size());
@ -180,7 +180,7 @@ public class SmsVerifyCodeController {
@PostMapping("/register")
@Operation(summary = "注册用户")
@Transactional
public ResponseResult register(@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
public ResponseResult register(@RequestHeader(value = "Tenant_id", required = false) String tenantId,@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
String code = smsVerifyCodeRequest.getCode();
if (smsVerifyCodeRequest.getPhone() == null || smsVerifyCodeRequest.getPhone().isEmpty()) {
return ResponseResult.error("手机号不能为空");
@ -195,12 +195,12 @@ public class SmsVerifyCodeController {
return ResponseResult.error("验证码不能为空");
}
boolean verified = smsVerifyCodeService.verifyCode(smsVerifyCodeRequest.getPhone(), code, SmsVerifyCode.TYPE_REGISTER);
boolean verified = smsVerifyCodeService.verifyCode(smsVerifyCodeRequest.getPhone(), code, SmsVerifyCode.TYPE_REGISTER,tenantId);
if (!verified) {
return ResponseResult.error("验证码错误或已过期");
}
SysUser existUser = userService.getUserByPhone(smsVerifyCodeRequest.getPhone());
SysUser existUser = userService.getUserByPhone(smsVerifyCodeRequest.getPhone(),tenantId);
if (existUser != null) {
return ResponseResult.error("该手机号已注册");
}
@ -225,7 +225,7 @@ public class SmsVerifyCodeController {
user.setCompanyCode(smsVerifyCodeRequest.getCompanyCode());
boolean success = userService.save(user);
// 给注册用户加上默认权限
SysUser savedUser = userService.getUserByPhone(smsVerifyCodeRequest.getPhone());
SysUser savedUser = userService.getUserByPhone(smsVerifyCodeRequest.getPhone(),tenantId);
if (savedUser != null) {
this.addDefaultRole(savedUser.getId(), smsVerifyCodeRequest);
}
@ -338,7 +338,7 @@ public class SmsVerifyCodeController {
*/
@PostMapping("/resetPassword")
@Operation(summary = "找回密码")
public ResponseResult resetPassword(@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
public ResponseResult resetPassword(@RequestHeader(value = "Tenant_id", required = false) String tenantId,@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
String password = smsVerifyCodeRequest.getPassword();
String phone = smsVerifyCodeRequest.getPhone();
String code = smsVerifyCodeRequest.getCode();
@ -352,12 +352,12 @@ public class SmsVerifyCodeController {
return ResponseResult.error("新密码不能为空");
}
boolean verified = smsVerifyCodeService.verifyCode(phone, code, SmsVerifyCode.TYPE_FIND_PASSWORD);
boolean verified = smsVerifyCodeService.verifyCode(phone, code, SmsVerifyCode.TYPE_FIND_PASSWORD,tenantId);
if (!verified) {
return ResponseResult.error("验证码错误或已过期");
}
SysUser existUser = userService.getUserByPhone(phone);
SysUser existUser = userService.getUserByPhone(phone,tenantId);
if (existUser == null) {
return ResponseResult.error("该手机号未注册");
}
@ -382,11 +382,11 @@ public class SmsVerifyCodeController {
*/
@PostMapping("/verifyCode")
@Operation(summary = "验证验证码")
public ResponseResult verifyCode(@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
public ResponseResult verifyCode(@RequestHeader(value = "Tenant_id", required = false) String tenantId,@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
String phone = smsVerifyCodeRequest.getPhone();
String code = smsVerifyCodeRequest.getCode();
Integer type = smsVerifyCodeRequest.getType();
boolean valid = smsVerifyCodeService.verifyCode(phone, code, type);
boolean valid = smsVerifyCodeService.verifyCode(phone, code, type,tenantId);
if (valid) {
return ResponseResult.success();
} else {
@ -399,7 +399,7 @@ public class SmsVerifyCodeController {
*/
@PostMapping("/login")
@Operation(summary = "短信验证码登录")
public ResponseResult smsLogin(@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
public ResponseResult smsLogin(@RequestHeader(value = "Tenant_id", required = false) String tenantId,@RequestBody SmsVerifyCodeRequest smsVerifyCodeRequest) {
String phone = smsVerifyCodeRequest.getPhone();
String code = smsVerifyCodeRequest.getCode();
if (phone == null || phone.isEmpty()) {
@ -409,12 +409,12 @@ public class SmsVerifyCodeController {
return ResponseResult.error("验证码不能为空");
}
boolean verified = smsVerifyCodeService.verifyCode(phone, code, SmsVerifyCode.TYPE_LOGIN);
boolean verified = smsVerifyCodeService.verifyCode(phone, code, SmsVerifyCode.TYPE_LOGIN,tenantId);
if (!verified) {
return ResponseResult.error("验证码错误或已过期");
}
SysUser user = userService.getUserByPhone(phone);
SysUser user = userService.getUserByPhone(phone,tenantId);
if (user == null) {
return ResponseResult.error("该手机号未注册");
}

View File

@ -0,0 +1,59 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@TableName("PUSH_CONFIG")
public class PushConfig implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String categoryCode;
private String categoryName;
private String baseIdList;
private String baseNameList;
private String messageType;
private String cronExpression;
private Integer targetType;
private Integer isSms;
private Long pushCount;
private Long dailyPushCount;
private Date finishTime;
private Integer status;
private Date createdAt;
private Date updatedAt;
private String recordUser;
private String modifyUser;
private Date modifyTime;
private Integer isDeleted;
private String deleteUser;
private Date deleteTime;
}

View File

@ -0,0 +1,21 @@
package com.yfd.platform.system.domain;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class PushConfigTargetRequest implements Serializable {
private static final long serialVersionUID = 1L;
private String configId;
/**
* 0-用户1-角色
*/
private Integer type;
private List<String> userRoleIds;
}

View File

@ -0,0 +1,23 @@
package com.yfd.platform.system.domain;
import lombok.Data;
import java.io.Serializable;
@Data
public class PushConfigTargetVo implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String configId;
private Integer type;
private String userRoleId;
private String targetName;
private String targetPhone;
}

View File

@ -0,0 +1,39 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@TableName("PUSH_CONFIG_USER")
public class PushConfigUser implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String configId;
private Integer type;
private String userRoleId;
private Date createdAt;
private String recordUser;
private String modifyUser;
private Date modifyTime;
private Integer isDeleted;
private String deleteUser;
private Date deleteTime;
}

View File

@ -0,0 +1,63 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@TableName("PUSH_HISTORY")
public class PushHistory implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String configId;
private Date planTime;
private String messageTypeCode;
private String messageTypeName;
private String title;
private String content;
private Long pushedCount;
private Long successCount;
private Long failCount;
private Long pendingCount;
private String sendChannel;
private Integer status;
private String source;
private String relation;
private Date createdAt;
private Date updatedAt;
private String recordUser;
private String modifyUser;
private Date modifyTime;
private Integer isDeleted;
private String deleteUser;
private Date deleteTime;
}

View File

@ -0,0 +1,47 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@TableName("PUSH_HISTORY_DETAIL")
public class PushHistoryDetail implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String historyId;
private String targetName;
private String targetPhone;
private Integer status;
private String sendChannel;
private Date sendTime;
private String errorMsg;
private Date createdAt;
private String recordUser;
private String modifyUser;
private Date modifyTime;
private Integer isDeleted;
private String deleteUser;
private Date deleteTime;
}

View File

@ -0,0 +1,17 @@
package com.yfd.platform.system.domain;
import lombok.Data;
import java.io.Serializable;
@Data
public class PushTargetUserVo implements Serializable {
private static final long serialVersionUID = 1L;
private String userId;
private String targetName;
private String targetPhone;
}

View File

@ -1,6 +1,7 @@
package com.yfd.platform.system.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;
@ -115,4 +116,18 @@ public class QuartzJob implements Serializable {
@Schema(description = "备用3")
private String custom3;
/**
* 业务模块编码PUSH-推送配置SYNC-数据同步REPORT-报表生成
*/
@Schema(description = "业务模块编码")
@TableField("BIZ_MODULE")
private String bizModule;
/**
* 关联业务表的主键ID PUSH_CONFIG.ID
*/
@Schema(description = "关联业务主键ID")
@TableField("BIZ_ID")
private String bizId;
}

View File

@ -1,6 +1,7 @@
package com.yfd.platform.system.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;
@ -63,4 +64,10 @@ public class SmsVerifyCode implements Serializable {
* 0-未使用 1-已使用
*/
private Integer status;
/**
* 租户ID
*/
@TableField("TENANT_ID")
private String tenantId;
}

View File

@ -0,0 +1,7 @@
package com.yfd.platform.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.system.domain.PushConfig;
public interface PushConfigMapper extends BaseMapper<PushConfig> {
}

View File

@ -0,0 +1,18 @@
package com.yfd.platform.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.system.domain.PushConfigTargetVo;
import com.yfd.platform.system.domain.PushConfigUser;
import com.yfd.platform.system.domain.PushTargetUserVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface PushConfigUserMapper extends BaseMapper<PushConfigUser> {
List<PushTargetUserVo> selectAllActiveUsers();
List<PushTargetUserVo> selectTargetUsersByConfigId(@Param("configId") String configId);
List<PushConfigTargetVo> selectConfigTargets(@Param("configId") String configId);
}

View File

@ -0,0 +1,7 @@
package com.yfd.platform.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.system.domain.PushHistoryDetail;
public interface PushHistoryDetailMapper extends BaseMapper<PushHistoryDetail> {
}

View File

@ -0,0 +1,7 @@
package com.yfd.platform.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.system.domain.PushHistory;
public interface PushHistoryMapper extends BaseMapper<PushHistory> {
}

View File

@ -0,0 +1,50 @@
package com.yfd.platform.system.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.system.domain.PushConfig;
import com.yfd.platform.system.domain.PushConfigTargetRequest;
import com.yfd.platform.system.domain.PushConfigTargetVo;
import com.yfd.platform.system.domain.PushHistory;
import com.yfd.platform.system.domain.PushHistoryDetail;
import java.util.Date;
import java.util.List;
public interface IPushConfigService extends IService<PushConfig> {
Page<PushConfig> getPushConfigPage(Page<PushConfig> page,
String categoryName,
String messageType,
Integer targetType,
Integer status);
boolean addPushConfig(PushConfig pushConfig);
boolean updatePushConfig(PushConfig pushConfig);
boolean deletePushConfig(String ids);
boolean setPushConfigStatus(String id, Integer status);
boolean setPushConfigSmsSwitch(String id, Integer isSms);
boolean savePushTargets(PushConfigTargetRequest request);
List<PushConfigTargetVo> getPushTargets(String configId);
Page<PushHistory> getPushHistoryPage(Page<PushHistory> page,
String configId,
Integer status,
String messageTypeCode,
Date startTime,
Date endTime);
Page<PushHistoryDetail> getPushHistoryDetailPage(Page<PushHistoryDetail> page,
String historyId,
Integer status);
boolean executeNow(String configId);
void executePushConfig(String configId);
}

View File

@ -0,0 +1,7 @@
package com.yfd.platform.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.system.domain.PushConfigUser;
public interface IPushConfigUserService extends IService<PushConfigUser> {
}

View File

@ -0,0 +1,7 @@
package com.yfd.platform.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.system.domain.PushHistoryDetail;
public interface IPushHistoryDetailService extends IService<PushHistoryDetail> {
}

View File

@ -0,0 +1,7 @@
package com.yfd.platform.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.system.domain.PushHistory;
public interface IPushHistoryService extends IService<PushHistory> {
}

View File

@ -18,7 +18,7 @@ public interface ISmsVerifyCodeService extends IService<SmsVerifyCode> {
* @param type 1-注册 2-找回密码
* @return 验证码
*/
String sendVerifyCode(String phone, Integer type);
String sendVerifyCode(String phone, Integer type,String tenantId);
/**
* 验证验证码
@ -27,7 +27,7 @@ public interface ISmsVerifyCodeService extends IService<SmsVerifyCode> {
* @param type 类型 1-注册 2-找回密码
* @return 是否验证通过
*/
boolean verifyCode(String phone, String code, Integer type);
boolean verifyCode(String phone, String code, Integer type,String tenantId);
/**
* 标记验证码已使用
@ -50,5 +50,5 @@ public interface ISmsVerifyCodeService extends IService<SmsVerifyCode> {
boolean sendAuditNotify(String phone, String auditStatus, String reason);
void batchSendContent(List<String> phoneList, String content);
int urgeByUserIds(List<String> userIds, String content);
int urgeByUserIds(String tenantId,List<String> userIds, String content);
}

View File

@ -155,7 +155,7 @@ public interface IUserService extends IService<SysUser> {
*phone 手机号
* 返回值说明: 用户对象
************************************/
SysUser getUserByPhone(String phone);
SysUser getUserByPhone(String phone,String tenantId);
/***********************************
* 用途说明根据手机号修改密码

View File

@ -0,0 +1,16 @@
package com.yfd.platform.system.service.impl;
import com.yfd.platform.system.service.IPushConfigService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@Service("pushConfigQuartzExecutor")
public class PushConfigQuartzExecutor {
@Resource
private IPushConfigService pushConfigService;
public void execute(String configId) {
pushConfigService.executePushConfig(configId);
}
}

View File

@ -0,0 +1,511 @@
package com.yfd.platform.system.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.common.exception.BizException;
import com.yfd.platform.system.domain.PushConfig;
import com.yfd.platform.system.domain.PushConfigTargetRequest;
import com.yfd.platform.system.domain.PushConfigTargetVo;
import com.yfd.platform.system.domain.PushConfigUser;
import com.yfd.platform.system.domain.PushHistory;
import com.yfd.platform.system.domain.PushHistoryDetail;
import com.yfd.platform.system.domain.PushTargetUserVo;
import com.yfd.platform.system.domain.QuartzJob;
import com.yfd.platform.system.mapper.PushConfigMapper;
import com.yfd.platform.system.mapper.PushConfigUserMapper;
import com.yfd.platform.system.service.IPushConfigService;
import com.yfd.platform.system.service.IPushConfigUserService;
import com.yfd.platform.system.service.IPushHistoryDetailService;
import com.yfd.platform.system.service.IPushHistoryService;
import com.yfd.platform.system.service.IQuartzJobService;
import com.yfd.platform.utils.QuartzManage;
import com.yfd.platform.utils.SecurityUtils;
import jakarta.annotation.Resource;
import org.quartz.CronExpression;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@Service
public class PushConfigServiceImpl extends ServiceImpl<PushConfigMapper, PushConfig> implements IPushConfigService {
private static final String QUARTZ_BIZ_TYPE = "PUSH_CONFIG";
private static final String DEFAULT_SEND_CHANNEL = "SMS";
private static final String DEFAULT_SOURCE = "PUSH_CONFIG";
@Resource
private PushConfigUserMapper pushConfigUserMapper;
@Resource
private IPushConfigUserService pushConfigUserService;
@Resource
private IPushHistoryService pushHistoryService;
@Resource
private IPushHistoryDetailService pushHistoryDetailService;
@Resource
private IQuartzJobService quartzJobService;
@Resource
private QuartzManage quartzManage;
@Override
public Page<PushConfig> getPushConfigPage(Page<PushConfig> page,
String categoryName,
String messageType,
Integer targetType,
Integer status) {
LambdaQueryWrapper<PushConfig> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(PushConfig::getIsDeleted, 0)
.like(StrUtil.isNotBlank(categoryName), PushConfig::getCategoryName, categoryName)
.like(StrUtil.isNotBlank(messageType), PushConfig::getMessageType, messageType)
.eq(targetType != null, PushConfig::getTargetType, targetType)
.eq(status != null, PushConfig::getStatus, status)
.orderByDesc(PushConfig::getUpdatedAt, PushConfig::getCreatedAt);
return this.page(page, wrapper);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean addPushConfig(PushConfig pushConfig) {
validatePushConfig(pushConfig, false);
Date now = new Date();
pushConfig.setCreatedAt(now);
pushConfig.setUpdatedAt(now);
pushConfig.setModifyTime(now);
pushConfig.setRecordUser(currentUserIdOrSystem());
pushConfig.setModifyUser(currentUserIdOrSystem());
pushConfig.setIsDeleted(0);
pushConfig.setStatus(pushConfig.getStatus() == null ? 1 : pushConfig.getStatus());
pushConfig.setIsSms(pushConfig.getIsSms() == null ? 0 : pushConfig.getIsSms());
pushConfig.setPushCount(pushConfig.getPushCount() == null ? 0L : pushConfig.getPushCount());
pushConfig.setDailyPushCount(pushConfig.getDailyPushCount() == null ? 0L : pushConfig.getDailyPushCount());
return this.save(pushConfig);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updatePushConfig(PushConfig pushConfig) {
validatePushConfig(pushConfig, true);
PushConfig dbConfig = getAvailableConfig(pushConfig.getId());
dbConfig.setCategoryCode(pushConfig.getCategoryCode());
dbConfig.setCategoryName(pushConfig.getCategoryName());
dbConfig.setBaseIdList(pushConfig.getBaseIdList());
dbConfig.setBaseNameList(pushConfig.getBaseNameList());
dbConfig.setMessageType(pushConfig.getMessageType());
dbConfig.setCronExpression(pushConfig.getCronExpression());
dbConfig.setTargetType(pushConfig.getTargetType());
// dbConfig.setIsSms(pushConfig.getIsSms() == null ? 0 : pushConfig.getIsSms());
// dbConfig.setStatus(pushConfig.getStatus() == null ? dbConfig.getStatus() : pushConfig.getStatus());
dbConfig.setUpdatedAt(new Date());
dbConfig.setModifyTime(new Date());
dbConfig.setModifyUser(currentUserIdOrSystem());
boolean updated = this.updateById(dbConfig);
if (updated) {
if (Objects.equals(dbConfig.getTargetType(), 1)) {
softDeleteTargets(dbConfig.getId(), currentUserIdOrSystem(), new Date());
}
refreshQuartzJobIfExists(dbConfig);
}
return updated;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean deletePushConfig(String ids) {
if (StrUtil.isBlank(ids)) {
throw new BizException("参数不能为空.");
}
Date now = new Date();
String userId = currentUserIdOrSystem();
for (String id : ids.split(",")) {
String configId = StrUtil.trim(id);
if (StrUtil.isBlank(configId)) {
continue;
}
PushConfig config = getAvailableConfig(configId);
config.setIsDeleted(1);
config.setDeleteUser(userId);
config.setDeleteTime(now);
config.setModifyUser(userId);
config.setModifyTime(now);
config.setUpdatedAt(now);
this.updateById(config);
softDeleteTargets(configId, userId, now);
deleteQuartzJob(configId);
}
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean setPushConfigStatus(String id, Integer status) {
if (StrUtil.isBlank(id) || status == null) {
throw new BizException("参数不能为空.");
}
PushConfig config = getAvailableConfig(id);
config.setStatus(status);
if (Objects.equals(status, 0)) {
config.setIsSms(0);
}
config.setUpdatedAt(new Date());
config.setModifyTime(new Date());
config.setModifyUser(currentUserIdOrSystem());
boolean updated = this.updateById(config);
// if (updated) {
// syncQuartzJobBySwitch(config);
// }
return updated;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean setPushConfigSmsSwitch(String id, Integer isSms) {
if (StrUtil.isBlank(id) || isSms == null) {
throw new BizException("参数不能为空.");
}
if (!Objects.equals(isSms, 0) && !Objects.equals(isSms, 1)) {
throw new BizException("短信推送开关值不正确.");
}
PushConfig config = getAvailableConfig(id);
config.setIsSms(isSms);
config.setUpdatedAt(new Date());
config.setModifyTime(new Date());
config.setModifyUser(currentUserIdOrSystem());
boolean updated = this.updateById(config);
if (updated) {
syncQuartzJobBySwitch(config);
}
return updated;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean savePushTargets(PushConfigTargetRequest request) {
validatePushTargetRequest(request);
PushConfig config = getAvailableConfig(request.getConfigId());
validateTargetTypeMatch(config.getTargetType(), request.getType());
Date now = new Date();
String userId = currentUserIdOrSystem();
softDeleteTargets(config.getId(), userId, now);
if (request.getUserRoleIds() == null || request.getUserRoleIds().isEmpty()) {
return true;
}
List<PushConfigUser> list = new ArrayList<>();
for (String userRoleId : request.getUserRoleIds()) {
String targetId = StrUtil.trim(userRoleId);
if (StrUtil.isBlank(targetId)) {
continue;
}
PushConfigUser relation = new PushConfigUser();
relation.setConfigId(config.getId());
relation.setType(request.getType());
relation.setUserRoleId(targetId);
relation.setCreatedAt(now);
relation.setRecordUser(userId);
relation.setModifyUser(userId);
relation.setModifyTime(now);
relation.setIsDeleted(0);
list.add(relation);
}
return list.isEmpty() || pushConfigUserService.saveBatch(list);
}
@Override
public List<PushConfigTargetVo> getPushTargets(String configId) {
if (StrUtil.isBlank(configId)) {
return Collections.emptyList();
}
return pushConfigUserMapper.selectConfigTargets(configId);
}
@Override
public Page<PushHistory> getPushHistoryPage(Page<PushHistory> page,
String configId,
Integer status,
String messageTypeCode,
Date startTime,
Date endTime) {
LambdaQueryWrapper<PushHistory> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(PushHistory::getIsDeleted, 0)
.eq(StrUtil.isNotBlank(configId), PushHistory::getConfigId, configId)
.eq(status != null, PushHistory::getStatus, status)
.eq(StrUtil.isNotBlank(messageTypeCode), PushHistory::getMessageTypeCode, messageTypeCode)
.ge(startTime != null, PushHistory::getPlanTime, startTime)
.le(endTime != null, PushHistory::getPlanTime, endTime)
.orderByDesc(PushHistory::getPlanTime, PushHistory::getCreatedAt);
return pushHistoryService.page(page, wrapper);
}
@Override
public Page<PushHistoryDetail> getPushHistoryDetailPage(Page<PushHistoryDetail> page,
String historyId,
Integer status) {
LambdaQueryWrapper<PushHistoryDetail> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(PushHistoryDetail::getIsDeleted, 0)
.eq(StrUtil.isNotBlank(historyId), PushHistoryDetail::getHistoryId, historyId)
.eq(status != null, PushHistoryDetail::getStatus, status)
.orderByDesc(PushHistoryDetail::getCreatedAt, PushHistoryDetail::getSendTime);
return pushHistoryDetailService.page(page, wrapper);
}
@Override
public boolean executeNow(String configId) {
executePushConfig(configId);
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void executePushConfig(String configId) {
PushConfig config = getAvailableConfig(configId);
List<PushTargetUserVo> targets = resolveTargets(config);
Date now = new Date();
String operator = currentUserIdOrSystem();
PushHistory history = new PushHistory();
history.setConfigId(config.getId());
history.setPlanTime(now);
history.setMessageTypeCode(config.getCategoryCode());
history.setMessageTypeName(config.getCategoryName());
history.setTitle(buildDefaultTitle(config));
history.setContent(buildDefaultContent(config));
history.setPushedCount(0L);
history.setSuccessCount(0L);
history.setFailCount(0L);
history.setPendingCount((long) targets.size());
history.setSendChannel(DEFAULT_SEND_CHANNEL);
history.setStatus(0);
history.setSource(DEFAULT_SOURCE);
history.setRelation(StrUtil.blankToDefault(config.getBaseNameList(), config.getCategoryName()));
history.setCreatedAt(now);
history.setUpdatedAt(now);
history.setRecordUser(operator);
history.setModifyUser(operator);
history.setModifyTime(now);
history.setIsDeleted(0);
pushHistoryService.save(history);
if (!targets.isEmpty()) {
List<PushHistoryDetail> detailList = new ArrayList<>();
for (PushTargetUserVo target : targets) {
PushHistoryDetail detail = new PushHistoryDetail();
detail.setHistoryId(history.getId());
detail.setTargetName(target.getTargetName());
detail.setTargetPhone(target.getTargetPhone());
detail.setStatus(0);
detail.setSendChannel(DEFAULT_SEND_CHANNEL);
detail.setCreatedAt(now);
detail.setRecordUser(operator);
detail.setModifyUser(operator);
detail.setModifyTime(now);
detail.setIsDeleted(0);
detailList.add(detail);
}
pushHistoryDetailService.saveBatch(detailList);
}
}
private void validatePushConfig(PushConfig pushConfig, boolean requireId) {
if (pushConfig == null) {
throw new BizException("参数不能为空.");
}
if (requireId && StrUtil.isBlank(pushConfig.getId())) {
throw new BizException("配置ID不能为空.");
}
if (StrUtil.isBlank(pushConfig.getCategoryCode())) {
throw new BizException("消息类别编码不能为空.");
}
if (StrUtil.isBlank(pushConfig.getCategoryName())) {
throw new BizException("消息类别名称不能为空.");
}
if (StrUtil.isBlank(pushConfig.getMessageType())) {
throw new BizException("消息类型不能为空.");
}
if (StrUtil.isBlank(pushConfig.getCronExpression()) || !CronExpression.isValidExpression(pushConfig.getCronExpression())) {
throw new BizException("cron表达式格式错误.");
}
if (pushConfig.getTargetType() == null || (pushConfig.getTargetType() != 1 && pushConfig.getTargetType() != 2 && pushConfig.getTargetType() != 3)) {
throw new BizException("推送目标类型不正确.");
}
}
private void validatePushTargetRequest(PushConfigTargetRequest request) {
if (request == null) {
throw new BizException("参数不能为空.");
}
if (StrUtil.isBlank(request.getConfigId())) {
throw new BizException("推送配置ID不能为空.");
}
if (request.getType() == null || (request.getType() != 0 && request.getType() != 1)) {
throw new BizException("绑定类型不正确.");
}
}
private void validateTargetTypeMatch(Integer targetType, Integer relationType) {
if (targetType == null) {
return;
}
if (targetType == 1) {
throw new BizException("当前配置为所有人推送,无需绑定目标.");
}
if (targetType == 2 && !Objects.equals(relationType, 0)) {
throw new BizException("按人推送只能绑定用户.");
}
if (targetType == 3 && !Objects.equals(relationType, 1)) {
throw new BizException("按角色推送只能绑定角色.");
}
}
private PushConfig getAvailableConfig(String id) {
List<PushConfig> list = this.list(new LambdaQueryWrapper<PushConfig>()
.eq(PushConfig::getId, id)
.eq(PushConfig::getIsDeleted, 0));
PushConfig config = list.isEmpty() ? null : list.get(0);
if (config == null) {
throw new BizException("推送配置不存在.");
}
return config;
}
private void softDeleteTargets(String configId, String userId, Date now) {
LambdaUpdateWrapper<PushConfigUser> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(PushConfigUser::getConfigId, configId)
.eq(PushConfigUser::getIsDeleted, 0)
.set(PushConfigUser::getIsDeleted, 1)
.set(PushConfigUser::getDeleteUser, userId)
.set(PushConfigUser::getDeleteTime, now)
.set(PushConfigUser::getModifyUser, userId)
.set(PushConfigUser::getModifyTime, now);
pushConfigUserService.update(updateWrapper);
}
private void syncQuartzJob(PushConfig config) {
QuartzJob quartzJob = getPushQuartzJob(config.getId());
Date now = new Date();
if (quartzJob == null) {
quartzJob = new QuartzJob();
quartzJob.setBizModule(QUARTZ_BIZ_TYPE);
quartzJob.setBizId(config.getId());
}
quartzJob.setJobName("推送配置-" + config.getCategoryName());
quartzJob.setJobClass("pushConfigQuartzExecutor");
quartzJob.setJobMethod("execute");
quartzJob.setJobCron(config.getCronExpression());
quartzJob.setJobParams(config.getId());
quartzJob.setDescription("推送配置定时任务-" + config.getMessageType());
quartzJob.setStatus(Objects.equals(config.getStatus(), 1) ? "1" : "0");
quartzJob.setLastmodifier(currentUsernameOrSystem());
quartzJob.setLastmodifydate(new Timestamp(now.getTime()));
quartzJob.setOrderno(0);
if (StrUtil.isBlank(quartzJob.getId())) {
quartzJobService.save(quartzJob);
quartzManage.addJob(quartzJob);
} else {
quartzJobService.updateById(quartzJob);
quartzManage.updateJobCron(quartzJob);
}
}
private void refreshQuartzJobIfExists(PushConfig config) {
QuartzJob quartzJob = getPushQuartzJob(config.getId());
if (quartzJob == null) {
return;
}
if (canCreateQuartzJob(config)) {
syncQuartzJob(config);
} else {
deleteQuartzJob(config.getId());
}
}
private void syncQuartzJobBySwitch(PushConfig config) {
if (canCreateQuartzJob(config)) {
syncQuartzJob(config);
} else {
deleteQuartzJob(config.getId());
}
}
private boolean canCreateQuartzJob(PushConfig config) {
return config != null
&& Objects.equals(config.getStatus(), 1)
&& Objects.equals(config.getIsSms(), 1);
}
private void deleteQuartzJob(String configId) {
QuartzJob quartzJob = getPushQuartzJob(configId);
if (quartzJob != null) {
quartzManage.deleteJob(quartzJob);
quartzJobService.removeById(quartzJob.getId());
}
}
private QuartzJob getPushQuartzJob(String configId) {
List<QuartzJob> list = quartzJobService.list(new LambdaQueryWrapper<QuartzJob>()
.eq(QuartzJob::getBizModule, QUARTZ_BIZ_TYPE)
.eq(QuartzJob::getBizId, configId));
return list.isEmpty() ? null : list.getFirst();
}
private List<PushTargetUserVo> resolveTargets(PushConfig config) {
List<PushTargetUserVo> rawTargets;
if (Objects.equals(config.getTargetType(), 1)) {
rawTargets = pushConfigUserMapper.selectAllActiveUsers();
} else {
rawTargets = pushConfigUserMapper.selectTargetUsersByConfigId(config.getId());
}
if (rawTargets == null || rawTargets.isEmpty()) {
return Collections.emptyList();
}
Map<String, PushTargetUserVo> targetMap = new LinkedHashMap<>();
for (PushTargetUserVo target : rawTargets) {
if (target == null || StrUtil.isBlank(target.getUserId()) || StrUtil.isBlank(target.getTargetPhone())) {
continue;
}
targetMap.putIfAbsent(target.getUserId(), target);
}
return new ArrayList<>(targetMap.values());
}
private String buildDefaultTitle(PushConfig config) {
return StrUtil.format("【{}】默认推送标题", StrUtil.blankToDefault(config.getCategoryName(), "消息通知"));
}
private String buildDefaultContent(PushConfig config) {
return StrUtil.format("【{}】默认推送内容,消息类型:{},执行时间:{}",
StrUtil.blankToDefault(config.getCategoryName(), "消息通知"),
StrUtil.blankToDefault(config.getMessageType(), "未配置"),
DateUtil.formatDateTime(new Date()));
}
private String currentUserIdOrSystem() {
try {
return SecurityUtils.getUserId();
} catch (Exception ex) {
return "system";
}
}
private String currentUsernameOrSystem() {
try {
return SecurityUtils.getCurrentUsername();
} catch (Exception ex) {
return "system";
}
}
}

View File

@ -0,0 +1,11 @@
package com.yfd.platform.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.system.domain.PushConfigUser;
import com.yfd.platform.system.mapper.PushConfigUserMapper;
import com.yfd.platform.system.service.IPushConfigUserService;
import org.springframework.stereotype.Service;
@Service
public class PushConfigUserServiceImpl extends ServiceImpl<PushConfigUserMapper, PushConfigUser> implements IPushConfigUserService {
}

View File

@ -0,0 +1,11 @@
package com.yfd.platform.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.system.domain.PushHistoryDetail;
import com.yfd.platform.system.mapper.PushHistoryDetailMapper;
import com.yfd.platform.system.service.IPushHistoryDetailService;
import org.springframework.stereotype.Service;
@Service
public class PushHistoryDetailServiceImpl extends ServiceImpl<PushHistoryDetailMapper, PushHistoryDetail> implements IPushHistoryDetailService {
}

View File

@ -0,0 +1,11 @@
package com.yfd.platform.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.system.domain.PushHistory;
import com.yfd.platform.system.mapper.PushHistoryMapper;
import com.yfd.platform.system.service.IPushHistoryService;
import org.springframework.stereotype.Service;
@Service
public class PushHistoryServiceImpl extends ServiceImpl<PushHistoryMapper, PushHistory> implements IPushHistoryService {
}

View File

@ -42,13 +42,15 @@ public class SmsVerifyCodeServiceImpl extends ServiceImpl<SmsVerifyCodeMapper, S
@Override
@Transactional(rollbackFor = Exception.class)
public String sendVerifyCode(String phone, Integer type) {
public String sendVerifyCode(String phone, Integer type,String tenantId) {
String code = generateCode();
LambdaQueryWrapper<SmsVerifyCode> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SmsVerifyCode::getPhone, phone)
.eq(SmsVerifyCode::getType, type)
.gt(SmsVerifyCode::getTenantId, tenantId)
.eq(SmsVerifyCode::getStatus, SmsVerifyCode.STATUS_UNUSED);
this.remove(queryWrapper);
SmsVerifyCode verifyCode = new SmsVerifyCode();
@ -58,6 +60,7 @@ public class SmsVerifyCodeServiceImpl extends ServiceImpl<SmsVerifyCodeMapper, S
verifyCode.setType(type);
verifyCode.setStatus(SmsVerifyCode.STATUS_UNUSED);
verifyCode.setCreateTime(new Date());
verifyCode.setTenantId(tenantId);
Date expireTime = new Date(System.currentTimeMillis() + CODE_VALID_MINUTES * 60 * 1000L);
verifyCode.setExpireTime(expireTime);
@ -75,11 +78,12 @@ public class SmsVerifyCodeServiceImpl extends ServiceImpl<SmsVerifyCodeMapper, S
}
@Override
public boolean verifyCode(String phone, String code, Integer type) {
public boolean verifyCode(String phone, String code, Integer type,String tenantId) {
LambdaQueryWrapper<SmsVerifyCode> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SmsVerifyCode::getPhone, phone)
.eq(SmsVerifyCode::getCode, code)
.eq(SmsVerifyCode::getType, type)
.eq(SmsVerifyCode::getTenantId, tenantId)
.eq(SmsVerifyCode::getStatus, SmsVerifyCode.STATUS_UNUSED)
.gt(SmsVerifyCode::getExpireTime, new Date());
@ -150,14 +154,14 @@ public class SmsVerifyCodeServiceImpl extends ServiceImpl<SmsVerifyCodeMapper, S
@Override
public int urgeByUserIds(List<String> userIds, String content) {
public int urgeByUserIds(String tenantId,List<String> userIds, String content) {
if (userIds == null || userIds.isEmpty()) {
log.warn("催促短信发送失败用户ID列表为空");
return 0;
}
List<String> ids = userIds.stream().distinct().toList();
List<SysUser> sysUsers = sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>().in(SysUser::getId, ids)
.eq(SysUser::getRegStatus, "APPROVED").eq(SysUser::getStatus,1).select(SysUser::getPhone));
.eq(SysUser::getRegStatus, "APPROVED").eq(SysUser::getTenantId, tenantId).eq(SysUser::getStatus,1).select(SysUser::getPhone));
if (sysUsers.isEmpty()) {
log.warn("催促短信发送失败未找到有效的手机号userIds: {}", ids);

View File

@ -648,9 +648,10 @@ public class UserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impleme
}
@Override
public SysUser getUserByPhone(String phone) {
public SysUser getUserByPhone(String phone,String tenantId) {
LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SysUser::getPhone, phone);
queryWrapper.eq(SysUser::getTenantId, tenantId);
return this.getOne(queryWrapper);
}

View File

@ -19,12 +19,12 @@ import com.yfd.platform.config.MessageConfig;
import com.yfd.platform.config.thread.ThreadPoolExecutorUtil;
import com.yfd.platform.system.domain.Message;
import com.yfd.platform.system.domain.QuartzJob;
import com.yfd.platform.system.service.IMessageService;
import com.yfd.platform.system.service.IQuartzJobService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.springframework.scheduling.annotation.Async;
import org.quartz.PersistJobDataAfterExecution;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import java.sql.Timestamp;
@ -32,48 +32,72 @@ import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 参考人人开源https://gitee.com/renrenio/renren-security
* 定时任务执行器禁止同一Job并发执行
*
* @author /
* @date 2019-01-07
*/
@Async
@DisallowConcurrentExecution
@PersistJobDataAfterExecution
@SuppressWarnings({"unchecked", "all"})
@Slf4j
public class ExecutionJob extends QuartzJobBean {
/**
* 该处仅供参考
*/
private final static ThreadPoolExecutor EXECUTOR =
ThreadPoolExecutorUtil.getPoll();
private static final ThreadPoolExecutor EXECUTOR = ThreadPoolExecutorUtil.getPoll();
@Resource
private IMessageService messageService;
@Resource
private MessageConfig messageConfig;
@Override
public void executeInternal(JobExecutionContext context) {
protected void executeInternal(JobExecutionContext context) {
QuartzJob quartzJob =
(QuartzJob) context.getMergedJobDataMap().get(QuartzJob.JOB_KEY);
// 获取spring bean
IQuartzJobService quartzJobService =
SpringContextHolder.getBean(IQuartzJobService.class);
String uuid = quartzJob.getId();
long startTime = System.currentTimeMillis();
String jobName = quartzJob.getJobName();
String bizModule = quartzJob.getBizModule();
String bizId = quartzJob.getBizId();
try {
// 执行任务
System.out.println(
"--------------------------------------------------------------");
System.out.println("任务开始执行,任务名称:" + jobName);
QuartzRunnable task = new QuartzRunnable(quartzJob.getJobClass(),
logExecutionStart(jobName, bizModule, bizId);
QuartzRunnable task = new QuartzRunnable(
quartzJob.getJobClass(),
quartzJob.getJobMethod(),
quartzJob.getJobParams());
Future<?> future = EXECUTOR.submit(task);
future.get();
long times = System.currentTimeMillis() - startTime;
logExecutionEnd(jobName, bizModule, bizId, times);
// sendCompletionMessage(quartzJob);
} catch (Exception e) {
log.error("任务执行失败: jobName={}, module={}, bizId={}", jobName, bizModule, bizId, e);
quartzJob.setStatus("0");
quartzJobService.updateById(quartzJob);
}
}
private void logExecutionStart(String jobName, String bizModule, String bizId) {
log.info("--------------------------------------------------------------");
log.info("任务开始执行,任务名称:" + jobName +
(bizModule != null ? ",模块:" + bizModule : "") +
(bizId != null ? "业务ID" + bizId : ""));
}
private void logExecutionEnd(String jobName, String bizModule, String bizId, long times) {
log.info("任务执行完毕,任务名称:" + jobName +
(bizModule != null ? ",模块:" + bizModule : "") +
",执行时间:" + times + "毫秒");
log.info("--------------------------------------------------------------");
}
private void sendCompletionMessage(QuartzJob quartzJob) {
Message message = new Message();
message.setCreatetime(new Timestamp(System.currentTimeMillis()));
message.setType("1");
@ -85,19 +109,5 @@ public class ExecutionJob extends QuartzJobBean {
message.setStatus("1");
message.setValidperiod(24);
messageConfig.addMessage(message);
// 任务状态
System.out.println("任务执行完毕,任务名称:" + jobName + ", " +
"执行时间:" + times + "毫秒");
System.out.println(
"--------------------------------------------------------------");
} catch (Exception e) {
System.out.println("任务执行失败,任务名称:" + jobName);
System.out.println(
"--------------------------------------------------------------");
quartzJob.setStatus("0");
//更新状态
quartzJobService.updateById(quartzJob);
}
}
}

View File

@ -18,15 +18,21 @@ package com.yfd.platform.utils;
import com.yfd.platform.system.domain.QuartzJob;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import static org.quartz.TriggerBuilder.newTrigger;
/**
* 定时任务管理器线程安全支持多模块
*
* @author
* @date 2019-01-07
*/
@ -34,154 +40,267 @@ import static org.quartz.TriggerBuilder.newTrigger;
@Component
public class QuartzManage {
private static final String JOB_NAME = "TASK_";
private static final String JOB_NAME_PREFIX = "TASK_";
private static final String GROUP_SEPARATOR = "_";
@Resource(name = "scheduler")
private Scheduler scheduler;
public void addJob(QuartzJob quartzJob) {
try {
// 构建job信息
JobDetail jobDetail = JobBuilder.newJob(ExecutionJob.class).
withIdentity(JOB_NAME + quartzJob.getId()).build();
/** 按任务ID粒度的锁避免全局锁竞争 */
private static final ReentrantLock GLOBAL_LOCK = new ReentrantLock();
/**
* 构建 JobKey包含 bizModule 用于分组隔离
*/
private JobKey buildJobKey(QuartzJob quartzJob) {
String group = resolveGroup(quartzJob);
return JobKey.jobKey(JOB_NAME_PREFIX + quartzJob.getId(), group);
}
/**
* 构建 TriggerKey
*/
private TriggerKey buildTriggerKey(QuartzJob quartzJob) {
String group = resolveGroup(quartzJob);
return TriggerKey.triggerKey(JOB_NAME_PREFIX + quartzJob.getId(), group);
}
/**
* 解析 Quartz 分组名 bizModule 则按模块分组否则默认分组
*/
private String resolveGroup(QuartzJob quartzJob) {
if (quartzJob.getBizModule() != null && !quartzJob.getBizModule().isBlank()) {
return quartzJob.getBizModule();
}
return "DEFAULT";
}
/**
* 添加定时任务线程安全
*/
public void addJob(QuartzJob quartzJob) {
GLOBAL_LOCK.lock();
try {
JobDetail jobDetail = JobBuilder.newJob(ExecutionJob.class)
.withIdentity(buildJobKey(quartzJob))
.storeDurably()
.build();
//通过触发器名和cron 表达式创建 Trigger
Trigger cronTrigger = newTrigger()
.withIdentity(JOB_NAME + quartzJob.getId())
.withIdentity(buildTriggerKey(quartzJob))
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule(quartzJob.getJobCron()))
.withSchedule(CronScheduleBuilder.cronSchedule(quartzJob.getJobCron())
.withMisfireHandlingInstructionDoNothing())
.build();
cronTrigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob);
//重置启动时间
((CronTriggerImpl) cronTrigger).setStartTime(new Date());
//执行定时任务
scheduler.scheduleJob(jobDetail, cronTrigger);
// 暂停任务
if ("0".equals(quartzJob.getStatus())) {
pauseJob(quartzJob);
scheduler.pauseJob(buildJobKey(quartzJob));
}
log.info("创建定时任务成功: module={}, bizId={}, jobName={}",
quartzJob.getBizModule(), quartzJob.getBizId(), quartzJob.getJobName());
} catch (Exception e) {
log.error("创建定时任务失败", e);
throw new RuntimeException("创建定时任务失败");
log.error("创建定时任务失败: module={}, bizId={}", quartzJob.getBizModule(), quartzJob.getBizId(), e);
throw new RuntimeException("创建定时任务失败", e);
} finally {
GLOBAL_LOCK.unlock();
}
}
/**
* 更新job cron表达式
*
* @param quartzJob /
* 更新任务 Cron 表达式线程安全check-then-act 原子化
*/
public void updateJobCron(QuartzJob quartzJob) {
GLOBAL_LOCK.lock();
try {
TriggerKey triggerKey =
TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
CronTrigger trigger =
(CronTrigger) scheduler.getTrigger(triggerKey);
// 如果不存在则创建一个定时任务
TriggerKey triggerKey = buildTriggerKey(quartzJob);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if (trigger == null) {
addJob(quartzJob);
trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
return;
}
CronScheduleBuilder scheduleBuilder =
CronScheduleBuilder.cronSchedule(quartzJob.getJobCron());
trigger =
trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
//重置启动时间
CronScheduleBuilder.cronSchedule(quartzJob.getJobCron())
.withMisfireHandlingInstructionDoNothing();
trigger = trigger.getTriggerBuilder()
.withIdentity(triggerKey)
.withSchedule(scheduleBuilder)
.build();
((CronTriggerImpl) trigger).setStartTime(new Date());
trigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob);
scheduler.rescheduleJob(triggerKey, trigger);
// 暂停任务
if ("0".equals(quartzJob.getStatus())) {
pauseJob(quartzJob);
}
} catch (Exception e) {
log.error("更新定时任务失败", e);
throw new RuntimeException("更新定时任务失败");
}
if ("0".equals(quartzJob.getStatus())) {
scheduler.pauseJob(buildJobKey(quartzJob));
} else {
scheduler.resumeJob(buildJobKey(quartzJob));
}
log.info("更新定时任务成功: module={}, bizId={}, jobName={}",
quartzJob.getBizModule(), quartzJob.getBizId(), quartzJob.getJobName());
} catch (Exception e) {
log.error("更新定时任务失败: module={}, bizId={}", quartzJob.getBizModule(), quartzJob.getBizId(), e);
throw new RuntimeException("更新定时任务失败", e);
} finally {
GLOBAL_LOCK.unlock();
}
}
/**
* 删除一个job
*
* @param quartzJob /
* 删除任务
*/
public void deleteJob(QuartzJob quartzJob) {
try {
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
JobKey jobKey = buildJobKey(quartzJob);
scheduler.pauseJob(jobKey);
scheduler.deleteJob(jobKey);
log.info("删除定时任务成功: module={}, bizId={}, jobName={}",
quartzJob.getBizModule(), quartzJob.getBizId(), quartzJob.getJobName());
} catch (Exception e) {
log.error("删除定时任务失败", e);
throw new RuntimeException("删除定时任务失败");
log.error("删除定时任务失败: module={}, bizId={}", quartzJob.getBizModule(), quartzJob.getBizId(), e);
throw new RuntimeException("删除定时任务失败", e);
}
}
/**
* 恢复一个job
*
* @param quartzJob /
* 恢复任务
*/
public void resumeJob(QuartzJob quartzJob) {
try {
TriggerKey triggerKey =
TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
CronTrigger trigger =
(CronTrigger) scheduler.getTrigger(triggerKey);
// 如果不存在则创建一个定时任务
TriggerKey triggerKey = buildTriggerKey(quartzJob);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if (trigger == null) {
addJob(quartzJob);
return;
}
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
scheduler.resumeJob(jobKey);
scheduler.resumeJob(buildJobKey(quartzJob));
log.info("恢复定时任务成功: module={}, bizId={}", quartzJob.getBizModule(), quartzJob.getBizId());
} catch (Exception e) {
log.error("恢复定时任务失败", e);
throw new RuntimeException("恢复定时任务失败");
log.error("恢复定时任务失败: module={}, bizId={}", quartzJob.getBizModule(), quartzJob.getBizId(), e);
throw new RuntimeException("恢复定时任务失败", e);
}
}
/**
* 立即执行job
*
* @param quartzJob /
* 立即执行任务保留已有 JobDataMap追加最新 quartzJob 数据
*/
public void runJobNow(QuartzJob quartzJob) {
try {
TriggerKey triggerKey =
TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
CronTrigger trigger =
(CronTrigger) scheduler.getTrigger(triggerKey);
// 如果不存在则创建一个定时任务
TriggerKey triggerKey = buildTriggerKey(quartzJob);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if (trigger == null) {
log.warn("任务不存在,先创建再执行: jobName={}", quartzJob.getJobName());
addJob(quartzJob);
trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
}
JobDataMap dataMap = new JobDataMap();
JobDataMap dataMap = trigger.getJobDataMap();
dataMap.put(QuartzJob.JOB_KEY, quartzJob);
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
JobKey jobKey = buildJobKey(quartzJob);
scheduler.triggerJob(jobKey, dataMap);
log.info("手动触发任务执行: module={}, bizId={}, jobName={}",
quartzJob.getBizModule(), quartzJob.getBizId(), quartzJob.getJobName());
} catch (Exception e) {
log.error("定时任务执行失败", e);
throw new RuntimeException("定时任务执行失败");
log.error("手动触发任务失败: module={}, bizId={}", quartzJob.getBizModule(), quartzJob.getBizId(), e);
throw new RuntimeException("定时任务执行失败", e);
}
}
/**
* 暂停一个job
*
* @param quartzJob /
* 暂停任务
*/
public void pauseJob(QuartzJob quartzJob) {
try {
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
scheduler.pauseJob(jobKey);
scheduler.pauseJob(buildJobKey(quartzJob));
log.info("暂停定时任务成功: module={}, bizId={}", quartzJob.getBizModule(), quartzJob.getBizId());
} catch (Exception e) {
log.error("定时任务暂停失败", e);
throw new RuntimeException("定时任务暂停失败");
log.error("定时任务暂停失败: module={}, bizId={}", quartzJob.getBizModule(), quartzJob.getBizId(), e);
throw new RuntimeException("定时任务暂停失败", e);
}
}
// ==================== 多模块支持方法 ====================
/**
* 根据业务模块和业务ID查找已存在的任务
*
* @param bizModule 业务模块编码
* @param bizId 业务主键ID
* @return 是否存在
*/
public boolean existsByBiz(String bizModule, String bizId) {
if (bizModule == null || bizModule.isBlank() || bizId == null || bizId.isBlank()) {
return false;
}
try {
Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.groupEquals(bizModule));
for (JobKey jobKey : jobKeys) {
JobDetail detail = scheduler.getJobDetail(jobKey);
if (detail != null) {
QuartzJob job = (QuartzJob) detail.getJobDataMap().get(QuartzJob.JOB_KEY);
if (job != null && bizId.equals(job.getBizId())) {
return true;
}
}
}
} catch (SchedulerException e) {
log.error("查询任务失败: module={}, bizId={}", bizModule, bizId, e);
}
return false;
}
/**
* 按模块暂停该模块下所有任务
*/
public void pauseAllByModule(String bizModule) {
if (bizModule == null || bizModule.isBlank()) {
return;
}
try {
Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.groupEquals(bizModule));
scheduler.pauseJobs(org.quartz.impl.matchers.GroupMatcher.groupEquals(bizModule));
log.info("暂停模块[{}]下所有任务,共{}个", bizModule, jobKeys.size());
} catch (SchedulerException e) {
log.error("暂停模块任务失败: module={}", bizModule, e);
}
}
/**
* 按模块恢复该模块下所有任务
*/
public void resumeAllByModule(String bizModule) {
if (bizModule == null || bizModule.isBlank()) {
return;
}
try {
scheduler.resumeJobs(org.quartz.impl.matchers.GroupMatcher.groupEquals(bizModule));
log.info("恢复模块[{}]下所有任务", bizModule);
} catch (SchedulerException e) {
log.error("恢复模块任务失败: module={}", bizModule, e);
}
}
/**
* 按模块删除该模块下所有任务
*/
public void deleteAllByModule(String bizModule) {
if (bizModule == null || bizModule.isBlank()) {
return;
}
try {
Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.groupEquals(bizModule));
scheduler.deleteJobs(new java.util.ArrayList<>(jobKeys));
log.info("删除模块[{}]下所有任务,共{}个", bizModule, jobKeys.size());
} catch (SchedulerException e) {
log.error("删除模块任务失败: module={}", bizModule, e);
}
}
}

View File

@ -111,9 +111,11 @@ spring:
matching-strategy: ant_path_matcher
data:
redis:
host: "${REDIS_HOST:172.16.21.142}"
# host: "${REDIS_HOST:172.16.21.142}"
host: "${REDIS_HOST:localhost}"
port: "${REDIS_PORT:6379}"
password: "${REDIS_PASSWORD:zny5678}"
password: "${REDIS_PASSWORD:}"
# password: "${REDIS_PASSWORD:zny5678}"
database: "${REDIS_DATABASE:15}"
timeout: 10000ms
lettuce:

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yfd.platform.system.mapper.PushConfigUserMapper">
<select id="selectAllActiveUsers" resultType="com.yfd.platform.system.domain.PushTargetUserVo">
SELECT
u.ID AS userId,
NVL(u.REAL_NAME, NVL(u.NICKNAME, u.USERNAME)) AS targetName,
u.PHONE AS targetPhone
FROM SYS_USER u
WHERE u.STATUS = 1
AND u.PHONE IS NOT NULL
AND TRIM(u.PHONE) IS NOT NULL
</select>
<select id="selectTargetUsersByConfigId" resultType="com.yfd.platform.system.domain.PushTargetUserVo">
SELECT DISTINCT
t.userId,
t.targetName,
t.targetPhone
FROM (
SELECT
u.ID AS userId,
NVL(u.REAL_NAME, NVL(u.NICKNAME, u.USERNAME)) AS targetName,
u.PHONE AS targetPhone
FROM PUSH_CONFIG_USER pcu
INNER JOIN SYS_USER u ON u.ID = pcu.USER_ROLE_ID
WHERE pcu.CONFIG_ID = #{configId}
AND pcu.TYPE = 0
AND NVL(pcu.IS_DELETED, 0) = 0
AND u.STATUS = 1
AND u.PHONE IS NOT NULL
AND TRIM(u.PHONE) IS NOT NULL
UNION ALL
SELECT
u.ID AS userId,
NVL(u.REAL_NAME, NVL(u.NICKNAME, u.USERNAME)) AS targetName,
u.PHONE AS targetPhone
FROM PUSH_CONFIG_USER pcu
INNER JOIN SYS_ROLE_USERS sru ON sru.ROLEID = pcu.USER_ROLE_ID
INNER JOIN SYS_USER u ON u.ID = sru.USERID
WHERE pcu.CONFIG_ID = #{configId}
AND pcu.TYPE = 1
AND NVL(pcu.IS_DELETED, 0) = 0
AND u.STATUS = 1
AND u.PHONE IS NOT NULL
AND TRIM(u.PHONE) IS NOT NULL
) t
</select>
<select id="selectConfigTargets" resultType="com.yfd.platform.system.domain.PushConfigTargetVo">
SELECT
pcu.ID AS id,
pcu.CONFIG_ID AS configId,
pcu.TYPE AS type,
pcu.USER_ROLE_ID AS userRoleId,
CASE
WHEN pcu.TYPE = 0 THEN NVL(u.REAL_NAME, NVL(u.NICKNAME, u.USERNAME))
ELSE r.ROLENAME
END AS targetName,
CASE
WHEN pcu.TYPE = 0 THEN u.PHONE
ELSE NULL
END AS targetPhone
FROM PUSH_CONFIG_USER pcu
LEFT JOIN SYS_USER u ON pcu.TYPE = 0 AND u.ID = pcu.USER_ROLE_ID
LEFT JOIN SYS_ROLE r ON pcu.TYPE = 1 AND r.ID = pcu.USER_ROLE_ID
WHERE pcu.CONFIG_ID = #{configId}
AND NVL(pcu.IS_DELETED, 0) = 0
ORDER BY pcu.CREATED_AT DESC, pcu.ID DESC
</select>
</mapper>