工作流 Flowable 转办任务的实现

This commit is contained in:
jason 2022-02-16 17:12:48 +08:00
parent c1884c3196
commit 41e4283f99
9 changed files with 203 additions and 5 deletions

View File

@ -37,7 +37,7 @@ public class BpmTaskController {
@GetMapping("done-page") @GetMapping("done-page")
@ApiOperation("获取 Done 已办任务分页") @ApiOperation("获取 Done 已办任务分页")
@PreAuthorize("@ss.hasPermission('bpm:task:query')") @PreAuthorize("@ss.hasPermission('bpm:task:query')")
public CommonResult<PageResult<BpmTaskDonePageItemRespVO>> getTodoTaskPage(@Valid BpmTaskDonePageReqVO pageVO) { public CommonResult<PageResult<BpmTaskDonePageItemRespVO>> getDoneTaskPage(@Valid BpmTaskDonePageReqVO pageVO) {
return success(taskService.getDoneTaskPage(getLoginUserId(), pageVO)); return success(taskService.getDoneTaskPage(getLoginUserId(), pageVO));
} }

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.bpm.api.task; package cn.iocoder.yudao.module.bpm.api.task;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -14,11 +15,13 @@ import javax.validation.Valid;
*/ */
@Service @Service
@Validated @Validated
public class FlowableProcessInstanceApiImpl implements BpmProcessInstanceApi { public class BpmProcessInstanceApiImpl implements BpmProcessInstanceApi {
@Resource
private BpmProcessInstanceService processInstanceService;
@Override @Override
public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO reqDTO) { public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO reqDTO) {
//TODO return processInstanceService.createProcessInstance(userId, reqDTO);
return null;
} }
} }

View File

@ -37,6 +37,13 @@ public class BpmTaskController {
return success(taskService.getTodoTaskPage(getLoginUserId(), pageVO)); return success(taskService.getTodoTaskPage(getLoginUserId(), pageVO));
} }
@GetMapping("done-page")
@ApiOperation("获取 Done 已办任务分页")
@PreAuthorize("@ss.hasPermission('bpm:task:query')")
public CommonResult<PageResult<BpmTaskDonePageItemRespVO>> getDoneTaskPage(@Valid BpmTaskDonePageReqVO pageVO) {
return success(taskService.getDoneTaskPage(getLoginUserId(), pageVO));
}
@GetMapping("/list-by-process-instance-id") @GetMapping("/list-by-process-instance-id")
@ApiOperation(value = "获得指定流程实例的任务列表", notes = "包括完成的、未完成的") @ApiOperation(value = "获得指定流程实例的任务列表", notes = "包括完成的、未完成的")
@ApiImplicitParam(name = "processInstanceId", value = "流程实例的编号", required = true, dataTypeClass = String.class) @ApiImplicitParam(name = "processInstanceId", value = "流程实例的编号", required = true, dataTypeClass = String.class)
@ -61,4 +68,12 @@ public class BpmTaskController {
taskService.rejectTask(getLoginUserId(), reqVO); taskService.rejectTask(getLoginUserId(), reqVO);
return success(true); return success(true);
} }
@PutMapping("/update-assignee")
@ApiOperation(value = "更新任务的负责人", notes = "用于【流程详情】的【转派】按钮")
@PreAuthorize("@ss.hasPermission('bpm:task:update')")
public CommonResult<Boolean> updateTaskAssignee(@Valid @RequestBody BpmTaskUpdateAssigneeReqVO reqVO) {
taskService.updateTaskAssignee(getLoginUserId(), reqVO);
return success(true);
}
} }

View File

@ -53,6 +53,24 @@ public interface BpmTaskConvert {
SuspensionState.ACTIVE.getStateCode(); SuspensionState.ACTIVE.getStateCode();
} }
default List<BpmTaskDonePageItemRespVO> convertList2(List<HistoricTaskInstance> tasks, Map<String, BpmTaskExtDO> bpmTaskExtDOMap,
Map<String, HistoricProcessInstance> historicProcessInstanceMap,
Map<Long, AdminUserRespDTO> userMap) {
return CollectionUtils.convertList(tasks, task -> {
BpmTaskDonePageItemRespVO respVO = convert2(task);
BpmTaskExtDO taskExtDO = bpmTaskExtDOMap.get(task.getId());
copyTo(taskExtDO, respVO);
HistoricProcessInstance processInstance = historicProcessInstanceMap.get(task.getProcessInstanceId());
if (processInstance != null) {
AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
respVO.setProcessInstance(convert(processInstance, startUser));
}
return respVO;
});
}
BpmTaskDonePageItemRespVO convert2(HistoricTaskInstance bean);
@Mappings({ @Mappings({
@Mapping(source = "processInstance.id", target = "id"), @Mapping(source = "processInstance.id", target = "id"),
@Mapping(source = "processInstance.name", target = "name"), @Mapping(source = "processInstance.name", target = "name"),
@ -111,6 +129,18 @@ public interface BpmTaskConvert {
taskExtDO.setCreateTime(task.getCreateTime()); taskExtDO.setCreateTime(task.getCreateTime());
return taskExtDO; return taskExtDO;
} }
default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, AdminUserRespDTO startUser, Task task) {
BpmMessageSendWhenTaskCreatedReqDTO reqDTO = new BpmMessageSendWhenTaskCreatedReqDTO();
reqDTO.setProcessInstanceId(processInstance.getProcessInstanceId())
.setProcessInstanceName(processInstance.getName())
.setStartUserId(startUser.getId())
.setStartUserNickname(startUser.getNickname())
.setTaskId(task.getId())
.setTaskName(task.getName())
.setAssigneeUserId(NumberUtils.parseLong(task.getAssignee()));
return reqDTO;
}
} }

