Commit 1784aab186bbbba85c7be2bcb5064283a75501b3
Merge remote-tracking branch 'origin/feature/bpm' into feature/bpm
Showing
12 changed files
with
101 additions
and
84 deletions
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 { | @@ -54,6 +54,7 @@ public interface ErrorCodeConstants { | ||
| 54 | ErrorCode TASK_TRANSFER_FAIL_USER_REPEAT = new ErrorCode(1_009_005_013, "任务转办失败,转办人和当前审批人为同一人"); | 54 | ErrorCode TASK_TRANSFER_FAIL_USER_REPEAT = new ErrorCode(1_009_005_013, "任务转办失败,转办人和当前审批人为同一人"); |
| 55 | ErrorCode TASK_TRANSFER_FAIL_USER_NOT_EXISTS = new ErrorCode(1_009_005_014, "任务转办失败,转办人不存在"); | 55 | ErrorCode TASK_TRANSFER_FAIL_USER_NOT_EXISTS = new ErrorCode(1_009_005_014, "任务转办失败,转办人不存在"); |
| 56 | ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1_009_006_003, "操作失败,原因:找不到任务的审批人!"); | 56 | ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1_009_006_003, "操作失败,原因:找不到任务的审批人!"); |
| 57 | + ErrorCode TASK_SIGNATURE_NOT_EXISTS = new ErrorCode(1_009_005_015, "签名不能为空!"); | ||
| 57 | 58 | ||
| 58 | // ========== 动态表单模块 1-009-010-000 ========== | 59 | // ========== 动态表单模块 1-009-010-000 ========== |
| 59 | ErrorCode FORM_NOT_EXISTS = new ErrorCode(1_009_010_000, "动态表单不存在"); | 60 | ErrorCode FORM_NOT_EXISTS = new ErrorCode(1_009_010_000, "动态表单不存在"); |
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 { | @@ -33,7 +33,7 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { | ||
| 33 | CONDITION_BRANCH_NODE(51, "条件分支", "exclusiveGateway"), | 33 | CONDITION_BRANCH_NODE(51, "条件分支", "exclusiveGateway"), |
| 34 | PARALLEL_BRANCH_NODE(52, "并行分支", "parallelGateway"), | 34 | PARALLEL_BRANCH_NODE(52, "并行分支", "parallelGateway"), |
| 35 | INCLUSIVE_BRANCH_NODE(53, "包容分支", "inclusiveGateway"), | 35 | INCLUSIVE_BRANCH_NODE(53, "包容分支", "inclusiveGateway"), |
| 36 | - ROUTE_BRANCH_NODE(54, "路由分支", "exclusiveGateway") | 36 | + ROUTER_BRANCH_NODE(54, "路由分支", "exclusiveGateway") |
| 37 | ; | 37 | ; |
| 38 | 38 | ||
| 39 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray(); | 39 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmSimpleModelNodeType::getType).toArray(); |
| @@ -51,7 +51,7 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { | @@ -51,7 +51,7 @@ public enum BpmSimpleModelNodeType implements IntArrayValuable { | ||
| 51 | return Objects.equals(CONDITION_BRANCH_NODE.getType(), type) | 51 | return Objects.equals(CONDITION_BRANCH_NODE.getType(), type) |
| 52 | || Objects.equals(PARALLEL_BRANCH_NODE.getType(), type) | 52 | || Objects.equals(PARALLEL_BRANCH_NODE.getType(), type) |
| 53 | || Objects.equals(INCLUSIVE_BRANCH_NODE.getType(), type) | 53 | || Objects.equals(INCLUSIVE_BRANCH_NODE.getType(), type) |
| 54 | - || Objects.equals(ROUTE_BRANCH_NODE.getType(), type); | 54 | + || Objects.equals(ROUTER_BRANCH_NODE.getType(), type); |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | public static BpmSimpleModelNodeType valueOf(Integer type) { | 57 | public static BpmSimpleModelNodeType valueOf(Integer type) { |
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 { | @@ -117,11 +117,10 @@ public class BpmSimpleModelNodeVO { | ||
| 117 | private ConditionGroups conditionGroups; // 仅用于条件节点 BpmSimpleModelNodeType.CONDITION_NODE | 117 | private ConditionGroups conditionGroups; // 仅用于条件节点 BpmSimpleModelNodeType.CONDITION_NODE |
| 118 | 118 | ||
| 119 | @Schema(description = "路由分支组", example = "[]") | 119 | @Schema(description = "路由分支组", example = "[]") |
| 120 | - private List<RouteCondition> routerGroups; | 120 | + private List<RouterCondition> routerGroups; |
| 121 | 121 | ||
| 122 | - // TODO @lesan:这个目前前端是随机生成的。可以后端来随机么? | ||
| 123 | - @Schema(description = "默认分支 ID", example = "Flow_xxx") | ||
| 124 | - private String defaultFlowId; // 仅用于路由分支节点 BpmSimpleModelNodeType.ROUTE_BRANCH_NODE | 122 | + @Schema(description = "默认分支 ID", example = "Flow_xxx", hidden = true) // 由后端生成,所以 hidden = true |
| 123 | + private String defaultFlowId; // 仅用于路由分支节点 BpmSimpleModelNodeType.ROUTER_BRANCH_NODE | ||
| 125 | 124 | ||
| 126 | @Schema(description = "任务监听器") | 125 | @Schema(description = "任务监听器") |
| 127 | @Valid | 126 | @Valid |
| @@ -290,11 +289,10 @@ public class BpmSimpleModelNodeVO { | @@ -290,11 +289,10 @@ public class BpmSimpleModelNodeVO { | ||
| 290 | 289 | ||
| 291 | } | 290 | } |
| 292 | 291 | ||
| 293 | - // TODO @lesan:还有相关的也要改下哈。route 到 router | ||
| 294 | @Schema(description = "路由分支") | 292 | @Schema(description = "路由分支") |
| 295 | @Data | 293 | @Data |
| 296 | @Valid | 294 | @Valid |
| 297 | - public static class RouteCondition { | 295 | + public static class RouterCondition { |
| 298 | 296 | ||
| 299 | @Schema(description = "节点 Id", example = "Activity_xxx") // 跳转到该节点 | 297 | @Schema(description = "节点 Id", example = "Activity_xxx") // 跳转到该节点 |
| 300 | @NotEmpty(message = "节点 Id 不能为空") | 298 | @NotEmpty(message = "节点 Id 不能为空") |
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 { | @@ -101,6 +101,10 @@ public class BpmApprovalDetailRespVO { | ||
| 101 | @Schema(description = "审批意见", example = "同意") | 101 | @Schema(description = "审批意见", example = "同意") |
| 102 | private String reason; | 102 | private String reason; |
| 103 | 103 | ||
| 104 | + // TODO @lesan:改成 signPicUrl 会好点 | ||
| 105 | + @Schema(description = "签名", example = "https://www.iocoder.cn/sign.png") | ||
| 106 | + private String sign; | ||
| 107 | + | ||
| 104 | } | 108 | } |
| 105 | 109 | ||
| 106 | } | 110 | } |
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 { | @@ -18,6 +18,10 @@ public class BpmTaskApproveReqVO { | ||
| 18 | @NotEmpty(message = "审批意见不能为空") | 18 | @NotEmpty(message = "审批意见不能为空") |
| 19 | private String reason; | 19 | private String reason; |
| 20 | 20 | ||
| 21 | + // TODO @lesan:改成 signPicUrl 会好点 | ||
| 22 | + @Schema(description = "签名", example = "https://www.iocoder.cn/sign.png") | ||
| 23 | + private String sign; | ||
| 24 | + | ||
| 21 | @Schema(description = "变量实例(动态表单)", requiredMode = Schema.RequiredMode.REQUIRED) | 25 | @Schema(description = "变量实例(动态表单)", requiredMode = Schema.RequiredMode.REQUIRED) |
| 22 | private Map<String, Object> variables; | 26 | private Map<String, Object> variables; |
| 23 | 27 |
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 { | @@ -186,7 +186,8 @@ public interface BpmProcessInstanceConvert { | ||
| 186 | return null; | 186 | return null; |
| 187 | } | 187 | } |
| 188 | return BeanUtils.toBean(task, BpmApprovalDetailRespVO.ActivityNodeTask.class) | 188 | return BeanUtils.toBean(task, BpmApprovalDetailRespVO.ActivityNodeTask.class) |
| 189 | - .setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task)); | 189 | + .setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task)) |
| 190 | + .setSign(FlowableUtils.getTaskSign(task)); | ||
| 190 | } | 191 | } |
| 191 | 192 | ||
| 192 | default Set<Long> parseUserIds(HistoricProcessInstance processInstance, | 193 | default Set<Long> parseUserIds(HistoricProcessInstance processInstance, |
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 { | @@ -59,4 +59,7 @@ public class BpmnVariableConstants { | ||
| 59 | */ | 59 | */ |
| 60 | public static final String TASK_VARIABLE_REASON = "TASK_REASON"; | 60 | public static final String TASK_VARIABLE_REASON = "TASK_REASON"; |
| 61 | 61 | ||
| 62 | + // TODO @lesan:TASK_SIGN_PIC_URL 。。。虽然长一点,嘿嘿 | ||
| 63 | + public static final String TASK_VARIABLE_SIGN = "TASK_SIGN"; | ||
| 64 | + | ||
| 62 | } | 65 | } |
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; | @@ -2,9 +2,11 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; | ||
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.core.convert.Convert; | 4 | import cn.hutool.core.convert.Convert; |
| 5 | +import cn.hutool.core.lang.Assert; | ||
| 5 | import cn.hutool.core.map.MapUtil; | 6 | import cn.hutool.core.map.MapUtil; |
| 6 | import cn.hutool.core.util.*; | 7 | import cn.hutool.core.util.*; |
| 7 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | 8 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 9 | +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||
| 8 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | 10 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 9 | import cn.iocoder.yudao.framework.common.util.string.StrUtils; | 11 | import cn.iocoder.yudao.framework.common.util.string.StrUtils; |
| 10 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; | 12 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; |
| @@ -21,6 +23,7 @@ import org.flowable.bpmn.model.Process; | @@ -21,6 +23,7 @@ import org.flowable.bpmn.model.Process; | ||
| 21 | import org.flowable.bpmn.model.*; | 23 | import org.flowable.bpmn.model.*; |
| 22 | import org.flowable.common.engine.api.FlowableException; | 24 | import org.flowable.common.engine.api.FlowableException; |
| 23 | import org.flowable.common.engine.impl.util.io.BytesStreamSource; | 25 | import org.flowable.common.engine.impl.util.io.BytesStreamSource; |
| 26 | +import org.flowable.engine.impl.el.FixedValue; | ||
| 24 | 27 | ||
| 25 | import java.util.*; | 28 | import java.util.*; |
| 26 | 29 | ||
| @@ -346,12 +349,8 @@ public class BpmnModelUtils { | @@ -346,12 +349,8 @@ public class BpmnModelUtils { | ||
| 346 | } | 349 | } |
| 347 | 350 | ||
| 348 | public static void addSignEnable(Boolean signEnable, FlowElement userTask) { | 351 | public static void addSignEnable(Boolean signEnable, FlowElement userTask) { |
| 349 | - // TODO @lesan:是不是改成表达式会好点 addExtensionElement(userTask, SIGN_ENABLE, ObjUtil.isNotNull(signEnable) ? ) | ||
| 350 | - if (ObjUtil.isNotNull(signEnable)) { | ||
| 351 | - addExtensionElement(userTask, SIGN_ENABLE, signEnable.toString()); | ||
| 352 | - } else { | ||
| 353 | - addExtensionElement(userTask, SIGN_ENABLE, "false"); | ||
| 354 | - } | 352 | + addExtensionElement(userTask, SIGN_ENABLE, |
| 353 | + ObjUtil.isNotNull(signEnable) ? signEnable.toString() : Boolean.FALSE.toString()); | ||
| 355 | } | 354 | } |
| 356 | 355 | ||
| 357 | public static Boolean parseSignEnable(BpmnModel bpmnModel, String flowElementId) { | 356 | public static Boolean parseSignEnable(BpmnModel bpmnModel, String flowElementId) { |
| @@ -366,6 +365,19 @@ public class BpmnModelUtils { | @@ -366,6 +365,19 @@ public class BpmnModelUtils { | ||
| 366 | return Convert.toBool(extensionElements.get(0).getElementText(), false); | 365 | return Convert.toBool(extensionElements.get(0).getElementText(), false); |
| 367 | } | 366 | } |
| 368 | 367 | ||
| 368 | + public static void addListenerConfig(FlowableListener flowableListener, BpmSimpleModelNodeVO.ListenerHandler handler) { | ||
| 369 | + FieldExtension fieldExtension = new FieldExtension(); | ||
| 370 | + fieldExtension.setFieldName("listenerConfig"); | ||
| 371 | + fieldExtension.setStringValue(JsonUtils.toJsonString(handler)); | ||
| 372 | + flowableListener.getFieldExtensions().add(fieldExtension); | ||
| 373 | + } | ||
| 374 | + | ||
| 375 | + public static BpmSimpleModelNodeVO.ListenerHandler parseListenerConfig(FixedValue fixedValue) { | ||
| 376 | + String expressionText = fixedValue.getExpressionText(); | ||
| 377 | + Assert.notNull(expressionText, "监听器扩展字段({})不能为空", expressionText); | ||
| 378 | + return JsonUtils.parseObject(expressionText, BpmSimpleModelNodeVO.ListenerHandler.class); | ||
| 379 | + } | ||
| 380 | + | ||
| 369 | // ========== BPM 简单查找相关的方法 ========== | 381 | // ========== BPM 简单查找相关的方法 ========== |
| 370 | 382 | ||
| 371 | /** | 383 | /** |
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 { | @@ -213,6 +213,11 @@ public class FlowableUtils { | ||
| 213 | return (String) task.getTaskLocalVariables().get(BpmnVariableConstants.TASK_VARIABLE_REASON); | 213 | return (String) task.getTaskLocalVariables().get(BpmnVariableConstants.TASK_VARIABLE_REASON); |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | + // TODO @lesan:这个方法名,也改咧 | ||
| 217 | + public static String getTaskSign(TaskInfo task) { | ||
| 218 | + return (String) task.getTaskLocalVariables().get(BpmnVariableConstants.TASK_VARIABLE_SIGN); | ||
| 219 | + } | ||
| 220 | + | ||
| 216 | /** | 221 | /** |
| 217 | * 获得任务的表单 | 222 | * 获得任务的表单 |
| 218 | * | 223 | * |
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; | @@ -5,7 +5,6 @@ import cn.hutool.core.lang.Assert; | ||
| 5 | import cn.hutool.core.map.MapUtil; | 5 | import cn.hutool.core.map.MapUtil; |
| 6 | import cn.hutool.core.util.*; | 6 | import cn.hutool.core.util.*; |
| 7 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | 7 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 8 | -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||
| 9 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; | 8 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; |
| 10 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.ConditionGroups; | 9 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.ConditionGroups; |
| 11 | import cn.iocoder.yudao.module.bpm.enums.definition.*; | 10 | import cn.iocoder.yudao.module.bpm.enums.definition.*; |
| @@ -188,7 +187,7 @@ public class SimpleModelUtils { | @@ -188,7 +187,7 @@ public class SimpleModelUtils { | ||
| 188 | // 分支终点节点 ID | 187 | // 分支终点节点 ID |
| 189 | String branchEndNodeId = null; | 188 | String branchEndNodeId = null; |
| 190 | if (nodeType == BpmSimpleModelNodeType.CONDITION_BRANCH_NODE | 189 | if (nodeType == BpmSimpleModelNodeType.CONDITION_BRANCH_NODE |
| 191 | - || nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) { // 条件分支或路由分支 | 190 | + || nodeType == BpmSimpleModelNodeType.ROUTER_BRANCH_NODE) { // 条件分支或路由分支 |
| 192 | // 分两种情况 1. 分支节点有孩子节点为孩子节点 Id 2. 分支节点孩子为无效节点时 (分支嵌套且为分支最后一个节点) 为分支终点节点 ID | 191 | // 分两种情况 1. 分支节点有孩子节点为孩子节点 Id 2. 分支节点孩子为无效节点时 (分支嵌套且为分支最后一个节点) 为分支终点节点 ID |
| 193 | branchEndNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId; | 192 | branchEndNodeId = isValidNode(childNode) ? childNode.getId() : targetNodeId; |
| 194 | } else if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE | 193 | } else if (nodeType == BpmSimpleModelNodeType.PARALLEL_BRANCH_NODE |
| @@ -199,10 +198,10 @@ public class SimpleModelUtils { | @@ -199,10 +198,10 @@ public class SimpleModelUtils { | ||
| 199 | Assert.notEmpty(branchEndNodeId, "分支终点节点 Id 不能为空"); | 198 | Assert.notEmpty(branchEndNodeId, "分支终点节点 Id 不能为空"); |
| 200 | 199 | ||
| 201 | // 3. 遍历分支节点 | 200 | // 3. 遍历分支节点 |
| 202 | - if (nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) { | 201 | + if (nodeType == BpmSimpleModelNodeType.ROUTER_BRANCH_NODE) { |
| 203 | // 路由分支遍历 | 202 | // 路由分支遍历 |
| 204 | - for (BpmSimpleModelNodeVO.RouteCondition route : node.getRouterGroups()) { | ||
| 205 | - SequenceFlow sequenceFlow = RouteBranchNodeConvert.buildSequenceFlow(node.getId(), route); | 203 | + for (BpmSimpleModelNodeVO.RouterCondition router : node.getRouterGroups()) { |
| 204 | + SequenceFlow sequenceFlow = RouteBranchNodeConvert.buildSequenceFlow(node.getId(), router); | ||
| 206 | process.addFlowElement(sequenceFlow); | 205 | process.addFlowElement(sequenceFlow); |
| 207 | } | 206 | } |
| 208 | } else { | 207 | } else { |
| @@ -233,7 +232,7 @@ public class SimpleModelUtils { | @@ -233,7 +232,7 @@ public class SimpleModelUtils { | ||
| 233 | SequenceFlow sequenceFlow = buildBpmnSequenceFlow(branchEndNodeId, nextNodeId); | 232 | SequenceFlow sequenceFlow = buildBpmnSequenceFlow(branchEndNodeId, nextNodeId); |
| 234 | process.addFlowElement(sequenceFlow); | 233 | process.addFlowElement(sequenceFlow); |
| 235 | // 4.2 如果是路由分支,需要连接后续节点为默认路由 | 234 | // 4.2 如果是路由分支,需要连接后续节点为默认路由 |
| 236 | - } else if (nodeType == BpmSimpleModelNodeType.ROUTE_BRANCH_NODE) { | 235 | + } else if (nodeType == BpmSimpleModelNodeType.ROUTER_BRANCH_NODE) { |
| 237 | SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), branchEndNodeId, node.getDefaultFlowId(), | 236 | SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), branchEndNodeId, node.getDefaultFlowId(), |
| 238 | null, null); | 237 | null, null); |
| 239 | process.addFlowElement(sequenceFlow); | 238 | process.addFlowElement(sequenceFlow); |
| @@ -453,10 +452,7 @@ public class SimpleModelUtils { | @@ -453,10 +452,7 @@ public class SimpleModelUtils { | ||
| 453 | flowableListener.setEvent(TaskListener.EVENTNAME_CREATE); | 452 | flowableListener.setEvent(TaskListener.EVENTNAME_CREATE); |
| 454 | flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); | 453 | flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); |
| 455 | flowableListener.setImplementation(DELEGATE_EXPRESSION); | 454 | flowableListener.setImplementation(DELEGATE_EXPRESSION); |
| 456 | - FieldExtension fieldExtension = new FieldExtension(); | ||
| 457 | - fieldExtension.setFieldName("listenerConfig"); | ||
| 458 | - fieldExtension.setStringValue(JsonUtils.toJsonString(node.getTaskCreateListener())); | ||
| 459 | - flowableListener.getFieldExtensions().add(fieldExtension); | 455 | + addListenerConfig(flowableListener, node.getTaskCreateListener()); |
| 460 | flowableListeners.add(flowableListener); | 456 | flowableListeners.add(flowableListener); |
| 461 | } | 457 | } |
| 462 | if (node.getTaskAssignListener() != null | 458 | if (node.getTaskAssignListener() != null |
| @@ -465,11 +461,7 @@ public class SimpleModelUtils { | @@ -465,11 +461,7 @@ public class SimpleModelUtils { | ||
| 465 | flowableListener.setEvent(TaskListener.EVENTNAME_ASSIGNMENT); | 461 | flowableListener.setEvent(TaskListener.EVENTNAME_ASSIGNMENT); |
| 466 | flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); | 462 | flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); |
| 467 | flowableListener.setImplementation(DELEGATE_EXPRESSION); | 463 | flowableListener.setImplementation(DELEGATE_EXPRESSION); |
| 468 | - // TODO @lesan:可以在 BpmnModelUtils 搞个方法,类似 public static Integer parseCandidateStrategy。这样,就收敛啦! | ||
| 469 | - FieldExtension fieldExtension = new FieldExtension(); | ||
| 470 | - fieldExtension.setFieldName("listenerConfig"); | ||
| 471 | - fieldExtension.setStringValue(JsonUtils.toJsonString(node.getTaskAssignListener())); | ||
| 472 | - flowableListener.getFieldExtensions().add(fieldExtension); | 464 | + addListenerConfig(flowableListener, node.getTaskAssignListener()); |
| 473 | flowableListeners.add(flowableListener); | 465 | flowableListeners.add(flowableListener); |
| 474 | } | 466 | } |
| 475 | if (node.getTaskCompleteListener() != null | 467 | if (node.getTaskCompleteListener() != null |
| @@ -478,10 +470,7 @@ public class SimpleModelUtils { | @@ -478,10 +470,7 @@ public class SimpleModelUtils { | ||
| 478 | flowableListener.setEvent(TaskListener.EVENTNAME_COMPLETE); | 470 | flowableListener.setEvent(TaskListener.EVENTNAME_COMPLETE); |
| 479 | flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); | 471 | flowableListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); |
| 480 | flowableListener.setImplementation(DELEGATE_EXPRESSION); | 472 | flowableListener.setImplementation(DELEGATE_EXPRESSION); |
| 481 | - FieldExtension fieldExtension = new FieldExtension(); | ||
| 482 | - fieldExtension.setFieldName("listenerConfig"); | ||
| 483 | - fieldExtension.setStringValue(JsonUtils.toJsonString(node.getTaskCompleteListener())); | ||
| 484 | - flowableListener.getFieldExtensions().add(fieldExtension); | 473 | + addListenerConfig(flowableListener, node.getTaskCompleteListener()); |
| 485 | flowableListeners.add(flowableListener); | 474 | flowableListeners.add(flowableListener); |
| 486 | } | 475 | } |
| 487 | if (CollUtil.isNotEmpty(flowableListeners)) { | 476 | if (CollUtil.isNotEmpty(flowableListeners)) { |
| @@ -646,9 +635,9 @@ public class SimpleModelUtils { | @@ -646,9 +635,9 @@ public class SimpleModelUtils { | ||
| 646 | node.getConditionGroups()); | 635 | node.getConditionGroups()); |
| 647 | } | 636 | } |
| 648 | 637 | ||
| 649 | - public static String buildConditionExpression(BpmSimpleModelNodeVO.RouteCondition route) { | ||
| 650 | - return buildConditionExpression(route.getConditionType(), route.getConditionExpression(), | ||
| 651 | - route.getConditionGroups()); | 638 | + public static String buildConditionExpression(BpmSimpleModelNodeVO.RouterCondition router) { |
| 639 | + return buildConditionExpression(router.getConditionType(), router.getConditionExpression(), | ||
| 640 | + router.getConditionGroups()); | ||
| 652 | } | 641 | } |
| 653 | 642 | ||
| 654 | public static String buildConditionExpression(Integer conditionType, String conditionExpression, | 643 | public static String buildConditionExpression(Integer conditionType, String conditionExpression, |
| @@ -728,18 +717,19 @@ public class SimpleModelUtils { | @@ -728,18 +717,19 @@ public class SimpleModelUtils { | ||
| 728 | exclusiveGateway.setId(node.getId()); | 717 | exclusiveGateway.setId(node.getId()); |
| 729 | 718 | ||
| 730 | // 设置默认的序列流(条件) | 719 | // 设置默认的序列流(条件) |
| 720 | + node.setDefaultFlowId("Flow_" + IdUtil.fastUUID()); | ||
| 731 | exclusiveGateway.setDefaultFlow(node.getDefaultFlowId()); | 721 | exclusiveGateway.setDefaultFlow(node.getDefaultFlowId()); |
| 732 | return exclusiveGateway; | 722 | return exclusiveGateway; |
| 733 | } | 723 | } |
| 734 | 724 | ||
| 735 | @Override | 725 | @Override |
| 736 | public BpmSimpleModelNodeType getType() { | 726 | public BpmSimpleModelNodeType getType() { |
| 737 | - return BpmSimpleModelNodeType.ROUTE_BRANCH_NODE; | 727 | + return BpmSimpleModelNodeType.ROUTER_BRANCH_NODE; |
| 738 | } | 728 | } |
| 739 | 729 | ||
| 740 | - public static SequenceFlow buildSequenceFlow(String nodeId, BpmSimpleModelNodeVO.RouteCondition route) { | ||
| 741 | - String conditionExpression = ConditionNodeConvert.buildConditionExpression(route); | ||
| 742 | - return buildBpmnSequenceFlow(nodeId, route.getNodeId(), null, null, conditionExpression); | 730 | + public static SequenceFlow buildSequenceFlow(String nodeId, BpmSimpleModelNodeVO.RouterCondition router) { |
| 731 | + String conditionExpression = ConditionNodeConvert.buildConditionExpression(router); | ||
| 732 | + return buildBpmnSequenceFlow(nodeId, router.getNodeId(), null, null, conditionExpression); | ||
| 743 | } | 733 | } |
| 744 | 734 | ||
| 745 | } | 735 | } |
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 { | @@ -482,6 +482,12 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||
| 482 | if (instance == null) { | 482 | if (instance == null) { |
| 483 | throw exception(PROCESS_INSTANCE_NOT_EXISTS); | 483 | throw exception(PROCESS_INSTANCE_NOT_EXISTS); |
| 484 | } | 484 | } |
| 485 | + // 1.3 校验签名 | ||
| 486 | + BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId()); | ||
| 487 | + Boolean signEnable = parseSignEnable(bpmnModel, task.getTaskDefinitionKey()); | ||
| 488 | + if (signEnable && StrUtil.isEmpty(reqVO.getSign())) { | ||
| 489 | + throw exception(TASK_SIGNATURE_NOT_EXISTS); | ||
| 490 | + } | ||
| 485 | 491 | ||
| 486 | // 情况一:被委派的任务,不调用 complete 去完成任务 | 492 | // 情况一:被委派的任务,不调用 complete 去完成任务 |
| 487 | if (DelegationState.PENDING.equals(task.getDelegationState())) { | 493 | if (DelegationState.PENDING.equals(task.getDelegationState())) { |
| @@ -496,8 +502,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { | @@ -496,8 +502,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||
| 496 | } | 502 | } |
| 497 | 503 | ||
| 498 | // 情况三:审批普通的任务。大多数情况下,都是这样 | 504 | // 情况三:审批普通的任务。大多数情况下,都是这样 |
| 499 | - // 2.1 更新 task 状态、原因 | 505 | + // 2.1 更新 task 状态、原因、签字 |
| 500 | updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.APPROVE.getStatus(), reqVO.getReason()); | 506 | updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.APPROVE.getStatus(), reqVO.getReason()); |
| 507 | + if (signEnable) { | ||
| 508 | + taskService.setVariableLocal(task.getId(), BpmnVariableConstants.TASK_VARIABLE_SIGN, reqVO.getSign()); | ||
| 509 | + } | ||
| 501 | // 2.2 添加评论 | 510 | // 2.2 添加评论 |
| 502 | taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(), | 511 | taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(), |
| 503 | BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason())); | 512 | BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason())); |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmUserTaskListener.java
| 1 | package cn.iocoder.yudao.module.bpm.service.task.listener; | 1 | package cn.iocoder.yudao.module.bpm.service.task.listener; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | -import cn.hutool.core.lang.Assert; | ||
| 5 | import cn.hutool.core.util.StrUtil; | 4 | import cn.hutool.core.util.StrUtil; |
| 6 | -import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||
| 7 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; | 5 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; |
| 8 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmListenerParamTypeEnum; | 6 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmListenerParamTypeEnum; |
| 9 | -import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; | ||
| 10 | -import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; | ||
| 11 | import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; | 7 | import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; |
| 12 | import jakarta.annotation.Resource; | 8 | import jakarta.annotation.Resource; |
| 9 | +import lombok.Setter; | ||
| 13 | import lombok.extern.slf4j.Slf4j; | 10 | import lombok.extern.slf4j.Slf4j; |
| 14 | -import org.flowable.bpmn.model.BpmnModel; | ||
| 15 | -import org.flowable.bpmn.model.FieldExtension; | ||
| 16 | -import org.flowable.bpmn.model.FlowableListener; | ||
| 17 | -import org.flowable.bpmn.model.UserTask; | ||
| 18 | import org.flowable.engine.delegate.TaskListener; | 11 | import org.flowable.engine.delegate.TaskListener; |
| 19 | import org.flowable.engine.history.HistoricProcessInstance; | 12 | import org.flowable.engine.history.HistoricProcessInstance; |
| 13 | +import org.flowable.engine.impl.el.FixedValue; | ||
| 20 | import org.flowable.task.service.delegate.DelegateTask; | 14 | import org.flowable.task.service.delegate.DelegateTask; |
| 15 | +import org.springframework.context.annotation.Scope; | ||
| 21 | import org.springframework.http.HttpEntity; | 16 | import org.springframework.http.HttpEntity; |
| 22 | import org.springframework.http.HttpMethod; | 17 | import org.springframework.http.HttpMethod; |
| 23 | import org.springframework.http.ResponseEntity; | 18 | import org.springframework.http.ResponseEntity; |
| 24 | import org.springframework.stereotype.Component; | 19 | import org.springframework.stereotype.Component; |
| 25 | import org.springframework.util.LinkedMultiValueMap; | 20 | import org.springframework.util.LinkedMultiValueMap; |
| 26 | import org.springframework.util.MultiValueMap; | 21 | import org.springframework.util.MultiValueMap; |
| 22 | +import org.springframework.web.client.RestClientException; | ||
| 27 | import org.springframework.web.client.RestTemplate; | 23 | import org.springframework.web.client.RestTemplate; |
| 28 | 24 | ||
| 29 | import java.util.List; | 25 | import java.util.List; |
| 30 | import java.util.Map; | 26 | import java.util.Map; |
| 31 | 27 | ||
| 32 | import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; | 28 | import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; |
| 29 | +import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.parseListenerConfig; | ||
| 33 | 30 | ||
| 34 | /** | 31 | /** |
| 35 | * BPM 用户任务通用监听器 | 32 | * BPM 用户任务通用监听器 |
| @@ -38,34 +35,32 @@ import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_ | @@ -38,34 +35,32 @@ import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_ | ||
| 38 | */ | 35 | */ |
| 39 | @Component | 36 | @Component |
| 40 | @Slf4j | 37 | @Slf4j |
| 38 | +@Scope("prototype") | ||
| 41 | public class BpmUserTaskListener implements TaskListener { | 39 | public class BpmUserTaskListener implements TaskListener { |
| 42 | 40 | ||
| 43 | public static final String DELEGATE_EXPRESSION = "${bpmUserTaskListener}"; | 41 | public static final String DELEGATE_EXPRESSION = "${bpmUserTaskListener}"; |
| 44 | 42 | ||
| 45 | @Resource | 43 | @Resource |
| 46 | - private BpmModelService modelService; | ||
| 47 | - | ||
| 48 | - @Resource | ||
| 49 | private BpmProcessInstanceService processInstanceService; | 44 | private BpmProcessInstanceService processInstanceService; |
| 50 | 45 | ||
| 51 | @Resource | 46 | @Resource |
| 52 | private RestTemplate restTemplate; | 47 | private RestTemplate restTemplate; |
| 53 | 48 | ||
| 49 | + @Setter | ||
| 50 | + private FixedValue listenerConfig; | ||
| 51 | + | ||
| 54 | @Override | 52 | @Override |
| 55 | public void notify(DelegateTask delegateTask) { | 53 | public void notify(DelegateTask delegateTask) { |
| 56 | // 1. 获取所需基础信息 | 54 | // 1. 获取所需基础信息 |
| 57 | HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(delegateTask.getProcessInstanceId()); | 55 | HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(delegateTask.getProcessInstanceId()); |
| 58 | - BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(delegateTask.getProcessDefinitionId()); | ||
| 59 | - UserTask userTask = (UserTask) BpmnModelUtils.getFlowElementById(bpmnModel, delegateTask.getTaskDefinitionKey()); | ||
| 60 | - BpmSimpleModelNodeVO.ListenerHandler listenerHandler = getListenerHandlerByEvent(delegateTask.getEventName(), | ||
| 61 | - userTask.getTaskListeners()); | 56 | + BpmSimpleModelNodeVO.ListenerHandler listenerHandler = parseListenerConfig(listenerConfig); |
| 62 | 57 | ||
| 63 | // 2. 获取请求头和请求体 | 58 | // 2. 获取请求头和请求体 |
| 64 | Map<String, Object> processVariables = processInstance.getProcessVariables(); | 59 | Map<String, Object> processVariables = processInstance.getProcessVariables(); |
| 65 | MultiValueMap<String, String> headers = new LinkedMultiValueMap<>(); | 60 | MultiValueMap<String, String> headers = new LinkedMultiValueMap<>(); |
| 66 | MultiValueMap<String, String> body = new LinkedMultiValueMap<>(); | 61 | MultiValueMap<String, String> body = new LinkedMultiValueMap<>(); |
| 67 | - parseListenerMap(listenerHandler.getHeader(), processVariables, headers); | ||
| 68 | - parseListenerMap(listenerHandler.getBody(), processVariables, body); | 62 | + parseListenerParam(listenerHandler.getHeader(), processVariables, headers); |
| 63 | + parseListenerParam(listenerHandler.getBody(), processVariables, body); | ||
| 69 | // 2.1 请求头默认参数 | 64 | // 2.1 请求头默认参数 |
| 70 | if (StrUtil.isNotEmpty(delegateTask.getTenantId())) { | 65 | if (StrUtil.isNotEmpty(delegateTask.getTenantId())) { |
| 71 | headers.add(HEADER_TENANT_ID, delegateTask.getTenantId()); | 66 | headers.add(HEADER_TENANT_ID, delegateTask.getTenantId()); |
| @@ -80,21 +75,29 @@ public class BpmUserTaskListener implements TaskListener { | @@ -80,21 +75,29 @@ public class BpmUserTaskListener implements TaskListener { | ||
| 80 | // 3. 异步发起请求 | 75 | // 3. 异步发起请求 |
| 81 | // TODO @芋艿:确认要同步,还是异步 | 76 | // TODO @芋艿:确认要同步,还是异步 |
| 82 | HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body, headers); | 77 | HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body, headers); |
| 83 | - // TODO @lesan:可能需要 try catch 哇? RestClientException | ||
| 84 | - ResponseEntity<String> responseEntity = restTemplate.exchange(listenerHandler.getPath(), HttpMethod.POST, | ||
| 85 | - requestEntity, String.class); | ||
| 86 | - log.info("[notify][监听器:{},事件类型:{},请求头:{},请求体:{},响应结果:{}]", | ||
| 87 | - DELEGATE_EXPRESSION, | ||
| 88 | - delegateTask.getEventName(), | ||
| 89 | - headers, | ||
| 90 | - body, | ||
| 91 | - responseEntity); | 78 | + try { |
| 79 | + ResponseEntity<String> responseEntity = restTemplate.exchange(listenerHandler.getPath(), HttpMethod.POST, | ||
| 80 | + requestEntity, String.class); | ||
| 81 | + log.info("[notify][监听器:{},事件类型:{},请求头:{},请求体:{},响应结果:{}]", | ||
| 82 | + DELEGATE_EXPRESSION, | ||
| 83 | + delegateTask.getEventName(), | ||
| 84 | + headers, | ||
| 85 | + body, | ||
| 86 | + responseEntity); | ||
| 87 | + } catch (RestClientException e) { | ||
| 88 | + log.error("[error][监听器:{},事件类型:{},请求头:{},请求体:{},请求出错:{}]", | ||
| 89 | + DELEGATE_EXPRESSION, | ||
| 90 | + delegateTask.getEventName(), | ||
| 91 | + headers, | ||
| 92 | + body, | ||
| 93 | + e.getMessage()); | ||
| 94 | + } | ||
| 92 | // 4. 是否需要后续操作?TODO 芋艿:待定! | 95 | // 4. 是否需要后续操作?TODO 芋艿:待定! |
| 93 | } | 96 | } |
| 94 | 97 | ||
| 95 | - private void parseListenerMap(List<BpmSimpleModelNodeVO.ListenerHandler.ListenerParam> list, | ||
| 96 | - Map<String, Object> processVariables, | ||
| 97 | - MultiValueMap<String, String> to) { | 98 | + private void parseListenerParam(List<BpmSimpleModelNodeVO.ListenerHandler.ListenerParam> list, |
| 99 | + Map<String, Object> processVariables, | ||
| 100 | + MultiValueMap<String, String> to) { | ||
| 98 | if (CollUtil.isEmpty(list)) { | 101 | if (CollUtil.isEmpty(list)) { |
| 99 | return; | 102 | return; |
| 100 | } | 103 | } |
| @@ -107,17 +110,4 @@ public class BpmUserTaskListener implements TaskListener { | @@ -107,17 +110,4 @@ public class BpmUserTaskListener implements TaskListener { | ||
| 107 | }); | 110 | }); |
| 108 | } | 111 | } |
| 109 | 112 | ||
| 110 | - private BpmSimpleModelNodeVO.ListenerHandler getListenerHandlerByEvent(String eventName, List<FlowableListener> node) { | ||
| 111 | - FlowableListener flowableListener = node.stream() | ||
| 112 | - .filter(item -> item.getEvent().equals(eventName)) | ||
| 113 | - .findFirst().orElse(null); | ||
| 114 | - Assert.notNull(flowableListener, "监听器({})不能为空", flowableListener); | ||
| 115 | - // TODO @lesan:BpmnModelUtils 提供一个 BpmSimpleModelNodeVO.ListenerHandler 解析方法,尽量收敛掉。 | ||
| 116 | - FieldExtension fieldExtension = flowableListener.getFieldExtensions().stream() | ||
| 117 | - .filter(item -> item.getFieldName().equals("listenerConfig")) | ||
| 118 | - .findFirst().orElse(null); | ||
| 119 | - Assert.notNull(fieldExtension, "监听器扩展字段({})不能为空", fieldExtension); | ||
| 120 | - return JsonUtils.parseObject(fieldExtension.getStringValue(), BpmSimpleModelNodeVO.ListenerHandler.class); | ||
| 121 | - } | ||
| 122 | - | ||
| 123 | } | 113 | } |
| 124 | \ No newline at end of file | 114 | \ No newline at end of file |