commit:支持服务、接收任务,支持串行会签

This commit is contained in:
Jerry
2024-09-19 10:02:16 +08:00
parent e9a39c24ba
commit efac1ee620
10 changed files with 490 additions and 46 deletions

View File

@@ -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<List<String>> {
/**
* 现有的Assignee列表并逗号分隔。
*/
private String originalAssignees;
/**
* 当前任务编号。
*/
private String taskId;
/**
* 被加签人。
*/
private List<String> newAssignees;
/**
* 是否为前加签。
*/
private boolean before;
@Override
public List<String> 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<String> 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;
}
}

View File

@@ -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";
/**
* 中止。
*/

View File

@@ -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<Void> submitSequenceConsign(
@MyRequestBody(required = true) String processInstanceId,
@MyRequestBody(required = true) String taskId,
@MyRequestBody(required = true) String newAssignees,
@MyRequestBody(required = true) Boolean before) {
String errorMessage;
ResponseResult<Task> verifyResult = this.doVerifySequenceMultiSign(processInstanceId, taskId);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
Task activeMultiInstanceTask = verifyResult.getData();
ResponseResult<Void> 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<FlowTaskComment> commentList =
flowTaskCommentService.getFlowTaskCommentListByMultiInstanceExecId(multiInstanceExecId);
if (CollUtil.isNotEmpty(commentList)) {
Set<String> 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<String> 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<Void> 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<Void> 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<FlowTaskComment> commentList =
flowTaskCommentService.getFlowTaskCommentListByMultiInstanceExecId(multiInstanceExecId);
if (CollUtil.isNotEmpty(commentList)) {
Set<String> 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<String> 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<Task> doVerifySequenceMultiSign(String processInstanceId, String taskId) {
String errorMessage;
if (!flowApiService.existActiveProcessInstance(processInstanceId)) {
errorMessage = "数据验证失败,当前流程实例已经结束,不能执行加签!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
List<Task> 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<String, UserTask> 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<JSONObject> 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(

View File

@@ -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);
/**
* 完成任务,同时提交审批数据。
*

View File

@@ -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<String> 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<String> 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) {