View File

@ -44,4 +44,9 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
protected void taskCompleted(FlowableEngineEntityEvent event) { protected void taskCompleted(FlowableEngineEntityEvent event) {
taskService.updateTaskExtComplete((Task)event.getEntity()); taskService.updateTaskExtComplete((Task)event.getEntity());
} }
@Override
protected void taskAssigned(FlowableEngineEntityEvent event) {
taskService.updateTaskExtAssign((Task)event.getEntity());
}
} }

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.service.task;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent; import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.delegate.event.FlowableCancelledEvent;
@ -55,7 +56,6 @@ public interface BpmProcessInstanceService {
*/ */
PageResult<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId, PageResult<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId,
@Valid BpmProcessInstanceMyPageReqVO pageReqVO); @Valid BpmProcessInstanceMyPageReqVO pageReqVO);
/** /**
* 创建流程实例提供给前端 * 创建流程实例提供给前端
* *
@ -65,6 +65,15 @@ public interface BpmProcessInstanceService {
*/ */
String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO); String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO);
/**
* 创建流程实例提供给内部
*
* @param userId 用户编号
* @param createReqDTO 创建信息
* @return 实例的编号
*/
String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO);
/** /**
* 获得流程实例 VO 信息 * 获得流程实例 VO 信息
* *
@ -89,6 +98,24 @@ public interface BpmProcessInstanceService {
*/ */
HistoricProcessInstance getHistoricProcessInstance(String id); HistoricProcessInstance getHistoricProcessInstance(String id);
/**
* 获得历史的流程实例列表
*
* @param ids 流程实例的编号集合
* @return 历史的流程实例列表
*/
List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids);
/**
* 获得历史的流程实例 Map
*
* @param ids 流程实例的编号集合
* @return 历史的流程实例列表 Map
*/
default Map<String, HistoricProcessInstance> getHistoricProcessInstanceMap(Set<String> ids) {
return CollectionUtils.convertMap(getHistoricProcessInstances(ids), HistoricProcessInstance::getId);
}
/** /**
* 创建 ProcessInstance 拓展记录 * 创建 ProcessInstance 拓展记录
* *

View File

@ -5,6 +5,7 @@ import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*;
import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
@ -112,6 +113,14 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); return createProcessInstance0(userId, definition, createReqVO.getVariables(), null);
} }
@Override
public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) {
// 获得流程定义
ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey());
// 发起流程
return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey());
}
@Override @Override
public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { public BpmProcessInstanceRespVO getProcessInstanceVO(String id) {
// 获得流程实例 // 获得流程实例
@ -172,6 +181,11 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult();
} }
@Override
public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) {
return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list();
}
@Override @Override
public void createProcessInstanceExt(ProcessInstance instance) { public void createProcessInstanceExt(ProcessInstance instance) {
// 获得流程定义 // 获得流程定义

View File

@ -25,6 +25,14 @@ public interface BpmTaskService {
* @return 流程任务分页 * @return 流程任务分页
*/ */
PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageReqVO); PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageReqVO);
/**
* 获得已办的流程任务分页
*
* @param userId 用户编号
* @param pageReqVO 分页请求
* @return 流程任务分页
*/
PageResult<BpmTaskDonePageItemRespVO> getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageReqVO);
/** /**
* 获得流程任务 Map * 获得流程任务 Map
@ -69,6 +77,22 @@ public interface BpmTaskService {
*/ */
void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO); void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO);
/**
* 将流程任务分配给指定用户
*
* @param userId 用户编号
* @param reqVO 分配请求
*/
void updateTaskAssignee(Long userId, BpmTaskUpdateAssigneeReqVO reqVO);
/**
* 将流程任务分配给指定用户
*
* @param id 流程任务编号
* @param userId 用户编号
*/
void updateTaskAssignee(String id, Long userId);
/** /**
* 创建 Task 拓展记录 * 创建 Task 拓展记录
* *
@ -83,4 +107,11 @@ public interface BpmTaskService {
*/ */
void updateTaskExtComplete(Task task); void updateTaskExtComplete(Task task);
/**
* 更新 Task 拓展记录并发送通知
*
* @param task 任务实体
*/
void updateTaskExtAssign(Task task);
} }

