From efac1ee62062ad743bffaeca92d8a0adc204decb Mon Sep 17 00:00:00 2001 From: Jerry <707344974@qq.com> Date: Thu, 19 Sep 2024 10:02:16 +0800 Subject: [PATCH] =?UTF-8?q?commit=EF=BC=9A=E6=94=AF=E6=8C=81=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E3=80=81=E6=8E=A5=E6=94=B6=E4=BB=BB=E5=8A=A1=EF=BC=8C?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E4=B8=B2=E8=A1=8C=E4=BC=9A=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flow/cmd/AddSequenceMultiInstanceCmd.java | 110 +++++++++++++++++ .../flow/constant/FlowApprovalType.java | 8 ++ .../controller/FlowOperationController.java | 115 ++++++++++++++---- .../common/flow/service/FlowApiService.java | 9 ++ .../flow/service/impl/FlowApiServiceImpl.java | 26 ++++ .../flow/cmd/AddSequenceMultiInstanceCmd.java | 110 +++++++++++++++++ .../flow/constant/FlowApprovalType.java | 8 ++ .../controller/FlowOperationController.java | 115 ++++++++++++++---- .../common/flow/service/FlowApiService.java | 9 ++ .../flow/service/impl/FlowApiServiceImpl.java | 26 ++++ 10 files changed, 490 insertions(+), 46 deletions(-) create mode 100644 OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/cmd/AddSequenceMultiInstanceCmd.java create mode 100644 OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/cmd/AddSequenceMultiInstanceCmd.java diff --git a/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/cmd/AddSequenceMultiInstanceCmd.java b/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/cmd/AddSequenceMultiInstanceCmd.java new file mode 100644 index 00000000..99f33601 --- /dev/null +++ b/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/cmd/AddSequenceMultiInstanceCmd.java @@ -0,0 +1,110 @@ +package com.orangeforms.common.flow.cmd; + +import cn.hutool.core.util.StrUtil; +import com.orangeforms.common.flow.constant.FlowConstant; +import lombok.AllArgsConstructor; +import org.flowable.bpmn.model.Activity; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.MultiInstanceLoopCharacteristics; +import org.flowable.common.engine.api.FlowableException; +import org.flowable.common.engine.impl.interceptor.Command; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.persistence.entity.ExecutionEntity; +import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager; +import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.engine.impl.util.ProcessDefinitionUtil; +import org.flowable.engine.impl.util.TaskHelper; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; +import org.flowable.task.service.impl.persistence.entity.TaskEntityManager; + +import java.util.List; + +/** + * 串行会签任务前后加签的命令对象。 + * + * @author Jerry + * @date 2024-04-15 + */ +@AllArgsConstructor +public class AddSequenceMultiInstanceCmd implements Command> { + + /** + * 现有的Assignee列表,并逗号分隔。 + */ + private String originalAssignees; + /** + * 当前任务编号。 + */ + private String taskId; + /** + * 被加签人。 + */ + private List newAssignees; + /** + * 是否为前加签。 + */ + private boolean before; + + @Override + public List execute(CommandContext commandContext) { + ProcessEngineConfigurationImpl processEngineConfiguration = + CommandContextUtil.getProcessEngineConfiguration(commandContext); + TaskEntityManager taskEntityManager = + processEngineConfiguration.getTaskServiceConfiguration().getTaskEntityManager(); + ExecutionEntityManager executionEntityManager = processEngineConfiguration.getExecutionEntityManager(); + //根据任务id获取任务实例 + TaskEntity taskEntity = taskEntityManager.findById(taskId); + //根据执行实例ID获取当前执行实例 + ExecutionEntity currentExecutionEntity = executionEntityManager.findById(taskEntity.getExecutionId()); + //获取多实例的根执行实例 + ExecutionEntity multiExecutionEntity = searchForMultiInstanceActivity(taskEntity, executionEntityManager); + //判断当前执行实例的节点是否是多实例节点 + BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(multiExecutionEntity.getProcessDefinitionId()); + Activity miActivityElement = (Activity) bpmnModel.getFlowElement(multiExecutionEntity.getCurrentActivityId()); + MultiInstanceLoopCharacteristics loopCharacteristics = miActivityElement.getLoopCharacteristics(); + if (loopCharacteristics == null) { + throw new FlowableException("此节点不是多实例节点"); + } + //判断是否是串行行多实例 + if (!loopCharacteristics.isSequential()) { + throw new FlowableException("此节点为串行节点"); + } + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + //获取多实例用户的变量 + List collectionUsers = StrUtil.split(this.originalAssignees, ","); + //获取当前任务在多实例中的次序 + Integer loopCounter = currentExecutionEntity.getVariableLocal("loopCounter", Integer.class); + //操作多实例用户的变量 + if (before) { + collectionUsers.addAll(loopCounter, this.newAssignees); + runtimeService.setVariable(taskEntity.getProcessInstanceId(), FlowConstant.MULTI_ASSIGNEE_LIST_VAR, collectionUsers); + //更新任务办理人 + TaskHelper.changeTaskAssignee(taskEntity, newAssignees.get(0)); + } else { + collectionUsers.addAll(loopCounter + 1, this.newAssignees); + runtimeService.setVariable(taskEntity.getProcessInstanceId(), FlowConstant.MULTI_ASSIGNEE_LIST_VAR, collectionUsers); + } + //增加多实例实例数内置变量 + Integer nrOfInstances = (Integer) multiExecutionEntity.getVariableLocal(FlowConstant.NUMBER_OF_INSTANCES_VAR); + multiExecutionEntity.setVariableLocal(FlowConstant.NUMBER_OF_INSTANCES_VAR, nrOfInstances + newAssignees.size()); + return collectionUsers; + } + + protected ExecutionEntity searchForMultiInstanceActivity( + TaskEntity taskEntity, ExecutionEntityManager executionEntityManager) { + ExecutionEntity miExecution = null; + ExecutionEntity taskExecution = + executionEntityManager.findById(taskEntity.getExecutionId()); + ExecutionEntity parentExecution = + executionEntityManager.findById(taskExecution.getParentId()); + if (taskEntity.getTaskDefinitionKey().equals(parentExecution.getActivityId()) && parentExecution.isMultiInstanceRoot()) { + miExecution = parentExecution; + } + if (miExecution == null) { + throw new FlowableException("Multiple multi instance executions found for activity id " + taskEntity.getTaskDefinitionKey()); + } + return miExecution; + } +} diff --git a/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/constant/FlowApprovalType.java b/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/constant/FlowApprovalType.java index aa4de82c..3ab18e1a 100644 --- a/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/constant/FlowApprovalType.java +++ b/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/constant/FlowApprovalType.java @@ -56,6 +56,14 @@ public final class FlowApprovalType { * 多实例减签。 */ public static final String MULTI_MINUS_SIGN = "multi_minus_sign"; + /** + * 串行多实例前加签。 + */ + public static final String MULTI_BEFORE_CONSIGN = "multi_before_consign"; + /** + * 串行多实例后加签。 + */ + public static final String MULTI_AFTER_CONSIGN = "multi_after_consign"; /** * 中止。 */ diff --git a/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/controller/FlowOperationController.java b/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/controller/FlowOperationController.java index f2d925fb..c1ffa347 100644 --- a/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/controller/FlowOperationController.java +++ b/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/controller/FlowOperationController.java @@ -319,6 +319,41 @@ public class FlowOperationController { return ResponseResult.success(resultList); } + /** + * 提交串行多实例加签或减签。 + * + * @param processInstanceId 流程实例Id。 + * @param taskId 当前多实例任务中正在审批的实例。 + * @param newAssignees 加签减签人列表,多个指派人之间逗号分隔。 + * @param before 是否为前加签,true是前加签,否则后加签。 + * @return 应答结果。 + */ + @PostMapping("/submitSequenceConsign") + public ResponseResult submitSequenceConsign( + @MyRequestBody(required = true) String processInstanceId, + @MyRequestBody(required = true) String taskId, + @MyRequestBody(required = true) String newAssignees, + @MyRequestBody(required = true) Boolean before) { + String errorMessage; + ResponseResult verifyResult = this.doVerifySequenceMultiSign(processInstanceId, taskId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + Task activeMultiInstanceTask = verifyResult.getData(); + ResponseResult assigneeVerifyResult = + this.doVerifyConsignAssignee(activeMultiInstanceTask, newAssignees, true); + if (!assigneeVerifyResult.isSuccess()) { + return ResponseResult.errorFrom(assigneeVerifyResult); + } + try { + flowApiService.submitSequenceConsign(activeMultiInstanceTask, newAssignees, before); + } catch (FlowOperationException e) { + errorMessage = e.getMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + return ResponseResult.success(); + } + /** * 提交多实例加签或减签。 * NOTE: 白名单接口。 @@ -350,28 +385,10 @@ public class FlowOperationController { if (isAdd == null) { isAdd = true; } - if (!isAdd) { - List commentList = - flowTaskCommentService.getFlowTaskCommentListByMultiInstanceExecId(multiInstanceExecId); - if (CollUtil.isNotEmpty(commentList)) { - Set approvedAssigneeSet = commentList.stream() - .map(FlowTaskComment::getCreateLoginName).collect(Collectors.toSet()); - String loginName = this.findExistAssignee(approvedAssigneeSet, assigneeArray); - if (loginName != null) { - errorMessage = "数据验证失败,用户 [" + loginName + "] 已经审批,不能减签该用户!"; - return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); - } - } - } else { - // 避免同一人被重复加签。 - FlowMultiInstanceTrans trans = - flowMultiInstanceTransService.getWithAssigneeListByMultiInstanceExecId(multiInstanceExecId); - Set assigneeSet = new HashSet<>(StrUtil.split(trans.getAssigneeList(), ",")); - String loginName = this.findExistAssignee(assigneeSet, assigneeArray); - if (loginName != null) { - errorMessage = "数据验证失败,用户 [" + loginName + "] 已经是会签人,不能重复指定!"; - return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); - } + ResponseResult assigneeVerifyResult = + this.doVerifyConsignAssignee(activeMultiInstanceTask, newAssignees, isAdd); + if (!assigneeVerifyResult.isSuccess()) { + return ResponseResult.errorFrom(assigneeVerifyResult); } try { flowApiService.submitConsign(taskInstance, activeMultiInstanceTask, newAssignees, isAdd); @@ -937,6 +954,58 @@ public class FlowOperationController { return taskCommentList; } + private ResponseResult doVerifyConsignAssignee(Task activeMultiInstanceTask, String newAssignees, Boolean isAdd) { + String errorMessage; + String multiInstanceExecId = flowApiService.getExecutionVariableStringWithSafe( + activeMultiInstanceTask.getExecutionId(), FlowConstant.MULTI_SIGN_TASK_EXECUTION_ID_VAR); + JSONArray assigneeArray = JSON.parseArray(newAssignees); + if (BooleanUtil.isFalse(isAdd)) { + List commentList = + flowTaskCommentService.getFlowTaskCommentListByMultiInstanceExecId(multiInstanceExecId); + if (CollUtil.isNotEmpty(commentList)) { + Set approvedAssigneeSet = commentList.stream() + .map(FlowTaskComment::getCreateLoginName).collect(Collectors.toSet()); + String existAssignee = this.findExistAssignee(approvedAssigneeSet, assigneeArray); + if (existAssignee != null) { + errorMessage = "数据验证失败,用户 [" + existAssignee + "] 已经审批,不能减签该用户!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + } else { + // 避免同一人被重复加签。 + FlowMultiInstanceTrans trans = + flowMultiInstanceTransService.getWithAssigneeListByMultiInstanceExecId(multiInstanceExecId); + Set assigneeSet = new HashSet<>(StrUtil.split(trans.getAssigneeList(), ",")); + String existAssignee = this.findExistAssignee(assigneeSet, assigneeArray); + if (existAssignee != null) { + errorMessage = "数据验证失败,用户 [" + existAssignee + "] 已经是会签人,不能重复指定!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + return ResponseResult.success(); + } + + private ResponseResult doVerifySequenceMultiSign(String processInstanceId, String taskId) { + String errorMessage; + if (!flowApiService.existActiveProcessInstance(processInstanceId)) { + errorMessage = "数据验证失败,当前流程实例已经结束,不能执行加签!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + List activeTaskList = flowApiService.getProcessInstanceActiveTaskList(processInstanceId); + Task task = activeTaskList.stream().filter(t -> t.getId().equals(taskId)).findFirst().orElse(null); + if (task == null) { + errorMessage = "数据验证失败,当前任务已经不是待审批任务!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + Map userTaskMap = flowApiService.getAllUserTaskMap(task.getProcessDefinitionId()); + UserTask userTask = userTaskMap.get(task.getTaskDefinitionKey()); + if (!userTask.hasMultiInstanceLoopCharacteristics() || !userTask.getLoopCharacteristics().isSequential()) { + errorMessage = "数据验证失败,当前任务不是串行会签多实例任务!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + return ResponseResult.success(task); + } + private ResponseResult doVerifyMultiSign(String processInstanceId, String taskId) { String errorMessage; if (!flowApiService.existActiveProcessInstance(processInstanceId)) { @@ -959,7 +1028,7 @@ public class FlowOperationController { for (Task activeTask : activeTaskList) { UserTask userTask = userTaskMap.get(activeTask.getTaskDefinitionKey()); if (!userTask.hasMultiInstanceLoopCharacteristics()) { - errorMessage = "数据验证失败,指定加签任务不存在或已审批完毕!"; + errorMessage = "数据验证失败,当前任务不是会签多实例任务!"; return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); } String startTaskId = flowApiService.getTaskVariableStringWithSafe( diff --git a/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/service/FlowApiService.java b/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/service/FlowApiService.java index 892ea587..edebe800 100644 --- a/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/service/FlowApiService.java +++ b/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/service/FlowApiService.java @@ -79,6 +79,15 @@ public interface FlowApiService { */ void submitConsign(HistoricTaskInstance startTaskInstance, Task multiInstanceActiveTask, String newAssignees, boolean isAdd); + /** + * 串行多实例加签减签。 + * + * @param multiInstanceActiveTask 正在执行的多实例任务对象。 + * @param newAssignees 新指派人,多个指派人之间逗号分隔。 + * @param before 是否为前加签,true是前加签,否则后加签。 + */ + void submitSequenceConsign(Task multiInstanceActiveTask, String newAssignees, boolean before); + /** * 完成任务,同时提交审批数据。 * diff --git a/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/service/impl/FlowApiServiceImpl.java b/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/service/impl/FlowApiServiceImpl.java index 164d5486..f24ec9c5 100644 --- a/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/service/impl/FlowApiServiceImpl.java +++ b/OrangeFormsOpen-MybatisFlex/common/common-flow/src/main/java/com/orangeforms/common/flow/service/impl/FlowApiServiceImpl.java @@ -17,6 +17,7 @@ import com.orangeforms.common.core.object.*; import com.orangeforms.common.core.util.MyDateUtil; import com.orangeforms.common.core.util.MyCommonUtil; import com.orangeforms.common.core.util.DefaultDataSourceResolver; +import com.orangeforms.common.flow.cmd.AddSequenceMultiInstanceCmd; import com.orangeforms.common.flow.exception.FlowOperationException; import com.orangeforms.common.flow.object.*; import com.orangeforms.common.flow.constant.FlowConstant; @@ -199,6 +200,31 @@ public class FlowApiServiceImpl implements FlowApiService { flowTaskCommentService.saveNew(flowTaskComment); } + @Transactional(rollbackFor = Exception.class) + @Override + public void submitSequenceConsign(Task multiInstanceActiveTask, String newAssignees, boolean before) { + JSONArray assigneeArray = JSON.parseArray(newAssignees); + List newAssigneeList = new LinkedList<>(); + for (int i = 0; i < assigneeArray.size(); i++) { + newAssigneeList.add(assigneeArray.getString(i)); + } + String multiInstanceExecId = this.getExecutionVariableStringWithSafe( + multiInstanceActiveTask.getExecutionId(), FlowConstant.MULTI_SIGN_TASK_EXECUTION_ID_VAR); + FlowMultiInstanceTrans trans = + flowMultiInstanceTransService.getWithAssigneeListByMultiInstanceExecId(multiInstanceExecId); + List updatedAssignees = managementService.executeCommand( + new AddSequenceMultiInstanceCmd(trans.getAssigneeList(), multiInstanceActiveTask.getId(), newAssigneeList, before)); + trans.setAssigneeList(StrUtil.join(",", updatedAssignees)); + flowMultiInstanceTransService.updateById(trans); + FlowTaskComment flowTaskComment = new FlowTaskComment(); + flowTaskComment.fillWith(multiInstanceActiveTask); + flowTaskComment.setApprovalType(before ? FlowApprovalType.MULTI_BEFORE_CONSIGN : FlowApprovalType.MULTI_AFTER_CONSIGN); + String showName = TokenData.takeFromRequest().getLoginName(); + String comment = String.format("用户 [%s] [%s] [%s]。", before ? "前加签" : "后加签", showName, newAssignees); + flowTaskComment.setTaskComment(comment); + flowTaskCommentService.saveNew(flowTaskComment); + } + @Transactional(rollbackFor = Exception.class) @Override public void completeTask(Task task, FlowTaskComment flowTaskComment, JSONObject taskVariableData) { diff --git a/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/cmd/AddSequenceMultiInstanceCmd.java b/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/cmd/AddSequenceMultiInstanceCmd.java new file mode 100644 index 00000000..99f33601 --- /dev/null +++ b/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/cmd/AddSequenceMultiInstanceCmd.java @@ -0,0 +1,110 @@ +package com.orangeforms.common.flow.cmd; + +import cn.hutool.core.util.StrUtil; +import com.orangeforms.common.flow.constant.FlowConstant; +import lombok.AllArgsConstructor; +import org.flowable.bpmn.model.Activity; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.MultiInstanceLoopCharacteristics; +import org.flowable.common.engine.api.FlowableException; +import org.flowable.common.engine.impl.interceptor.Command; +import org.flowable.common.engine.impl.interceptor.CommandContext; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.engine.impl.persistence.entity.ExecutionEntity; +import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager; +import org.flowable.engine.impl.util.CommandContextUtil; +import org.flowable.engine.impl.util.ProcessDefinitionUtil; +import org.flowable.engine.impl.util.TaskHelper; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; +import org.flowable.task.service.impl.persistence.entity.TaskEntityManager; + +import java.util.List; + +/** + * 串行会签任务前后加签的命令对象。 + * + * @author Jerry + * @date 2024-04-15 + */ +@AllArgsConstructor +public class AddSequenceMultiInstanceCmd implements Command> { + + /** + * 现有的Assignee列表,并逗号分隔。 + */ + private String originalAssignees; + /** + * 当前任务编号。 + */ + private String taskId; + /** + * 被加签人。 + */ + private List newAssignees; + /** + * 是否为前加签。 + */ + private boolean before; + + @Override + public List execute(CommandContext commandContext) { + ProcessEngineConfigurationImpl processEngineConfiguration = + CommandContextUtil.getProcessEngineConfiguration(commandContext); + TaskEntityManager taskEntityManager = + processEngineConfiguration.getTaskServiceConfiguration().getTaskEntityManager(); + ExecutionEntityManager executionEntityManager = processEngineConfiguration.getExecutionEntityManager(); + //根据任务id获取任务实例 + TaskEntity taskEntity = taskEntityManager.findById(taskId); + //根据执行实例ID获取当前执行实例 + ExecutionEntity currentExecutionEntity = executionEntityManager.findById(taskEntity.getExecutionId()); + //获取多实例的根执行实例 + ExecutionEntity multiExecutionEntity = searchForMultiInstanceActivity(taskEntity, executionEntityManager); + //判断当前执行实例的节点是否是多实例节点 + BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(multiExecutionEntity.getProcessDefinitionId()); + Activity miActivityElement = (Activity) bpmnModel.getFlowElement(multiExecutionEntity.getCurrentActivityId()); + MultiInstanceLoopCharacteristics loopCharacteristics = miActivityElement.getLoopCharacteristics(); + if (loopCharacteristics == null) { + throw new FlowableException("此节点不是多实例节点"); + } + //判断是否是串行行多实例 + if (!loopCharacteristics.isSequential()) { + throw new FlowableException("此节点为串行节点"); + } + RuntimeService runtimeService = processEngineConfiguration.getRuntimeService(); + //获取多实例用户的变量 + List collectionUsers = StrUtil.split(this.originalAssignees, ","); + //获取当前任务在多实例中的次序 + Integer loopCounter = currentExecutionEntity.getVariableLocal("loopCounter", Integer.class); + //操作多实例用户的变量 + if (before) { + collectionUsers.addAll(loopCounter, this.newAssignees); + runtimeService.setVariable(taskEntity.getProcessInstanceId(), FlowConstant.MULTI_ASSIGNEE_LIST_VAR, collectionUsers); + //更新任务办理人 + TaskHelper.changeTaskAssignee(taskEntity, newAssignees.get(0)); + } else { + collectionUsers.addAll(loopCounter + 1, this.newAssignees); + runtimeService.setVariable(taskEntity.getProcessInstanceId(), FlowConstant.MULTI_ASSIGNEE_LIST_VAR, collectionUsers); + } + //增加多实例实例数内置变量 + Integer nrOfInstances = (Integer) multiExecutionEntity.getVariableLocal(FlowConstant.NUMBER_OF_INSTANCES_VAR); + multiExecutionEntity.setVariableLocal(FlowConstant.NUMBER_OF_INSTANCES_VAR, nrOfInstances + newAssignees.size()); + return collectionUsers; + } + + protected ExecutionEntity searchForMultiInstanceActivity( + TaskEntity taskEntity, ExecutionEntityManager executionEntityManager) { + ExecutionEntity miExecution = null; + ExecutionEntity taskExecution = + executionEntityManager.findById(taskEntity.getExecutionId()); + ExecutionEntity parentExecution = + executionEntityManager.findById(taskExecution.getParentId()); + if (taskEntity.getTaskDefinitionKey().equals(parentExecution.getActivityId()) && parentExecution.isMultiInstanceRoot()) { + miExecution = parentExecution; + } + if (miExecution == null) { + throw new FlowableException("Multiple multi instance executions found for activity id " + taskEntity.getTaskDefinitionKey()); + } + return miExecution; + } +} diff --git a/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/constant/FlowApprovalType.java b/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/constant/FlowApprovalType.java index aa4de82c..3ab18e1a 100644 --- a/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/constant/FlowApprovalType.java +++ b/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/constant/FlowApprovalType.java @@ -56,6 +56,14 @@ public final class FlowApprovalType { * 多实例减签。 */ public static final String MULTI_MINUS_SIGN = "multi_minus_sign"; + /** + * 串行多实例前加签。 + */ + public static final String MULTI_BEFORE_CONSIGN = "multi_before_consign"; + /** + * 串行多实例后加签。 + */ + public static final String MULTI_AFTER_CONSIGN = "multi_after_consign"; /** * 中止。 */ diff --git a/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/controller/FlowOperationController.java b/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/controller/FlowOperationController.java index 3671955e..73302281 100644 --- a/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/controller/FlowOperationController.java +++ b/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/controller/FlowOperationController.java @@ -319,6 +319,41 @@ public class FlowOperationController { return ResponseResult.success(resultList); } + /** + * 提交串行多实例加签或减签。 + * + * @param processInstanceId 流程实例Id。 + * @param taskId 当前多实例任务中正在审批的实例。 + * @param newAssignees 加签减签人列表,多个指派人之间逗号分隔。 + * @param before 是否为前加签,true是前加签,否则后加签。 + * @return 应答结果。 + */ + @PostMapping("/submitSequenceConsign") + public ResponseResult submitSequenceConsign( + @MyRequestBody(required = true) String processInstanceId, + @MyRequestBody(required = true) String taskId, + @MyRequestBody(required = true) String newAssignees, + @MyRequestBody(required = true) Boolean before) { + String errorMessage; + ResponseResult verifyResult = this.doVerifySequenceMultiSign(processInstanceId, taskId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + Task activeMultiInstanceTask = verifyResult.getData(); + ResponseResult assigneeVerifyResult = + this.doVerifyConsignAssignee(activeMultiInstanceTask, newAssignees, true); + if (!assigneeVerifyResult.isSuccess()) { + return ResponseResult.errorFrom(assigneeVerifyResult); + } + try { + flowApiService.submitSequenceConsign(activeMultiInstanceTask, newAssignees, before); + } catch (FlowOperationException e) { + errorMessage = e.getMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + return ResponseResult.success(); + } + /** * 提交多实例加签或减签。 * NOTE: 白名单接口。 @@ -350,28 +385,10 @@ public class FlowOperationController { if (isAdd == null) { isAdd = true; } - if (!isAdd) { - List commentList = - flowTaskCommentService.getFlowTaskCommentListByMultiInstanceExecId(multiInstanceExecId); - if (CollUtil.isNotEmpty(commentList)) { - Set approvedAssigneeSet = commentList.stream() - .map(FlowTaskComment::getCreateLoginName).collect(Collectors.toSet()); - String loginName = this.findExistAssignee(approvedAssigneeSet, assigneeArray); - if (loginName != null) { - errorMessage = "数据验证失败,用户 [" + loginName + "] 已经审批,不能减签该用户!"; - return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); - } - } - } else { - // 避免同一人被重复加签。 - FlowMultiInstanceTrans trans = - flowMultiInstanceTransService.getWithAssigneeListByMultiInstanceExecId(multiInstanceExecId); - Set assigneeSet = new HashSet<>(StrUtil.split(trans.getAssigneeList(), ",")); - String loginName = this.findExistAssignee(assigneeSet, assigneeArray); - if (loginName != null) { - errorMessage = "数据验证失败,用户 [" + loginName + "] 已经是会签人,不能重复指定!"; - return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); - } + ResponseResult assigneeVerifyResult = + this.doVerifyConsignAssignee(activeMultiInstanceTask, newAssignees, isAdd); + if (!assigneeVerifyResult.isSuccess()) { + return ResponseResult.errorFrom(assigneeVerifyResult); } try { flowApiService.submitConsign(taskInstance, activeMultiInstanceTask, newAssignees, isAdd); @@ -937,6 +954,58 @@ public class FlowOperationController { return taskCommentList; } + private ResponseResult doVerifyConsignAssignee(Task activeMultiInstanceTask, String newAssignees, Boolean isAdd) { + String errorMessage; + String multiInstanceExecId = flowApiService.getExecutionVariableStringWithSafe( + activeMultiInstanceTask.getExecutionId(), FlowConstant.MULTI_SIGN_TASK_EXECUTION_ID_VAR); + JSONArray assigneeArray = JSON.parseArray(newAssignees); + if (BooleanUtil.isFalse(isAdd)) { + List commentList = + flowTaskCommentService.getFlowTaskCommentListByMultiInstanceExecId(multiInstanceExecId); + if (CollUtil.isNotEmpty(commentList)) { + Set approvedAssigneeSet = commentList.stream() + .map(FlowTaskComment::getCreateLoginName).collect(Collectors.toSet()); + String existAssignee = this.findExistAssignee(approvedAssigneeSet, assigneeArray); + if (existAssignee != null) { + errorMessage = "数据验证失败,用户 [" + existAssignee + "] 已经审批,不能减签该用户!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + } else { + // 避免同一人被重复加签。 + FlowMultiInstanceTrans trans = + flowMultiInstanceTransService.getWithAssigneeListByMultiInstanceExecId(multiInstanceExecId); + Set assigneeSet = new HashSet<>(StrUtil.split(trans.getAssigneeList(), ",")); + String existAssignee = this.findExistAssignee(assigneeSet, assigneeArray); + if (existAssignee != null) { + errorMessage = "数据验证失败,用户 [" + existAssignee + "] 已经是会签人,不能重复指定!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + return ResponseResult.success(); + } + + private ResponseResult doVerifySequenceMultiSign(String processInstanceId, String taskId) { + String errorMessage; + if (!flowApiService.existActiveProcessInstance(processInstanceId)) { + errorMessage = "数据验证失败,当前流程实例已经结束,不能执行加签!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + List activeTaskList = flowApiService.getProcessInstanceActiveTaskList(processInstanceId); + Task task = activeTaskList.stream().filter(t -> t.getId().equals(taskId)).findFirst().orElse(null); + if (task == null) { + errorMessage = "数据验证失败,当前任务已经不是待审批任务!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + Map userTaskMap = flowApiService.getAllUserTaskMap(task.getProcessDefinitionId()); + UserTask userTask = userTaskMap.get(task.getTaskDefinitionKey()); + if (!userTask.hasMultiInstanceLoopCharacteristics() || !userTask.getLoopCharacteristics().isSequential()) { + errorMessage = "数据验证失败,当前任务不是串行会签多实例任务!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + return ResponseResult.success(task); + } + private ResponseResult doVerifyMultiSign(String processInstanceId, String taskId) { String errorMessage; if (!flowApiService.existActiveProcessInstance(processInstanceId)) { @@ -959,7 +1028,7 @@ public class FlowOperationController { for (Task activeTask : activeTaskList) { UserTask userTask = userTaskMap.get(activeTask.getTaskDefinitionKey()); if (!userTask.hasMultiInstanceLoopCharacteristics()) { - errorMessage = "数据验证失败,指定加签任务不存在或已审批完毕!"; + errorMessage = "数据验证失败,当前任务不是会签多实例任务!"; return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); } String startTaskId = flowApiService.getTaskVariableStringWithSafe( diff --git a/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/service/FlowApiService.java b/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/service/FlowApiService.java index 892ea587..edebe800 100644 --- a/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/service/FlowApiService.java +++ b/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/service/FlowApiService.java @@ -79,6 +79,15 @@ public interface FlowApiService { */ void submitConsign(HistoricTaskInstance startTaskInstance, Task multiInstanceActiveTask, String newAssignees, boolean isAdd); + /** + * 串行多实例加签减签。 + * + * @param multiInstanceActiveTask 正在执行的多实例任务对象。 + * @param newAssignees 新指派人,多个指派人之间逗号分隔。 + * @param before 是否为前加签,true是前加签,否则后加签。 + */ + void submitSequenceConsign(Task multiInstanceActiveTask, String newAssignees, boolean before); + /** * 完成任务,同时提交审批数据。 * diff --git a/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/service/impl/FlowApiServiceImpl.java b/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/service/impl/FlowApiServiceImpl.java index 7699f795..011f82b8 100644 --- a/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/service/impl/FlowApiServiceImpl.java +++ b/OrangeFormsOpen-MybatisPlus/common/common-flow/src/main/java/com/orangeforms/common/flow/service/impl/FlowApiServiceImpl.java @@ -19,6 +19,7 @@ import com.orangeforms.common.core.object.*; import com.orangeforms.common.core.util.DefaultDataSourceResolver; import com.orangeforms.common.core.util.MyCommonUtil; import com.orangeforms.common.core.util.MyDateUtil; +import com.orangeforms.common.flow.cmd.AddSequenceMultiInstanceCmd; import com.orangeforms.common.flow.constant.FlowApprovalType; import com.orangeforms.common.flow.constant.FlowConstant; import com.orangeforms.common.flow.constant.FlowTaskStatus; @@ -206,6 +207,31 @@ public class FlowApiServiceImpl implements FlowApiService { flowTaskCommentService.saveNew(flowTaskComment); } + @Transactional(rollbackFor = Exception.class) + @Override + public void submitSequenceConsign(Task multiInstanceActiveTask, String newAssignees, boolean before) { + JSONArray assigneeArray = JSON.parseArray(newAssignees); + List newAssigneeList = new LinkedList<>(); + for (int i = 0; i < assigneeArray.size(); i++) { + newAssigneeList.add(assigneeArray.getString(i)); + } + String multiInstanceExecId = this.getExecutionVariableStringWithSafe( + multiInstanceActiveTask.getExecutionId(), FlowConstant.MULTI_SIGN_TASK_EXECUTION_ID_VAR); + FlowMultiInstanceTrans trans = + flowMultiInstanceTransService.getWithAssigneeListByMultiInstanceExecId(multiInstanceExecId); + List updatedAssignees = managementService.executeCommand( + new AddSequenceMultiInstanceCmd(trans.getAssigneeList(), multiInstanceActiveTask.getId(), newAssigneeList, before)); + trans.setAssigneeList(StrUtil.join(",", updatedAssignees)); + flowMultiInstanceTransService.updateById(trans); + FlowTaskComment flowTaskComment = new FlowTaskComment(); + flowTaskComment.fillWith(multiInstanceActiveTask); + flowTaskComment.setApprovalType(before ? FlowApprovalType.MULTI_BEFORE_CONSIGN : FlowApprovalType.MULTI_AFTER_CONSIGN); + String showName = TokenData.takeFromRequest().getLoginName(); + String comment = String.format("用户 [%s] [%s] [%s]。", before ? "前加签" : "后加签", showName, newAssignees); + flowTaskComment.setTaskComment(comment); + flowTaskCommentService.saveNew(flowTaskComment); + } + @Transactional(rollbackFor = Exception.class) @Override public void completeTask(Task task, FlowTaskComment flowTaskComment, JSONObject taskVariableData) {