Commit 3f1cd8057399e8a12c9d25da588ff04571e10374
Merge remote-tracking branch 'origin/feature/bpm' into feature/bpm
# Conflicts: # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
Showing
12 changed files
with
115 additions
and
74 deletions
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmBoundaryEventTypeEnum.java
| @@ -14,7 +14,8 @@ import lombok.Getter; | @@ -14,7 +14,8 @@ import lombok.Getter; | ||
| 14 | public enum BpmBoundaryEventTypeEnum { | 14 | public enum BpmBoundaryEventTypeEnum { |
| 15 | 15 | ||
| 16 | USER_TASK_TIMEOUT(1, "用户任务超时"), | 16 | USER_TASK_TIMEOUT(1, "用户任务超时"), |
| 17 | - DELAY_TIMER_TIMEOUT(2, "延迟器超时"); | 17 | + DELAY_TIMER_TIMEOUT(2, "延迟器超时"), |
| 18 | + CHILD_PROCESS_TIMEOUT(3, "子流程超时"); | ||
| 18 | 19 | ||
| 19 | private final Integer type; | 20 | private final Integer type; |
| 20 | private final String name; | 21 | private final String name; |
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeTypeEnum.java
| @@ -30,8 +30,7 @@ public enum BpmSimpleModelNodeTypeEnum implements ArrayValuable<Integer> { | @@ -30,8 +30,7 @@ public enum BpmSimpleModelNodeTypeEnum implements ArrayValuable<Integer> { | ||
| 30 | DELAY_TIMER_NODE(14, "延迟器", "receiveTask"), | 30 | DELAY_TIMER_NODE(14, "延迟器", "receiveTask"), |
| 31 | TRIGGER_NODE(15, "触发器", "serviceTask"), | 31 | TRIGGER_NODE(15, "触发器", "serviceTask"), |
| 32 | 32 | ||
| 33 | - CHILD_PROCESS(20, "子流程", "callActivity"), // TODO @lesan:CHILD_PROCESS、ASYNC_CHILD_PROCESS 可以合并为一个么? | ||
| 34 | - ASYNC_CHILD_PROCESS(21, "异步子流程", "callActivity"), | 33 | + CHILD_PROCESS(20, "子流程", "callActivity"), |
| 35 | 34 | ||
| 36 | // 50 ~ 条件分支 | 35 | // 50 ~ 条件分支 |
| 37 | CONDITION_NODE(50, "条件", "sequenceFlow"), // 用于构建流转条件的表达式 | 36 | CONDITION_NODE(50, "条件", "sequenceFlow"), // 用于构建流转条件的表达式 |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java
| @@ -423,35 +423,35 @@ public class BpmSimpleModelNodeVO { | @@ -423,35 +423,35 @@ public class BpmSimpleModelNodeVO { | ||
| 423 | @Valid | 423 | @Valid |
| 424 | public static class ChildProcessSetting { | 424 | public static class ChildProcessSetting { |
| 425 | 425 | ||
| 426 | - // TODO @lesan:calledElement => calledProcessDefinitionKey ? 这样更容易理解?不过如果一个流程多次发起,key 变了,好像会有问题? | ||
| 427 | @Schema(description = "被调用流程", requiredMode = Schema.RequiredMode.REQUIRED, example = "xxx") | 426 | @Schema(description = "被调用流程", requiredMode = Schema.RequiredMode.REQUIRED, example = "xxx") |
| 428 | @NotEmpty(message = "被调用流程不能为空") | 427 | @NotEmpty(message = "被调用流程不能为空") |
| 429 | - private String calledElement; | 428 | + private String calledProcessDefinitionKey; |
| 430 | 429 | ||
| 431 | @Schema(description = "被调用流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "xxx") | 430 | @Schema(description = "被调用流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "xxx") |
| 432 | @NotEmpty(message = "被调用流程名称不能为空") | 431 | @NotEmpty(message = "被调用流程名称不能为空") |
| 433 | - private String calledElementName; | 432 | + private String calledProcessDefinitionName; |
| 434 | 433 | ||
| 435 | @Schema(description = "是否异步", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") | 434 | @Schema(description = "是否异步", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") |
| 436 | @NotNull(message = "是否异步不能为空") | 435 | @NotNull(message = "是否异步不能为空") |
| 437 | private Boolean async; | 436 | private Boolean async; |
| 438 | 437 | ||
| 439 | - // TODO @lesan:inVariables | ||
| 440 | - @Schema(description = "输入参数(主->子)", requiredMode = Schema.RequiredMode.REQUIRED, example = "[]") | ||
| 441 | - private List<IOParameter> inVariable; | 438 | + @Schema(description = "输入参数(主->子)", example = "[]") |
| 439 | + private List<IOParameter> inVariables; | ||
| 442 | 440 | ||
| 443 | - // TODO @lesan:outVariables | ||
| 444 | @Schema(description = "输出参数(子->主)", example = "[]") | 441 | @Schema(description = "输出参数(子->主)", example = "[]") |
| 445 | - private List<IOParameter> outVariable; | 442 | + private List<IOParameter> outVariables; |
| 446 | 443 | ||
| 447 | - @Schema(description = "是否自动跳过子流程发起节点", example = "false") | 444 | + @Schema(description = "是否自动跳过子流程发起节点", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") |
| 448 | @NotNull(message = "是否自动跳过子流程发起节点不能为空") | 445 | @NotNull(message = "是否自动跳过子流程发起节点不能为空") |
| 449 | private Boolean skipStartUserNode; | 446 | private Boolean skipStartUserNode; |
| 450 | 447 | ||
| 451 | @Schema(description = "子流程发起人配置", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") | 448 | @Schema(description = "子流程发起人配置", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") |
| 452 | - // TODO @lesan:这个应该也必须填写? | 449 | + @NotNull(message = "子流程发起人配置不能为空") |
| 453 | private StartUserSetting startUserSetting; | 450 | private StartUserSetting startUserSetting; |
| 454 | 451 | ||
| 452 | + @Schema(description = "超时设置", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}") | ||
| 453 | + private TimeoutSetting timeoutSetting; | ||
| 454 | + | ||
| 455 | @Schema(description = "子流程发起人配置") | 455 | @Schema(description = "子流程发起人配置") |
| 456 | @Data | 456 | @Data |
| 457 | @Valid | 457 | @Valid |
| @@ -465,11 +465,28 @@ public class BpmSimpleModelNodeVO { | @@ -465,11 +465,28 @@ public class BpmSimpleModelNodeVO { | ||
| 465 | @Schema(description = "表单", example = "xxx") | 465 | @Schema(description = "表单", example = "xxx") |
| 466 | private String formField; | 466 | private String formField; |
| 467 | 467 | ||
| 468 | - // TODO @lesan:emptyHandleType => emptyType,和 type 对上? | ||
| 469 | @Schema(description = "当子流程发起人为空时类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | 468 | @Schema(description = "当子流程发起人为空时类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") |
| 470 | @NotNull(message = "当子流程发起人为空时类型不能为空") | 469 | @NotNull(message = "当子流程发起人为空时类型不能为空") |
| 471 | @InEnum(BpmChildProcessStartUserEmptyTypeEnum.class) | 470 | @InEnum(BpmChildProcessStartUserEmptyTypeEnum.class) |
| 472 | - private Integer emptyHandleType; | 471 | + private Integer emptyType; |
| 472 | + | ||
| 473 | + } | ||
| 474 | + | ||
| 475 | + @Schema(description = "超时设置") | ||
| 476 | + @Data | ||
| 477 | + @Valid | ||
| 478 | + public static class TimeoutSetting { | ||
| 479 | + | ||
| 480 | + @Schema(description = "是否开启超时设置", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") | ||
| 481 | + @NotNull(message = "是否开启超时设置不能为空") | ||
| 482 | + private Boolean enable; | ||
| 483 | + | ||
| 484 | + @Schema(description = "时间类型", example = "1") | ||
| 485 | + @InEnum(BpmDelayTimerTypeEnum.class) | ||
| 486 | + private Integer type; | ||
| 487 | + | ||
| 488 | + @Schema(description = "时间表达式", example = "PT1H,2025-01-01T00:00:00") | ||
| 489 | + private String timeExpression; | ||
| 473 | 490 | ||
| 474 | } | 491 | } |
| 475 | 492 |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java
| @@ -110,6 +110,10 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { | @@ -110,6 +110,10 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { | ||
| 110 | } else if (ObjectUtil.equal(bpmTimerBoundaryEventType, BpmBoundaryEventTypeEnum.DELAY_TIMER_TIMEOUT)) { | 110 | } else if (ObjectUtil.equal(bpmTimerBoundaryEventType, BpmBoundaryEventTypeEnum.DELAY_TIMER_TIMEOUT)) { |
| 111 | String taskKey = boundaryEvent.getAttachedToRefId(); | 111 | String taskKey = boundaryEvent.getAttachedToRefId(); |
| 112 | taskService.triggerTask(event.getProcessInstanceId(), taskKey); | 112 | taskService.triggerTask(event.getProcessInstanceId(), taskKey); |
| 113 | + // 2.3 子流程超时处理 | ||
| 114 | + } else if (ObjectUtil.equal(bpmTimerBoundaryEventType, BpmBoundaryEventTypeEnum.CHILD_PROCESS_TIMEOUT)) { | ||
| 115 | + String taskKey = boundaryEvent.getAttachedToRefId(); | ||
| 116 | + taskService.processChildProcessTimeout(event.getProcessInstanceId(), taskKey); | ||
| 113 | } | 117 | } |
| 114 | } | 118 | } |
| 115 | 119 |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java
| 1 | package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; | 1 | package cn.iocoder.yudao.module.bpm.framework.flowable.core.util; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.map.MapUtil; | ||
| 3 | import cn.hutool.core.util.ObjectUtil; | 4 | import cn.hutool.core.util.ObjectUtil; |
| 4 | -import cn.hutool.core.util.StrUtil; | ||
| 5 | import cn.hutool.extra.spring.SpringUtil; | 5 | import cn.hutool.extra.spring.SpringUtil; |
| 6 | import cn.iocoder.yudao.framework.common.core.KeyValue; | 6 | import cn.iocoder.yudao.framework.common.core.KeyValue; |
| 7 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | 7 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| @@ -244,8 +244,7 @@ public class FlowableUtils { | @@ -244,8 +244,7 @@ public class FlowableUtils { | ||
| 244 | return formFieldsMap.entrySet().stream() | 244 | return formFieldsMap.entrySet().stream() |
| 245 | .limit(3) | 245 | .limit(3) |
| 246 | .map(entry -> new KeyValue<>(entry.getValue().getTitle(), | 246 | .map(entry -> new KeyValue<>(entry.getValue().getTitle(), |
| 247 | - // TODO @lesan: MapUtil.getStr 可以更简单? | ||
| 248 | - StrUtil.toStringOrEmpty(processVariables.getOrDefault(entry.getValue().getField(), "")))) | 247 | + MapUtil.getStr(processVariables, entry.getValue().getField(), ""))) |
| 249 | .collect(Collectors.toList()); | 248 | .collect(Collectors.toList()); |
| 250 | } | 249 | } |
| 251 | 250 |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
| @@ -48,7 +48,7 @@ public class SimpleModelUtils { | @@ -48,7 +48,7 @@ public class SimpleModelUtils { | ||
| 48 | new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(), new TransactorNodeConvert(), | 48 | new StartUserNodeConvert(), new ApproveNodeConvert(), new CopyNodeConvert(), new TransactorNodeConvert(), |
| 49 | new DelayTimerNodeConvert(), new TriggerNodeConvert(), | 49 | new DelayTimerNodeConvert(), new TriggerNodeConvert(), |
| 50 | new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert(), new RouteBranchNodeConvert(), | 50 | new ConditionBranchNodeConvert(), new ParallelBranchNodeConvert(), new InclusiveBranchNodeConvert(), new RouteBranchNodeConvert(), |
| 51 | - new ChildProcessConvert(), new AsyncChildProcessConvert()); | 51 | + new ChildProcessConvert()); |
| 52 | converts.forEach(convert -> NODE_CONVERTS.put(convert.getType(), convert)); | 52 | converts.forEach(convert -> NODE_CONVERTS.put(convert.getType(), convert)); |
| 53 | } | 53 | } |
| 54 | 54 | ||
| @@ -416,6 +416,7 @@ public class SimpleModelUtils { | @@ -416,6 +416,7 @@ public class SimpleModelUtils { | ||
| 416 | private BoundaryEvent buildUserTaskTimeoutBoundaryEvent(UserTask userTask, | 416 | private BoundaryEvent buildUserTaskTimeoutBoundaryEvent(UserTask userTask, |
| 417 | BpmSimpleModelNodeVO.TimeoutHandler timeoutHandler) { | 417 | BpmSimpleModelNodeVO.TimeoutHandler timeoutHandler) { |
| 418 | // 1.1 定时器边界事件 | 418 | // 1.1 定时器边界事件 |
| 419 | + // TODO @lesan:一些 BoundaryEvent timeout 的,可以做一些基础的设置么? | ||
| 419 | BoundaryEvent boundaryEvent = new BoundaryEvent(); | 420 | BoundaryEvent boundaryEvent = new BoundaryEvent(); |
| 420 | boundaryEvent.setId("Event-" + IdUtil.fastUUID()); | 421 | boundaryEvent.setId("Event-" + IdUtil.fastUUID()); |
| 421 | boundaryEvent.setCancelActivity(false); // 设置关联的任务为不会被中断 | 422 | boundaryEvent.setCancelActivity(false); // 设置关联的任务为不会被中断 |
| @@ -723,6 +724,7 @@ public class SimpleModelUtils { | @@ -723,6 +724,7 @@ public class SimpleModelUtils { | ||
| 723 | // 2. 添加接收任务的 Timer Boundary Event | 724 | // 2. 添加接收任务的 Timer Boundary Event |
| 724 | if (node.getDelaySetting() != null) { | 725 | if (node.getDelaySetting() != null) { |
| 725 | // 2.1 定时器边界事件 | 726 | // 2.1 定时器边界事件 |
| 727 | + // TODO @lesan:一些 BoundaryEvent timeout 的,可以做一些基础的设置么? | ||
| 726 | BoundaryEvent boundaryEvent = new BoundaryEvent(); | 728 | BoundaryEvent boundaryEvent = new BoundaryEvent(); |
| 727 | boundaryEvent.setId("Event-" + IdUtil.fastUUID()); | 729 | boundaryEvent.setId("Event-" + IdUtil.fastUUID()); |
| 728 | boundaryEvent.setCancelActivity(false); | 730 | boundaryEvent.setCancelActivity(false); |
| @@ -816,48 +818,41 @@ public class SimpleModelUtils { | @@ -816,48 +818,41 @@ public class SimpleModelUtils { | ||
| 816 | private static class ChildProcessConvert implements NodeConvert { | 818 | private static class ChildProcessConvert implements NodeConvert { |
| 817 | 819 | ||
| 818 | @Override | 820 | @Override |
| 819 | - public CallActivity convert(BpmSimpleModelNodeVO node) { | 821 | + public List<FlowElement> convertList(BpmSimpleModelNodeVO node) { |
| 822 | + List<FlowElement> flowElements = new ArrayList<>(2); | ||
| 820 | BpmSimpleModelNodeVO.ChildProcessSetting childProcessSetting = node.getChildProcessSetting(); | 823 | BpmSimpleModelNodeVO.ChildProcessSetting childProcessSetting = node.getChildProcessSetting(); |
| 821 | - List<IOParameter> inVariable = childProcessSetting.getInVariable() == null ? | ||
| 822 | - new ArrayList<>() : new ArrayList<>(childProcessSetting.getInVariable()); | 824 | + List<IOParameter> inVariables = childProcessSetting.getInVariables() == null ? |
| 825 | + new ArrayList<>() : new ArrayList<>(childProcessSetting.getInVariables()); | ||
| 823 | CallActivity callActivity = new CallActivity(); | 826 | CallActivity callActivity = new CallActivity(); |
| 824 | callActivity.setId(node.getId()); | 827 | callActivity.setId(node.getId()); |
| 825 | callActivity.setName(node.getName()); | 828 | callActivity.setName(node.getName()); |
| 826 | - callActivity.setCalledElementType("key"); // TODO @lesan:这里为啥是 key 哈? | 829 | + callActivity.setCalledElementType("key"); |
| 827 | // 1. 是否异步 | 830 | // 1. 是否异步 |
| 828 | - callActivity.setAsynchronous(node.getChildProcessSetting().getAsync()); | 831 | + if (node.getChildProcessSetting().getAsync()) { |
| 832 | + // TODO @lesan: 这里目前测试没有跳过执行call activity 后面的节点 | ||
| 833 | + callActivity.setAsynchronous(true); | ||
| 834 | + } | ||
| 829 | 835 | ||
| 830 | // 2. 调用的子流程 | 836 | // 2. 调用的子流程 |
| 831 | - callActivity.setCalledElement(childProcessSetting.getCalledElement()); | ||
| 832 | - callActivity.setProcessInstanceName(childProcessSetting.getCalledElementName()); | 837 | + callActivity.setCalledElement(childProcessSetting.getCalledProcessDefinitionKey()); |
| 838 | + callActivity.setProcessInstanceName(childProcessSetting.getCalledProcessDefinitionName()); | ||
| 833 | 839 | ||
| 834 | // 3. 是否自动跳过子流程发起节点 | 840 | // 3. 是否自动跳过子流程发起节点 |
| 835 | - // TODO @lesan:貌似只有 SourceExpression 的区别,直接通过 valueOf childProcessSetting.getSkipStartUserNode()??? | ||
| 836 | - if (Boolean.TRUE.equals(childProcessSetting.getSkipStartUserNode())) { | ||
| 837 | - IOParameter ioParameter = new IOParameter(); | ||
| 838 | - ioParameter.setSourceExpression("true"); | ||
| 839 | - ioParameter.setTarget(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE); | ||
| 840 | - inVariable.add(ioParameter); | ||
| 841 | - } else { | ||
| 842 | - IOParameter ioParameter = new IOParameter(); | ||
| 843 | - ioParameter.setSourceExpression("false"); | ||
| 844 | - ioParameter.setTarget(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE); | ||
| 845 | - inVariable.add(ioParameter); | ||
| 846 | - } | ||
| 847 | - | ||
| 848 | - // 4. 主→子变量传递 | ||
| 849 | - // 4.1 【默认需要传递的一些变量】流程状态 | ||
| 850 | - // TODO @lesan:4.1 这个要不,单独一个序号,类似 3. 这个。然后下面,就是把 主→子变量传递、子→主变量传递;这样逻辑连贯点哈 | ||
| 851 | IOParameter ioParameter = new IOParameter(); | 841 | IOParameter ioParameter = new IOParameter(); |
| 842 | + ioParameter.setSourceExpression(childProcessSetting.getSkipStartUserNode().toString()); | ||
| 843 | + ioParameter.setTarget(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE); | ||
| 844 | + inVariables.add(ioParameter); | ||
| 845 | + | ||
| 846 | + // 4. 【默认需要传递的一些变量】流程状态 | ||
| 847 | + ioParameter = new IOParameter(); | ||
| 852 | ioParameter.setSource(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS); | 848 | ioParameter.setSource(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS); |
| 853 | ioParameter.setTarget(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS); | 849 | ioParameter.setTarget(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS); |
| 854 | - inVariable.add(ioParameter); | ||
| 855 | - callActivity.setInParameters(inVariable); | 850 | + inVariables.add(ioParameter); |
| 856 | 851 | ||
| 857 | - // 5. 子→主变量传递 | ||
| 858 | - // TODO @lesan:通过 isNotEmpty 这种哈 | ||
| 859 | - if (childProcessSetting.getOutVariable() != null && !childProcessSetting.getOutVariable().isEmpty()) { | ||
| 860 | - callActivity.setOutParameters(childProcessSetting.getOutVariable()); | 852 | + // 5. 主→子变量传递、子->主变量传递 |
| 853 | + callActivity.setInParameters(inVariables); | ||
| 854 | + if (ArrayUtil.isNotEmpty(childProcessSetting.getOutVariables()) && ObjUtil.notEqual(childProcessSetting.getAsync(), Boolean.TRUE)) { | ||
| 855 | + callActivity.setOutParameters(childProcessSetting.getOutVariables()); | ||
| 861 | } | 856 | } |
| 862 | 857 | ||
| 863 | // 6. 子流程发起人配置 | 858 | // 6. 子流程发起人配置 |
| @@ -873,9 +868,28 @@ public class SimpleModelUtils { | @@ -873,9 +868,28 @@ public class SimpleModelUtils { | ||
| 873 | executionListeners.add(flowableListener); | 868 | executionListeners.add(flowableListener); |
| 874 | callActivity.setExecutionListeners(executionListeners); | 869 | callActivity.setExecutionListeners(executionListeners); |
| 875 | 870 | ||
| 871 | + // 7. 超时设置 | ||
| 872 | + if (childProcessSetting.getTimeoutSetting() != null) { | ||
| 873 | + // TODO @lesan:一些 BoundaryEvent timeout 的,可以做一些基础的设置么? | ||
| 874 | + BoundaryEvent boundaryEvent = new BoundaryEvent(); | ||
| 875 | + boundaryEvent.setId("Event-" + IdUtil.fastUUID()); | ||
| 876 | + boundaryEvent.setCancelActivity(false); | ||
| 877 | + boundaryEvent.setAttachedToRef(callActivity); | ||
| 878 | + TimerEventDefinition eventDefinition = new TimerEventDefinition(); | ||
| 879 | + if (childProcessSetting.getTimeoutSetting().getType().equals(BpmDelayTimerTypeEnum.FIXED_DATE_TIME.getType())) { | ||
| 880 | + eventDefinition.setTimeDuration(childProcessSetting.getTimeoutSetting().getTimeExpression()); | ||
| 881 | + } else if (childProcessSetting.getTimeoutSetting().getType().equals(BpmDelayTimerTypeEnum.FIXED_TIME_DURATION.getType())) { | ||
| 882 | + eventDefinition.setTimeDate(childProcessSetting.getTimeoutSetting().getTimeExpression()); | ||
| 883 | + } | ||
| 884 | + boundaryEvent.addEventDefinition(eventDefinition); | ||
| 885 | + addExtensionElement(boundaryEvent, BOUNDARY_EVENT_TYPE, BpmBoundaryEventTypeEnum.CHILD_PROCESS_TIMEOUT.getType()); | ||
| 886 | + flowElements.add(boundaryEvent); | ||
| 887 | + } | ||
| 888 | + | ||
| 876 | // 添加节点类型 | 889 | // 添加节点类型 |
| 877 | addNodeType(node.getType(), callActivity); | 890 | addNodeType(node.getType(), callActivity); |
| 878 | - return callActivity; | 891 | + flowElements.add(callActivity); |
| 892 | + return flowElements; | ||
| 879 | } | 893 | } |
| 880 | 894 | ||
| 881 | @Override | 895 | @Override |
| @@ -885,16 +899,6 @@ public class SimpleModelUtils { | @@ -885,16 +899,6 @@ public class SimpleModelUtils { | ||
| 885 | 899 | ||
| 886 | } | 900 | } |
| 887 | 901 | ||
| 888 | - private static class AsyncChildProcessConvert extends ChildProcessConvert { | ||
| 889 | - | ||
| 890 | - @Override | ||
| 891 | - public BpmSimpleModelNodeTypeEnum getType() { | ||
| 892 | - return BpmSimpleModelNodeTypeEnum.ASYNC_CHILD_PROCESS; | ||
| 893 | - } | ||
| 894 | - | ||
| 895 | - } | ||
| 896 | - | ||
| 897 | - | ||
| 898 | private static String buildGatewayJoinId(String id) { | 902 | private static String buildGatewayJoinId(String id) { |
| 899 | return id + "_join"; | 903 | return id + "_join"; |
| 900 | } | 904 | } |
| @@ -925,7 +929,6 @@ public class SimpleModelUtils { | @@ -925,7 +929,6 @@ public class SimpleModelUtils { | ||
| 925 | || nodeType == BpmSimpleModelNodeTypeEnum.TRANSACTOR_NODE | 929 | || nodeType == BpmSimpleModelNodeTypeEnum.TRANSACTOR_NODE |
| 926 | || nodeType == BpmSimpleModelNodeTypeEnum.COPY_NODE | 930 | || nodeType == BpmSimpleModelNodeTypeEnum.COPY_NODE |
| 927 | || nodeType == BpmSimpleModelNodeTypeEnum.CHILD_PROCESS | 931 | || nodeType == BpmSimpleModelNodeTypeEnum.CHILD_PROCESS |
| 928 | - || nodeType == BpmSimpleModelNodeTypeEnum.ASYNC_CHILD_PROCESS | ||
| 929 | || nodeType == BpmSimpleModelNodeTypeEnum.END_NODE) { | 932 | || nodeType == BpmSimpleModelNodeTypeEnum.END_NODE) { |
| 930 | // 添加元素 | 933 | // 添加元素 |
| 931 | resultNodes.add(currentNode); | 934 | resultNodes.add(currentNode); |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
| @@ -320,7 +320,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | @@ -320,7 +320,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | ||
| 320 | // 遍历 tasks 列表,只处理已结束的 UserTask | 320 | // 遍历 tasks 列表,只处理已结束的 UserTask |
| 321 | // 为什么不通过 activities 呢?因为,加签场景下,它只存在于 tasks,没有 activities,导致如果遍历 activities | 321 | // 为什么不通过 activities 呢?因为,加签场景下,它只存在于 tasks,没有 activities,导致如果遍历 activities |
| 322 | // 的话,它无法成为一个节点 | 322 | // 的话,它无法成为一个节点 |
| 323 | - // TODO @芋艿:子流程只有activity,这里获取不到已结束的子流程;TODO @lesan:这个会有啥影响?微信聊? | 323 | + // TODO @芋艿:子流程只有activity,这里获取不到已结束的子流程;TODO @lesan:这个会导致timeline不会展示已结束的子流程 |
| 324 | List<HistoricTaskInstance> endTasks = filterList(tasks, task -> task.getEndTime() != null); | 324 | List<HistoricTaskInstance> endTasks = filterList(tasks, task -> task.getEndTime() != null); |
| 325 | List<ActivityNode> approvalNodes = convertList(endTasks, task -> { | 325 | List<ActivityNode> approvalNodes = convertList(endTasks, task -> { |
| 326 | FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); | 326 | FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); |
| @@ -414,7 +414,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | @@ -414,7 +414,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | ||
| 414 | // 处理每个任务的 tasks 属性 | 414 | // 处理每个任务的 tasks 属性 |
| 415 | for (HistoricActivityInstance activity : taskActivities) { | 415 | for (HistoricActivityInstance activity : taskActivities) { |
| 416 | HistoricTaskInstance task = taskMap.get(activity.getTaskId()); | 416 | HistoricTaskInstance task = taskMap.get(activity.getTaskId()); |
| 417 | - // TODO @lesan:这里为啥 continue 哈? | 417 | + // TODO @lesan:这里为啥 continue 哈? @芋艿:子流程的 activity 中 task 是null 下面的方法会报错;TODO @lesan:写个注释??? |
| 418 | if (task == null) { | 418 | if (task == null) { |
| 419 | continue; | 419 | continue; |
| 420 | } | 420 | } |
| @@ -510,8 +510,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | @@ -510,8 +510,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | ||
| 510 | } | 510 | } |
| 511 | 511 | ||
| 512 | // 4. 子流程节点 | 512 | // 4. 子流程节点 |
| 513 | - if (BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType().equals(node.getType()) || | ||
| 514 | - BpmSimpleModelNodeTypeEnum.ASYNC_CHILD_PROCESS.getType().equals(node.getType())) { | 513 | + if (BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType().equals(node.getType())) { |
| 515 | return activityNode; | 514 | return activityNode; |
| 516 | } | 515 | } |
| 517 | return null; | 516 | return null; |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
| @@ -276,6 +276,13 @@ public interface BpmTaskService { | @@ -276,6 +276,13 @@ public interface BpmTaskService { | ||
| 276 | */ | 276 | */ |
| 277 | void processTaskTimeout(String processInstanceId, String taskDefineKey, Integer handlerType); | 277 | void processTaskTimeout(String processInstanceId, String taskDefineKey, Integer handlerType); |
| 278 | 278 | ||
| 279 | + /** | ||
| 280 | + * 处理 ChildProcess 子流程的审批超时事件 | ||
| 281 | + * | ||
| 282 | + * @param processInstanceId 流程示例编号 | ||
| 283 | + * @param taskDefineKey 任务 Key | ||
| 284 | + */ | ||
| 285 | + void processChildProcessTimeout(String processInstanceId, String taskDefineKey); | ||
| 279 | 286 | ||
| 280 | /** | 287 | /** |
| 281 | * 触发流程任务 (ReceiveTask) 的执行 | 288 | * 触发流程任务 (ReceiveTask) 的执行 |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
| @@ -41,6 +41,7 @@ import org.flowable.engine.ManagementService; | @@ -41,6 +41,7 @@ import org.flowable.engine.ManagementService; | ||
| 41 | import org.flowable.engine.RuntimeService; | 41 | import org.flowable.engine.RuntimeService; |
| 42 | import org.flowable.engine.TaskService; | 42 | import org.flowable.engine.TaskService; |
| 43 | import org.flowable.engine.history.HistoricActivityInstance; | 43 | import org.flowable.engine.history.HistoricActivityInstance; |
| 44 | +import org.flowable.engine.runtime.ActivityInstance; | ||
| 44 | import org.flowable.engine.runtime.Execution; | 45 | import org.flowable.engine.runtime.Execution; |
| 45 | import org.flowable.engine.runtime.ProcessInstance; | 46 | import org.flowable.engine.runtime.ProcessInstance; |
| 46 | import org.flowable.task.api.DelegationState; | 47 | import org.flowable.task.api.DelegationState; |
| @@ -1230,7 +1231,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { | @@ -1230,7 +1231,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||
| 1230 | if (userTaskElement.getId().equals(START_USER_NODE_ID) | 1231 | if (userTaskElement.getId().equals(START_USER_NODE_ID) |
| 1231 | && (skipStartUserNodeFlag == null // 目的:一般是“主流程”,发起人节点,自动通过审核 | 1232 | && (skipStartUserNodeFlag == null // 目的:一般是“主流程”,发起人节点,自动通过审核 |
| 1232 | || Boolean.TRUE.equals(skipStartUserNodeFlag)) // 目的:一般是“子流程”,发起人节点,按配置自动通过审核 | 1233 | || Boolean.TRUE.equals(skipStartUserNodeFlag)) // 目的:一般是“子流程”,发起人节点,按配置自动通过审核 |
| 1233 | - && !Boolean.TRUE.equals(returnTaskFlag)) { // TODO @lesan:ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE) 改成这个有问题么?尽量不用 ! 取反 | 1234 | + && ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE)) { |
| 1234 | getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId()) | 1235 | getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId()) |
| 1235 | .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_SKIP_START_USER_NODE.getReason())); | 1236 | .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_SKIP_START_USER_NODE.getReason())); |
| 1236 | return; | 1237 | return; |
| @@ -1323,6 +1324,16 @@ public class BpmTaskServiceImpl implements BpmTaskService { | @@ -1323,6 +1324,16 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||
| 1323 | } | 1324 | } |
| 1324 | 1325 | ||
| 1325 | @Override | 1326 | @Override |
| 1327 | + @Transactional(rollbackFor = Exception.class) | ||
| 1328 | + public void processChildProcessTimeout(String processInstanceId, String taskDefineKey) { | ||
| 1329 | + List<ActivityInstance> activityInstances = runtimeService.createActivityInstanceQuery() | ||
| 1330 | + .processInstanceId(processInstanceId) | ||
| 1331 | + .activityId(taskDefineKey).list(); | ||
| 1332 | + activityInstances.forEach(activityInstance -> FlowableUtils.execute(activityInstance.getTenantId(), | ||
| 1333 | + () -> moveTaskToEnd(activityInstance.getCalledProcessInstanceId(), BpmReasonEnum.TIMEOUT_APPROVE.getReason()))); | ||
| 1334 | + } | ||
| 1335 | + | ||
| 1336 | + @Override | ||
| 1326 | public void triggerTask(String processInstanceId, String taskDefineKey) { | 1337 | public void triggerTask(String processInstanceId, String taskDefineKey) { |
| 1327 | Execution execution = runtimeService.createExecutionQuery() | 1338 | Execution execution = runtimeService.createExecutionQuery() |
| 1328 | .processInstanceId(processInstanceId) | 1339 | .processInstanceId(processInstanceId) |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmCallActivityListener.java
| @@ -59,19 +59,19 @@ public class BpmCallActivityListener implements ExecutionListener { | @@ -59,19 +59,19 @@ public class BpmCallActivityListener implements ExecutionListener { | ||
| 59 | // 2.1 当表单值为空时 | 59 | // 2.1 当表单值为空时 |
| 60 | if (StrUtil.isEmpty(formFieldValue)) { | 60 | if (StrUtil.isEmpty(formFieldValue)) { |
| 61 | // 2.1.1 来自主流程发起人 | 61 | // 2.1.1 来自主流程发起人 |
| 62 | - if (startUserSetting.getEmptyHandleType().equals(BpmChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_START_USER.getType())) { | 62 | + if (startUserSetting.getEmptyType().equals(BpmChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_START_USER.getType())) { |
| 63 | FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId())); | 63 | FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId())); |
| 64 | return; | 64 | return; |
| 65 | } | 65 | } |
| 66 | // 2.1.2 来自子流程管理员 | 66 | // 2.1.2 来自子流程管理员 |
| 67 | - if (startUserSetting.getEmptyHandleType().equals(BpmChildProcessStartUserEmptyTypeEnum.CHILD_PROCESS_ADMIN.getType())) { | 67 | + if (startUserSetting.getEmptyType().equals(BpmChildProcessStartUserEmptyTypeEnum.CHILD_PROCESS_ADMIN.getType())) { |
| 68 | BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(execution.getProcessDefinitionId()); | 68 | BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(execution.getProcessDefinitionId()); |
| 69 | List<Long> managerUserIds = processDefinition.getManagerUserIds(); | 69 | List<Long> managerUserIds = processDefinition.getManagerUserIds(); |
| 70 | FlowableUtils.setAuthenticatedUserId(managerUserIds.get(0)); | 70 | FlowableUtils.setAuthenticatedUserId(managerUserIds.get(0)); |
| 71 | return; | 71 | return; |
| 72 | } | 72 | } |
| 73 | // 2.1.3 来自主流程管理员 | 73 | // 2.1.3 来自主流程管理员 |
| 74 | - if (startUserSetting.getEmptyHandleType().equals(BpmChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_ADMIN.getType())) { | 74 | + if (startUserSetting.getEmptyType().equals(BpmChildProcessStartUserEmptyTypeEnum.MAIN_PROCESS_ADMIN.getType())) { |
| 75 | BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(parent.getProcessDefinitionId()); | 75 | BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(parent.getProcessDefinitionId()); |
| 76 | List<Long> managerUserIds = processDefinition.getManagerUserIds(); | 76 | List<Long> managerUserIds = processDefinition.getManagerUserIds(); |
| 77 | FlowableUtils.setAuthenticatedUserId(managerUserIds.get(0)); | 77 | FlowableUtils.setAuthenticatedUserId(managerUserIds.get(0)); |
| @@ -82,7 +82,8 @@ public class BpmCallActivityListener implements ExecutionListener { | @@ -82,7 +82,8 @@ public class BpmCallActivityListener implements ExecutionListener { | ||
| 82 | try { | 82 | try { |
| 83 | FlowableUtils.setAuthenticatedUserId(Long.parseLong(formFieldValue)); | 83 | FlowableUtils.setAuthenticatedUserId(Long.parseLong(formFieldValue)); |
| 84 | } catch (Exception e) { | 84 | } catch (Exception e) { |
| 85 | - // todo @lesan:打个日志,方便排查 | 85 | + log.error("[notify][监听器:{},子流程监听器设置流程的发起人字符串转 Long 失败,字符串:{}]", |
| 86 | + DELEGATE_EXPRESSION, formFieldValue); | ||
| 86 | FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId())); | 87 | FlowableUtils.setAuthenticatedUserId(Long.parseLong(parent.getStartUserId())); |
| 87 | } | 88 | } |
| 88 | } | 89 | } |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiAccessLogServiceImpl.java
| 1 | package cn.iocoder.yudao.module.infra.service.logger; | 1 | package cn.iocoder.yudao.module.infra.service.logger; |
| 2 | 2 | ||
| 3 | -import cn.hutool.core.util.StrUtil; | ||
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 4 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 5 | +import cn.iocoder.yudao.framework.common.util.string.StrUtils; | ||
| 6 | import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; | 6 | import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; |
| 7 | import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | 7 | import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; |
| 8 | import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO; | 8 | import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO; |
| @@ -35,8 +35,8 @@ public class ApiAccessLogServiceImpl implements ApiAccessLogService { | @@ -35,8 +35,8 @@ public class ApiAccessLogServiceImpl implements ApiAccessLogService { | ||
| 35 | @Override | 35 | @Override |
| 36 | public void createApiAccessLog(ApiAccessLogCreateReqDTO createDTO) { | 36 | public void createApiAccessLog(ApiAccessLogCreateReqDTO createDTO) { |
| 37 | ApiAccessLogDO apiAccessLog = BeanUtils.toBean(createDTO, ApiAccessLogDO.class); | 37 | ApiAccessLogDO apiAccessLog = BeanUtils.toBean(createDTO, ApiAccessLogDO.class); |
| 38 | - apiAccessLog.setRequestParams(StrUtil.maxLength(apiAccessLog.getRequestParams(), REQUEST_PARAMS_MAX_LENGTH)); | ||
| 39 | - apiAccessLog.setResultMsg(StrUtil.maxLength(apiAccessLog.getResultMsg(), RESULT_MSG_MAX_LENGTH)); | 38 | + apiAccessLog.setRequestParams(StrUtils.maxLength(apiAccessLog.getRequestParams(), REQUEST_PARAMS_MAX_LENGTH)); |
| 39 | + apiAccessLog.setResultMsg(StrUtils.maxLength(apiAccessLog.getResultMsg(), RESULT_MSG_MAX_LENGTH)); | ||
| 40 | if (TenantContextHolder.getTenantId() != null) { | 40 | if (TenantContextHolder.getTenantId() != null) { |
| 41 | apiAccessLogMapper.insert(apiAccessLog); | 41 | apiAccessLogMapper.insert(apiAccessLog); |
| 42 | } else { | 42 | } else { |
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/logger/ApiErrorLogServiceImpl.java
| 1 | package cn.iocoder.yudao.module.infra.service.logger; | 1 | package cn.iocoder.yudao.module.infra.service.logger; |
| 2 | 2 | ||
| 3 | -import cn.hutool.core.util.StrUtil; | ||
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 4 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 5 | +import cn.iocoder.yudao.framework.common.util.string.StrUtils; | ||
| 6 | import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; | 6 | import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; |
| 7 | import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | 7 | import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; |
| 8 | import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO; | 8 | import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO; |
| @@ -39,7 +39,7 @@ public class ApiErrorLogServiceImpl implements ApiErrorLogService { | @@ -39,7 +39,7 @@ public class ApiErrorLogServiceImpl implements ApiErrorLogService { | ||
| 39 | public void createApiErrorLog(ApiErrorLogCreateReqDTO createDTO) { | 39 | public void createApiErrorLog(ApiErrorLogCreateReqDTO createDTO) { |
| 40 | ApiErrorLogDO apiErrorLog = BeanUtils.toBean(createDTO, ApiErrorLogDO.class) | 40 | ApiErrorLogDO apiErrorLog = BeanUtils.toBean(createDTO, ApiErrorLogDO.class) |
| 41 | .setProcessStatus(ApiErrorLogProcessStatusEnum.INIT.getStatus()); | 41 | .setProcessStatus(ApiErrorLogProcessStatusEnum.INIT.getStatus()); |
| 42 | - apiErrorLog.setRequestParams(StrUtil.maxLength(apiErrorLog.getRequestParams(), REQUEST_PARAMS_MAX_LENGTH)); | 42 | + apiErrorLog.setRequestParams(StrUtils.maxLength(apiErrorLog.getRequestParams(), REQUEST_PARAMS_MAX_LENGTH)); |
| 43 | if (TenantContextHolder.getTenantId() != null) { | 43 | if (TenantContextHolder.getTenantId() != null) { |
| 44 | apiErrorLogMapper.insert(apiErrorLog); | 44 | apiErrorLogMapper.insert(apiErrorLog); |
| 45 | } else { | 45 | } else { |