【代码评审】工作流:连续多级部门负责人的实现

This commit is contained in:
YunaiV 2024-08-17 20:30:51 +08:00
parent e7815dd762
commit 040a1bcfad
5 changed files with 44 additions and 39 deletions

View File

@ -6,10 +6,7 @@ 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.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import java.util.Collections; import java.util.*;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
/** /**
* 部门的负责人 {@link BpmTaskCandidateStrategy} 抽象类 * 部门的负责人 {@link BpmTaskCandidateStrategy} 抽象类
@ -25,44 +22,43 @@ public abstract class BpmTaskCandidateAbstractDeptLeaderStrategy implements BpmT
} }
/** /**
* 取上级部门的负责人 * 得指定层级的部门负责人只有第 level 的负责人
* *
* @param assignDept 指定部门 * @param dept 指定部门
* @param level 第几级 * @param level 第几级
* @return 部门负责人 Id * @return 部门负责人的编号
*/ */
protected Long getAssignLevelDeptLeaderId(DeptRespDTO assignDept, Integer level) { protected Long getAssignLevelDeptLeaderId(DeptRespDTO dept, Integer level) {
Assert.isTrue(level > 0, "level 必须大于 0"); Assert.isTrue(level > 0, "level 必须大于 0");
if (assignDept == null) { if (dept == null) {
return null; return null;
} }
DeptRespDTO dept = assignDept; DeptRespDTO currentDept = dept;
for (int i = 1; i < level; i++) { for (int i = 1; i < level; i++) {
DeptRespDTO parentDept = deptApi.getDept(dept.getParentId()); DeptRespDTO parentDept = deptApi.getDept(currentDept.getParentId());
if (parentDept == null) { // 找不到父级部门到了最高级返回最高级的部门负责人 if (parentDept == null) { // 找不到父级部门到了最高级返回最高级的部门负责人
break; break;
} }
dept = parentDept; currentDept = parentDept;
} }
return dept.getLeaderUserId(); return currentDept.getLeaderUserId();
} }
/** /**
* 取连续上级部门的负责人, 包含指定部门的负责人 * 得连续层级的部门负责人包含 [1, level] 的负责人
* *
* @param assignDeptIds 指定部门 Ids * @param deptIds 指定部门编号数组
* @param level 第几 * @param level 最大层
* @return 连续部门负责人 Id * @return 连续部门负责人 Id
*/ */
protected Set<Long> getMultiLevelDeptLeaderIds(List<Long> assignDeptIds, Integer level) { protected Set<Long> getMultiLevelDeptLeaderIds(List<Long> deptIds, Integer level) {
Assert.isTrue(level > 0, "level 必须大于 0"); Assert.isTrue(level > 0, "level 必须大于 0");
if (CollUtil.isEmpty(assignDeptIds)) { if (CollUtil.isEmpty(deptIds)) {
return Collections.emptySet(); return new HashSet<>();
} }
Set<Long> deptLeaderIds = new LinkedHashSet<>(); // 保证有序 Set<Long> deptLeaderIds = new LinkedHashSet<>(); // 保证有序
DeptRespDTO dept; for (Long deptId : deptIds) {
for (Long deptId : assignDeptIds) { DeptRespDTO dept = deptApi.getDept(deptId);
dept = deptApi.getDept(deptId);
for (int i = 0; i < level; i++) { for (int i = 0; i < level; i++) {
if (dept.getLeaderUserId() != null) { if (dept.getLeaderUserId() != null) {
deptLeaderIds.add(dept.getLeaderUserId()); deptLeaderIds.add(dept.getLeaderUserId());

View File

@ -18,20 +18,21 @@ import java.util.Set;
* @author jason * @author jason
*/ */
@Component @Component
public class BpmTaskCandidateMultiLevelDeptLeaderStrategy extends BpmTaskCandidateAbstractDeptLeaderStrategy { public class BpmTaskCandidateDeptLeaderMultiStrategy extends BpmTaskCandidateAbstractDeptLeaderStrategy {
public BpmTaskCandidateMultiLevelDeptLeaderStrategy(DeptApi deptApi) { public BpmTaskCandidateDeptLeaderMultiStrategy(DeptApi deptApi) {
super(deptApi); super(deptApi);
} }
@Override @Override
public BpmTaskCandidateStrategyEnum getStrategy() { public BpmTaskCandidateStrategyEnum getStrategy() {
return BpmTaskCandidateStrategyEnum.MULTI_LEVEL_DEPT_LEADER; return BpmTaskCandidateStrategyEnum.MULTI_DEPT_LEADER_MULTI;
} }
@Override @Override
public void validateParam(String param) { public void validateParam(String param) {
// 参数格式: ,分割前面的部门Id. 可以为多个 最后一个为部门层级 // TODO @jason是不是可以 | 分隔 deptId 数组 level这样后续可以加更多的参数
// 参数格式: , 分割前面的部门编号可以为多个最后一个为部门层级
List<Long> params = StrUtils.splitToLong(param, ","); List<Long> params = StrUtils.splitToLong(param, ",");
List<List<Long>> splitList = CollUtil.split(params, params.size() - 1); List<List<Long>> splitList = CollUtil.split(params, params.size() - 1);
Assert.isTrue(splitList.size() == 2, "参数格式不匹配"); Assert.isTrue(splitList.size() == 2, "参数格式不匹配");
@ -41,6 +42,7 @@ public class BpmTaskCandidateMultiLevelDeptLeaderStrategy extends BpmTaskCandida
@Override @Override
public Set<Long> calculateUsers(DelegateExecution execution, String param) { public Set<Long> calculateUsers(DelegateExecution execution, String param) {
// TODO @jason是不是可以 | 分隔 deptId 数组 level这样后续可以加更多的参数
// 参数格式: ,分割前面的部门Id. 可以为多个 最后一个为部门层级 // 参数格式: ,分割前面的部门Id. 可以为多个 最后一个为部门层级
List<Long> params = StrUtils.splitToLong(param, ","); List<Long> params = StrUtils.splitToLong(param, ",");
List<List<Long>> splitList = CollUtil.split(params, params.size() - 1); List<List<Long>> splitList = CollUtil.split(params, params.size() - 1);

View File

@ -15,7 +15,7 @@ import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.Collections; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import static cn.hutool.core.collection.ListUtil.toList; import static cn.hutool.core.collection.ListUtil.toList;
@ -26,7 +26,7 @@ import static cn.hutool.core.collection.ListUtil.toList;
* @author jason * @author jason
*/ */
@Component @Component
public class BpmTaskCandidateStartUserMultiLevelDeptLeaderStrategy extends BpmTaskCandidateAbstractDeptLeaderStrategy { public class BpmTaskCandidateStartUserDeptLeaderMultiStrategy extends BpmTaskCandidateAbstractDeptLeaderStrategy {
@Resource @Resource
@Lazy @Lazy
@ -35,13 +35,13 @@ public class BpmTaskCandidateStartUserMultiLevelDeptLeaderStrategy extends BpmTa
@Resource @Resource
private AdminUserApi adminUserApi; private AdminUserApi adminUserApi;
public BpmTaskCandidateStartUserMultiLevelDeptLeaderStrategy(DeptApi deptApi) { public BpmTaskCandidateStartUserDeptLeaderMultiStrategy(DeptApi deptApi) {
super(deptApi); super(deptApi);
} }
@Override @Override
public BpmTaskCandidateStrategyEnum getStrategy() { public BpmTaskCandidateStrategyEnum getStrategy() {
return BpmTaskCandidateStrategyEnum.START_USER_MULTI_LEVEL_DEPT_LEADER; return BpmTaskCandidateStrategyEnum.START_USER_DEPT_LEADER_MULTI;
} }
@Override @Override
@ -55,9 +55,10 @@ public class BpmTaskCandidateStartUserMultiLevelDeptLeaderStrategy extends BpmTa
// 获得流程发起人 // 获得流程发起人
ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId()); ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId()); Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId());
// 获取发起人的 multi 部门负责人
DeptRespDTO dept = getStartUserDept(startUserId); DeptRespDTO dept = getStartUserDept(startUserId);
if (dept == null) { if (dept == null) {
return Collections.emptySet(); return new HashSet<>();
} }
return getMultiLevelDeptLeaderIds(toList(dept.getId()), Integer.valueOf(param)); // 参数是部门的层级 return getMultiLevelDeptLeaderIds(toList(dept.getId()), Integer.valueOf(param)); // 参数是部门的层级
} }

View File

@ -15,10 +15,10 @@ import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
import static java.util.Collections.emptySet;
/** /**
* 发起人的部门负责人, 可以是上级部门负责人 {@link BpmTaskCandidateStrategy} 实现类 * 发起人的部门负责人, 可以是上级部门负责人 {@link BpmTaskCandidateStrategy} 实现类
@ -27,11 +27,14 @@ import static java.util.Collections.emptySet;
*/ */
@Component @Component
public class BpmTaskCandidateStartUserDeptLeaderStrategy extends BpmTaskCandidateAbstractDeptLeaderStrategy { public class BpmTaskCandidateStartUserDeptLeaderStrategy extends BpmTaskCandidateAbstractDeptLeaderStrategy {
@Resource @Resource
@Lazy @Lazy // 避免循环依赖
private BpmProcessInstanceService processInstanceService; private BpmProcessInstanceService processInstanceService;
@Resource @Resource
private AdminUserApi adminUserApi; private AdminUserApi adminUserApi;
@Override @Override
public BpmTaskCandidateStrategyEnum getStrategy() { public BpmTaskCandidateStrategyEnum getStrategy() {
return BpmTaskCandidateStrategyEnum.START_USER_DEPT_LEADER; return BpmTaskCandidateStrategyEnum.START_USER_DEPT_LEADER;
@ -52,10 +55,13 @@ public class BpmTaskCandidateStartUserDeptLeaderStrategy extends BpmTaskCandidat
// 获得流程发起人 // 获得流程发起人
ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId()); ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId()); Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId());
// 获取发起人的部门负责人
DeptRespDTO dept = getStartUserDept(startUserId); DeptRespDTO dept = getStartUserDept(startUserId);
if (dept == null) {
return new HashSet<>();
}
Long deptLeaderId = getAssignLevelDeptLeaderId(dept, Integer.valueOf(param)); // 参数是部门的层级 Long deptLeaderId = getAssignLevelDeptLeaderId(dept, Integer.valueOf(param)); // 参数是部门的层级
return deptLeaderId != null ? asSet(deptLeaderId) : emptySet(); return deptLeaderId != null ? asSet(deptLeaderId) : new HashSet<>();
} }
/** /**

View File

@ -21,13 +21,13 @@ public enum BpmTaskCandidateStrategyEnum implements IntArrayValuable {
ROLE(10, "角色"), ROLE(10, "角色"),
DEPT_MEMBER(20, "部门的成员"), // 包括负责人 DEPT_MEMBER(20, "部门的成员"), // 包括负责人
DEPT_LEADER(21, "部门的负责人"), DEPT_LEADER(21, "部门的负责人"),
MULTI_LEVEL_DEPT_LEADER(23, "连续多级部门的负责人"), MULTI_DEPT_LEADER_MULTI(23, "连续多级部门的负责人"),
POST(22, "岗位"), POST(22, "岗位"),
USER(30, "用户"), USER(30, "用户"),
START_USER_SELECT(35, "发起人自选"), // 申请人自己可在提交申请时选择此节点的审批人 START_USER_SELECT(35, "发起人自选"), // 申请人自己可在提交申请时选择此节点的审批人
START_USER(36, "发起人自己"), // 申请人自己, 一般紧挨开始节点常用于发起人信息审核场景 START_USER(36, "发起人自己"), // 申请人自己, 一般紧挨开始节点常用于发起人信息审核场景
START_USER_DEPT_LEADER(37, "发起人部门负责人"), // 可以是发起人上级部门负责人 START_USER_DEPT_LEADER(37, "发起人部门负责人"),
START_USER_MULTI_LEVEL_DEPT_LEADER(38, "发起人连续多级部门的负责人"), START_USER_DEPT_LEADER_MULTI(38, "发起人连续多级部门的负责人"),
USER_GROUP(40, "用户组"), USER_GROUP(40, "用户组"),
EXPRESSION(60, "流程表达式"), // 表达式 ExpressionManager EXPRESSION(60, "流程表达式"), // 表达式 ExpressionManager
ASSIGN_EMPTY(1, "审批人为空"), ASSIGN_EMPTY(1, "审批人为空"),