feat(system): 新增外部系统推送配置功能

- 添加 BusinessTypeEnum 枚举定义采购、销售、生产三种业务类型
- 在 ErrorCodeConstants 中新增外部系统推送配置相关错误码
- 创建 ExternalPushConfigApi 定义推送配置的 RPC 接口
- 实现 ExternalPushConfigApiImpl 提供推送判断功能
- 设计 ExternalPushConfigDO 数据对象存储推送配置信息
- 开发 ExternalPushConfigMapper 提供数据库操作功能
- 实现 ExternalPushConfigService 业务逻辑处理
- 创建管理后台 Controller 提供 CRUD 和查询接口
- 定义请求响应 VO 对象规范接口参数和返回值
- 添加数据库表结构初始化脚本支持推送配置存储
This commit is contained in:
wuzongyong
2026-01-20 17:14:37 +08:00
parent a5d3afaf9b
commit 95d156940f
15 changed files with 1061 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
package com.zt.plat.module.system.api.push;
import com.zt.plat.framework.common.pojo.CommonResult;
import com.zt.plat.module.system.service.push.ExternalPushConfigService;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import static com.zt.plat.framework.common.pojo.CommonResult.success;
/**
* 外部系统推送配置 Feign API 实现类
*
* @author ZT Cloud
*/
@RestController
@Validated
public class ExternalPushConfigApiImpl implements ExternalPushConfigApi {
@Resource
private ExternalPushConfigService externalPushConfigService;
@Override
public CommonResult<Boolean> isPushEnabled(Long companyId, Long deptId, String businessType, String externalSystem) {
Boolean result = externalPushConfigService.isPushEnabled(companyId, deptId, businessType, externalSystem);
return success(result);
}
}

View File

