mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-01 02:38:43 +08:00 
			
		
		
		
	仿钉钉流程设计- 基于服务任务实现会签下的拒绝需要全员
This commit is contained in:
		| @@ -15,7 +15,7 @@ public enum BpmUserTaskRejectHandlerType { | |||||||
|  |  | ||||||
|     FINISH_PROCESS(1, "终止流程"), |     FINISH_PROCESS(1, "终止流程"), | ||||||
|     RETURN_PRE_USER_TASK(2, "驳回到指定任务节点"), |     RETURN_PRE_USER_TASK(2, "驳回到指定任务节点"), | ||||||
|     FINISH_PROCESS_BY_REJECT_RATIO(3, "按拒绝人数比例终止流程"), // 用于会签 |     FINISH_PROCESS_BY_REJECT_NUMBER(3, "按拒绝人数终止流程"), // 用于会签 | ||||||
|     FINISH_TASK(4, "结束任务"); // 待实现,可能会用于意见分支 |     FINISH_TASK(4, "结束任务"); // 待实现,可能会用于意见分支 | ||||||
|  |  | ||||||
|     private final Integer type; |     private final Integer type; | ||||||
|   | |||||||
| @@ -41,6 +41,12 @@ public class BpmSimpleModelNodeVO { | |||||||
|  |  | ||||||
|     @Schema(description = "节点的属性") |     @Schema(description = "节点的属性") | ||||||
|     private Map<String, Object> attributes; // TODO @jason:建议是字段分拆下;类似说: |     private Map<String, Object> attributes; // TODO @jason:建议是字段分拆下;类似说: | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 附加节点 Id, 该节点不从前端传入。 由程序生成. 由于当个节点无法完成功能。 需要附加节点来完成。 | ||||||
|  |      * 例如: 会签时需要按拒绝人数来终止流程。 需要 userTask + ServiceTask 两个节点配合完成。 serviceTask 由后端生成。 | ||||||
|  |      */ | ||||||
|  |     private String attachNodeId; | ||||||
|     // Map<String, Integer> formPermissions; 表单权限;仅发起、审批、抄送节点会使用 |     // Map<String, Integer> formPermissions; 表单权限;仅发起、审批、抄送节点会使用 | ||||||
|     // Integer approveMethod; 审批方式;仅审批节点会使用 |     // Integer approveMethod; 审批方式;仅审批节点会使用 | ||||||
|     // TODO @jason 后面和前端一起调整一下 |     // TODO @jason 后面和前端一起调整一下 | ||||||
|   | |||||||
| @@ -50,6 +50,16 @@ public interface BpmnModelConstants { | |||||||
|      */ |      */ | ||||||
|     String USER_TASK_REJECT_RETURN_TASK_ID = "rejectReturnTaskId"; |     String USER_TASK_REJECT_RETURN_TASK_ID = "rejectReturnTaskId"; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * BPMN UserTask 的扩展属性,用于标记用户任务的审批方式 | ||||||
|  |      */ | ||||||
|  |     String USER_TASK_APPROVE_METHOD = "approveMethod"; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * BPMN ExtensionElement 的扩展属性,用于标记 服务任务附属的用户任务 Id | ||||||
|  |      */ | ||||||
|  |     String SERVICE_TASK_ATTACH_USER_TASK_ID = "attachUserTaskId"; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * BPMN ExtensionElement 流程表单字段权限元素, 用于标记字段权限 |      * BPMN ExtensionElement 流程表单字段权限元素, 用于标记字段权限 | ||||||
|      */ |      */ | ||||||
| @@ -75,6 +85,4 @@ public interface BpmnModelConstants { | |||||||
|      * 支持转仿钉钉设计模型的 Bpmn 节点 |      * 支持转仿钉钉设计模型的 Bpmn 节点 | ||||||
|      */ |      */ | ||||||
|     Set<Class<? extends FlowNode>> SUPPORT_CONVERT_SIMPLE_FlOW_NODES = ImmutableSet.of(UserTask.class, EndEvent.class); |     Set<Class<? extends FlowNode>> SUPPORT_CONVERT_SIMPLE_FlOW_NODES = ImmutableSet.of(UserTask.class, EndEvent.class); | ||||||
|  |  | ||||||
|     String REJECT_POST_PROCESS_MESSAGE_NAME = "message_reject_post_process"; |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,66 @@ | |||||||
|  | package cn.iocoder.yudao.module.bpm.framework.flowable.core.expression; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.lang.Assert; | ||||||
|  | import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; | ||||||
|  | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||||||
|  | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | ||||||
|  | import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; | ||||||
|  | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; | ||||||
|  | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import org.flowable.bpmn.model.FlowElement; | ||||||
|  | import org.flowable.engine.delegate.DelegateExecution; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  |  | ||||||
|  | import java.util.Objects; | ||||||
|  |  | ||||||
|  | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||||
|  | import static cn.iocoder.yudao.module.bpm.enums.definition.BpmApproveMethodEnum.ANY_APPROVE_ALL_REJECT; | ||||||
|  | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.USER_TASK_APPROVE_METHOD; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 按拒绝人数计算会签的完成条件的流程表达式实现 | ||||||
|  |  * | ||||||
|  |  * @author jason | ||||||
|  |  */ | ||||||
|  | @Component | ||||||
|  | @Slf4j | ||||||
|  | public class CompleteByRejectCountExpression { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  会签的完成条件 | ||||||
|  |      */ | ||||||
|  |     public boolean completionCondition(DelegateExecution execution) { | ||||||
|  |         FlowElement flowElement = execution.getCurrentFlowElement(); | ||||||
|  |         // 实例总数 | ||||||
|  |         Integer nrOfInstances = (Integer) execution.getVariable("nrOfInstances"); | ||||||
|  |         // 完成的实例数 | ||||||
|  |         Integer nrOfCompletedInstances = (Integer) execution.getVariable("nrOfCompletedInstances"); | ||||||
|  |         // 审批方式 | ||||||
|  |         Integer approveMethod = NumberUtils.parseInt(BpmnModelUtils.parseExtensionElement(flowElement, USER_TASK_APPROVE_METHOD)); | ||||||
|  |         Assert.notNull(approveMethod, "审批方式不能空"); | ||||||
|  |         // 计算拒绝的人数 | ||||||
|  |         Integer rejectCount = CollectionUtils.getSumValue(execution.getExecutions(), | ||||||
|  |                 item -> Objects.equals(BpmTaskStatusEnum.REJECT.getStatus(), item.getVariableLocal(BpmConstants.TASK_VARIABLE_STATUS, Integer.class)) ? 1 : 0, | ||||||
|  |                 Integer::sum, 0); | ||||||
|  |         // 同意的人数为 完成人数 - 拒绝人数 | ||||||
|  |         int agreeCount = nrOfCompletedInstances - rejectCount; | ||||||
|  |         // 1. 多人会签(通过只需一人,拒绝需要全员) | ||||||
|  |         if (Objects.equals(ANY_APPROVE_ALL_REJECT.getMethod(), approveMethod)) { | ||||||
|  |             // 1.1 一人同意. 会签任务完成 | ||||||
|  |             if (agreeCount > 0) { | ||||||
|  |                 return true; | ||||||
|  |             } else { | ||||||
|  |                 // 1.2 所有人都拒绝了。设置任务拒绝变量, 会签任务完成。 后续终止流程在 ServiceTask【MultiInstanceServiceTaskExpression】处理 | ||||||
|  |                 if (Objects.equals(nrOfInstances, rejectCount)) { | ||||||
|  |                     execution.setVariable(String.format("%s_reject",flowElement.getId()), Boolean.TRUE); | ||||||
|  |                     return true; | ||||||
|  |                 } | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         // TODO 多人会签(按比例投票) | ||||||
|  |         log.error("[completionCondition] 按拒绝人数计算会签的完成条件的审批方式[{}],配置有误", approveMethod); | ||||||
|  |         throw exception(GlobalErrorCodeConstants.ERROR_CONFIGURATION); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,38 @@ | |||||||
|  | package cn.iocoder.yudao.module.bpm.framework.flowable.core.expression; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.lang.Assert; | ||||||
|  | import cn.hutool.core.util.BooleanUtil; | ||||||
|  | import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum; | ||||||
|  | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; | ||||||
|  | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; | ||||||
|  | import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; | ||||||
|  | import jakarta.annotation.Resource; | ||||||
|  | import org.flowable.engine.delegate.DelegateExecution; | ||||||
|  | import org.flowable.engine.delegate.JavaDelegate; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 处理会签 Service Task 代理表达式 | ||||||
|  |  * | ||||||
|  |  * @author jason | ||||||
|  |  */ | ||||||
|  | @Component | ||||||
|  | public class MultiInstanceServiceTaskExpression implements JavaDelegate { | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     private BpmProcessInstanceService processInstanceService; | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void execute(DelegateExecution execution) { | ||||||
|  |         String attachUserTaskId = BpmnModelUtils.parseExtensionElement(execution.getCurrentFlowElement(), | ||||||
|  |                 BpmnModelConstants.SERVICE_TASK_ATTACH_USER_TASK_ID); | ||||||
|  |         Assert.notNull(attachUserTaskId, "附属的用户任务 Id 不能为空"); | ||||||
|  |         // 获取会签任务是否被拒绝 | ||||||
|  |         Boolean userTaskRejected = execution.getVariable(String.format("%s_reject", attachUserTaskId), Boolean.class); | ||||||
|  |         // 如果会签任务被拒绝, 终止流程 | ||||||
|  |         if (BooleanUtil.isTrue(userTaskRejected)) { | ||||||
|  |             processInstanceService.updateProcessInstanceReject(execution.getProcessInstanceId(), | ||||||
|  |                     BpmCommentTypeEnum.REJECT.formatComment("会签任务拒绝人数满足条件")); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -26,6 +26,7 @@ import java.util.Objects; | |||||||
|  |  | ||||||
| import static cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventType.USER_TASK_TIMEOUT; | import static cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventType.USER_TASK_TIMEOUT; | ||||||
| import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.*; | import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.*; | ||||||
|  | import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskRejectHandlerType.FINISH_PROCESS_BY_REJECT_NUMBER; | ||||||
| import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutActionEnum.AUTO_REMINDER; | import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutActionEnum.AUTO_REMINDER; | ||||||
| import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*; | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*; | ||||||
| import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.*; | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.*; | ||||||
| @@ -55,6 +56,11 @@ public class SimpleModelUtils { | |||||||
|      */ |      */ | ||||||
|     public static final String ANY_OF_APPROVE_COMPLETE_EXPRESSION = "${ nrOfCompletedInstances > 0 }"; |     public static final String ANY_OF_APPROVE_COMPLETE_EXPRESSION = "${ nrOfCompletedInstances > 0 }"; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 按拒绝人数计算多实例完成条件的表达式 | ||||||
|  |      */ | ||||||
|  |     public static final String COMPLETE_BY_REJECT_COUNT_EXPRESSION = "${completeByRejectCountExpression.completionCondition(execution)}"; | ||||||
|  |  | ||||||
|     // TODO-DONE @jason:建议方法名,改成 buildBpmnModel |     // TODO-DONE @jason:建议方法名,改成 buildBpmnModel | ||||||
|     // TODO @yunai:注释需要完善下; |     // TODO @yunai:注释需要完善下; | ||||||
|  |  | ||||||
| @@ -71,10 +77,6 @@ public class SimpleModelUtils { | |||||||
|         // 不加这个 解析 Message 会报 NPE 异常 . |         // 不加这个 解析 Message 会报 NPE 异常 . | ||||||
|         bpmnModel.setTargetNamespace(BPMN2_NAMESPACE); // TODO @jason:待定:是不是搞个自定义的 namespace; |         bpmnModel.setTargetNamespace(BPMN2_NAMESPACE); // TODO @jason:待定:是不是搞个自定义的 namespace; | ||||||
|         // TODO 芋艿:后续在 review |         // TODO 芋艿:后续在 review | ||||||
|         // @芋艿 这个 Message 可以去掉 暂时用不上 |  | ||||||
|         Message rejectPostProcessMsg = new Message(); |  | ||||||
|         rejectPostProcessMsg.setName(REJECT_POST_PROCESS_MESSAGE_NAME); |  | ||||||
|         bpmnModel.addMessage(rejectPostProcessMsg); |  | ||||||
|  |  | ||||||
|         Process process = new Process(); |         Process process = new Process(); | ||||||
|         process.setId(processId); |         process.setId(processId); | ||||||
| @@ -107,19 +109,30 @@ public class SimpleModelUtils { | |||||||
|         if (nodeType == END_NODE) { |         if (nodeType == END_NODE) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 2.1 情况一:普通节点 |         // 2.1 情况一:普通节点 | ||||||
|         BpmSimpleModelNodeVO childNode = node.getChildNode(); |         BpmSimpleModelNodeVO childNode = node.getChildNode(); | ||||||
|         if (!BpmSimpleModelNodeType.isBranchNode(node.getType())) { |         if (!BpmSimpleModelNodeType.isBranchNode(node.getType())) { | ||||||
|             if (!isValidNode(childNode)) { |             if (!isValidNode(childNode)) { | ||||||
|                 // 2.1.1 普通节点且无孩子节点。分两种情况 |                 // 2.1.1 普通节点且无孩子节点。分两种情况 | ||||||
|                 // a.结束节点  b. 条件分支的最后一个节点.与分支节点的孩子节点或聚合节点建立连线。 |                 // a.结束节点  b. 条件分支的最后一个节点.与分支节点的孩子节点或聚合节点建立连线。 | ||||||
|                 SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), targetNodeId, null, null, null); |                 if (StrUtil.isNotEmpty(node.getAttachNodeId())) { | ||||||
|                 process.addFlowElement(sequenceFlow); |                     // 2.1.1.1 如果有附加节点. 需要先建立和附加节点的连线。再建立附加节点和目标节点的连线 | ||||||
|  |                     List<SequenceFlow> sequenceFlows = buildAttachNodeSequenceFlow(node.getId(), node.getAttachNodeId(), targetNodeId); | ||||||
|  |                     sequenceFlows.forEach(process::addFlowElement); | ||||||
|  |                 } else { | ||||||
|  |                     SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), targetNodeId, null, null, null); | ||||||
|  |                     process.addFlowElement(sequenceFlow); | ||||||
|  |                 } | ||||||
|             } else { |             } else { | ||||||
|                 // 2.1.2 普通节点且有孩子节点。建立连线 |                 // 2.1.2 普通节点且有孩子节点。建立连线 | ||||||
|                 SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), childNode.getId(), null, null, null); |                 if (StrUtil.isNotEmpty(node.getAttachNodeId())) { | ||||||
|                 process.addFlowElement(sequenceFlow); |                     // 2.1.1.2 如果有附加节点. 需要先建立和附加节点的连线。再建立附加节点和目标节点的连线 | ||||||
|  |                     List<SequenceFlow> sequenceFlows = buildAttachNodeSequenceFlow(node.getId(), node.getAttachNodeId(), childNode.getId()); | ||||||
|  |                     sequenceFlows.forEach(process::addFlowElement); | ||||||
|  |                 } else { | ||||||
|  |                     SequenceFlow sequenceFlow = buildBpmnSequenceFlow(node.getId(), childNode.getId(), null, null, null); | ||||||
|  |                     process.addFlowElement(sequenceFlow); | ||||||
|  |                 } | ||||||
|                 // 递归调用后续节点 |                 // 递归调用后续节点 | ||||||
|                 traverseNodeToBuildSequenceFlow(process, childNode, targetNodeId); |                 traverseNodeToBuildSequenceFlow(process, childNode, targetNodeId); | ||||||
|             } |             } | ||||||
| @@ -173,6 +186,18 @@ public class SimpleModelUtils { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      *  构建有附加节点的连线 | ||||||
|  |      * @param nodeId 当前节点 Id | ||||||
|  |      * @param attachNodeId 附属节点 Id | ||||||
|  |      * @param targetNodeId 目标节点 Id | ||||||
|  |      */ | ||||||
|  |     private static List<SequenceFlow> buildAttachNodeSequenceFlow(String nodeId, String attachNodeId, String targetNodeId) { | ||||||
|  |         SequenceFlow sequenceFlow = buildBpmnSequenceFlow(nodeId, attachNodeId, null, null, null); | ||||||
|  |         SequenceFlow attachSequenceFlow = buildBpmnSequenceFlow(attachNodeId, targetNodeId, null, null, null); | ||||||
|  |         return CollUtil.newArrayList(sequenceFlow, attachSequenceFlow); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 构造条件表达式 |      * 构造条件表达式 | ||||||
|      * |      * | ||||||
| @@ -331,9 +356,28 @@ public class SimpleModelUtils { | |||||||
|             BoundaryEvent boundaryEvent = buildUserTaskTimerBoundaryEvent(userTask, userTaskConfig.getTimeoutHandler()); |             BoundaryEvent boundaryEvent = buildUserTaskTimerBoundaryEvent(userTask, userTaskConfig.getTimeoutHandler()); | ||||||
|             flowElements.add(boundaryEvent); |             flowElements.add(boundaryEvent); | ||||||
|         } |         } | ||||||
|  |         // 如果按拒绝人数终止流程。需要添加附加的 ServiceTask 处理 | ||||||
|  |         if (userTaskConfig.getRejectHandler() != null && | ||||||
|  |                 Objects.equals(FINISH_PROCESS_BY_REJECT_NUMBER.getType(), userTaskConfig.getRejectHandler().getType())) { | ||||||
|  |             ServiceTask serviceTask = buildMultiInstanceServiceTask(node); | ||||||
|  |             flowElements.add(serviceTask); | ||||||
|  |         } | ||||||
|         return flowElements; |         return flowElements; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private static ServiceTask buildMultiInstanceServiceTask(BpmSimpleModelNodeVO node) { | ||||||
|  |         ServiceTask serviceTask = new ServiceTask(); | ||||||
|  |         String id = String.format("Activity-%s", IdUtil.fastSimpleUUID()); | ||||||
|  |         serviceTask.setId(id); | ||||||
|  |         serviceTask.setName("会签服务任务"); | ||||||
|  |         serviceTask.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION); | ||||||
|  |         serviceTask.setImplementation("${multiInstanceServiceTaskExpression}"); | ||||||
|  |         serviceTask.setAsynchronous(false); | ||||||
|  |         addExtensionElement(serviceTask, SERVICE_TASK_ATTACH_USER_TASK_ID, node.getId()); | ||||||
|  |         node.setAttachNodeId(id); | ||||||
|  |         return serviceTask; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private static BoundaryEvent buildUserTaskTimerBoundaryEvent(UserTask userTask, SimpleModelUserTaskConfig.TimeoutHandler timeoutHandler) { |     private static BoundaryEvent buildUserTaskTimerBoundaryEvent(UserTask userTask, SimpleModelUserTaskConfig.TimeoutHandler timeoutHandler) { | ||||||
|         // 定时器边界事件 |         // 定时器边界事件 | ||||||
|         BoundaryEvent boundaryEvent = new BoundaryEvent(); |         BoundaryEvent boundaryEvent = new BoundaryEvent(); | ||||||
| @@ -468,6 +512,9 @@ public class SimpleModelUtils { | |||||||
|         if (bpmApproveMethodEnum == null || bpmApproveMethodEnum == BpmApproveMethodEnum.SINGLE_PERSON_APPROVE) { |         if (bpmApproveMethodEnum == null || bpmApproveMethodEnum == BpmApproveMethodEnum.SINGLE_PERSON_APPROVE) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |         // 添加审批方式的扩展属性 | ||||||
|  |         addExtensionElement(userTask, BpmnModelConstants.USER_TASK_APPROVE_METHOD, | ||||||
|  |                 approveMethod == null ? null : approveMethod.toString()); | ||||||
|         MultiInstanceLoopCharacteristics multiInstanceCharacteristics = new MultiInstanceLoopCharacteristics(); |         MultiInstanceLoopCharacteristics multiInstanceCharacteristics = new MultiInstanceLoopCharacteristics(); | ||||||
|         //  设置 collectionVariable。本系统用不到。会在 仅仅为了校验。 |         //  设置 collectionVariable。本系统用不到。会在 仅仅为了校验。 | ||||||
|         multiInstanceCharacteristics.setInputDataItem("${coll_userList}"); |         multiInstanceCharacteristics.setInputDataItem("${coll_userList}"); | ||||||
| @@ -484,8 +531,7 @@ public class SimpleModelUtils { | |||||||
|             multiInstanceCharacteristics.setLoopCardinality("1"); |             multiInstanceCharacteristics.setLoopCardinality("1"); | ||||||
|             userTask.setLoopCharacteristics(multiInstanceCharacteristics); |             userTask.setLoopCharacteristics(multiInstanceCharacteristics); | ||||||
|         } else if (bpmApproveMethodEnum == BpmApproveMethodEnum.ANY_APPROVE_ALL_REJECT) { |         } else if (bpmApproveMethodEnum == BpmApproveMethodEnum.ANY_APPROVE_ALL_REJECT) { | ||||||
|             // 这种情况。拒绝任务时候,不会终止或者完成任务 参见 BpmTaskService#rejectTask 方法 |             multiInstanceCharacteristics.setCompletionCondition(COMPLETE_BY_REJECT_COUNT_EXPRESSION); | ||||||
|             multiInstanceCharacteristics.setCompletionCondition(ANY_OF_APPROVE_COMPLETE_EXPRESSION); |  | ||||||
|             multiInstanceCharacteristics.setSequential(false); |             multiInstanceCharacteristics.setSequential(false); | ||||||
|         } |         } | ||||||
|         // TODO 会签(按比例投票 ) |         // TODO 会签(按比例投票 ) | ||||||
|   | |||||||
| @@ -35,7 +35,6 @@ import org.flowable.engine.HistoryService; | |||||||
| import org.flowable.engine.ManagementService; | import org.flowable.engine.ManagementService; | ||||||
| import org.flowable.engine.RuntimeService; | import org.flowable.engine.RuntimeService; | ||||||
| import org.flowable.engine.TaskService; | import org.flowable.engine.TaskService; | ||||||
| import org.flowable.engine.runtime.Execution; |  | ||||||
| import org.flowable.engine.runtime.ProcessInstance; | import org.flowable.engine.runtime.ProcessInstance; | ||||||
| import org.flowable.task.api.DelegationState; | import org.flowable.task.api.DelegationState; | ||||||
| import org.flowable.task.api.Task; | import org.flowable.task.api.Task; | ||||||
| @@ -352,30 +351,17 @@ public class BpmTaskServiceImpl implements BpmTaskService { | |||||||
|                     .setReason(reqVO.getReason()); |                     .setReason(reqVO.getReason()); | ||||||
|             returnTask(userId, returnReq); |             returnTask(userId, returnReq); | ||||||
|             return; |             return; | ||||||
|         } else if (userTaskRejectHandlerType == BpmUserTaskRejectHandlerType.FINISH_PROCESS_BY_REJECT_RATIO) { |         } else if (userTaskRejectHandlerType == BpmUserTaskRejectHandlerType.FINISH_PROCESS_BY_REJECT_NUMBER) { | ||||||
|             // 3.3 按拒绝人数比例终止流程 |             // 3.3 按拒绝人数终止流程 | ||||||
|             if (!flowElement.hasMultiInstanceLoopCharacteristics()) { |             if (!flowElement.hasMultiInstanceLoopCharacteristics()) { | ||||||
|                 log.error("[rejectTask] 用户任务拒绝处理类型配置错误, 按拒绝人数终止流程只能用于会签任务"); |                 log.error("[rejectTask] 用户任务拒绝处理类型配置错误, 按拒绝人数终止流程只能用于会签任务"); | ||||||
|                 throw exception(GlobalErrorCodeConstants.ERROR_CONFIGURATION); |                 throw exception(GlobalErrorCodeConstants.ERROR_CONFIGURATION); | ||||||
|             } |             } | ||||||
|             // 获取并行任务总数 |             // 设置变量值为拒绝 | ||||||
|             Execution execution = runtimeService.createExecutionQuery().processInstanceId(task.getProcessInstanceId()) |             runtimeService.setVariableLocal(task.getExecutionId(), BpmConstants.TASK_VARIABLE_STATUS, BpmTaskStatusEnum.REJECT.getStatus()); | ||||||
|                     .executionId(task.getExecutionId()).singleResult(); |             // 完成任务 | ||||||
|             Integer nrOfInstances = runtimeService.getVariable(execution.getParentId(), "nrOfInstances", Integer.class); |             taskService.complete(task.getId()); | ||||||
|             // 获取未完成任务列表 |             return; | ||||||
|             List<Task> taskList = getTaskListByProcessInstanceIdAndAssigned(task.getProcessInstanceId(), null, |  | ||||||
|                     task.getTaskDefinitionKey()); |  | ||||||
|             // 获取已经拒绝的任务数 |  | ||||||
|             Integer rejectNumber = getSumValue(taskList, |  | ||||||
|                     item -> Objects.equals(BpmTaskStatusEnum.REJECT.getStatus(), FlowableUtils.getTaskStatus(item)) ? 1 : 0, |  | ||||||
|                     Integer::sum, 0); |  | ||||||
| //            // TODO @jason:如果这样的话,后续会不会在【已完成】里面查询不到哈?【重要!!!!】 |  | ||||||
| //            // 拒绝任务后,任务分配人清空。但不能完成任务 |  | ||||||
| //            taskService.setAssignee(task.getId(), ""); |  | ||||||
|             // 不是所有人拒绝返回。 TODO 后续需要做按拒绝人数比例来判断 |  | ||||||
|             if (!Objects.equals(nrOfInstances, rejectNumber)) { |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|         // 3.4 其他情况 终止流程。 TODO 后续可能会增加处理类型 |         // 3.4 其他情况 终止流程。 TODO 后续可能会增加处理类型 | ||||||
|         processInstanceService.updateProcessInstanceReject(instance.getProcessInstanceId(), reqVO.getReason()); |         processInstanceService.updateProcessInstanceReject(instance.getProcessInstanceId(), reqVO.getReason()); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 jason
					jason