first commit

This commit is contained in:
那些花儿
2025-07-14 08:45:13 +08:00
commit 3e86198a82
2710 changed files with 610330 additions and 0 deletions
@@ -0,0 +1,200 @@
package com.budwk.app.bpm.util;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.expression.ExpressionUtil;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.bpm.enums.BpmProcessNodeApprovalTypeEnum;
import com.budwk.app.bpm.enums.BpmProcessNodeTypeEnum;
import com.budwk.app.bpm.enums.BpmTaskApprovalTypeEnum;
import com.budwk.app.bpm.models.BpmProcessNodeDefine;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 流程工具类
*/
public class BpmUtil {
/**
* 执行动态判断表达式 获取下一个节点
*
* @param decisions
* @param variables
* @return
*/
public static String evalExpressionGetNextTaskNodeId(BpmProcessNodeDefine taskNode, BpmTaskApprovalTypeEnum bpmTaskApprovalTypeEnum, List<BpmProcessNodeDefine.DynamicDecision> decisions, Map<String, Object> variables) {
if (bpmTaskApprovalTypeEnum.equals(BpmTaskApprovalTypeEnum.DYNAMIC)) {
if (ObjectUtil.isEmpty(decisions)) {
throw new BaseException("动态分支节点配置为空");
}
for (BpmProcessNodeDefine.DynamicDecision decision : decisions) {
String expression = decision.getCondition();
Object eval = ExpressionUtil.eval(expression, variables);
if (Convert.toBool(eval, false)) {
return decision.getToNodeId();
}
}
return null;
} else if (bpmTaskApprovalTypeEnum.equals(BpmTaskApprovalTypeEnum.APPLY)) {
if(ObjectUtil.isEmpty(taskNode.getDynamicDecisions())){
return taskNode.getPassNextNodeId();
}else{
for (BpmProcessNodeDefine.DynamicDecision decision : decisions) {
String expression = decision.getCondition();
Object eval = ExpressionUtil.eval(expression, variables);
if (Convert.toBool(eval, false)) {
return decision.getToNodeId();
}
}
}
} else if (bpmTaskApprovalTypeEnum.equals(BpmTaskApprovalTypeEnum.REJECT)) {
return taskNode.getRejectNextNodeId();
} else if (bpmTaskApprovalTypeEnum.equals(BpmTaskApprovalTypeEnum.BACK)) {
return taskNode.getBackNextNodeId();
} else if (bpmTaskApprovalTypeEnum.equals(BpmTaskApprovalTypeEnum.PASS)) {
return taskNode.getPassNextNodeId();
}
throw new BaseException("{}节点{}配置错误", taskNode.getNodeName(), bpmTaskApprovalTypeEnum.name());
}
/**
* 验证流程定义节点是否正确
* @param nodes
*/
public static void validateNodes(List<BpmProcessNodeDefine> nodes) {
//名称必填
for (BpmProcessNodeDefine node : nodes) {
if (StrUtil.isBlank(node.getNodeName())) {
throw new RuntimeException("节点名称不能为空,请检查");
}
}
//code必填
for (BpmProcessNodeDefine node : nodes) {
if (ObjectUtil.isNull(node.getNodeCode())) {
throw new RuntimeException("节点编码不能为空,请检查");
}
}
//节点类型必填
for (BpmProcessNodeDefine node : nodes) {
if (StrUtil.isBlank(node.getNodeType())) {
throw new RuntimeException("节点类型不能为空,请检查");
}
}
//code不能重复
Set<Integer> codes = new HashSet<>();
for (BpmProcessNodeDefine node : nodes) {
if (!codes.add(node.getNodeCode())) {
throw new RuntimeException("节点编码重复,请检查");
}
}
if (nodes.stream().noneMatch(node -> node.getNodeType().equals(BpmProcessNodeTypeEnum.START.name()))) {
throw new RuntimeException("流程定义中必须存在开始节点,请检查");
}
if (nodes.stream().noneMatch(node -> node.getNodeType().equals(BpmProcessNodeTypeEnum.END.name()))) {
throw new RuntimeException("流程定义中必须存在结束节点,请检查");
}
if (nodes.stream().noneMatch(node -> node.getNodeType().equals(BpmProcessNodeTypeEnum.TASK.name()))) {
throw new RuntimeException("流程定义中必须存在任务节点,请检查");
}
//单个判断
for (BpmProcessNodeDefine node : nodes) {
if(node.getNodeType().equals(BpmProcessNodeTypeEnum.START.name())){
validateStartNode(node, nodes);
}else if(node.getNodeType().equals(BpmProcessNodeTypeEnum.END.name())){
validateEndNode(node, nodes);
}else if(node.getNodeType().equals(BpmProcessNodeTypeEnum.TASK.name())){
validateTaskNode(node, nodes);
}else if(node.getNodeType().equals(BpmProcessNodeTypeEnum.BACK.name())){
validateBackNode(node, nodes);
}
}
}
/**
* 验证开始节点
*
* @param startNode
* @param nodes
*/
private static void validateStartNode(BpmProcessNodeDefine startNode, List<BpmProcessNodeDefine> nodes) {
String passNextNodeId = startNode.getPassNextNodeId();
if (StrUtil.isBlank(passNextNodeId) && ObjectUtil.isEmpty(startNode.getDynamicDecisions())) {
throw new RuntimeException("开始节点的通过节点或者动态决策表达式不能为空,请检查");
}
if (passNextNodeId.equals(startNode.getId())) {
throw new RuntimeException("开始节点的通过节点不能指向自己,请检查");
}
// if (StrUtil.isBlank(startNode.getNodeApprovalType())) {
// throw new RuntimeException("开始节点的审批完成类型不能为空,请检查");
// }
// if (!startNode.getNodeApprovalType().equals(BpmProcessNodeApprovalTypeEnum.NODE_APPLY.name())) {
// throw new RuntimeException("开始节点的审批完成类型只能为申请,请检查");
// }
}
/**
* 验证结束节点
*
* @param endNode
* @param nodes
*/
private static void validateEndNode(BpmProcessNodeDefine endNode, List<BpmProcessNodeDefine> nodes) {
}
/**
* 验证任务节点
*
* @param taskNode
* @param nodes
*/
private static void validateTaskNode(BpmProcessNodeDefine taskNode, List<BpmProcessNodeDefine> nodes) {
if (StrUtil.isAllBlank(taskNode.getPassNextNodeId(), taskNode.getRejectNextNodeId(), taskNode.getBackNextNodeId()) && ObjectUtil.isEmpty(taskNode.getDynamicDecisions())) {
throw new RuntimeException("任务节点的通过、拒绝、退回节点和动态决策不能同时为空,请检查");
}
if (ObjectUtil.isEmpty(taskNode.getDynamicDecisions()) && StrUtil.isBlank(taskNode.getPassNextNodeId())) {
throw new RuntimeException("任务节点的通过节点不能为空,请检查");
}
if (StrUtil.isNotBlank(taskNode.getPassNextNodeId()) && taskNode.getPassNextNodeId().equals(taskNode.getId())) {
throw new RuntimeException("任务节点的通过节点不能指向自己,请检查");
}
if (StrUtil.isBlank(taskNode.getNodePerformType())) {
throw new RuntimeException("任务节点的参与类型不能为空,请检查");
}
// if (StrUtil.isBlank(taskNode.getNodeApprovalType())) {
// throw new RuntimeException("任务节点的审批完成类型不能为空,请检查");
// }
}
/**
* 验证退回节点
* @param backNode
* @param nodes
*/
private static void validateBackNode(BpmProcessNodeDefine backNode, List<BpmProcessNodeDefine> nodes) {
}
/**
* 获取开始节点
* @param nodes
* @return
*/
public static BpmProcessNodeDefine getStartNode(List<BpmProcessNodeDefine> nodes) {
return nodes.stream().filter(node -> node.getNodeType().equals(BpmProcessNodeTypeEnum.START.name())).findFirst().orElse(null);
}
}