工作流模块提交

This commit is contained in:
2024-05-09 14:23:18 +08:00
parent bedd70136b
commit 4936d22884
98 changed files with 6780 additions and 108 deletions

View File

@@ -0,0 +1,113 @@
package com.njcn.bpm.strategy;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.google.common.annotations.VisibleForTesting;
import com.njcn.bpm.enums.BpmTaskCandidateStrategyEnum;
import com.njcn.bpm.utils.BpmnModelUtils;
import com.njcn.bpm.utils.CollectionUtils;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.user.api.UserFeignClient;
import com.njcn.user.pojo.po.User;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.stereotype.Component;
import java.util.*;
/**
* @author 芋道源码
*/
@Slf4j
public class BpmTaskCandidateInvoker {
private final Map<BpmTaskCandidateStrategyEnum, IBpmTaskCandidateStrategy> strategyMap = new HashMap<>();
private final UserFeignClient adminUserApi;
public BpmTaskCandidateInvoker(List<IBpmTaskCandidateStrategy> strategyList,
UserFeignClient adminUserApi) {
strategyList.forEach(strategy -> {
IBpmTaskCandidateStrategy oldStrategy = strategyMap.put(strategy.getStrategy(), strategy);
Assert.isNull(oldStrategy, "策略(%s) 重复", strategy.getStrategy());
});
this.adminUserApi = adminUserApi;
}
/**
* 校验流程模型的任务分配规则全部都配置了
* 目的:如果有规则未配置,会导致流程任务找不到负责人,进而流程无法进行下去!
*
* @param bpmnBytes BPMN XML
*/
public void validateBpmnConfig(byte[] bpmnBytes) {
BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnBytes);
assert bpmnModel != null;
List<UserTask> userTaskList = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class);
// 遍历所有的 UserTask校验审批人配置
userTaskList.forEach(userTask -> {
// 1. 非空校验
Integer strategy = BpmnModelUtils.parseCandidateStrategy(userTask);
String param = BpmnModelUtils.parseCandidateParam(userTask);
if (strategy == null) {
throw new BusinessException("部署流程失败原因BPMN 流程图中,用户任务(" + userTask.getName() + ")的名字不存在");
}
IBpmTaskCandidateStrategy candidateStrategy = getCandidateStrategy(strategy);
if (candidateStrategy.isParamRequired() && StrUtil.isBlank(param)) {
throw new BusinessException("部署流程失败,原因:用户任务(" + userTask.getName() + ")未配置审批人,请点击【流程设计】按钮,选择该它的【任务(审批人)】进行配置");
}
// 2. 具体策略校验
getCandidateStrategy(strategy).validateParam(param);
});
}
/**
* 计算任务的候选人
*
* @param execution 执行任务
* @return 用户编号集合
*/
public List<String> calculateUsers(DelegateExecution execution) {
Integer strategy = BpmnModelUtils.parseCandidateStrategy(execution.getCurrentFlowElement());
String param = BpmnModelUtils.parseCandidateParam(execution.getCurrentFlowElement());
// 1.1 计算任务的候选人
List<String> userIds = getCandidateStrategy(strategy).calculateUsers(execution, param);
// 1.2 移除被禁用的用户
removeDisableUsers(userIds);
// 2. 校验是否有候选人
if (CollUtil.isEmpty(userIds)) {
log.error("[calculateUsers][流程任务({}/{}/{}) 任务规则({}/{}) 找不到候选人]", execution.getId(),
execution.getProcessDefinitionId(), execution.getCurrentActivityId(), strategy, param);
throw new BusinessException("操作失败,原因:找不到任务的审批人!");
}
return userIds;
}
@VisibleForTesting
void removeDisableUsers(List<String> assigneeUserIds) {
if (CollUtil.isEmpty(assigneeUserIds)) {
return;
}
List<User> users = adminUserApi.getUserByIdList(assigneeUserIds).getData();
Map<String, User> userMap = CollectionUtils.convertMap(users, User::getId);
assigneeUserIds.removeIf(id -> {
User user = userMap.get(id);
return user == null || !DataStateEnum.ENABLE.getCode().equals(user.getState());
});
}
private IBpmTaskCandidateStrategy getCandidateStrategy(Integer strategy) {
BpmTaskCandidateStrategyEnum strategyEnum = BpmTaskCandidateStrategyEnum.valueOf(strategy);
Assert.notNull(strategyEnum, "策略(%s) 不存在", strategy);
IBpmTaskCandidateStrategy strategyObj = strategyMap.get(strategyEnum);
Assert.notNull(strategyObj, "策略(%s) 不存在", strategy);
return strategyObj;
}
}

View File

