feat:1.公共组件

This commit is contained in:
zuoqinbo 2023-11-14 10:57:49 +08:00
parent a5b3c25219
commit 2ea93ebeb5

View File

@ -1,13 +1,9 @@
package cn.axzo.workflow.core.service.impl;
import cn.axzo.framework.core.util.StringUtil;
import cn.axzo.workflow.common.enums.BpmnCountersignType;
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAssigneeDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.*;
import cn.axzo.workflow.common.model.response.BpmPageResult;
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO;
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO;
@ -15,6 +11,7 @@ import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO;
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO;
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.engine.id.TimeBasedIdGenerator;
import cn.axzo.workflow.core.service.BpmnTaskService;
import cn.axzo.workflow.core.service.converter.BpmnHistoricCommentConverter;
import cn.axzo.workflow.core.service.converter.BpmnHistoricTaskInstanceConverter;
@ -22,11 +19,9 @@ import cn.axzo.workflow.core.service.converter.BpmnTaskConverter;
import cn.axzo.workflow.core.service.converter.BpmnTaskDonePageItemConverter;
import cn.axzo.workflow.core.service.converter.BpmnTaskTodoPageItemConverter;
import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.Activity;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.UserTask;
import org.flowable.bpmn.model.*;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.HistoryService;
import org.flowable.engine.ManagementService;
@ -39,12 +34,14 @@ import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.form.api.FormInfo;
import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.flowable.task.service.history.NativeHistoricTaskInstanceQuery;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.flowable.variable.api.persistence.entity.VariableInstance;
import org.springframework.stereotype.Service;
@ -53,39 +50,17 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static cn.axzo.workflow.common.constant.BpmnConstants.APPROVAL_ENDS_AUTOMATICALLY;
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_DELETE_PROCESS_FLAG;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_END_TENANT_ID;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_END_USER_ID;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_END_USER_NAME;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_TYPE_REJECT;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_SPECIFY_NEXT_APPROVER;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT;
import static cn.axzo.workflow.common.constant.BpmnConstants.MULTI_INSTANCE_LOOP_COUNTER;
import static cn.axzo.workflow.common.constant.BpmnConstants.NUMBER_OF_INSTANCES;
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
import static cn.axzo.workflow.common.constant.BpmnConstants.*;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.CANCELLED;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.valueOfStatus;
import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.PROCESS_INSTANCE_ID_NOT_EXISTS;
import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.PROCESS_INSTANCE_NOT_EXISTS;
import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF;
import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.TASK_COMPLETE_FAIL_NOT_EXISTS;
import static cn.axzo.workflow.core.common.enums.BpmnErrorCode.*;
import static cn.axzo.workflow.core.common.utils.BpmnCollectionUtils.convertSet;
import static cn.axzo.workflow.core.common.utils.BpmnNativeQueryUtil.countSql;
import static cn.axzo.workflow.core.common.utils.BpmnNativeQueryUtil.sqlConnectors;
@ -209,7 +184,7 @@ public class BpmnTaskServiceImpl implements BpmnTaskService {
NativeHistoricTaskInstanceQuery nativeQuery = historyService.createNativeHistoricTaskInstanceQuery();
String tableName = managementService.getTableName(HistoricTaskInstance.class);
baseQuerySql.append("SELECT a.* FROM ").append(tableName).append(" a JOIN " +
"ACT_HI_PROCINST b")
"ACT_HI_PROCINST b")
.append(" ON b.PROC_INST_ID_ = a.PROC_INST_ID_");
if (StringUtils.hasLength(dto.getTenantId())) {
@ -288,10 +263,10 @@ public class BpmnTaskServiceImpl implements BpmnTaskService {
@Override
public void approveTask(BpmnTaskAuditDTO dto) {
// 校验任务存在
Task task = checkTask(dto.getApprover().getTenantId(), dto.getApprover().buildAssigneeId(), dto.getTaskId());
TaskEntity task = (TaskEntity) checkTask(dto.getApprover().getTenantId(), dto.getApprover().buildAssigneeId(), dto.getTaskId());
// 校验流程实例存在
HistoricProcessInstance instance = processInstanceService.getProcessInstance(
task.getProcessInstanceId(), null, true);
task.getProcessInstanceId(), dto.getApprover().getTenantId(), true);
if (instance == null) {
throw new WorkflowEngineException(PROCESS_INSTANCE_NOT_EXISTS);
}
@ -303,10 +278,123 @@ public class BpmnTaskServiceImpl implements BpmnTaskService {
if (Objects.nonNull(dto.getNextApprover())) {
runtimeService.setVariable(task.getExecutionId(), INTERNAL_SPECIFY_NEXT_APPROVER, dto.getNextApprover());
}
taskService.setAssignee(task.getId(), dto.getApprover().buildAssigneeId());
// 主动设置下级审批人
// 完成任务审批通过
// FIXME 如果 task 被重复删除会抛出异常
taskService.complete(task.getId(), runtimeService.getVariables(task.getExecutionId()));
if (StringUtil.isNotEmpty(task.getExecutionId())) {
taskService.complete(task.getId(), runtimeService.getVariables(task.getExecutionId()));
} else {
//子任务 没有executionId
taskService.complete(task.getId());
}
String parentTaskId = task.getParentTaskId();
//add by zuoqinbo 处理加签任务分为向前加签和向后加签
if (cn.azxo.framework.common.utils.StringUtils.isNotBlank(parentTaskId)) {
String tableName = managementService.getTableName(TaskEntity.class);
String sql = "select count(1) from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}";
long subTaskCount = taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).count();
TaskEntity taskEntity = (TaskEntity) taskService.createTaskQuery().taskId(parentTaskId).singleResult();
//当前任务是加签任务,如最后一个审批parentTask下没有其他子任务 subTaskCount == 0
//目前子任务是依次顺序审批, taskService.complete(task.getId()) 已经把任务完成,则subTaskCount == 0
if (subTaskCount == 0) {
//让下一个加签人进行处理
List<BpmnTaskDelegateAssigner> remainAssignerList =
(List<BpmnTaskDelegateAssigner>) task.getVariable("COUNTERSIGN_REMAIN_ASSIGNER_LIST");
if (!CollectionUtils.isEmpty(remainAssignerList)) {
BpmnTaskDelegateAssigner remainAssigner = remainAssignerList.get(0);
this.createSubTask(taskEntity, parentTaskId, remainAssigner.buildAssigneeId());
}else {
taskService.resolveTask(parentTaskId);//向后加签 会直接完成该任务
if (BpmnCountersignType.BACK_COUNTERSIGN.getType().equals(taskEntity.getScopeType())) {
taskService.complete(parentTaskId);
}
}
}
}
}
/**
* 创建加签子任务
* A加签给A A再加签给A
* A加签给B B再加签给A 再加签给B
* A加签给B B加签给C 再加签A
* A加签给B B加签给C 再加签D
*
* @param countersignDTO 加签参数
* @param taskEntity 父任务
*/
private void createSignSubTasks(BpmnTaskCountersignDTO countersignDTO, TaskEntity taskEntity) {
//如果还有预留或者继承的加签人
List<BpmnTaskDelegateAssigner> targetAssignerList =
(List<BpmnTaskDelegateAssigner>) taskEntity.getVariable("COUNTERSIGN_REMAIN_ASSIGNER_LIST",List.class);
List<BpmnTaskDelegateAssigner> newTargetAssignerList = Lists.newArrayList();
//为了保证顺序优先使用当前的加签人列表
newTargetAssignerList.addAll(countersignDTO.getTargetAssignerList());
//再添加遗留的加签人列表
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(targetAssignerList)) {
newTargetAssignerList.addAll(targetAssignerList);
}
String originAssigner = countersignDTO.getOriginAssigner().buildAssigneeId();
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(newTargetAssignerList)) {
String parentTaskId = taskEntity.getParentTaskId();
if (cn.azxo.framework.common.utils.StringUtils.isBlank(parentTaskId)) {
parentTaskId = taskEntity.getId();
}
String finalParentTaskId = parentTaskId;
//一次加签只创建一个任务
BpmnTaskDelegateAssigner removeAssigner = newTargetAssignerList.remove(0);
this.createSubTask(taskEntity, finalParentTaskId, removeAssigner.buildAssigneeId());
//剩余处理的加签人列表
taskEntity.setVariable("COUNTERSIGN_REMAIN_ASSIGNER_LIST", newTargetAssignerList);
String taskId = taskEntity.getId();
if (cn.azxo.framework.common.utils.StringUtils.isBlank(taskEntity.getParentTaskId())) {
//2.创建加签人的任务并执行完毕
Task task = this.createSubTask(taskEntity, finalParentTaskId, originAssigner);
taskId = task.getId();
}
Task taskInfo = taskService.createTaskQuery().taskId(taskId).singleResult();
if (taskInfo != null) {
taskService.complete(taskId);
}
// //如果是候选人需要删除运行时候选表种的数据
// long candidateCount = taskService.createTaskQuery().taskId(parentTaskId).taskCandidateUser(originAssigner).count();
// if (candidateCount > 0) {
// taskService.deleteCandidateUser(parentTaskId, originAssigner);
// }
}
}
/**
* 创建子任务
*
* @param parentTask 子任务继承原始任务信息
* @param assignee 子任务的执行人
* @return
*/
protected TaskEntity createSubTask(TaskEntity parentTask, String parentTaskId, String assignee) {
TaskEntity task = null;
if (parentTask != null) {
//1.生成新的工作流子任务
task = (TaskEntity) taskService.newTask(new TimeBasedIdGenerator().getNextId());
task.setCategory(parentTask.getCategory());
task.setDescription(parentTask.getDescription());
task.setTenantId(parentTask.getTenantId());
task.setAssignee(assignee);
task.setName(parentTask.getName());
task.setParentTaskId(parentTaskId);
task.setProcessDefinitionId(parentTask.getProcessDefinitionId());
task.setProcessInstanceId(parentTask.getProcessInstanceId());
task.setTaskDefinitionKey(parentTask.getTaskDefinitionKey());
task.setTaskDefinitionId(parentTask.getTaskDefinitionId());
//task.setExecutionId(parentTask.getExecutionId());
task.setPriority(parentTask.getPriority());
task.setCreateTime(new Date());
taskService.saveTask(task);
}
return task;
}
@Override
@ -379,9 +467,7 @@ public class BpmnTaskServiceImpl implements BpmnTaskService {
query.taskTenantId(tenantId);
}
HistoricProcessInstanceQuery instanceQuery =
historyService.createHistoricProcessInstanceQuery()
.includeProcessVariables()
.processInstanceId(processInstanceId);
historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId);
if (StringUtils.hasLength(tenantId)) {
instanceQuery.processInstanceTenantId(tenantId);
}
@ -401,16 +487,20 @@ public class BpmnTaskServiceImpl implements BpmnTaskService {
Map<String, HistoricVariableInstance> variableInstanceMap =
historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).list()
.stream().collect(Collectors.toMap(HistoricVariableInstance::getVariableName,
Function.identity(), (s, t) -> s));
Function.identity(), (s, t) -> s));
Set<String> taskDefinitionKeys = new HashSet<>();
int count = 0;
BpmnProcessInstanceResultEnum processBusinessStatus = valueOfStatus(instance.getBusinessStatus());
BpmnProcessInstanceResultEnum finalBusinessStatus = valueOfStatus(instance.getBusinessStatus());
for (BpmnHistoricTaskInstanceVO vo : vos) {
vo.setResult(processBusinessStatus);
if (Objects.nonNull(vo.getEndTime())) {
// 只有拒绝时, 为指定的 taskId 设置过拒绝变量
vo.setResult((BpmnProcessInstanceResultEnum) instance.getProcessVariables().getOrDefault(TASK_COMPLETE_OPERATION_TYPE + vo.getTaskId(), APPROVED));
if (count == 0 || taskDefinitionKeys.contains(vo.getTaskDefinitionKey())) {
vo.setResult(finalBusinessStatus);
if (Objects.nonNull(vo.getEndTime()) && !Objects.equals(finalBusinessStatus, REJECTED)
&& !Objects.equals(finalBusinessStatus, CANCELLED)) {
vo.setResult(APPROVED);
}
} else {
vo.setResult(APPROVED);
}
taskDefinitionKeys.add(vo.getTaskDefinitionKey());
List<Comment> taskComments = commentByTaskIdMap.getOrDefault(vo.getTaskId(), Collections.emptyList());
@ -485,20 +575,9 @@ public class BpmnTaskServiceImpl implements BpmnTaskService {
List<BpmnTaskInstanceVO> vos = bpmnTaskConverter.toVos(query.list());
List<String> snapshotTaskIds =
vos.stream().map(i -> INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT + i.getTaskId()).collect(Collectors.toList());
ProcessInstance processInstance =
runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
if (Objects.isNull(processInstance)) {
throw new WorkflowEngineException(PROCESS_INSTANCE_NOT_EXISTS);
}
Map<String, VariableInstance> instanceMap = runtimeService.getVariableInstances(processInstanceId,
snapshotTaskIds);
vos.forEach(i -> {
VariableInstance variableInstance =
instanceMap.get(INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT + i.getTaskId());
if (!Objects.isNull(variableInstance)) {
i.setAssigner((BpmnTaskDelegateAssigner) variableInstance.getValue());
}
});
vos.forEach(i -> i.setAssigner((BpmnTaskDelegateAssigner) instanceMap.get(INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT + i.getTaskId()).getValue()));
return vos;
}
@ -511,11 +590,13 @@ public class BpmnTaskServiceImpl implements BpmnTaskService {
* @param taskId 任务ID
*/
private Task checkTask(String tenantId, String assignee, String taskId) {
Task task = getTask(taskId, null, null);
Task task = getTask(taskId, assignee, tenantId);
if (Objects.nonNull(task) && !Objects.equals(assignee, task.getAssignee())) {
throw new WorkflowEngineException(TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF);
}
if (Objects.isNull(task)) {
throw new WorkflowEngineException(TASK_COMPLETE_FAIL_NOT_EXISTS);
} else if (!Objects.equals(assignee, task.getAssignee()) && !Objects.equals(tenantId, task.getTenantId())) {
throw new WorkflowEngineException(TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF);
}
return task;
}
@ -585,23 +666,35 @@ public class BpmnTaskServiceImpl implements BpmnTaskService {
@Override
public void countersignTask(BpmnTaskCountersignDTO countersignDTO) {
String tenantId = countersignDTO.getTargetAssigner().getTenantId();
TaskEntity taskEntity = (TaskEntity) taskService.createTaskQuery().taskId(countersignDTO.getTaskId());
String tenantId = countersignDTO.getOriginAssigner().getTenantId();
TaskEntityImpl taskEntity = (TaskEntityImpl) taskService.createTaskQuery().taskId(countersignDTO.getTaskId()).active().singleResult();
if (Objects.isNull(taskEntity)) {
throw new WorkflowEngineException(TASK_COMPLETE_FAIL_NOT_EXISTS);
}
if (org.apache.commons.lang.StringUtils.isNotEmpty(tenantId)) {
taskEntity.setTenantId(tenantId);
}
taskEntity.setScopeType(countersignDTO.getCountersignType().getType());
taskEntity.setOwner(countersignDTO.getTargetAssigner().getPersonId());
taskEntity.setAssigneeValue(null);
//审批时,需要从Scope中判断是 向前加签还是向后加签
//taskService.resolveTask(parentTaskId);
//if (BpmnCountersignType.BACK_COUNTERSIGN.equals(task.getScopeType())) {
// taskService.complete(parentTaskId);
//}
taskService.saveTask(taskEntity);
if (BpmnCountersignType.isValidAppType(countersignDTO.getCountersignType()) != null) {
//加签不能改变BPMN2.0原流程定义因为下一个流程实例不需要加签
//如果是加签再加签 parentTaskId=null
String parentTaskId = taskEntity.getParentTaskId();
BpmnTaskDelegateAssigner originAssigner = countersignDTO.getOriginAssigner();
//更新父任务信息
if (StringUtil.isEmpty(parentTaskId)) {
taskEntity.setOwner(originAssigner.buildAssigneeId());
taskEntity.setAssignee(null);
taskEntity.setCountEnabled(true);
taskEntity.setScopeType(countersignDTO.getCountersignType());
taskService.saveTask(taskEntity);
}
//该任务加签时会创建子任务用于分配其他人加签
//目前多个子任务时会按照加签人的顺序依次进行加签
//例如 加签按顺序依次分配给ABC三人,需A任务进行完成后进行B任务再进行C任务
this.createSignSubTasks(countersignDTO, taskEntity);
} else {
throw new WorkflowEngineException(TASK_APOSTILLE_NOT_SUPPORT);
}
}
private Activity getActivity(TaskEntity task) {