@@ -0,0 +1,160 @@
package com.zt.plat.module.system.controller.admin.push;
import com.zt.plat.framework.common.pojo.CommonResult;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.common.util.collection.CollectionUtils;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.module.system.controller.admin.push.vo.BusinessTypeRespVO;
import com.zt.plat.module.system.controller.admin.push.vo.ExternalPushConfigPageReqVO;
import com.zt.plat.module.system.controller.admin.push.vo.ExternalPushConfigRespVO;
import com.zt.plat.module.system.controller.admin.push.vo.ExternalPushConfigSaveReqVO;
import com.zt.plat.module.system.dal.dataobject.dept.DeptDO;
import com.zt.plat.module.system.dal.dataobject.push.ExternalPushConfigDO;
import com.zt.plat.module.system.enums.push.BusinessTypeEnum;
import com.zt.plat.module.system.service.dept.DeptService;
import com.zt.plat.module.system.service.push.ExternalPushConfigService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static com.zt.plat.framework.common.pojo.CommonResult.success;
/**
* 外部系统推送配置 Controller
*
* @author ZT Cloud
*/
@Tag(name = "管理后台 - 外部系统推送配置")
@RestController
@RequestMapping("/system/external-push-config")
@Validated
public class ExternalPushConfigController {
@Resource
private ExternalPushConfigService externalPushConfigService;
@Resource
private DeptService deptService;
@PostMapping("/create")
@Operation(summary = "创建推送配置")
@PreAuthorize("@ss.hasPermission('system:external-push-config:create')")
public CommonResult<Long> create(@Valid @RequestBody ExternalPushConfigSaveReqVO createReqVO) {
Long id = externalPushConfigService.createExternalPushConfig(createReqVO);
return success(id);
}
@PutMapping("/update")
@Operation(summary = "修改推送配置")
@PreAuthorize("@ss.hasPermission('system:external-push-config:update')")
public CommonResult<Boolean> update(@Valid @RequestBody ExternalPushConfigSaveReqVO updateReqVO) {
externalPushConfigService.updateExternalPushConfig(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除推送配置")
@PreAuthorize("@ss.hasPermission('system:external-push-config:delete')")
public CommonResult<Boolean> delete(@RequestParam("id") Long id) {
externalPushConfigService.deleteExternalPushConfig(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获取推送配置详情")
@PreAuthorize("@ss.hasPermission('system:external-push-config:query')")
public CommonResult<ExternalPushConfigRespVO> get(@RequestParam("id") Long id) {
ExternalPushConfigDO entity = externalPushConfigService.getExternalPushConfig(id);
ExternalPushConfigRespVO respVO = BeanUtils.toBean(entity, ExternalPushConfigRespVO.class);
fillDeptInfo(List.of(respVO));
return success(respVO);
}
@GetMapping("/page")
@Operation(summary = "分页查询推送配置")
@PreAuthorize("@ss.hasPermission('system:external-push-config:query')")
public CommonResult<PageResult<ExternalPushConfigRespVO>> page(@Valid ExternalPushConfigPageReqVO reqVO) {
PageResult<ExternalPushConfigDO> pageResult = externalPushConfigService.getExternalPushConfigPage(reqVO);
PageResult<ExternalPushConfigRespVO> result = BeanUtils.toBean(pageResult, ExternalPushConfigRespVO.class);
fillDeptInfo(result.getList());
return success(result);
}
@GetMapping("/is-push-enabled")
@Operation(summary = "判断是否允许推送")
@Parameter(name = "companyId", description = "公司编号(为空表示不限制公司)")
@Parameter(name = "deptId", description = "部门编号")
@Parameter(name = "businessType", description = "业务类型(为空表示所有业务类型)")
@Parameter(name = "externalSystem", description = "外部系统标识(为空表示所有外部系统)")
@PreAuthorize("@ss.hasPermission('system:external-push-config:query')")
public CommonResult<Boolean> isPushEnabled(
@RequestParam(value = "companyId", required = false) Long companyId,
@RequestParam(value = "deptId", required = false) Long deptId,
@RequestParam(value = "businessType", required = false) String businessType,
@RequestParam(value = "externalSystem", required = false) String externalSystem) {
Boolean result = externalPushConfigService.isPushEnabled(companyId, deptId, businessType, externalSystem);
return success(result);
}
@GetMapping("/business-types")
@Operation(summary = "获取业务类型列表")
public CommonResult<List<BusinessTypeRespVO>> getBusinessTypes() {
List<BusinessTypeRespVO> result = Arrays.stream(BusinessTypeEnum.values())
.map(e -> new BusinessTypeRespVO(e.getType(), e.getCode(), e.getName()))
.collect(Collectors.toList());
return success(result);
}
/**
* 填充公司和部门名称
*/
private void fillDeptInfo(List<ExternalPushConfigRespVO> list) {
if (list == null || list.isEmpty()) {
return;
}
// 收集所有公司ID和部门ID
Set<Long> deptIds = list.stream()
.flatMap(item -> {
Set<Long> ids = new java.util.HashSet<>();
ids.add(item.getCompanyId());
if (item.getDeptId() != null) {
ids.add(item.getDeptId());
}
return ids.stream();
})
.collect(Collectors.toSet());
if (deptIds.isEmpty()) {
return;
}
// 批量查询部门信息
Map<Long, DeptDO> deptMap = CollectionUtils.convertMap(
deptService.getDeptList(deptIds), DeptDO::getId);
// 填充名称
list.forEach(item -> {
DeptDO company = deptMap.get(item.getCompanyId());
if (company != null) {
item.setCompanyName(company.getName());
}
if (item.getDeptId() != null) {
DeptDO dept = deptMap.get(item.getDeptId());
if (dept != null) {
item.setDeptName(dept.getName());
}
}
});
}
}

View File

@@ -0,0 +1,22 @@
package com.zt.plat.module.system.controller.admin.push.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Schema(description = "管理后台 - 业务类型 Response VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BusinessTypeRespVO {
@Schema(description = "类型", example = "1")
private Integer type;
@Schema(description = "编码", example = "PURCHASE")
private String code;
@Schema(description = "名称", example = "采购")
private String name;
}

View File

@@ -0,0 +1,33 @@
package com.zt.plat.module.system.controller.admin.push.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
@Schema(description = "管理后台 - 外部系统推送配置基础信息")
@Data
public class ExternalPushConfigBaseVO {
@Schema(description = "公司编号(为空表示不限制公司)", example = "1024")
private Long companyId;
@Schema(description = "部门编号(为空表示公司级配置)", example = "2048")
private Long deptId;
@Schema(description = "业务类型(为空表示所有业务类型)", example = "PURCHASE")
@Size(max = 32, message = "业务类型长度不能超过 32 个字符")
private String businessType;
@Schema(description = "外部系统标识(为空表示所有外部系统)", example = "ERP")
@Size(max = 64, message = "外部系统标识长度不能超过 64 个字符")
private String externalSystem;
@Schema(description = "是否启用推送", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "推送开关不能为空")
private Boolean enablePush;
@Schema(description = "备注", example = "ERP 采购单推送配置")
@Size(max = 512, message = "备注长度不能超过 512 个字符")
private String remark;
}

View File

@@ -0,0 +1,27 @@
package com.zt.plat.module.system.controller.admin.push.vo;
import com.zt.plat.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Schema(description = "管理后台 - 外部系统推送配置分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class ExternalPushConfigPageReqVO extends PageParam {
@Schema(description = "公司编号", example = "1024")
private Long companyId;
@Schema(description = "部门编号", example = "2048")
private Long deptId;
@Schema(description = "业务类型", example = "PURCHASE")
private String businessType;
@Schema(description = "外部系统标识", example = "ERP")
private String externalSystem;
@Schema(description = "是否启用推送", example = "true")
private Boolean enablePush;
}

View File

@@ -0,0 +1,28 @@
package com.zt.plat.module.system.controller.admin.push.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 外部系统推送配置 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class ExternalPushConfigRespVO extends ExternalPushConfigBaseVO {
@Schema(description = "配置编号", example = "1024")
private Long id;
@Schema(description = "公司名称", example = "浙江中天建设集团")
private String companyName;
@Schema(description = "部门名称", example = "采购部")
private String deptName;
@Schema(description = "创建时间")
private LocalDateTime createTime;
@Schema(description = "最后更新时间")
private LocalDateTime updateTime;
}

View File

@@ -0,0 +1,14 @@
package com.zt.plat.module.system.controller.admin.push.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Schema(description = "管理后台 - 外部系统推送配置创建/修改 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class ExternalPushConfigSaveReqVO extends ExternalPushConfigBaseVO {
@Schema(description = "配置编号", example = "1024")
private Long id;
}

View File

@@ -0,0 +1,76 @@
package com.zt.plat.module.system.dal.dataobject.push;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.zt.plat.framework.tenant.core.db.TenantBaseDO;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 外部系统推送配置 DO
*
* 用于配置不同公司/部门/业务类型下的外部系统推送开关
*
* @author ZT Cloud
*/
@TableName("system_external_push_config")
@KeySequence("system_external_push_config_seq")
@Data
@EqualsAndHashCode(callSuper = true)
public class ExternalPushConfigDO extends TenantBaseDO {
/**
* 主键编号
*/
@TableId(type = IdType.ASSIGN_ID)
private Long id;
/**
* 公司编号(可为空)
*
* 关联 system_dept 表is_company = 1
* 为空表示不限制公司
*/
private Long companyId;
/**
* 部门编号(可为空)
*
* 关联 system_dept 表is_company = 0
* 为空表示公司级配置
*/
private Long deptId;
/**
* 业务类型(可为空)
*
* 枚举值PURCHASE, SALE, PRODUCTION
* 为空表示所有业务类型
* 枚举 {@link com.zt.plat.module.system.enums.push.BusinessTypeEnum}
*/
private String businessType;
/**
* 外部系统标识(可为空)
*
* 如ERP, IWORK
* 为空表示所有外部系统
* 枚举 {@link com.zt.plat.module.system.enums.dept.ExternalPlatformEnum}
*/
private String externalSystem;
/**
* 是否启用推送
*
* true启用推送
* false停用推送
*/
private Boolean enablePush;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,92 @@
package com.zt.plat.module.system.dal.mysql.push;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.zt.plat.module.system.controller.admin.push.vo.ExternalPushConfigPageReqVO;
import com.zt.plat.module.system.dal.dataobject.push.ExternalPushConfigDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 外部系统推送配置 Mapper
*
* @author ZT Cloud
*/
@Mapper
public interface ExternalPushConfigMapper extends BaseMapperX<ExternalPushConfigDO> {
default PageResult<ExternalPushConfigDO> selectPage(ExternalPushConfigPageReqVO reqVO) {
LambdaQueryWrapperX<ExternalPushConfigDO> wrapper = new LambdaQueryWrapperX<ExternalPushConfigDO>()
.eqIfPresent(ExternalPushConfigDO::getCompanyId, reqVO.getCompanyId())
.eqIfPresent(ExternalPushConfigDO::getBusinessType, reqVO.getBusinessType())
.eqIfPresent(ExternalPushConfigDO::getExternalSystem, reqVO.getExternalSystem())
.eqIfPresent(ExternalPushConfigDO::getEnablePush, reqVO.getEnablePush());
// 如果传了 companyId 但没传 deptId则只查公司级配置dept_id IS NULL
if (reqVO.getCompanyId() != null && reqVO.getDeptId() == null) {
wrapper.isNull(ExternalPushConfigDO::getDeptId);
} else if (reqVO.getDeptId() != null) {
// 如果传了 deptId则查指定部门的配置
wrapper.eq(ExternalPushConfigDO::getDeptId, reqVO.getDeptId());
}
// 如果都没传,则查所有配置
wrapper.orderByDesc(ExternalPushConfigDO::getId);
return selectPage(reqVO, wrapper);
}
/**
* 通用查询配置方法
*
* @param companyId 公司IDnull 表示查询 company_id IS NULL 的记录)
* @param deptId 部门IDnull 表示查询 dept_id IS NULL 的记录)
* @param businessType 业务类型null 表示查询 business_type IS NULL 的记录)
* @param externalSystem 外部系统null 表示查询 external_system IS NULL 的记录)
* @return 配置对象
*/
default ExternalPushConfigDO selectByConfig(Long companyId, Long deptId, String businessType, String externalSystem) {
LambdaQueryWrapperX<ExternalPushConfigDO> wrapper = new LambdaQueryWrapperX<>();
if (companyId == null) {
wrapper.isNull(ExternalPushConfigDO::getCompanyId);
} else {
wrapper.eq(ExternalPushConfigDO::getCompanyId, companyId);
}
if (deptId == null) {
wrapper.isNull(ExternalPushConfigDO::getDeptId);
} else {
wrapper.eq(ExternalPushConfigDO::getDeptId, deptId);
}
if (businessType == null) {
wrapper.isNull(ExternalPushConfigDO::getBusinessType);
} else {
wrapper.eq(ExternalPushConfigDO::getBusinessType, businessType);
}
if (externalSystem == null) {
wrapper.isNull(ExternalPushConfigDO::getExternalSystem);
} else {
wrapper.eq(ExternalPushConfigDO::getExternalSystem, externalSystem);
}
return selectOne(wrapper);
}
/**
* 查询公司下所有配置
*/
default List<ExternalPushConfigDO> selectListByCompanyId(Long companyId) {
return selectList(ExternalPushConfigDO::getCompanyId, companyId);
}
/**
* 查询部门下所有配置
*/
default List<ExternalPushConfigDO> selectListByDeptId(Long deptId) {
return selectList(ExternalPushConfigDO::getDeptId, deptId);
}
}

View File

@@ -0,0 +1,53 @@
package com.zt.plat.module.system.service.push;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.module.system.controller.admin.push.vo.ExternalPushConfigPageReqVO;
import com.zt.plat.module.system.controller.admin.push.vo.ExternalPushConfigSaveReqVO;
import com.zt.plat.module.system.dal.dataobject.push.ExternalPushConfigDO;
import jakarta.validation.Valid;
/**
* 外部系统推送配置 Service 接口
*
* @author ZT Cloud
*/
public interface ExternalPushConfigService {
/**
* 创建推送配置
*/
Long createExternalPushConfig(@Valid ExternalPushConfigSaveReqVO createReqVO);
/**
* 修改推送配置
*/
void updateExternalPushConfig(@Valid ExternalPushConfigSaveReqVO updateReqVO);
/**
* 删除推送配置
*/
void deleteExternalPushConfig(Long id);
/**
* 获取推送配置详情
*/
ExternalPushConfigDO getExternalPushConfig(Long id);
/**
* 分页查询推送配置
*/
PageResult<ExternalPushConfigDO> getExternalPushConfigPage(ExternalPushConfigPageReqVO reqVO);
/**
* 判断是否允许推送(核心业务逻辑)
*
* 优先级:部门配置 > 公司配置 > 默认允许
*
* @param companyId 公司编号(必填)
* @param deptId 部门编号(可选)
* @param businessType 业务类型(必填)
* @param externalSystem 外部系统标识(必填)
* @return 是否允许推送true=允许false=禁止,默认 true
*/
Boolean isPushEnabled(Long companyId, Long deptId, String businessType, String externalSystem);
}

View File

@@ -0,0 +1,280 @@
package com.zt.plat.module.system.service.push;
import cn.hutool.core.util.StrUtil;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.module.system.controller.admin.push.vo.ExternalPushConfigPageReqVO;
import com.zt.plat.module.system.controller.admin.push.vo.ExternalPushConfigSaveReqVO;
import com.zt.plat.module.system.dal.dataobject.dept.DeptDO;
import com.zt.plat.module.system.dal.dataobject.push.ExternalPushConfigDO;
import com.zt.plat.module.system.dal.mysql.dept.DeptMapper;
import com.zt.plat.module.system.dal.mysql.push.ExternalPushConfigMapper;
import com.zt.plat.module.system.enums.push.BusinessTypeEnum;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.module.system.enums.ErrorCodeConstants.*;
/**
* 外部系统推送配置 Service 实现类
*
* @author ZT Cloud
*/
@Service
@Validated
public class ExternalPushConfigServiceImpl implements ExternalPushConfigService {
@Resource
private ExternalPushConfigMapper externalPushConfigMapper;
@Resource
private DeptMapper deptMapper;
@Override
public Long createExternalPushConfig(ExternalPushConfigSaveReqVO createReqVO) {
// 参数规范化
normalizeRequest(createReqVO);
// 业务校验
validateForCreateOrUpdate(null, createReqVO);
// 创建配置
ExternalPushConfigDO entity = BeanUtils.toBean(createReqVO, ExternalPushConfigDO.class);
if (entity.getEnablePush() == null) {
entity.setEnablePush(true);
}
externalPushConfigMapper.insert(entity);
return entity.getId();
}
@Override
public void updateExternalPushConfig(ExternalPushConfigSaveReqVO updateReqVO) {
// 参数规范化
normalizeRequest(updateReqVO);
// 校验存在
validateExists(updateReqVO.getId());
// 业务校验
validateForCreateOrUpdate(updateReqVO.getId(), updateReqVO);
// 更新配置
ExternalPushConfigDO updateObj = BeanUtils.toBean(updateReqVO, ExternalPushConfigDO.class);
externalPushConfigMapper.updateById(updateObj);
}
@Override
public void deleteExternalPushConfig(Long id) {
validateExists(id);
externalPushConfigMapper.deleteById(id);
}
@Override
public ExternalPushConfigDO getExternalPushConfig(Long id) {
return externalPushConfigMapper.selectById(id);
}
@Override
public PageResult<ExternalPushConfigDO> getExternalPushConfigPage(ExternalPushConfigPageReqVO reqVO) {
return externalPushConfigMapper.selectPage(reqVO);
}
@Override
public Boolean isPushEnabled(Long companyId, Long deptId, String businessType, String externalSystem) {
// 规范化参数
String normalizedBusinessType = StrUtil.isNotBlank(businessType) ? businessType.trim().toUpperCase() : null;
String normalizedExternalSystem = StrUtil.isNotBlank(externalSystem) ? externalSystem.trim().toUpperCase() : null;
// 优先级 1部门级配置如果 deptId 不为空),递归查找父部门
if (deptId != null) {
ExternalPushConfigDO deptConfig = findDeptConfigRecursive(
companyId, deptId, normalizedBusinessType, normalizedExternalSystem);
if (deptConfig != null) {
return deptConfig.getEnablePush() != null ? deptConfig.getEnablePush() : true;
}
}
// 优先级 2公司级配置dept_id 为 null
if (companyId != null) {
ExternalPushConfigDO companyConfig = externalPushConfigMapper.selectByConfig(
companyId, null, normalizedBusinessType, normalizedExternalSystem);
if (companyConfig != null) {
return companyConfig.getEnablePush() != null ? companyConfig.getEnablePush() : true;
}
}
// 优先级 3全局配置company_id 和 dept_id 都为空)
ExternalPushConfigDO globalConfig = externalPushConfigMapper.selectByConfig(
null, null, normalizedBusinessType, normalizedExternalSystem);
if (globalConfig != null) {
return globalConfig.getEnablePush() != null ? globalConfig.getEnablePush() : true;
}
// 优先级 4没有配置默认允许推送
return true;
}
/**
* 递归查找部门配置(包括父部门)
*
* @param companyId 公司ID
* @param deptId 部门ID
* @param businessType 业务类型
* @param externalSystem 外部系统
* @return 配置对象,如果找不到返回 null
*/
private ExternalPushConfigDO findDeptConfigRecursive(Long companyId, Long deptId,
String businessType, String externalSystem) {
if (deptId == null) {
return null;
}
// 查询当前部门的配置
ExternalPushConfigDO config = externalPushConfigMapper.selectByConfig(
companyId, deptId, businessType, externalSystem);
if (config != null) {
return config;
}
// 查询当前部门信息获取父部门ID
DeptDO dept = deptMapper.selectById(deptId);
if (dept == null || dept.getParentId() == null || dept.getParentId() == 0L) {
// 没有父部门了,返回 null
return null;
}
// 检查父部门是否是公司节点
DeptDO parentDept = deptMapper.selectById(dept.getParentId());
if (parentDept != null && Boolean.TRUE.equals(parentDept.getIsCompany())) {
// 父部门是公司,不再向上查找(公司级配置在外层处理)
return null;
}
// 递归查找父部门的配置
return findDeptConfigRecursive(companyId, dept.getParentId(), businessType, externalSystem);
}
//==================== 私有方法 ====================
/**
* 校验配置是否存在
*/
private ExternalPushConfigDO validateExists(Long id) {
if (id == null) {
throw exception(EXTERNAL_PUSH_CONFIG_NOT_EXISTS);
}
ExternalPushConfigDO entity = externalPushConfigMapper.selectById(id);
if (entity == null) {
throw exception(EXTERNAL_PUSH_CONFIG_NOT_EXISTS);
}
return entity;
}
/**
* 业务校验
*/
private void validateForCreateOrUpdate(Long id, ExternalPushConfigSaveReqVO reqVO) {
// 1. 如果指定公司,校验公司存在且是公司节点
if (reqVO.getCompanyId() != null) {
DeptDO company = deptMapper.selectById(reqVO.getCompanyId());
if (company == null) {
throw exception(DEPT_NOT_FOUND);
}
if (!Boolean.TRUE.equals(company.getIsCompany())) {
throw exception(EXTERNAL_PUSH_CONFIG_COMPANY_INVALID);
}
}
// 2. 如果指定部门,校验部门存在且不是公司节点
if (reqVO.getDeptId() != null) {
DeptDO dept = deptMapper.selectById(reqVO.getDeptId());
if (dept == null) {
throw exception(DEPT_NOT_FOUND);
}
if (Boolean.TRUE.equals(dept.getIsCompany())) {
throw exception(EXTERNAL_PUSH_CONFIG_DEPT_INVALID);
}
}
// 3. 如果指定业务类型,校验业务类型有效性
if (StrUtil.isNotBlank(reqVO.getBusinessType())) {
if (!BusinessTypeEnum.isValidCode(reqVO.getBusinessType())) {
throw exception(EXTERNAL_PUSH_CONFIG_BUSINESS_TYPE_INVALID);
}
}
// 4. 校验唯一性:同一租户+公司+部门+业务类型+外部系统的配置唯一
ExternalPushConfigDO existing = externalPushConfigMapper.selectByConfig(
reqVO.getCompanyId(), reqVO.getDeptId(),
reqVO.getBusinessType(), reqVO.getExternalSystem());
if (existing != null && (id == null || !existing.getId().equals(id))) {
throw exception(EXTERNAL_PUSH_CONFIG_EXISTS);
}
}
/**
* 参数规范化
*/
private void normalizeRequest(ExternalPushConfigSaveReqVO reqVO) {
if (reqVO == null) {
return;
}
// 如果 companyId 为空但 deptId 不为空自动查找并填充顶级公司ID
if (reqVO.getCompanyId() == null && reqVO.getDeptId() != null) {
Long topCompanyId = findTopCompanyId(reqVO.getDeptId());
if (topCompanyId != null) {
reqVO.setCompanyId(topCompanyId);
}
}
if (StrUtil.isNotBlank(reqVO.getBusinessType())) {
reqVO.setBusinessType(reqVO.getBusinessType().trim().toUpperCase());
}
if (StrUtil.isNotBlank(reqVO.getExternalSystem())) {
reqVO.setExternalSystem(reqVO.getExternalSystem().trim().toUpperCase());
}
}
/**
* 查找部门的顶级公司ID
*
* @param deptId 部门ID
* @return 顶级公司ID如果不存在返回 null
*/
private Long findTopCompanyId(Long deptId) {
if (deptId == null) {
return null;
}
DeptDO dept = deptMapper.selectById(deptId);
if (dept == null) {
return null;
}
// 递归向上查找直到找到公司节点或者parentId为空/0
Long currentDeptId = deptId;
while (currentDeptId != null) {
DeptDO currentDept = deptMapper.selectById(currentDeptId);
if (currentDept == null) {
break;
}
// 如果当前节点是公司返回其ID
if (Boolean.TRUE.equals(currentDept.getIsCompany())) {
return currentDept.getId();
}
// 如果没有父节点或父节点为0结束查找
if (currentDept.getParentId() == null || currentDept.getParentId() == 0L) {
break;
}
// 继续向上查找
currentDeptId = currentDept.getParentId();
}
return null;
}
}