瀏覽代碼

工作流 Flowable 转办任务的实现

jason 3 年之前
父節點
當前提交
41e4283f99

+ 1 - 1
yudao-module-bpm/yudao-module-bpm-impl-activiti/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java

@@ -37,7 +37,7 @@ public class BpmTaskController {
     @GetMapping("done-page")
     @ApiOperation("获取 Done 已办任务分页")
     @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));
     }
 

+ 6 - 3
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/api/task/FlowableProcessInstanceApiImpl.java

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

+ 15 - 0
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java

@@ -37,6 +37,13 @@ public class BpmTaskController {
         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")
     @ApiOperation(value = "获得指定流程实例的任务列表", notes = "包括完成的、未完成的")
     @ApiImplicitParam(name = "processInstanceId", value = "流程实例的编号", required = true, dataTypeClass = String.class)
@@ -61,4 +68,12 @@ public class BpmTaskController {
         taskService.rejectTask(getLoginUserId(), reqVO);
         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);
+    }
 }

+ 30 - 0
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java

@@ -53,6 +53,24 @@ public interface BpmTaskConvert {
                 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({
             @Mapping(source = "processInstance.id", target = "id"),
             @Mapping(source = "processInstance.name", target = "name"),
@@ -111,6 +129,18 @@ public interface BpmTaskConvert {
         taskExtDO.setCreateTime(task.getCreateTime());
         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;
+    }
 }
 
 

+ 5 - 0
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java

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

+ 28 - 1
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java

@@ -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.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 org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
 import org.flowable.engine.delegate.event.FlowableCancelledEvent;
@@ -55,7 +56,6 @@ public interface BpmProcessInstanceService {
      */
     PageResult<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId,
                                                                           @Valid BpmProcessInstanceMyPageReqVO pageReqVO);
-
     /**
      * 创建流程实例(提供给前端)
      *
@@ -66,6 +66,15 @@ public interface BpmProcessInstanceService {
     String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO);
 
     /**
+     * 创建流程实例(提供给内部)
+     *
+     * @param userId 用户编号
+     * @param createReqDTO 创建信息
+     * @return 实例的编号
+     */
+    String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO);
+
+    /**
      * 获得流程实例 VO 信息
      *
      * @param id 流程实例的编号
@@ -90,6 +99,24 @@ public interface BpmProcessInstanceService {
     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 拓展记录
      *
      * @param instance 流程任务

+ 14 - 0
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java

@@ -5,6 +5,7 @@ import cn.hutool.core.lang.Assert;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 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.convert.task.BpmProcessInstanceConvert;
 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
@@ -113,6 +114,14 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
     }
 
     @Override
+    public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) {
+        // 获得流程定义
+        ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey());
+        // 发起流程
+        return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey());
+    }
+
+    @Override
     public BpmProcessInstanceRespVO getProcessInstanceVO(String id) {
         // 获得流程实例
         HistoricProcessInstance processInstance = getHistoricProcessInstance(id);
@@ -173,6 +182,11 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
     }
 
     @Override
+    public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) {
+        return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list();
+    }
+
+    @Override
     public void createProcessInstanceExt(ProcessInstance instance) {
         // 获得流程定义
         ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId());

+ 31 - 0
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java

@@ -25,6 +25,14 @@ public interface BpmTaskService {
      * @return 流程任务分页
      */
     PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageReqVO);
+    /**
+     * 获得已办的流程任务分页
+     *
+     * @param userId 用户编号
+     * @param pageReqVO 分页请求
+     * @return 流程任务分页
+     */
+    PageResult<BpmTaskDonePageItemRespVO> getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageReqVO);
 
     /**
      * 获得流程任务 Map
@@ -70,6 +78,22 @@ public interface BpmTaskService {
     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 拓展记录
      *
      * @param task 任务实体
@@ -83,4 +107,11 @@ public interface BpmTaskService {
      */
     void updateTaskExtComplete(Task task);
 
+    /**
+     * 更新 Task 拓展记录,并发送通知
+     *
+     * @param task 任务实体
+     */
+    void updateTaskExtAssign(Task task);
+
 }

+ 73 - 0
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java

@@ -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.mysql.task.BpmTaskExtMapper;
 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.dto.DeptRespDTO;
 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.TaskQuery;
 import org.flowable.task.api.history.HistoricTaskInstance;
+import org.flowable.task.api.history.HistoricTaskInstanceQuery;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.support.TransactionSynchronization;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
 
 import javax.annotation.Resource;
 import javax.validation.Valid;
@@ -56,6 +60,8 @@ public class BpmTaskServiceImpl implements BpmTaskService{
     private DeptApi deptApi;
     @Resource
     private BpmTaskExtMapper taskExtMapper;
+    @Resource
+    private BpmMessageService messageService;
 
     @Override
     public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) {
@@ -90,6 +96,42 @@ public class BpmTaskServiceImpl implements BpmTaskService{
     }
 
     @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
     public List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds) {
         if (CollUtil.isEmpty(processInstanceIds)) {
             return Collections.emptyList();
@@ -158,6 +200,19 @@ public class BpmTaskServiceImpl implements BpmTaskService{
                 .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
     public void createTaskExt(Task task) {
@@ -173,6 +228,24 @@ public class BpmTaskServiceImpl implements BpmTaskService{
         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