Jelajahi Sumber

!1189 Simple设计器功能完善
Merge pull request !1189 from Lesan/feature/bpm-n

芋道源码 7 bulan lalu
induk
melakukan
adc05cad66

+ 2 - 3
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmListenerMapType.java → yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmListenerParamTypeEnum.java

@@ -6,7 +6,6 @@ import lombok.Getter;
 
 import java.util.Arrays;
 
-// TODO @lesan:BpmListenerParamTypeEnum
 /**
  * BPM 任务监听器键值对类型
  *
@@ -14,7 +13,7 @@ import java.util.Arrays;
  */
 @Getter
 @AllArgsConstructor
-public enum BpmListenerMapType implements IntArrayValuable {
+public enum BpmListenerParamTypeEnum implements IntArrayValuable {
 
     FIXED_VALUE(1, "固定值"),
     FROM_FORM(2, "表单");
@@ -22,7 +21,7 @@ public enum BpmListenerMapType implements IntArrayValuable {
     private final Integer type;
     private final String name;
 
-    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmListenerMapType::getType).toArray();
+    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmListenerParamTypeEnum::getType).toArray();
 
     @Override
     public int[] array() {

+ 8 - 11
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java

@@ -60,6 +60,9 @@ public class BpmSimpleModelNodeVO {
     @Schema(description = "操作按钮设置", example = "[]")
     private List<OperationButtonSetting> buttonsSetting;  // 用于审批节点
 
+    @Schema(description = "是否需要签名", example = "false")
+    private Boolean signEnable;
+
     /**
      * 审批节点拒绝处理
      */
@@ -113,13 +116,9 @@ public class BpmSimpleModelNodeVO {
      */
     private ConditionGroups conditionGroups; // 仅用于条件节点 BpmSimpleModelNodeType.CONDITION_NODE
 
-    // TODO @lesan:route 改成 router 会不会好点。因为触发器、延迟器,都带了类似 r
-
-    // TODO @lesan:routeGroups
     @Schema(description = "路由分支组", example = "[]")
-    private List<RouteCondition> routeGroup;
+    private List<RouteCondition> routerGroups;
 
-    // TODO @lesan:貌似没用???
     @Schema(description = "默认分支 ID", example = "Flow_xxx")
     private String defaultFlowId; // 仅用于路由分支节点 BpmSimpleModelNodeType.ROUTE_BRANCH_NODE
 
@@ -136,20 +135,19 @@ public class BpmSimpleModelNodeVO {
         private String path;
 
         @Schema(description = "请求头", example = "[]")
-        private List<ListenerMap> header;
+        private List<ListenerParam> header;
 
         @Schema(description = "请求体", example = "[]")
-        private List<ListenerMap> body;
+        private List<ListenerParam> body;
 
         // TODO @芋艿:这里后续要不要复用;
 
-        // TODO @lesan:ListenerParam 更合适哈。首先它是参数配置,然后形式是键值对
         @Schema(description = "任务监听器键值对")
         @Data
-        public static class ListenerMap {
+        public static class ListenerParam {
 
             @Schema(description = "值类型", example = "1")
-            @InEnum(BpmListenerMapType.class)
+            @InEnum(BpmListenerParamTypeEnum.class)
             private Integer type;
 
             @Schema(description = "键", example = "xxx")
@@ -300,7 +298,6 @@ public class BpmSimpleModelNodeVO {
         @NotEmpty(message = "节点 Id 不能为空")
         private String nodeId;
 
-        // TODO @lesan:type、expression、groups;
         @Schema(description = "条件类型", example = "1")
         @InEnum(BpmSimpleModeConditionType.class)
         @NotNull(message = "条件类型不能为空")

+ 3 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java

@@ -78,6 +78,9 @@ public class BpmTaskRespVO {
     @Schema(description = "操作按钮设置值")
     private Map<Integer, OperationButtonSetting> buttonsSetting;
 
+    @Schema(description = "是否需要签名")
+    private Boolean signEnable;
+
     @Data
     @Schema(description = "流程实例")
     public static class ProcessInstance {

+ 5 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java

@@ -110,4 +110,9 @@ public interface BpmnModelConstants {
      */
     String START_USER_NODE_ID = "StartUserNode";
 
+    /**
+     * 是否需要签名
+     */
+    String SIGN_ENABLE = "signEnable";
+
 }

+ 21 - 19
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.bpm.framework.flowable.core.util;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.ObjUtil;
@@ -114,25 +115,6 @@ public class BpmnModelUtils {
         return element != null ? JsonUtils.parseObject(element.getElementText(), clazz) : null;
     }
 
-    /**
-     * 给节点添加Simple设计器配置Json
-     *
-     * @param userTask 节点
-     * @param node 节点对象
-     */
-    public static void addSimpleConfigInfo(FlowElement userTask, Object node) {
-        addExtensionElementJson(userTask, "config", node);
-    }
-
-    /**
-     * 解析Simple设计器配置Json
-     *
-     * @param userTask 节点
-     */
-    public static BpmSimpleModelNodeVO parseSimpleConfigInfo(FlowElement userTask) {
-        return parseExtensionElementJson(userTask, "config", BpmSimpleModelNodeVO.class);
-    }
-
     /**
      * 给节点添加候选人元素
      *
@@ -386,6 +368,26 @@ public class BpmnModelUtils {
         return Optional.ofNullable(extensionElement).map(ExtensionElement::getElementText).orElse(null);
     }
 
+    public static void addSignEnable(Boolean signEnable, FlowElement userTask) {
+        if (ObjUtil.isNotNull(signEnable)) {
+            addExtensionElement(userTask, SIGN_ENABLE, signEnable.toString());
+        } else {
+            addExtensionElement(userTask, SIGN_ENABLE, "false");
+        }
+    }
+
+    public static Boolean parseSignEnable(BpmnModel bpmnModel, String flowElementId) {
+        FlowElement flowElement = getFlowElementById(bpmnModel, flowElementId);
+        if (flowElement == null) {
+            return false;
+        }
+        List<ExtensionElement> extensionElements = flowElement.getExtensionElements().get(SIGN_ENABLE);
+        if (CollUtil.isEmpty(extensionElements)) {
+            return false;
+        }
+        return Convert.toBool(extensionElements.get(0).getElementText(), false);
+    }
+
     // ========== BPM 简单查找相关的方法 ==========
 
     /**

+ 16 - 4
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java

@@ -5,6 +5,7 @@ import cn.hutool.core.lang.Assert;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.*;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.ConditionGroups;
 import cn.iocoder.yudao.module.bpm.enums.definition.*;
@@ -200,7 +201,7 @@ public class SimpleModelUtils {
         // 3. 遍历分支节点
         if (nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) {
             // 路由分支遍历
-            for (BpmSimpleModelNodeVO.RouteCondition route : node.getRouteGroup()) {
+            for (BpmSimpleModelNodeVO.RouteCondition route : node.getRouterGroups()) {
                 SequenceFlow sequenceFlow = RouteBranchNodeConvert.buildSequenceFlow(node.getId(), route);
                 process.addFlowElement(sequenceFlow);
             }
@@ -439,9 +440,8 @@ public class SimpleModelUtils {
             }
             // 设置监听器
             addUserTaskListener(node, userTask);
-            // 设置 Simple 设计器节点配置
-            // TODO @lesan:只设置到 flowableListener 里面,整个 node 太大了!因为很多都保存过啦。
-            addSimpleConfigInfo(userTask, node);
+            // 添加是否需要签名
+            addSignEnable(node.getSignEnable(), userTask);
             return userTask;
         }
 
@@ -453,6 +453,10 @@ public class SimpleModelUtils {
                 flowableListener.setEvent(TaskListener.EVENTNAME_CREATE);
                 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
                 flowableListener.setImplementation(DELEGATE_EXPRESSION);
+                FieldExtension fieldExtension = new FieldExtension();
+                fieldExtension.setFieldName("listenerConfig");
+                fieldExtension.setStringValue(JsonUtils.toJsonString(node.getTaskCreateListener()));
+                flowableListener.getFieldExtensions().add(fieldExtension);
                 flowableListeners.add(flowableListener);
             }
             if (node.getTaskAssignListener() != null
@@ -461,6 +465,10 @@ public class SimpleModelUtils {
                 flowableListener.setEvent(TaskListener.EVENTNAME_ASSIGNMENT);
                 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
                 flowableListener.setImplementation(DELEGATE_EXPRESSION);
+                FieldExtension fieldExtension = new FieldExtension();
+                fieldExtension.setFieldName("listenerConfig");
+                fieldExtension.setStringValue(JsonUtils.toJsonString(node.getTaskAssignListener()));
+                flowableListener.getFieldExtensions().add(fieldExtension);
                 flowableListeners.add(flowableListener);
             }
             if (node.getTaskCompleteListener() != null
@@ -469,6 +477,10 @@ public class SimpleModelUtils {
                 flowableListener.setEvent(TaskListener.EVENTNAME_COMPLETE);
                 flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION);
                 flowableListener.setImplementation(DELEGATE_EXPRESSION);
+                FieldExtension fieldExtension = new FieldExtension();
+                fieldExtension.setFieldName("listenerConfig");
+                fieldExtension.setStringValue(JsonUtils.toJsonString(node.getTaskCompleteListener()));
+                flowableListener.getFieldExtensions().add(fieldExtension);
                 flowableListeners.add(flowableListener);
             }
             if (CollUtil.isNotEmpty(flowableListeners)) {

+ 6 - 1
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java

@@ -64,6 +64,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
 import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_RETURN_FLAG;
+import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.parseSignEnable;
 
 /**
  * 流程任务实例 Service 实现类
@@ -161,13 +162,17 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         BpmnModel bpmnModel = bpmProcessDefinitionService.getProcessDefinitionBpmnModel(todoTask.getProcessDefinitionId());
         Map<Integer, BpmTaskRespVO.OperationButtonSetting> buttonsSetting = BpmnModelUtils.parseButtonsSetting(
                 bpmnModel, todoTask.getTaskDefinitionKey());
+        Boolean signEnable = parseSignEnable(bpmnModel, todoTask.getTaskDefinitionKey());
 
         // 4. 任务表单
         BpmFormDO taskForm = null;
         if (StrUtil.isNotBlank(todoTask.getFormKey())){
             taskForm = formService.getForm(NumberUtils.parseLong(todoTask.getFormKey()));
         }
-        return BpmTaskConvert.INSTANCE.buildTodoTask(todoTask, childrenTasks, buttonsSetting, taskForm);
+
+        BpmTaskRespVO bpmTaskRespVO = BpmTaskConvert.INSTANCE.buildTodoTask(todoTask, childrenTasks, buttonsSetting, taskForm);
+        bpmTaskRespVO.setSignEnable(signEnable);
+        return bpmTaskRespVO;
     }
 
     @Override

+ 28 - 19
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmUserTaskListener.java

@@ -1,16 +1,20 @@
 package cn.iocoder.yudao.module.bpm.service.task.listener;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.Assert;
 import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
-import cn.iocoder.yudao.module.bpm.enums.definition.BpmListenerMapType;
+import cn.iocoder.yudao.module.bpm.enums.definition.BpmListenerParamTypeEnum;
 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
 import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.flowable.bpmn.model.BpmnModel;
-import org.flowable.bpmn.model.FlowElement;
+import org.flowable.bpmn.model.FieldExtension;
+import org.flowable.bpmn.model.FlowableListener;
+import org.flowable.bpmn.model.UserTask;
 import org.flowable.engine.delegate.TaskListener;
 import org.flowable.engine.history.HistoricProcessInstance;
 import org.flowable.task.service.delegate.DelegateTask;
@@ -26,7 +30,6 @@ import java.util.List;
 import java.util.Map;
 
 import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
-import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.parseSimpleConfigInfo;
 
 /**
  * BPM 用户任务通用监听器
@@ -53,9 +56,9 @@ public class BpmUserTaskListener implements TaskListener {
         // 1. 获取所需基础信息
         HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(delegateTask.getProcessInstanceId());
         BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(delegateTask.getProcessDefinitionId());
-        FlowElement userTask = BpmnModelUtils.getFlowElementById(bpmnModel, delegateTask.getTaskDefinitionKey());
-        BpmSimpleModelNodeVO node = parseSimpleConfigInfo(userTask);
-        BpmSimpleModelNodeVO.ListenerHandler listenerHandler = getListenerHandlerByEvent(delegateTask.getEventName(), node);
+        UserTask userTask = (UserTask) BpmnModelUtils.getFlowElementById(bpmnModel, delegateTask.getTaskDefinitionKey());
+        BpmSimpleModelNodeVO.ListenerHandler listenerHandler = getListenerHandlerByEvent(delegateTask.getEventName(),
+                userTask.getTaskListeners());
 
         // 2. 获取请求头和请求体
         Map<String, Object> processVariables = processInstance.getProcessVariables();
@@ -79,34 +82,40 @@ public class BpmUserTaskListener implements TaskListener {
         HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body, headers);
         ResponseEntity<String> responseEntity = restTemplate.exchange(listenerHandler.getPath(), HttpMethod.POST,
                 requestEntity, String.class);
-        // TODO @lesan:日志打印,可以更全哈,例如说,请求参数、对应的 task id,哪个 listener
-        log.info("[notify][的响应结果({})]", responseEntity);
+        log.info("[notify][监听器:{},事件类型:{},请求头:{},请求体:{},响应结果:{}]",
+                DELEGATE_EXPRESSION,
+                delegateTask.getEventName(),
+                headers,
+                body,
+                responseEntity);
         // 4. 是否需要后续操作?TODO 芋艿:待定!
     }
 
-    private void parseListenerMap(List<BpmSimpleModelNodeVO.ListenerHandler.ListenerMap> list,
+    private void parseListenerMap(List<BpmSimpleModelNodeVO.ListenerHandler.ListenerParam> list,
                                   Map<String, Object> processVariables,
                                   MultiValueMap<String, String> to) {
         if (CollUtil.isEmpty(list)) {
             return;
         }
         list.forEach(item -> {
-            if (item.getType().equals(BpmListenerMapType.FIXED_VALUE.getType())) {
+            if (item.getType().equals(BpmListenerParamTypeEnum.FIXED_VALUE.getType())) {
                 to.add(item.getKey(), item.getValue());
-            } else if (item.getType().equals(BpmListenerMapType.FROM_FORM.getType())) {
+            } else if (item.getType().equals(BpmListenerParamTypeEnum.FROM_FORM.getType())) {
                 to.add(item.getKey(), processVariables.get(item.getValue()).toString());
             }
         });
     }
 
-    // TODO @lesan:改成 jdk8 写法哈。主要考虑好兼容!
-    private BpmSimpleModelNodeVO.ListenerHandler getListenerHandlerByEvent(String eventName, BpmSimpleModelNodeVO node) {
-        return switch (eventName) {
-            case TaskListener.EVENTNAME_CREATE -> node.getTaskCreateListener();
-            case TaskListener.EVENTNAME_ASSIGNMENT -> node.getTaskAssignListener();
-            case TaskListener.EVENTNAME_COMPLETE -> node.getTaskCompleteListener();
-            default -> null; // TODO @lesan:这个抛出异常,可控一点
-        };
+    private BpmSimpleModelNodeVO.ListenerHandler getListenerHandlerByEvent(String eventName, List<FlowableListener> node) {
+        FlowableListener flowableListener = node.stream()
+                .filter(item -> item.getEvent().equals(eventName))
+                .findFirst().orElse(null);
+        Assert.notNull(flowableListener, "监听器({})不能为空", flowableListener);
+        FieldExtension fieldExtension = flowableListener.getFieldExtensions().stream()
+                .filter(item -> item.getFieldName().equals("listenerConfig"))
+                .findFirst().orElse(null);
+        Assert.notNull(fieldExtension, "监听器扩展字段({})不能为空", fieldExtension);
+        return JsonUtils.parseObject(fieldExtension.getStringValue(), BpmSimpleModelNodeVO.ListenerHandler.class);
     }
 
 }