diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java index 6c7a7ce92e..67df493971 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java @@ -54,6 +54,7 @@ public interface ErrorCodeConstants { ErrorCode TASK_TRANSFER_FAIL_USER_REPEAT = new ErrorCode(1_009_005_013, "任务转办失败,转办人和当前审批人为同一人"); ErrorCode TASK_TRANSFER_FAIL_USER_NOT_EXISTS = new ErrorCode(1_009_005_014, "任务转办失败,转办人不存在"); ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1_009_006_003, "操作失败,原因:找不到任务的审批人!"); + ErrorCode TASK_SIGNATURE_NOT_EXISTS = new ErrorCode(1_009_005_015, "签名不能为空!"); // ========== 动态表单模块 1-009-010-000 ========== ErrorCode FORM_NOT_EXISTS = new ErrorCode(1_009_010_000, "动态表单不存在"); diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java index e95c59dcdc..4dbae58cbe 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeType.java @@ -33,7 +33,7 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { CONDITION_BRANCH_NODE(51, "条件分支", "exclusiveGateway"), PARALLEL_BRANCH_NODE(52, "并行分支", "parallelGateway"), INCLUSIVE_BRANCH_NODE(53, "包容分支", "inclusiveGateway"), - ROUTE_BRANCH_NODE(54, "路由分支", "exclusiveGateway") + ROUTER_BRANCH_NODE(54, "路由分支", "exclusiveGateway") ; public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray(); @@ -51,7 +51,7 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { return Objects.equals(CONDITION_BRANCH_NODE.getType(), type) || Objects.equals(PARALLEL_BRANCH_NODE.getType(), type) || Objects.equals(INCLUSIVE_BRANCH_NODE.getType(), type) - || Objects.equals(ROUTE_BRANCH_NODE.getType(), type); + || Objects.equals(ROUTER_BRANCH_NODE.getType(), type); } public static BpmSimpleModelNodeType valueOf(Integer type) { 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 2b87bffccb..1ba4f39b53 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 @@ -117,11 +117,10 @@ public class BpmSimpleModelNodeVO { private ConditionGroups conditionGroups; // 仅用于条件节点 BpmSimpleModelNodeType.CONDITION_NODE @Schema(description = "路由分支组", example = "[]") - private List routerGroups; + private List routerGroups; - // TODO @lesan:这个目前前端是随机生成的。可以后端来随机么? - @Schema(description = "默认分支 ID", example = "Flow_xxx") - private String defaultFlowId; // 仅用于路由分支节点 BpmSimpleModelNodeType.ROUTE_BRANCH_NODE + @Schema(description = "默认分支 ID", example = "Flow_xxx", hidden = true) // 由后端生成,所以 hidden = true + private String defaultFlowId; // 仅用于路由分支节点 BpmSimpleModelNodeType.ROUTER_BRANCH_NODE @Schema(description = "任务监听器") @Valid @@ -290,11 +289,10 @@ public class BpmSimpleModelNodeVO { } - // TODO @lesan:还有相关的也要改下哈。route 到 router @Schema(description = "路由分支") @Data @Valid - public static class RouteCondition { + public static class RouterCondition { @Schema(description = "节点 Id", example = "Activity_xxx") // 跳转到该节点 @NotEmpty(message = "节点 Id 不能为空") diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java index 148175d938..16a6c0e9e4 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java @@ -101,6 +101,10 @@ public class BpmApprovalDetailRespVO { @Schema(description = "审批意见", example = "同意") private String reason; + // TODO @lesan:改成 signPicUrl 会好点 + @Schema(description = "签名", example = "https://www.iocoder.cn/sign.png") + private String sign; + } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java index 5bec026608..3988754a29 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java @@ -18,6 +18,10 @@ public class BpmTaskApproveReqVO { @NotEmpty(message = "审批意见不能为空") private String reason; + // TODO @lesan:改成 signPicUrl 会好点 + @Schema(description = "签名", example = "https://www.iocoder.cn/sign.png") + private String sign; + @Schema(description = "变量实例(动态表单)", requiredMode = Schema.RequiredMode.REQUIRED) private Map variables; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java index 450699c2f7..b409f0639c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java @@ -186,7 +186,8 @@ public interface BpmProcessInstanceConvert { return null; } return BeanUtils.toBean(task, BpmApprovalDetailRespVO.ActivityNodeTask.class) - .setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task)); + .setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task)) + .setSign(FlowableUtils.getTaskSign(task)); } default Set parseUserIds(HistoricProcessInstance processInstance, diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnVariableConstants.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnVariableConstants.java index 08fb5c48ee..a108789db5 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnVariableConstants.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnVariableConstants.java @@ -59,4 +59,7 @@ public class BpmnVariableConstants { */ public static final String TASK_VARIABLE_REASON = "TASK_REASON"; + // TODO @lesan:TASK_SIGN_PIC_URL 。。。虽然长一点,嘿嘿 + public static final String TASK_VARIABLE_SIGN = "TASK_SIGN"; + } 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 0ffb9dcb38..df2aed30f9 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 @@ -2,9 +2,11 @@ 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.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.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.string.StrUtils; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; @@ -21,6 +23,7 @@ import org.flowable.bpmn.model.Process; import org.flowable.bpmn.model.*; import org.flowable.common.engine.api.FlowableException; import org.flowable.common.engine.impl.util.io.BytesStreamSource; +import org.flowable.engine.impl.el.FixedValue; import java.util.*; @@ -346,12 +349,8 @@ public class BpmnModelUtils { } public static void addSignEnable(Boolean signEnable, FlowElement userTask) { - // TODO @lesan:是不是改成表达式会好点 addExtensionElement(userTask, SIGN_ENABLE, ObjUtil.isNotNull(signEnable) ? ) - if (ObjUtil.isNotNull(signEnable)) { - addExtensionElement(userTask, SIGN_ENABLE, signEnable.toString()); - } else { - addExtensionElement(userTask, SIGN_ENABLE, "false"); - } + addExtensionElement(userTask, SIGN_ENABLE, + ObjUtil.isNotNull(signEnable) ? signEnable.toString() : Boolean.FALSE.toString()); } public static Boolean parseSignEnable(BpmnModel bpmnModel, String flowElementId) { @@ -366,6 +365,19 @@ public class BpmnModelUtils { return Convert.toBool(extensionElements.get(0).getElementText(), false); } + public static void addListenerConfig(FlowableListener flowableListener, BpmSimpleModelNodeVO.ListenerHandler handler) { + FieldExtension fieldExtension = new FieldExtension(); + fieldExtension.setFieldName("listenerConfig"); + fieldExtension.setStringValue(JsonUtils.toJsonString(handler)); + flowableListener.getFieldExtensions().add(fieldExtension); + } + + public static BpmSimpleModelNodeVO.ListenerHandler parseListenerConfig(FixedValue fixedValue) { + String expressionText = fixedValue.getExpressionText(); + Assert.notNull(expressionText, "监听器扩展字段({})不能为空", expressionText); + return JsonUtils.parseObject(expressionText, BpmSimpleModelNodeVO.ListenerHandler.class); + } + // ========== BPM 简单查找相关的方法 ========== /** diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java index 9742c08ed3..fde29a122f 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java @@ -213,6 +213,11 @@ public class FlowableUtils { return (String) task.getTaskLocalVariables().get(BpmnVariableConstants.TASK_VARIABLE_REASON); } + // TODO @lesan:这个方法名,也改咧 + public static String getTaskSign(TaskInfo task) { + return (String) task.getTaskLocalVariables().get(BpmnVariableConstants.TASK_VARIABLE_SIGN); + } + /** * 获得任务的表单 * 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 e5a9a06070..51452b3b7d 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,7 +5,6 @@ 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.*; @@ -188,7 +187,7 @@ public class SimpleModelUtils { // 分支终点节点 ID String branchEndNodeId = null; if (nodeType == BpmSimpleModelNodeType.CONDITION_BRANCH_NODE - || nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) { // 条件分支或路由分支 + || nodeType == BpmSimpleModelNodeType.ROUTER_BRANCH_NODE) { // 条件分支或路由分支 // 分两种情况 1. 分支节点有孩子节点为孩子节点 Id 2. 分支节点孩子为无效节点时 (分支嵌套且为分支最后一个节点) 为分支终点节点 ID branchEndNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId; } else if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE @@ -199,10 +198,10 @@ public class SimpleModelUtils { Assert.notEmpty(branchEndNodeId, "分支终点节点 Id 不能为空"); // 3. 遍历分支节点 - if (nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) { + if (nodeType == BpmSimpleModelNodeType.ROUTER_BRANCH_NODE) { // 路由分支遍历 - for (BpmSimpleModelNodeVO.RouteCondition route : node.getRouterGroups()) { - SequenceFlow sequenceFlow = RouteBranchNodeConvert.buildSequenceFlow(node.getId(), route); + for (BpmSimpleModelNodeVO.RouterCondition router : node.getRouterGroups()) { + SequenceFlow sequenceFlow = RouteBranchNodeConvert.buildSequenceFlow(node.getId(), router); process.addFlowElement(sequenceFlow); } } else { @@ -233,7 +232,7 @@ public class SimpleModelUtils { SequenceFlow sequenceFlow = buildBpmnSequenceFlow(branchEndNodeId, nextNodeId); process.addFlowElement(sequenceFlow); // 4.2 如果是路由分支,需要连接后续节点为默认路由 - } else if (nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) { + } else if (nodeType == BpmSimpleModelNodeType.ROUTER_BRANCH_NODE) { SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), branchEndNodeId, node.getDefaultFlowId(), null, null); process.addFlowElement(sequenceFlow); @@ -453,10 +452,7 @@ 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); + addListenerConfig(flowableListener, node.getTaskCreateListener()); flowableListeners.add(flowableListener); } if (node.getTaskAssignListener() != null @@ -465,11 +461,7 @@ public class SimpleModelUtils { flowableListener.setEvent(TaskListener.EVENTNAME_ASSIGNMENT); flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); flowableListener.setImplementation(DELEGATE_EXPRESSION); - // TODO @lesan:可以在 BpmnModelUtils 搞个方法,类似 public static Integer parseCandidateStrategy。这样,就收敛啦! - FieldExtension fieldExtension = new FieldExtension(); - fieldExtension.setFieldName("listenerConfig"); - fieldExtension.setStringValue(JsonUtils.toJsonString(node.getTaskAssignListener())); - flowableListener.getFieldExtensions().add(fieldExtension); + addListenerConfig(flowableListener, node.getTaskAssignListener()); flowableListeners.add(flowableListener); } if (node.getTaskCompleteListener() != null @@ -478,10 +470,7 @@ 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); + addListenerConfig(flowableListener, node.getTaskCompleteListener()); flowableListeners.add(flowableListener); } if (CollUtil.isNotEmpty(flowableListeners)) { @@ -646,9 +635,9 @@ public class SimpleModelUtils { node.getConditionGroups()); } - public static String buildConditionExpression(BpmSimpleModelNodeVO.RouteCondition route) { - return buildConditionExpression(route.getConditionType(), route.getConditionExpression(), - route.getConditionGroups()); + public static String buildConditionExpression(BpmSimpleModelNodeVO.RouterCondition router) { + return buildConditionExpression(router.getConditionType(), router.getConditionExpression(), + router.getConditionGroups()); } public static String buildConditionExpression(Integer conditionType, String conditionExpression, @@ -728,18 +717,19 @@ public class SimpleModelUtils { exclusiveGateway.setId(node.getId()); // 设置默认的序列流(条件) + node.setDefaultFlowId("Flow_" + IdUtil.fastUUID()); exclusiveGateway.setDefaultFlow(node.getDefaultFlowId()); return exclusiveGateway; } @Override public BpmSimpleModelNodeType getType() { - return BpmSimpleModelNodeType.ROUTE_BRANCH_NODE; + return BpmSimpleModelNodeType.ROUTER_BRANCH_NODE; } - public static SequenceFlow buildSequenceFlow(String nodeId, BpmSimpleModelNodeVO.RouteCondition route) { - String conditionExpression = ConditionNodeConvert.buildConditionExpression(route); - return buildBpmnSequenceFlow(nodeId, route.getNodeId(), null, null, conditionExpression); + public static SequenceFlow buildSequenceFlow(String nodeId, BpmSimpleModelNodeVO.RouterCondition router) { + String conditionExpression = ConditionNodeConvert.buildConditionExpression(router); + return buildBpmnSequenceFlow(nodeId, router.getNodeId(), null, null, conditionExpression); } } 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 300c3ee700..4e2185a7c3 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 @@ -482,6 +482,12 @@ public class BpmTaskServiceImpl implements BpmTaskService { if (instance == null) { throw exception(PROCESS_INSTANCE_NOT_EXISTS); } + // 1.3 校验签名 + BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId()); + Boolean signEnable = parseSignEnable(bpmnModel, task.getTaskDefinitionKey()); + if (signEnable && StrUtil.isEmpty(reqVO.getSign())) { + throw exception(TASK_SIGNATURE_NOT_EXISTS); + } // 情况一:被委派的任务,不调用 complete 去完成任务 if (DelegationState.PENDING.equals(task.getDelegationState())) { @@ -496,8 +502,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { } // 情况三:审批普通的任务。大多数情况下,都是这样 - // 2.1 更新 task 状态、原因 + // 2.1 更新 task 状态、原因、签字 updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.APPROVE.getStatus(), reqVO.getReason()); + if (signEnable) { + taskService.setVariableLocal(task.getId(), BpmnVariableConstants.TASK_VARIABLE_SIGN, reqVO.getSign()); + } // 2.2 添加评论 taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(), BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason())); 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 2eb9240564..ffe91f277f 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,35 +1,32 @@ 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.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.Setter; import lombok.extern.slf4j.Slf4j; -import org.flowable.bpmn.model.BpmnModel; -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.engine.impl.el.FixedValue; import org.flowable.task.service.delegate.DelegateTask; +import org.springframework.context.annotation.Scope; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; 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.parseListenerConfig; /** * BPM 用户任务通用监听器 @@ -38,34 +35,32 @@ import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_ */ @Component @Slf4j +@Scope("prototype") public class BpmUserTaskListener implements TaskListener { public static final String DELEGATE_EXPRESSION = "${bpmUserTaskListener}"; - @Resource - private BpmModelService modelService; - @Resource private BpmProcessInstanceService processInstanceService; @Resource private RestTemplate restTemplate; + @Setter + private FixedValue listenerConfig; + @Override public void notify(DelegateTask delegateTask) { // 1. 获取所需基础信息 HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(delegateTask.getProcessInstanceId()); - BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(delegateTask.getProcessDefinitionId()); - UserTask userTask = (UserTask) BpmnModelUtils.getFlowElementById(bpmnModel, delegateTask.getTaskDefinitionKey()); - BpmSimpleModelNodeVO.ListenerHandler listenerHandler = getListenerHandlerByEvent(delegateTask.getEventName(), - userTask.getTaskListeners()); + BpmSimpleModelNodeVO.ListenerHandler listenerHandler = parseListenerConfig(listenerConfig); // 2. 获取请求头和请求体 Map processVariables = processInstance.getProcessVariables(); MultiValueMap headers = new LinkedMultiValueMap<>(); MultiValueMap body = new LinkedMultiValueMap<>(); - parseListenerMap(listenerHandler.getHeader(), processVariables, headers); - parseListenerMap(listenerHandler.getBody(), processVariables, body); + parseListenerParam(listenerHandler.getHeader(), processVariables, headers); + parseListenerParam(listenerHandler.getBody(), processVariables, body); // 2.1 请求头默认参数 if (StrUtil.isNotEmpty(delegateTask.getTenantId())) { headers.add(HEADER_TENANT_ID, delegateTask.getTenantId()); @@ -80,21 +75,29 @@ public class BpmUserTaskListener implements TaskListener { // 3. 异步发起请求 // TODO @芋艿:确认要同步,还是异步 HttpEntity> requestEntity = new HttpEntity<>(body, headers); - // TODO @lesan:可能需要 try catch 哇? RestClientException - ResponseEntity responseEntity = restTemplate.exchange(listenerHandler.getPath(), HttpMethod.POST, - requestEntity, String.class); - log.info("[notify][监听器:{},事件类型:{},请求头:{},请求体:{},响应结果:{}]", - DELEGATE_EXPRESSION, - delegateTask.getEventName(), - headers, - body, - responseEntity); + try { + ResponseEntity responseEntity = restTemplate.exchange(listenerHandler.getPath(), HttpMethod.POST, + requestEntity, String.class); + log.info("[notify][监听器:{},事件类型:{},请求头:{},请求体:{},响应结果:{}]", + DELEGATE_EXPRESSION, + delegateTask.getEventName(), + headers, + body, + responseEntity); + } catch (RestClientException e) { + log.error("[error][监听器:{},事件类型:{},请求头:{},请求体:{},请求出错:{}]", + DELEGATE_EXPRESSION, + delegateTask.getEventName(), + headers, + body, + e.getMessage()); + } // 4. 是否需要后续操作?TODO 芋艿:待定! } - private void parseListenerMap(List list, - Map processVariables, - MultiValueMap to) { + private void parseListenerParam(List list, + Map processVariables, + MultiValueMap to) { if (CollUtil.isEmpty(list)) { return; } @@ -107,17 +110,4 @@ public class BpmUserTaskListener implements TaskListener { }); } - 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); - // TODO @lesan:BpmnModelUtils 提供一个 BpmSimpleModelNodeVO.ListenerHandler 解析方法,尽量收敛掉。 - 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