package cn.iocoder.yudao.module.system.service.approval;
|
|
import cn.hutool.core.collection.CollUtil;
|
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
import cn.iocoder.yudao.module.system.controller.admin.approval.vo.ApprovalConfigPageReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.approval.vo.ApprovalConfigRespVO;
|
import cn.iocoder.yudao.module.system.controller.admin.approval.vo.ApprovalConfigSaveReqVO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.approval.ApprovalConfigDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.approval.ApprovalConfigUserDO;
|
import cn.iocoder.yudao.module.system.dal.mysql.approval.SystemApprovalConfigMapper;
|
import cn.iocoder.yudao.module.system.dal.mysql.approval.SystemApprovalConfigUserMapper;
|
import jakarta.annotation.Resource;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.validation.annotation.Validated;
|
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
|
/**
|
* 通用审批配置 Service 实现类
|
*
|
* 设计说明:本配置替代原有基于 BPM(Flowable)流程定义的审批方式,采用轻量级单级审批。
|
* 同一业务类型可配置多个审批人,多人之间为【或签】关系,即任意一人审核通过即推进业务状态。
|
*
|
* @author 超级管理员
|
*/
|
@Service
|
@Validated
|
@Slf4j
|
public class ApprovalConfigServiceImpl implements ApprovalConfigService {
|
|
@Resource
|
private SystemApprovalConfigMapper systemApprovalConfigMapper;
|
|
@Resource
|
private SystemApprovalConfigUserMapper systemApprovalConfigUserMapper;
|
|
@Resource
|
private AdminUserApi adminUserApi;
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public Long saveApprovalConfig(ApprovalConfigSaveReqVO saveReqVO) {
|
// 1. 校验业务类型编码唯一
|
validateBizTypeUnique(saveReqVO.getId(), saveReqVO.getBizType());
|
// 2. 校验审批人存在且未被禁用
|
List<Long> userIds = saveReqVO.getUserIds() == null ? Collections.emptyList()
|
: saveReqVO.getUserIds().stream().filter(Objects::nonNull).distinct().collect(Collectors.toList());
|
validateApproverUsers(userIds);
|
// 3. 保存主表
|
ApprovalConfigDO config = BeanUtils.toBean(saveReqVO, ApprovalConfigDO.class);
|
if (config.getId() == null) {
|
config.setId(null);
|
systemApprovalConfigMapper.insert(config);
|
} else {
|
validateApprovalConfigExists(config.getId());
|
systemApprovalConfigMapper.updateById(config);
|
}
|
// 4. 保存审批人:整体覆盖(先物理删除旧的,再插入新的)
|
systemApprovalConfigUserMapper.deleteByConfigId(config.getId());
|
if (CollUtil.isNotEmpty(userIds)) {
|
List<ApprovalConfigUserDO> userDOList = new ArrayList<>(userIds.size());
|
for (int i = 0; i < userIds.size(); i++) {
|
userDOList.add(ApprovalConfigUserDO.builder()
|
.configId(config.getId())
|
.userId(userIds.get(i))
|
.sort(i)
|
.build());
|
}
|
systemApprovalConfigUserMapper.insertBatch(userDOList);
|
}
|
return config.getId();
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void deleteApprovalConfig(Long id) {
|
validateApprovalConfigExists(id);
|
systemApprovalConfigMapper.deleteById(id);
|
systemApprovalConfigUserMapper.deleteByConfigId(id);
|
}
|
|
@Override
|
public ApprovalConfigDO getApprovalConfig(Long id) {
|
return systemApprovalConfigMapper.selectById(id);
|
}
|
|
@Override
|
public ApprovalConfigDO getApprovalConfigByBizType(String bizType) {
|
if (bizType == null) {
|
return null;
|
}
|
return systemApprovalConfigMapper.selectByBizType(bizType);
|
}
|
|
@Override
|
public PageResult<ApprovalConfigRespVO> getApprovalConfigPage(ApprovalConfigPageReqVO pageReqVO) {
|
PageResult<ApprovalConfigDO> pageResult = systemApprovalConfigMapper.selectPage(pageReqVO);
|
if (CollUtil.isEmpty(pageResult.getList())) {
|
return PageResult.empty(pageResult.getTotal());
|
}
|
// 1. 批量查询审批人子表
|
List<ApprovalConfigUserDO> allConfigUsers = systemApprovalConfigUserMapper.selectListByConfigIds(
|
convertSet(pageResult.getList(), ApprovalConfigDO::getId));
|
Map<Long, List<ApprovalConfigUserDO>> configUserMap = allConfigUsers.stream()
|
.collect(Collectors.groupingBy(ApprovalConfigUserDO::getConfigId));
|
// 2. 批量查询审批人昵称
|
Map<Long, String> nicknameMap = getUserNicknameMap(
|
convertSet(allConfigUsers, ApprovalConfigUserDO::getUserId));
|
// 3. 组装返回
|
List<ApprovalConfigRespVO> list = convertList(pageResult.getList(), config -> {
|
ApprovalConfigRespVO vo = BeanUtils.toBean(config, ApprovalConfigRespVO.class);
|
List<ApprovalConfigUserDO> configUsers = configUserMap.getOrDefault(config.getId(),
|
Collections.emptyList());
|
vo.setUserIds(convertList(configUsers, ApprovalConfigUserDO::getUserId));
|
vo.setUserNames(convertList(configUsers, user -> nicknameMap.get(user.getUserId())));
|
return vo;
|
});
|
return new PageResult<>(list, pageResult.getTotal());
|
}
|
|
@Override
|
public Set<Long> getApproverUserIds(String bizType) {
|
ApprovalConfigDO config = getApprovalConfigByBizType(bizType);
|
if (config == null) {
|
return Collections.emptySet();
|
}
|
return getValidApproverUserIds(config.getId());
|
}
|
|
@Override
|
public Set<Long> validateApprovalEnabledAndGetApprovers(String bizType) {
|
// 1. 校验业务类型已配置审批
|
ApprovalConfigDO config = getApprovalConfigByBizType(bizType);
|
if (config == null) {
|
throw exception(APPROVAL_CONFIG_NOT_EXISTS);
|
}
|
// 2. 校验已启用审批
|
if (!Boolean.TRUE.equals(config.getApprovalEnabled())) {
|
throw exception(APPROVAL_CONFIG_NOT_ENABLED);
|
}
|
// 3. 校验存在有效审批人(过滤掉已删除 / 已禁用的用户)
|
Set<Long> approverIds = getValidApproverUserIds(config.getId());
|
if (CollUtil.isEmpty(approverIds)) {
|
throw exception(APPROVAL_CONFIG_APPROVER_EMPTY);
|
}
|
return approverIds;
|
}
|
|
@Override
|
public void validateApprover(String bizType, Long userId) {
|
Set<Long> approverIds = getApproverUserIds(bizType);
|
if (userId == null || !approverIds.contains(userId)) {
|
throw exception(APPROVAL_CONFIG_NOT_APPROVER);
|
}
|
}
|
|
/**
|
* 查询配置下的有效审批人编号(过滤已删除 / 已禁用的用户)
|
*
|
* 审批人可能在配置之后被禁用或删除,此处统一过滤,
|
* 避免出现「配置里有人、但实际无人可审」导致单据卡在待审核状态。
|
*
|
* @param configId 配置编号
|
* @return 有效审批人编号集合
|
*/
|
private Set<Long> getValidApproverUserIds(Long configId) {
|
List<ApprovalConfigUserDO> configUsers = systemApprovalConfigUserMapper.selectListByConfigId(configId);
|
if (CollUtil.isEmpty(configUsers)) {
|
return Collections.emptySet();
|
}
|
Set<Long> userIds = convertSet(configUsers, ApprovalConfigUserDO::getUserId);
|
return convertSet(adminUserApi.getUserList(userIds), AdminUserRespDTO::getId,
|
user -> !CommonStatusEnum.isDisable(user.getStatus()));
|
}
|
|
private Map<Long, String> getUserNicknameMap(Collection<Long> userIds) {
|
if (CollUtil.isEmpty(userIds)) {
|
return Collections.emptyMap();
|
}
|
return adminUserApi.getUserList(userIds).stream()
|
.collect(Collectors.toMap(AdminUserRespDTO::getId, AdminUserRespDTO::getNickname, (a, b) -> a));
|
}
|
|
private void validateApprovalConfigExists(Long id) {
|
if (systemApprovalConfigMapper.selectById(id) == null) {
|
throw exception(APPROVAL_CONFIG_NOT_EXISTS);
|
}
|
}
|
|
private void validateBizTypeUnique(Long id, String bizType) {
|
ApprovalConfigDO config = systemApprovalConfigMapper.selectByBizType(bizType);
|
if (config != null && !config.getId().equals(id)) {
|
throw exception(APPROVAL_CONFIG_BIZ_TYPE_DUPLICATE, bizType);
|
}
|
}
|
|
private void validateApproverUsers(Collection<Long> userIds) {
|
if (CollUtil.isEmpty(userIds)) {
|
return;
|
}
|
List<AdminUserRespDTO> users = adminUserApi.getUserList(userIds);
|
Map<Long, AdminUserRespDTO> userMap = users.stream()
|
.collect(Collectors.toMap(AdminUserRespDTO::getId, user -> user, (a, b) -> a));
|
for (Long userId : userIds) {
|
AdminUserRespDTO user = userMap.get(userId);
|
if (user == null || CommonStatusEnum.isDisable(user.getStatus())) {
|
throw exception(APPROVAL_CONFIG_APPROVER_NOT_EXISTS);
|
}
|
}
|
}
|
|
}
|