协议转换优化

This commit is contained in:
lvshaohua 2023-07-03 17:59:28 +08:00
parent 88cb143512
commit ad6bba3ddc
13 changed files with 1047 additions and 215 deletions

View File

@ -0,0 +1,36 @@
package cn.axzo.workflow.core.common.enums;
import org.flowable.bpmn.model.UserTask;
public enum BpmFlowMultiMode {
//0 发起人 1审批 2抄送 3条件 4路由
OR("OR", "或签"),
AND("AND", "会签");
private String type;
private String desc;
BpmFlowMultiMode(String type, String desc) {
this.type = type;
this.desc = desc;
}
public boolean isEqual(String type) {
return this.type.equals(type);
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}

View File

@ -1,5 +1,6 @@
package cn.axzo.workflow.core.common.enums;
import lombok.Data;
import org.flowable.bpmn.model.UserTask;
public enum BpmFlowNodeType {
@ -22,4 +23,28 @@ public enum BpmFlowNodeType {
public boolean isEqual(String type) {
return this.type.equals(type);
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public Class<?> getTypeClass() {
return typeClass;
}
public void setTypeClass(Class<?> typeClass) {
this.typeClass = typeClass;
}
}

View File

@ -1,23 +1,27 @@
package cn.axzo.workflow.core.common.utils;
import cn.axzo.workflow.core.common.BpmConstants;
import cn.axzo.workflow.core.common.enums.BpmFlowMultiMode;
import cn.axzo.workflow.core.common.enums.BpmFlowNodeType;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.service.dto.BpmJsonNode;
import cn.axzo.workflow.core.service.dto.request.BpmJsonNodeProperty;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.BpmnAutoLayout;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.engine.delegate.ExecutionListener;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.engine.repository.Model;
import org.springframework.util.CollectionUtils;
import java.util.*;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.stream.Collectors;
import static cn.axzo.workflow.core.common.BpmConstants.*;
import static cn.axzo.workflow.core.common.enums.BpmErrorCode.BPM_META_DATA_FORMAT_ERROR;
import static org.flowable.bpmn.model.ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION;
@ -31,28 +35,31 @@ public class BpmTransformUtil {
BpmnModel bpmnModel =new BpmnModel();
Process process=new Process();
bpmnModel.addProcess(process);
List<SequenceFlow> sequenceFlows = Lists.newArrayList();
process.setId(model.getKey());
StartEvent startEvent = createStartEvent();
process.addFlowElement(startEvent);
process.setName(model.getName());
JSONObject jsonObject = (JSONObject) JSONObject.toJSON(bpmnJson);
List<SequenceFlow> sequenceFlows = Lists.newArrayList();
Map<String,BpmJsonNode> childNodeMap=new HashMap<>();
// JSONObject jsonObject = (JSONObject) JSONObject.toJSON(bpmnJson);
// ExtensionAttribute extensionAttribute=new ExtensionAttribute();
// extensionAttribute.setName("TestName");
// extensionAttribute.setNamespace("http://flowable.org/bpmn");
// extensionAttribute.setValue(bpmnJson.toJSONString());
//// process.addAttribute(extensionAttribute);
// JSONObject processNodes = bpmnJson.getJSONObject("nodeConfig");
String lastNode = null;
try {
lastNode = create(startEvent.getId(), jsonObject, bpmnModel,process,sequenceFlows);
lastNode = create(startEvent.getId(), bpmnJson,process, bpmnModel, sequenceFlows, childNodeMap);
} catch (Exception e) {
e.printStackTrace();
throw new WorkflowEngineException(BPM_META_DATA_FORMAT_ERROR);
}
EndEvent endEvent = createEndEvent();
process.addFlowElement(endEvent);
process.addFlowElement(connect(lastNode, endEvent.getId(),sequenceFlows));
process.addFlowElement(connect(lastNode, endEvent.getId(),sequenceFlows, childNodeMap, process));
new BpmnAutoLayout(bpmnModel).execute();
@ -62,187 +69,8 @@ public class BpmTransformUtil {
return xmlMeta;
}
private static String create(String fromId, JSONObject flowNode, BpmnModel model, Process process, List<SequenceFlow> sequenceFlows) throws IllegalAccessException {
String nodeType = flowNode.getString("type");
if (BpmFlowNodeType.NODE_STARTER.name().equals(nodeType)) {
// flowNode.put("incoming", Collections.singletonList(fromId));
String id = fromId;
// 如果当前任务还有后续任务则遍历创建后续任务
com.alibaba.fastjson.JSONObject nextNode = flowNode.getJSONObject("childNode");
if (Objects.nonNull(nextNode)) {
FlowElement flowElement = model.getFlowElement(id);
return create(id, nextNode,model,process,sequenceFlows);
} else {
return id;
}
}
else if (BpmFlowNodeType.NODE_TASK.name().equals(nodeType)) {
flowNode.put("incoming", Collections.singletonList(fromId));
String id = createTask(flowNode,process,sequenceFlows);
// 如果当前任务还有后续任务则遍历创建后续任务
com.alibaba.fastjson.JSONObject nextNode = flowNode.getJSONObject("childNode");
if (Objects.nonNull(nextNode)&& Objects.nonNull(nextNode.get("nodeId"))) {
FlowElement flowElement = model.getFlowElement(id);
return create(id, nextNode,model,process,sequenceFlows);
} else {
return id;
}
}
else {
throw new RuntimeException("未知节点类型: nodeType=" + nodeType);
}
}
private static String createParallelGatewayBuilder(String formId, com.alibaba.fastjson.JSONObject flowNode, BpmnModel model, Process process, List<SequenceFlow> sequenceFlows) throws IllegalAccessException {
String name = flowNode.getString("nodeName");
ParallelGateway parallelGateway = new ParallelGateway();
String parallelGatewayId = id("parallelGateway");
parallelGateway.setId(parallelGatewayId);
parallelGateway.setName(name);
process.addFlowElement(parallelGateway);
process.addFlowElement(connect(formId, parallelGatewayId,sequenceFlows));
if (Objects.isNull(flowNode.getJSONArray("conditionNodes"))
&& Objects.isNull(flowNode.getJSONObject("childNode"))) {
return parallelGatewayId;
}
List<com.alibaba.fastjson.JSONObject> flowNodes = Optional.ofNullable(flowNode.getJSONArray("conditionNodes")).map(e -> e.toJavaList(com.alibaba.fastjson.JSONObject.class)).orElse(Collections.emptyList());
List<String> incoming = Lists.newArrayListWithCapacity(flowNodes.size());
for (com.alibaba.fastjson.JSONObject element : flowNodes) {
com.alibaba.fastjson.JSONObject childNode = element.getJSONObject("childNode");
if (Objects.isNull(childNode)) {
incoming.add(parallelGatewayId);
continue;
}
String identifier = create(parallelGatewayId, childNode,model,process,sequenceFlows);
if (Objects.nonNull(identifier)) {
incoming.add(identifier);
}
}
com.alibaba.fastjson.JSONObject childNode = flowNode.getJSONObject("childNode");
if (Objects.nonNull(childNode)) {
// 普通结束网关
if (CollectionUtils.isEmpty(incoming)) {
return create(parallelGatewayId, childNode,model,process,sequenceFlows);
} else {
// 所有 service task 连接 end parallel gateway
childNode.put("incoming", incoming);
FlowElement flowElement = model.getFlowElement(incoming.get(0));
// 1.0 先进行边连接, 暂存 nextNode
com.alibaba.fastjson.JSONObject nextNode = childNode.getJSONObject("childNode");
childNode.put("childNode", null);
String identifier = create(incoming.get(0), childNode,model,process,sequenceFlows);
for (int i = 1; i < incoming.size(); i++) {
FlowElement flowElement1 = model.getFlowElement(incoming.get(i));
process.addFlowElement(connect(flowElement1.getId(), identifier,sequenceFlows));
}
// 1.1 边连接完成后在进行 nextNode 创建
if (Objects.nonNull(nextNode)) {
return create(identifier, nextNode,model,process,sequenceFlows);
} else {
return identifier;
}
}
}
return parallelGatewayId;
}
private static String createServiceTask(com.alibaba.fastjson.JSONObject flowNode, Process process, List<SequenceFlow> sequenceFlows) {
List<String> incoming = flowNode.getJSONArray("incoming").toJavaList(String.class);
// 自动生成id
String id = id("serviceTask");
if (incoming != null && !incoming.isEmpty()) {
ServiceTask serviceTask = new ServiceTask();
serviceTask.setName(flowNode.getString("nodeName"));
serviceTask.setId(id);
// todo lvshaohua
serviceTask.setImplementationType("class");
serviceTask.setImplementation("com.dingding.mid.listener.Vue3Listener");
process.addFlowElement(serviceTask);
process.addFlowElement(connect(incoming.get(0), id,sequenceFlows));
}
return id;
}
private static String createTask(com.alibaba.fastjson.JSONObject flowNode, Process process, List<SequenceFlow> sequenceFlows) {
List<String> incoming = flowNode.getJSONArray("incoming").toJavaList(String.class);
// 自动生成id
String id = flowNode.getString("nodeId");
if (incoming != null && !incoming.isEmpty()) {
UserTask userTask = new UserTask();
userTask.setName(flowNode.getString("nodeName"));
userTask.setId(id);
process.addFlowElement(userTask);
if(BpmFlowNodeType.NODE_STARTER.name().equals(flowNode.getString("type"))){
id = BpmConstants.START_EVENT_ID;
}
else{
// if ((!ObjectUtils.isEmpty(flowNode.getJSONArray("nodeUserList")) && flowNode.getJSONArray("nodeUserList").size() > 1)
// || flowNode.getBoolean(""))
MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics=new MultiInstanceLoopCharacteristics();
String examineMode = flowNode.getString("examineMode");
// 审批人集合参数
multiInstanceLoopCharacteristics.setInputDataItem(userTask.getId()+"_assigneeList");
// 迭代集合
multiInstanceLoopCharacteristics.setElementVariable("assignee");
// 并行
multiInstanceLoopCharacteristics.setSequential(false);
// userTask.setAssignee("${assigneeName}");
// 设置多实例属性
if("NEXT".equals(examineMode)){
multiInstanceLoopCharacteristics.setSequential(true);
} else if("OR".equals(examineMode)){
multiInstanceLoopCharacteristics.setCompletionCondition("${nrOfCompletedInstances==1}");
} else if ("AND".equals(examineMode)) {
multiInstanceLoopCharacteristics.setCompletionCondition("${nrOfCompletedInstances==nrOfInstances}");
}
ArrayList<FlowableListener> taskListeners = new ArrayList<>();
FlowableListener taskListener = new FlowableListener();
// 事件类型,
taskListener.setEvent(TaskListener.EVENTNAME_CREATE);
// 监听器类型
taskListener.setImplementationType(IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
// 设置实现了这里设置监听器的类型是delegateExpression这样可以在实现类注入Spring bean.
taskListener.setImplementation("${DDTaskCreateListener}");
taskListeners.add(taskListener);
userTask.setLoopCharacteristics(multiInstanceLoopCharacteristics);
userTask.setTaskListeners(taskListeners);
}
SequenceFlow sequenceFlow = connect(incoming.get(0), id,sequenceFlows);
if (sequenceFlow != null) {
process.addFlowElement(sequenceFlow);
}
}
return id;
}
@SneakyThrows
private static String id(String prefix) {
long qutient = (System.currentTimeMillis() - DateUtils.parseDate("2020-08-01", "yyyy-MM-dd").getTime());
qutient += Math.ceil(Math.random() * 1000); // 防止重複
String chars = "0123456789ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz";
int radix = chars.length();
StringBuilder stringBuffer = new StringBuilder(prefix + "_");
do {
int mod = (int) (qutient % radix);
qutient = ( qutient - mod ) / radix;
stringBuffer.append(chars.charAt(mod));
} while ( qutient > 0 );
return stringBuffer.toString();
return prefix + "_" + UUID.randomUUID().toString().replace("-", "").toLowerCase();
}
private static ServiceTask serviceTask(String name) {
@ -251,35 +79,283 @@ public class BpmTransformUtil {
return serviceTask;
}
protected static SequenceFlow connect(String from, String to,List<SequenceFlow> sequenceFlows) {
public static SequenceFlow connect(String from, String to,List<SequenceFlow> sequenceFlows,Map<String,BpmJsonNode> childNodeMap,Process process) {
SequenceFlow flow = new SequenceFlow();
flow.setId(id("sequenceFlow"));
String sequenceFlowId = id("sequenceFlow");
if(process.getFlowElement(from) !=null && process.getFlowElement(from) instanceof ExclusiveGateway){
BpmJsonNode childNode = childNodeMap.get(to);
if(childNode!=null){
String parentId = childNode.getParentId();
if(StringUtils.isNotBlank(parentId)){
BpmJsonNode parentNode = childNodeMap.get(parentId);
if(parentNode!=null){
if(BpmFlowNodeType.NODE_CONDITION.getType().equals(parentNode.getType()) ){
sequenceFlowId=parentNode.getId();
flow.setName(parentNode.getName());
if(!Boolean.TRUE.equals(parentNode.getProperty().getDefaultCondition())){
//解析条件表达式
StringBuffer conditionExpression=new StringBuffer();
conditionExpression.append("${ ( ");
conditionExpression.append(EXPRESSION_CLASS+"numberEquals("+parentNode.getProperty().getConditionKey()+","+parentNode.getProperty().getConditionBranchValue()+") ");
conditionExpression.append(" ) }");
flow.setConditionExpression(conditionExpression.toString());
}
}
}
}
}
}
flow.setId(sequenceFlowId);
flow.setSourceRef(from);
flow.setTargetRef(to);
// 连接线必须同时有 source target
if (from == null || to == null) {
return null;
}
sequenceFlows.add(flow);
return flow;
}
protected static StartEvent createStartEvent() {
public static StartEvent createStartEvent() {
StartEvent startEvent = new StartEvent();
startEvent.setId(id("start"));
startEvent.setId(START_EVENT_ID);
startEvent.setInitiator("applyUserId");
return startEvent;
}
protected static EndEvent createEndEvent() {
public static EndEvent createEndEvent() {
EndEvent endEvent = new EndEvent();
endEvent.setId(id("end"));
endEvent.setId(END_EVENT_ID);
return endEvent;
}
// public static StartEvent createStartEvent() {
// StartEvent startEvent = new StartEvent();
// startEvent.setId(WorkflowConstants.START_EVENT_ID);
// startEvent.setInitiator("applyUserId");
// return startEvent;
// }
public static String create(String fromId, BpmJsonNode flowNode, Process process,BpmnModel bpmnModel,List<SequenceFlow> sequenceFlows,Map<String,BpmJsonNode> childNodeMap) throws InvocationTargetException, IllegalAccessException {
String nodeType = flowNode.getType();
if (BpmFlowNodeType.NODE_CONDITION.isEqual(nodeType)) {
return createExclusiveGatewayBuilder(fromId, flowNode,process,bpmnModel,sequenceFlows,childNodeMap);
} else if (BpmFlowNodeType.NODE_TASK.isEqual(nodeType)) {
childNodeMap.put(flowNode.getId(),flowNode);
Map incoming = flowNode.getIncoming();
incoming.put("incoming", Collections.singletonList(fromId));
String id = createTask(process,flowNode,sequenceFlows,childNodeMap);
// 如果当前任务还有后续任务则遍历创建后续任务
BpmJsonNode children = flowNode.getChildren();
if (Objects.nonNull(children) &&StringUtils.isNotBlank(children.getId())) {
return create(id, children,process,bpmnModel,sequenceFlows,childNodeMap);
} else {
return id;
}
}
else if(BpmFlowNodeType.NODE_STARTER.isEqual(nodeType)){
childNodeMap.put(flowNode.getId(),flowNode);
Map incoming = flowNode.getIncoming();
incoming.put("incoming", Collections.singletonList(fromId));
String id = createTask(process,flowNode,sequenceFlows,childNodeMap);
// 如果当前任务还有后续任务则遍历创建后续任务
BpmJsonNode children = flowNode.getChildren();
if (Objects.nonNull(children) &&StringUtils.isNotBlank(children.getId())) {
return create(id, children,process,bpmnModel,sequenceFlows,childNodeMap);
} else {
return id;
}
}
else {
throw new RuntimeException("未知节点类型: nodeType=" + nodeType);
}
}
public static ExclusiveGateway createExclusiveGateWayEnd(String id){
ExclusiveGateway exclusiveGateway=new ExclusiveGateway();
exclusiveGateway.setId(id);
return exclusiveGateway;
}
private static String createExclusiveGatewayBuilder(String formId, BpmJsonNode flowNode,Process process,BpmnModel bpmnModel,List<SequenceFlow> sequenceFlows,Map<String,BpmJsonNode> childNodeMap) throws InvocationTargetException, IllegalAccessException {
childNodeMap.put(flowNode.getId(),flowNode);
String name =flowNode.getName();
String exclusiveGatewayId = flowNode.getId();
ExclusiveGateway exclusiveGateway = new ExclusiveGateway();
exclusiveGateway.setId(exclusiveGatewayId);
exclusiveGateway.setName(name);
process.addFlowElement(exclusiveGateway);
process.addFlowElement(connect(formId, exclusiveGatewayId,sequenceFlows,childNodeMap,process));
if (Objects.isNull(flowNode.getBranches()) && Objects.isNull(flowNode.getChildren())) {
return exclusiveGatewayId;
}
List<BpmJsonNode> flowNodes = flowNode.getBranches();
List<String> incoming = Lists.newArrayListWithCapacity(flowNodes.size());
List<Map> conditions = Lists.newCopyOnWriteArrayList();
for (BpmJsonNode element : flowNodes) {
Boolean typeElse = element.getProperty().getDefaultCondition();
if(Boolean.TRUE.equals(typeElse)){
exclusiveGateway.setDefaultFlow(element.getId());
}
childNodeMap.put(element.getId(),element);
BpmJsonNode childNode = element.getChildren();
String nodeName = element.getName();
if (Objects.isNull(childNode) || StringUtils.isBlank(childNode.getId())) {
incoming.add(exclusiveGatewayId);
Map condition = new HashMap();
//解析条件表达式
StringBuffer conditionExpression=new StringBuffer();
conditionExpression.append("${ ( ");
conditionExpression.append(EXPRESSION_CLASS+"numberEquals("+element.getProperty().getConditionKey()+","+element.getProperty().getConditionBranchValue()+") ");
conditionExpression.append(" ) }");
condition.put("nodeName", nodeName);
condition.put("expression", conditionExpression.toString());
conditions.add(condition);
continue;
}
// 只生成一个任务同时设置当前任务的条件
Map incomingObj = childNode.getIncoming();
incomingObj.put("incoming", Collections.singletonList(exclusiveGatewayId));
String identifier = create(exclusiveGatewayId, childNode,process,bpmnModel,sequenceFlows,childNodeMap);
List<SequenceFlow> flows = sequenceFlows.stream().filter(flow -> StringUtils.equals(exclusiveGatewayId, flow.getSourceRef()))
.collect(Collectors.toList());
flows.stream().forEach(
e -> {
if (StringUtils.isBlank(e.getName()) && StringUtils.isNotBlank(nodeName)) {
e.setName(nodeName);
}
// 设置条件表达式
// TODO 不知道什么意思
// if (Objects.isNull(e.getConditionExpression()) && StringUtils.isNotBlank(expression)) {
// e.setConditionExpression(expression);
// }
}
);
if (Objects.nonNull(identifier)) {
incoming.add(identifier);
}
}
BpmJsonNode childNode = flowNode.getChildren();
if (Objects.nonNull(childNode) &&StringUtils.isNotBlank(childNode.getId()) ) {
String parentId = childNode.getParentId();
BpmJsonNode parentChildNode = childNodeMap.get(parentId);
if(BpmFlowNodeType.NODE_CONDITION.getType().equals(parentChildNode.getType())){
String endExId= parentChildNode.getId()+"end";
process.addFlowElement(createExclusiveGateWayEnd(endExId));
if (incoming == null || incoming.isEmpty()) {
return create(exclusiveGatewayId, childNode, process, bpmnModel, sequenceFlows,
childNodeMap);
}
else {
Map incomingObj = childNode.getIncoming();
// 所有 service task 连接 end exclusive gateway
incomingObj.put("incoming", incoming);
FlowElement flowElement = bpmnModel.getFlowElement(incoming.get(0));
// 1.0 先进行边连接, 暂存 nextNode
BpmJsonNode nextNode = childNode.getChildren();
childNode.setChildren(null);
String identifier = endExId;
for (int i = 0; i < incoming.size(); i++) {
process.addFlowElement(connect(incoming.get(i), identifier, sequenceFlows,childNodeMap,process));
}
// 针对 gateway 空任务分支 添加条件表达式
if (!conditions.isEmpty()) {
FlowElement flowElement1 = bpmnModel.getFlowElement(identifier);
// 获取从 gateway 到目标节点 未设置条件表达式的节点
List<SequenceFlow> flows = sequenceFlows.stream().filter(
flow -> StringUtils.equals(flowElement1.getId(), flow.getTargetRef()))
.filter(
flow -> StringUtils.equals(flow.getSourceRef(), exclusiveGatewayId))
.collect(Collectors.toList());
flows.stream().forEach(sequenceFlow -> {
if (!conditions.isEmpty()) {
Map condition = conditions.get(0);
String nodeName = (String) condition.get("nodeName");
String expression = (String) condition.get("expression");
if (StringUtils.isBlank(sequenceFlow.getName()) && StringUtils
.isNotBlank(nodeName)) {
sequenceFlow.setName(nodeName);
}
// 设置条件表达式
if (Objects.isNull(sequenceFlow.getConditionExpression())
&& StringUtils.isNotBlank(expression)) {
sequenceFlow.setConditionExpression(expression);
}
conditions.remove(0);
}
});
}
// 1.1 边连接完成后在进行 nextNode 创建
if (Objects.nonNull(nextNode) &&StringUtils.isNotBlank(nextNode.getId())) {
return create(identifier, nextNode, process, bpmnModel, sequenceFlows,
childNodeMap);
} else {
return identifier;
}
}
}
}
return exclusiveGatewayId;
}
private static String createTask(Process process,BpmJsonNode flowNode,List<SequenceFlow> sequenceFlows,Map<String,BpmJsonNode> childNodeMap) {
Map incomingJson = flowNode.getIncoming();
List<String> incoming = (List<String>) incomingJson.get("incoming");
// 自动生成id
// String id = id("serviceTask");
String id=flowNode.getId();
if (incoming != null && !incoming.isEmpty()) {
UserTask userTask = new UserTask();
userTask.setName(flowNode.getName());
userTask.setId(id);
process.addFlowElement(userTask);
process.addFlowElement(connect(incoming.get(0), id,sequenceFlows,childNodeMap,process));
FlowableListener createTaskListener = new FlowableListener();
createTaskListener.setEvent(TaskListener.EVENTNAME_ALL_EVENTS);
createTaskListener.setImplementationType(IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
createTaskListener.setImplementation("${engineTaskEventListener}");
userTask.setTaskListeners(Arrays.asList(createTaskListener));
if("root".equalsIgnoreCase(id)){
}
else{
ArrayList<FlowableListener> listeners = new ArrayList<>();
FlowableListener activitiListener = new FlowableListener();
activitiListener.setEvent(ExecutionListener.EVENTNAME_START);
activitiListener.setImplementationType(IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
activitiListener.setImplementation("${counterSignListener}");
listeners.add(activitiListener);
userTask.setExecutionListeners(listeners);
if (Boolean.TRUE.equals(flowNode.getProperty().getIsMultiTask())) {
BpmJsonNodeProperty property = flowNode.getProperty();
BpmFlowMultiMode mode = property.getMultiMode();
MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = new MultiInstanceLoopCharacteristics();
// 审批人集合参数
multiInstanceLoopCharacteristics.setInputDataItem(userTask.getId()+"assigneeList");
// 迭代集合
multiInstanceLoopCharacteristics.setElementVariable("assigneeName");
// 并行
multiInstanceLoopCharacteristics.setSequential(false);
userTask.setAssignee("${assigneeName}");
// 设置多实例属性
userTask.setLoopCharacteristics(multiInstanceLoopCharacteristics);
if(BpmFlowMultiMode.OR.getType().equals(mode.getType())){
multiInstanceLoopCharacteristics.setCompletionCondition("${nrOfCompletedInstances/nrOfInstances > 0}");
} else if (BpmFlowMultiMode.AND.getType().equals(mode.getType())){
multiInstanceLoopCharacteristics.setCompletionCondition("${nrOfInstances == nrOfCompletedInstances}");
}
}
}
}
return id;
}
}

View File

@ -0,0 +1,23 @@
package cn.axzo.workflow.core.deletege;
import lombok.Data;
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
import org.flowable.identitylink.api.IdentityLink;
import org.flowable.identitylink.api.IdentityLinkType;
import org.flowable.task.api.DelegationState;
import java.util.Collection;
import java.util.Date;
import java.util.Set;
@Data
public class BpmTaskCalculateDTO {
private String taskId;
private String taskName;
private String processDefinitionId;
private String processInstanceId;
private String taskDefinitionKey;
private String category;
private String tenantId;
}

View File

@ -5,5 +5,5 @@ import org.flowable.task.service.delegate.DelegateTask;
import java.util.List;
public interface BpmTaskDelegate {
List<BpmTaskDelegateAssigner> calculateAssignerAtExecution(DelegateTask delegateTask);
List<BpmTaskDelegateAssigner> calculateAssignerAtExecution(BpmTaskCalculateDTO delegateTask);
}

View File

@ -2,9 +2,8 @@ package cn.axzo.workflow.core.service;
import cn.axzo.workflow.core.service.dto.response.process.BpmProcessInstanceVO;
import cn.axzo.workflow.core.service.dto.request.process.BpmProcessInstanceCreateDTO;
import cn.axzo.workflow.core.service.dto.response.process.BpmProcessInstanceWithdrawDTO;
import cn.axzo.workflow.core.service.dto.request.process.BpmProcessInstanceWithdrawDTO;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
public interface BpmProcessInstanceService {

View File

@ -1,10 +1,14 @@
package cn.axzo.workflow.core.service.dto;
import cn.axzo.workflow.core.common.enums.BpmFlowNodeType;
import cn.axzo.workflow.core.service.dto.request.BpmJsonNodeProperty;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Data
public class BpmJsonNode {
@ApiModelProperty(value = "节点ID", required = true)
@ -25,6 +29,11 @@ public class BpmJsonNode {
private BpmJsonNode children;
@ApiModelProperty(value = "分支节点信息", required = true)
private List<BpmJsonNode> branches;
private BpmJsonNodeProperty property;
/*自己使用,不需要外界传*/
private Map incoming;
public BpmJsonNode() {
}
@ -84,4 +93,8 @@ public class BpmJsonNode {
public void setBranches(List<BpmJsonNode> branches) {
this.branches = branches;
}
class properties {
}
}

View File

@ -0,0 +1,35 @@
package cn.axzo.workflow.core.service.dto.request;
import cn.axzo.workflow.core.common.enums.BpmFlowMultiMode;
import lombok.Data;
@Data
public class BpmJsonNodeProperty {
/**
* 是否是多实例节点
* */
private Boolean isMultiTask;
/**
* 多实例模式OR"或签"AND"会签"
* */
private BpmFlowMultiMode multiMode;
/**
* 条件节点中是否是默认分支
* */
private Boolean defaultCondition;
/**
* 条件分支的Key
* */
private String conditionKey;
/**
* 当ConditionKey的值是多少走该分支
* */
private Integer conditionBranchValue;
}

View File

@ -1,4 +1,4 @@
package cn.axzo.workflow.core.service.dto.response.process;
package cn.axzo.workflow.core.service.dto.request.process;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

View File

@ -0,0 +1,54 @@
package cn.axzo.workflow.core.service.engine;
import cn.axzo.workflow.core.deletege.BpmTaskCalculateDTO;
import cn.axzo.workflow.core.deletege.BpmTaskDelegate;
import cn.axzo.workflow.core.deletege.BpmTaskDelegateAssigner;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* 在这里设置审批人
* */
@Component
public class EngineExecutionStartListener implements ExecutionListener {
@Resource
private RepositoryService repositoryService;
@Resource
private BpmTaskDelegate bpmTaskDelegate;
@Override
public void notify(DelegateExecution execution) {
String currentActivityId = execution.getCurrentActivityId();
Process mainProcess = repositoryService.getBpmnModel(execution.getProcessDefinitionId()).getMainProcess();
UserTask userTask = (UserTask) mainProcess.getFlowElement(currentActivityId);
String variable=currentActivityId+"assigneeList";
List usersValue = (List) execution.getVariable(variable);
if(usersValue==null){
BpmTaskCalculateDTO calculateDTO = new BpmTaskCalculateDTO();
calculateDTO.setTaskId(userTask.getId());
calculateDTO.setCategory(userTask.getCategory());
calculateDTO.setProcessDefinitionId(execution.getProcessDefinitionId());
calculateDTO.setProcessInstanceId(execution.getProcessInstanceId());
calculateDTO.setTaskName(userTask.getName());
calculateDTO.setTenantId(execution.getTenantId());
calculateDTO.setTaskDefinitionKey(currentActivityId);
List<BpmTaskDelegateAssigner> assigners = bpmTaskDelegate.calculateAssignerAtExecution(calculateDTO);
List<String> assigneeIdList= new ArrayList<>();
for (BpmTaskDelegateAssigner user : assigners) {
assigneeIdList.add(user.getAssignerId());
}
execution.setVariable(variable,assigneeIdList);
}
}
}

View File

@ -5,7 +5,6 @@ import cn.axzo.workflow.core.common.enums.BpmProcessInstanceResultEnum;
import cn.axzo.workflow.core.common.enums.BpmProcessInstanceStatusEnum;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.common.utils.BpmCollectionUtils;
import cn.axzo.workflow.core.repository.entity.BpmProcessDefinitionExtDO;
import cn.axzo.workflow.core.repository.entity.BpmProcessInstanceExtDO;
import cn.axzo.workflow.core.repository.mapper.BpmProcessInstanceExtMapper;
import cn.axzo.workflow.core.service.dto.response.process.BpmProcessInstanceVO;
@ -13,14 +12,11 @@ import cn.axzo.workflow.core.service.BpmProcessDefinitionService;
import cn.axzo.workflow.core.service.BpmProcessInstanceService;
import cn.axzo.workflow.core.service.BpmTaskService;
import cn.axzo.workflow.core.service.dto.request.process.BpmProcessInstanceCreateDTO;
import cn.axzo.framework.domain.web.BizException;
import cn.axzo.workflow.core.service.dto.response.process.BpmProcessInstanceWithdrawDTO;
import cn.axzo.workflow.core.service.dto.request.process.BpmProcessInstanceWithdrawDTO;
import cn.azxo.framework.common.utils.StringUtils;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;

View File

@ -4,7 +4,7 @@ import cn.axzo.framework.jackson.utility.JSON;
import cn.axzo.workflow.core.service.BpmProcessInstanceService;
import cn.axzo.workflow.core.service.dto.request.process.BpmProcessInstanceCreateDTO;
import cn.axzo.workflow.core.service.dto.response.process.BpmProcessInstanceVO;
import cn.axzo.workflow.core.service.dto.response.process.BpmProcessInstanceWithdrawDTO;
import cn.axzo.workflow.core.service.dto.request.process.BpmProcessInstanceWithdrawDTO;
import cn.azxo.framework.common.model.CommonResponse;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.history.HistoricProcessInstance;

View File

@ -0,0 +1,575 @@
{
"id":"root",
"desc":"任何人",
"name":"发起人",
"type":"ROOT",
"props":{
"formPerms":[
{
"id":"field6315293116649",
"perm":"E",
"title":"单行文本输入",
"required":false
},
{
"id":"field2424440922220",
"perm":"E",
"title":"单行文本输入1",
"required":false
},
{
"id":"field3654540926170",
"perm":"E",
"title":"日期时间点",
"required":false
},
{
"id":"field6931940950104",
"perm":"E",
"title":"多选框",
"required":false
},
{
"id":"field8821740927538",
"perm":"E",
"title":"日期时间区间",
"required":false
},
{
"id":"field5416940932938",
"perm":"E",
"title":"说明文字",
"required":false
},
{
"id":"field1905040930820",
"perm":"E",
"title":"部门选择",
"required":false
},
{
"id":"field6136640929087",
"perm":"E",
"title":"上传图片",
"required":false
}
],
"assignedUser":[
{
"id":231535,
"name":"生产管理部",
"type":"dept",
"selected":false
},
{
"id":4319868,
"name":"销售服务部",
"type":"dept",
"selected":false
}
]
},
"children":{
"id":"node_598263651142",
"name":"审批人",
"type":"APPROVAL",
"props":{
"mode":"AND",
"role":[
],
"sign":false,
"leader":{
"level":1
},
"nobody":{
"handler":"TO_PASS",
"assignedUser":[
]
},
"refuse":{
"type":"TO_END",
"target":""
},
"formUser":"",
"formPerms":[
{
"id":"field6315293116649",
"perm":"R",
"title":"单行文本输入",
"required":false
},
{
"id":"field2424440922220",
"perm":"R",
"title":"单行文本输入1",
"required":false
},
{
"id":"field3654540926170",
"perm":"R",
"title":"日期时间点",
"required":false
},
{
"id":"field6931940950104",
"perm":"R",
"title":"多选框",
"required":false
},
{
"id":"field8821740927538",
"perm":"R",
"title":"日期时间区间",
"required":false
},
{
"id":"field5416940932938",
"perm":"R",
"title":"说明文字",
"required":false
},
{
"id":"field1905040930820",
"perm":"R",
"title":"部门选择",
"required":false
},
{
"id":"field6136640929087",
"perm":"R",
"title":"上传图片",
"required":false
}
],
"leaderTop":{
"endLevel":1,
"endCondition":"TOP"
},
"timeLimit":{
"handler":{
"type":"REFUSE",
"notify":{
"hour":1,
"once":true
}
},
"timeout":{
"unit":"H",
"value":0
}
},
"selfSelect":{
"multiple":false
},
"assignedType":"LEADER",
"assignedUser":[
{
"id":61769798,
"name":"李四",
"type":"user",
"selected":true
}
]
},
"children":{
"id":"node_698816342966",
"name":"审批人",
"type":"APPROVAL",
"props":{
"mode":"OR",
"role":[
],
"sign":false,
"leader":{
"level":1
},
"nobody":{
"handler":"TO_PASS",
"assignedUser":[
]
},
"refuse":{
"type":"TO_END",
"target":""
},
"formUser":"",
"formPerms":[
{
"id":"field6315293116649",
"perm":"R",
"title":"单行文本输入",
"required":false
},
{
"id":"field2424440922220",
"perm":"R",
"title":"单行文本输入1",
"required":false
},
{
"id":"field3654540926170",
"perm":"R",
"title":"日期时间点",
"required":false
},
{
"id":"field6931940950104",
"perm":"R",
"title":"多选框",
"required":false
},
{
"id":"field8821740927538",
"perm":"R",
"title":"日期时间区间",
"required":false
},
{
"id":"field5416940932938",
"perm":"R",
"title":"说明文字",
"required":false
},
{
"id":"field1905040930820",
"perm":"R",
"title":"部门选择",
"required":false
},
{
"id":"field6136640929087",
"perm":"R",
"title":"上传图片",
"required":false
}
],
"leaderTop":{
"endLevel":1,
"endCondition":"TOP"
},
"timeLimit":{
"handler":{
"type":"REFUSE",
"notify":{
"hour":1,
"once":true
}
},
"timeout":{
"unit":"H",
"value":0
}
},
"selfSelect":{
"multiple":true
},
"assignedType":"SELF_SELECT",
"assignedUser":[
]
},
"children":{
"id":"node_905097096913",
"name":"条件分支",
"type":"CONDITIONS",
"props":{
},
"branchs":[
{
"id":"node_905097097011",
"name":"条件1",
"type":"CONDITION",
"props":{
"groups":[
{
"cids":[
"root"
],
"groupType":"AND",
"conditions":[
{
"id":"root",
"title":"发起人",
"value":[
{
"id":381496,
"name":"旅人",
"type":"user",
"selected":false
}
],
"compare":"",
"valueType":"User"
}
]
}
],
"expression":"",
"groupsType":"AND"
},
"children":{
"id":"node_275574083794",
"name":"审批人",
"type":"APPROVAL",
"props":{
"mode":"AND",
"role":[
],
"sign":false,
"leader":{
"level":1
},
"nobody":{
"handler":"TO_PASS",
"assignedUser":[
]
},
"refuse":{
"type":"TO_END",
"target":""
},
"formUser":"",
"formPerms":[
{
"id":"field6315293116649",
"perm":"R",
"title":"单行文本输入",
"required":false
},
{
"id":"field2424440922220",
"perm":"R",
"title":"单行文本输入1",
"required":false
},
{
"id":"field3654540926170",
"perm":"R",
"title":"日期时间点",
"required":false
},
{
"id":"field6931940950104",
"perm":"R",
"title":"多选框",
"required":false
},
{
"id":"field8821740927538",
"perm":"R",
"title":"日期时间区间",
"required":false
},
{
"id":"field5416940932938",
"perm":"R",
"title":"说明文字",
"required":false
},
{
"id":"field1905040930820",
"perm":"R",
"title":"部门选择",
"required":false
},
{
"id":"field6136640929087",
"perm":"R",
"title":"上传图片",
"required":false
}
],
"leaderTop":{
"endLevel":1,
"endCondition":"TOP"
},
"timeLimit":{
"handler":{
"type":"REFUSE",
"notify":{
"hour":1,
"once":true
}
},
"timeout":{
"unit":"H",
"value":0
}
},
"selfSelect":{
"multiple":false
},
"assignedType":"LEADER",
"assignedUser":[
]
},
"children":{
},
"parentId":"node_905097097011"
},
"parentId":"node_905097096913"
},
{
"id":"node_905097094019",
"name":"条件2",
"type":"CONDITION",
"props":{
"groups":[
{
"cids":[
"root"
],
"groupType":"AND",
"conditions":[
{
"id":"root",
"title":"发起人",
"value":[
{
"id":381496,
"name":"旅人",
"type":"user",
"selected":false
}
],
"compare":"",
"valueType":"User"
}
]
}
],
"expression":"",
"groupsType":"OR"
},
"children":{
"id":"node_275658471060",
"name":"审批人",
"type":"APPROVAL",
"props":{
"mode":"AND",
"role":[
],
"sign":false,
"leader":{
"level":1
},
"nobody":{
"handler":"TO_PASS",
"assignedUser":[
]
},
"refuse":{
"type":"TO_END",
"target":""
},
"formUser":"",
"formPerms":[
{
"id":"field6315293116649",
"perm":"R",
"title":"单行文本输入",
"required":false
},
{
"id":"field2424440922220",
"perm":"R",
"title":"单行文本输入1",
"required":false
},
{
"id":"field3654540926170",
"perm":"R",
"title":"日期时间点",
"required":false
},
{
"id":"field6931940950104",
"perm":"R",
"title":"多选框",
"required":false
},
{
"id":"field8821740927538",
"perm":"R",
"title":"日期时间区间",
"required":false
},
{
"id":"field5416940932938",
"perm":"R",
"title":"说明文字",
"required":false
},
{
"id":"field1905040930820",
"perm":"R",
"title":"部门选择",
"required":false
},
{
"id":"field6136640929087",
"perm":"R",
"title":"上传图片",
"required":false
}
],
"leaderTop":{
"endLevel":1,
"endCondition":"TOP"
},
"timeLimit":{
"handler":{
"type":"REFUSE",
"notify":{
"hour":1,
"once":true
}
},
"timeout":{
"unit":"H",
"value":0
}
},
"selfSelect":{
"multiple":false
},
"assignedType":"SELF_SELECT",
"assignedUser":[
]
},
"children":{
},
"parentId":"node_905097094019"
},
"parentId":"node_905097096913"
}
],
"children":{
"id":"node_905097099172",
"type":"EMPTY",
"children":{
},
"parentId":"node_905097096913"
},
"parentId":"node_698816342966"
},
"parentId":"node_598263651142"
},
"parentId":"root"
},
"parentId":null
}