View File

@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService;
import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@ -22,7 +23,10 @@ import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task; import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery; import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
@ -56,6 +60,8 @@ public class BpmTaskServiceImpl implements BpmTaskService{
private DeptApi deptApi; private DeptApi deptApi;
@Resource @Resource
private BpmTaskExtMapper taskExtMapper; private BpmTaskExtMapper taskExtMapper;
@Resource
private BpmMessageService messageService;
@Override @Override
public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) { public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) {
@ -89,6 +95,42 @@ public class BpmTaskServiceImpl implements BpmTaskService{
taskQuery.count()); taskQuery.count());
} }
@Override
public PageResult<BpmTaskDonePageItemRespVO> getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageVO) {
// 查询已办任务
HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery()
.finished() // 已完成
.taskAssignee(String.valueOf(userId)) // 分配给自己
.orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序
if (StrUtil.isNotBlank(pageVO.getName())) {
taskQuery.taskNameLike("%" + pageVO.getName() + "%");
}
if (pageVO.getBeginCreateTime() != null) {
taskQuery.taskCreatedAfter(pageVO.getBeginCreateTime());
}
if (pageVO.getEndCreateTime() != null) {
taskQuery.taskCreatedBefore(pageVO.getEndCreateTime());
}
// 执行查询
List<HistoricTaskInstance> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
if (CollUtil.isEmpty(tasks)) {
return PageResult.empty(taskQuery.count());
}
// 获得 TaskExtDO Map
List<BpmTaskExtDO> bpmTaskExtDOs = taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId));
Map<String, BpmTaskExtDO> bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId);
// 获得 ProcessInstance Map
Map<String, HistoricProcessInstance> historicProcessInstanceMap = processInstanceService.getHistoricProcessInstanceMap(
convertSet(tasks, HistoricTaskInstance::getProcessInstanceId));
// 获得 User Map
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
convertSet(historicProcessInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
// 拼接结果
return new PageResult<>(BpmTaskConvert.INSTANCE.convertList2(tasks, bpmTaskExtDOMap, historicProcessInstanceMap, userMap),
taskQuery.count());
}
@Override @Override
public List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds) { public List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds) {
if (CollUtil.isEmpty(processInstanceIds)) { if (CollUtil.isEmpty(processInstanceIds)) {
@ -158,6 +200,19 @@ public class BpmTaskServiceImpl implements BpmTaskService{
.setResult(BpmProcessInstanceResultEnum.REJECT.getResult()).setComment(reqVO.getComment())); .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()).setComment(reqVO.getComment()));
} }
@Override
public void updateTaskAssignee(Long userId, BpmTaskUpdateAssigneeReqVO reqVO) {
// 校验任务存在
Task task = checkTask(userId, reqVO.getId());
// 更新负责人
updateTaskAssignee(task.getId(), reqVO.getAssigneeUserId());
}
@Override
public void updateTaskAssignee(String id, Long userId) {
taskService.setAssignee(id, String.valueOf(userId));
}
@Override @Override
public void createTaskExt(Task task) { public void createTaskExt(Task task) {
@ -173,6 +228,24 @@ public class BpmTaskServiceImpl implements BpmTaskService{
taskExtMapper.updateByTaskId(taskExtDO); taskExtMapper.updateByTaskId(taskExtDO);
} }
@Override
public void updateTaskExtAssign(Task task) {
BpmTaskExtDO taskExtDO = new BpmTaskExtDO()
.setAssigneeUserId(NumberUtils.parseLong(task.getAssignee()))
.setTaskId(task.getId());
taskExtMapper.updateByTaskId(taskExtDO);
//TODO 创建任务时候 也会调用 updateTaskExtAssign processInstance 名称为空 校验不通过
// 发送通知在事务提交时批量执行操作所以直接查询会无法查询到 ProcessInstance所以这里是通过监听事务的提交来实现
// TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
// @Override
// public void afterCommit() {
// ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
// AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId()));
// messageService.sendMessageWhenTaskAssigned(BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task));
// }
// });
}
/** /**
* 校验任务是否存在 并且是否是分配给自己的任务 * 校验任务是否存在 并且是否是分配给自己的任务
* @param userId 用户 id * @param userId 用户 id