Commit 942f51dd594cb8c399bb871e1f5b7181f6c57e99
Merge branch 'develop' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into master-jdk17
Showing
19 changed files
with
248 additions
and
122 deletions
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java
| @@ -73,7 +73,7 @@ public class BpmApprovalDetailRespVO { | @@ -73,7 +73,7 @@ public class BpmApprovalDetailRespVO { | ||
| 73 | private List<UserSimpleBaseVO> candidateUsers; // 只包含未生成 ApprovalTaskInfo 的用户列表 | 73 | private List<UserSimpleBaseVO> candidateUsers; // 只包含未生成 ApprovalTaskInfo 的用户列表 |
| 74 | 74 | ||
| 75 | @Schema(description = "流程编号", example = "8761d8e0-0922-11f0-bd37-00ff1db677bf") | 75 | @Schema(description = "流程编号", example = "8761d8e0-0922-11f0-bd37-00ff1db677bf") |
| 76 | - private String processInstanceId; // 当且仅当,该节点是子流程节点时,才会有值(CallActivity 的 processInstanceId 字段) | 76 | + private String processInstanceId; // 当且仅当,该节点是子流程节点时,才会有值(CallActivity 的 calledProcessInstanceId 字段) |
| 77 | 77 | ||
| 78 | } | 78 | } |
| 79 | 79 |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java
| @@ -74,6 +74,7 @@ public interface ErrorCodeConstants { | @@ -74,6 +74,7 @@ public interface ErrorCodeConstants { | ||
| 74 | ErrorCode CATEGORY_NOT_EXISTS = new ErrorCode(1_009_012_000, "流程分类不存在"); | 74 | ErrorCode CATEGORY_NOT_EXISTS = new ErrorCode(1_009_012_000, "流程分类不存在"); |
| 75 | ErrorCode CATEGORY_NAME_DUPLICATE = new ErrorCode(1_009_012_001, "流程分类名字【{}】重复"); | 75 | ErrorCode CATEGORY_NAME_DUPLICATE = new ErrorCode(1_009_012_001, "流程分类名字【{}】重复"); |
| 76 | ErrorCode CATEGORY_CODE_DUPLICATE = new ErrorCode(1_009_012_002, "流程分类编码【{}】重复"); | 76 | ErrorCode CATEGORY_CODE_DUPLICATE = new ErrorCode(1_009_012_002, "流程分类编码【{}】重复"); |
| 77 | + ErrorCode CATEGORY_DELETE_FAIL_MODEL_USED = new ErrorCode(1_009_012_003, "删除失败,流程分类【{}】已被流程模型使用,请先删除对应的流程模型"); | ||
| 77 | 78 | ||
| 78 | // ========== BPM 流程监听器 1-009-013-000 ========== | 79 | // ========== BPM 流程监听器 1-009-013-000 ========== |
| 79 | ErrorCode PROCESS_LISTENER_NOT_EXISTS = new ErrorCode(1_009_013_000, "流程监听器不存在"); | 80 | ErrorCode PROCESS_LISTENER_NOT_EXISTS = new ErrorCode(1_009_013_000, "流程监听器不存在"); |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmSimpleModelNodeTypeEnum.java
| @@ -35,7 +35,7 @@ public enum BpmSimpleModelNodeTypeEnum implements ArrayValuable<Integer> { | @@ -35,7 +35,7 @@ public enum BpmSimpleModelNodeTypeEnum implements ArrayValuable<Integer> { | ||
| 35 | // 50 ~ 条件分支 | 35 | // 50 ~ 条件分支 |
| 36 | CONDITION_NODE(50, "条件", "sequenceFlow"), // 用于构建流转条件的表达式 | 36 | CONDITION_NODE(50, "条件", "sequenceFlow"), // 用于构建流转条件的表达式 |
| 37 | CONDITION_BRANCH_NODE(51, "条件分支", "exclusiveGateway"), | 37 | CONDITION_BRANCH_NODE(51, "条件分支", "exclusiveGateway"), |
| 38 | - PARALLEL_BRANCH_NODE(52, "并行分支", "parallelGateway"), | 38 | + PARALLEL_BRANCH_NODE(52, "并行分支", "inclusiveGateway"), // 并行分支使用包容网关实现,条件表达式结果设置为 true |
| 39 | INCLUSIVE_BRANCH_NODE(53, "包容分支", "inclusiveGateway"), | 39 | INCLUSIVE_BRANCH_NODE(53, "包容分支", "inclusiveGateway"), |
| 40 | ROUTER_BRANCH_NODE(54, "路由分支", "exclusiveGateway") | 40 | ROUTER_BRANCH_NODE(54, "路由分支", "exclusiveGateway") |
| 41 | ; | 41 | ; |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java
| @@ -18,10 +18,7 @@ import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | @@ -18,10 +18,7 @@ import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | ||
| 18 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | 18 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| 19 | import com.google.common.annotations.VisibleForTesting; | 19 | import com.google.common.annotations.VisibleForTesting; |
| 20 | import lombok.extern.slf4j.Slf4j; | 20 | import lombok.extern.slf4j.Slf4j; |
| 21 | -import org.flowable.bpmn.model.BpmnModel; | ||
| 22 | -import org.flowable.bpmn.model.CallActivity; | ||
| 23 | -import org.flowable.bpmn.model.FlowElement; | ||
| 24 | -import org.flowable.bpmn.model.UserTask; | 21 | +import org.flowable.bpmn.model.*; |
| 25 | import org.flowable.engine.delegate.DelegateExecution; | 22 | import org.flowable.engine.delegate.DelegateExecution; |
| 26 | import org.flowable.engine.runtime.ProcessInstance; | 23 | import org.flowable.engine.runtime.ProcessInstance; |
| 27 | 24 | ||
| @@ -132,7 +129,7 @@ public class BpmTaskCandidateInvoker { | @@ -132,7 +129,7 @@ public class BpmTaskCandidateInvoker { | ||
| 132 | Long startUserId, String processDefinitionId, Map<String, Object> processVariables) { | 129 | Long startUserId, String processDefinitionId, Map<String, Object> processVariables) { |
| 133 | // 如果是 CallActivity 子流程,不进行计算候选人 | 130 | // 如果是 CallActivity 子流程,不进行计算候选人 |
| 134 | FlowElement flowElement = BpmnModelUtils.getFlowElementById(bpmnModel, activityId); | 131 | FlowElement flowElement = BpmnModelUtils.getFlowElementById(bpmnModel, activityId); |
| 135 | - if (flowElement instanceof CallActivity) { | 132 | + if (flowElement instanceof CallActivity || flowElement instanceof SubProcess) { |
| 136 | return new HashSet<>(); | 133 | return new HashSet<>(); |
| 137 | } | 134 | } |
| 138 | // 审批类型非人工审核时,不进行计算候选人。原因是:后续会自动通过、不通过 | 135 | // 审批类型非人工审核时,不进行计算候选人。原因是:后续会自动通过、不通过 |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java
| @@ -24,6 +24,7 @@ import static java.util.Collections.emptySet; | @@ -24,6 +24,7 @@ import static java.util.Collections.emptySet; | ||
| 24 | * @author 芋道源码 | 24 | * @author 芋道源码 |
| 25 | */ | 25 | */ |
| 26 | @Component | 26 | @Component |
| 27 | +@Deprecated // 仅仅是表达式的示例,建议使用 BpmTaskCandidateStartUserDeptLeaderStrategy 替代 | ||
| 27 | public class BpmTaskAssignLeaderExpression { | 28 | public class BpmTaskAssignLeaderExpression { |
| 28 | 29 | ||
| 29 | @Resource | 30 | @Resource |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java
| @@ -16,6 +16,7 @@ import java.util.Set; | @@ -16,6 +16,7 @@ import java.util.Set; | ||
| 16 | * @author 芋道源码 | 16 | * @author 芋道源码 |
| 17 | */ | 17 | */ |
| 18 | @Component | 18 | @Component |
| 19 | +@Deprecated // 仅仅是表达式的示例,建议使用 BpmTaskCandidateStartUserStrategy 替代 | ||
| 19 | public class BpmTaskAssignStartUserExpression { | 20 | public class BpmTaskAssignStartUserExpression { |
| 20 | 21 | ||
| 21 | @Resource | 22 | @Resource |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/other/BpmTaskCandidateExpressionStrategy.java
| @@ -8,6 +8,7 @@ import com.google.common.collect.Sets; | @@ -8,6 +8,7 @@ import com.google.common.collect.Sets; | ||
| 8 | import lombok.extern.slf4j.Slf4j; | 8 | import lombok.extern.slf4j.Slf4j; |
| 9 | import org.flowable.bpmn.model.BpmnModel; | 9 | import org.flowable.bpmn.model.BpmnModel; |
| 10 | import org.flowable.common.engine.api.FlowableException; | 10 | import org.flowable.common.engine.api.FlowableException; |
| 11 | +import org.flowable.common.engine.impl.javax.el.PropertyNotFoundException; | ||
| 11 | import org.flowable.engine.delegate.DelegateExecution; | 12 | import org.flowable.engine.delegate.DelegateExecution; |
| 12 | import org.springframework.stereotype.Component; | 13 | import org.springframework.stereotype.Component; |
| 13 | 14 | ||
| @@ -48,10 +49,12 @@ public class BpmTaskCandidateExpressionStrategy implements BpmTaskCandidateStrat | @@ -48,10 +49,12 @@ public class BpmTaskCandidateExpressionStrategy implements BpmTaskCandidateStrat | ||
| 48 | Object result = FlowableUtils.getExpressionValue(variables, param); | 49 | Object result = FlowableUtils.getExpressionValue(variables, param); |
| 49 | return CollectionUtils.toLinkedHashSet(Long.class, result); | 50 | return CollectionUtils.toLinkedHashSet(Long.class, result); |
| 50 | } catch (FlowableException ex) { | 51 | } catch (FlowableException ex) { |
| 51 | - // 预测未运行的节点时候,表达式如果包含 execution 或者不存在的流程变量会抛异常, | ||
| 52 | - log.warn("[calculateUsersByActivity][表达式({}) 变量({}) 解析报错", param, variables, ex); | ||
| 53 | - // 不能预测候选人,返回空列表, 避免流程无法进行 | ||
| 54 | - return Sets.newHashSet(); | 52 | + // 预测未运行的节点时候,表达式如果包含 execution 或者不存在的流程变量会抛异常,此时忽略该异常!相当于说,不做流程预测!!! |
| 53 | + if (ex.getCause() != null && ex.getCause() instanceof PropertyNotFoundException) { | ||
| 54 | + return Sets.newHashSet(); | ||
| 55 | + } | ||
| 56 | + log.error("[calculateUsersByActivity][表达式({}) 变量({}) 解析报错", param, variables, ex); | ||
| 57 | + throw ex; | ||
| 55 | } | 58 | } |
| 56 | } | 59 | } |
| 57 | 60 |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmProcessInstanceEventListener.java
| 1 | package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener; | 1 | package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; | ||
| 3 | import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; | 4 | import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; |
| 4 | import com.google.common.collect.ImmutableSet; | 5 | import com.google.common.collect.ImmutableSet; |
| 5 | import jakarta.annotation.Resource; | 6 | import jakarta.annotation.Resource; |
| @@ -37,18 +38,26 @@ public class BpmProcessInstanceEventListener extends AbstractFlowableEngineEvent | @@ -37,18 +38,26 @@ public class BpmProcessInstanceEventListener extends AbstractFlowableEngineEvent | ||
| 37 | 38 | ||
| 38 | @Override | 39 | @Override |
| 39 | protected void processCreated(FlowableEngineEntityEvent event) { | 40 | protected void processCreated(FlowableEngineEntityEvent event) { |
| 40 | - processInstanceService.processProcessInstanceCreated((ProcessInstance)event.getEntity()); | 41 | + ProcessInstance processInstance = (ProcessInstance) event.getEntity(); |
| 42 | + FlowableUtils.execute(processInstance.getTenantId(), | ||
| 43 | + () -> processInstanceService.processProcessInstanceCreated(processInstance)); | ||
| 41 | } | 44 | } |
| 42 | 45 | ||
| 43 | @Override | 46 | @Override |
| 44 | protected void processCompleted(FlowableEngineEntityEvent event) { | 47 | protected void processCompleted(FlowableEngineEntityEvent event) { |
| 45 | - processInstanceService.processProcessInstanceCompleted((ProcessInstance)event.getEntity()); | 48 | + ProcessInstance processInstance = (ProcessInstance) event.getEntity(); |
| 49 | + FlowableUtils.execute(processInstance.getTenantId(), | ||
| 50 | + () -> processInstanceService.processProcessInstanceCompleted(processInstance)); | ||
| 46 | } | 51 | } |
| 47 | 52 | ||
| 48 | - @Override // 特殊情况:当跳转到 EndEvent 流程实例未结束, 会执行 deleteProcessInstance 方法 | 53 | + @Override |
| 49 | protected void processCancelled(FlowableCancelledEvent event) { | 54 | protected void processCancelled(FlowableCancelledEvent event) { |
| 55 | + // 特殊情况:当跳转到 EndEvent 流程实例未结束, 会执行 deleteProcessInstance 方法 | ||
| 50 | ProcessInstance processInstance = processInstanceService.getProcessInstance(event.getProcessInstanceId()); | 56 | ProcessInstance processInstance = processInstanceService.getProcessInstance(event.getProcessInstanceId()); |
| 51 | - processInstanceService.processProcessInstanceCompleted(processInstance); | 57 | + if (processInstance != null) { |
| 58 | + FlowableUtils.execute(processInstance.getTenantId(), | ||
| 59 | + () -> processInstanceService.processProcessInstanceCompleted(processInstance)); | ||
| 60 | + } | ||
| 52 | } | 61 | } |
| 53 | 62 | ||
| 54 | } | 63 | } |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java
| @@ -3,10 +3,12 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener; | @@ -3,10 +3,12 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener; | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.core.util.ObjectUtil; | 4 | import cn.hutool.core.util.ObjectUtil; |
| 5 | import cn.hutool.core.util.StrUtil; | 5 | import cn.hutool.core.util.StrUtil; |
| 6 | +import cn.hutool.json.JSONObject; | ||
| 6 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | 7 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 7 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventTypeEnum; | 8 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventTypeEnum; |
| 8 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; | 9 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; |
| 9 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; | 10 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; |
| 11 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; | ||
| 10 | import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; | 12 | import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; |
| 11 | import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; | 13 | import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; |
| 12 | import com.google.common.collect.ImmutableSet; | 14 | import com.google.common.collect.ImmutableSet; |
| @@ -58,17 +60,20 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { | @@ -58,17 +60,20 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { | ||
| 58 | 60 | ||
| 59 | @Override | 61 | @Override |
| 60 | protected void taskCreated(FlowableEngineEntityEvent event) { | 62 | protected void taskCreated(FlowableEngineEntityEvent event) { |
| 61 | - taskService.processTaskCreated((Task) event.getEntity()); | 63 | + Task entity = (Task) event.getEntity(); |
| 64 | + FlowableUtils.execute(entity.getTenantId(), () -> taskService.processTaskCreated(entity)); | ||
| 62 | } | 65 | } |
| 63 | 66 | ||
| 64 | @Override | 67 | @Override |
| 65 | protected void taskAssigned(FlowableEngineEntityEvent event) { | 68 | protected void taskAssigned(FlowableEngineEntityEvent event) { |
| 66 | - taskService.processTaskAssigned((Task) event.getEntity()); | 69 | + Task entity = (Task) event.getEntity(); |
| 70 | + FlowableUtils.execute(entity.getTenantId(), () -> taskService.processTaskAssigned(entity)); | ||
| 67 | } | 71 | } |
| 68 | 72 | ||
| 69 | @Override | 73 | @Override |
| 70 | protected void taskCompleted(FlowableEngineEntityEvent event) { | 74 | protected void taskCompleted(FlowableEngineEntityEvent event) { |
| 71 | - taskService.processTaskCompleted((Task) event.getEntity()); | 75 | + Task entity = (Task) event.getEntity(); |
| 76 | + FlowableUtils.execute(entity.getTenantId(), () -> taskService.processTaskCompleted(entity)); | ||
| 72 | } | 77 | } |
| 73 | 78 | ||
| 74 | @Override | 79 | @Override |
| @@ -94,6 +99,23 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { | @@ -94,6 +99,23 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { | ||
| 94 | String processDefinitionId = event.getProcessDefinitionId(); | 99 | String processDefinitionId = event.getProcessDefinitionId(); |
| 95 | BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processDefinitionId); | 100 | BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processDefinitionId); |
| 96 | Job entity = (Job) event.getEntity(); | 101 | Job entity = (Job) event.getEntity(); |
| 102 | + // 特殊 from https://t.zsxq.com/h6oWr :当 elementId 为空时,尝试从 JobHandlerConfiguration 中解析 JSON 获取 | ||
| 103 | + String elementId = entity.getElementId(); | ||
| 104 | + if (elementId == null && entity.getJobHandlerConfiguration() != null) { | ||
| 105 | + try { | ||
| 106 | + String handlerConfig = entity.getJobHandlerConfiguration(); | ||
| 107 | + if (handlerConfig.startsWith("{") && handlerConfig.contains("activityId")) { | ||
| 108 | + elementId = new JSONObject(handlerConfig).getStr("activityId"); | ||
| 109 | + } | ||
| 110 | + } catch (Exception e) { | ||
| 111 | + log.error("[timerFired][解析 entity({}) 失败]", entity, e); | ||
| 112 | + return; | ||
| 113 | + } | ||
| 114 | + } | ||
| 115 | + if (elementId == null) { | ||
| 116 | + log.error("[timerFired][解析 entity({}) elementId 为空,跳过处理]", entity); | ||
| 117 | + return; | ||
| 118 | + } | ||
| 97 | FlowElement element = BpmnModelUtils.getFlowElementById(bpmnModel, entity.getElementId()); | 119 | FlowElement element = BpmnModelUtils.getFlowElementById(bpmnModel, entity.getElementId()); |
| 98 | if (!(element instanceof BoundaryEvent)) { | 120 | if (!(element instanceof BoundaryEvent)) { |
| 99 | return; | 121 | return; |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmHttpRequestUtils.java
| @@ -108,7 +108,9 @@ public class BpmHttpRequestUtils { | @@ -108,7 +108,9 @@ public class BpmHttpRequestUtils { | ||
| 108 | Map<String, Object> processVariables = processInstance.getProcessVariables(); | 108 | Map<String, Object> processVariables = processInstance.getProcessVariables(); |
| 109 | MultiValueMap<String, String> body = new LinkedMultiValueMap<>(); | 109 | MultiValueMap<String, String> body = new LinkedMultiValueMap<>(); |
| 110 | addHttpRequestParam(body, bodySettings, processVariables); | 110 | addHttpRequestParam(body, bodySettings, processVariables); |
| 111 | - body.add("processInstanceId", processInstance.getId()); | 111 | + if (!body.containsKey("processInstanceId")) { // 避免重复添加 |
| 112 | + body.add("processInstanceId", processInstance.getId()); | ||
| 113 | + } | ||
| 112 | return body; | 114 | return body; |
| 113 | } | 115 | } |
| 114 | 116 |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
| @@ -478,7 +478,11 @@ public class BpmnModelUtils { | @@ -478,7 +478,11 @@ public class BpmnModelUtils { | ||
| 478 | */ | 478 | */ |
| 479 | public static FlowElement getFlowElementById(BpmnModel model, String flowElementId) { | 479 | public static FlowElement getFlowElementById(BpmnModel model, String flowElementId) { |
| 480 | Process process = model.getMainProcess(); | 480 | Process process = model.getMainProcess(); |
| 481 | - return process.getFlowElement(flowElementId); | 481 | + FlowElement flowElement = process.getFlowElement(flowElementId); |
| 482 | + if (flowElement != null) { | ||
| 483 | + return flowElement; | ||
| 484 | + } | ||
| 485 | + return model.getFlowElement(flowElementId); | ||
| 482 | } | 486 | } |
| 483 | 487 | ||
| 484 | /** | 488 | /** |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
| @@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil; | @@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil; | ||
| 4 | import cn.hutool.core.lang.Assert; | 4 | 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; | ||
| 8 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | 7 | 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; |
| @@ -17,13 +16,14 @@ import cn.iocoder.yudao.module.bpm.service.task.listener.BpmCallActivityListener | @@ -17,13 +16,14 @@ import cn.iocoder.yudao.module.bpm.service.task.listener.BpmCallActivityListener | ||
| 17 | import cn.iocoder.yudao.module.bpm.service.task.listener.BpmUserTaskListener; | 16 | import cn.iocoder.yudao.module.bpm.service.task.listener.BpmUserTaskListener; |
| 18 | import org.flowable.bpmn.BpmnAutoLayout; | 17 | import org.flowable.bpmn.BpmnAutoLayout; |
| 19 | import org.flowable.bpmn.constants.BpmnXMLConstants; | 18 | import org.flowable.bpmn.constants.BpmnXMLConstants; |
| 20 | -import org.flowable.bpmn.model.Process; | ||
| 21 | import org.flowable.bpmn.model.*; | 19 | import org.flowable.bpmn.model.*; |
| 20 | +import org.flowable.bpmn.model.Process; | ||
| 22 | import org.flowable.engine.delegate.ExecutionListener; | 21 | import org.flowable.engine.delegate.ExecutionListener; |
| 23 | import org.flowable.engine.delegate.TaskListener; | 22 | import org.flowable.engine.delegate.TaskListener; |
| 24 | 23 | ||
| 25 | import java.util.*; | 24 | import java.util.*; |
| 26 | 25 | ||
| 26 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | ||
| 27 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*; | 27 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*; |
| 28 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.*; | 28 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.*; |
| 29 | import static java.util.Arrays.asList; | 29 | import static java.util.Arrays.asList; |
| @@ -239,13 +239,13 @@ public class SimpleModelUtils { | @@ -239,13 +239,13 @@ public class SimpleModelUtils { | ||
| 239 | // 3.1 分支有后续节点。即分支 1: A->B->C->D 的情况 | 239 | // 3.1 分支有后续节点。即分支 1: A->B->C->D 的情况 |
| 240 | if (isValidNode(conditionChildNode)) { | 240 | if (isValidNode(conditionChildNode)) { |
| 241 | // 3.1.1 建立与后续的节点的连线。例如说,建立 A->B 的连线 | 241 | // 3.1.1 建立与后续的节点的连线。例如说,建立 A->B 的连线 |
| 242 | - SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), conditionChildNode.getId(), item); | 242 | + SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), conditionChildNode.getId(), nodeType, item); |
| 243 | process.addFlowElement(sequenceFlow); | 243 | process.addFlowElement(sequenceFlow); |
| 244 | // 3.1.2 递归调用后续节点连线。例如说,建立 B->C->D 的连线 | 244 | // 3.1.2 递归调用后续节点连线。例如说,建立 B->C->D 的连线 |
| 245 | traverseNodeToBuildSequenceFlow(process, conditionChildNode, branchEndNodeId); | 245 | traverseNodeToBuildSequenceFlow(process, conditionChildNode, branchEndNodeId); |
| 246 | } else { | 246 | } else { |
| 247 | // 3.2 分支没有后续节点。例如说,建立 A->D 的连线 | 247 | // 3.2 分支没有后续节点。例如说,建立 A->D 的连线 |
| 248 | - SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), branchEndNodeId, item); | 248 | + SequenceFlow sequenceFlow = ConditionNodeConvert.buildSequenceFlow(node.getId(), branchEndNodeId, nodeType, item); |
| 249 | process.addFlowElement(sequenceFlow); | 249 | process.addFlowElement(sequenceFlow); |
| 250 | } | 250 | } |
| 251 | } | 251 | } |
| @@ -591,17 +591,23 @@ public class SimpleModelUtils { | @@ -591,17 +591,23 @@ public class SimpleModelUtils { | ||
| 591 | 591 | ||
| 592 | private static class ParallelBranchNodeConvert implements NodeConvert { | 592 | private static class ParallelBranchNodeConvert implements NodeConvert { |
| 593 | 593 | ||
| 594 | + /** | ||
| 595 | + * 并行分支使用包容网关。需要设置所有出口条件表达式的值为 true 。原因是,解决 https://t.zsxq.com/m6GXh 反馈问题 | ||
| 596 | + * | ||
| 597 | + * @see {@link ConditionNodeConvert#buildSequenceFlow} | ||
| 598 | + */ | ||
| 594 | @Override | 599 | @Override |
| 595 | - public List<ParallelGateway> convertList(BpmSimpleModelNodeVO node) { | ||
| 596 | - ParallelGateway parallelGateway = new ParallelGateway(); | ||
| 597 | - parallelGateway.setId(node.getId()); | 600 | + public List<InclusiveGateway> convertList(BpmSimpleModelNodeVO node) { |
| 601 | + | ||
| 602 | + InclusiveGateway inclusiveGateway = new InclusiveGateway(); | ||
| 603 | + inclusiveGateway.setId(node.getId()); | ||
| 598 | // TODO @jason:setName | 604 | // TODO @jason:setName |
| 599 | 605 | ||
| 600 | - // 并行聚合网关由程序创建,前端不需要传入 | ||
| 601 | - ParallelGateway joinParallelGateway = new ParallelGateway(); | 606 | + // 合并网关 由程序创建,前端不需要传入 |
| 607 | + InclusiveGateway joinParallelGateway = new InclusiveGateway(); | ||
| 602 | joinParallelGateway.setId(buildGatewayJoinId(node.getId())); | 608 | joinParallelGateway.setId(buildGatewayJoinId(node.getId())); |
| 603 | // TODO @jason:setName | 609 | // TODO @jason:setName |
| 604 | - return CollUtil.newArrayList(parallelGateway, joinParallelGateway); | 610 | + return CollUtil.newArrayList(inclusiveGateway, joinParallelGateway); |
| 605 | } | 611 | } |
| 606 | 612 | ||
| 607 | @Override | 613 | @Override |
| @@ -652,8 +658,14 @@ public class SimpleModelUtils { | @@ -652,8 +658,14 @@ public class SimpleModelUtils { | ||
| 652 | } | 658 | } |
| 653 | 659 | ||
| 654 | public static SequenceFlow buildSequenceFlow(String sourceId, String targetId, | 660 | public static SequenceFlow buildSequenceFlow(String sourceId, String targetId, |
| 655 | - BpmSimpleModelNodeVO node) { | ||
| 656 | - String conditionExpression = buildConditionExpression(node.getConditionSetting()); | 661 | + BpmSimpleModelNodeTypeEnum nodeType, BpmSimpleModelNodeVO node) { |
| 662 | + String conditionExpression; | ||
| 663 | + // 并行分支,使用包容网关实现,强制设置条件表达式为 true | ||
| 664 | + if (BpmSimpleModelNodeTypeEnum.PARALLEL_BRANCH_NODE == nodeType) { | ||
| 665 | + conditionExpression ="${true}"; | ||
| 666 | + } else { | ||
| 667 | + conditionExpression = buildConditionExpression(node.getConditionSetting()); | ||
| 668 | + } | ||
| 657 | return buildBpmnSequenceFlow(sourceId, targetId, node.getId(), node.getName(), conditionExpression); | 669 | return buildBpmnSequenceFlow(sourceId, targetId, node.getId(), node.getName(), conditionExpression); |
| 658 | } | 670 | } |
| 659 | } | 671 | } |
| @@ -662,7 +674,6 @@ public class SimpleModelUtils { | @@ -662,7 +674,6 @@ public class SimpleModelUtils { | ||
| 662 | * 构造条件表达式 | 674 | * 构造条件表达式 |
| 663 | */ | 675 | */ |
| 664 | public static String buildConditionExpression(BpmSimpleModelNodeVO.ConditionSetting conditionSetting) { | 676 | public static String buildConditionExpression(BpmSimpleModelNodeVO.ConditionSetting conditionSetting) { |
| 665 | - // 并行网关不需要设置条件 | ||
| 666 | if (conditionSetting == null) { | 677 | if (conditionSetting == null) { |
| 667 | return null; | 678 | return null; |
| 668 | } | 679 | } |
| @@ -684,15 +695,18 @@ public class SimpleModelUtils { | @@ -684,15 +695,18 @@ public class SimpleModelUtils { | ||
| 684 | if (conditionGroups == null || CollUtil.isEmpty(conditionGroups.getConditions())) { | 695 | if (conditionGroups == null || CollUtil.isEmpty(conditionGroups.getConditions())) { |
| 685 | return null; | 696 | return null; |
| 686 | } | 697 | } |
| 687 | - List<String> strConditionGroups = CollectionUtils.convertList(conditionGroups.getConditions(), item -> { | 698 | + List<String> strConditionGroups = convertList(conditionGroups.getConditions(), item -> { |
| 688 | if (CollUtil.isEmpty(item.getRules())) { | 699 | if (CollUtil.isEmpty(item.getRules())) { |
| 689 | return ""; | 700 | return ""; |
| 690 | } | 701 | } |
| 691 | // 构造规则表达式 | 702 | // 构造规则表达式 |
| 692 | - List<String> list = CollectionUtils.convertList(item.getRules(), (rule) -> { | 703 | + List<String> list = convertList(item.getRules(), (rule) -> { |
| 693 | String rightSide = NumberUtil.isNumber(rule.getRightSide()) ? rule.getRightSide() | 704 | String rightSide = NumberUtil.isNumber(rule.getRightSide()) ? rule.getRightSide() |
| 694 | : "\"" + rule.getRightSide() + "\""; // 如果非数值类型加引号 | 705 | : "\"" + rule.getRightSide() + "\""; // 如果非数值类型加引号 |
| 695 | - return String.format(" %s %s var:convertByType(%s,%s)", rule.getLeftSide(), rule.getOpCode(), rule.getLeftSide(), rightSide); | 706 | + return String.format(" vars:getOrDefault(%s, null) %s var:convertByType(%s,%s) ", |
| 707 | + rule.getLeftSide(), // 左侧:读取变量 | ||
| 708 | + rule.getOpCode(), // 中间:操作符,比较 | ||
| 709 | + rule.getLeftSide(), rightSide); // 右侧:转换变量,VariableConvertByTypeExpressionFunction | ||
| 696 | }); | 710 | }); |
| 697 | // 构造条件组的表达式 | 711 | // 构造条件组的表达式 |
| 698 | Boolean and = item.getAnd(); | 712 | Boolean and = item.getAnd(); |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmCategoryServiceImpl.java
| @@ -34,6 +34,9 @@ public class BpmCategoryServiceImpl implements BpmCategoryService { | @@ -34,6 +34,9 @@ public class BpmCategoryServiceImpl implements BpmCategoryService { | ||
| 34 | @Resource | 34 | @Resource |
| 35 | private BpmCategoryMapper bpmCategoryMapper; | 35 | private BpmCategoryMapper bpmCategoryMapper; |
| 36 | 36 | ||
| 37 | + @Resource | ||
| 38 | + private BpmModelService modelService; | ||
| 39 | + | ||
| 37 | @Override | 40 | @Override |
| 38 | public Long createCategory(BpmCategorySaveReqVO createReqVO) { | 41 | public Long createCategory(BpmCategorySaveReqVO createReqVO) { |
| 39 | // 校验唯一 | 42 | // 校验唯一 |
| @@ -77,15 +80,22 @@ public class BpmCategoryServiceImpl implements BpmCategoryService { | @@ -77,15 +80,22 @@ public class BpmCategoryServiceImpl implements BpmCategoryService { | ||
| 77 | @Override | 80 | @Override |
| 78 | public void deleteCategory(Long id) { | 81 | public void deleteCategory(Long id) { |
| 79 | // 校验存在 | 82 | // 校验存在 |
| 80 | - validateCategoryExists(id); | 83 | + BpmCategoryDO category = validateCategoryExists(id); |
| 84 | + // 校验是否被流程模型使用 | ||
| 85 | + Long count = modelService.getModelCountByCategory(category.getCode()); | ||
| 86 | + if (count > 0) { | ||
| 87 | + throw exception(CATEGORY_DELETE_FAIL_MODEL_USED, category.getName()); | ||
| 88 | + } | ||
| 81 | // 删除 | 89 | // 删除 |
| 82 | bpmCategoryMapper.deleteById(id); | 90 | bpmCategoryMapper.deleteById(id); |
| 83 | } | 91 | } |
| 84 | 92 | ||
| 85 | - private void validateCategoryExists(Long id) { | ||
| 86 | - if (bpmCategoryMapper.selectById(id) == null) { | 93 | + private BpmCategoryDO validateCategoryExists(Long id) { |
| 94 | + BpmCategoryDO category = bpmCategoryMapper.selectById(id); | ||
| 95 | + if (category == null) { | ||
| 87 | throw exception(CATEGORY_NOT_EXISTS); | 96 | throw exception(CATEGORY_NOT_EXISTS); |
| 88 | } | 97 | } |
| 98 | + return category; | ||
| 89 | } | 99 | } |
| 90 | 100 | ||
| 91 | @Override | 101 | @Override |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java
| @@ -25,6 +25,14 @@ public interface BpmModelService { | @@ -25,6 +25,14 @@ public interface BpmModelService { | ||
| 25 | List<Model> getModelList(String name); | 25 | List<Model> getModelList(String name); |
| 26 | 26 | ||
| 27 | /** | 27 | /** |
| 28 | + * 根据分类编码获得流程模型数量 | ||
| 29 | + * | ||
| 30 | + * @param category 分类编码 | ||
| 31 | + * @return 流程模型数量 | ||
| 32 | + */ | ||
| 33 | + Long getModelCountByCategory(String category); | ||
| 34 | + | ||
| 35 | + /** | ||
| 28 | * 创建流程模型 | 36 | * 创建流程模型 |
| 29 | * | 37 | * |
| 30 | * @param modelVO 创建信息 | 38 | * @param modelVO 创建信息 |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java
| @@ -89,6 +89,14 @@ public class BpmModelServiceImpl implements BpmModelService { | @@ -89,6 +89,14 @@ public class BpmModelServiceImpl implements BpmModelService { | ||
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | @Override | 91 | @Override |
| 92 | + public Long getModelCountByCategory(String category) { | ||
| 93 | + return repositoryService.createModelQuery() | ||
| 94 | + .modelCategory(category) | ||
| 95 | + .modelTenantId(FlowableUtils.getTenantId()) | ||
| 96 | + .count(); | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + @Override | ||
| 92 | @Transactional(rollbackFor = Exception.class) | 100 | @Transactional(rollbackFor = Exception.class) |
| 93 | public String createModel(@Valid BpmModelSaveReqVO createReqVO) { | 101 | public String createModel(@Valid BpmModelSaveReqVO createReqVO) { |
| 94 | if (!ValidationUtils.isXmlNCName(createReqVO.getKey())) { | 102 | if (!ValidationUtils.isXmlNCName(createReqVO.getKey())) { |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
| @@ -4,11 +4,9 @@ import cn.hutool.core.collection.CollUtil; | @@ -4,11 +4,9 @@ import cn.hutool.core.collection.CollUtil; | ||
| 4 | import cn.hutool.core.collection.ListUtil; | 4 | import cn.hutool.core.collection.ListUtil; |
| 5 | import cn.hutool.core.date.DateUtil; | 5 | import cn.hutool.core.date.DateUtil; |
| 6 | import cn.hutool.core.lang.Assert; | 6 | import cn.hutool.core.lang.Assert; |
| 7 | -import cn.hutool.core.util.ArrayUtil; | ||
| 8 | -import cn.hutool.core.util.ObjUtil; | ||
| 9 | -import cn.hutool.core.util.ObjectUtil; | ||
| 10 | -import cn.hutool.core.util.StrUtil; | 7 | +import cn.hutool.core.util.*; |
| 11 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 8 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 9 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 12 | import cn.iocoder.yudao.framework.common.util.date.DateUtils; | 10 | import cn.iocoder.yudao.framework.common.util.date.DateUtils; |
| 13 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | 11 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 14 | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | 12 | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; |
| @@ -61,12 +59,15 @@ import org.flowable.task.api.history.HistoricTaskInstance; | @@ -61,12 +59,15 @@ import org.flowable.task.api.history.HistoricTaskInstance; | ||
| 61 | import org.springframework.context.annotation.Lazy; | 59 | import org.springframework.context.annotation.Lazy; |
| 62 | import org.springframework.stereotype.Service; | 60 | import org.springframework.stereotype.Service; |
| 63 | import org.springframework.transaction.annotation.Transactional; | 61 | import org.springframework.transaction.annotation.Transactional; |
| 62 | +import org.springframework.transaction.support.TransactionSynchronization; | ||
| 63 | +import org.springframework.transaction.support.TransactionSynchronizationManager; | ||
| 64 | import org.springframework.validation.annotation.Validated; | 64 | import org.springframework.validation.annotation.Validated; |
| 65 | 65 | ||
| 66 | import java.util.*; | 66 | import java.util.*; |
| 67 | 67 | ||
| 68 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 68 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 69 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | 69 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 70 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | ||
| 70 | import static cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO.ActivityNode; | 71 | import static cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO.ActivityNode; |
| 71 | import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; | 72 | import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; |
| 72 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID; | 73 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID; |
| @@ -264,7 +265,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | @@ -264,7 +265,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | ||
| 264 | // 3. 获取下一个将要执行的节点集合 | 265 | // 3. 获取下一个将要执行的节点集合 |
| 265 | FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey()); | 266 | FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey()); |
| 266 | List<FlowNode> nextFlowNodes = BpmnModelUtils.getNextFlowNodes(flowElement, bpmnModel, processVariables); | 267 | List<FlowNode> nextFlowNodes = BpmnModelUtils.getNextFlowNodes(flowElement, bpmnModel, processVariables); |
| 267 | - List<ActivityNode> nextActivityNodes = convertList(nextFlowNodes, node -> new ActivityNode().setId(node.getId()) | 268 | + // 仅仅获取 UserTask 节点 TODO add from jason:如果网关节点和网关节点相连,获取下个 UserTask. 貌似有点不准。 |
| 269 | + List<FlowNode> nextUserTaskList = CollectionUtils.filterList(nextFlowNodes, node -> node instanceof UserTask); | ||
| 270 | + List<ActivityNode> nextActivityNodes = convertList(nextUserTaskList, node -> new ActivityNode().setId(node.getId()) | ||
| 268 | .setName(node.getName()).setNodeType(BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType()) | 271 | .setName(node.getName()).setNodeType(BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType()) |
| 269 | .setStatus(BpmTaskStatusEnum.RUNNING.getStatus()) | 272 | .setStatus(BpmTaskStatusEnum.RUNNING.getStatus()) |
| 270 | .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(node)) | 273 | .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(node)) |
| @@ -449,7 +452,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | @@ -449,7 +452,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | ||
| 449 | .setNodeType(BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType()).setStatus(processInstanceStatus) | 452 | .setNodeType(BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType()).setStatus(processInstanceStatus) |
| 450 | .setStartTime(DateUtils.of(activity.getStartTime())) | 453 | .setStartTime(DateUtils.of(activity.getStartTime())) |
| 451 | .setEndTime(DateUtils.of(activity.getEndTime())) | 454 | .setEndTime(DateUtils.of(activity.getEndTime())) |
| 452 | - .setProcessInstanceId(activity.getProcessInstanceId()); | 455 | + .setProcessInstanceId(activity.getCalledProcessInstanceId()); |
| 453 | approvalNodes.add(callActivity); | 456 | approvalNodes.add(callActivity); |
| 454 | } | 457 | } |
| 455 | }); | 458 | }); |
| @@ -521,7 +524,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | @@ -521,7 +524,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | ||
| 521 | activityNode.setCandidateUserIds(CollUtil.sub(candidateUserIds, index + 1, candidateUserIds.size())); | 524 | activityNode.setCandidateUserIds(CollUtil.sub(candidateUserIds, index + 1, candidateUserIds.size())); |
| 522 | } | 525 | } |
| 523 | if (BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType().equals(activityNode.getNodeType())) { | 526 | if (BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType().equals(activityNode.getNodeType())) { |
| 524 | - activityNode.setProcessInstanceId(firstActivity.getProcessInstanceId()); | 527 | + activityNode.setProcessInstanceId(firstActivity.getCalledProcessInstanceId()); |
| 525 | } | 528 | } |
| 526 | return activityNode; | 529 | return activityNode; |
| 527 | }); | 530 | }); |
| @@ -771,17 +774,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | @@ -771,17 +774,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | ||
| 771 | processInstanceBuilder.predefineProcessInstanceId(processIdRedisDAO.generate(processIdRule)); | 774 | processInstanceBuilder.predefineProcessInstanceId(processIdRedisDAO.generate(processIdRule)); |
| 772 | } | 775 | } |
| 773 | // 3.2 流程名称 | 776 | // 3.2 流程名称 |
| 774 | - BpmModelMetaInfoVO.TitleSetting titleSetting = processDefinitionInfo.getTitleSetting(); | ||
| 775 | - if (titleSetting != null && Boolean.TRUE.equals(titleSetting.getEnable())) { | ||
| 776 | - AdminUserRespDTO user = adminUserApi.getUser(userId); | ||
| 777 | - Map<String, Object> cloneVariables = new HashMap<>(variables); | ||
| 778 | - cloneVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, user.getNickname()); | ||
| 779 | - cloneVariables.put(BpmnVariableConstants.PROCESS_START_TIME, DateUtil.now()); | ||
| 780 | - cloneVariables.put(BpmnVariableConstants.PROCESS_DEFINITION_NAME, definition.getName().trim()); | ||
| 781 | - processInstanceBuilder.name(StrUtil.format(titleSetting.getTitle(), cloneVariables)); | ||
| 782 | - } else { | ||
| 783 | - processInstanceBuilder.name(definition.getName().trim()); | ||
| 784 | - } | 777 | + processInstanceBuilder.name(generateProcessInstanceName(userId, definition, processDefinitionInfo, variables)); |
| 785 | // 3.3 发起流程实例 | 778 | // 3.3 发起流程实例 |
| 786 | ProcessInstance instance = processInstanceBuilder.start(); | 779 | ProcessInstance instance = processInstanceBuilder.start(); |
| 787 | return instance.getId(); | 780 | return instance.getId(); |
| @@ -817,6 +810,25 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | @@ -817,6 +810,25 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | ||
| 817 | }); | 810 | }); |
| 818 | } | 811 | } |
| 819 | 812 | ||
| 813 | + private String generateProcessInstanceName(Long userId, | ||
| 814 | + ProcessDefinition definition, | ||
| 815 | + BpmProcessDefinitionInfoDO definitionInfo, | ||
| 816 | + Map<String, Object> variables) { | ||
| 817 | + if (definition == null || definitionInfo == null) { | ||
| 818 | + return null; | ||
| 819 | + } | ||
| 820 | + BpmModelMetaInfoVO.TitleSetting titleSetting = definitionInfo.getTitleSetting(); | ||
| 821 | + if (titleSetting == null || !BooleanUtil.isTrue(titleSetting.getEnable())) { | ||
| 822 | + return definition.getName(); | ||
| 823 | + } | ||
| 824 | + AdminUserRespDTO user = adminUserApi.getUser(userId); | ||
| 825 | + Map<String, Object> cloneVariables = new HashMap<>(variables); | ||
| 826 | + cloneVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, user.getNickname()); | ||
| 827 | + cloneVariables.put(BpmnVariableConstants.PROCESS_START_TIME, DateUtil.now()); | ||
| 828 | + cloneVariables.put(BpmnVariableConstants.PROCESS_DEFINITION_NAME, definition.getName().trim()); | ||
| 829 | + return StrUtil.format(definitionInfo.getTitleSetting().getTitle(), cloneVariables); | ||
| 830 | + } | ||
| 831 | + | ||
| 820 | @Override | 832 | @Override |
| 821 | public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { | 833 | public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { |
| 822 | // 1.1 校验流程实例存在 | 834 | // 1.1 校验流程实例存在 |
| @@ -833,7 +845,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | @@ -833,7 +845,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | ||
| 833 | .getProcessDefinitionInfo(instance.getProcessDefinitionId()); | 845 | .getProcessDefinitionInfo(instance.getProcessDefinitionId()); |
| 834 | Assert.notNull(processDefinitionInfo, "流程定义({})不存在", processDefinitionInfo); | 846 | Assert.notNull(processDefinitionInfo, "流程定义({})不存在", processDefinitionInfo); |
| 835 | if (processDefinitionInfo.getAllowCancelRunningProcess() != null // 防止未配置 AllowCancelRunningProcess , 默认为可取消 | 847 | if (processDefinitionInfo.getAllowCancelRunningProcess() != null // 防止未配置 AllowCancelRunningProcess , 默认为可取消 |
| 836 | - && Boolean.FALSE.equals(processDefinitionInfo.getAllowCancelRunningProcess())) { | 848 | + && BooleanUtil.isFalse(processDefinitionInfo.getAllowCancelRunningProcess())) { |
| 837 | throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_ALLOW); | 849 | throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_ALLOW); |
| 838 | } | 850 | } |
| 839 | // 1.4 子流程不允许取消 | 851 | // 1.4 子流程不允许取消 |
| @@ -900,64 +912,77 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | @@ -900,64 +912,77 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | ||
| 900 | 912 | ||
| 901 | @Override | 913 | @Override |
| 902 | public void processProcessInstanceCompleted(ProcessInstance instance) { | 914 | public void processProcessInstanceCompleted(ProcessInstance instance) { |
| 903 | - // 注意:需要基于 instance 设置租户编号,避免 Flowable 内部异步时,丢失租户编号 | ||
| 904 | - FlowableUtils.execute(instance.getTenantId(), () -> { | ||
| 905 | - // 1.1 获取当前状态 | ||
| 906 | - Integer status = (Integer) instance.getProcessVariables() | ||
| 907 | - .get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS); | ||
| 908 | - String reason = (String) instance.getProcessVariables() | ||
| 909 | - .get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON); | ||
| 910 | - // 1.2 当流程状态还是审批状态中,说明审批通过了,则变更下它的状态 | ||
| 911 | - // 为什么这么处理?因为流程完成,并且完成了,说明审批通过了 | ||
| 912 | - if (Objects.equals(status, BpmProcessInstanceStatusEnum.RUNNING.getStatus())) { | ||
| 913 | - status = BpmProcessInstanceStatusEnum.APPROVE.getStatus(); | ||
| 914 | - runtimeService.setVariable(instance.getId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, | ||
| 915 | - status); | ||
| 916 | - } | 915 | + // 1.1 获取当前状态 |
| 916 | + Integer status = (Integer) instance.getProcessVariables() | ||
| 917 | + .get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS); | ||
| 918 | + String reason = (String) instance.getProcessVariables() | ||
| 919 | + .get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON); | ||
| 920 | + // 1.2 当流程状态还是审批状态中,说明审批通过了,则变更下它的状态 | ||
| 921 | + // 为什么这么处理?因为流程完成,并且完成了,说明审批通过了 | ||
| 922 | + if (Objects.equals(status, BpmProcessInstanceStatusEnum.RUNNING.getStatus())) { | ||
| 923 | + status = BpmProcessInstanceStatusEnum.APPROVE.getStatus(); | ||
| 924 | + runtimeService.setVariable(instance.getId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, | ||
| 925 | + status); | ||
| 926 | + } | ||
| 927 | + | ||
| 928 | + // 2. 发送对应的消息通知 | ||
| 929 | + if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) { | ||
| 930 | + messageService.sendMessageWhenProcessInstanceApprove( | ||
| 931 | + BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance)); | ||
| 932 | + } else if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus())) { | ||
| 933 | + messageService.sendMessageWhenProcessInstanceReject( | ||
| 934 | + BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(instance, reason)); | ||
| 935 | + } | ||
| 936 | + | ||
| 937 | + // 3. 发送流程实例的状态事件 | ||
| 938 | + processInstanceEventPublisher.sendProcessInstanceResultEvent( | ||
| 939 | + BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status)); | ||
| 940 | + | ||
| 941 | + // 4. 流程后置通知 | ||
| 942 | + if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) { | ||
| 943 | + BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService. | ||
| 944 | + getProcessDefinitionInfo(instance.getProcessDefinitionId()); | ||
| 945 | + if (ObjUtil.isNotNull(processDefinitionInfo) && | ||
| 946 | + ObjUtil.isNotNull(processDefinitionInfo.getProcessAfterTriggerSetting())) { | ||
| 947 | + BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessAfterTriggerSetting(); | ||
| 917 | 948 | ||
| 918 | - // 2. 发送对应的消息通知 | ||
| 919 | - if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) { | ||
| 920 | - messageService.sendMessageWhenProcessInstanceApprove( | ||
| 921 | - BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance)); | ||
| 922 | - } else if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus())) { | ||
| 923 | - messageService.sendMessageWhenProcessInstanceReject( | ||
| 924 | - BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(instance, reason)); | 949 | + BpmHttpRequestUtils.executeBpmHttpRequest(instance, |
| 950 | + setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse()); | ||
| 925 | } | 951 | } |
| 952 | + } | ||
| 953 | + } | ||
| 926 | 954 | ||
| 927 | - // 3. 发送流程实例的状态事件 | ||
| 928 | - processInstanceEventPublisher.sendProcessInstanceResultEvent( | ||
| 929 | - BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status)); | 955 | + @Override |
| 956 | + public void processProcessInstanceCreated(ProcessInstance instance) { | ||
| 957 | + BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService. | ||
| 958 | + getProcessDefinitionInfo(instance.getProcessDefinitionId()); | ||
| 959 | + ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition(instance.getProcessDefinitionId()); | ||
| 960 | + if (processDefinition == null || processDefinitionInfo == null) { | ||
| 961 | + return; | ||
| 962 | + } | ||
| 930 | 963 | ||
| 931 | - // 4. 流程后置通知 | ||
| 932 | - if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) { | ||
| 933 | - BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService. | ||
| 934 | - getProcessDefinitionInfo(instance.getProcessDefinitionId()); | ||
| 935 | - if (ObjUtil.isNotNull(processDefinitionInfo) && | ||
| 936 | - ObjUtil.isNotNull(processDefinitionInfo.getProcessAfterTriggerSetting())) { | ||
| 937 | - BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessAfterTriggerSetting(); | 964 | + // 自定义标题。目的:主要处理子流程的标题无法处理 |
| 965 | + // 注意:必须使用 TransactionSynchronizationManager 事务提交后,否则不生效!!! | ||
| 966 | + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { | ||
| 938 | 967 | ||
| 939 | - BpmHttpRequestUtils.executeBpmHttpRequest(instance, | ||
| 940 | - setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse()); | 968 | + @Override |
| 969 | + public void afterCommit() { | ||
| 970 | + String name = generateProcessInstanceName(Long.valueOf(instance.getStartUserId()), | ||
| 971 | + processDefinition, processDefinitionInfo, instance.getProcessVariables()); | ||
| 972 | + if (ObjUtil.notEqual(instance.getName(), name)) { | ||
| 973 | + runtimeService.setProcessInstanceName(instance.getProcessInstanceId(), name); | ||
| 941 | } | 974 | } |
| 942 | } | 975 | } |
| 943 | - }); | ||
| 944 | - } | ||
| 945 | 976 | ||
| 946 | - @Override | ||
| 947 | - public void processProcessInstanceCreated(ProcessInstance instance) { | ||
| 948 | - // 注意:需要基于 instance 设置租户编号,避免 Flowable 内部异步时,丢失租户编号 | ||
| 949 | - FlowableUtils.execute(instance.getTenantId(), () -> { | ||
| 950 | - // 流程前置通知 | ||
| 951 | - BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService. | ||
| 952 | - getProcessDefinitionInfo(instance.getProcessDefinitionId()); | ||
| 953 | - if (ObjUtil.isNull(processDefinitionInfo) || | ||
| 954 | - ObjUtil.isNull(processDefinitionInfo.getProcessBeforeTriggerSetting())) { | ||
| 955 | - return; | ||
| 956 | - } | ||
| 957 | - BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting(); | ||
| 958 | - BpmHttpRequestUtils.executeBpmHttpRequest(instance, | ||
| 959 | - setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse()); | ||
| 960 | }); | 977 | }); |
| 978 | + | ||
| 979 | + // 流程前置通知 | ||
| 980 | + if (ObjUtil.isNull(processDefinitionInfo.getProcessBeforeTriggerSetting())) { | ||
| 981 | + return; | ||
| 982 | + } | ||
| 983 | + BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting(); | ||
| 984 | + BpmHttpRequestUtils.executeBpmHttpRequest(instance, | ||
| 985 | + setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse()); | ||
| 961 | } | 986 | } |
| 962 | 987 | ||
| 963 | } | 988 | } |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
| @@ -230,10 +230,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { | @@ -230,10 +230,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||
| 230 | if (StrUtil.isNotBlank(pageVO.getName())) { | 230 | if (StrUtil.isNotBlank(pageVO.getName())) { |
| 231 | taskQuery.taskNameLike("%" + pageVO.getName() + "%"); | 231 | taskQuery.taskNameLike("%" + pageVO.getName() + "%"); |
| 232 | } | 232 | } |
| 233 | - if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { | ||
| 234 | - taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0])); | ||
| 235 | - taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1])); | ||
| 236 | - } | 233 | +// if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { |
| 234 | +// taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0])); | ||
| 235 | +// taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1])); | ||
| 236 | +// } | ||
| 237 | // 执行查询 | 237 | // 执行查询 |
| 238 | long count = taskQuery.count(); | 238 | long count = taskQuery.count(); |
| 239 | if (count == 0) { | 239 | if (count == 0) { |
| @@ -244,6 +244,12 @@ public class BpmTaskServiceImpl implements BpmTaskService { | @@ -244,6 +244,12 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||
| 244 | // 特殊:强制移除自动完成的“发起人”节点 | 244 | // 特殊:强制移除自动完成的“发起人”节点 |
| 245 | // 补充说明:由于 taskQuery 无法方面的过滤,所以暂时通过内存过滤 | 245 | // 补充说明:由于 taskQuery 无法方面的过滤,所以暂时通过内存过滤 |
| 246 | tasks.removeIf(task -> task.getTaskDefinitionKey().equals(START_USER_NODE_ID)); | 246 | tasks.removeIf(task -> task.getTaskDefinitionKey().equals(START_USER_NODE_ID)); |
| 247 | + // TODO @芋艿:https://t.zsxq.com/MNzqp 【flowable bug】:taskCreatedAfter、taskCreatedBefore 拼接的是 OR | ||
| 248 | + if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { | ||
| 249 | + tasks.removeIf(task -> task.getCreateTime() == null | ||
| 250 | + || task.getCreateTime().before(DateUtils.of(pageVO.getCreateTime()[0])) | ||
| 251 | + || task.getCreateTime().after(DateUtils.of(pageVO.getCreateTime()[1]))); | ||
| 252 | + } | ||
| 247 | return new PageResult<>(tasks, count); | 253 | return new PageResult<>(tasks, count); |
| 248 | } | 254 | } |
| 249 | 255 | ||
| @@ -259,16 +265,22 @@ public class BpmTaskServiceImpl implements BpmTaskService { | @@ -259,16 +265,22 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||
| 259 | if (StrUtil.isNotEmpty(pageVO.getCategory())) { | 265 | if (StrUtil.isNotEmpty(pageVO.getCategory())) { |
| 260 | taskQuery.taskCategory(pageVO.getCategory()); | 266 | taskQuery.taskCategory(pageVO.getCategory()); |
| 261 | } | 267 | } |
| 262 | - if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { | ||
| 263 | - taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0])); | ||
| 264 | - taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1])); | ||
| 265 | - } | 268 | +// if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { |
| 269 | +// taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getCreateTime()[0])); | ||
| 270 | +// taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getCreateTime()[1])); | ||
| 271 | +// } | ||
| 266 | // 执行查询 | 272 | // 执行查询 |
| 267 | long count = taskQuery.count(); | 273 | long count = taskQuery.count(); |
| 268 | if (count == 0) { | 274 | if (count == 0) { |
| 269 | return PageResult.empty(); | 275 | return PageResult.empty(); |
| 270 | } | 276 | } |
| 271 | List<HistoricTaskInstance> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); | 277 | List<HistoricTaskInstance> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize()); |
| 278 | + // TODO @芋艿:https://t.zsxq.com/MNzqp 【flowable bug】:taskCreatedAfter、taskCreatedBefore 拼接的是 OR | ||
| 279 | + if (ArrayUtil.isNotEmpty(pageVO.getCreateTime())) { | ||
| 280 | + tasks.removeIf(task -> task.getCreateTime() == null | ||
| 281 | + || task.getCreateTime().before(DateUtils.of(pageVO.getCreateTime()[0])) | ||
| 282 | + || task.getCreateTime().after(DateUtils.of(pageVO.getCreateTime()[1]))); | ||
| 283 | + } | ||
| 272 | return new PageResult<>(tasks, count); | 284 | return new PageResult<>(tasks, count); |
| 273 | } | 285 | } |
| 274 | 286 | ||
| @@ -886,7 +898,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { | @@ -886,7 +898,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||
| 886 | if (!returnTaskKeyList.contains(task.getTaskDefinitionKey())) { | 898 | if (!returnTaskKeyList.contains(task.getTaskDefinitionKey())) { |
| 887 | return; | 899 | return; |
| 888 | } | 900 | } |
| 889 | - runExecutionIds.add(task.getExecutionId()); | 901 | + if (task.getExecutionId() != null) { |
| 902 | + runExecutionIds.add(task.getExecutionId()); | ||
| 903 | + } | ||
| 890 | 904 | ||
| 891 | // 判断是否分配给自己任务,因为会签任务,一个节点会有多个任务 | 905 | // 判断是否分配给自己任务,因为会签任务,一个节点会有多个任务 |
| 892 | if (isAssignUserTask(userId, task)) { // 情况一:自己的任务,进行 RETURN 标记 | 906 | if (isAssignUserTask(userId, task)) { // 情况一:自己的任务,进行 RETURN 标记 |
| @@ -1367,7 +1381,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { | @@ -1367,7 +1381,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { | ||
| 1367 | PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE, String.class)); | 1381 | PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE, String.class)); |
| 1368 | if (userTaskElement.getId().equals(START_USER_NODE_ID) | 1382 | if (userTaskElement.getId().equals(START_USER_NODE_ID) |
| 1369 | && (skipStartUserNodeFlag == null // 目的:一般是“主流程”,发起人节点,自动通过审核 | 1383 | && (skipStartUserNodeFlag == null // 目的:一般是“主流程”,发起人节点,自动通过审核 |
| 1370 | - || Boolean.TRUE.equals(skipStartUserNodeFlag)) // 目的:一般是“子流程”,发起人节点,按配置自动通过审核 | 1384 | + || BooleanUtil.isTrue(skipStartUserNodeFlag)) // 目的:一般是“子流程”,发起人节点,按配置自动通过审核 |
| 1371 | && ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE)) { | 1385 | && ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE)) { |
| 1372 | getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId()) | 1386 | getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId()) |
| 1373 | .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_SKIP_START_USER_NODE.getReason())); | 1387 | .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_SKIP_START_USER_NODE.getReason())); |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/listener/BpmCallActivityListener.java
| @@ -85,10 +85,15 @@ public class BpmCallActivityListener implements ExecutionListener { | @@ -85,10 +85,15 @@ public class BpmCallActivityListener implements ExecutionListener { | ||
| 85 | // 2.2 使用表单值,并兜底字符串转 Long 失败时使用主流程发起人 | 85 | // 2.2 使用表单值,并兜底字符串转 Long 失败时使用主流程发起人 |
| 86 | try { | 86 | try { |
| 87 | FlowableUtils.setAuthenticatedUserId(Long.parseLong(formFieldValue)); | 87 | FlowableUtils.setAuthenticatedUserId(Long.parseLong(formFieldValue)); |
| 88 | - } catch (Exception e) { | ||
| 89 | - log.error("[notify][监听器:{},子流程监听器设置流程的发起人字符串转 Long 失败,字符串:{}]", | ||
| 90 | - DELEGATE_EXPRESSION, formFieldValue); | ||
| 91 | - FlowableUtils.setAuthenticatedUserId(Long.parseLong(processInstance.getStartUserId())); | 88 | + } catch (NumberFormatException ex) { |
| 89 | + try { | ||
| 90 | + List<Long> formFieldValues = JsonUtils.parseArray(formFieldValue, Long.class); | ||
| 91 | + FlowableUtils.setAuthenticatedUserId(formFieldValues.get(0)); | ||
| 92 | + } catch (Exception e) { | ||
| 93 | + log.error("[notify][监听器:{},子流程监听器设置流程的发起人字符串转 Long 失败,字符串:{}]", | ||
| 94 | + DELEGATE_EXPRESSION, formFieldValue); | ||
| 95 | + FlowableUtils.setAuthenticatedUserId(Long.parseLong(processInstance.getStartUserId())); | ||
| 96 | + } | ||
| 92 | } | 97 | } |
| 93 | } | 98 | } |
| 94 | } | 99 | } |
yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java
| @@ -303,7 +303,9 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { | @@ -303,7 +303,9 @@ public class SeckillActivityServiceImpl implements SeckillActivityService { | ||
| 303 | throw exception(SECKILL_JOIN_ACTIVITY_TIME_ERROR); | 303 | throw exception(SECKILL_JOIN_ACTIVITY_TIME_ERROR); |
| 304 | } | 304 | } |
| 305 | SeckillConfigDO config = seckillConfigService.getCurrentSeckillConfig(); | 305 | SeckillConfigDO config = seckillConfigService.getCurrentSeckillConfig(); |
| 306 | - if (config == null || !CollectionUtil.contains(activity.getConfigIds(), config.getId())) { | 306 | + if (config == null |
| 307 | + || !CollectionUtil.contains(activity.getConfigIds(), config.getId()) | ||
| 308 | + || !LocalDateTimeUtils.isBetween(config.getStartTime(), config.getEndTime())) { | ||
| 307 | throw exception(SECKILL_JOIN_ACTIVITY_TIME_ERROR); | 309 | throw exception(SECKILL_JOIN_ACTIVITY_TIME_ERROR); |
| 308 | } | 310 | } |
| 309 | // 1.3 超过单次购买限制 | 311 | // 1.3 超过单次购买限制 |