From 26894bb889c6d278390e79513e2a6a761438d647 Mon Sep 17 00:00:00 2001 From: wangli <274027703@qq.com> Date: Wed, 15 Nov 2023 15:40:20 +0800 Subject: [PATCH] =?UTF-8?q?update=20-=20=E5=AE=8C=E5=96=84=20BPMN=20?= =?UTF-8?q?=E5=8D=8F=E8=AE=AE=20JSON=20=E8=BD=AC=E6=8D=A2=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/model/dto/CooperationOrgDTO.java | 47 ++ .../model/request/bpmn/BpmnFieldConf.java | 37 -- .../request/bpmn/BpmnFieldOptionConf.java | 47 ++ .../request/bpmn/BpmnJsonNodeProperty.java | 2 +- .../process/BpmnProcessInstanceCreateDTO.java | 9 + .../common/utils/BpmnJsonConverterUtil.java | 198 ++++++- .../json/ReceiveTaskJsonConverter.java | 25 + .../converter/json/UserTaskJsonConverter.java | 126 ++++ .../impl/BpmnProcessModelServiceImpl.java | 1 + .../src/main/resources/test.bpmn20.xml | 365 ++++++++++++ .../src/main/resources/test.json | 552 +++++++++++++++++- 11 files changed, 1345 insertions(+), 64 deletions(-) create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CooperationOrgDTO.java create mode 100644 workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnFieldOptionConf.java create mode 100644 workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/ReceiveTaskJsonConverter.java create mode 100644 workflow-engine-server/src/main/resources/test.bpmn20.xml diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CooperationOrgDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CooperationOrgDTO.java new file mode 100644 index 000000000..0a31776f0 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/CooperationOrgDTO.java @@ -0,0 +1,47 @@ +package cn.axzo.workflow.common.model.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 组织架构人员选择器 + * 协同组织列表的限制条件 + * + * @author tanjie@axzo.cn + * @date 2023/11/14 11:29 + */ +@Data +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +public class CooperationOrgDTO { + + /** + * 企业组织架构 + */ + private List entOrg; + /** + * 项目部工作台 + */ + private Long projWorkspaceId; + + /** + * 参与项目部工作台的指定单位 + */ + private List projOuId; + + + @Data + @Accessors(chain = true) + @NoArgsConstructor + @AllArgsConstructor + public static class OrgScope { + private Long workspaceId; + + private Long ouId; + } +} diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnFieldConf.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnFieldConf.java index ff49cb2ac..e7604f4e6 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnFieldConf.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnFieldConf.java @@ -51,40 +51,3 @@ public class BpmnFieldConf { private List options; } -/** - * 单选/多选的选项配置 - */ -@Accessors(chain = true) -@Data -@NoArgsConstructor -class BpmnFieldOptionConf { - /** - * 选项的名称 - */ - @ApiModelProperty(value = "选项的名称", example = "选项1") - @NotBlank(message = "选项的名称不能为空") - private String name; - - /** - * 选项的值 - */ - @ApiModelProperty(value = "选项的值", example = "1") - @NotBlank(message = "选项的值不能为空") - private String value; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } -} diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnFieldOptionConf.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnFieldOptionConf.java new file mode 100644 index 000000000..58bbf85a8 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnFieldOptionConf.java @@ -0,0 +1,47 @@ +package cn.axzo.workflow.common.model.request.bpmn; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotBlank; + +/** + * 单选/多选的选项配置 + */ +@Accessors(chain = true) +@Data +@NoArgsConstructor +public class BpmnFieldOptionConf { + + /** + * 选项的名称 + */ + @ApiModelProperty(value = "选项的名称", example = "选项1") + @NotBlank(message = "选项的名称不能为空") + private String name; + + /** + * 选项的值 + */ + @ApiModelProperty(value = "选项的值", example = "1") + @NotBlank(message = "选项的值不能为空") + private String value; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnJsonNodeProperty.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnJsonNodeProperty.java index 3d35127ce..773137f80 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnJsonNodeProperty.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnJsonNodeProperty.java @@ -90,7 +90,7 @@ public class BpmnJsonNodeProperty { * 按钮权限 */ @ApiModelProperty(value = "发起人节点/任务节点: 按钮权限集合") - private List buttonPermission; + private BpmnButtonConf buttonPermission; //************* 条件节点Start **************// diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java index c15c73adc..870cbf885 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java @@ -1,11 +1,13 @@ package cn.axzo.workflow.common.model.request.bpmn.process; +import cn.axzo.workflow.common.model.dto.CooperationOrgDTO; import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; import java.util.HashMap; import java.util.Map; @@ -31,6 +33,13 @@ public class BpmnProcessInstanceCreateDTO { */ private Map variables = new HashMap<>(); + /** + * 组织关系 + */ + @ApiModelProperty(value = "组织关系") + @NotNull(message = "组织关系不能为空") + private CooperationOrgDTO cooperationOrg; + /** * 业务的唯一标识 *

diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnJsonConverterUtil.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnJsonConverterUtil.java index cdbbe41a6..d17d4f9d1 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnJsonConverterUtil.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnJsonConverterUtil.java @@ -1,27 +1,66 @@ package cn.axzo.workflow.core.common.utils; -import cn.axzo.workflow.common.model.request.bpmn.*; +import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf; +import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo; +import cn.axzo.workflow.common.model.request.bpmn.BpmnFieldConf; +import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode; +import cn.axzo.workflow.common.model.request.bpmn.BpmnNoticeConf; import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelCreateDTO; import cn.axzo.workflow.core.common.exception.WorkflowEngineException; -import cn.axzo.workflow.core.converter.json.*; +import cn.axzo.workflow.core.converter.json.AbstractBpmnJsonConverter; +import cn.axzo.workflow.core.converter.json.EndEventJsonConverter; +import cn.axzo.workflow.core.converter.json.ExclusiveGatewayJsonConverter; +import cn.axzo.workflow.core.converter.json.NotSupportConverter; +import cn.axzo.workflow.core.converter.json.ParallelGatewayJsonConverter; +import cn.axzo.workflow.core.converter.json.ReceiveTaskJsonConverter; +import cn.axzo.workflow.core.converter.json.SequenceFlowJsonConverter; +import cn.axzo.workflow.core.converter.json.ServiceTaskJsonConverter; +import cn.axzo.workflow.core.converter.json.StartEventJsonConverter; +import cn.axzo.workflow.core.converter.json.UserTaskJsonConverter; import com.alibaba.fastjson.JSON; import com.google.common.collect.Lists; import org.flowable.bpmn.BpmnAutoLayout; import org.flowable.bpmn.converter.BpmnXMLConverter; +import org.flowable.bpmn.model.BaseElement; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.EndEvent; +import org.flowable.bpmn.model.ExclusiveGateway; +import org.flowable.bpmn.model.ExtensionAttribute; +import org.flowable.bpmn.model.ExtensionElement; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.bpmn.model.Gateway; +import org.flowable.bpmn.model.ParallelGateway; import org.flowable.bpmn.model.Process; -import org.flowable.bpmn.model.*; +import org.flowable.bpmn.model.ReceiveTask; +import org.flowable.bpmn.model.SequenceFlow; +import org.flowable.bpmn.model.ServiceTask; +import org.flowable.bpmn.model.StartEvent; +import org.flowable.bpmn.model.UserTask; +import org.flowable.image.ProcessDiagramGenerator; +import org.flowable.image.impl.DefaultProcessDiagramGenerator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; +import java.io.File; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; -import static cn.axzo.workflow.common.constant.BpmnConstants.*; +import static cn.axzo.workflow.common.constant.BpmnConstants.END_EVENT_ID; +import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_NODE_JSON; +import static cn.axzo.workflow.common.constant.BpmnConstants.SEQUENCE_FLOW_ID; +import static cn.axzo.workflow.common.constant.BpmnConstants.START_EVENT_ID; import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_EMPTY; import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.CONVERTOR_COMMON_ERROR; @@ -45,6 +84,7 @@ public class BpmnJsonConverterUtil { converters.put(ParallelGateway.class, new ParallelGatewayJsonConverter()); converters.put(UserTask.class, new UserTaskJsonConverter()); converters.put(ServiceTask.class, new ServiceTaskJsonConverter()); + converters.put(ReceiveTask.class, new ReceiveTaskJsonConverter()); } /** @@ -86,9 +126,11 @@ public class BpmnJsonConverterUtil { mainProcess.setDocumentation(documentation); mainProcess.addAttribute(extensionAttribute); - + // 设置流程的通知管理配置 setProcessNoticeConfig(noticeConf, mainProcess); + // 设置流程的默认的按钮配置 setProcessButtonConfig(buttonConf, mainProcess); + // 设置流程的字段元数据配置 setProcessFieldConfig(fieldConf, mainProcess); bpmnModel.addProcess(mainProcess); @@ -112,12 +154,56 @@ public class BpmnJsonConverterUtil { } private static void setProcessFieldConfig(List fieldConf, Process mainProcess) { - // TODO + ExtensionElement fieldConfigElement = new ExtensionElement(); + fieldConfigElement.setName("fieldConfig"); + + if (!CollectionUtils.isEmpty(fieldConf)) { + fieldConf.forEach(i -> { + ExtensionElement field = new ExtensionElement(); + field.setName("filed"); + + ExtensionAttribute fieldDataType = new ExtensionAttribute(); + fieldDataType.setName("type"); + fieldDataType.setValue(i.getType()); + field.addAttribute(fieldDataType); + + ExtensionAttribute fieldName = new ExtensionAttribute(); + fieldName.setName("name"); + fieldName.setValue(i.getName()); + field.addAttribute(fieldName); + + ExtensionAttribute fieldCode = new ExtensionAttribute(); + fieldCode.setName("code"); + fieldCode.setValue(i.getCode()); + field.addAttribute(fieldCode); + + if (!CollectionUtils.isEmpty(i.getOptions())) { + i.getOptions().forEach(j -> { + ExtensionElement option = new ExtensionElement(); + option.setName("option"); + + ExtensionAttribute optionName = new ExtensionAttribute(); + optionName.setName("name"); + optionName.setValue(j.getName()); + option.addAttribute(optionName); + + ExtensionAttribute optionValue = new ExtensionAttribute(); + optionValue.setName("value"); + optionValue.setValue(j.getValue()); + option.addAttribute(optionValue); + + field.addChildElement(option); + }); + } + fieldConfigElement.addChildElement(field); + }); + } + mainProcess.addExtensionElement(fieldConfigElement); } private static void setProcessButtonConfig(BpmnButtonConf buttonConf, Process mainProcess) { ExtensionElement buttonConfigElement = new ExtensionElement(); - buttonConfigElement.setName("buttonConfigElement"); + buttonConfigElement.setName("buttonConfig"); buildMetaButton(buttonConf.getInitiator(), "initiator", buttonConfigElement); buildMetaButton(buttonConf.getCurrent(), "current", buttonConfigElement); @@ -127,7 +213,7 @@ public class BpmnJsonConverterUtil { mainProcess.addExtensionElement(buttonConfigElement); } - private static void buildMetaButton(List buttonMetaInfos, String buttonType, + public static void buildMetaButton(List buttonMetaInfos, String buttonType, ExtensionElement buttonConfigElement) { if (!CollectionUtils.isEmpty(buttonMetaInfos)) { ExtensionElement initiator = new ExtensionElement(); @@ -135,11 +221,15 @@ public class BpmnJsonConverterUtil { buttonMetaInfos.forEach(i -> { ExtensionElement button = new ExtensionElement(); button.setName(i.getBtnKey()); - ExtensionAttribute attribute = new ExtensionAttribute(); - attribute.setName("name"); - attribute.setValue(i.getBtnName()); - button.addAttribute(attribute); - button.setElementText(String.valueOf(i.getEnabled())); + ExtensionAttribute nameAttribute = new ExtensionAttribute(); + nameAttribute.setName("name"); + nameAttribute.setValue(i.getBtnName()); + button.addAttribute(nameAttribute); + + ExtensionAttribute valueAttribute = new ExtensionAttribute(); + valueAttribute.setName("value"); + valueAttribute.setValue(String.valueOf(i.getEnabled())); + button.addAttribute(valueAttribute); initiator.addChildElement(button); }); buttonConfigElement.addChildElement(initiator); @@ -148,7 +238,7 @@ public class BpmnJsonConverterUtil { private static void setProcessNoticeConfig(BpmnNoticeConf noticeConf, Process mainProcess) { ExtensionElement noticeConfigElement = new ExtensionElement(); - noticeConfigElement.setName("noticeConfigElement"); + noticeConfigElement.setName("noticeConfig"); // 通知消息模板配置 ExtensionElement noticeMessage = new ExtensionElement(); @@ -223,7 +313,17 @@ public class BpmnJsonConverterUtil { case NODE_CONDITION: clz = SequenceFlow.class; break; + case NODE_BUSINESS: + // "业务节点"是很特殊包装节点,因为它在前端有两种配法: + // 一种是: 可以不配置人, 当运行到该节点时, 需要由外部发送信号来触发(这个信号的发送方通常是程序应用), 流程继续运行. + // 另外一种是: 可以配置人, 当运行到该节点时, 有需要人为来处理. 这种情况下, 该节点就是一个普通的任务节点. + clz = ReceiveTask.class; + if (!Objects.equals("nobody", bpmnJsonNode.getProperty().getApprovalMethod())) { + clz = UserTask.class; + } + break; case NODE_TRIGGER: + // 这个类型目前暂不支持 case NODE_CARBON_COPY: // 这里可以细化, 带后续有实际场景了,再处理, 现目前只有 "抄送" 功能可能会用到 clz = ServiceTask.class; @@ -238,12 +338,15 @@ public class BpmnJsonConverterUtil { // 通用链接当前节点和前一个节点的 SequenceFlow if (preNodeIdList.size() > 1) { // 如果涉及到网关,那么 incoming 就是大于 1 - preNodeIdList.forEach(income -> { - Map> tmpIncomeMap = new HashMap<>(); - tmpIncomeMap.put("incoming", Lists.newArrayList(income)); - bpmnJsonNode.setIncoming(tmpIncomeMap); - mainProcess.addFlowElement(convertJsonToElement(SequenceFlow.class, bpmnJsonNode, mainProcess)); - }); + preNodeIdList.stream() + // 过滤掉自己 + .filter(income -> !Objects.equals(bpmnJsonNode.getId(), income)) + .forEach(income -> { + Map> tmpIncomeMap = new HashMap<>(); + tmpIncomeMap.put("incoming", Lists.newArrayList(income)); + bpmnJsonNode.setIncoming(tmpIncomeMap); + mainProcess.addFlowElement(convertJsonToElement(SequenceFlow.class, bpmnJsonNode, mainProcess)); + }); } else { FlowElement sequenceFlow = convertJsonToElement(SequenceFlow.class, bpmnJsonNode, mainProcess); mainProcess.addFlowElement(sequenceFlow); @@ -264,9 +367,12 @@ public class BpmnJsonConverterUtil { List gatewayPreIds = new ArrayList<>(); if (!CollectionUtils.isEmpty(bpmnJsonNode.getBranches())) { for (BpmnJsonNode branch : bpmnJsonNode.getBranches()) { - BpmnJsonNode children = branch.getChildren(); - children.setPreJsonNode(branch); - gatewayPreIds.add(create(children, mainProcess, bpmnModel, flowElement.getId())); + BpmnJsonNode children = Objects.isNull(branch.getChildren()) ? bpmnJsonNode.getChildren() : + branch.getChildren(); + if (Objects.nonNull(children)) { + children.setPreJsonNode(branch); + gatewayPreIds.add(create(children, mainProcess, bpmnModel, flowElement.getId())); + } } } @@ -329,6 +435,48 @@ public class BpmnJsonConverterUtil { model.getButtonConf(), model.getFieldConf()); System.out.println("bpmnModel = " + bpmnModel); transformBytes(bpmnModel); - + generateImage(bpmnModel); } + + public static void generateImage(BpmnModel bpmnModel) { + String pngName = "/Users/wangli/work/company/yizhi/workflow-engine/workflow-engine-server/src/main" + + "/resources/test.png"; + ProcessDiagramGenerator diagramGenerator = new DefaultProcessDiagramGenerator(); + + // 设置字体渲染选项 + System.setProperty("java.awt.headless", "false"); + System.setProperty("awt.useSystemAAFontSettings", "on"); + System.setProperty("swing.aatext", "true"); + System.setProperty("sun.java2d.xrender", "true"); + + try { + // 创建输出流 + OutputStream outputStream = Files.newOutputStream(new File(pngName).toPath()); + // 生成图像并写入输出流 + InputStream imageStream = diagramGenerator.generateDiagram(bpmnModel, "png", new ArrayList<>(), 1.0d, true); + + // 将图像流写入输出流 + try { + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = imageStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + } catch (Exception e) { + // 处理异常 + } finally { + try { + imageStream.close(); + outputStream.close(); + } catch (Exception e) { + // 处理异常 + } + } + // 关闭输出流 + outputStream.close(); + } catch (Exception e) { + // 处理异常 + } + } + } diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/ReceiveTaskJsonConverter.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/ReceiveTaskJsonConverter.java new file mode 100644 index 000000000..5888c3fa6 --- /dev/null +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/ReceiveTaskJsonConverter.java @@ -0,0 +1,25 @@ +package cn.axzo.workflow.core.converter.json; + +import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode; +import org.flowable.bpmn.model.Process; +import org.flowable.bpmn.model.ReceiveTask; + +/** + * 接收任务节点 + * + * @author wangli + * @since 2023/10/13 17:01 + */ +public class ReceiveTaskJsonConverter extends AbstractBpmnJsonConverter { + + @Override + public ReceiveTask convertJsonToElement(BpmnJsonNode node, Process process) { + ReceiveTask receiveTask = new ReceiveTask(); + + receiveTask.setId(node.getId()); + receiveTask.setName(node.getName()); + + return receiveTask; + } + +} diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/UserTaskJsonConverter.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/UserTaskJsonConverter.java index 3ee8a655a..f6367c77c 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/UserTaskJsonConverter.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/UserTaskJsonConverter.java @@ -1,17 +1,23 @@ package cn.axzo.workflow.core.converter.json; +import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf; import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode; +import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNodeProperty; +import org.flowable.bpmn.model.ExtensionAttribute; +import org.flowable.bpmn.model.ExtensionElement; import org.flowable.bpmn.model.FlowableListener; import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.UserTask; import org.flowable.engine.delegate.BaseExecutionListener; import org.flowable.engine.delegate.TaskListener; +import org.springframework.util.StringUtils; import java.util.ArrayList; import java.util.List; import java.util.Objects; import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER; +import static cn.axzo.workflow.core.common.utils.BpmnJsonConverterUtil.buildMetaButton; import static org.flowable.bpmn.model.ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION; /** @@ -28,6 +34,14 @@ public class UserTaskJsonConverter extends AbstractBpmnJsonConverter { userTask.setId(node.getId()); userTask.setName(node.getName()); + + // "设置审批人" + setApprovalExtensionElement(node, userTask); + // "权限设置" + setFieldExtensionElement(node, userTask); + // "高级设置" + setButtonExtensionElement(node, userTask); + setTaskListeners(userTask); if (!Objects.equals(NODE_STARTER, node.getType())) { @@ -37,6 +51,118 @@ public class UserTaskJsonConverter extends AbstractBpmnJsonConverter { return userTask; } + private static void setButtonExtensionElement(BpmnJsonNode node, UserTask userTask) { + if (Objects.isNull(node.getProperty())) { + return; + } + BpmnButtonConf buttonConf = node.getProperty().getButtonPermission(); + ExtensionElement buttonConfigElement = new ExtensionElement(); + buttonConfigElement.setName("buttonConfig"); + + if (Objects.nonNull(buttonConf)) { + buildMetaButton(buttonConf.getInitiator(), "initiator", buttonConfigElement); + buildMetaButton(buttonConf.getCurrent(), "current", buttonConfigElement); + buildMetaButton(buttonConf.getHistory(), "history", buttonConfigElement); + buildMetaButton(buttonConf.getCarbonCopy(), "carbonCopy", buttonConfigElement); + } + + userTask.addExtensionElement(buttonConfigElement); + } + + private static void setFieldExtensionElement(BpmnJsonNode node, UserTask userTask) { + if (Objects.isNull(node.getProperty())) { + return; + } + ExtensionElement fieldElement = new ExtensionElement(); + fieldElement.setName("fieldPermission"); + fieldElement.setElementText(node.getProperty().getFieldPermission()); + userTask.addExtensionElement(fieldElement); + } + + private static void setApprovalExtensionElement(BpmnJsonNode node, UserTask userTask) { + BpmnJsonNodeProperty property = node.getProperty(); + if (Objects.isNull(property)) { + return; + } + + // 审批方式 + ExtensionElement approvalMethodElement = new ExtensionElement(); + approvalMethodElement.setName("approvalMethod"); + + ExtensionAttribute approvalMethodValueAttribute = new ExtensionAttribute(); + approvalMethodValueAttribute.setName("value"); + approvalMethodValueAttribute.setValue(property.getApprovalMethod()); + approvalMethodElement.addAttribute(approvalMethodValueAttribute); + + ExtensionAttribute approvalMethodDescAttribute = new ExtensionAttribute(); + approvalMethodDescAttribute.setName("desc"); + approvalMethodDescAttribute.setValue("审批方式"); + approvalMethodElement.addAttribute(approvalMethodDescAttribute); + + userTask.addExtensionElement(approvalMethodElement); + + // 审批人所在范围 + ExtensionElement approverScopeElement = new ExtensionElement(); + approverScopeElement.setName("approverScope"); + + ExtensionAttribute approverScopeValueAttribute = new ExtensionAttribute(); + approverScopeValueAttribute.setName("value"); + approverScopeValueAttribute.setValue(property.getApproverScope()); + approverScopeElement.addAttribute(approverScopeValueAttribute); + + ExtensionAttribute approverScopeDescAttribute = new ExtensionAttribute(); + approverScopeDescAttribute.setName("desc"); + approverScopeDescAttribute.setValue("审批人所在范围"); + approverScopeElement.addAttribute(approverScopeDescAttribute); + userTask.addExtensionElement(approverScopeElement); + + // 审批人指定 + ExtensionElement approverSpecifyElement = new ExtensionElement(); + approverSpecifyElement.setName("approverSpecify"); + + ExtensionAttribute approverSpecifyValueAttribute = new ExtensionAttribute(); + approverSpecifyValueAttribute.setName("value"); + approverSpecifyValueAttribute.setValue(property.getApproverSpecify()); + approverSpecifyElement.addAttribute(approverSpecifyValueAttribute); + + ExtensionAttribute approverSpecifyDescAttribute = new ExtensionAttribute(); + approverSpecifyDescAttribute.setName("desc"); + approverSpecifyDescAttribute.setValue("审批人指定"); + approverSpecifyElement.addAttribute(approverSpecifyDescAttribute); + // 审批人指定的具体值 + approverSpecifyElement.setElementText(StringUtils.collectionToCommaDelimitedString(property.getSpecifyValue())); + userTask.addExtensionElement(approverSpecifyElement); + + // 多人审批时审批模式 + ExtensionElement approverModeTypeElement = new ExtensionElement(); + approverModeTypeElement.setName("approverModeType"); + + ExtensionAttribute approverModeTypeValueAttribute = new ExtensionAttribute(); + approverModeTypeValueAttribute.setName("value"); + approverModeTypeValueAttribute.setValue(property.getMultiMode().getType()); + approverModeTypeElement.addAttribute(approverModeTypeValueAttribute); + + ExtensionAttribute approverModeTypeDescAttribute = new ExtensionAttribute(); + approverModeTypeDescAttribute.setName("desc"); + approverModeTypeDescAttribute.setValue("多人审批时审批模式"); + approverModeTypeElement.addAttribute(approverModeTypeDescAttribute); + userTask.addExtensionElement(approverModeTypeElement); + + // 审批人为空时 + ExtensionElement approverEmptyHandleTypeElement = new ExtensionElement(); + approverEmptyHandleTypeElement.setName("approverEmptyHandleType"); + ExtensionAttribute approverEmptyHandleTypeValueAttribute = new ExtensionAttribute(); + approverEmptyHandleTypeValueAttribute.setName("value"); + approverEmptyHandleTypeValueAttribute.setValue(property.getApproverEmptyHandleType()); + approverEmptyHandleTypeElement.addAttribute(approverEmptyHandleTypeValueAttribute); + + ExtensionAttribute approverEmptyHandleTypeDescAttribute = new ExtensionAttribute(); + approverEmptyHandleTypeDescAttribute.setName("desc"); + approverEmptyHandleTypeDescAttribute.setValue("审批人为空时"); + approverEmptyHandleTypeElement.addAttribute(approverEmptyHandleTypeDescAttribute); + userTask.addExtensionElement(approverEmptyHandleTypeElement); + } + /** * 设置执行监听 * diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessModelServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessModelServiceImpl.java index 1e90517d5..e4f0bf751 100644 --- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessModelServiceImpl.java +++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessModelServiceImpl.java @@ -107,6 +107,7 @@ public class BpmnProcessModelServiceImpl implements BpmnProcessModelService { } @Override + @Transactional(rollbackFor = Exception.class) public String createBpmModel(@Valid BpmnModelCreateDTO dto) { Model existModel = repositoryService.createModelQuery() .modelKey(dto.getKey()) diff --git a/workflow-engine-server/src/main/resources/test.bpmn20.xml b/workflow-engine-server/src/main/resources/test.bpmn20.xml new file mode 100644 index 000000000..4b05a0a87 --- /dev/null +++ b/workflow-engine-server/src/main/resources/test.bpmn20.xml @@ -0,0 +1,365 @@ + + + + 极引非东活已运王点越组油门展总想立。年深江亲联热制者条济它部即月。号线信平和者京两马何标这。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/workflow-engine-server/src/main/resources/test.json b/workflow-engine-server/src/main/resources/test.json index 00a02eb0c..da36f0e13 100644 --- a/workflow-engine-server/src/main/resources/test.json +++ b/workflow-engine-server/src/main/resources/test.json @@ -229,7 +229,557 @@ "parentId": "0", "type": "NODE_STARTER", "name": "发起人", - "children": null, + "children": { + "id": "2", + "parentId": "1", + "type": "NODE_TASK", + "name": "一级审批", + "children": { + "id": "3", + "parentId": "2", + "type": "NODE_EXCLUSIVE_GATEWAY", + "name": "排它网关", + "children": { + "id": "11", + "parentId": "3", + "type": "NODE_CARBON_COPY", + "name": "主流程抄送节点", + "children": { + "id": "12", + "parentId": "3", + "type": "NODE_EMPTY", + "name": "结束", + "children": null, + "branches": null, + "property": null + }, + "branches": null, + "property": null + }, + "branches": [ + { + "id": "4", + "parentId": "3", + "type": "NODE_CONDITION", + "name": "条件1", + "property": { + "groups": [ + { + "conditionsType": "and", + "conditions": [ + { + "fieldDataType": "string", + "fieldCode": "title", + "operator": "contains", + "defaultValue": "测试" + }, + { + "fieldDataType": "number", + "fieldCode": "price", + "operator": "eq", + "defaultValue": "2" + } + ] + } + ], + "defaultBranch": false, + "groupsType": "and" + }, + "children": { + "id": "7", + "parentId": "4", + "type": "NODE_TASK", + "name": "条件1审核节点", + "children": { + "id": "8", + "parentId": "7", + "type": "NODE_CARBON_COPY", + "name": "条件1抄送节点", + "children": null, + "property": null, + "branches": null + }, + "property": { + "approvalMethod": "autoPassed", + "approverScope": "entWorkspace", + "approverSpecify": "position", + "specifyValue": [ + "job1", + "job2" + ], + "isMultiTask": "true", + "multiMode": "AND", + "approverEmptyHandleType": "autoPassed", + "fieldPermission": null, + "buttonPermission": { + "initiator": [ + { + "btnKey": "BPMN_APPROVE", + "enabled": true, + "btnName": "同意" + }, + { + "btnKey": "BPMN_REJECT", + "btnName": "拒绝", + "enabled": true + }, + { + "btnKey": "BPMN_REVOCATION", + "btnName": "撤回", + "enabled": true + }, + { + "btnKey": "BPMN_FORWARD", + "btnName": "转交", + "enabled": true + }, + { + "btnKey": "BPMN_COUNTERSIGN", + "btnName": "加签", + "enabled": true + }, + { + "btnKey": "BPMN_COMMENT", + "btnName": "评论", + "enabled": true + }, + { + "btnKey": "BPMN_ROLLBACK", + "btnName": "回退", + "enabled": true + }, + { + "btnKey": "BPMN_COPY", + "btnName": "抄送", + "enabled": true + } + ], + "carbonCopy": [ + { + "btnKey": "BPMN_APPROVE", + "enabled": true, + "btnName": "同意" + }, + { + "btnKey": "BPMN_REJECT", + "btnName": "拒绝", + "enabled": true + }, + { + "btnKey": "BPMN_REVOCATION", + "btnName": "撤回", + "enabled": true + }, + { + "btnKey": "BPMN_FORWARD", + "btnName": "转交", + "enabled": true + }, + { + "btnKey": "BPMN_COUNTERSIGN", + "btnName": "加签", + "enabled": true + }, + { + "btnKey": "BPMN_COMMENT", + "btnName": "评论", + "enabled": true + }, + { + "btnKey": "BPMN_ROLLBACK", + "btnName": "回退", + "enabled": true + }, + { + "btnKey": "BPMN_COPY", + "btnName": "抄送", + "enabled": true + } + ], + "history": [ + { + "btnKey": "BPMN_APPROVE", + "enabled": true, + "btnName": "同意" + }, + { + "btnKey": "BPMN_REJECT", + "btnName": "拒绝", + "enabled": true + }, + { + "btnKey": "BPMN_REVOCATION", + "btnName": "撤回", + "enabled": true + }, + { + "btnKey": "BPMN_FORWARD", + "btnName": "转交", + "enabled": true + }, + { + "btnKey": "BPMN_COUNTERSIGN", + "btnName": "加签", + "enabled": true + }, + { + "btnKey": "BPMN_COMMENT", + "btnName": "评论", + "enabled": true + }, + { + "btnKey": "BPMN_ROLLBACK", + "btnName": "回退", + "enabled": true + }, + { + "btnKey": "BPMN_COPY", + "btnName": "抄送", + "enabled": true + } + ], + "current": [ + { + "btnKey": "BPMN_APPROVE", + "enabled": true, + "btnName": "同意" + }, + { + "btnKey": "BPMN_REJECT", + "btnName": "拒绝", + "enabled": true + }, + { + "btnKey": "BPMN_REVOCATION", + "btnName": "撤回", + "enabled": true + }, + { + "btnKey": "BPMN_FORWARD", + "btnName": "转交", + "enabled": true + }, + { + "btnKey": "BPMN_COUNTERSIGN", + "btnName": "加签", + "enabled": true + }, + { + "btnKey": "BPMN_COMMENT", + "btnName": "评论", + "enabled": true + }, + { + "btnKey": "BPMN_ROLLBACK", + "btnName": "回退", + "enabled": true + }, + { + "btnKey": "BPMN_COPY", + "btnName": "抄送", + "enabled": true + } + ] + } + }, + "branches": null + }, + "branches": null + }, + { + "id": "5", + "parentId": "3", + "type": "NODE_CONDITION", + "name": "条件2", + "property": { + "groups": [ + { + "conditionsType": "and", + "conditions": [ + { + "fieldDataType": "number", + "fieldCode": "size", + "operator": "between", + "leftValue": "31", + "leftOperator": "le", + "rightValue": "34", + "rightOperator": "gt" + }, + { + "fieldDataType": "radio", + "fieldCode": "sex", + "operator": "eq", + "defaultValue": "2" + }, + { + "fieldDataType": "checkbox", + "fieldCode": "color", + "operator": "in", + "defaultValues": [ + "red", + "blue" + ] + } + ] + } + ], + "defaultBranch": false, + "groupsType": "and" + }, + "children": { + "id": "9", + "parentId": "5", + "type": "NODE_BUSINESS", + "name": "条件2业务节点", + "children": { + "id": "10", + "parentId": "9", + "type": "NODE_TASK", + "name": "条件2审批节点", + "children": { + "id": "13", + "parentId": "10", + "type": "NODE_BUSINESS", + "name": "业务节点有审批人", + "property": { + "approvalMethod": "human", + "approverScope": "projectWorkspace", + "approverSpecify": "identity", + "specifyValue": [ + "worker", + "team_worker" + ], + "isMultiTask": "true", + "multiMode": "AND", + "approverEmptyHandleType": "transferToAdmin", + "fieldPermission": null, + "buttonPermission": null + }, + "children": null, + "branches": null + }, + "property": { + "approvalMethod": "human", + "approverScope": "projectWorkspace", + "approverSpecify": "position", + "specifyValue": [ + "job1", + "job2" + ], + "isMultiTask": "true", + "multiMode": "AND", + "approverEmptyHandleType": "autoPassed", + "fieldPermission": null, + "buttonPermission": null + }, + "branches": null + }, + "property": { + "approvalMethod": "nobody" + }, + "branches": null + }, + "branches": null + }, + { + "id": "6", + "parentId": "3", + "type": "NODE_CONDITION", + "name": "默认条件", + "property": { + "defaultBranch": true + }, + "children": null, + "branches": null + } + ], + "property": null + }, + "branches": null, + "property": { + "approvalMethod": "human", + "approverScope": "projectWorkspace", + "approverSpecify": "position", + "specifyValue": [ + "job1", + "job2" + ], + "isMultiTask": "true", + "multiMode": "AND", + "approverEmptyHandleType": "autoPassed", + "fieldPermission": null, + "buttonPermission": { + "initiator": [ + { + "btnKey": "BPMN_APPROVE", + "enabled": true, + "btnName": "同意" + }, + { + "btnKey": "BPMN_REJECT", + "btnName": "拒绝", + "enabled": true + }, + { + "btnKey": "BPMN_REVOCATION", + "btnName": "撤回", + "enabled": true + }, + { + "btnKey": "BPMN_FORWARD", + "btnName": "转交", + "enabled": true + }, + { + "btnKey": "BPMN_COUNTERSIGN", + "btnName": "加签", + "enabled": true + }, + { + "btnKey": "BPMN_COMMENT", + "btnName": "评论", + "enabled": true + }, + { + "btnKey": "BPMN_ROLLBACK", + "btnName": "回退", + "enabled": true + }, + { + "btnKey": "BPMN_COPY", + "btnName": "抄送", + "enabled": true + } + ], + "carbonCopy": [ + { + "btnKey": "BPMN_APPROVE", + "enabled": true, + "btnName": "同意" + }, + { + "btnKey": "BPMN_REJECT", + "btnName": "拒绝", + "enabled": true + }, + { + "btnKey": "BPMN_REVOCATION", + "btnName": "撤回", + "enabled": true + }, + { + "btnKey": "BPMN_FORWARD", + "btnName": "转交", + "enabled": true + }, + { + "btnKey": "BPMN_COUNTERSIGN", + "btnName": "加签", + "enabled": true + }, + { + "btnKey": "BPMN_COMMENT", + "btnName": "评论", + "enabled": true + }, + { + "btnKey": "BPMN_ROLLBACK", + "btnName": "回退", + "enabled": true + }, + { + "btnKey": "BPMN_COPY", + "btnName": "抄送", + "enabled": true + } + ], + "history": [ + { + "btnKey": "BPMN_APPROVE", + "enabled": true, + "btnName": "同意" + }, + { + "btnKey": "BPMN_REJECT", + "btnName": "拒绝", + "enabled": true + }, + { + "btnKey": "BPMN_REVOCATION", + "btnName": "撤回", + "enabled": true + }, + { + "btnKey": "BPMN_FORWARD", + "btnName": "转交", + "enabled": true + }, + { + "btnKey": "BPMN_COUNTERSIGN", + "btnName": "加签", + "enabled": true + }, + { + "btnKey": "BPMN_COMMENT", + "btnName": "评论", + "enabled": true + }, + { + "btnKey": "BPMN_ROLLBACK", + "btnName": "回退", + "enabled": true + }, + { + "btnKey": "BPMN_COPY", + "btnName": "抄送", + "enabled": true + } + ], + "current": [ + { + "btnKey": "BPMN_APPROVE", + "enabled": true, + "btnName": "同意" + }, + { + "btnKey": "BPMN_REJECT", + "btnName": "拒绝", + "enabled": true + }, + { + "btnKey": "BPMN_REVOCATION", + "btnName": "撤回", + "enabled": true + }, + { + "btnKey": "BPMN_FORWARD", + "btnName": "转交", + "enabled": true + }, + { + "btnKey": "BPMN_COUNTERSIGN", + "btnName": "加签", + "enabled": true + }, + { + "btnKey": "BPMN_COMMENT", + "btnName": "评论", + "enabled": true + }, + { + "btnKey": "BPMN_ROLLBACK", + "btnName": "回退", + "enabled": true + }, + { + "btnKey": "BPMN_COPY", + "btnName": "抄送", + "enabled": true + } + ] + } + } + }, "branches": null, "property": null },