mirror of
https://gitee.com/orangeform/orange-admin.git
synced 2026-01-17 10:36:31 +08:00
commit:支持服务、接收任务,支持串行会签
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -56,6 +56,14 @@ public final class FlowApprovalType {
|
|||||||
* 多实例减签。
|
* 多实例减签。
|
||||||
*/
|
*/
|
||||||
public static final String MULTI_MINUS_SIGN = "multi_minus_sign";
|
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";
|
||||||
/**
|
/**
|
||||||
* 中止。
|
* 中止。
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -319,6 +319,41 @@ public class FlowOperationController {
|
|||||||
return ResponseResult.success(resultList);
|
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: 白名单接口。
|
* NOTE: 白名单接口。
|
||||||
@@ -350,28 +385,10 @@ public class FlowOperationController {
|
|||||||
if (isAdd == null) {
|
if (isAdd == null) {
|
||||||
isAdd = true;
|
isAdd = true;
|
||||||
}
|
}
|
||||||
if (!isAdd) {
|
ResponseResult<Void> assigneeVerifyResult =
|
||||||
List<FlowTaskComment> commentList =
|
this.doVerifyConsignAssignee(activeMultiInstanceTask, newAssignees, isAdd);
|
||||||
flowTaskCommentService.getFlowTaskCommentListByMultiInstanceExecId(multiInstanceExecId);
|
if (!assigneeVerifyResult.isSuccess()) {
|
||||||
if (CollUtil.isNotEmpty(commentList)) {
|
return ResponseResult.errorFrom(assigneeVerifyResult);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
flowApiService.submitConsign(taskInstance, activeMultiInstanceTask, newAssignees, isAdd);
|
flowApiService.submitConsign(taskInstance, activeMultiInstanceTask, newAssignees, isAdd);
|
||||||
@@ -937,6 +954,58 @@ public class FlowOperationController {
|
|||||||
return taskCommentList;
|
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) {
|
private ResponseResult<JSONObject> doVerifyMultiSign(String processInstanceId, String taskId) {
|
||||||
String errorMessage;
|
String errorMessage;
|
||||||
if (!flowApiService.existActiveProcessInstance(processInstanceId)) {
|
if (!flowApiService.existActiveProcessInstance(processInstanceId)) {
|
||||||
@@ -959,7 +1028,7 @@ public class FlowOperationController {
|
|||||||
for (Task activeTask : activeTaskList) {
|
for (Task activeTask : activeTaskList) {
|
||||||
UserTask userTask = userTaskMap.get(activeTask.getTaskDefinitionKey());
|
UserTask userTask = userTaskMap.get(activeTask.getTaskDefinitionKey());
|
||||||
if (!userTask.hasMultiInstanceLoopCharacteristics()) {
|
if (!userTask.hasMultiInstanceLoopCharacteristics()) {
|
||||||
errorMessage = "数据验证失败,指定加签任务不存在或已审批完毕!";
|
errorMessage = "数据验证失败,当前任务不是会签多实例任务!";
|
||||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||||
}
|
}
|
||||||
String startTaskId = flowApiService.getTaskVariableStringWithSafe(
|
String startTaskId = flowApiService.getTaskVariableStringWithSafe(
|
||||||
|
|||||||
@@ -79,6 +79,15 @@ public interface FlowApiService {
|
|||||||
*/
|
*/
|
||||||
void submitConsign(HistoricTaskInstance startTaskInstance, Task multiInstanceActiveTask, String newAssignees, boolean isAdd);
|
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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 完成任务,同时提交审批数据。
|
* 完成任务,同时提交审批数据。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import com.orangeforms.common.core.object.*;
|
|||||||
import com.orangeforms.common.core.util.MyDateUtil;
|
import com.orangeforms.common.core.util.MyDateUtil;
|
||||||
import com.orangeforms.common.core.util.MyCommonUtil;
|
import com.orangeforms.common.core.util.MyCommonUtil;
|
||||||
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
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.exception.FlowOperationException;
|
||||||
import com.orangeforms.common.flow.object.*;
|
import com.orangeforms.common.flow.object.*;
|
||||||
import com.orangeforms.common.flow.constant.FlowConstant;
|
import com.orangeforms.common.flow.constant.FlowConstant;
|
||||||
@@ -199,6 +200,31 @@ public class FlowApiServiceImpl implements FlowApiService {
|
|||||||
flowTaskCommentService.saveNew(flowTaskComment);
|
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)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@Override
|
@Override
|
||||||
public void completeTask(Task task, FlowTaskComment flowTaskComment, JSONObject taskVariableData) {
|
public void completeTask(Task task, FlowTaskComment flowTaskComment, JSONObject taskVariableData) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -56,6 +56,14 @@ public final class FlowApprovalType {
|
|||||||
* 多实例减签。
|
* 多实例减签。
|
||||||
*/
|
*/
|
||||||
public static final String MULTI_MINUS_SIGN = "multi_minus_sign";
|
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";
|
||||||
/**
|
/**
|
||||||
* 中止。
|
* 中止。
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -319,6 +319,41 @@ public class FlowOperationController {
|
|||||||
return ResponseResult.success(resultList);
|
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: 白名单接口。
|
* NOTE: 白名单接口。
|
||||||
@@ -350,28 +385,10 @@ public class FlowOperationController {
|
|||||||
if (isAdd == null) {
|
if (isAdd == null) {
|
||||||
isAdd = true;
|
isAdd = true;
|
||||||
}
|
}
|
||||||
if (!isAdd) {
|
ResponseResult<Void> assigneeVerifyResult =
|
||||||
List<FlowTaskComment> commentList =
|
this.doVerifyConsignAssignee(activeMultiInstanceTask, newAssignees, isAdd);
|
||||||
flowTaskCommentService.getFlowTaskCommentListByMultiInstanceExecId(multiInstanceExecId);
|
if (!assigneeVerifyResult.isSuccess()) {
|
||||||
if (CollUtil.isNotEmpty(commentList)) {
|
return ResponseResult.errorFrom(assigneeVerifyResult);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
flowApiService.submitConsign(taskInstance, activeMultiInstanceTask, newAssignees, isAdd);
|
flowApiService.submitConsign(taskInstance, activeMultiInstanceTask, newAssignees, isAdd);
|
||||||
@@ -937,6 +954,58 @@ public class FlowOperationController {
|
|||||||
return taskCommentList;
|
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) {
|
private ResponseResult<JSONObject> doVerifyMultiSign(String processInstanceId, String taskId) {
|
||||||
String errorMessage;
|
String errorMessage;
|
||||||
if (!flowApiService.existActiveProcessInstance(processInstanceId)) {
|
if (!flowApiService.existActiveProcessInstance(processInstanceId)) {
|
||||||
@@ -959,7 +1028,7 @@ public class FlowOperationController {
|
|||||||
for (Task activeTask : activeTaskList) {
|
for (Task activeTask : activeTaskList) {
|
||||||
UserTask userTask = userTaskMap.get(activeTask.getTaskDefinitionKey());
|
UserTask userTask = userTaskMap.get(activeTask.getTaskDefinitionKey());
|
||||||
if (!userTask.hasMultiInstanceLoopCharacteristics()) {
|
if (!userTask.hasMultiInstanceLoopCharacteristics()) {
|
||||||
errorMessage = "数据验证失败,指定加签任务不存在或已审批完毕!";
|
errorMessage = "数据验证失败,当前任务不是会签多实例任务!";
|
||||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||||
}
|
}
|
||||||
String startTaskId = flowApiService.getTaskVariableStringWithSafe(
|
String startTaskId = flowApiService.getTaskVariableStringWithSafe(
|
||||||
|
|||||||
@@ -79,6 +79,15 @@ public interface FlowApiService {
|
|||||||
*/
|
*/
|
||||||
void submitConsign(HistoricTaskInstance startTaskInstance, Task multiInstanceActiveTask, String newAssignees, boolean isAdd);
|
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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 完成任务,同时提交审批数据。
|
* 完成任务,同时提交审批数据。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import com.orangeforms.common.core.object.*;
|
|||||||
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
|
||||||
import com.orangeforms.common.core.util.MyCommonUtil;
|
import com.orangeforms.common.core.util.MyCommonUtil;
|
||||||
import com.orangeforms.common.core.util.MyDateUtil;
|
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.FlowApprovalType;
|
||||||
import com.orangeforms.common.flow.constant.FlowConstant;
|
import com.orangeforms.common.flow.constant.FlowConstant;
|
||||||
import com.orangeforms.common.flow.constant.FlowTaskStatus;
|
import com.orangeforms.common.flow.constant.FlowTaskStatus;
|
||||||
@@ -206,6 +207,31 @@ public class FlowApiServiceImpl implements FlowApiService {
|
|||||||
flowTaskCommentService.saveNew(flowTaskComment);
|
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)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@Override
|
@Override
|
||||||
public void completeTask(Task task, FlowTaskComment flowTaskComment, JSONObject taskVariableData) {
|
public void completeTask(Task task, FlowTaskComment flowTaskComment, JSONObject taskVariableData) {
|
||||||
|
|||||||
Reference in New Issue
Block a user