update - 完善流程实例的任务查询

This commit is contained in:
wangli 2023-07-29 23:20:06 +08:00
parent 4329742fad
commit 29e7c3964b
11 changed files with 156 additions and 50 deletions

View File

@ -1,6 +1,5 @@
package cn.axzo.workflow.core.service;
import cn.axzo.workflow.core.common.enums.BpmProcessInstanceResultEnum;
import cn.axzo.workflow.core.service.dto.request.process.*;
import cn.axzo.workflow.core.service.dto.response.BpmPageResult;
import cn.axzo.workflow.core.service.dto.response.process.BpmProcessInstancePageItemVO;
@ -85,7 +84,7 @@ public interface BpmProcessInstanceService {
*/
BpmProcessInstanceVO getProcessInstanceVO(BpmProcessInstanceQueryDTO dto);
void deleteProcessInstance(String id, String reason, BpmProcessInstanceResultEnum resultEnum);
void deleteProcessInstance(String id, String reason);
ObjectNode getProcessInstanceGraphical(String processInstanceId, @Nullable String tenantId);

View File

@ -5,6 +5,7 @@ import cn.axzo.workflow.core.service.dto.request.task.BpmTaskAuditDTO;
import cn.axzo.workflow.core.service.dto.request.task.BpmTaskCommentDTO;
import cn.axzo.workflow.core.service.dto.request.task.BpmTaskTodoPageSearchDTO;
import cn.axzo.workflow.core.service.dto.response.BpmPageResult;
import cn.axzo.workflow.core.service.dto.response.task.BpmHistoricTaskInstanceGroupVO;
import cn.axzo.workflow.core.service.dto.response.task.BpmHistoricTaskInstanceVO;
import cn.axzo.workflow.core.service.dto.response.task.BpmTaskDonePageItemVO;
import cn.axzo.workflow.core.service.dto.response.task.BpmTaskTodoPageItemVO;
@ -39,9 +40,23 @@ public interface BpmTaskService {
/**
* 获取历史已审批的列表详情
* <p>
* 扁平的任务列表
*/
List<BpmHistoricTaskInstanceVO> getHistoricTaskListByProcessInstanceId(String processInstanceId, String tenantId);
/**
* 获取历史已审批的列表详情
* <p>
* 任务根据定义 ID 分组
*
* @param processInstanceId
* @param tenantId
* @return
*/
List<BpmHistoricTaskInstanceGroupVO> getHistoricTaskListGroupByProcessInstanceId(String processInstanceId,
String tenantId);
/**
* 获取实例正在审核的人列表
* <p>
@ -71,4 +86,6 @@ public interface BpmTaskService {
void assigneeTask(BpmTaskAssigneeDTO dto);
void commentTask(BpmTaskCommentDTO dto);
}

View File

@ -1,11 +1,13 @@
package cn.axzo.workflow.core.service.converter;
import cn.axzo.workflow.core.service.dto.response.task.BpmHistoricTaskInstanceVO;
import org.flowable.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.springframework.util.CollectionUtils;
import java.util.Arrays;
import java.util.*;
import static org.mapstruct.NullValueCheckStrategy.ALWAYS;
@ -22,6 +24,10 @@ import static org.mapstruct.NullValueCheckStrategy.ALWAYS;
)
public interface BpmHistoricTaskInstanceConverter extends EntityConverter<BpmHistoricTaskInstanceVO,
HistoricTaskInstance> {
/**
* @see MultiInstanceActivityBehavior#DELETE_REASON_END
*/
String DELETE_REASON_END = "MI_END";
@Override
@Mapping(target = "taskId", source = "id")
@ -29,9 +35,24 @@ public interface BpmHistoricTaskInstanceConverter extends EntityConverter<BpmHis
@Mapping(target = "name", source = "name")
@Mapping(target = "processInstanceId", source = "processInstanceId")
@Mapping(target = "processDefinitionId", source = "processDefinitionId")
@Mapping(target = "assignee", source = "assignee")
@Mapping(target = "createTime", source = "createTime")
@Mapping(target = "endTime", source = "endTime")
@Mapping(target = "durationInMillis", source = "durationInMillis")
@Mapping(target = "tenantId", source = "tenantId")
@Mapping(target = "deleteReason", source = "deleteReason")
BpmHistoricTaskInstanceVO toVo(HistoricTaskInstance entity);
default List<BpmHistoricTaskInstanceVO> toVosSkipMiEnd(List<HistoricTaskInstance> entities) {
if (CollectionUtils.isEmpty(entities)) {
return Collections.emptyList();
}
List<BpmHistoricTaskInstanceVO> vos = new ArrayList<>();
entities.stream()
.filter(i -> !Objects.equals(DELETE_REASON_END, i.getDeleteReason()))
.forEach(i -> vos.add(toVo(i)));
return vos;
}
}

View File

@ -0,0 +1,22 @@
package cn.axzo.workflow.core.service.dto.response.task;
import lombok.Data;
import java.util.List;
/**
* TODO
*
* @author wangli
* @sine 2023/7/29 22:59
*/
@Data
public class BpmHistoricTaskInstanceGroupVO {
private String taskDefinitionKey;
private String processInstanceId;
private List<BpmHistoricTaskInstanceVO> tasks;
}

View File

@ -25,6 +25,8 @@ public class BpmHistoricTaskInstanceVO {
private String processDefinitionId;
private String assignee;
private Date createTime;
private Date endTime;
@ -36,4 +38,7 @@ public class BpmHistoricTaskInstanceVO {
private BpmProcessInstanceResultEnum result;
private String comment;
private transient String deleteReason;
}

View File

@ -1,11 +1,15 @@
package cn.axzo.workflow.core.service.engine;
import cn.axzo.workflow.core.common.enums.BpmProcessInstanceResultEnum;
import cn.axzo.workflow.core.listener.BpmProcessEventListener;
import cn.axzo.workflow.core.service.BpmProcessInstanceService;
import com.google.common.collect.ImmutableSet;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener;
import org.flowable.engine.delegate.event.FlowableCancelledEvent;
import org.flowable.engine.delegate.event.FlowableProcessStartedEvent;
import org.flowable.engine.delegate.event.impl.FlowableProcessStartedEventImpl;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@ -19,7 +23,7 @@ public class EngineProcessInstanceEventListener extends AbstractFlowableEngineEv
ObjectProvider<BpmProcessEventListener> processEventListener;
@Resource
@Lazy
BpmProcessInstanceService processInstanceService;
private RuntimeService runtimeService;
public static final Set<FlowableEngineEventType> PROCESS_INSTANCE_EVENTS =
ImmutableSet.<FlowableEngineEventType>builder()
.add(FlowableEngineEventType.PROCESS_CREATED)
@ -32,26 +36,29 @@ public class EngineProcessInstanceEventListener extends AbstractFlowableEngineEv
super(PROCESS_INSTANCE_EVENTS);
}
// @Override
// protected void processCreated(FlowableEngineEntityEvent event) {
// processInstanceService.createProcessInstanceExt((ProcessInstance) event.getEntity());
// processEventListener.ifAvailable(listener -> listener.onCreated(event));
// }
@Override
protected void processCreated(FlowableEngineEntityEvent event) {
processEventListener.ifAvailable(listener -> listener.onCreated(event));
}
@Override
protected void processStarted(FlowableProcessStartedEvent event) {
runtimeService.updateBusinessStatus(((FlowableProcessStartedEventImpl) event).getProcessInstanceId(),
BpmProcessInstanceResultEnum.PROCESSING.getStatus());
processEventListener.ifAvailable(listener -> listener.onStarted(event));
}
// @Override
// protected void processCompleted(FlowableEngineEntityEvent event) {
// this.processInstanceService.updateProcessInstanceExtComplete((ProcessInstance) event.getEntity());
// processEventListener.ifAvailable(listener -> listener.onCompleted(event));
// }
@Override
protected void processCompleted(FlowableEngineEntityEvent event) {
runtimeService.updateBusinessStatus(event.getProcessInstanceId(),
BpmProcessInstanceResultEnum.APPROVED.getStatus());
processEventListener.ifAvailable(listener -> listener.onCompleted(event));
}
// @Override
// protected void processCancelled(FlowableCancelledEvent event) {
// processInstanceService.updateProcessInstanceExtCancel(event);
// processEventListener.ifAvailable(listener -> listener.onCancelled(event));
// }
@Override
protected void processCancelled(FlowableCancelledEvent event) {
runtimeService.updateBusinessStatus(event.getProcessInstanceId(),
BpmProcessInstanceResultEnum.REJECTED.getStatus());
processEventListener.ifAvailable(listener -> listener.onCancelled(event));
}
}

