mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 12:18:42 +08:00 
			
		
		
		
	【代码重构】工作流:BpmTaskCandidateStrategy 拆分成 calculateUsers、calculateUsersByTask、calculateUsersByActivity,定位更明确
This commit is contained in:
		@@ -9,7 +9,7 @@ import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConver
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateStartUserSelectStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept.BpmTaskCandidateStartUserSelectStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConver
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEvent;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateStartUserSelectStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept.BpmTaskCandidateStartUserSelectStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO;
 | 
			
		||||
 
 | 
			
		||||
@@ -53,7 +53,7 @@ public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehav
 | 
			
		||||
        @SuppressWarnings("unchecked")
 | 
			
		||||
        Set<Long> assigneeUserIds = (Set<Long>) execution.getVariable(super.collectionVariable, Set.class);
 | 
			
		||||
        if (assigneeUserIds == null) {
 | 
			
		||||
            assigneeUserIds = taskCandidateInvoker.calculateUsers(execution);
 | 
			
		||||
            assigneeUserIds = taskCandidateInvoker.calculateUsersByTask(execution);
 | 
			
		||||
            execution.setVariable(super.collectionVariable, assigneeUserIds);
 | 
			
		||||
            if (CollUtil.isEmpty(assigneeUserIds)) {
 | 
			
		||||
                // 特殊:如果没有处理人的情况下,至少有一个 null 空元素,避免自动通过!
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ public class BpmSequentialMultiInstanceBehavior extends SequentialMultiInstanceB
 | 
			
		||||
        @SuppressWarnings("unchecked")
 | 
			
		||||
        Set<Long> assigneeUserIds = (Set<Long>) execution.getVariable(super.collectionVariable, Set.class);
 | 
			
		||||
        if (assigneeUserIds == null) {
 | 
			
		||||
            assigneeUserIds = taskCandidateInvoker.calculateUsers(execution);
 | 
			
		||||
            assigneeUserIds = taskCandidateInvoker.calculateUsersByTask(execution);
 | 
			
		||||
            execution.setVariable(super.collectionVariable, assigneeUserIds);
 | 
			
		||||
            if (CollUtil.isEmpty(assigneeUserIds)) {
 | 
			
		||||
                // 特殊:如果没有处理人的情况下,至少有一个 null 空元素,避免自动通过!
 | 
			
		||||
 
 | 
			
		||||
@@ -57,7 +57,7 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior {
 | 
			
		||||
 | 
			
		||||
        // 情况二,如果非多实例的任务,则计算任务处理人
 | 
			
		||||
        // 第一步,先计算可处理该任务的处理人们
 | 
			
		||||
        Set<Long> candidateUserIds = taskCandidateInvoker.calculateUsers(execution);
 | 
			
		||||
        Set<Long> candidateUserIds = taskCandidateInvoker.calculateUsersByTask(execution);
 | 
			
		||||
        if (CollUtil.isEmpty(candidateUserIds)) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 | 
			
		||||
import com.google.common.annotations.VisibleForTesting;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.flowable.bpmn.model.BpmnModel;
 | 
			
		||||
import org.flowable.bpmn.model.FlowElement;
 | 
			
		||||
import org.flowable.bpmn.model.UserTask;
 | 
			
		||||
import org.flowable.engine.delegate.DelegateExecution;
 | 
			
		||||
import org.flowable.engine.runtime.ProcessInstance;
 | 
			
		||||
@@ -89,31 +90,66 @@ public class BpmTaskCandidateInvoker {
 | 
			
		||||
     * @return 用户编号集合
 | 
			
		||||
     */
 | 
			
		||||
    @DataPermission(enable = false) // 忽略数据权限,避免因为过滤,导致找不到候选人
 | 
			
		||||
    public Set<Long> calculateUsers(DelegateExecution execution) {
 | 
			
		||||
    public Set<Long> calculateUsersByTask(DelegateExecution execution) {
 | 
			
		||||
        // 审批类型非人工审核时,不进行计算候选人。原因是:后续会自动通过、不通过
 | 
			
		||||
        Integer approveType = BpmnModelUtils.parseApproveType(execution.getCurrentFlowElement());
 | 
			
		||||
        FlowElement flowElement = execution.getCurrentFlowElement();
 | 
			
		||||
        Integer approveType = BpmnModelUtils.parseApproveType(flowElement);
 | 
			
		||||
        if (ObjectUtils.equalsAny(approveType,
 | 
			
		||||
                BpmUserTaskApproveTypeEnum.AUTO_APPROVE.getType(),
 | 
			
		||||
                BpmUserTaskApproveTypeEnum.AUTO_REJECT.getType())) {
 | 
			
		||||
            return new HashSet<>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Integer strategy = BpmnModelUtils.parseCandidateStrategy(execution.getCurrentFlowElement());
 | 
			
		||||
        String param = BpmnModelUtils.parseCandidateParam(execution.getCurrentFlowElement());
 | 
			
		||||
        Integer strategy = BpmnModelUtils.parseCandidateStrategy(flowElement);
 | 
			
		||||
        String param = BpmnModelUtils.parseCandidateParam(flowElement);
 | 
			
		||||
        // 1.1 计算任务的候选人
 | 
			
		||||
        Set<Long> userIds = getCandidateStrategy(strategy).calculateUsers(execution, param);
 | 
			
		||||
        // 1.2 移除被禁用的用户 TODO @芋艿 在 calculateUsers 方法中默认已经移除了被禁用的用户, 这里还需要移除被禁用的用户吗?
 | 
			
		||||
        Set<Long> userIds = getCandidateStrategy(strategy).calculateUsersByTask(execution, param);
 | 
			
		||||
        // 1.2 移除被禁用的用户
 | 
			
		||||
        removeDisableUsers(userIds);
 | 
			
		||||
 | 
			
		||||
        // 2. 候选人为空时,根据“审批人为空”的配置补充
 | 
			
		||||
        if (CollUtil.isEmpty(userIds)) {
 | 
			
		||||
            userIds = getCandidateStrategy(BpmTaskCandidateStrategyEnum.ASSIGN_EMPTY.getStrategy())
 | 
			
		||||
                    .calculateUsers(execution, param);
 | 
			
		||||
                    .calculateUsersByTask(execution, param);
 | 
			
		||||
            // ASSIGN_EMPTY 策略,不需要移除被禁用的用户。原因是,再移除,可能会出现更没审批人了!!!
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 3. 移除发起人的用户
 | 
			
		||||
        removeStartUserIfSkip(execution, userIds);
 | 
			
		||||
        ProcessInstance processInstance = SpringUtil.getBean(BpmProcessInstanceService.class)
 | 
			
		||||
                .getProcessInstance(execution.getProcessInstanceId());
 | 
			
		||||
        Assert.notNull(processInstance, "流程实例({}) 不存在", execution.getProcessInstanceId());
 | 
			
		||||
        removeStartUserIfSkip(userIds, flowElement, Long.valueOf(processInstance.getStartUserId()));
 | 
			
		||||
        return userIds;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId,
 | 
			
		||||
                                              Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
 | 
			
		||||
        // 审批类型非人工审核时,不进行计算候选人。原因是:后续会自动通过、不通过
 | 
			
		||||
        FlowElement flowElement = BpmnModelUtils.getFlowElementById(bpmnModel, activityId);
 | 
			
		||||
        Integer approveType = BpmnModelUtils.parseApproveType(flowElement);
 | 
			
		||||
        if (ObjectUtils.equalsAny(approveType,
 | 
			
		||||
                BpmUserTaskApproveTypeEnum.AUTO_APPROVE.getType(),
 | 
			
		||||
                BpmUserTaskApproveTypeEnum.AUTO_REJECT.getType())) {
 | 
			
		||||
            return new HashSet<>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Integer strategy = BpmnModelUtils.parseCandidateStrategy(flowElement);
 | 
			
		||||
        String param = BpmnModelUtils.parseCandidateParam(flowElement);
 | 
			
		||||
        // 1.1 计算任务的候选人
 | 
			
		||||
        Set<Long> userIds = getCandidateStrategy(strategy).calculateUsersByActivity(bpmnModel, activityId, param,
 | 
			
		||||
                startUserId, processDefinitionId, processVariables);
 | 
			
		||||
        // 1.2 移除被禁用的用户
 | 
			
		||||
        removeDisableUsers(userIds);
 | 
			
		||||
 | 
			
		||||
        // 2. 候选人为空时,根据“审批人为空”的配置补充
 | 
			
		||||
        if (CollUtil.isEmpty(userIds)) {
 | 
			
		||||
            userIds = getCandidateStrategy(BpmTaskCandidateStrategyEnum.ASSIGN_EMPTY.getStrategy())
 | 
			
		||||
                    .calculateUsersByActivity(bpmnModel, activityId, param, startUserId, processDefinitionId, processVariables);
 | 
			
		||||
            // ASSIGN_EMPTY 策略,不需要移除被禁用的用户。原因是,再移除,可能会出现更没审批人了!!!
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 3. 移除发起人的用户
 | 
			
		||||
        removeStartUserIfSkip(userIds, flowElement, startUserId);
 | 
			
		||||
        return userIds;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -134,25 +170,23 @@ public class BpmTaskCandidateInvoker {
 | 
			
		||||
     *
 | 
			
		||||
     * 注意:如果只有一个候选人,则不处理,避免无法审批
 | 
			
		||||
     *
 | 
			
		||||
     * @param execution 执行中的任务
 | 
			
		||||
     * @param assigneeUserIds 当前分配的候选人
 | 
			
		||||
     * @param flowElement 当前节点
 | 
			
		||||
     * @param startUserId 发起人
 | 
			
		||||
     */
 | 
			
		||||
    @VisibleForTesting
 | 
			
		||||
    void removeStartUserIfSkip(DelegateExecution execution, Set<Long> assigneeUserIds) {
 | 
			
		||||
    void removeStartUserIfSkip(Set<Long> assigneeUserIds, FlowElement flowElement, Long startUserId) {
 | 
			
		||||
        if (CollUtil.size(assigneeUserIds) <= 1) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        Integer assignStartUserHandlerType = BpmnModelUtils.parseAssignStartUserHandlerType(execution.getCurrentFlowElement());
 | 
			
		||||
        Integer assignStartUserHandlerType = BpmnModelUtils.parseAssignStartUserHandlerType(flowElement);
 | 
			
		||||
        if (ObjectUtil.notEqual(assignStartUserHandlerType, BpmUserTaskAssignStartUserHandlerTypeEnum.SKIP.getType())) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        ProcessInstance processInstance = SpringUtil.getBean(BpmProcessInstanceService.class)
 | 
			
		||||
                .getProcessInstance(execution.getProcessInstanceId());
 | 
			
		||||
        Assert.notNull(processInstance, "流程实例({}) 不存在", execution.getProcessInstanceId());
 | 
			
		||||
        assigneeUserIds.remove(Long.valueOf(processInstance.getStartUserId()));
 | 
			
		||||
        assigneeUserIds.remove(startUserId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BpmTaskCandidateStrategy getCandidateStrategy(Integer strategy) {
 | 
			
		||||
    private BpmTaskCandidateStrategy getCandidateStrategy(Integer strategy) {
 | 
			
		||||
        BpmTaskCandidateStrategyEnum strategyEnum = BpmTaskCandidateStrategyEnum.valueOf(strategy);
 | 
			
		||||
        Assert.notNull(strategyEnum, "策略(%s) 不存在", strategy);
 | 
			
		||||
        BpmTaskCandidateStrategy strategyObj = strategyMap.get(strategyEnum);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,10 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
 | 
			
		||||
import org.flowable.bpmn.model.BpmnModel;
 | 
			
		||||
import org.flowable.engine.delegate.DelegateExecution;
 | 
			
		||||
import org.flowable.engine.runtime.ProcessInstance;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -42,47 +42,44 @@ public interface BpmTaskCandidateStrategy {
 | 
			
		||||
    /**
 | 
			
		||||
     * 基于候选人参数,获得任务的候选用户们
 | 
			
		||||
     *
 | 
			
		||||
     * 注意:实现 calculateUsers 系列方法时,有两种选择:
 | 
			
		||||
     * 1. 只重写 calculateUsers 默认方法
 | 
			
		||||
     * 2. 都重写 calculateUsersByTask 和 calculateUsersByActivity 两个方法
 | 
			
		||||
     *
 | 
			
		||||
     * @param param 执行任务
 | 
			
		||||
     * @return 用户编号集合
 | 
			
		||||
     */
 | 
			
		||||
    default Set<Long> calculateUsers(String param) {
 | 
			
		||||
        return Collections.emptySet();
 | 
			
		||||
        throw new UnsupportedOperationException("该分配方法未实现,请检查!");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 基于执行任务,获得任务的候选用户们
 | 
			
		||||
     * 基于【执行任务】,获得任务的候选用户们
 | 
			
		||||
     *
 | 
			
		||||
     * @param execution 执行任务
 | 
			
		||||
     * @return 用户编号集合
 | 
			
		||||
     */
 | 
			
		||||
    default Set<Long> calculateUsers(DelegateExecution execution, String param) {
 | 
			
		||||
        Set<Long> users = calculateUsers(param);
 | 
			
		||||
        removeDisableUsers(users);
 | 
			
		||||
        return users;
 | 
			
		||||
    default Set<Long> calculateUsersByTask(DelegateExecution execution, String param) {
 | 
			
		||||
        return calculateUsers(param);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 基于流程实例,获得任务的候选用户们
 | 
			
		||||
     * 基于【流程活动】,获得任务的候选用户们
 | 
			
		||||
     * <p>
 | 
			
		||||
     * 目的:用于获取未执行节点的候选用户们
 | 
			
		||||
     *
 | 
			
		||||
     * @param startUserId  流程发起人编号
 | 
			
		||||
     * @param processInstance 流程实例编号
 | 
			
		||||
     * @param activityId 活动 Id (对应 Bpmn XML id)
 | 
			
		||||
     * @param bpmnModel 流程图
 | 
			
		||||
     * @param activityId 活动 ID (对应 Bpmn XML id)
 | 
			
		||||
     * @param param     节点的参数
 | 
			
		||||
     * @param startUserId  流程发起人编号
 | 
			
		||||
     * @param processDefinitionId 流程定义编号
 | 
			
		||||
     * @param processVariables 流程变量
 | 
			
		||||
     * @return 用户编号集合
 | 
			
		||||
     */
 | 
			
		||||
    default Set<Long> calculateUsers(Long startUserId, ProcessInstance processInstance, String activityId, String param) {
 | 
			
		||||
        Set<Long> users = calculateUsers(param);
 | 
			
		||||
        removeDisableUsers(users);
 | 
			
		||||
        return users;
 | 
			
		||||
    @SuppressWarnings("unused")
 | 
			
		||||
    default Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
 | 
			
		||||
                                               Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
 | 
			
		||||
        return calculateUsers(param);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 移除被禁用的用户
 | 
			
		||||
     *
 | 
			
		||||
     * @param users 用户 Ids
 | 
			
		||||
     */
 | 
			
		||||
    void removeDisableUsers(Set<Long> users);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,37 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * {@link BpmTaskCandidateStrategy} 抽象类
 | 
			
		||||
 *
 | 
			
		||||
 * @author jason
 | 
			
		||||
 */
 | 
			
		||||
public abstract class BpmTaskCandidateAbstractStrategy implements BpmTaskCandidateStrategy {
 | 
			
		||||
 | 
			
		||||
    protected AdminUserApi adminUserApi;
 | 
			
		||||
 | 
			
		||||
    public BpmTaskCandidateAbstractStrategy(AdminUserApi adminUserApi) {
 | 
			
		||||
        this.adminUserApi = adminUserApi;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void removeDisableUsers(Set<Long> users) {
 | 
			
		||||
        if (CollUtil.isEmpty(users)) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(users);
 | 
			
		||||
        users.removeIf(id -> {
 | 
			
		||||
            AdminUserRespDTO user = userMap.get(id);
 | 
			
		||||
            return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus());
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,92 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.lang.Assert;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import org.flowable.engine.delegate.DelegateExecution;
 | 
			
		||||
import org.flowable.engine.runtime.ProcessInstance;
 | 
			
		||||
import org.springframework.context.annotation.Lazy;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import static cn.hutool.core.collection.ListUtil.toList;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 发起人连续多级部门的负责人 {@link BpmTaskCandidateStrategy} 实现类
 | 
			
		||||
 *
 | 
			
		||||
 * @author jason
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class BpmTaskCandidateStartUserDeptLeaderMultiStrategy extends BpmTaskCandidateAbstractDeptLeaderStrategy {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    @Lazy
 | 
			
		||||
    private BpmProcessInstanceService processInstanceService;
 | 
			
		||||
 | 
			
		||||
    public BpmTaskCandidateStartUserDeptLeaderMultiStrategy(AdminUserApi adminUserApi, DeptApi deptApi) {
 | 
			
		||||
        super(adminUserApi, deptApi);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public BpmTaskCandidateStrategyEnum getStrategy() {
 | 
			
		||||
        return BpmTaskCandidateStrategyEnum.START_USER_DEPT_LEADER_MULTI;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void validateParam(String param) {
 | 
			
		||||
        // 参数是部门的层级
 | 
			
		||||
        Assert.isTrue(Integer.parseInt(param) > 0, "部门的层级必须大于 0");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<Long> calculateUsers(DelegateExecution execution, String param) {
 | 
			
		||||
        // 获得流程发起人
 | 
			
		||||
        ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
 | 
			
		||||
        Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId());
 | 
			
		||||
        // 获取发起人的 multi 部门负责人
 | 
			
		||||
        DeptRespDTO dept = getStartUserDept(startUserId);
 | 
			
		||||
        if (dept == null) {
 | 
			
		||||
            return new HashSet<>();
 | 
			
		||||
        }
 | 
			
		||||
        Set<Long> users = getMultiLevelDeptLeaderIds(toList(dept.getId()), Integer.valueOf(param)); // 参数是部门的层级
 | 
			
		||||
        // TODO @jason:这里 removeDisableUsers 的原因是啥呀?
 | 
			
		||||
        // TODO @芋艿 calculateUsers(execution, param)  calculateUsers(startUserId, processInstance, activityId, param) 现在这两个方法, 默认都移除了被禁用的用户
 | 
			
		||||
        // TODO @芋艿 因为被禁用的用户是不能审批任务。 在这里移除是不是好一点。 代码可以重用。
 | 
			
		||||
        removeDisableUsers(users);
 | 
			
		||||
        return users;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<Long> calculateUsers(Long startUserId, ProcessInstance processInstance, String activityId, String param) {
 | 
			
		||||
        DeptRespDTO dept = getStartUserDept(startUserId);
 | 
			
		||||
        if (dept == null) {
 | 
			
		||||
            return new HashSet<>();
 | 
			
		||||
        }
 | 
			
		||||
        Set<Long> users =  getMultiLevelDeptLeaderIds(toList(dept.getId()), Integer.valueOf(param)); // 参数是部门的层级
 | 
			
		||||
        removeDisableUsers(users);
 | 
			
		||||
        return users;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取发起人的部门
 | 
			
		||||
     *
 | 
			
		||||
     * @param startUserId 发起人 Id
 | 
			
		||||
     */
 | 
			
		||||
    protected DeptRespDTO getStartUserDept(Long startUserId) {
 | 
			
		||||
        AdminUserRespDTO startUser = adminUserApi.getUser(startUserId);
 | 
			
		||||
        if (startUser.getDeptId() == null) { // 找不到部门
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return deptApi.getDept(startUser.getDeptId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
import cn.hutool.core.lang.Assert;
 | 
			
		||||
@@ -6,6 +6,8 @@ import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCand
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
 | 
			
		||||
import java.util.*;
 | 
			
		||||
 | 
			
		||||
@@ -14,14 +16,12 @@ import java.util.*;
 | 
			
		||||
 *
 | 
			
		||||
 * @author jason
 | 
			
		||||
 */
 | 
			
		||||
public abstract class BpmTaskCandidateAbstractDeptLeaderStrategy extends  BpmTaskCandidateAbstractStrategy {
 | 
			
		||||
public abstract class AbstractBpmTaskCandidateDeptLeaderStrategy implements BpmTaskCandidateStrategy {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    protected DeptApi deptApi;
 | 
			
		||||
 | 
			
		||||
    public BpmTaskCandidateAbstractDeptLeaderStrategy(AdminUserApi adminUserApi, DeptApi deptApi) {
 | 
			
		||||
        super(adminUserApi);
 | 
			
		||||
        this.deptApi = deptApi;
 | 
			
		||||
    }
 | 
			
		||||
    @Resource
 | 
			
		||||
    protected AdminUserApi adminUserApi;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得指定层级的部门负责人,只有第 level 的负责人
 | 
			
		||||
@@ -75,4 +75,17 @@ public abstract class BpmTaskCandidateAbstractDeptLeaderStrategy extends  BpmTas
 | 
			
		||||
        return deptLeaderIds;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取发起人的部门
 | 
			
		||||
     *
 | 
			
		||||
     * @param startUserId 发起人 Id
 | 
			
		||||
     */
 | 
			
		||||
    protected DeptRespDTO getStartUserDept(Long startUserId) {
 | 
			
		||||
        AdminUserRespDTO startUser = adminUserApi.getUser(startUserId);
 | 
			
		||||
        if (startUser.getDeptId() == null) { // 找不到部门
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return deptApi.getDept(startUser.getDeptId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,13 +1,12 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.lang.Assert;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -16,11 +15,7 @@ import java.util.Set;
 | 
			
		||||
 * @author jason
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class BpmTaskCandidateDeptLeaderMultiStrategy extends BpmTaskCandidateAbstractDeptLeaderStrategy {
 | 
			
		||||
 | 
			
		||||
    public BpmTaskCandidateDeptLeaderMultiStrategy(AdminUserApi adminUserApi, DeptApi deptApi) {
 | 
			
		||||
        super(adminUserApi, deptApi);
 | 
			
		||||
    }
 | 
			
		||||
public class BpmTaskCandidateDeptLeaderMultiStrategy extends AbstractBpmTaskCandidateDeptLeaderStrategy {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public BpmTaskCandidateStrategyEnum getStrategy() {
 | 
			
		||||
@@ -32,14 +27,19 @@ public class BpmTaskCandidateDeptLeaderMultiStrategy extends BpmTaskCandidateAbs
 | 
			
		||||
        // 参数格式: | 分隔:1)左边为部门(多个部门用 , 分隔)。2)右边为部门层级
 | 
			
		||||
        String[] params = param.split("\\|");
 | 
			
		||||
        Assert.isTrue(params.length == 2, "参数格式不匹配");
 | 
			
		||||
        deptApi.validateDeptList(StrUtils.splitToLong(params[0], ","));
 | 
			
		||||
        Assert.isTrue(Integer.parseInt(params[1]) > 0, "部门层级必须大于 0");
 | 
			
		||||
        List<Long> deptIds = StrUtils.splitToLong(params[0], ",");
 | 
			
		||||
        int level = Integer.parseInt(params[1]);
 | 
			
		||||
        // 校验部门存在
 | 
			
		||||
        deptApi.validateDeptList(deptIds);
 | 
			
		||||
        Assert.isTrue(level > 0, "部门层级必须大于 0");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<Long> calculateUsers(String param) {
 | 
			
		||||
        String[] params = param.split("\\|");
 | 
			
		||||
        return getMultiLevelDeptLeaderIds(StrUtils.splitToLong(params[0], ","), Integer.valueOf(params[1]));
 | 
			
		||||
        List<Long> deptIds = StrUtils.splitToLong(params[0], ",");
 | 
			
		||||
        int level = Integer.parseInt(params[1]);
 | 
			
		||||
        return super.getMultiLevelDeptLeaderIds(deptIds, level);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,11 +1,11 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -19,14 +19,10 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
 | 
			
		||||
 * @author kyle
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class BpmTaskCandidateDeptLeaderStrategy extends BpmTaskCandidateAbstractStrategy {
 | 
			
		||||
public class BpmTaskCandidateDeptLeaderStrategy implements BpmTaskCandidateStrategy {
 | 
			
		||||
 | 
			
		||||
    private final DeptApi deptApi;
 | 
			
		||||
 | 
			
		||||
    public BpmTaskCandidateDeptLeaderStrategy(AdminUserApi adminUserApi, DeptApi deptApi) {
 | 
			
		||||
        super(adminUserApi);
 | 
			
		||||
        this.deptApi = deptApi;
 | 
			
		||||
    }
 | 
			
		||||
    @Resource
 | 
			
		||||
    private DeptApi deptApi;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public BpmTaskCandidateStrategyEnum getStrategy() {
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
 | 
			
		||||
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidat
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -19,14 +20,12 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
 | 
			
		||||
 * @author kyle
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class BpmTaskCandidateDeptMemberStrategy extends BpmTaskCandidateAbstractStrategy {
 | 
			
		||||
public class BpmTaskCandidateDeptMemberStrategy implements BpmTaskCandidateStrategy {
 | 
			
		||||
 | 
			
		||||
    private final DeptApi deptApi;
 | 
			
		||||
 | 
			
		||||
    public BpmTaskCandidateDeptMemberStrategy(AdminUserApi adminUserApi, DeptApi deptApi) {
 | 
			
		||||
        super(adminUserApi);
 | 
			
		||||
        this.deptApi = deptApi;
 | 
			
		||||
    }
 | 
			
		||||
    @Resource
 | 
			
		||||
    private DeptApi deptApi;
 | 
			
		||||
    @Resource
 | 
			
		||||
    private AdminUserApi adminUserApi;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public BpmTaskCandidateStrategyEnum getStrategy() {
 | 
			
		||||
@@ -0,0 +1,70 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.lang.Assert;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import org.flowable.bpmn.model.BpmnModel;
 | 
			
		||||
import org.flowable.engine.delegate.DelegateExecution;
 | 
			
		||||
import org.flowable.engine.runtime.ProcessInstance;
 | 
			
		||||
import org.springframework.context.annotation.Lazy;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import static cn.hutool.core.collection.ListUtil.toList;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 发起人连续多级部门的负责人 {@link BpmTaskCandidateStrategy} 实现类
 | 
			
		||||
 *
 | 
			
		||||
 * @author jason
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class BpmTaskCandidateStartUserDeptLeaderMultiStrategy extends AbstractBpmTaskCandidateDeptLeaderStrategy {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    @Lazy
 | 
			
		||||
    private BpmProcessInstanceService processInstanceService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public BpmTaskCandidateStrategyEnum getStrategy() {
 | 
			
		||||
        return BpmTaskCandidateStrategyEnum.START_USER_DEPT_LEADER_MULTI;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void validateParam(String param) {
 | 
			
		||||
        int level = Integer.parseInt(param); // 参数是部门的层级
 | 
			
		||||
        Assert.isTrue(level > 0, "部门的层级必须大于 0");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<Long> calculateUsersByTask(DelegateExecution execution, String param) {
 | 
			
		||||
        int level = Integer.parseInt(param); // 参数是部门的层级
 | 
			
		||||
        // 获得流程发起人
 | 
			
		||||
        ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
 | 
			
		||||
        Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId());
 | 
			
		||||
        // 获取发起人的 multi 部门负责人
 | 
			
		||||
        DeptRespDTO dept = super.getStartUserDept(startUserId);
 | 
			
		||||
        if (dept == null) {
 | 
			
		||||
            return new HashSet<>();
 | 
			
		||||
        }
 | 
			
		||||
        return super.getMultiLevelDeptLeaderIds(toList(dept.getId()), level);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
 | 
			
		||||
                                              Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
 | 
			
		||||
        int level = Integer.parseInt(param); // 参数是部门的层级
 | 
			
		||||
        DeptRespDTO dept = super.getStartUserDept(startUserId);
 | 
			
		||||
        if (dept == null) {
 | 
			
		||||
            return new HashSet<>();
 | 
			
		||||
        }
 | 
			
		||||
        return super.getMultiLevelDeptLeaderIds(toList(dept.getId()), level);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,21 +1,20 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.lang.Assert;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import org.flowable.bpmn.model.BpmnModel;
 | 
			
		||||
import org.flowable.engine.delegate.DelegateExecution;
 | 
			
		||||
import org.flowable.engine.runtime.ProcessInstance;
 | 
			
		||||
import org.springframework.context.annotation.Lazy;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
 | 
			
		||||
@@ -26,7 +25,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
 | 
			
		||||
 * @author jason
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class BpmTaskCandidateStartUserDeptLeaderStrategy extends BpmTaskCandidateAbstractDeptLeaderStrategy {
 | 
			
		||||
public class BpmTaskCandidateStartUserDeptLeaderStrategy extends AbstractBpmTaskCandidateDeptLeaderStrategy {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    @Lazy // 避免循环依赖
 | 
			
		||||
@@ -37,10 +36,6 @@ public class BpmTaskCandidateStartUserDeptLeaderStrategy extends BpmTaskCandidat
 | 
			
		||||
        return BpmTaskCandidateStrategyEnum.START_USER_DEPT_LEADER;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BpmTaskCandidateStartUserDeptLeaderStrategy(AdminUserApi adminUserApi, DeptApi deptApi) {
 | 
			
		||||
        super(adminUserApi, deptApi);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void validateParam(String param) {
 | 
			
		||||
        // 参数是部门的层级
 | 
			
		||||
@@ -48,44 +43,29 @@ public class BpmTaskCandidateStartUserDeptLeaderStrategy extends BpmTaskCandidat
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<Long> calculateUsers(DelegateExecution execution, String param) {
 | 
			
		||||
    public Set<Long> calculateUsersByTask(DelegateExecution execution, String param) {
 | 
			
		||||
        // 获得流程发起人
 | 
			
		||||
        ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
 | 
			
		||||
        Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId());
 | 
			
		||||
        // 获取发起人的部门负责人
 | 
			
		||||
        Set<Long> users = getStartUserDeptLeader(startUserId, param);
 | 
			
		||||
        removeDisableUsers(users);
 | 
			
		||||
        return users;
 | 
			
		||||
        return getStartUserDeptLeader(startUserId, param);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<Long> calculateUsers(Long startUserId, ProcessInstance processInstance, String activityId, String param) {
 | 
			
		||||
    public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
 | 
			
		||||
                                              Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
 | 
			
		||||
        // 获取发起人的部门负责人
 | 
			
		||||
        Set<Long> users =  getStartUserDeptLeader(startUserId, param);
 | 
			
		||||
        removeDisableUsers(users);
 | 
			
		||||
        return users;
 | 
			
		||||
        return getStartUserDeptLeader(startUserId, param);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Set<Long> getStartUserDeptLeader(Long startUserId, String param) {
 | 
			
		||||
        DeptRespDTO dept = getStartUserDept(startUserId);
 | 
			
		||||
        int level = Integer.parseInt(param); // 参数是部门的层级
 | 
			
		||||
        DeptRespDTO dept = super.getStartUserDept(startUserId);
 | 
			
		||||
        if (dept == null) {
 | 
			
		||||
            return new HashSet<>();
 | 
			
		||||
        }
 | 
			
		||||
        Long deptLeaderId = getAssignLevelDeptLeaderId(dept, Integer.valueOf(param)); // 参数是部门的层级
 | 
			
		||||
        Long deptLeaderId = super.getAssignLevelDeptLeaderId(dept, level);
 | 
			
		||||
        return deptLeaderId != null ? asSet(deptLeaderId) : new HashSet<>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取发起人的部门
 | 
			
		||||
     *
 | 
			
		||||
     * @param startUserId 发起人 Id
 | 
			
		||||
     */
 | 
			
		||||
    protected DeptRespDTO getStartUserDept(Long startUserId) {
 | 
			
		||||
        AdminUserRespDTO startUser = adminUserApi.getUser(startUserId);
 | 
			
		||||
        if (startUser.getDeptId() == null) { // 找不到部门
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return deptApi.getDept(startUser.getDeptId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,12 +1,13 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
import cn.hutool.core.lang.Assert;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user.BpmTaskCandidateUserStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
import com.google.common.collect.Sets;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import org.flowable.bpmn.model.BpmnModel;
 | 
			
		||||
import org.flowable.bpmn.model.UserTask;
 | 
			
		||||
@@ -23,16 +24,12 @@ import java.util.*;
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class BpmTaskCandidateStartUserSelectStrategy extends BpmTaskCandidateAbstractStrategy {
 | 
			
		||||
public class BpmTaskCandidateStartUserSelectStrategy extends AbstractBpmTaskCandidateDeptLeaderStrategy {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    @Lazy // 延迟加载,避免循环依赖
 | 
			
		||||
    private BpmProcessInstanceService processInstanceService;
 | 
			
		||||
 | 
			
		||||
    public BpmTaskCandidateStartUserSelectStrategy(AdminUserApi adminUserApi) {
 | 
			
		||||
        super(adminUserApi);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public BpmTaskCandidateStrategyEnum getStrategy() {
 | 
			
		||||
        return BpmTaskCandidateStrategyEnum.START_USER_SELECT;
 | 
			
		||||
@@ -42,7 +39,12 @@ public class BpmTaskCandidateStartUserSelectStrategy extends BpmTaskCandidateAbs
 | 
			
		||||
    public void validateParam(String param) {}
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<Long> calculateUsers(DelegateExecution execution, String param) {
 | 
			
		||||
    public boolean isParamRequired() {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public LinkedHashSet<Long> calculateUsersByTask(DelegateExecution execution, String param) {
 | 
			
		||||
        ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
 | 
			
		||||
        Assert.notNull(processInstance, "流程实例({})不能为空", execution.getProcessInstanceId());
 | 
			
		||||
        Map<String, List<Long>> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance);
 | 
			
		||||
@@ -50,28 +52,22 @@ public class BpmTaskCandidateStartUserSelectStrategy extends BpmTaskCandidateAbs
 | 
			
		||||
                execution.getProcessInstanceId());
 | 
			
		||||
        // 获得审批人
 | 
			
		||||
        List<Long> assignees = startUserSelectAssignees.get(execution.getCurrentActivityId());
 | 
			
		||||
        Set<Long> users = new LinkedHashSet<>(assignees);
 | 
			
		||||
        removeDisableUsers(users);
 | 
			
		||||
        return users;
 | 
			
		||||
        return new LinkedHashSet<>(assignees);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<Long> calculateUsers(Long startUserId, ProcessInstance processInstance, String activityId, String param) {
 | 
			
		||||
        if (processInstance == null) {
 | 
			
		||||
            return Collections.emptySet();
 | 
			
		||||
    public LinkedHashSet<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
 | 
			
		||||
                                                        Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
 | 
			
		||||
        if (processVariables == null) {
 | 
			
		||||
            return Sets.newLinkedHashSet();
 | 
			
		||||
        }
 | 
			
		||||
        Map<String, List<Long>> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processVariables);
 | 
			
		||||
        if (startUserSelectAssignees == null) {
 | 
			
		||||
            return Sets.newLinkedHashSet();
 | 
			
		||||
        }
 | 
			
		||||
        Map<String, List<Long>> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance);
 | 
			
		||||
        Assert.notNull(startUserSelectAssignees, "流程实例({}) 的发起人自选审批人不能为空", processInstance.getId());
 | 
			
		||||
        // 获得审批人
 | 
			
		||||
        List<Long> assignees = startUserSelectAssignees.get(activityId);
 | 
			
		||||
        Set<Long> users = new LinkedHashSet<>(assignees);
 | 
			
		||||
        removeDisableUsers(users);
 | 
			
		||||
        return users;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean isParamRequired() {
 | 
			
		||||
        return false;
 | 
			
		||||
        return new LinkedHashSet<>(assignees);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.other;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.lang.Assert;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
 | 
			
		||||
@@ -7,13 +7,15 @@ import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCand
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import org.flowable.bpmn.model.BpmnModel;
 | 
			
		||||
import org.flowable.bpmn.model.FlowElement;
 | 
			
		||||
import org.flowable.engine.delegate.DelegateExecution;
 | 
			
		||||
import org.springframework.context.annotation.Lazy;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
@@ -23,16 +25,12 @@ import java.util.Set;
 | 
			
		||||
 * @author kyle
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class BpmTaskCandidateAssignEmptyStrategy extends BpmTaskCandidateAbstractStrategy {
 | 
			
		||||
public class BpmTaskCandidateAssignEmptyStrategy implements BpmTaskCandidateStrategy {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    @Lazy // 延迟加载,避免循环依赖
 | 
			
		||||
    private BpmProcessDefinitionService processDefinitionService;
 | 
			
		||||
 | 
			
		||||
    public BpmTaskCandidateAssignEmptyStrategy(AdminUserApi adminUserApi) {
 | 
			
		||||
        super(adminUserApi);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public BpmTaskCandidateStrategyEnum getStrategy() {
 | 
			
		||||
        return BpmTaskCandidateStrategyEnum.ASSIGN_EMPTY;
 | 
			
		||||
@@ -43,19 +41,28 @@ public class BpmTaskCandidateAssignEmptyStrategy extends BpmTaskCandidateAbstrac
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<Long> calculateUsers(DelegateExecution execution, String param) {
 | 
			
		||||
    public Set<Long> calculateUsersByTask(DelegateExecution execution, String param) {
 | 
			
		||||
        return getCandidateUsers(execution.getProcessDefinitionId(), execution.getCurrentFlowElement());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
 | 
			
		||||
                                              Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
 | 
			
		||||
        FlowElement flowElement = BpmnModelUtils.getFlowElementById(bpmnModel, activityId);
 | 
			
		||||
        return getCandidateUsers(processDefinitionId, flowElement);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Set<Long> getCandidateUsers(String processDefinitionId, FlowElement flowElement) {
 | 
			
		||||
        // 情况一:指定人员审批
 | 
			
		||||
        Integer assignEmptyHandlerType = BpmnModelUtils.parseAssignEmptyHandlerType(execution.getCurrentFlowElement());
 | 
			
		||||
        Integer assignEmptyHandlerType = BpmnModelUtils.parseAssignEmptyHandlerType(flowElement);
 | 
			
		||||
        if (Objects.equals(assignEmptyHandlerType, BpmUserTaskAssignEmptyHandlerTypeEnum.ASSIGN_USER.getType())) {
 | 
			
		||||
            Set<Long> users = new HashSet<>(BpmnModelUtils.parseAssignEmptyHandlerUserIds(execution.getCurrentFlowElement()));
 | 
			
		||||
            removeDisableUsers(users);
 | 
			
		||||
            return users;
 | 
			
		||||
            return new HashSet<>(BpmnModelUtils.parseAssignEmptyHandlerUserIds(flowElement));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 情况二:流程管理员
 | 
			
		||||
        if (Objects.equals(assignEmptyHandlerType, BpmUserTaskAssignEmptyHandlerTypeEnum.ASSIGN_ADMIN.getType())) {
 | 
			
		||||
            BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(execution.getProcessDefinitionId());
 | 
			
		||||
            Assert.notNull(processDefinition, "流程定义({})不存在", execution.getProcessDefinitionId());
 | 
			
		||||
            BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(processDefinitionId);
 | 
			
		||||
            Assert.notNull(processDefinition, "流程定义({})不存在", processDefinitionId);
 | 
			
		||||
            return new HashSet<>(processDefinition.getManagerUserIds());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -1,13 +1,14 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.other;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.convert.Convert;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
import org.flowable.bpmn.model.BpmnModel;
 | 
			
		||||
import org.flowable.engine.delegate.DelegateExecution;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -16,11 +17,7 @@ import java.util.Set;
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class BpmTaskCandidateExpressionStrategy extends BpmTaskCandidateAbstractStrategy {
 | 
			
		||||
 | 
			
		||||
    public BpmTaskCandidateExpressionStrategy(AdminUserApi adminUserApi) {
 | 
			
		||||
        super(adminUserApi);
 | 
			
		||||
    }
 | 
			
		||||
public class BpmTaskCandidateExpressionStrategy implements BpmTaskCandidateStrategy {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public BpmTaskCandidateStrategyEnum getStrategy() {
 | 
			
		||||
@@ -33,11 +30,16 @@ public class BpmTaskCandidateExpressionStrategy extends BpmTaskCandidateAbstract
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<Long> calculateUsers(DelegateExecution execution, String param) {
 | 
			
		||||
    public Set<Long> calculateUsersByTask(DelegateExecution execution, String param) {
 | 
			
		||||
        Object result = FlowableUtils.getExpressionValue(execution, param);
 | 
			
		||||
        Set<Long> users = Convert.toSet(Long.class, result);
 | 
			
		||||
        removeDisableUsers(users);
 | 
			
		||||
        return users;
 | 
			
		||||
        return Convert.toSet(Long.class, result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
 | 
			
		||||
                                              Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
 | 
			
		||||
        Object result = FlowableUtils.getExpressionValue(processVariables, param);
 | 
			
		||||
        return Convert.toSet(Long.class, result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,11 +1,11 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
@@ -20,14 +20,10 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
 | 
			
		||||
 * @author kyle
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class BpmTaskCandidateGroupStrategy extends BpmTaskCandidateAbstractStrategy {
 | 
			
		||||
public class BpmTaskCandidateGroupStrategy implements BpmTaskCandidateStrategy {
 | 
			
		||||
 | 
			
		||||
    private final BpmUserGroupService userGroupService;
 | 
			
		||||
 | 
			
		||||
    public BpmTaskCandidateGroupStrategy(AdminUserApi adminUserApi, BpmUserGroupService userGroupService) {
 | 
			
		||||
        super(adminUserApi);
 | 
			
		||||
        this.userGroupService = userGroupService;
 | 
			
		||||
    }
 | 
			
		||||
    @Resource
 | 
			
		||||
    private BpmUserGroupService userGroupService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public BpmTaskCandidateStrategyEnum getStrategy() {
 | 
			
		||||
@@ -37,7 +33,7 @@ public class BpmTaskCandidateGroupStrategy extends BpmTaskCandidateAbstractStrat
 | 
			
		||||
    @Override
 | 
			
		||||
    public void validateParam(String param) {
 | 
			
		||||
        Set<Long> groupIds = StrUtils.splitToLongSet(param);
 | 
			
		||||
        userGroupService.getUserGroupList(groupIds);
 | 
			
		||||
        userGroupService.validUserGroups(groupIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
 | 
			
		||||
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidat
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.PostApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -19,14 +20,12 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
 | 
			
		||||
 * @author kyle
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class BpmTaskCandidatePostStrategy extends BpmTaskCandidateAbstractStrategy {
 | 
			
		||||
public class BpmTaskCandidatePostStrategy implements BpmTaskCandidateStrategy {
 | 
			
		||||
 | 
			
		||||
    private final PostApi postApi;
 | 
			
		||||
 | 
			
		||||
    public BpmTaskCandidatePostStrategy(AdminUserApi adminUserApi, PostApi postApi) {
 | 
			
		||||
        super(adminUserApi);
 | 
			
		||||
        this.postApi = postApi;
 | 
			
		||||
    }
 | 
			
		||||
    @Resource
 | 
			
		||||
    private PostApi postApi;
 | 
			
		||||
    @Resource
 | 
			
		||||
    private AdminUserApi adminUserApi;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public BpmTaskCandidateStrategyEnum getStrategy() {
 | 
			
		||||
@@ -1,11 +1,10 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.permission.RoleApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
@@ -17,17 +16,13 @@ import java.util.Set;
 | 
			
		||||
 * @author kyle
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class BpmTaskCandidateRoleStrategy extends BpmTaskCandidateAbstractStrategy {
 | 
			
		||||
public class BpmTaskCandidateRoleStrategy implements BpmTaskCandidateStrategy {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private RoleApi roleApi;
 | 
			
		||||
    @Resource
 | 
			
		||||
    private PermissionApi permissionApi;
 | 
			
		||||
 | 
			
		||||
    public BpmTaskCandidateRoleStrategy(AdminUserApi adminUserApi) {
 | 
			
		||||
        super(adminUserApi);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public BpmTaskCandidateStrategyEnum getStrategy() {
 | 
			
		||||
        return BpmTaskCandidateStrategyEnum.ROLE;
 | 
			
		||||
@@ -1,15 +1,17 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import org.flowable.bpmn.model.BpmnModel;
 | 
			
		||||
import org.flowable.engine.delegate.DelegateExecution;
 | 
			
		||||
import org.flowable.engine.runtime.ProcessInstance;
 | 
			
		||||
import org.springframework.context.annotation.Lazy;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -20,16 +22,12 @@ import java.util.Set;
 | 
			
		||||
 * @author jason
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class BpmTaskCandidateStartUserStrategy extends BpmTaskCandidateAbstractStrategy {
 | 
			
		||||
public class BpmTaskCandidateStartUserStrategy implements BpmTaskCandidateStrategy {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    @Lazy // 延迟加载,避免循环依赖
 | 
			
		||||
    private BpmProcessInstanceService processInstanceService;
 | 
			
		||||
 | 
			
		||||
    public BpmTaskCandidateStartUserStrategy(AdminUserApi adminUserApi) {
 | 
			
		||||
        super(adminUserApi);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public BpmTaskCandidateStrategyEnum getStrategy() {
 | 
			
		||||
        return BpmTaskCandidateStrategyEnum.START_USER;
 | 
			
		||||
@@ -45,18 +43,15 @@ public class BpmTaskCandidateStartUserStrategy extends BpmTaskCandidateAbstractS
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<Long> calculateUsers(DelegateExecution execution, String param) {
 | 
			
		||||
    public Set<Long> calculateUsersByTask(DelegateExecution execution, String param) {
 | 
			
		||||
        ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
 | 
			
		||||
        Set<Long> users =  SetUtils.asSet(Long.valueOf(processInstance.getStartUserId()));
 | 
			
		||||
        removeDisableUsers(users);
 | 
			
		||||
        return users;
 | 
			
		||||
        return SetUtils.asSet(Long.valueOf(processInstance.getStartUserId()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<Long> calculateUsers(Long startUserId, ProcessInstance processInstance, String activityId, String param) {
 | 
			
		||||
        Set<Long> users = SetUtils.asSet(startUserId);
 | 
			
		||||
        removeDisableUsers(users);
 | 
			
		||||
        return users;
 | 
			
		||||
    public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
 | 
			
		||||
                                              Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
 | 
			
		||||
        return SetUtils.asSet(startUserId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,14 +1,14 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.text.StrPool;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
import java.util.LinkedHashSet;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 用户 {@link BpmTaskCandidateStrategy} 实现类
 | 
			
		||||
@@ -16,11 +16,10 @@ import java.util.Set;
 | 
			
		||||
 * @author kyle
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class BpmTaskCandidateUserStrategy extends BpmTaskCandidateAbstractStrategy {
 | 
			
		||||
public class BpmTaskCandidateUserStrategy implements BpmTaskCandidateStrategy {
 | 
			
		||||
 | 
			
		||||
    public BpmTaskCandidateUserStrategy(AdminUserApi adminUserApi) {
 | 
			
		||||
        super(adminUserApi);
 | 
			
		||||
    }
 | 
			
		||||
    @Resource
 | 
			
		||||
    private AdminUserApi adminUserApi;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public BpmTaskCandidateStrategyEnum getStrategy() {
 | 
			
		||||
@@ -33,7 +32,7 @@ public class BpmTaskCandidateUserStrategy extends BpmTaskCandidateAbstractStrate
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<Long> calculateUsers(String param) {
 | 
			
		||||
    public LinkedHashSet<Long> calculateUsers(String param) {
 | 
			
		||||
        return new LinkedHashSet<>(StrUtils.splitToLong(param, StrPool.COMMA));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -34,7 +34,7 @@ public class BpmCopyTaskDelegate implements JavaDelegate {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void execute(DelegateExecution execution) {
 | 
			
		||||
        // 1. 获得抄送人
 | 
			
		||||
        Set<Long> userIds = taskCandidateInvoker.calculateUsers(execution);
 | 
			
		||||
        Set<Long> userIds = taskCandidateInvoker.calculateUsersByTask(execution);
 | 
			
		||||
        if (CollUtil.isEmpty(userIds)) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,6 @@ import cn.hutool.core.map.MapUtil;
 | 
			
		||||
import cn.hutool.core.util.ArrayUtil;
 | 
			
		||||
import cn.hutool.core.util.ObjUtil;
 | 
			
		||||
import cn.hutool.core.util.StrUtil;
 | 
			
		||||
import cn.hutool.extra.spring.SpringUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
 | 
			
		||||
@@ -23,7 +22,6 @@ import org.flowable.bpmn.model.Process;
 | 
			
		||||
import org.flowable.bpmn.model.*;
 | 
			
		||||
import org.flowable.common.engine.api.FlowableException;
 | 
			
		||||
import org.flowable.common.engine.impl.util.io.BytesStreamSource;
 | 
			
		||||
import org.flowable.engine.ManagementService;
 | 
			
		||||
 | 
			
		||||
import java.util.*;
 | 
			
		||||
 | 
			
		||||
@@ -773,20 +771,16 @@ public class BpmnModelUtils {
 | 
			
		||||
     * @return 是否满足条件
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean evalConditionExpress(Map<String, Object> variables, String express) {
 | 
			
		||||
        ManagementService managementService = SpringUtil.getBean(ManagementService.class);
 | 
			
		||||
        if (express == null) {
 | 
			
		||||
            return Boolean.FALSE;
 | 
			
		||||
        }
 | 
			
		||||
        // TODO @jason:疑问,为啥这里要在 managementService 里执行哈?
 | 
			
		||||
        Object result = managementService.executeCommand(context -> {
 | 
			
		||||
        try {
 | 
			
		||||
                return FlowableUtils.getExpressionValue(variables, express);
 | 
			
		||||
            Object result = FlowableUtils.getExpressionValue(variables, express);
 | 
			
		||||
            return Boolean.TRUE.equals(result);
 | 
			
		||||
        } catch (FlowableException ex) {
 | 
			
		||||
                log.error("[evalConditionExpress][条件表达式({}) 解析报错", express, ex);
 | 
			
		||||
            log.error("[evalConditionExpress][条件表达式({}) 变量({}) 解析报错", express, variables, ex);
 | 
			
		||||
            return Boolean.FALSE;
 | 
			
		||||
        }
 | 
			
		||||
        });
 | 
			
		||||
        return Boolean.TRUE.equals(result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @SuppressWarnings("PatternVariableCanBeUsed")
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.util;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.util.ObjectUtil;
 | 
			
		||||
import cn.hutool.extra.spring.SpringUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
 | 
			
		||||
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
 | 
			
		||||
@@ -9,6 +10,7 @@ import org.flowable.common.engine.api.variable.VariableContainer;
 | 
			
		||||
import org.flowable.common.engine.impl.el.ExpressionManager;
 | 
			
		||||
import org.flowable.common.engine.impl.identity.Authentication;
 | 
			
		||||
import org.flowable.common.engine.impl.variable.MapDelegateVariableContainer;
 | 
			
		||||
import org.flowable.engine.ManagementService;
 | 
			
		||||
import org.flowable.engine.ProcessEngineConfiguration;
 | 
			
		||||
import org.flowable.engine.history.HistoricProcessInstance;
 | 
			
		||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
 | 
			
		||||
@@ -146,9 +148,22 @@ public class FlowableUtils {
 | 
			
		||||
     * @param processInstance 流程实例
 | 
			
		||||
     * @return 发起用户选择的审批人 Map
 | 
			
		||||
     */
 | 
			
		||||
    @SuppressWarnings("unchecked")
 | 
			
		||||
    public static Map<String, List<Long>> getStartUserSelectAssignees(ProcessInstance processInstance) {
 | 
			
		||||
        return (Map<String, List<Long>>) processInstance.getProcessVariables().get(
 | 
			
		||||
        return processInstance != null ? getStartUserSelectAssignees(processInstance.getProcessVariables()) : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得流程实例的发起用户选择的审批人 Map
 | 
			
		||||
     *
 | 
			
		||||
     * @param processVariables 流程变量
 | 
			
		||||
     * @return 发起用户选择的审批人 Map
 | 
			
		||||
     */
 | 
			
		||||
    @SuppressWarnings("unchecked")
 | 
			
		||||
    public static Map<String, List<Long>> getStartUserSelectAssignees(Map<String, Object> processVariables) {
 | 
			
		||||
        if (processVariables == null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return (Map<String, List<Long>>) processVariables.get(
 | 
			
		||||
                BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -202,8 +217,8 @@ public class FlowableUtils {
 | 
			
		||||
 | 
			
		||||
    // ========== Expression 相关的工具方法 ==========
 | 
			
		||||
 | 
			
		||||
    public static Object getExpressionValue(VariableContainer variableContainer, String expressionString) {
 | 
			
		||||
        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
 | 
			
		||||
    private static Object getExpressionValue(VariableContainer variableContainer, String expressionString,
 | 
			
		||||
                                             ProcessEngineConfigurationImpl processEngineConfiguration) {
 | 
			
		||||
        assert processEngineConfiguration!= null;
 | 
			
		||||
        ExpressionManager expressionManager = processEngineConfiguration.getExpressionManager();
 | 
			
		||||
        assert expressionManager!= null;
 | 
			
		||||
@@ -211,9 +226,20 @@ public class FlowableUtils {
 | 
			
		||||
        return expression.getValue(variableContainer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Object getExpressionValue(VariableContainer variableContainer, String expressionString) {
 | 
			
		||||
        ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
 | 
			
		||||
        if (processEngineConfiguration != null) {
 | 
			
		||||
            return getExpressionValue(variableContainer, expressionString, processEngineConfiguration);
 | 
			
		||||
        }
 | 
			
		||||
        // 如果 ProcessEngineConfigurationImpl 获取不到,则需要通过 ManagementService 来获取
 | 
			
		||||
        ManagementService managementService = SpringUtil.getBean(ManagementService.class);
 | 
			
		||||
        assert managementService != null;
 | 
			
		||||
        return managementService.executeCommand(context ->
 | 
			
		||||
                getExpressionValue(variableContainer, expressionString, CommandContextUtil.getProcessEngineConfiguration()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Object getExpressionValue(Map<String, Object> variable, String expressionString) {
 | 
			
		||||
        VariableContainer variableContainer = new MapDelegateVariableContainer(variable,
 | 
			
		||||
                VariableContainer.empty());
 | 
			
		||||
        VariableContainer variableContainer = new MapDelegateVariableContainer(variable, VariableContainer.empty());
 | 
			
		||||
        return getExpressionValue(variableContainer, expressionString);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate;
 | 
			
		||||
import cn.hutool.core.map.MapUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateUserStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user.BpmTaskCandidateUserStrategy;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
@@ -47,13 +47,13 @@ public class BpmTaskCandidateInvokerTest extends BaseMockitoUnitTest {
 | 
			
		||||
 | 
			
		||||
    @BeforeEach
 | 
			
		||||
    public void setUp() {
 | 
			
		||||
        strategy = new BpmTaskCandidateUserStrategy(adminUserApi); // 创建strategy实例
 | 
			
		||||
        strategy = new BpmTaskCandidateUserStrategy(); // 创建strategy实例
 | 
			
		||||
        strategyList = Collections.singletonList(strategy); // 创建strategyList
 | 
			
		||||
        taskCandidateInvoker = new BpmTaskCandidateInvoker(strategyList, adminUserApi);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCalculateUsers() {
 | 
			
		||||
    public void testCalculateUsersByTask() {
 | 
			
		||||
        // 准备参数
 | 
			
		||||
        String param = "1,2";
 | 
			
		||||
        DelegateExecution execution = mock(DelegateExecution.class);
 | 
			
		||||
@@ -74,7 +74,7 @@ public class BpmTaskCandidateInvokerTest extends BaseMockitoUnitTest {
 | 
			
		||||
        when(adminUserApi.getUserMap(eq(asSet(1L, 2L)))).thenReturn(userMap);
 | 
			
		||||
 | 
			
		||||
        // 调用
 | 
			
		||||
        Set<Long> results = taskCandidateInvoker.calculateUsers(execution);
 | 
			
		||||
        Set<Long> results = taskCandidateInvoker.calculateUsersByTask(execution);
 | 
			
		||||
        // 断言
 | 
			
		||||
        assertEquals(asSet(1L, 2L), results);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,43 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 | 
			
		||||
import org.assertj.core.util.Sets;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
import org.mockito.stubbing.Answer;
 | 
			
		||||
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
 | 
			
		||||
import static org.junit.jupiter.api.Assertions.assertEquals;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.any;
 | 
			
		||||
import static org.mockito.Mockito.when;
 | 
			
		||||
 | 
			
		||||
public class BpmTaskCandidateDeptLeaderMultiStrategyTest extends BaseMockitoUnitTest {
 | 
			
		||||
 | 
			
		||||
    @InjectMocks
 | 
			
		||||
    private BpmTaskCandidateDeptLeaderMultiStrategy strategy;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private DeptApi deptApi;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCalculateUsers() {
 | 
			
		||||
        // 准备参数
 | 
			
		||||
        String param = "10,20|2";
 | 
			
		||||
        // mock 方法
 | 
			
		||||
        when(deptApi.getDept(any())).thenAnswer((Answer<DeptRespDTO>) invocationOnMock -> {
 | 
			
		||||
            Long deptId = invocationOnMock.getArgument(0);
 | 
			
		||||
            return randomPojo(DeptRespDTO.class, o -> o.setId(deptId).setParentId(deptId * 100).setLeaderUserId(deptId + 1));
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // 调用
 | 
			
		||||
        Set<Long> userIds = strategy.calculateUsers(param);
 | 
			
		||||
        // 断言结果
 | 
			
		||||
        assertEquals(Sets.newLinkedHashSet(11L, 1001L, 21L, 2001L), userIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,15 +1,16 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 | 
			
		||||
import org.assertj.core.util.Sets;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
 | 
			
		||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
 | 
			
		||||
import static java.util.Arrays.asList;
 | 
			
		||||
import static org.junit.jupiter.api.Assertions.assertEquals;
 | 
			
		||||
@@ -27,16 +28,16 @@ public class BpmTaskCandidateDeptLeaderStrategyTest extends BaseMockitoUnitTest
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCalculateUsers() {
 | 
			
		||||
        // 准备参数
 | 
			
		||||
        String param = "1,2";
 | 
			
		||||
        String param = "10,20";
 | 
			
		||||
        // mock 方法
 | 
			
		||||
        DeptRespDTO dept1 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(11L));
 | 
			
		||||
        DeptRespDTO dept2 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(22L));
 | 
			
		||||
        when(deptApi.getDeptList(eq(asSet(1L, 2L)))).thenReturn(asList(dept1, dept2));
 | 
			
		||||
        when(deptApi.getDeptList(eq(SetUtils.asSet(10L, 20L)))).thenReturn(asList(
 | 
			
		||||
                randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(10L).setLeaderUserId(11L)),
 | 
			
		||||
                randomPojo(DeptRespDTO.class, o -> o.setId(20L).setParentId(20L).setLeaderUserId(21L))));
 | 
			
		||||
 | 
			
		||||
        // 调用
 | 
			
		||||
        Set<Long> results = strategy.calculateUsers(null, param);
 | 
			
		||||
        // 断言
 | 
			
		||||
        assertEquals(asSet(11L, 22L), results);
 | 
			
		||||
        Set<Long> userIds = strategy.calculateUsers(param);
 | 
			
		||||
        // 断言结果
 | 
			
		||||
        assertEquals(Sets.newLinkedHashSet(11L, 21L), userIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,17 +1,19 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 | 
			
		||||
import org.assertj.core.util.Sets;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
 | 
			
		||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
 | 
			
		||||
import static java.util.Arrays.asList;
 | 
			
		||||
import static org.junit.jupiter.api.Assertions.assertEquals;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.eq;
 | 
			
		||||
import static org.mockito.Mockito.when;
 | 
			
		||||
@@ -21,22 +23,24 @@ public class BpmTaskCandidateDeptMemberStrategyTest extends BaseMockitoUnitTest
 | 
			
		||||
    @InjectMocks
 | 
			
		||||
    private BpmTaskCandidateDeptMemberStrategy strategy;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private DeptApi deptApi;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private AdminUserApi adminUserApi;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCalculateUsers() {
 | 
			
		||||
        // 准备参数
 | 
			
		||||
        String param = "11,22";
 | 
			
		||||
        String param = "10,20";
 | 
			
		||||
        // mock 方法
 | 
			
		||||
        List<AdminUserRespDTO> users = convertList(asSet(11L, 22L),
 | 
			
		||||
                id -> new AdminUserRespDTO().setId(id));
 | 
			
		||||
        when(adminUserApi.getUserListByDeptIds(eq(asSet(11L, 22L)))).thenReturn(users);
 | 
			
		||||
        when(adminUserApi.getUserListByDeptIds(eq(SetUtils.asSet(10L, 20L)))).thenReturn(asList(
 | 
			
		||||
                randomPojo(AdminUserRespDTO.class, o -> o.setId(11L)),
 | 
			
		||||
                randomPojo(AdminUserRespDTO.class, o -> o.setId(21L))));
 | 
			
		||||
 | 
			
		||||
        // 调用
 | 
			
		||||
        Set<Long> results = strategy.calculateUsers(null, param);
 | 
			
		||||
        // 断言
 | 
			
		||||
        assertEquals(asSet(11L, 22L), results);
 | 
			
		||||
        Set<Long> userIds = strategy.calculateUsers(param);
 | 
			
		||||
        // 断言结果
 | 
			
		||||
        assertEquals(Sets.newLinkedHashSet(11L, 21L), userIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,82 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 | 
			
		||||
import org.assertj.core.util.Sets;
 | 
			
		||||
import org.flowable.engine.delegate.DelegateExecution;
 | 
			
		||||
import org.flowable.engine.runtime.ProcessInstance;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
import org.mockito.stubbing.Answer;
 | 
			
		||||
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
 | 
			
		||||
import static org.junit.jupiter.api.Assertions.assertEquals;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.any;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.eq;
 | 
			
		||||
import static org.mockito.Mockito.mock;
 | 
			
		||||
import static org.mockito.Mockito.when;
 | 
			
		||||
 | 
			
		||||
public class BpmTaskCandidateStartUserDeptLeaderMultiStrategyTest extends BaseMockitoUnitTest {
 | 
			
		||||
 | 
			
		||||
    @InjectMocks
 | 
			
		||||
    private BpmTaskCandidateStartUserDeptLeaderMultiStrategy strategy;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private BpmProcessInstanceService processInstanceService;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private AdminUserApi adminUserApi;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private DeptApi deptApi;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCalculateUsersByTask() {
 | 
			
		||||
        // 准备参数
 | 
			
		||||
        String param = "2";
 | 
			
		||||
        // mock 方法(获得流程发起人)
 | 
			
		||||
        Long startUserId = 1L;
 | 
			
		||||
        ProcessInstance processInstance = mock(ProcessInstance.class);
 | 
			
		||||
        DelegateExecution execution = mock(DelegateExecution.class);
 | 
			
		||||
        when(processInstanceService.getProcessInstance(eq(execution.getProcessInstanceId()))).thenReturn(processInstance);
 | 
			
		||||
        when(processInstance.getStartUserId()).thenReturn(startUserId.toString());
 | 
			
		||||
        // mock 方法(获取发起人的 multi 部门负责人)
 | 
			
		||||
        mockGetStartUserDept(startUserId);
 | 
			
		||||
 | 
			
		||||
        // 调用
 | 
			
		||||
        Set<Long> userIds = strategy.calculateUsersByTask(execution, param);
 | 
			
		||||
        // 断言
 | 
			
		||||
        assertEquals(Sets.newLinkedHashSet(11L, 1001L), userIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCalculateUsersByActivity() {
 | 
			
		||||
        // 准备参数
 | 
			
		||||
        String param = "2";
 | 
			
		||||
        // mock 方法
 | 
			
		||||
        Long startUserId = 1L;
 | 
			
		||||
        mockGetStartUserDept(startUserId);
 | 
			
		||||
 | 
			
		||||
        // 调用
 | 
			
		||||
        Set<Long> userIds = strategy.calculateUsersByActivity(null, null, param,
 | 
			
		||||
                startUserId, null, null);
 | 
			
		||||
        // 断言
 | 
			
		||||
        assertEquals(Sets.newLinkedHashSet(11L, 1001L), userIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void mockGetStartUserDept(Long startUserId) {
 | 
			
		||||
        when(adminUserApi.getUser(eq(startUserId))).thenReturn(
 | 
			
		||||
                randomPojo(AdminUserRespDTO.class, o -> o.setId(startUserId).setDeptId(10L)));
 | 
			
		||||
        when(deptApi.getDept(any())).thenAnswer((Answer<DeptRespDTO>) invocationOnMock -> {
 | 
			
		||||
            Long deptId = invocationOnMock.getArgument(0);
 | 
			
		||||
            return randomPojo(DeptRespDTO.class, o -> o.setId(deptId).setParentId(deptId * 100).setLeaderUserId(deptId + 1));
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,82 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 | 
			
		||||
import org.assertj.core.util.Sets;
 | 
			
		||||
import org.flowable.engine.delegate.DelegateExecution;
 | 
			
		||||
import org.flowable.engine.runtime.ProcessInstance;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
import org.mockito.stubbing.Answer;
 | 
			
		||||
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
 | 
			
		||||
import static org.junit.jupiter.api.Assertions.assertEquals;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.any;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.eq;
 | 
			
		||||
import static org.mockito.Mockito.mock;
 | 
			
		||||
import static org.mockito.Mockito.when;
 | 
			
		||||
 | 
			
		||||
public class BpmTaskCandidateStartUserDeptLeaderStrategyTest extends BaseMockitoUnitTest {
 | 
			
		||||
 | 
			
		||||
    @InjectMocks
 | 
			
		||||
    private BpmTaskCandidateStartUserDeptLeaderStrategy strategy;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private BpmProcessInstanceService processInstanceService;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private AdminUserApi adminUserApi;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private DeptApi deptApi;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCalculateUsersByTask() {
 | 
			
		||||
        // 准备参数
 | 
			
		||||
        String param = "2";
 | 
			
		||||
        // mock 方法(获得流程发起人)
 | 
			
		||||
        Long startUserId = 1L;
 | 
			
		||||
        ProcessInstance processInstance = mock(ProcessInstance.class);
 | 
			
		||||
        DelegateExecution execution = mock(DelegateExecution.class);
 | 
			
		||||
        when(processInstanceService.getProcessInstance(eq(execution.getProcessInstanceId()))).thenReturn(processInstance);
 | 
			
		||||
        when(processInstance.getStartUserId()).thenReturn(startUserId.toString());
 | 
			
		||||
        // mock 方法(获取发起人的部门负责人)
 | 
			
		||||
        mockGetStartUserDeptLeader(startUserId);
 | 
			
		||||
 | 
			
		||||
        // 调用
 | 
			
		||||
        Set<Long> userIds = strategy.calculateUsersByTask(execution, param);
 | 
			
		||||
        // 断言
 | 
			
		||||
        assertEquals(Sets.newLinkedHashSet(1001L), userIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetStartUserDeptLeader() {
 | 
			
		||||
        // 准备参数
 | 
			
		||||
        String param = "2";
 | 
			
		||||
        // mock 方法
 | 
			
		||||
        Long startUserId = 1L;
 | 
			
		||||
        mockGetStartUserDeptLeader(startUserId);
 | 
			
		||||
 | 
			
		||||
        // 调用
 | 
			
		||||
        Set<Long> userIds = strategy.calculateUsersByActivity(null, null, param,
 | 
			
		||||
                startUserId, null, null);
 | 
			
		||||
        // 断言
 | 
			
		||||
        assertEquals(Sets.newLinkedHashSet(1001L), userIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void mockGetStartUserDeptLeader(Long startUserId) {
 | 
			
		||||
        when(adminUserApi.getUser(eq(startUserId))).thenReturn(
 | 
			
		||||
                randomPojo(AdminUserRespDTO.class, o -> o.setId(startUserId).setDeptId(10L)));
 | 
			
		||||
        when(deptApi.getDept(any())).thenAnswer((Answer<DeptRespDTO>) invocationOnMock -> {
 | 
			
		||||
            Long deptId = invocationOnMock.getArgument(0);
 | 
			
		||||
            return randomPojo(DeptRespDTO.class, o -> o.setId(deptId).setParentId(deptId * 100).setLeaderUserId(deptId + 1));
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,68 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.map.MapUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
 | 
			
		||||
import org.assertj.core.util.Sets;
 | 
			
		||||
import org.flowable.engine.delegate.DelegateExecution;
 | 
			
		||||
import org.flowable.engine.runtime.ProcessInstance;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import static org.junit.jupiter.api.Assertions.assertEquals;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.eq;
 | 
			
		||||
import static org.mockito.Mockito.mock;
 | 
			
		||||
import static org.mockito.Mockito.when;
 | 
			
		||||
 | 
			
		||||
public class BpmTaskCandidateStartUserSelectStrategyTest extends BaseMockitoUnitTest {
 | 
			
		||||
 | 
			
		||||
    @InjectMocks
 | 
			
		||||
    private BpmTaskCandidateStartUserSelectStrategy strategy;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private BpmProcessInstanceService processInstanceService;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCalculateUsersByTask() {
 | 
			
		||||
        // 准备参数
 | 
			
		||||
        String param = "2";
 | 
			
		||||
        // mock 方法(获得流程发起人)
 | 
			
		||||
        ProcessInstance processInstance = mock(ProcessInstance.class);
 | 
			
		||||
        DelegateExecution execution = mock(DelegateExecution.class);
 | 
			
		||||
        when(processInstanceService.getProcessInstance(eq(execution.getProcessInstanceId()))).thenReturn(processInstance);
 | 
			
		||||
        when(execution.getCurrentActivityId()).thenReturn("activity_001");
 | 
			
		||||
        // mock 方法(FlowableUtils)
 | 
			
		||||
        Map<String, Object> processVariables = new HashMap<>();
 | 
			
		||||
        processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES,
 | 
			
		||||
                MapUtil.of("activity_001", List.of(1L, 2L)));
 | 
			
		||||
        when(processInstance.getProcessVariables()).thenReturn(processVariables);
 | 
			
		||||
 | 
			
		||||
        // 调用
 | 
			
		||||
        Set<Long> userIds = strategy.calculateUsersByTask(execution, param);
 | 
			
		||||
        // 断言
 | 
			
		||||
        assertEquals(Sets.newLinkedHashSet(1L, 2L), userIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCalculateUsersByActivity() {
 | 
			
		||||
        // 准备参数
 | 
			
		||||
        String activityId = "activity_001";
 | 
			
		||||
        Map<String, Object> processVariables = new HashMap<>();
 | 
			
		||||
        processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES,
 | 
			
		||||
                MapUtil.of("activity_001", List.of(1L, 2L)));
 | 
			
		||||
 | 
			
		||||
        // 调用
 | 
			
		||||
        Set<Long> userIds = strategy.calculateUsersByActivity(null, activityId, null,
 | 
			
		||||
                null, null, processVariables);
 | 
			
		||||
        // 断言
 | 
			
		||||
        assertEquals(Sets.newLinkedHashSet(1L, 2L), userIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,88 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.other;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.collection.ListUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskAssignEmptyHandlerTypeEnum;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
 | 
			
		||||
import org.flowable.bpmn.model.BpmnModel;
 | 
			
		||||
import org.flowable.bpmn.model.FlowElement;
 | 
			
		||||
import org.flowable.engine.delegate.DelegateExecution;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
import org.mockito.MockedStatic;
 | 
			
		||||
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
 | 
			
		||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
 | 
			
		||||
import static org.junit.jupiter.api.Assertions.assertEquals;
 | 
			
		||||
import static org.mockito.Mockito.*;
 | 
			
		||||
 | 
			
		||||
public class BpmTaskCandidateAssignEmptyStrategyTest extends BaseMockitoUnitTest {
 | 
			
		||||
 | 
			
		||||
    @InjectMocks
 | 
			
		||||
    private BpmTaskCandidateAssignEmptyStrategy strategy;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private BpmProcessDefinitionService processDefinitionService;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCalculateUsersByTask() {
 | 
			
		||||
        try (MockedStatic<FlowableUtils> flowableUtilMockedStatic = mockStatic(FlowableUtils.class);
 | 
			
		||||
             MockedStatic<BpmnModelUtils> bpmnModelUtilsMockedStatic = mockStatic(BpmnModelUtils.class)) {
 | 
			
		||||
            // 准备参数
 | 
			
		||||
            DelegateExecution execution = mock(DelegateExecution.class);
 | 
			
		||||
            String param = randomString();
 | 
			
		||||
            // mock 方法(execution)
 | 
			
		||||
            String processDefinitionId = randomString();
 | 
			
		||||
            when(execution.getProcessDefinitionId()).thenReturn(processDefinitionId);
 | 
			
		||||
            FlowElement flowElement = mock(FlowElement.class);
 | 
			
		||||
            when(execution.getCurrentFlowElement()).thenReturn(flowElement);
 | 
			
		||||
            // mock 方法(parseAssignEmptyHandlerType)
 | 
			
		||||
            bpmnModelUtilsMockedStatic.when(() -> BpmnModelUtils.parseAssignEmptyHandlerType(same(flowElement)))
 | 
			
		||||
                    .thenReturn(BpmUserTaskAssignEmptyHandlerTypeEnum.ASSIGN_USER.getType());
 | 
			
		||||
            bpmnModelUtilsMockedStatic.when(() -> BpmnModelUtils.parseAssignEmptyHandlerUserIds(same(flowElement)))
 | 
			
		||||
                    .thenReturn(ListUtil.of(1L, 2L));
 | 
			
		||||
 | 
			
		||||
            // 调用
 | 
			
		||||
            Set<Long> userIds = strategy.calculateUsersByTask(execution, param);
 | 
			
		||||
            // 断言
 | 
			
		||||
            assertEquals(SetUtils.asSet(1L, 2L), userIds);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCalculateUsersByActivity() {
 | 
			
		||||
        try (MockedStatic<BpmnModelUtils> bpmnModelUtilsMockedStatic = mockStatic(BpmnModelUtils.class)) {
 | 
			
		||||
            // 准备参数
 | 
			
		||||
            String processDefinitionId = randomString();
 | 
			
		||||
            String activityId = randomString();
 | 
			
		||||
            String param = randomString();
 | 
			
		||||
            // mock 方法(getFlowElementById)
 | 
			
		||||
            FlowElement flowElement = mock(FlowElement.class);
 | 
			
		||||
            BpmnModel bpmnModel = mock(BpmnModel.class);
 | 
			
		||||
            bpmnModelUtilsMockedStatic.when(() -> BpmnModelUtils.getFlowElementById(same(bpmnModel), eq(activityId)))
 | 
			
		||||
                    .thenReturn(flowElement);
 | 
			
		||||
            // mock 方法(parseAssignEmptyHandlerType)
 | 
			
		||||
            bpmnModelUtilsMockedStatic.when(() -> BpmnModelUtils.parseAssignEmptyHandlerType(same(flowElement)))
 | 
			
		||||
                 .thenReturn(BpmUserTaskAssignEmptyHandlerTypeEnum.ASSIGN_ADMIN.getType());
 | 
			
		||||
            // mock 方法(getProcessDefinitionInfo)
 | 
			
		||||
            BpmProcessDefinitionInfoDO processDefinition = randomPojo(BpmProcessDefinitionInfoDO.class,
 | 
			
		||||
                    o -> o.setManagerUserIds(ListUtil.of(1L, 2L)));
 | 
			
		||||
            when(processDefinitionService.getProcessDefinitionInfo(eq(processDefinitionId))).thenReturn(processDefinition);
 | 
			
		||||
 | 
			
		||||
            // 调用
 | 
			
		||||
            Set<Long> userIds = strategy.calculateUsersByActivity(bpmnModel, activityId, param,
 | 
			
		||||
                    null, processDefinitionId, null);
 | 
			
		||||
            // 断言
 | 
			
		||||
            assertEquals(SetUtils.asSet(1L, 2L), userIds);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,12 +1,14 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.other;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
 | 
			
		||||
import org.flowable.engine.delegate.DelegateExecution;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.MockedStatic;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
 | 
			
		||||
@@ -20,7 +22,7 @@ public class BpmTaskCandidateExpressionStrategyTest extends BaseMockitoUnitTest
 | 
			
		||||
    private BpmTaskCandidateExpressionStrategy strategy;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCalculateUsers() {
 | 
			
		||||
    public void testCalculateUsersByTask() {
 | 
			
		||||
        try (MockedStatic<FlowableUtils> flowableUtilMockedStatic = mockStatic(FlowableUtils.class)) {
 | 
			
		||||
            // 准备参数
 | 
			
		||||
            String param = "1,2";
 | 
			
		||||
@@ -30,7 +32,25 @@ public class BpmTaskCandidateExpressionStrategyTest extends BaseMockitoUnitTest
 | 
			
		||||
                    .thenReturn(asSet(1L, 2L));
 | 
			
		||||
 | 
			
		||||
            // 调用
 | 
			
		||||
            Set<Long> results = strategy.calculateUsers(execution, param);
 | 
			
		||||
            Set<Long> results = strategy.calculateUsersByTask(execution, param);
 | 
			
		||||
            // 断言
 | 
			
		||||
            assertEquals(asSet(1L, 2L), results);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCalculateUsersByActivity() {
 | 
			
		||||
        try (MockedStatic<FlowableUtils> flowableUtilMockedStatic = mockStatic(FlowableUtils.class)) {
 | 
			
		||||
            // 准备参数
 | 
			
		||||
            String param = "1,2";
 | 
			
		||||
            Map<String, Object> processVariables = new HashMap<>();
 | 
			
		||||
            // mock 方法
 | 
			
		||||
            flowableUtilMockedStatic.when(() -> FlowableUtils.getExpressionValue(same(processVariables), eq(param)))
 | 
			
		||||
                    .thenReturn(asSet(1L, 2L));
 | 
			
		||||
 | 
			
		||||
            // 调用
 | 
			
		||||
            Set<Long> results = strategy.calculateUsersByActivity(null, null, param,
 | 
			
		||||
                    null, null, processVariables);
 | 
			
		||||
            // 断言
 | 
			
		||||
            assertEquals(asSet(1L, 2L), results);
 | 
			
		||||
        }
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
 | 
			
		||||
@@ -34,9 +34,9 @@ public class BpmTaskCandidateGroupStrategyTest extends BaseMockitoUnitTest {
 | 
			
		||||
        when(userGroupService.getUserGroupList(eq(asSet(1L, 2L)))).thenReturn(Arrays.asList(userGroup1, userGroup2));
 | 
			
		||||
 | 
			
		||||
        // 调用
 | 
			
		||||
        Set<Long> results = strategy.calculateUsers(null, param);
 | 
			
		||||
        Set<Long> userIds = strategy.calculateUsersByTask(null, param);
 | 
			
		||||
        // 断言
 | 
			
		||||
        assertEquals(asSet(11L, 12L, 21L, 22L), results);
 | 
			
		||||
        assertEquals(asSet(11L, 12L, 21L, 22L), userIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.dept.PostApi;
 | 
			
		||||
@@ -37,9 +37,9 @@ public class BpmTaskCandidatePostStrategyTest extends BaseMockitoUnitTest {
 | 
			
		||||
        when(adminUserApi.getUserListByPostIds(eq(asSet(1L, 2L)))).thenReturn(users);
 | 
			
		||||
 | 
			
		||||
        // 调用
 | 
			
		||||
        Set<Long> results = strategy.calculateUsers(null, param);
 | 
			
		||||
        Set<Long> userIds = strategy.calculateUsersByTask(null, param);
 | 
			
		||||
        // 断言
 | 
			
		||||
        assertEquals(asSet(11L, 22L), results);
 | 
			
		||||
        assertEquals(asSet(11L, 22L), userIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
 | 
			
		||||
@@ -33,9 +33,9 @@ public class BpmTaskCandidateRoleStrategyTest extends BaseMockitoUnitTest {
 | 
			
		||||
            .thenReturn(asSet(11L, 22L));
 | 
			
		||||
 | 
			
		||||
        // 调用
 | 
			
		||||
        Set<Long> results = strategy.calculateUsers(null, param);
 | 
			
		||||
        Set<Long> userIds = strategy.calculateUsersByTask(null, param);
 | 
			
		||||
        // 断言
 | 
			
		||||
        assertEquals(asSet(11L, 22L), results);
 | 
			
		||||
        assertEquals(asSet(11L, 22L), userIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,56 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 | 
			
		||||
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
 | 
			
		||||
import org.assertj.core.util.Sets;
 | 
			
		||||
import org.flowable.engine.delegate.DelegateExecution;
 | 
			
		||||
import org.flowable.engine.runtime.ProcessInstance;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import static org.junit.jupiter.api.Assertions.assertEquals;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.eq;
 | 
			
		||||
import static org.mockito.Mockito.mock;
 | 
			
		||||
import static org.mockito.Mockito.when;
 | 
			
		||||
 | 
			
		||||
public class BpmTaskCandidateStartUserStrategyTest extends BaseMockitoUnitTest {
 | 
			
		||||
 | 
			
		||||
    @InjectMocks
 | 
			
		||||
    private BpmTaskCandidateStartUserStrategy strategy;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private BpmProcessInstanceService processInstanceService;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCalculateUsersByTask() {
 | 
			
		||||
        // 准备参数
 | 
			
		||||
        String param = "2";
 | 
			
		||||
        // mock 方法(获得流程发起人)
 | 
			
		||||
        Long startUserId = 1L;
 | 
			
		||||
        ProcessInstance processInstance = mock(ProcessInstance.class);
 | 
			
		||||
        DelegateExecution execution = mock(DelegateExecution.class);
 | 
			
		||||
        when(processInstanceService.getProcessInstance(eq(execution.getProcessInstanceId()))).thenReturn(processInstance);
 | 
			
		||||
        when(processInstance.getStartUserId()).thenReturn(startUserId.toString());
 | 
			
		||||
 | 
			
		||||
        // 调用
 | 
			
		||||
        Set<Long> userIds = strategy.calculateUsersByTask(execution, param);
 | 
			
		||||
        // 断言
 | 
			
		||||
        assertEquals(Sets.newLinkedHashSet(startUserId), userIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCalculateUsersByActivity() {
 | 
			
		||||
        // 准备参数
 | 
			
		||||
        Long startUserId = 1L;
 | 
			
		||||
 | 
			
		||||
        // 调用
 | 
			
		||||
        Set<Long> userIds = strategy.calculateUsersByActivity(null, null, null,
 | 
			
		||||
                startUserId, null, null);
 | 
			
		||||
        // 断言
 | 
			
		||||
        assertEquals(Sets.newLinkedHashSet(startUserId), userIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
 | 
			
		||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
@@ -15,14 +15,15 @@ public class BpmTaskCandidateUserStrategyTest extends BaseMockitoUnitTest {
 | 
			
		||||
    private BpmTaskCandidateUserStrategy strategy;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCalculateUsers() {
 | 
			
		||||
    public void test() {
 | 
			
		||||
        // 准备参数
 | 
			
		||||
        String param = "1,2";
 | 
			
		||||
 | 
			
		||||
        // 调用
 | 
			
		||||
        Set<Long> results = strategy.calculateUsers(null, param);
 | 
			
		||||
        Set<Long> userIds = strategy.calculateUsersByTask(null, param);
 | 
			
		||||
        // 断言
 | 
			
		||||
        assertEquals(asSet(1L, 2L), results);
 | 
			
		||||
        assertEquals(asSet(1L, 2L), userIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user