@@ -0,0 +1,44 @@
package com.njcn.bpm.strategy;
import com.njcn.user.api.UserFeignClient;
import com.njcn.bpm.utils.StrUtils;
import org.flowable.engine.delegate.DelegateExecution;
import com.njcn.bpm.enums.BpmTaskCandidateStrategyEnum;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
/**
* 角色 {@link IBpmTaskCandidateStrategy} 实现类
*
* @author kyle
*/
@Component
public class BpmTaskCandidateRoleStrategy implements IBpmTaskCandidateStrategy {
@Resource
private UserFeignClient userFeignClient;
// @Resource
// private PermissionApi permissionApi;
@Override
public BpmTaskCandidateStrategyEnum getStrategy() {
return BpmTaskCandidateStrategyEnum.ROLE;
}
@Override
public void validateParam(String param) {
// Set<Long> roleIds = StrUtils.splitToLongSet(param);
// roleApi.validRoleList(roleIds);
}
@Override
public List<String> calculateUsers(DelegateExecution execution, String param) {
List<String> roleIds = StrUtils.splitToStringList(param);
return userFeignClient.getUserIdByRoleId(roleIds).getData();
}
}

View File

@@ -0,0 +1,74 @@
package com.njcn.bpm.strategy;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import com.njcn.bpm.enums.BpmTaskCandidateStrategyEnum;
import com.njcn.bpm.service.task.IBpmProcessInstanceService;
import com.njcn.bpm.utils.BpmnModelUtils;
import com.njcn.bpm.utils.FlowableUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.*;
/**
*
* @author 芋道源码
*/
@Component
public class BpmTaskCandidateStartUserSelectStrategy implements IBpmTaskCandidateStrategy {
@Resource
@Lazy // 延迟加载,避免循环依赖
private IBpmProcessInstanceService processInstanceService;
@Override
public BpmTaskCandidateStrategyEnum getStrategy() {
return BpmTaskCandidateStrategyEnum.START_USER_SELECT;
}
@Override
public void validateParam(String param) {}
@Override
public List<String> calculateUsers(DelegateExecution execution, String param) {
ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
Assert.notNull(processInstance, "流程实例({})不能为空", execution.getProcessInstanceId());
Map<String, List<String>> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance);
Assert.notNull(startUserSelectAssignees, "流程实例({}) 的发起人自选审批人不能为空",
execution.getProcessInstanceId());
// 获得审批人
List<String> assignees = startUserSelectAssignees.get(execution.getCurrentActivityId());
return new ArrayList<>(assignees);
}
@Override
public boolean isParamRequired() {
return false;
}
/**
* 获得发起人自选审批人的 UserTask 列表
*
* @param bpmnModel BPMN 模型
* @return UserTask 列表
*/
public static List<UserTask> getStartUserSelectUserTaskList(BpmnModel bpmnModel) {
if (bpmnModel == null) {
return null;
}
List<UserTask> userTaskList = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class);
if (CollUtil.isEmpty(userTaskList)) {
return null;
}
userTaskList.removeIf(userTask -> !Objects.equals(BpmnModelUtils.parseCandidateStrategy(userTask),
BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy()));
return userTaskList;
}
}

View File

@@ -0,0 +1,39 @@
package com.njcn.bpm.strategy;
import com.njcn.bpm.enums.BpmTaskCandidateStrategyEnum;
import com.njcn.bpm.utils.StrUtils;
import com.njcn.user.api.UserFeignClient;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
/**
* 用户 {@link IBpmTaskCandidateStrategy} 实现类
*
* @author kyle
*/
@Component
public class BpmTaskCandidateUserStrategy implements IBpmTaskCandidateStrategy {
@Resource
private UserFeignClient adminUserApi;
@Override
public BpmTaskCandidateStrategyEnum getStrategy() {
return BpmTaskCandidateStrategyEnum.USER;
}
@Override
public void validateParam(String param) {
// adminUserApi.validateUserList(StrUtils.splitToLongSet(param));
//暂时默认均有效后期可以加强管理todo...
}
@Override
public List<String> calculateUsers(DelegateExecution execution, String param) {
return StrUtils.splitToStringList(param);
}
}

View File

@@ -0,0 +1,49 @@
package com.njcn.bpm.strategy;
import com.njcn.bpm.enums.BpmTaskCandidateStrategyEnum;
import org.flowable.engine.delegate.DelegateExecution;
import java.util.List;
import java.util.Set;
/**
* BPM 任务的候选人的策略接口
*
* 例如说:分配审批人
*
* @author 芋道源码
*/
public interface IBpmTaskCandidateStrategy {
/**
* 对应策略
*
* @return 策略
*/
BpmTaskCandidateStrategyEnum getStrategy();
/**
* 校验参数
*
* @param param 参数
*/
void validateParam(String param);
/**
* 基于执行任务,获得任务的候选用户们
*
* @param execution 执行任务
* @return 用户编号集合
*/
List<String> calculateUsers(DelegateExecution execution, String param);
/**
* 是否一定要输入参数
*
* @return 是否
*/
default boolean isParamRequired() {
return true;
}
}