View File

@ -1,7 +1,6 @@
package cn.axzo.workflow.core.service.impl;
import cn.axzo.workflow.core.common.enums.BpmProcessInstanceDeleteReasonEnum;
import cn.axzo.workflow.core.common.enums.BpmProcessInstanceResultEnum;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.common.utils.BpmCollectionUtils;
import cn.axzo.workflow.core.repository.mapper.InfoMapper;
@ -45,8 +44,6 @@ import java.util.*;
import static cn.axzo.workflow.core.common.BpmConstants.*;
import static cn.axzo.workflow.core.common.enums.BpmErrorCode.*;
import static cn.axzo.workflow.core.common.enums.BpmProcessInstanceResultEnum.CANCELLED;
import static cn.axzo.workflow.core.common.enums.BpmProcessInstanceResultEnum.PROCESSING;
@Service
@Slf4j
@ -214,7 +211,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
// extDO.setExt(dto.getExt());
// // 补全流程实例的拓展表
// processInstanceExtMapper.updateByProcessInstanceId(extDO);
runtimeService.updateBusinessStatus(instance.getProcessInstanceId(), PROCESSING.getStatus());
// runtimeService.updateBusinessStatus(instance.getProcessInstanceId(), PROCESSING.getStatus());
return instance.getProcessInstanceId();
}
@ -251,7 +248,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
// extDO.setExt(dto.getExt());
// // 补全流程实例的拓展表
// processInstanceExtMapper.updateByProcessInstanceId(extDO);
runtimeService.updateBusinessStatus(instance.getProcessInstanceId(), PROCESSING.getStatus());
// runtimeService.updateBusinessStatus(instance.getProcessInstanceId(), PROCESSING.getStatus());
return instance.getProcessInstanceId();
}
@ -284,7 +281,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
runtimeService.setVariables(instance.getId(), variables);
deleteProcessInstance(instance.getId(),
BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(dto.getReason()), CANCELLED);
BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(dto.getReason()));
return true;
}
@ -418,9 +415,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
// }
@Override
public void deleteProcessInstance(String id, String reason, BpmProcessInstanceResultEnum resultEnum) {
public void deleteProcessInstance(String id, String reason) {
log.info("当前线程: {}", Thread.currentThread().getName());
runtimeService.updateBusinessStatus(id, resultEnum.getStatus());
runtimeService.deleteProcessInstance(id, reason);
}

View File

@ -11,12 +11,14 @@ import cn.axzo.workflow.core.service.dto.request.task.BpmTaskAuditDTO;
import cn.axzo.workflow.core.service.dto.request.task.BpmTaskCommentDTO;
import cn.axzo.workflow.core.service.dto.request.task.BpmTaskTodoPageSearchDTO;
import cn.axzo.workflow.core.service.dto.response.BpmPageResult;
import cn.axzo.workflow.core.service.dto.response.task.BpmHistoricTaskInstanceGroupVO;
import cn.axzo.workflow.core.service.dto.response.task.BpmHistoricTaskInstanceVO;
import cn.axzo.workflow.core.service.dto.response.task.BpmTaskDonePageItemVO;
import cn.axzo.workflow.core.service.dto.response.task.BpmTaskTodoPageItemVO;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
@ -41,7 +43,7 @@ import java.util.stream.Collectors;
import static cn.axzo.workflow.core.common.BpmConstants.*;
import static cn.axzo.workflow.core.common.enums.BpmErrorCode.*;
import static cn.axzo.workflow.core.common.enums.BpmProcessInstanceResultEnum.REJECTED;
import static cn.axzo.workflow.core.common.enums.BpmProcessInstanceResultEnum.APPROVED;
import static cn.axzo.workflow.core.common.enums.BpmProcessInstanceResultEnum.valueOfStatus;
import static cn.axzo.workflow.core.common.utils.BpmCollectionUtils.convertSet;
@ -191,6 +193,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
// Map<String, Object> transientMap = new HashMap<>();
// transientMap.put(BpmConstants.INTERNAL_TASK_COMMENT, dto.getComment());
Authentication.setAuthenticatedUserId(dto.getUserId());
taskService.addComment(dto.getTaskId(), instance.getId(), dto.getComment());
// 完成任务审批通过
// FIXME 如果 task 被重复删除会抛出异常
@ -217,8 +220,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
runtimeService.setVariables(instance.getId(), variables);
// 删除流程实例以实现驳回任务时取消整个审批流程
processInstanceService.deleteProcessInstance(instance.getId(), dto.getComment(),
REJECTED);
processInstanceService.deleteProcessInstance(instance.getId(), dto.getComment());
}
@ -243,25 +245,46 @@ public class BpmTaskServiceImpl implements BpmTaskService {
// Map<String, List<HistoricTaskInstance>> taskMapByDefKey =
// taskInstances.stream().collect(Collectors.groupingBy
// (HistoricTaskInstance::getTaskDefinitionKey));
List<BpmHistoricTaskInstanceVO> vos = historicTaskInstanceConverter.toVos(taskInstances);
List<Comment> comments = taskService.getProcessInstanceComments(processInstanceId, CommentEntity.TYPE_COMMENT);
if (!CollectionUtils.isEmpty(vos) && !CollectionUtils.isEmpty(comments)) {
for (BpmHistoricTaskInstanceVO vo : vos) {
vo.setResult(valueOfStatus(instance.getBusinessStatus()));
List<BpmHistoricTaskInstanceVO> vos = historicTaskInstanceConverter.toVosSkipMiEnd(taskInstances);
Map<String, List<Comment>> commentByTaskIdMap = taskService.getProcessInstanceComments(processInstanceId,
CommentEntity.TYPE_COMMENT).stream().collect(Collectors.groupingBy(Comment::getTaskId));
for (Comment comment : comments) {
if (Objects.equals(vo.getTaskId(), comment.getTaskId())
// 使用流程引擎的 Comment 表来记录审批意见,现目前业务一般只针对一个审批任务写一条审批建议
// 但防止后续新增多条评论,被动覆盖,所以简单粗暴的只取第一条评论
&& !StringUtils.hasLength(vo.getComment())) {
vo.setComment(comment.getFullMessage());
}
}
Set<String> taskDefinitionKeys = new HashSet<>();
int count = 0;
for (BpmHistoricTaskInstanceVO vo : vos) {
if (!taskDefinitionKeys.contains(vo.getTaskDefinitionKey()) && count == 0) {
vo.setResult(valueOfStatus(instance.getBusinessStatus()));
} else {
vo.setResult(APPROVED);
}
Optional<Comment> first = commentByTaskIdMap.getOrDefault(vo.getTaskId(), Collections.emptyList())
.stream().filter(i -> Objects.equals(i.getUserId(), vo.getAssignee()))
.findFirst();
first.ifPresent(i -> vo.setComment(i.getFullMessage()));
count++;
}
return vos;
}
@Override
public List<BpmHistoricTaskInstanceGroupVO> getHistoricTaskListGroupByProcessInstanceId(String processInstanceId,
String tenantId) {
List<BpmHistoricTaskInstanceVO> vos = getHistoricTaskListByProcessInstanceId(processInstanceId, tenantId);
Map<String, List<BpmHistoricTaskInstanceVO>> voMapByTaskDefKey =
vos.stream().collect(Collectors.groupingBy(BpmHistoricTaskInstanceVO::getTaskDefinitionKey));
List<BpmHistoricTaskInstanceGroupVO> groupVos = new ArrayList<>();
for (Map.Entry<String, List<BpmHistoricTaskInstanceVO>> entry : voMapByTaskDefKey.entrySet()) {
BpmHistoricTaskInstanceGroupVO groupVO = new BpmHistoricTaskInstanceGroupVO();
groupVO.setProcessInstanceId(processInstanceId);
groupVO.setTaskDefinitionKey(entry.getKey());
groupVO.setTasks(entry.getValue());
groupVos.add(groupVO);
}
return groupVos;
}
@Override
public List<Task> getActiveTasksByProcessInstanceId(String processInstanceId) {
if (StrUtil.isEmpty(processInstanceId)) {

View File

@ -25,7 +25,7 @@
<multiInstanceLoopCharacteristics isSequential="false"
flowable:collection="sid-6589489F-EE93-43F2-A98F-78F5A578D39B_assigneeList"
flowable:elementVariable="assigneeName">
<completionCondition>${nrOfInstances / nrOfCompletedInstances > 0}</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
<sequenceFlow id="sid-7A2B3B51-387C-4957-830C-F4B75147DD15" sourceRef="startEvent1"

View File

@ -21,7 +21,7 @@ public class BpmTaskDelegateImpl implements BpmTaskDelegate {
public List<BpmTaskDelegateAssigner> calculateAssignerAtExecution(BpmTaskCalculateDTO delegateTask) {
log.info("计算审核人,当前的审批任务 DefinitionKey 为: {}", delegateTask.getTaskDefinitionKey());
List<BpmTaskDelegateAssigner> assigners = new ArrayList<>();
if (Objects.equals("NODE1639041346796_0.5413743892974803_0", delegateTask.getTaskDefinitionKey())) {
if (Objects.equals("sid-6589489F-EE93-43F2-A98F-78F5A578D39B", delegateTask.getTaskDefinitionKey())) {
BpmTaskDelegateAssigner user1 = new BpmTaskDelegateAssigner();
user1.setAssignerId("66646");
user1.setAssignerName("王军");
@ -30,6 +30,10 @@ public class BpmTaskDelegateImpl implements BpmTaskDelegate {
user2.setAssignerId("66647");
user2.setAssignerName("王粒");
assigners.add(user2);
BpmTaskDelegateAssigner user3 = new BpmTaskDelegateAssigner();
user3.setAssignerId("66648");
user3.setAssignerName("小吴");
assigners.add(user3);
}
if (Objects.equals("NODE1687933854432_0.45762305710855467_1", delegateTask.getTaskDefinitionKey())) {

View File

@ -5,6 +5,7 @@ import cn.axzo.workflow.core.service.dto.request.task.BpmTaskAssigneeDTO;
import cn.axzo.workflow.core.service.dto.request.task.BpmTaskAuditDTO;
import cn.axzo.workflow.core.service.dto.request.task.BpmTaskTodoPageSearchDTO;
import cn.axzo.workflow.core.service.dto.response.BpmPageResult;
import cn.axzo.workflow.core.service.dto.response.task.BpmHistoricTaskInstanceGroupVO;
import cn.axzo.workflow.core.service.dto.response.task.BpmHistoricTaskInstanceVO;
import cn.axzo.workflow.core.service.dto.response.task.BpmTaskDonePageItemVO;
import cn.axzo.workflow.core.service.dto.response.task.BpmTaskTodoPageItemVO;
@ -78,16 +79,27 @@ public class BpmTaskController {
/**
* 获取指定流程实例的审批过程信息
* <p>
* 同一层级机构
*/
@GetMapping("/list")
public CommonResponse<List<BpmHistoricTaskInstanceVO>> getTaskListByProcessInstanceId(@RequestParam String processInstanceId,
@RequestParam(required =
false) String tenantId) {
@GetMapping("/list/flat")
public CommonResponse<List<BpmHistoricTaskInstanceVO>> getTaskListFlatByProcessInstanceId(@RequestParam String processInstanceId,
@RequestParam(required
= false) String tenantId) {
log.info("获取历史已审批的列表详情 getTaskListByProcessInstanceId===>>>参数:{}", processInstanceId);
return CommonResponse.success(bpmTaskService.getHistoricTaskListByProcessInstanceId(processInstanceId,
tenantId));
}
@GetMapping("/list/group")
public CommonResponse<List<BpmHistoricTaskInstanceGroupVO>> getTaskListGroupByProcessInstanceId(@RequestParam String processInstanceId,
@RequestParam(required
= false) String tenantId) {
log.info("获取历史已审批的列表详情 getTaskListByProcessInstanceId===>>>参数:{}", processInstanceId);
return CommonResponse.success(bpmTaskService.getHistoricTaskListGroupByProcessInstanceId(processInstanceId,
tenantId));
}
/**
* 获取实例正在审核的人列表
*/