diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmListenerMapType.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmListenerParamTypeEnum.java similarity index 78% rename from yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmListenerMapType.java rename to yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmListenerParamTypeEnum.java index 0396fbcce9..53b08c9e29 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmListenerMapType.java +++ b/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() { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java index b5057713ef..1fd048e9b6 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java +++ b/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 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 routeGroup; + private List 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 header; + private List header; @Schema(description = "请求体", example = "[]") - private List body; + private List 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 = "条件类型不能为空") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java index 5b34d36db9..95917f6292 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java +++ b/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 buttonsSetting; + @Schema(description = "是否需要签名") + private Boolean signEnable; + @Data @Schema(description = "流程实例") public static class ProcessInstance { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java index 60a864848a..6bb418f0fa 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java +++ b/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"; + } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java index f2f3017ec9..de31536681 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java +++ b/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 extensionElements = flowElement.getExtensionElements().get(SIGN_ENABLE); + if (CollUtil.isEmpty(extensionElements)) { + return false; + } + return Convert.toBool(extensionElements.get(0).getElementText(), false); + } + // ========== BPM 简单查找相关的方法 ========== /** diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java index 952cd6c26a..e392d8b6f7 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java +++ b/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)) { diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index 355e96979c..4240d402cf 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/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 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 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmUserTaskListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmUserTaskListener.java index 1680b26691..4fce01df3a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmUserTaskListener.java +++ b/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 processVariables = processInstance.getProcessVariables(); @@ -79,34 +82,40 @@ public class BpmUserTaskListener implements TaskListener { HttpEntity> requestEntity = new HttpEntity<>(body, headers); ResponseEntity 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 list, + private void parseListenerMap(List list, Map processVariables, MultiValueMap 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 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); } } \ No newline at end of file