Browse Source

!62 工作流的流程任务相关
Merge pull request !62 from 芋道源码/feature/activiti

芋道源码 3 years ago
parent
commit
8a3488f3d1
83 changed files with 2737 additions and 719 deletions
  1. 1 24
      sql/ruoyi-vue-pro.sql
  2. 4 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/BpmProcessDefinitionController.http
  3. 9 8
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/BpmProcessDefinitionController.java
  4. 19 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/BpmProcessDefinitionListReqVO.java
  5. 0 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/BpmProcessDefinitionPageItemRespVO.java
  6. 18 2
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmProcessInstanceController.http
  7. 21 4
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmProcessInstanceController.java
  8. 9 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmTaskController.http
  9. 79 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmTaskController.java
  10. 23 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstanceCancelReqVO.java
  11. 0 2
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstanceCreateReqVO.java
  12. 38 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstanceMyPageReqVO.java
  13. 55 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstancePageItemRespVO.java
  14. 25 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskApproveReqVO.java
  15. 66 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskDonePageItemRespVO.java
  16. 32 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskDonePageReqVO.java
  17. 21 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskRejectReqVO.java
  18. 54 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskTodoPageItemRespVO.java
  19. 32 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskTodoPageReqVO.java
  20. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/FileResp.java
  21. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/TaskHandleVO.java
  22. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/TaskQueryReqVO.java
  23. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/TaskStepVO.java
  24. 0 73
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/TaskController.java
  25. 0 17
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/vo/TaskReqVO.java
  26. 0 16
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/vo/TodoTaskPageReqVO.java
  27. 0 37
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/vo/TodoTaskRespVO.java
  28. 31 5
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/definition/BpmDefinitionConvert.java
  29. 61 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/task/BpmProcessInstanceConvert.java
  30. 103 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/task/BpmTaskConvert.java
  31. 0 44
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/workflow/TaskConvert.java
  32. 3 3
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmProcessDefinitionExtDO.java
  33. 81 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/task/BpmProcessInstanceExtDO.java
  34. 79 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/task/BpmTaskExtDO.java
  35. 0 4
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/task/package-info.java
  36. 4 4
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmProcessDefinitionExtMapper.java
  37. 31 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/task/BpmProcessInstanceExtMapper.java
  38. 22 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/task/BpmTaskExtMapper.java
  39. 5 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/BpmErrorCodeConstants.java
  40. 19 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/task/BpmProcessInstanceDeleteReasonEnum.java
  41. 29 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/task/BpmProcessInstanceResultEnum.java
  42. 8 10
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/task/BpmProcessInstanceStatusEnum.java
  43. 26 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/BpmActivitiConfiguration.java
  44. 6 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/package-info.java
  45. 20 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/BpmProcessDefinitionService.java
  46. 36 9
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmProcessDefinitionServiceImpl.java
  47. 3 3
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/oa/LeaveApplyEndProcessor.java
  48. 2 2
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/oa/impl/OALeaveServiceImpl.java
  49. 128 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmProcessInstanceService.java
  50. 99 18
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java
  51. 152 32
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmProcessInstanceServiceImpl.java
  52. 207 64
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java
  53. 58 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/listener/BpmProcessInstanceEventListener.java
  54. 53 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/listener/BpmTackActivitiEventListener.java
  55. 49 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/listener/BpmTaskEventListener.java
  56. 3 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/impl/SysUserServiceImpl.java
  57. 1 1
      yudao-admin-ui/package.json
  58. 8 0
      yudao-admin-ui/src/api/bpm/definition.js
  59. 28 0
      yudao-admin-ui/src/api/bpm/processInstance.js
  60. 41 0
      yudao-admin-ui/src/api/bpm/task.js
  61. 0 1
      yudao-admin-ui/src/components/bpmnProcessDesigner/package/designer/plugins/palette/index.js
  62. 30 20
      yudao-admin-ui/src/components/bpmnProcessDesigner/package/penal/base/ElementBaseInfo.vue
  63. 7 2
      yudao-admin-ui/src/components/parser/Parser.vue
  64. 12 0
      yudao-admin-ui/src/router/index.js
  65. 26 0
      yudao-admin-ui/src/utils/dateUtils.js
  66. 2 0
      yudao-admin-ui/src/utils/dict.js
  67. 1 1
      yudao-admin-ui/src/views/bpm/definition/index.vue
  68. 1 10
      yudao-admin-ui/src/views/bpm/model/modelEditor.vue
  69. 173 0
      yudao-admin-ui/src/views/bpm/processInstance/create.vue
  70. 209 0
      yudao-admin-ui/src/views/bpm/processInstance/index.vue
  71. 133 0
      yudao-admin-ui/src/views/bpm/task/done.vue
  72. 122 0
      yudao-admin-ui/src/views/bpm/task/todo.vue
  73. 0 286
      yudao-admin-ui/src/views/oa/todo/index.vue
  74. 3 1
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java
  75. 4 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageResult.java
  76. 9 0
      yudao-framework/yudao-spring-boot-starter-activiti/pom.xml
  77. 11 0
      yudao-framework/yudao-spring-boot-starter-activiti/src/main/java/cn/iocoder/yudao/framework/activiti/config/YudaoActivitiConfiguration.java
  78. 40 0
      yudao-framework/yudao-spring-boot-starter-activiti/src/main/java/cn/iocoder/yudao/framework/activiti/core/util/ActivitiUtils.java
  79. 37 0
      yudao-framework/yudao-spring-boot-starter-activiti/src/main/java/cn/iocoder/yudao/framework/activiti/core/web/ActivitiWebFilter.java
  80. 1 0
      yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/dataobject/BaseDO.java
  81. 5 0
      yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
  82. 0 9
      yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java
  83. 5 1
      更新日志.md

File diff suppressed because it is too large
+ 1 - 24
sql/ruoyi-vue-pro.sql


+ 4 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/BpmProcessDefinitionController.http

@@ -0,0 +1,4 @@
+### 请求 /bpm/process-definition/list 接口 => 成功
+GET {{baseUrl}}/bpm/process-definition/list?suspensionState=1
+tenant-id: 1
+Authorization: Bearer {{token}}

+ 9 - 8
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/BpmProcessDefinitionController.java

@@ -1,7 +1,9 @@
 package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition;
 
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionListReqVO;
 import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageItemRespVO;
 import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionRespVO;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
@@ -17,6 +19,8 @@ import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 
+import java.util.List;
+
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 
 @Api(tags = "流程定义")
@@ -36,14 +40,11 @@ public class BpmProcessDefinitionController {
         return success(bpmDefinitionService.getProcessDefinitionPage(pageReqVO));
     }
 
-    // TODO 芋艿:需要重写该方法
-    @GetMapping(value = "/getStartForm")
-    public CommonResult<String> getStartForm(@RequestParam("processKey") String processKey){
-//        final ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().
-//                processDefinitionKey(processKey).latestVersion().singleResult();
-//        processRuntime.processDefinition(processDefinition.getId()).getFormKey();
-        // TODO 这样查似乎有问题??, 暂时写死
-        return success("/flow/leave/apply");
+    @GetMapping ("/list")
+    @ApiOperation(value = "获得流程定义列表")
+    public CommonResult<List<BpmProcessDefinitionRespVO>> getProcessDefinitionList(
+            BpmProcessDefinitionListReqVO listReqVO) {
+        return success(bpmDefinitionService.getProcessDefinitionList(listReqVO));
     }
 
     @GetMapping ("/get-bpmn-xml")

+ 19 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/BpmProcessDefinitionListReqVO.java

@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@ApiModel("流程定义列表 Request VO")
+public class BpmProcessDefinitionListReqVO extends PageParam {
+
+    @ApiModelProperty(value = "中断状态", example = "1", notes = "参见 SuspensionState 枚举")
+    private Integer suspensionState;
+
+}

+ 0 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/BpmProcessDefinitionPageItemRespVO.java

@@ -20,5 +20,4 @@ public class BpmProcessDefinitionPageItemRespVO extends BpmProcessDefinitionResp
     @ApiModelProperty(value = "部署时间", required = true)
     private Date deploymentTime;
 
-
 }

+ 18 - 2
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmProcessInstanceController.http

@@ -1,13 +1,29 @@
-### 请求 /login 接口 => 成功
+### 请求 /bpm/process-instance/create 接口 => 成功
 POST {{baseUrl}}/bpm/process-instance/create
 Content-Type: application/json
 tenant-id: 1
 Authorization: Bearer {{token}}
 
 {
-  "processDefinitionId": "leave:7:20ada39c-6c95-11ec-88b1-cacd34981f8e",
+  "processDefinitionId": "gateway_test:2:00e52d8e-701b-11ec-aca9-a2380e71991a",
   "variables": {
     "a": 1,
     "b": "2"
   }
 }
+
+### 请求 /bpm/process-instance/cancel 接口 => 成功
+DELETE {{baseUrl}}/bpm/process-instance/cancel
+Content-Type: application/json
+tenant-id: 1
+Authorization: Bearer {{token}}
+
+{
+  "id": "b9220387-7088-11ec-bcae-a2380e71991a",
+  "reason": "我就取消"
+}
+
+### 请求 /bpm/process-instance/my-page 接口 => 成功
+GET {{baseUrl}}/bpm/process-instance/my-page
+tenant-id: 1
+Authorization: Bearer {{token}}

+ 21 - 4
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmProcessInstanceController.java

@@ -1,15 +1,16 @@
 package cn.iocoder.yudao.adminserver.modules.bpm.controller.task;
 
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceCancelReqVO;
 import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceCreateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceMyPageReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstancePageItemRespVO;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmProcessInstanceService;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
 import javax.validation.Valid;
@@ -26,10 +27,26 @@ public class BpmProcessInstanceController {
     @Resource
     private BpmProcessInstanceService processInstanceService;
 
+    // TODO 芋艿:权限
+
     @PostMapping("/create")
     @ApiOperation("新建流程实例")
     public CommonResult<String> createProcessInstance(@Valid @RequestBody BpmProcessInstanceCreateReqVO createReqVO) {
         return success(processInstanceService.createProcessInstance(getLoginUserId(), createReqVO));
     }
 
+    @DeleteMapping("/cancel")
+    @ApiOperation(value = "取消流程实例", notes = "撤回发起的流程")
+    public CommonResult<Boolean> cancelProcessInstance(@Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) {
+        processInstanceService.cancelProcessInstance(getLoginUserId(), cancelReqVO);
+        return success(true);
+    }
+
+    @GetMapping("/my-page")
+    @ApiOperation(value = "获得我的实例分页列表", notes = "在【我的流程】菜单中,进行调用")
+    public CommonResult<PageResult<BpmProcessInstancePageItemRespVO>> getMyProcessInstancePage(
+            @Valid BpmProcessInstanceMyPageReqVO pageReqVO) {
+        return success(processInstanceService.getMyProcessInstancePage(getLoginUserId(), pageReqVO));
+    }
+
 }

+ 9 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmTaskController.http

@@ -0,0 +1,9 @@
+### 请求 /bpm/task/todo-page 接口 => 成功
+GET {{baseUrl}}/bpm/task/todo-page
+tenant-id: 1
+Authorization: Bearer {{token}}
+
+### 请求 /bpm/task/done-page 接口 => 成功
+GET {{baseUrl}}/bpm/task/done-page?pageSize=100
+tenant-id: 1
+Authorization: Bearer {{token}}

+ 79 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmTaskController.java

@@ -0,0 +1,79 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.task;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.*;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmTaskService;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
+
+@Api(tags = "流程任务")
+@RestController
+@RequestMapping("/bpm/task")
+@Validated
+public class BpmTaskController {
+
+    @Resource
+    private BpmTaskService taskService;
+
+    // TODO 芋艿:权限、validation;
+
+    @GetMapping("todo-page")
+    @ApiOperation("获取 Todo 待办任务分页")
+    public CommonResult<PageResult<BpmTaskTodoPageItemRespVO>> getTodoTaskPage(@Valid BpmTaskTodoPageReqVO pageVO) {
+        return success(taskService.getTodoTaskPage(getLoginUserId(), pageVO));
+    }
+
+    @GetMapping("done-page")
+    @ApiOperation("获取 Done 已办任务分页")
+    public CommonResult<PageResult<BpmTaskDonePageItemRespVO>> getTodoTaskPage(@Valid BpmTaskDonePageReqVO pageVO) {
+        return success(taskService.getDoneTaskPage(getLoginUserId(), pageVO));
+    }
+
+    @PutMapping("/approve")
+    @ApiOperation("通过任务")
+    public CommonResult<Boolean> approveTask(@Valid @RequestBody BpmTaskApproveReqVO reqVO) {
+        taskService.approveTask(reqVO);
+        return success(true);
+    }
+
+    @PutMapping("/reject")
+    @ApiOperation("不通过任务")
+    public CommonResult<Boolean> rejectTask(@Valid @RequestBody BpmTaskRejectReqVO reqVO) {
+        taskService.rejectTask(reqVO);
+        return success(true);
+    }
+
+    @PostMapping("/task-steps")
+    public CommonResult<TaskHandleVO> getTaskSteps(@RequestBody TaskQueryReqVO taskQuery) {
+        return success(taskService.getTaskSteps(taskQuery));
+    }
+
+    @GetMapping("/process/history-steps")
+    public CommonResult<List<TaskStepVO>> getHistorySteps(@RequestParam("id") String processInstanceId) {
+        return success(taskService.getHistorySteps(processInstanceId));
+    }
+
+    /**
+     * 返回高亮的流转图SVG
+     * @param processInstanceId 流程Id
+     */
+    @GetMapping("/process/highlight-img")
+    public void getHighlightImg(@RequestParam String processInstanceId, HttpServletResponse response) throws IOException {
+        FileResp fileResp = taskService.getHighlightImg(processInstanceId);
+        ServletUtils.writeAttachment(response, fileResp.getFileName(), fileResp.getFileByte());
+    }
+
+}

+ 23 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstanceCancelReqVO.java

@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.Map;
+
+@ApiModel("流程实例的取消 Request VO")
+@Data
+public class BpmProcessInstanceCancelReqVO {
+
+    @ApiModelProperty(value = "流程实例的编号", required = true, example = "1024")
+    @NotEmpty(message = "流程实例的编号不能为空")
+    private String id;
+
+    @ApiModelProperty(value = "取消原因", required = true, example = "不请假了!")
+    @NotEmpty(message = "取消原因不能为空")
+    private String reason;
+
+}

+ 0 - 2
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstanceCreateReqVO.java

@@ -9,8 +9,6 @@ import java.util.Map;
 
 @ApiModel("流程实例的创建 Request VO")
 @Data
-//@EqualsAndHashCode(callSuper = true)
-//@ToString(callSuper = true)
 public class BpmProcessInstanceCreateReqVO {
 
     @ApiModelProperty(value = "流程定义的编号", required = true, example = "1024")

+ 38 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstanceMyPageReqVO.java

@@ -1,6 +1,44 @@
 package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance;
 
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
 
+import java.util.Date;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@ApiModel("流程实例的分页 Item Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
 public class BpmProcessInstanceMyPageReqVO extends PageParam {
+
+    @ApiModelProperty(value = "流程名称", example = "芋道")
+    private String name;
+
+    @ApiModelProperty(value = "流程定义的编号", example = "2048")
+    private String processDefinitionId;
+
+    @ApiModelProperty(value = "流程实例的状态", notes = "参见 bpm_process_instance_status", example = "1")
+    private Integer status;
+
+    @ApiModelProperty(value = "流程实例的结果", notes = "参见 bpm_process_instance_result", example = "2")
+    private Integer result;
+
+    @ApiModelProperty(value = "流程分类", notes = "参见 bpm_model_category 数据字典", example = "1")
+    private String category;
+
+    @ApiModelProperty(value = "开始的创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private Date beginCreateTime;
+
+    @ApiModelProperty(value = "结束的创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private Date endCreateTime;
+
 }

+ 55 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstancePageItemRespVO.java

@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+@ApiModel("流程实例的分页 Item Response VO")
+@Data
+public class BpmProcessInstancePageItemRespVO {
+
+    @ApiModelProperty(value = "流程实例的编号", required = true, example = "1024")
+    private String id;
+
+    @ApiModelProperty(value = "流程名称", required = true, example = "芋道")
+    private String name;
+
+    @ApiModelProperty(value = "流程定义的编号", required = true, example = "2048")
+    private String processDefinitionId;
+
+    @ApiModelProperty(value = "流程分类", required = true, notes = "参见 bpm_model_category 数据字典", example = "1")
+    private String category;
+
+    @ApiModelProperty(value = "流程实例的状态", required = true, notes = "参见 bpm_process_instance_status", example = "1")
+    private Integer status;
+
+    @ApiModelProperty(value = "流程实例的结果", required = true, notes = "参见 bpm_process_instance_result", example = "2")
+    private Integer result;
+
+    @ApiModelProperty(value = "提交时间", required = true)
+    private Date createTime;
+
+    @ApiModelProperty(value = "结束时间", required = true)
+    private Date endTime;
+
+    /**
+     * 当前任务
+     */
+    private List<Task> tasks;
+
+    @ApiModel("流程任务")
+    @Data
+    public static class Task {
+
+        @ApiModelProperty(value = "流程任务的编号", required = true, example = "1024")
+        private String id;
+
+        @ApiModelProperty(value = "任务名称", required = true, example = "芋道")
+        private String name;
+
+    }
+
+}

+ 25 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskApproveReqVO.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.Map;
+
+@ApiModel("通过流程任务的 Request VO")
+@Data
+public class BpmTaskApproveReqVO {
+
+    @ApiModelProperty(value = "任务编号", required = true, example = "1024")
+    @NotEmpty(message = "任务编号不能为空")
+    private String id;
+
+    @ApiModelProperty(value = "审批意见", required = true, example = "不错不错!")
+    @NotEmpty(message = "审批意见不能为空")
+    private String comment;
+
+}

+ 66 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskDonePageItemRespVO.java

@@ -0,0 +1,66 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@ApiModel("流程任务的 Done 已完成的分页项 Response VO")
+@Data
+public class BpmTaskDonePageItemRespVO {
+
+    @ApiModelProperty(value = "任务编号", required = true, example = "1024")
+    private String id;
+
+    @ApiModelProperty(value = "任务名字", required = true, example = "芋道")
+    private String name;
+
+    @ApiModelProperty(value = "接收时间", required = true)
+    private Date claimTime;
+
+    @ApiModelProperty(value = "创建时间", required = true)
+    private Date createTime;
+    @ApiModelProperty(value = "结束时间", required = true)
+    private Date endTime;
+    @ApiModelProperty(value = "持续时间", required = true, example = "1000")
+    private Long durationInMillis;
+
+    @ApiModelProperty(value = "任务结果", required = true, notes = "参见 bpm_process_instance_result", example = "2")
+    private Integer result;
+    @ApiModelProperty(value = "审批建议", required = true, example = "不请假了!")
+    private String comment;
+
+    /**
+     * 所属流程实例
+     */
+    private ProcessInstance processInstance;
+
+    @Data
+    @ApiModel("流程实例")
+    public static class ProcessInstance {
+
+        @ApiModelProperty(value = "流程实例编号", required = true, example = "1024")
+        private String id;
+
+        @ApiModelProperty(value = "流程实例名称", required = true, example = "芋道")
+        private String name;
+
+        @ApiModelProperty(value = "发起人的用户编号", required = true, example = "1024")
+        private Long startUserId;
+
+        @ApiModelProperty(value = "发起人的用户昵称", required = true, example = "芋艿")
+        private String startUserNickname;
+
+        @ApiModelProperty(value = "流程定义的编号", required = true, example = "2048")
+        private String processDefinitionId;
+
+    }
+
+
+    // 任务编号、流程名称、任务节点、流程发起人、接收时间、审批时间、耗时【名称、开始时间】「流程记录、撤回」
+    // 任务编号、任务名称、所属流程、委托代办人、流程发起人、优先级、审批操作、审批意见、耗时、创建时间【名称、开始时间】「申请详情」
+
+    // 任务编号、任务名称、流程名称、流程发起人、接收时间、审批时间、耗时【名称、接收时间】「详情」TODO 撤回
+
+}

+ 32 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskDonePageReqVO.java

@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@ApiModel("流程任务的 Done 已办的分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class BpmTaskDonePageReqVO extends PageParam {
+
+    @ApiModelProperty(value = "流程任务名", example = "芋道")
+    private String name;
+
+    @ApiModelProperty(value = "开始的创建收间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private Date beginCreateTime;
+
+    @ApiModelProperty(value = "结束的创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private Date endCreateTime;
+
+}

+ 21 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskRejectReqVO.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+
+@ApiModel("不通过流程任务的 Request VO")
+@Data
+public class BpmTaskRejectReqVO {
+
+    @ApiModelProperty(value = "任务编号", required = true, example = "1024")
+    @NotEmpty(message = "任务编号不能为空")
+    private String id;
+
+    @ApiModelProperty(value = "审批意见", required = true, example = "不错不错!")
+    @NotEmpty(message = "审批意见不能为空")
+    private String comment;
+
+}

+ 54 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskTodoPageItemRespVO.java

@@ -0,0 +1,54 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@ApiModel("流程任务的 Running 进行中的分页项 Response VO")
+@Data
+public class BpmTaskTodoPageItemRespVO {
+
+    @ApiModelProperty(value = "任务编号", required = true, example = "1024")
+    private String id;
+
+    @ApiModelProperty(value = "任务名字", required = true, example = "芋道")
+    private String name;
+
+    @ApiModelProperty(value = "接收时间", required = true)
+    private Date claimTime;
+
+    @ApiModelProperty(value = "创建时间", required = true)
+    private Date createTime;
+
+    @ApiModelProperty(value = "激活状态", required = true, example = "1", notes = "参见 SuspensionState 枚举")
+    private Integer suspensionState;
+
+    /**
+     * 所属流程实例
+     */
+    private ProcessInstance processInstance;
+
+    @Data
+    @ApiModel("流程实例")
+    public static class ProcessInstance {
+
+        @ApiModelProperty(value = "流程实例编号", required = true, example = "1024")
+        private String id;
+
+        @ApiModelProperty(value = "流程实例名称", required = true, example = "芋道")
+        private String name;
+
+        @ApiModelProperty(value = "发起人的用户编号", required = true, example = "1024")
+        private Long startUserId;
+
+        @ApiModelProperty(value = "发起人的用户昵称", required = true, example = "芋艿")
+        private String startUserNickname;
+
+        @ApiModelProperty(value = "流程定义的编号", required = true, example = "2048")
+        private String processDefinitionId;
+
+    }
+
+}

+ 32 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskTodoPageReqVO.java

@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@ApiModel("流程任务的 TODO 待办的分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class BpmTaskTodoPageReqVO extends PageParam {
+
+    @ApiModelProperty(value = "流程任务名", example = "芋道")
+    private String name;
+
+    @ApiModelProperty(value = "开始的创建收间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private Date beginCreateTime;
+
+    @ApiModelProperty(value = "结束的创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private Date endCreateTime;
+
+}

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/vo/FileResp.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/FileResp.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
 
 import lombok.Data;
 

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/vo/TaskHandleVO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/TaskHandleVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
 
 import lombok.Data;
 import lombok.ToString;

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/vo/TaskQueryReqVO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/TaskQueryReqVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
 
 import lombok.Data;
 import lombok.ToString;

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/vo/TaskStepVO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/TaskStepVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
 
 import lombok.Data;
 import lombok.ToString;

+ 0 - 73
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/TaskController.java

@@ -1,73 +0,0 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow;
-
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*;
-import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmTaskService;
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import org.springframework.web.bind.annotation.*;
-
-import javax.annotation.Resource;
-import javax.servlet.http.HttpServletResponse;
-import javax.validation.Valid;
-import java.io.IOException;
-import java.util.List;
-
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-
-// TODO @json:swagger 和 validation 的注解,后续要补全下哈。可以等 workflow 基本写的差不多之后
-@Api(tags = "工作流待办任务")
-@RestController
-@RequestMapping("/workflow/task")
-public class TaskController {
-
-    @Resource
-    private BpmTaskService bpmTaskService;
-
-    @GetMapping("/todo/page")
-    @ApiOperation("获取待办任务分页")
-    public CommonResult<PageResult<TodoTaskRespVO>> getTodoTaskPage(@Valid TodoTaskPageReqVO pageVO) {
-        return success(bpmTaskService.getTodoTaskPage(pageVO));
-    }
-
-    @GetMapping("/claim")
-    @ApiOperation("签收任务")
-    public CommonResult<Boolean> claimTask(@RequestParam("id") String taskId) {
-        bpmTaskService.claimTask(taskId);
-        return success(true);
-    }
-
-    @PostMapping("/task-steps")
-    public CommonResult<TaskHandleVO> getTaskSteps(@RequestBody TaskQueryReqVO taskQuery) {
-        return success(bpmTaskService.getTaskSteps(taskQuery));
-    }
-
-    @PostMapping("/formKey")
-    public CommonResult<TodoTaskRespVO> getTaskFormKey(@RequestBody TaskQueryReqVO taskQuery) {
-        return success(bpmTaskService.getTaskFormKey(taskQuery));
-    }
-
-    @PostMapping("/complete")
-    public CommonResult<Boolean> complete(@RequestBody TaskReqVO taskReq) {
-        bpmTaskService.completeTask(taskReq);
-        return success(true);
-    }
-
-    @GetMapping("/process/history-steps")
-    public CommonResult<List<TaskStepVO>> getHistorySteps(@RequestParam("id") String processInstanceId) {
-        return success(bpmTaskService.getHistorySteps(processInstanceId));
-    }
-
-    /**
-     * 返回高亮的流转图SVG
-     * @param processInstanceId 流程Id
-     */
-    @GetMapping("/process/highlight-img")
-    public void getHighlightImg(@RequestParam String processInstanceId, HttpServletResponse response) throws IOException {
-        FileResp fileResp = bpmTaskService.getHighlightImg(processInstanceId);
-        ServletUtils.writeAttachment(response, fileResp.getFileName(), fileResp.getFileByte());
-    }
-
-}

+ 0 - 17
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/vo/TaskReqVO.java

@@ -1,17 +0,0 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo;
-
-import lombok.Data;
-import lombok.ToString;
-
-import java.util.Map;
-
-@Data
-@ToString
-public class TaskReqVO {
-
-    private String taskId;
-
-    private Map<String,Object> variables;
-
-    private String comment;
-}

+ 0 - 16
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/vo/TodoTaskPageReqVO.java

@@ -1,16 +0,0 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo;
-
-import cn.iocoder.yudao.framework.common.pojo.PageParam;
-import io.swagger.annotations.ApiModel;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-@ApiModel("待办任务申请分页 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class TodoTaskPageReqVO extends PageParam {
-
-    private String assignee;
-}

+ 0 - 37
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/vo/TodoTaskRespVO.java

@@ -1,37 +0,0 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo;
-
-import io.swagger.annotations.ApiModel;
-import lombok.Data;
-import lombok.ToString;
-
-@ApiModel("待办任务 Response VO")
-@Data
-@ToString
-public class TodoTaskRespVO {
-
-    // TODO @jason:swagger 注解。这样接口文档才完整哈
-
-    private String id;
-
-
-    private String processInstanceId;
-
-    /**
-     * 1:未签收
-     * 2:已签收
-     */
-    private Integer status;
-
-
-    private String processName;
-
-
-    private String processKey;
-
-
-    private String businessKey;
-
-
-    private String formKey;
-
-}

+ 31 - 5
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/definition/BpmDefinitionConvert.java

@@ -1,7 +1,8 @@
 package cn.iocoder.yudao.adminserver.modules.bpm.convert.definition;
 
 import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageItemRespVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
 import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmDefinitionCreateReqDTO;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
@@ -9,10 +10,14 @@ import org.activiti.engine.impl.persistence.entity.SuspensionState;
 import org.activiti.engine.repository.Deployment;
 import org.activiti.engine.repository.ProcessDefinition;
 import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.Mappings;
+import org.mapstruct.Named;
 import org.mapstruct.factory.Mappers;
 
 import java.util.List;
 import java.util.Map;
+import java.util.function.Function;
 
 /**
  * Bpm 流程定义的 Convert
@@ -25,17 +30,17 @@ public interface BpmDefinitionConvert {
     BpmDefinitionConvert INSTANCE = Mappers.getMapper(BpmDefinitionConvert.class);
 
     default List<BpmProcessDefinitionPageItemRespVO> convertList(List<ProcessDefinition> list, Map<String, Deployment> deploymentMap,
-                               Map<String, BpmProcessDefinitionDO> processDefinitionDOMap, Map<Long, BpmFormDO> formMap) {
+                                                                 Map<String, BpmProcessDefinitionExtDO> processDefinitionDOMap, Map<Long, BpmFormDO> formMap) {
         return CollectionUtils.convertList(list, definition -> {
             Deployment deployment = definition.getDeploymentId() != null ? deploymentMap.get(definition.getDeploymentId()) : null;
-            BpmProcessDefinitionDO definitionDO = processDefinitionDOMap.get(definition.getId());
+            BpmProcessDefinitionExtDO definitionDO = processDefinitionDOMap.get(definition.getId());
             BpmFormDO form = definitionDO != null ? formMap.get(definitionDO.getFormId()) : null;
             return convert(definition, deployment, definitionDO, form);
         });
     }
 
     default BpmProcessDefinitionPageItemRespVO convert(ProcessDefinition bean, Deployment deployment,
-                                                       BpmProcessDefinitionDO processDefinitionDO, BpmFormDO form) {
+                                                       BpmProcessDefinitionExtDO processDefinitionDO, BpmFormDO form) {
         BpmProcessDefinitionPageItemRespVO respVO = convert(bean);
         respVO.setSuspensionState(bean.isSuspended() ? SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode());
         if (deployment != null) {
@@ -53,6 +58,27 @@ public interface BpmDefinitionConvert {
 
     BpmProcessDefinitionPageItemRespVO convert(ProcessDefinition bean);
 
-    BpmProcessDefinitionDO convert2(BpmDefinitionCreateReqDTO bean);
+    BpmProcessDefinitionExtDO convert2(BpmDefinitionCreateReqDTO bean);
+
+    default List<BpmProcessDefinitionRespVO> convertList3(List<ProcessDefinition> list,
+                                                          Map<String, BpmProcessDefinitionExtDO> processDefinitionDOMap) {
+        return CollectionUtils.convertList(list, processDefinition -> {
+            BpmProcessDefinitionRespVO respVO = convert3(processDefinition);
+            BpmProcessDefinitionExtDO processDefinitionExtDO = processDefinitionDOMap.get(processDefinition.getId());
+            if (processDefinitionExtDO != null) {
+                respVO.setFormId(processDefinitionExtDO.getFormId());
+            }
+            return respVO;
+        });
+    }
+
+    @Mapping(source = "suspended", target = "suspensionState", qualifiedByName = "convertSuspendedToSuspensionState")
+    BpmProcessDefinitionRespVO convert3(ProcessDefinition bean);
+
+    @Named("convertSuspendedToSuspensionState")
+    default Integer convertSuspendedToSuspensionState(boolean suspended) {
+        return suspended ? SuspensionState.SUSPENDED.getStateCode() :
+                SuspensionState.ACTIVE.getStateCode();
+    }
 
 }

+ 61 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/task/BpmProcessInstanceConvert.java

@@ -0,0 +1,61 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.convert.task;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstancePageItemRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import org.activiti.engine.repository.ProcessDefinition;
+import org.activiti.engine.runtime.ProcessInstance;
+import org.activiti.engine.task.Task;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.Mappings;
+import org.mapstruct.factory.Mappers;
+
+import java.sql.SQLXML;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+
+/**
+ * 流程实例 Convert
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface BpmProcessInstanceConvert {
+
+    BpmProcessInstanceConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceConvert.class);
+
+    @Mappings({
+            @Mapping(source = "instance.startUserId", target = "startUserId"),
+            @Mapping(source = "instance.id", target = "processInstanceId"),
+            @Mapping(source = "instance.startTime", target = "createTime"),
+            @Mapping(source = "definition.id", target = "processDefinitionId"),
+            @Mapping(source = "definition.name", target = "name"),
+            @Mapping(source = "definition.category", target = "category")
+    })
+    BpmProcessInstanceExtDO convert(ProcessInstance instance, ProcessDefinition definition);
+
+    default PageResult<BpmProcessInstancePageItemRespVO> convertPage(PageResult<BpmProcessInstanceExtDO> page,
+                                                                     Map<String, List<Task>> taskMap) {
+        List<BpmProcessInstancePageItemRespVO> list = convertList(page.getList());
+        list.forEach(respVO -> respVO.setTasks(convertList2(taskMap.get(respVO.getId()))));
+        return new PageResult<>(list, page.getTotal());
+    }
+
+    List<BpmProcessInstancePageItemRespVO> convertList(List<BpmProcessInstanceExtDO> list);
+
+    List<BpmProcessInstancePageItemRespVO.Task> convertList2(List<Task> tasks);
+
+    @Mapping(source = "processInstanceId", target = "id")
+    BpmProcessInstancePageItemRespVO convert(BpmProcessInstanceExtDO bean);
+
+    @Mappings({
+            @Mapping(source = "id", target = "processInstanceId"),
+            @Mapping(source = "startDate", target = "createTime"),
+            @Mapping(source = "initiator", target = "startUserId"),
+            @Mapping(source = "status", target = "status", ignore = true)
+    })
+    BpmProcessInstanceExtDO convert(org.activiti.api.process.model.ProcessInstance bean);
+
+}

+ 103 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/task/BpmTaskConvert.java

@@ -0,0 +1,103 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.convert.task;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.BpmTaskDonePageItemRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.BpmTaskTodoPageItemRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.TaskStepVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmTaskExtDO;
+import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import org.activiti.engine.history.HistoricActivityInstance;
+import org.activiti.engine.history.HistoricProcessInstance;
+import org.activiti.engine.history.HistoricTaskInstance;
+import org.activiti.engine.impl.persistence.entity.SuspensionState;
+import org.activiti.engine.runtime.ProcessInstance;
+import org.activiti.engine.task.Task;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.Mappings;
+import org.mapstruct.Named;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Bpm 任务 Convert
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface BpmTaskConvert {
+
+    BpmTaskConvert INSTANCE = Mappers.getMapper(BpmTaskConvert.class);
+
+    @Mappings(value = {
+            @Mapping(source = "activityName", target = "stepName"),
+            @Mapping(source = "assignee", target = "assignee")
+    })
+    TaskStepVO convert(HistoricActivityInstance instance);
+
+    default List<BpmTaskTodoPageItemRespVO> convertList(List<Task> tasks, Map<String, ProcessInstance> processInstanceMap,
+                                                        Map<Long, SysUserDO> userMap) {
+        return CollectionUtils.convertList(tasks, task -> {
+            ProcessInstance processInstance = processInstanceMap.get(task.getProcessInstanceId());
+            return convert(task, processInstance, userMap.get(Long.valueOf(processInstance.getStartUserId())));
+        });
+    }
+
+    @Mappings({
+            @Mapping(source = "task.id", target = "id"),
+            @Mapping(source = "task.name", target = "name"),
+            @Mapping(source = "task.claimTime", target = "claimTime"),
+            @Mapping(source = "task.createTime", target = "createTime"),
+            @Mapping(source = "task.suspended", target = "suspensionState", qualifiedByName = "convertSuspendedToSuspensionState"),
+            @Mapping(source = "processInstance.id", target = "processInstance.id"),
+            @Mapping(source = "processInstance.name", target = "processInstance.name"),
+            @Mapping(source = "processInstance.startUserId", target = "processInstance.startUserId"),
+            @Mapping(source = "processInstance.processDefinitionId", target = "processInstance.processDefinitionId"),
+            @Mapping(source = "user.nickname", target = "processInstance.startUserNickname")
+    })
+    BpmTaskTodoPageItemRespVO convert(Task task, ProcessInstance processInstance, SysUserDO user);
+
+    @Named("convertSuspendedToSuspensionState")
+    default Integer convertSuspendedToSuspensionState(boolean suspended) {
+        return suspended ? SuspensionState.SUSPENDED.getStateCode() :
+                SuspensionState.ACTIVE.getStateCode();
+    }
+
+    default List<BpmTaskDonePageItemRespVO> convertList2(List<HistoricTaskInstance> tasks, Map<String, BpmTaskExtDO> bpmTaskExtDOMap,
+                                                         Map<String, HistoricProcessInstance> historicProcessInstanceMap,
+                                                         Map<Long, SysUserDO> userMap) {
+        return CollectionUtils.convertList(tasks, task -> {
+            BpmTaskExtDO taskExtDO = bpmTaskExtDOMap.get(task.getId());
+            HistoricProcessInstance processInstance = historicProcessInstanceMap.get(task.getProcessInstanceId());
+            SysUserDO userDO = userMap.get(Long.valueOf(processInstance.getStartUserId()));
+            return convert(task, taskExtDO, processInstance, userDO);
+        });
+    }
+
+    @Mappings({
+            @Mapping(source = "task.id", target = "id"),
+            @Mapping(source = "task.name", target = "name"),
+            @Mapping(source = "task.claimTime", target = "claimTime"),
+            @Mapping(source = "task.createTime", target = "createTime"),
+            @Mapping(source = "task.endTime", target = "endTime"),
+            @Mapping(source = "task.durationInMillis", target = "durationInMillis"),
+            @Mapping(source = "taskExtDO.result", target = "result"),
+            @Mapping(source = "taskExtDO.comment", target = "comment"),
+            @Mapping(source = "processInstance.id", target = "processInstance.id"),
+            @Mapping(source = "processInstance.name", target = "processInstance.name"),
+            @Mapping(source = "processInstance.startUserId", target = "processInstance.startUserId"),
+            @Mapping(source = "processInstance.processDefinitionId", target = "processInstance.processDefinitionId"),
+            @Mapping(source = "user.nickname", target = "processInstance.startUserNickname")
+    })
+    BpmTaskDonePageItemRespVO convert(HistoricTaskInstance task, BpmTaskExtDO taskExtDO, HistoricProcessInstance processInstance, SysUserDO user);
+
+    @Mappings({
+            @Mapping(source = "id", target = "taskId"),
+            @Mapping(source = "assignee", target = "assigneeUserId"),
+            @Mapping(source = "createdDate", target = "createTime")
+    })
+    BpmTaskExtDO convert(org.activiti.api.task.model.Task bean);
+
+}

+ 0 - 44
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/workflow/TaskConvert.java

@@ -1,44 +0,0 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.convert.workflow;
-
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.TaskStepVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.TodoTaskRespVO;
-import org.activiti.api.task.model.Task;
-import org.activiti.engine.history.HistoricActivityInstance;
-import org.activiti.engine.repository.ProcessDefinition;
-import org.mapstruct.Mapper;
-import org.mapstruct.Mapping;
-import org.mapstruct.Mappings;
-import org.mapstruct.Named;
-import org.mapstruct.factory.Mappers;
-
-@Mapper
-public interface TaskConvert {
-    TaskConvert INSTANCE = Mappers.getMapper(TaskConvert.class);
-
-    @Mappings(value = {
-            @Mapping(source = "task.id", target = "id"),
-            @Mapping(source = "task.businessKey", target = "businessKey"),
-            @Mapping(source = "task.assignee", target = "status",qualifiedByName = "convertAssigneeToStatus"),
-            @Mapping(source = "definition.name", target = "processName"),
-            @Mapping(source = "definition.key", target = "processKey"),
-            @Mapping(source = "definition.id", target = "processInstanceId")
-    })
-    TodoTaskRespVO convert(Task task, ProcessDefinition definition);
-
-    @Mappings(value = {
-            @Mapping(source = "assignee", target = "status",qualifiedByName = "convertAssigneeToStatus")
-    })
-    TodoTaskRespVO convert(Task task);
-
-    @Named("convertAssigneeToStatus")
-    default Integer convertAssigneeToStatus(String assignee) {
-        //TODO 不应该通过 assignee 定义状态  需要定义更多的状态
-        return assignee == null ?  1 :  2;
-    }
-
-    @Mappings(value = {
-            @Mapping(source = "activityName", target = "stepName"),
-            @Mapping(source = "assignee", target = "assignee")
-    })
-    TaskStepVO convert(HistoricActivityInstance instance);
-}

+ 3 - 3
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmProcessDefinitionDO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmProcessDefinitionExtDO.java

@@ -9,18 +9,18 @@ import org.activiti.engine.repository.ProcessDefinition;
 
 /**
  * Bpm 流程定义的拓展表
- * 主要解决 主要进行 Activiti {@link ProcessDefinition} 不支持拓展字段,所以新建拓展表
+ * 主要解决 Activiti {@link ProcessDefinition} 不支持拓展字段,所以新建拓展表
  *
  * @author 芋道源码
  */
-@TableName(value = "bpm_process_definition", autoResultMap = true)
+@TableName(value = "bpm_process_definition_ext", autoResultMap = true)
 @Data
 @EqualsAndHashCode(callSuper = true)
 @ToString(callSuper = true)
 @Builder
 @NoArgsConstructor
 @AllArgsConstructor
-public class BpmProcessDefinitionDO extends BaseDO {
+public class BpmProcessDefinitionExtDO extends BaseDO {
 
     /**
      * 编号

+ 81 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/task/BpmProcessInstanceExtDO.java

@@ -0,0 +1,81 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum;
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceStatusEnum;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.activiti.engine.history.HistoricProcessInstance;
+import org.activiti.engine.repository.ProcessDefinition;
+import org.activiti.engine.runtime.ProcessInstance;
+
+import java.util.Date;
+
+/**
+ * Bpm 流程实例的拓展表
+ * 主要解决 Activiti {@link ProcessInstance} 和 {@link HistoricProcessInstance} 不支持拓展字段,所以新建拓展表
+ *
+ * @author 芋道源码
+ */
+@TableName(value = "bpm_process_instance_ext", autoResultMap = true)
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+//@Builder
+//@NoArgsConstructor
+//@AllArgsConstructor
+public class BpmProcessInstanceExtDO extends BaseDO {
+
+    /**
+     * 发起流程的用户编号
+     *
+     * 冗余 {@link HistoricProcessInstance#getStartUserId()}
+     */
+    private Long startUserId;
+    /**
+     * 流程实例的名字
+     *
+     * 冗余 {@link ProcessInstance#getName()} 为了筛选
+     */
+    private String name;
+    /**
+     * 流程实例的编号
+     *
+     * 关联 {@link ProcessInstance#getId()}
+     */
+    private String processInstanceId;
+    /**
+     * 流程定义的编号
+     *
+     * 关联 {@link ProcessDefinition#getId()}
+     */
+    private String processDefinitionId;
+    /**
+     * 流程分类
+     *
+     * 冗余 {@link ProcessDefinition#getCategory()}
+     * 数据字典 bpm_model_category
+     */
+    private String category;
+    /**
+     * 流程实例的状态
+     *
+     * 枚举 {@link BpmProcessInstanceStatusEnum}
+     */
+    private Integer status;
+    /**
+     * 流程实例的结果
+     *
+     * 枚举 {@link BpmProcessInstanceResultEnum}
+     */
+    private Integer result;
+    /**
+     * 结束时间
+     *
+     * 冗余 {@link HistoricProcessInstance#getEndTime()}
+     */
+    private Date endTime;
+
+}

+ 79 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/task/BpmTaskExtDO.java

@@ -0,0 +1,79 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.activiti.engine.history.HistoricTaskInstance;
+import org.activiti.engine.repository.ProcessDefinition;
+import org.activiti.engine.runtime.ProcessInstance;
+import org.activiti.engine.task.Task;
+
+import java.util.Date;
+
+/**
+ * Bpm 流程任务的拓展表
+ * 主要解决 Activiti {@link Task} 和 {@link HistoricTaskInstance} 不支持拓展字段,所以新建拓展表
+ *
+ * @author 芋道源码
+ */
+@TableName(value = "bpm_task_ext", autoResultMap = true)
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+//@Builder
+//@NoArgsConstructor
+//@AllArgsConstructor
+public class BpmTaskExtDO extends BaseDO {
+
+    /**
+     * 任务的审批人
+     *
+     * 冗余 {@link Task#getAssignee()}
+     */
+    private Long assigneeUserId;
+    /**
+     * 任务的名字
+     *
+     * 冗余 {@link Task#getName()} 为了筛选
+     */
+    private String name;
+    /**
+     * 任务的编号
+     *
+     * 关联 {@link Task#getId()}
+     */
+    private String taskId;
+    /**
+     * 任务的结果
+     *
+     * 枚举 {@link BpmProcessInstanceResultEnum}
+     */
+    private Integer result;
+    /**
+     * 审批建议
+     */
+    private String comment;
+    /**
+     * 任务的结束时间
+     *
+     * 冗余 {@link HistoricTaskInstance#getEndTime()}
+     */
+    private Date endTime;
+
+    /**
+     * 流程实例的编号
+     *
+     * 关联 {@link ProcessInstance#getId()}
+     */
+    private String processInstanceId;
+    /**
+     * 流程定义的编号
+     *
+     * 关联 {@link ProcessDefinition#getId()}
+     */
+    private String processDefinitionId;
+
+}

+ 0 - 4
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/task/package-info.java

@@ -1,4 +0,0 @@
-/**
- * TODO 芋艿:工作流创建后的定义
- */
-package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task;

+ 4 - 4
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmProcessDefinitionMapper.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmProcessDefinitionExtMapper.java

@@ -1,6 +1,6 @@
 package cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition;
 
-import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import org.apache.ibatis.annotations.Mapper;
@@ -9,10 +9,10 @@ import java.util.Collection;
 import java.util.List;
 
 @Mapper
-public interface BpmProcessDefinitionMapper extends BaseMapper<BpmProcessDefinitionDO> {
+public interface BpmProcessDefinitionExtMapper extends BaseMapper<BpmProcessDefinitionExtDO> {
 
-    default List<BpmProcessDefinitionDO> selectListByProcessDefinitionIds(Collection<String> processDefinitionIds) {
-        return selectList(new QueryWrapper<BpmProcessDefinitionDO>().in("process_definition_id", processDefinitionIds));
+    default List<BpmProcessDefinitionExtDO> selectListByProcessDefinitionIds(Collection<String> processDefinitionIds) {
+        return selectList(new QueryWrapper<BpmProcessDefinitionExtDO>().in("process_definition_id", processDefinitionIds));
     }
 
 }

+ 31 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/task/BpmProcessInstanceExtMapper.java

@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.task;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceMyPageReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface BpmProcessInstanceExtMapper extends BaseMapperX<BpmProcessInstanceExtDO> {
+
+    default PageResult<BpmProcessInstanceExtDO> selectPage(Long userId, BpmProcessInstanceMyPageReqVO reqVO) {
+        return selectPage(reqVO, new QueryWrapperX<BpmProcessInstanceExtDO>()
+                .eqIfPresent("start_user_id", userId)
+                .likeIfPresent("name", reqVO.getName())
+                .eqIfPresent("process_definition_id", reqVO.getProcessDefinitionId())
+                .eqIfPresent("category", reqVO.getCategory())
+                .eqIfPresent("status", reqVO.getStatus())
+                .eqIfPresent("result", reqVO.getResult())
+                .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
+                .orderByDesc("id"));
+    }
+
+    default void updateByProcessInstanceId(BpmProcessInstanceExtDO updateObj) {
+        update(updateObj, new QueryWrapper<BpmProcessInstanceExtDO>()
+                .eq("process_instance_id", updateObj.getProcessInstanceId()));
+    }
+
+}

+ 22 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/task/BpmTaskExtMapper.java

@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.task;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmTaskExtDO;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.Collection;
+import java.util.List;
+
+@Mapper
+public interface BpmTaskExtMapper extends BaseMapperX<BpmTaskExtDO> {
+
+    default void updateByTaskId(BpmTaskExtDO entity) {
+        update(entity, new QueryWrapper<BpmTaskExtDO>().eq("task_id", entity.getTaskId()));
+    }
+
+    default List<BpmTaskExtDO> selectListByTaskIds(Collection<String> taskIds) {
+        return selectList("task_id", taskIds);
+    }
+
+}

+ 5 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/BpmErrorCodeConstants.java

@@ -10,7 +10,6 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
 public interface BpmErrorCodeConstants {
 
     // ==========  通用流程处理 模块 1-009-000-000 ==========
-    ErrorCode PROCESS_INSTANCE_NOT_EXISTS = new ErrorCode(1009000001, "流程实例不存在");
     ErrorCode HIGHLIGHT_IMG_ERROR = new ErrorCode(1009000002, "获取高亮流程图异常");
 
     // ========== OA 流程模块 1-009-001-000 ==========
@@ -34,7 +33,12 @@ public interface BpmErrorCodeConstants {
     ErrorCode PROCESS_DEFINITION_IS_SUSPENDED = new ErrorCode(1009003002, "流程定义处于挂起状态");
 
     // ========== 流程实例 1-009-004-000 ==========
+    ErrorCode PROCESS_INSTANCE_NOT_EXISTS = new ErrorCode(1009004000, "流程实例不存在");
+    ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS = new ErrorCode(1009004001, "流程取消失败,流程不处于运行中");
+    ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF = new ErrorCode(1009004002, "流程取消失败,该流程不是你发起的");
 
+    // ========== 流程实例 1-009-005-000 ==========
+    ErrorCode TASK_COMPLETE_FAIL_NOT_EXISTS = new ErrorCode(1009004000, "审批任务失败,原因:该任务不处于未审批");
 
     // ========== 动态表单模块 1-009-010-000 ==========
     ErrorCode FORM_NOT_EXISTS = new ErrorCode(1009010000, "动态表单不存在");

+ 19 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/task/BpmProcessInstanceDeleteReasonEnum.java

@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.enums.task;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 流程实例的删除原因
+ *
+ * @author 芋道源码
+ */
+@Getter
+@AllArgsConstructor
+public enum BpmProcessInstanceDeleteReasonEnum {
+
+    REJECT_TASK("驳回任务");
+
+    private final String reason;
+
+}

+ 29 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/task/BpmProcessInstanceResultEnum.java

@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.enums.task;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 流程实例的结果
+ *
+ * @author jason
+ */
+@Getter
+@AllArgsConstructor
+public enum BpmProcessInstanceResultEnum {
+
+    PROCESS(1, "处理中"),
+    APPROVE(2, "通过"),
+    REJECT(3, "不通过"),
+    CANCEL(4, "已取消");
+
+    /**
+     * 结果
+     */
+    private final Integer result;
+    /**
+     * 描述
+     */
+    private final String desc;
+
+}

+ 8 - 10
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/FlowStatusEnum.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/task/BpmProcessInstanceStatusEnum.java

@@ -1,29 +1,27 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.enums;
+package cn.iocoder.yudao.adminserver.modules.bpm.enums.task;
 
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 
 /**
- * 流程状态
+ * 流程实例的状态
+ *
+ * @author 芋道源码
  */
 @Getter
 @AllArgsConstructor
-public enum FlowStatusEnum {
+public enum BpmProcessInstanceStatusEnum {
 
-    HANDLE(1, "处理中"),
-
-    PASS(2, "审批通过"),
-
-    REJECTED(3, "审批不通过");
+    RUNNING(1, "进行中"),
+    FINISH(2, "已完成");
 
     /**
      * 状态
      */
     private final Integer status;
-
-
     /**
      * 描述
      */
     private final String desc;
+
 }

+ 26 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/BpmActivitiConfiguration.java

@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.service.task.listener.BpmTackActivitiEventListener;
+import org.activiti.spring.SpringProcessEngineConfiguration;
+import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
+import org.springframework.context.annotation.Configuration;
+
+import javax.annotation.Resource;
+import java.util.Collections;
+
+/**
+ * BPM 模块的 Activiti 配置类
+ */
+@Configuration
+public class BpmActivitiConfiguration implements ProcessEngineConfigurationConfigurer {
+
+    @Resource
+    private BpmTackActivitiEventListener taskActivitiEventListener;
+
+    @Override
+    public void configure(SpringProcessEngineConfiguration configuration) {
+        // 注册监听器,例如说 BpmActivitiEventListener
+        configuration.setEventListeners(Collections.singletonList(taskActivitiEventListener));
+    }
+
+}

+ 6 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/package-info.java

@@ -0,0 +1,6 @@
+/**
+ * 属于 bpm 模块的 framework 封装
+ *
+ * @author 芋道源码
+ */
+package cn.iocoder.yudao.adminserver.modules.bpm.framework;

+ 20 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/BpmProcessDefinitionService.java

@@ -1,7 +1,9 @@
 package cn.iocoder.yudao.adminserver.modules.bpm.service.definition;
 
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionListReqVO;
 import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageItemRespVO;
 import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionRespVO;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmDefinitionCreateReqDTO;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
@@ -30,6 +32,14 @@ public interface BpmProcessDefinitionService {
      */
     PageResult<BpmProcessDefinitionPageItemRespVO> getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageReqVO);
 
+    /**
+     * 获得流程定义列表
+     *
+     * @param listReqVO 列表入参
+     * @return 流程定义列表
+     */
+    List<BpmProcessDefinitionRespVO> getProcessDefinitionList(BpmProcessDefinitionListReqVO listReqVO);
+
     /**
      * 获得流程定义对应的 BPMN XML
      *
@@ -54,6 +64,16 @@ public interface BpmProcessDefinitionService {
      */
     ProcessDefinition getProcessDefinition(String id);
 
+    /**
+     * 获得编号对应的 ProcessDefinition
+     *
+     * 相比 {@link #getProcessDefinition(String)} 方法,category 的取值是正确
+     *
+     * @param id 编号
+     * @return 流程定义
+     */
+    ProcessDefinition getProcessDefinition2(String id);
+
     /**
      * 获得 id 对应的 Deployment
      *

+ 36 - 9
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmProcessDefinitionServiceImpl.java

@@ -2,12 +2,14 @@ package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.impl;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionListReqVO;
 import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageItemRespVO;
 import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionRespVO;
 import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmDefinitionConvert;
-import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
 import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
-import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition.BpmProcessDefinitionMapper;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition.BpmProcessDefinitionExtMapper;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmDefinitionCreateReqDTO;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.form.BpmFormService;
@@ -56,7 +58,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
     private BpmFormService bpmFormService;
 
     @Resource
-    private BpmProcessDefinitionMapper processDefinitionMapper;
+    private BpmProcessDefinitionExtMapper processDefinitionMapper;
 
     @Override
     public PageResult<BpmProcessDefinitionPageItemRespVO> getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageVO) {
@@ -77,14 +79,13 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
         Map<String, Deployment> deploymentMap = getDeploymentMap(deploymentIds);
 
         // 获得 BpmProcessDefinitionDO Map
-        List<BpmProcessDefinitionDO> processDefinitionDOs = Collections.emptyList();
-        processDefinitionDOs = processDefinitionMapper.selectListByProcessDefinitionIds(
+        List<BpmProcessDefinitionExtDO> processDefinitionDOs = processDefinitionMapper.selectListByProcessDefinitionIds(
                 convertList(processDefinitions, ProcessDefinition::getId));
-        Map<String, BpmProcessDefinitionDO> processDefinitionDOMap = CollectionUtils.convertMap(processDefinitionDOs,
-                BpmProcessDefinitionDO::getProcessDefinitionId);
+        Map<String, BpmProcessDefinitionExtDO> processDefinitionDOMap = CollectionUtils.convertMap(processDefinitionDOs,
+                BpmProcessDefinitionExtDO::getProcessDefinitionId);
 
         // 获得 Form Map
-        Set<Long> formIds = CollectionUtils.convertSet(processDefinitionDOs, BpmProcessDefinitionDO::getFormId);
+        Set<Long> formIds = CollectionUtils.convertSet(processDefinitionDOs, BpmProcessDefinitionExtDO::getFormId);
         Map<Long, BpmFormDO> formMap = bpmFormService.getFormMap(formIds);
 
         // 拼接结果
@@ -93,6 +94,27 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
                 processDefinitionDOMap, formMap), definitionCount);
     }
 
+    @Override
+    public List<BpmProcessDefinitionRespVO> getProcessDefinitionList(BpmProcessDefinitionListReqVO listReqVO) {
+        // 拼接查询条件
+        ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery();
+        if (Objects.equals(SuspensionState.SUSPENDED.getStateCode(), listReqVO.getSuspensionState())) {
+            definitionQuery.suspended();
+        } else if (Objects.equals(SuspensionState.ACTIVE.getStateCode(), listReqVO.getSuspensionState())) {
+            definitionQuery.active();
+        }
+        // 执行查询
+        List<ProcessDefinition> processDefinitions = definitionQuery.list();
+
+        // 获得 BpmProcessDefinitionDO Map
+        List<BpmProcessDefinitionExtDO> processDefinitionDOs = processDefinitionMapper.selectListByProcessDefinitionIds(
+                convertList(processDefinitions, ProcessDefinition::getId));
+        Map<String, BpmProcessDefinitionExtDO> processDefinitionDOMap = CollectionUtils.convertMap(processDefinitionDOs,
+                BpmProcessDefinitionExtDO::getProcessDefinitionId);
+        // 执行查询,并返回
+        return BpmDefinitionConvert.INSTANCE.convertList3(processDefinitions, processDefinitionDOMap);
+    }
+
     @Override
     public String getProcessDefinitionBpmnXML(String id) {
         BpmnModel bpmnModel = repositoryService.getBpmnModel(id);
@@ -113,6 +135,11 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
         return repositoryService.getProcessDefinition(id);
     }
 
+    @Override
+    public ProcessDefinition getProcessDefinition2(String id) {
+        return repositoryService.createProcessDefinitionQuery().processDefinitionId(id).singleResult();
+    }
+
     @Override
     public Deployment getDeployment(String id) {
         if (StrUtil.isEmpty(id)) {
@@ -169,7 +196,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
         }
 
         // 插入拓展表
-        BpmProcessDefinitionDO definitionDO = BpmDefinitionConvert.INSTANCE.convert2(createReqDTO)
+        BpmProcessDefinitionExtDO definitionDO = BpmDefinitionConvert.INSTANCE.convert2(createReqDTO)
                 .setProcessDefinitionId(definition.getId());
         processDefinitionMapper.insert(definitionDO);
         return definition.getId();

+ 3 - 3
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/oa/LeaveApplyEndProcessor.java

@@ -2,7 +2,7 @@ package cn.iocoder.yudao.adminserver.modules.bpm.service.oa;
 
 import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.leave.OALeaveDO;
 import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.oa.OALeaveMapper;
-import cn.iocoder.yudao.adminserver.modules.bpm.enums.FlowStatusEnum;
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum;
 import org.activiti.engine.delegate.DelegateExecution;
 import org.activiti.engine.delegate.ExecutionListener;
 import org.springframework.stereotype.Component;
@@ -29,9 +29,9 @@ public class LeaveApplyEndProcessor implements ExecutionListener {
         OALeaveDO updateDo = new OALeaveDO();
         updateDo.setId(Long.valueOf(businessKey));
         if (Objects.equals(approved, true)) {
-            updateDo.setStatus(FlowStatusEnum.PASS.getStatus());
+            updateDo.setStatus(BpmProcessInstanceResultEnum.APPROVE.getResult());
         } else {
-            updateDo.setStatus(FlowStatusEnum.REJECTED.getStatus());
+            updateDo.setStatus(BpmProcessInstanceResultEnum.REJECT.getResult());
         }
 
         leaveMapper.updateById(updateDo);

+ 2 - 2
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/oa/impl/OALeaveServiceImpl.java

@@ -6,7 +6,7 @@ import cn.iocoder.yudao.adminserver.modules.bpm.controller.oa.vo.*;
 import cn.iocoder.yudao.adminserver.modules.bpm.convert.oa.OALeaveConvert;
 import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.leave.OALeaveDO;
 import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.oa.OALeaveMapper;
-import cn.iocoder.yudao.adminserver.modules.bpm.enums.FlowStatusEnum;
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.oa.OALeaveService;
 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysPostDO;
 import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.dept.SysPostMapper;
@@ -62,7 +62,7 @@ public class OALeaveServiceImpl implements OALeaveService {
     public Long createLeave(OALeaveCreateReqVO createReqVO) {
         // 插入 OA 请假单
         OALeaveDO leave = OALeaveConvert.INSTANCE.convert(createReqVO);
-        leave.setStatus(FlowStatusEnum.HANDLE.getStatus());
+        leave.setStatus(BpmProcessInstanceResultEnum.PROCESS.getResult());
         // TODO @jason:应该是存储 userId??
         leave.setUserId(SecurityFrameworkUtils.getLoginUser().getUsername());
         leaveMapper.insert(leave);

+ 128 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmProcessInstanceService.java

@@ -1,8 +1,20 @@
 package cn.iocoder.yudao.adminserver.modules.bpm.service.task;
 
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceCancelReqVO;
 import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceCreateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceMyPageReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstancePageItemRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum;
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import org.activiti.engine.history.HistoricProcessInstance;
+import org.activiti.engine.runtime.ProcessInstance;
 
 import javax.validation.Valid;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * 流程实例 Service 接口
@@ -20,4 +32,120 @@ public interface BpmProcessInstanceService {
      */
     String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO);
 
+    /**
+     * 取消流程实例
+     *
+     * @param userId 用户编号
+     * @param cancelReqVO 取消信息
+     */
+    void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO);
+
+    /**
+     * 删除流程实例
+     *
+     * @param id 流程编号
+     * @param reason 删除原因。可选 {@link BpmProcessInstanceDeleteReasonEnum}
+     */
+    @Deprecated
+    void deleteProcessInstance(String id, String reason);
+
+    /**
+     * 更新流程实例的结果
+     * 1. 如果更新为已拒绝时,会进行任务的删除
+     *
+     * @param id 流程编号
+     * @param result 结果,{@link BpmProcessInstanceResultEnum}
+     */
+    void updateProcessInstanceResult(String id, Integer result);
+
+    /**
+     * 获得流程实例的分页
+     *
+     * @param userId 用户编号
+     * @param pageReqVO 分页请求
+     * @return 流程实例的分页
+     */
+    PageResult<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId,
+                                                                          @Valid BpmProcessInstanceMyPageReqVO pageReqVO);
+
+    /**
+     * 获得流程实例
+     *
+     * @param id 流程实例的编号
+     * @return 流程实例
+     */
+    ProcessInstance getProcessInstance(String id);
+
+    /**
+     * 获得流程实例列表
+     *
+     * @param ids 流程实例的编号集合
+     * @return 流程实例列表
+     */
+    List<ProcessInstance> getProcessInstances(Set<String> ids);
+
+    /**
+     * 获得流程实例 Map
+     *
+     * @param ids 流程实例的编号集合
+     * @return 流程实例列表 Map
+     */
+    default Map<String, ProcessInstance> getProcessInstanceMap(Set<String> ids) {
+        return CollectionUtils.convertMap(getProcessInstances(ids), ProcessInstance::getProcessInstanceId);
+    }
+
+    /**
+     * 获得历史的流程实例
+     *
+     * @param id 流程实例的编号
+     * @return 历史的流程实例
+     */
+    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 流程任务
+     */
+    void createProcessInstanceExt(org.activiti.api.process.model.ProcessInstance instance);
+
+    /**
+     * 更新 ProcessInstance 拓展记录
+     *
+     * @param instance 流程任务
+     */
+    void updateProcessInstanceExt(org.activiti.api.process.model.ProcessInstance instance);
+
+    /**
+     * 更新 ProcessInstance 拓展记录为取消
+     *
+     * @param instance 流程任务
+     */
+    void updateProcessInstanceExtCancel(org.activiti.api.process.model.ProcessInstance instance);
+
+    /**
+     * 更新 ProcessInstance 拓展记录为完成
+     *
+     * @param instance 流程任务
+     */
+    void updateProcessInstanceExtComplete(org.activiti.api.process.model.ProcessInstance instance);
+
 }

+ 99 - 18
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java

@@ -1,57 +1,138 @@
 package cn.iocoder.yudao.adminserver.modules.bpm.service.task;
 
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.*;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import org.activiti.engine.task.Task;
 
+import javax.validation.Valid;
 import java.util.List;
+import java.util.Map;
 
 /**
- * 工作流用户任务服务接口
+ * 流程任务 Service 接口
+ *
+ * @author jason
+ * @author 芋道源码
  */
 public interface BpmTaskService {
 
+    /**
+     * 获得流程任务列表
+     *
+     * @param processInstanceId 流程实例的编号
+     * @return 流程任务列表
+     */
+    List<Task> getTasksByProcessInstanceId(String processInstanceId);
+
+    /**
+     * 获得流程任务列表
+     *
+     * @param processInstanceIds 流程实例的编号数组
+     * @return 流程任务列表
+     */
+    List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds);
+
+    /**
+     * 获得流程任务 Map
+     *
+     * @param processInstanceIds 流程实例的编号数组
+     * @return 流程任务 Map
+     */
+    default Map<String, List<Task>> getTaskMapByProcessInstanceIds(List<String> processInstanceIds) {
+        return CollectionUtils.convertMultiMap(getTasksByProcessInstanceIds(processInstanceIds),
+                Task::getProcessInstanceId);
+    }
 
     /**
-     * 获取当前用户的待办任务, 分页
+     * 获得待办的流程任务分页
+     *
+     * @param userId 用户编号
+     * @param pageReqVO 分页请求
+     * @return 流程任务分页
      */
-    PageResult<TodoTaskRespVO> getTodoTaskPage(TodoTaskPageReqVO pageReqVO);
+    PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageReqVO);
 
     /**
-     * 签收任务
-     * @param taskId  用户任务id
+     * 获得已办的流程任务分页
+     *
+     * @param userId 用户编号
+     * @param pageReqVO 分页请求
+     * @return 流程任务分页
      */
-    void claimTask(String taskId);
+    PageResult<BpmTaskDonePageItemRespVO> getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageReqVO);
 
     /**
-     * 工作流,完成 userTask, 完成用户任务 一般传入参数 1。是否同意(variables).  2. 评论(comment)
-     * variables 变量名 和 评论 由前台传入
-     * @param taskReq 任务参数
+     * 将流程任务分配给指定用户
+     *
+     * @param id 流程任务编号
+     * @param userId 用户编号
      */
-    void completeTask(TaskReqVO taskReq);
+    void updateTaskAssign(String id, Long userId);
+
+    /**
+     * 通过任务
+     *
+     * @param reqVO 通过请求
+     */
+    void approveTask(@Valid BpmTaskApproveReqVO reqVO);
+
+    /**
+     * 不通过任务
+     *
+     * @param reqVO 不通过请求
+     */
+    void rejectTask(@Valid BpmTaskRejectReqVO reqVO);
 
     /**
      * 根据任务id, 查询已经完成的用户任务,未完成的用户任务
      * @param taskQuery 查询参数  一般 taskId
      */
+    @Deprecated
     TaskHandleVO getTaskSteps(TaskQueryReqVO taskQuery);
 
     /**
      * 根据流程实例id, 查询历史用户任务,包括已完成,未完成
      * @param processInstanceId 流程实例id
      */
+    @Deprecated
     List<TaskStepVO> getHistorySteps(String processInstanceId);
 
-    /**
-     * 获取用户任务的 formKey, 对应外置表单, 需要根据formKey 对应业务表单
-     * @param taskQuery 查询参数 ,一般taskId
-     */
-    TodoTaskRespVO getTaskFormKey(TaskQueryReqVO taskQuery);
-
-
     /**
      * 返回高亮的流转进程
      * @param processInstanceId 实例Id
      * @return {@link FileResp} 返回文件
      */
     FileResp getHighlightImg(String processInstanceId);
+
+    // ========== Task 拓展表相关 ==========
+
+    /**
+     * 创建 Task 拓展记录
+     *
+     * @param task 任务实体
+     */
+    void createTaskExt(org.activiti.api.task.model.Task task);
+
+    /**
+     * 更新 Task 拓展记录
+     *
+     * @param task 任务实体
+     */
+    void updateTaskExt(org.activiti.api.task.model.Task task);
+
+    /**
+     * 更新 Task 拓展记录为取消
+     *
+     * @param task 任务实体
+     */
+    void updateTaskExtCancel(org.activiti.api.task.model.Task task);
+
+    /**
+     * 更新 Task 拓展记录为完成
+     *
+     * @param task 任务实体
+     */
+    void updateTaskExtComplete(org.activiti.api.task.model.Task task);
+
 }

+ 152 - 32
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmProcessInstanceServiceImpl.java

@@ -1,30 +1,39 @@
 package cn.iocoder.yudao.adminserver.modules.bpm.service.task.impl;
 
-import cn.hutool.core.lang.Assert;
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceCancelReqVO;
 import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceCreateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceMyPageReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstancePageItemRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.convert.task.BpmProcessInstanceConvert;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.task.BpmProcessInstanceExtMapper;
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum;
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum;
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceStatusEnum;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmProcessInstanceService;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmTaskService;
 import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
-import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import lombok.extern.slf4j.Slf4j;
 import org.activiti.engine.HistoryService;
-import org.activiti.engine.RepositoryService;
 import org.activiti.engine.RuntimeService;
-import org.activiti.engine.TaskService;
-import org.activiti.engine.history.HistoricProcessInstanceQuery;
-import org.activiti.engine.impl.identity.Authentication;
+import org.activiti.engine.history.HistoricProcessInstance;
 import org.activiti.engine.repository.ProcessDefinition;
 import org.activiti.engine.runtime.ProcessInstance;
 import org.activiti.engine.task.Task;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
-import java.util.Map;
+import java.util.*;
 
-import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.PROCESS_DEFINITION_IS_SUSPENDED;
-import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.PROCESS_DEFINITION_NOT_EXISTS;
+import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.*;
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
 
 /**
  * 流程实例 Service 实现类
@@ -43,21 +52,24 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
 @Slf4j
 public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService {
 
-    @Resource
-    private RepositoryService repositoryService;
     @Resource
     private RuntimeService runtimeService;
     @Resource
-    private TaskService taskService;
-    @Resource
     private HistoryService historyService;
 
     @Resource
     private SysUserService userService;
     @Resource
+    @Lazy // 解决循环依赖
+    private BpmTaskService taskService;
+    @Resource
     private BpmProcessDefinitionService processDefinitionService;
 
+    @Resource
+    private BpmProcessInstanceExtMapper processInstanceExtMapper;
+
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public String createProcessInstance(Long userId, BpmProcessInstanceCreateReqVO createReqVO) {
         // 校验流程定义
         ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId());
@@ -68,33 +80,141 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
             throw exception(PROCESS_DEFINITION_IS_SUSPENDED);
         }
 
-        // 设置流程发起人
-        Authentication.setAuthenticatedUserId(String.valueOf(userId));
-
         // 创建流程实例
         Map<String, Object> variables = createReqVO.getVariables();
-        variables.put("INITIATOR", userId); // TODO 芋艿:初始化人员
         ProcessInstance instance = runtimeService.startProcessInstanceById(createReqVO.getProcessDefinitionId(), variables);
+        // 设置流程名字
+        runtimeService.setProcessInstanceName(instance.getId(), definition.getName());
+
+        // TODO 芋艿:临时使用, 保证分配
+        List<Task> tasks = taskService.getTasksByProcessInstanceId(instance.getId());
+        tasks.forEach(task -> taskService.updateTaskAssign(task.getId(), userId));
 
         // 添加初始的评论 TODO 芋艿:在思考下
-        Task task = taskService.createTaskQuery().processInstanceId(instance.getId()).singleResult();
-        if (task != null) {
-            SysUserDO user = userService.getUser(userId);
-            Assert.notNull(user, "用户({})不存在", userId);
-            String type = "normal";
-            taskService.addComment(task.getId(), instance.getProcessInstanceId(), type,
-                    String.format("%s 发起流程申请", user.getNickname()));
-            // TODO 芋艿:应该不用下面两个步骤
-//           taskService.setAssignee(task.getId(), String.valueOf(userId));
-//            taskService.complete(task.getId(), variables);
-        }
+//        Task task = taskService.createTaskQuery().processInstanceId(instance.getId()).singleResult();
+//        if (task != null) {
+//            SysUserDO user = userService.getUser(userId);
+//            Assert.notNull(user, "用户({})不存在", userId);
+//            String type = "normal";
+//            taskService.addComment(task.getId(), instance.getProcessInstanceId(), type,
+//                    String.format("%s 发起流程申请", user.getNickname()));
+//            // TODO 芋艿:应该不用下面两个步骤
+////           taskService.setAssignee(task.getId(), String.valueOf(userId));
+////            taskService.complete(task.getId(), variables);
+//        }
         return instance.getId();
     }
 
-    public void getMyProcessInstancePage(Long userId) {
-        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery()
-                .startedBy(String.valueOf(userId)) // 发起人是自己
-                .orderByProcessInstanceStartTime().desc(); // 按照发起时间倒序
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void cancelProcessInstance(Long userId, BpmProcessInstanceCancelReqVO cancelReqVO) {
+        // 校验流程实例存在
+        ProcessInstance instance = getProcessInstance(cancelReqVO.getId());
+        if (instance == null) {
+            throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS);
+        }
+        // 只能取消自己的
+        if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) {
+            throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF);
+        }
+
+        // 通过删除流程实例,实现流程实例的取消
+        runtimeService.deleteProcessInstance(cancelReqVO.getId(), cancelReqVO.getReason());
+    }
+
+    @Override
+    public void deleteProcessInstance(String id, String reason) {
+        runtimeService.deleteProcessInstance(id, reason);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateProcessInstanceResult(String id, Integer result) {
+        // 删除流程实例,以实现驳回任务时,取消整个审批流程
+        if (Objects.equals(result, BpmProcessInstanceResultEnum.REJECT.getResult())) {
+            deleteProcessInstance(id, BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.getReason());
+        }
+        // 更新 status + result
+        processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(id)
+                .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()).setResult(result));
+    }
+
+    @Override
+    public PageResult<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId,
+                                                                                 BpmProcessInstanceMyPageReqVO pageReqVO) {
+        // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页
+        PageResult<BpmProcessInstanceExtDO> pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO);
+        if (CollUtil.isEmpty(pageResult.getList())) {
+            return new PageResult<>(pageResult.getTotal());
+        }
+
+        // 获得流程 Task Map
+        List<String> processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId);
+        Map<String, List<Task>> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds);
+        // 转换返回
+        return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap);
+    }
+
+    @Override
+    public List<ProcessInstance> getProcessInstances(Set<String> ids) {
+        return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list();
+    }
+
+    @Override
+    public ProcessInstance getProcessInstance(String id) {
+        return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult();
+    }
+
+    /**
+     * 获得历史的流程实例
+     *
+     * @param id 流程实例的编号
+     * @return 历史的流程实例
+     */
+    @Override
+    public HistoricProcessInstance getHistoricProcessInstance(String id) {
+        return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult();
+    }
+
+    @Override
+    public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) {
+        return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list();
+    }
+
+    @Override
+    public void createProcessInstanceExt(org.activiti.api.process.model.ProcessInstance instance) {
+        // 获得流程定义
+        ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId());
+        // 插入 BpmProcessInstanceExtDO 对象
+        BpmProcessInstanceExtDO instanceExtDO = BpmProcessInstanceConvert.INSTANCE.convert(instance)
+                .setCategory(definition.getCategory())
+                .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus())
+                .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
+        processInstanceExtMapper.insert(instanceExtDO);
+    }
+
+    @Override
+    public void updateProcessInstanceExt(org.activiti.api.process.model.ProcessInstance instance) {
+        BpmProcessInstanceExtDO instanceExtDO = BpmProcessInstanceConvert.INSTANCE.convert(instance);
+        processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);
+    }
+
+    @Override
+    public void updateProcessInstanceExtCancel(org.activiti.api.process.model.ProcessInstance instance) {
+        BpmProcessInstanceExtDO instanceExtDO = BpmProcessInstanceConvert.INSTANCE.convert(instance)
+                .setEndTime(new Date()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置
+                .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus())
+                .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult());
+        processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);
+    }
+
+    @Override
+    public void updateProcessInstanceExtComplete(org.activiti.api.process.model.ProcessInstance instance) {
+        BpmProcessInstanceExtDO instanceExtDO = BpmProcessInstanceConvert.INSTANCE.convert(instance)
+                .setEndTime(new Date()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置
+                .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus())
+                .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过
+        processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);
     }
 
 }

+ 207 - 64
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java

@@ -2,19 +2,20 @@ package cn.iocoder.yudao.adminserver.modules.bpm.service.task.impl;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.io.IoUtil;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*;
-import cn.iocoder.yudao.adminserver.modules.bpm.convert.workflow.TaskConvert;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.*;
+import cn.iocoder.yudao.adminserver.modules.bpm.convert.task.BpmTaskConvert;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmTaskExtDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.task.BpmTaskExtMapper;
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmProcessInstanceService;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmTaskService;
+import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
+import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
-import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.framework.common.util.object.PageUtils;
 import lombok.extern.slf4j.Slf4j;
-import org.activiti.api.runtime.shared.query.Page;
-import org.activiti.api.runtime.shared.query.Pageable;
-import org.activiti.api.task.model.Task;
-import org.activiti.api.task.model.builders.ClaimTaskPayloadBuilder;
-import org.activiti.api.task.model.builders.TaskPayloadBuilder;
-import org.activiti.api.task.runtime.TaskRuntime;
 import org.activiti.bpmn.constants.BpmnXMLConstants;
 import org.activiti.bpmn.model.BpmnModel;
 import org.activiti.bpmn.model.FlowNode;
@@ -22,100 +23,210 @@ import org.activiti.bpmn.model.SequenceFlow;
 import org.activiti.engine.HistoryService;
 import org.activiti.engine.RepositoryService;
 import org.activiti.engine.RuntimeService;
+import org.activiti.engine.TaskService;
 import org.activiti.engine.history.HistoricActivityInstance;
 import org.activiti.engine.history.HistoricProcessInstance;
+import org.activiti.engine.history.HistoricTaskInstance;
+import org.activiti.engine.history.HistoricTaskInstanceQuery;
 import org.activiti.engine.repository.ProcessDefinition;
 import org.activiti.engine.runtime.ProcessInstance;
 import org.activiti.engine.task.Comment;
+import org.activiti.engine.task.Task;
+import org.activiti.engine.task.TaskQuery;
 import org.activiti.image.ProcessDiagramGenerator;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.ObjectUtils;
 
 import javax.annotation.Resource;
+import javax.validation.Valid;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.HIGHLIGHT_IMG_ERROR;
-import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS;
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import java.util.*;
 
+import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.*;
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+/**
+ * 流程任务 Service 实现类
+ *
+ * @author jason
+ * @author 芋道源码
+ */
 @Slf4j
 @Service
 public class BpmTaskServiceImpl implements BpmTaskService {
 
     @Resource
-    private  TaskRuntime taskRuntime;
-
+    private TaskService taskService;
     @Resource
-    private org.activiti.engine.TaskService activitiTaskService;
-
+    private RuntimeService runtimeService;
     @Resource
     private HistoryService  historyService;
-
     @Resource
     private RepositoryService repositoryService;
 
     @Resource
-    private RuntimeService runtimeService;
+    private ProcessDiagramGenerator processDiagramGenerator;
 
     @Resource
-    private ProcessDiagramGenerator processDiagramGenerator;
+    private SysUserService userService;
+    @Resource
+    @Lazy // 解决循环依赖
+    private BpmProcessInstanceService processInstanceService;
+
+    @Resource
+    private BpmTaskExtMapper taskExtMapper;
 
     @Override
-    public PageResult<TodoTaskRespVO> getTodoTaskPage(TodoTaskPageReqVO pageReqVO) {
-        // TODO @jason:封装一个方法,用于转换成 activiti 的分页对象
-        final Pageable pageable = Pageable.of((pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize(), pageReqVO.getPageSize());
-        Page<Task> pageTasks = taskRuntime.tasks(pageable);
-        int totalItems = pageTasks.getTotalItems();
-        List<Task> tasks = pageTasks.getContent();
-        final List<TodoTaskRespVO> respVOList = tasks.stream().map(task -> {
-            ProcessDefinition definition = repositoryService.getProcessDefinition(task.getProcessDefinitionId());
-            return  TaskConvert.INSTANCE.convert(task, definition);
-        }).collect(Collectors.toList());
-        return new PageResult<>(respVOList, (long)totalItems);
+    public List<Task> getTasksByProcessInstanceId(String processInstanceId) {
+        return taskService.createTaskQuery().processInstanceId(processInstanceId).list();
     }
 
+    @Override
+    public List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds) {
+        if (CollUtil.isEmpty(processInstanceIds)) {
+            return Collections.emptyList();
+        }
+        return taskService.createTaskQuery().processInstanceIdIn(processInstanceIds).list();
+    }
 
     @Override
-    public void claimTask(String taskId) {
-        taskRuntime.claim(new ClaimTaskPayloadBuilder()
-                                .withTaskId(taskId)
-                                .withAssignee(SecurityFrameworkUtils.getLoginUser().getUsername())
-                                .build());
+    public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) {
+        // 查询待办任务
+        TaskQuery taskQuery = taskService.createTaskQuery()
+                .taskAssignee(String.valueOf(userId)) // 分配给自己
+                .orderByTaskCreateTime().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<Task> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
+        if (CollUtil.isEmpty(tasks)) {
+            return PageResult.empty(taskQuery.count());
+        }
+
+        // 获得 ProcessInstance Map
+        Map<String, ProcessInstance> processInstanceMap = processInstanceService.getProcessInstanceMap(
+                convertSet(tasks, Task::getProcessInstanceId));
+        // 获得 User Map
+        Map<Long, SysUserDO> userMap = userService.getUserMap(
+                convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
+        // 拼接结果
+        return new PageResult<>(BpmTaskConvert.INSTANCE.convertList(tasks, processInstanceMap, userMap),
+                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, SysUserDO> userMap = userService.getUserMap(
+                convertSet(historicProcessInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
+        // 拼接结果
+        return new PageResult<>(BpmTaskConvert.INSTANCE.convertList2(tasks, bpmTaskExtDOMap, historicProcessInstanceMap, userMap),
+                taskQuery.count());
+    }
 
     @Override
-    @Transactional
-    public void completeTask(TaskReqVO taskReq) {
-        final Task task = taskRuntime.task(taskReq.getTaskId());
+    public void updateTaskAssign(String id, Long userId) {
+        taskService.setAssignee(id, String.valueOf(userId));
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void approveTask(BpmTaskApproveReqVO reqVO) {
+        // 校验任务存在
+        Task task = getTask(reqVO.getId());
+        if (task == null) {
+            throw exception(TASK_COMPLETE_FAIL_NOT_EXISTS);
+        }
+        // 校验流程实例存在
+        ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
+        if (instance == null) {
+            throw exception(PROCESS_INSTANCE_NOT_EXISTS);
+        }
 
-        activitiTaskService.addComment(taskReq.getTaskId(), task.getProcessInstanceId(), taskReq.getComment());
+        // 完成任务,审批通过
+        taskService.complete(task.getId(), instance.getProcessVariables()); // TODO 芋艿:variables 的选择
+        // 更新任务拓展表为通过
+        taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId())
+                .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()).setComment(reqVO.getComment()));
 
-        taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(taskReq.getTaskId())
-                .withVariables(taskReq.getVariables())
-                .build());
+        // TODO 芋艿:添加评论
+//        taskService.addComment(task.getId(), task.getProcessInstanceId(), reqVO.getComment());
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void rejectTask(@Valid BpmTaskRejectReqVO reqVO) {
+        // 校验任务存在
+        Task task = getTask(reqVO.getId());
+        if (task == null) {
+            throw exception(TASK_COMPLETE_FAIL_NOT_EXISTS);
+        }
+        // 校验流程实例存在
+        ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
+        if (instance == null) {
+            throw exception(PROCESS_INSTANCE_NOT_EXISTS);
+        }
+
+        // 更新流程实例为不通过
+        processInstanceService.updateProcessInstanceResult(instance.getProcessInstanceId(),
+                BpmProcessInstanceResultEnum.REJECT.getResult());
 
+        // 更新任务拓展表为不通过
+        taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId())
+                .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()).setComment(reqVO.getComment()));
+
+        // TODO 芋艿:添加评论
+//        taskService.addComment(task.getId(), task.getProcessInstanceId(), reqVO.getComment());
+    }
 
     @Override
     public TaskHandleVO getTaskSteps(TaskQueryReqVO taskQuery) {
-        TaskHandleVO handleVO = new TaskHandleVO();
-        final Task task = taskRuntime.task(taskQuery.getTaskId());
-        List<TaskStepVO> steps = getTaskSteps(task.getProcessInstanceId());
-        handleVO.setHistoryTask(steps);
-        return handleVO;
+//        TaskHandleVO handleVO = new TaskHandleVO();
+//        final Task task = taskRuntime.task(taskQuery.getTaskId());
+//        List<TaskStepVO> steps = getTaskSteps(task.getProcessInstanceId());
+//        handleVO.setHistoryTask(steps);
+//        return handleVO;
+        return null;
     }
 
-
     private List<TaskStepVO> getTaskSteps(String processInstanceId) {
         // 获得已完成的活动
         List<HistoricActivityInstance> finished = historyService.createHistoricActivityInstanceQuery()
@@ -126,10 +237,10 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         // 获得对应的步骤
         List<TaskStepVO> steps = new ArrayList<>();
         finished.forEach(instance -> {
-            TaskStepVO stepVO = TaskConvert.INSTANCE.convert(instance);
+            TaskStepVO stepVO = BpmTaskConvert.INSTANCE.convert(instance);
             stepVO.setStatus(1); // TODO @jason:1 这个 magic number 要枚举起来。
             // TODO @jason:可以考虑把 comments 读取后,在统一调用 convert 拼接。另外 Comment 是废弃的类,有没其它可以使用的哈?
-            List<Comment> comments = activitiTaskService.getTaskComments(instance.getTaskId());
+            List<Comment> comments = taskService.getTaskComments(instance.getTaskId());
             if (!CollUtil.isEmpty(comments)) {
                 stepVO.setComment(Optional.ofNullable(comments.get(0)).map(Comment::getFullMessage).orElse(""));
             }
@@ -144,7 +255,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
                 .unfinished().list();
         // 获得对应的步骤
         for (HistoricActivityInstance instance : unfinished) {
-            TaskStepVO stepVO = TaskConvert.INSTANCE.convert(instance);
+            TaskStepVO stepVO = BpmTaskConvert.INSTANCE.convert(instance);
             stepVO.setComment("");
             stepVO.setStatus(0);
             steps.add(stepVO);
@@ -158,12 +269,6 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         return getTaskSteps(processInstanceId);
     }
 
-    @Override
-    public TodoTaskRespVO getTaskFormKey(TaskQueryReqVO taskQuery) {
-        final Task task = taskRuntime.task(taskQuery.getTaskId());
-        return TaskConvert.INSTANCE.convert(task);
-    }
-
     @Override
     public FileResp getHighlightImg(String processInstanceId) {
         // 查询历史
@@ -172,7 +277,8 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
         // 如果不存在实例。 说明数据异常
         if (hpi == null) {
-            throw exception(PROCESS_INSTANCE_NOT_EXISTS);
+//            throw exception(PROCESS_INSTANCE_NOT_EXISTS);
+            throw new RuntimeException("不存在");
         }
         // 如果有结束时间 返回model的流程图
         if (!ObjectUtils.isEmpty(hpi.getEndTime())) {
@@ -285,4 +391,41 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         }
         return highLightedFlowIds;
     }
+
+    private Task getTask(String id) {
+        return taskService.createTaskQuery().taskId(id).singleResult();
+    }
+
+    // ========== Task 拓展表相关 ==========
+
+    @Override
+    public void createTaskExt(org.activiti.api.task.model.Task task) {
+        // 插入 BpmTaskExtDO 记录
+        BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert(task)
+                .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
+        taskExtMapper.insert(taskExtDO);
+    }
+
+    @Override
+    public void updateTaskExt(org.activiti.api.task.model.Task task) {
+        BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert(task);
+        taskExtMapper.updateByTaskId(taskExtDO);
+    }
+
+    @Override
+    public void updateTaskExtCancel(org.activiti.api.task.model.Task task) {
+        BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert(task)
+                .setEndTime(new Date()) // 由于 Task 里没有办法拿到 endTime,所以这里设置
+                .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult());
+        taskExtMapper.updateByTaskId(taskExtDO);
+    }
+
+    @Override
+    public void updateTaskExtComplete(org.activiti.api.task.model.Task task) {
+        BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert(task)
+                .setEndTime(task.getCompletedDate())
+                .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult());
+        taskExtMapper.updateByTaskId(taskExtDO);
+    }
+
 }

+ 58 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/listener/BpmProcessInstanceEventListener.java

@@ -0,0 +1,58 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.service.task.listener;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmProcessInstanceService;
+import org.activiti.api.model.shared.event.RuntimeEvent;
+import org.activiti.api.process.model.ProcessInstance;
+import org.activiti.api.process.model.events.ProcessRuntimeEvent;
+import org.activiti.api.process.runtime.events.listener.ProcessEventListener;
+import org.activiti.api.process.runtime.events.listener.ProcessRuntimeEventListener;
+import org.activiti.api.task.model.events.TaskRuntimeEvent;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 监听 {@link ProcessInstance} 的开始与完成,创建与更新对应的 {@link BpmProcessInstanceExtDO} 记录
+ *
+ * @author 芋道源码
+ */
+@Component
+public class BpmProcessInstanceEventListener<T extends RuntimeEvent<?, ?>>
+        implements ProcessRuntimeEventListener<T> {
+
+    @Resource
+    @Lazy // 解决循环依赖
+    private BpmProcessInstanceService processInstanceService;
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void onEvent(T rawEvent) {
+        // 由于 ProcessRuntimeEventListener 无法保证只监听 ProcessRuntimeEvent 事件,所以通过这样的方式
+        if (!(rawEvent instanceof ProcessRuntimeEvent)) {
+            return;
+        }
+        ProcessRuntimeEvent<ProcessInstance> event = (ProcessRuntimeEvent<ProcessInstance>) rawEvent;
+
+        // 创建时,插入拓展表
+        if (event.getEventType() == ProcessRuntimeEvent.ProcessEvents.PROCESS_CREATED) {
+            processInstanceService.createProcessInstanceExt(event.getEntity());
+            return;
+        }
+        // 取消时,更新拓展表为取消
+        if (event.getEventType() == ProcessRuntimeEvent.ProcessEvents.PROCESS_CANCELLED) {
+            processInstanceService.updateProcessInstanceExtCancel(event.getEntity());
+            return;
+        }
+        // 完成时,更新拓展表为已完成
+        if (event.getEventType() == ProcessRuntimeEvent.ProcessEvents.PROCESS_COMPLETED) {
+            processInstanceService.updateProcessInstanceExtComplete(event.getEntity());
+            return;
+        }
+
+        // 其它事件,进行更新拓展表
+        processInstanceService.updateProcessInstanceExt(event.getEntity());
+    }
+
+}

+ 53 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/listener/BpmTackActivitiEventListener.java

@@ -0,0 +1,53 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.service.task.listener;
+
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
+import org.activiti.api.process.runtime.events.listener.ProcessRuntimeEventListener;
+import org.activiti.api.task.runtime.events.listener.TaskEventListener;
+import org.activiti.engine.delegate.event.ActivitiEvent;
+import org.activiti.engine.delegate.event.ActivitiEventListener;
+import org.activiti.engine.delegate.event.ActivitiEventType;
+import org.activiti.engine.delegate.event.impl.ActivitiEntityEventImpl;
+import org.activiti.engine.impl.persistence.entity.TaskEntity;
+import org.activiti.engine.repository.ProcessDefinition;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 监听 {@link TaskEntity} 相关的事件,设置相关属性。
+ * 目的:解决 {@link TaskEventListener} 无法解决的场景
+ *
+ * @author 芋道源码
+ */
+@Component
+public class BpmTackActivitiEventListener implements ActivitiEventListener {
+
+    @Resource
+    @Lazy // 解决循环依赖
+    private BpmProcessDefinitionService processDefinitionService;
+
+    @Override
+    public void onEvent(ActivitiEvent event) {
+        // Task 创建时,设置其分类,解决 TaskService 未提供 name 的设置方法
+        if (ActivitiEventType.TASK_CREATED == event.getType()) {
+            TaskEntity task = ((TaskEntity) ((ActivitiEntityEventImpl) event).getEntity());
+            if (StrUtil.isNotEmpty(task.getCategory())) {
+                return;
+            }
+            // 设置 name
+            ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition2(task.getProcessDefinitionId());
+            if (processDefinition == null) {
+                return;
+            }
+            task.setCategory(processDefinition.getCategory());
+        }
+    }
+
+    @Override
+    public boolean isFailOnException() {
+        return true;
+    }
+
+}

+ 49 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/listener/BpmTaskEventListener.java

@@ -0,0 +1,49 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.service.task.listener;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmTaskExtDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmTaskService;
+import org.activiti.api.task.model.Task;
+import org.activiti.api.task.model.events.TaskRuntimeEvent;
+import org.activiti.api.task.runtime.events.listener.TaskEventListener;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 监听 {@link Task} 的开始与完成,创建与更新对应的 {@link BpmTaskExtDO} 记录
+ *
+ * @author 芋道源码
+ */
+@Component
+public class BpmTaskEventListener<T extends TaskRuntimeEvent<? extends Task>>
+        implements TaskEventListener<T> {
+
+    @Resource
+    @Lazy // 解决循环依赖
+    private BpmTaskService taskService;
+
+    @Override
+    public void onEvent(T event) {
+        // 创建时,插入拓展表
+        if (event.getEventType() == TaskRuntimeEvent.TaskEvents.TASK_CREATED) {
+            taskService.createTaskExt(event.getEntity());
+            return;
+        }
+
+        // 取消时,更新拓展表为取消
+        if (event.getEventType() == TaskRuntimeEvent.TaskEvents.TASK_CANCELLED) {
+            taskService.updateTaskExtCancel(event.getEntity());
+            return;
+        }
+        // 完成时,更新拓展表为已完成。要注意,在调用 delete ProcessInstance 才会触发该逻辑
+        if (event.getEventType() == TaskRuntimeEvent.TaskEvents.TASK_COMPLETED) {
+            taskService.updateTaskExtComplete(event.getEntity());
+            return;
+        }
+
+        // 其它事件,进行更新拓展表
+        taskService.updateTaskExt(event.getEntity());
+    }
+
+}

+ 3 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/user/impl/SysUserServiceImpl.java

@@ -176,6 +176,9 @@ public class SysUserServiceImpl implements SysUserService {
 
     @Override
     public List<SysUserDO> getUsers(Collection<Long> ids) {
+        if (CollUtil.isEmpty(ids)) {
+            return Collections.emptyList();
+        }
         return userMapper.selectBatchIds(ids);
     }
 

+ 1 - 1
yudao-admin-ui/package.json

@@ -85,7 +85,7 @@
     "@vue/compiler-sfc": "^3.0.1",
     "@vue/eslint-config-prettier": "^5.0.0",
     "axios": "^0.21.1",
-    "bpmn-js": "^7.4.0",
+    "bpmn-js": "^8.8.3",
     "bpmn-js-properties-panel": "^0.37.2",
     "camunda-bpmn-moddle": "^4.4.1",
     "compression-webpack-plugin": "^6.1.1",

+ 8 - 0
yudao-admin-ui/src/api/bpm/definition.js

@@ -8,6 +8,14 @@ export function getProcessDefinitionPage(query) {
   })
 }
 
+export function getProcessDefinitionList(query) {
+  return request({
+    url: '/bpm/process-definition/list',
+    method: 'get',
+    params: query
+  })
+}
+
 export function getProcessDefinitionBpmnXML(id) {
   return request({
     url: '/bpm/process-definition/get-bpmn-xml?id=' + id,

+ 28 - 0
yudao-admin-ui/src/api/bpm/processInstance.js

@@ -0,0 +1,28 @@
+import request from '@/utils/request'
+
+export function getMyProcessInstancePage(query) {
+  return request({
+    url: '/bpm/process-instance/my-page',
+    method: 'get',
+    params: query
+  })
+}
+
+export function createProcessInstance(data) {
+  return request({
+    url: '/bpm/process-instance/create',
+    method: 'POST',
+    data: data
+  })
+}
+
+export function cancelProcessInstance(id, reason) {
+  return request({
+    url: '/bpm/process-instance/cancel',
+    method: 'DELETE',
+    data: {
+      id,
+      reason
+    }
+  })
+}

+ 41 - 0
yudao-admin-ui/src/api/bpm/task.js

@@ -0,0 +1,41 @@
+import request from '@/utils/request'
+
+export function getTodoTaskPage(query) {
+  return request({
+    url: '/bpm/task/todo-page',
+    method: 'get',
+    params: query
+  })
+}
+
+export function getDoneTaskPage(query) {
+  return request({
+    url: '/bpm/task/done-page',
+    method: 'get',
+    params: query
+  })
+}
+
+export function completeTask(data) {
+  return request({
+    url: '/bpm/task/complete',
+    method: 'PUT',
+    data: data
+  })
+}
+
+export function approveTask(data) {
+  return request({
+    url: '/bpm/task/approve',
+    method: 'PUT',
+    data: data
+  })
+}
+
+export function rejectTask(data) {
+  return request({
+    url: '/bpm/task/reject',
+    method: 'PUT',
+    data: data
+  })
+}

+ 0 - 1
yudao-admin-ui/src/components/bpmnProcessDesigner/package/designer/plugins/palette/index.js

@@ -14,7 +14,6 @@
 //   paletteProvider: ["type", PaletteProvider]
 // };
 
-// custom/index.js
 import CustomPalette from "./CustomPalette";
 
 export default {

+ 30 - 20
yudao-admin-ui/src/components/bpmnProcessDesigner/package/penal/base/ElementBaseInfo.vue

@@ -1,26 +1,36 @@
 <template>
   <div class="panel-tab__content">
     <el-form size="mini" label-width="90px" :model="model" :rules="rules" @submit.native.prevent>
-      <el-form-item label="流程标识" prop="key">
-        <el-input v-model="model.key" placeholder="请输入流标标识"
-                  :disabled="model.id !== undefined && model.id.length > 0" @change="handleKeyUpdate" />
-      </el-form-item>
-      <el-form-item label="流程名称" prop="name">
-        <el-input v-model="model.name" placeholder="请输入流程名称" clearable @change="handleNameUpdate" />
-      </el-form-item>
-      <el-form-item label="流程分类" prop="category">
-        <el-select v-model="model.category" placeholder="请选择流程分类" clearable style="width: 100%">
-          <el-option v-for="dict in categoryDictDatas" :key="dict.value" :label="dict.label" :value="dict.value"/>
-        </el-select>
-      </el-form-item>
-      <el-form-item label="流程表单" prop="formId">
-        <el-select v-model="model.formId" placeholder="请选择流程表单,非必选哟!" clearable style="width: 100%">
-          <el-option v-for="form in forms" :key="form.id" :label="form.name" :value="form.id"/>
-        </el-select>
-      </el-form-item>
-      <el-form-item label="流程描述" prop="description">
-        <el-input type="textarea" v-model="model.description" clearable @change="handleDescriptionUpdate" />
-      </el-form-item>
+      <div v-if="elementBaseInfo.$type === 'bpmn:Process'"> <!-- 如果是 Process 信息的时候,使用自定义表单 -->
+        <el-form-item label="流程标识" prop="key">
+          <el-input v-model="model.key" placeholder="请输入流标标识"
+                    :disabled="model.id !== undefined && model.id.length > 0" @change="handleKeyUpdate" />
+        </el-form-item>
+        <el-form-item label="流程名称" prop="name">
+          <el-input v-model="model.name" placeholder="请输入流程名称" clearable @change="handleNameUpdate" />
+        </el-form-item>
+        <el-form-item label="流程分类" prop="category">
+          <el-select v-model="model.category" placeholder="请选择流程分类" clearable style="width: 100%">
+            <el-option v-for="dict in categoryDictDatas" :key="dict.value" :label="dict.label" :value="dict.value"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="流程表单" prop="formId">
+          <el-select v-model="model.formId" placeholder="请选择流程表单,非必选哟!" clearable style="width: 100%">
+            <el-option v-for="form in forms" :key="form.id" :label="form.name" :value="form.id"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="流程描述" prop="description">
+          <el-input type="textarea" v-model="model.description" clearable @change="handleDescriptionUpdate" />
+        </el-form-item>
+      </div>
+      <div v-else>
+        <el-form-item label="ID">
+          <el-input v-model="elementBaseInfo.id" clearable @change="updateBaseInfo('id')"/>
+        </el-form-item>
+        <el-form-item label="名称">
+          <el-input v-model="elementBaseInfo.name" clearable @change="updateBaseInfo('name')" />
+        </el-form-item>
+      </div>
     </el-form>
   </div>
 </template>

+ 7 - 2
yudao-admin-ui/src/components/parser/Parser.vue

@@ -173,8 +173,13 @@ export default {
     submitForm() {
       this.$refs[this.formConf.formRef].validate(valid => {
         if (!valid) return false
-        // 触发sumit事件
-        this.$emit('submit', this[this.formConf.formModel])
+        // 触发 submit 事件
+        // update by 芋道源码
+        // this.$emit('submit', this[this.formConf.formModel])
+        this.$emit('submit', {
+          conf: this.formConfCopy,
+          values: this[this.formConf.formModel]
+        })
         return true
       })
     }

+ 12 - 0
yudao-admin-ui/src/router/index.js

@@ -188,6 +188,18 @@ export const constantRoutes = [
         meta: { title: '流程定义' }
       }
     ]
+  }, {
+    path: '/bpm',
+    component: Layout,
+    hidden: true,
+    children: [
+      {
+        path: 'process-instance/create',
+        component: (resolve) => require(['@/views/bpm/processInstance/create'], resolve),
+        name: '发起流程',
+        meta: { title: '发起流程' }
+      }
+    ]
   },
 ]
 

+ 26 - 0
yudao-admin-ui/src/utils/dateUtils.js

@@ -0,0 +1,26 @@
+/**
+ * 将毫秒,转换成时间字符串。例如说,xx 分钟
+ *
+ * @param ms 毫秒
+ * @returns {string} 字符串
+ */
+export function getDate(ms) {
+  const day = Math.floor(ms / (24 * 60 * 60 * 1000));
+  const hour =  Math.floor((ms / (60 * 60 * 1000) - day * 24));
+  const minute =  Math.floor(((ms / (60 * 1000)) - day * 24 * 60 - hour * 60));
+  const second =  Math.floor((ms / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60));
+  if (day > 0) {
+    return day + "天" + hour + "小时" + minute + "分钟";
+  }
+  if (hour > 0) {
+    return hour + "小时" + minute + "分钟";
+  }
+  if (minute > 0) {
+    return minute + "分钟";
+  }
+  if (second > 0) {
+    return second + "秒";
+  } else {
+    return 0 + "秒";
+  }
+}

+ 2 - 0
yudao-admin-ui/src/utils/dict.js

@@ -36,6 +36,8 @@ export const DICT_TYPE = {
 
   // bpm
   BPM_MODEL_CATEGORY: 'bpm_model_category',
+  BPM_PROCESS_INSTANCE_STATUS: 'bpm_process_instance_status',
+  BPM_PROCESS_INSTANCE_RESULT: 'bpm_process_instance_result',
   OA_LEAVE_STATUS: 'flow_status',
   OA_LEAVE_TYPE: 'oa_leave_type'
 }

+ 1 - 1
yudao-admin-ui/src/views/bpm/definition/index.vue

@@ -29,7 +29,7 @@
           <el-tag size="medium" type="warning" v-else>未部署</el-tag>
         </template>
       </el-table-column>
-      <el-table-column label="激活状态" align="center" prop="version" width="80">
+      <el-table-column label="状态" align="center" prop="version" width="80">
         <template slot-scope="scope">
             <el-tag type="success" v-if="scope.row.suspensionState === 1">激活</el-tag>
             <el-tag type="warning" v-if="scope.row.suspensionState === 2">挂起</el-tag>

+ 1 - 10
yudao-admin-ui/src/views/bpm/model/modelEditor.vue

@@ -175,17 +175,8 @@ export default {
 
 .my-process-designer {
   height: calc(100vh - 84px);
-  //height: 800px !important; // TODO 芋艿:bjs 容器的高度不对,临时改下
-  //z-index: 0 !important;
-  //pointer-events: none !important;
 }
-.process-panel__container { // TODO 芋艿:右边的位置不对,临时改下
-  //margin-top: -800px !important;
-  //float: right;
-  //margin-left: 800px !important;
-  //height: 800px;
-  //z-index: 2147483647 !important;
-  //cursor:pointer !important;
+.process-panel__container {
   position: absolute;
   right: 0;
   top: 55px;

+ 173 - 0
yudao-admin-ui/src/views/bpm/processInstance/create.vue

@@ -0,0 +1,173 @@
+<template>
+  <div class="app-container">
+    <!-- 第一步,通过流程定义的列表,选择对应的流程 -->
+    <div v-if="!selectProcessInstance">
+      <el-table v-loading="loading" :data="list">
+        <el-table-column label="流程名称" align="center" prop="name" width="200">
+          <template slot-scope="scope">
+            <el-button type="text" @click="handleBpmnDetail(scope.row)">
+              <span>{{ scope.row.name }}</span>
+            </el-button>
+          </template>
+        </el-table-column>
+        <el-table-column label="流程分类" align="center" prop="category" width="100">
+          <template slot-scope="scope">
+            <span>{{ getDictDataLabel(DICT_TYPE.BPM_MODEL_CATEGORY, scope.row.category) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="流程版本" align="center" prop="processDefinition.version" width="80">
+          <template slot-scope="scope">
+            <el-tag size="medium" v-if="scope.row">v{{ scope.row.version }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="流程描述" align="center" prop="description" width="300" show-overflow-tooltip />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template slot-scope="scope">
+            <el-button type="text" size="small" icon="el-icon-plus" @click="handleSelect(scope.row)">选择</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <!-- 第二步,填写表单,进行流程的提交 -->
+    <div v-else>
+      <el-card class="box-card" >
+        <div slot="header" class="clearfix">
+          <span class="el-icon-document">{{ selectProcessInstance.name }}</span>
+          <el-button style="float: right;" type="primary" @click="selectProcessInstance = undefined">选择其它流程</el-button>
+        </div>
+        <el-col :span="16" :offset="6">
+          <div>
+            <parser :key="new Date().getTime()" :form-conf="detailForm" @submit="submitForm" />
+          </div>
+        </el-col>
+      </el-card>
+      <el-card class="box-card">
+        <div slot="header" class="clearfix">
+          <span class="el-icon-picture-outline">流程图</span>
+        </div>
+        <my-process-viewer key="designer" v-model="bpmnXML" v-bind="bpmnControlForm" />
+      </el-card>
+    </div>
+
+  </div>
+</template>
+
+<script>
+import {getProcessDefinitionBpmnXML, getProcessDefinitionList} from "@/api/bpm/definition";
+import {DICT_TYPE, getDictDatas} from "@/utils/dict";
+import {getForm} from "@/api/bpm/form";
+import {decodeFields} from "@/utils/formGenerator";
+import Parser from '@/components/parser/Parser'
+import {createProcessInstance} from "@/api/bpm/processInstance";
+
+export default {
+  name: "processDefinition",
+  components: {
+    Parser
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 总条数
+      total: 0,
+      // 表格数据
+      list: [],
+
+      // 流程表单详情
+      detailForm: {
+        fields: []
+      },
+
+      // BPMN 数据
+      bpmnXML: null,
+      bpmnControlForm: {
+        prefix: "activiti"
+      },
+
+      // 流程表单
+      selectProcessInstance: undefined, // 选择的流程实例
+
+      // 数据字典
+      categoryDictDatas: getDictDatas(DICT_TYPE.BPM_MODEL_CATEGORY),
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询流程定义列表 */
+    getList() {
+      this.loading = true;
+      getProcessDefinitionList({
+        suspensionState: 1
+      }).then(response => {
+          this.list = response.data
+          this.loading = false
+        }
+      );
+    },
+    /** 处理选择流程的按钮操作 **/
+    handleSelect(row) {
+      // 如果无表单,则无法发起流程
+      if (!row.formId) {
+        this.$message.error('该流程未绑定表单,无法发起流程!请重新选择你要发起的流程');
+        return;
+      }
+      // 设置选择的流程
+      this.selectProcessInstance = row;
+
+      // 加载对应的表单
+      getForm(row.formId).then(response => {
+        // 设置值
+        const data = response.data
+        this.detailForm = {
+          ...JSON.parse(data.conf),
+          fields: decodeFields(data.fields)
+        }
+      });
+
+      // 加载流程图
+      getProcessDefinitionBpmnXML(row.id).then(response => {
+        this.bpmnXML = response.data
+      })
+    },
+    /** 提交按钮 */
+    submitForm(params) {
+      if (!params) {
+        return;
+      }
+      // 设置表单禁用
+      const conf = params.conf;
+      conf.disabled = true; // 表单禁用
+      conf.formBtns = false; // 按钮隐藏
+
+      // 提交表单,创建流程
+      const variables = params.values;
+      createProcessInstance({
+        processDefinitionId: this.selectProcessInstance.id,
+        variables: variables
+      }).then(response => {
+        this.msgSuccess("发起流程成功");
+        // 关闭当前窗口
+        this.$store.dispatch("tagsView/delView", this.$route);
+        this.$router.go(-1);
+      }).catch(() => {
+        conf.disabled = false; // 表单开启
+        conf.formBtns = true; // 按钮展示
+      })
+    },
+  }
+};
+</script>
+
+<style lang="scss">
+.my-process-designer {
+  height: calc(100vh - 200px);
+}
+
+.box-card {
+  width: 100%;
+  margin-bottom: 20px;
+}
+</style>

+ 209 - 0
yudao-admin-ui/src/views/bpm/processInstance/index.vue

@@ -0,0 +1,209 @@
+<template>
+  <div class="app-container">
+
+    <!-- 搜索工作栏 -->
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="流程名" prop="name">
+        <el-input v-model="queryParams.name" placeholder="请输入流程名" clearable size="small" @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="所属流程" prop="processDefinitionId">
+        <el-input v-model="queryParams.processDefinitionId" placeholder="请输入流程定义的编号" clearable size="small" @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="流程分类" prop="category">
+        <el-select v-model="queryParams.category" placeholder="请选择流程分类" clearable size="small">
+          <el-option v-for="dict in this.getDictDatas(DICT_TYPE.BPM_MODEL_CATEGORY)"
+                     :key="dict.value" :label="dict.label" :value="dict.value"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="提交时间">
+        <el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
+                        type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
+          <el-option v-for="dict in this.getDictDatas(DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS)"
+                     :key="dict.value" :label="dict.label" :value="dict.value"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="结果" prop="result">
+        <el-select v-model="queryParams.result" placeholder="请选择流结果" clearable size="small">
+          <el-option v-for="dict in this.getDictDatas(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT)"
+                     :key="dict.value" :label="dict.label" :value="dict.value"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 操作工具栏 -->
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">发起流程</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <!-- 列表 -->
+    <el-table v-loading="loading" :data="list">
+      <el-table-column label="编号" align="center" prop="id" width="320" />
+      <el-table-column label="流程名" align="center" prop="name" />
+      <el-table-column label="流程分类" align="center" prop="category">
+        <template slot-scope="scope">
+          <span>{{ getDictDataLabel(DICT_TYPE.BPM_MODEL_CATEGORY, scope.row.category) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="当前审批任务" align="center" prop="tasks">
+        <template slot-scope="scope">
+          <el-button v-for="task in scope.row.tasks" type="text" @click="handleFormDetail(task.id)">
+            <span>{{ task.name }}</span>
+          </el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <span>
+            <el-tag type="primary" v-if="scope.row.status === 1"> <!-- 进行中 -->
+              {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS, scope.row.status) }}
+            </el-tag>
+             <el-tag type="success" v-if="scope.row.status === 2"> <!-- 已结束 -->
+              {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS, scope.row.status) }}
+            </el-tag>
+          </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="结果" align="center" prop="result">
+        <template slot-scope="scope">
+          <span>
+            <el-tag type="primary" v-if="scope.row.result === 1"> <!-- 进行中 -->
+              {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
+            </el-tag>
+             <el-tag type="success" v-if="scope.row.result === 2"> <!-- 通过 -->
+              {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
+            </el-tag>
+             <el-tag type="danger" v-if="scope.row.result === 3"> <!-- 不通过 -->
+              {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
+            </el-tag>
+             <el-tag type="info" v-if="scope.row.result === 4"> <!-- 撤回 -->
+              {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
+            </el-tag>
+          </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="提交时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="结束时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.endTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <!-- TODO 芋艿:权限 -->
+          <el-button type="text" size="small" icon="el-icon-delete" v-if="scope.row.result === 1"
+                     @click="handleCancel(scope.row)">取消</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页组件 -->
+    <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
+                @pagination="getList"/>
+
+  </div>
+</template>
+
+<script>
+import {
+  getMyProcessInstancePage,
+  createProcessInstanceExt,
+  updateProcessInstanceExt,
+  deleteProcessInstanceExt,
+  getProcessInstanceExt,
+  getProcessInstanceExtPage,
+  exportProcessInstanceExtExcel, cancelProcessInstance
+} from "@/api/bpm/processInstance";
+import {deleteErrorCode} from "@/api/system/errorCode";
+
+export default {
+  name: "ProcessInstanceExt",
+  components: {
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 工作流的流程实例的拓展列表
+      list: [],
+      // 是否显示弹出层
+      dateRangeCreateTime: [],
+      // 查询参数
+      queryParams: {
+        pageNo: 1,
+        pageSize: 10,
+        name: null,
+        processDefinitionId: null,
+        category: null,
+        status: null,
+        result: null,
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询列表 */
+    getList() {
+      this.loading = true;
+      // 处理查询参数
+      let params = {...this.queryParams};
+      this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
+      // 执行查询
+      getMyProcessInstancePage(params).then(response => {
+        this.list = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNo = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRangeCreateTime = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 新增按钮操作 **/
+    handleAdd() {
+      this.$router.push({ path: "/bpm/process-instance/create"})
+    },
+    /** 取消按钮操作 */
+    handleCancel(row) {
+      const id = row.id;
+      this.$prompt('请输出取消原因?', "取消流程", {
+        type: 'warning',
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        inputPattern: /^[\s\S]*.*[^\s][\s\S]*$/, // 判断非空,且非空格
+        inputErrorMessage: "取消原因不能为空",
+      }).then(({ value }) => {
+        return cancelProcessInstance(id, value);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("取消成功");
+      })
+    },
+  }
+};
+</script>

+ 133 - 0
yudao-admin-ui/src/views/bpm/task/done.vue

@@ -0,0 +1,133 @@
+<template>
+  <div class="app-container">
+
+    <!-- 搜索工作栏 -->
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="流程名" prop="name">
+        <el-input v-model="queryParams.name" placeholder="请输入流程名" clearable size="small" @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="创建时间">
+        <el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
+                        type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 列表 -->
+    <el-table v-loading="loading" :data="list">
+      <el-table-column label="任务编号" align="center" prop="id" width="320" fixed />
+      <el-table-column label="任务名称" align="center" prop="name" width="200" />
+      <el-table-column label="所属流程" align="center" prop="processInstance.name" width="200" />
+      <el-table-column label="流程发起人" align="center" prop="processInstance.startUserNickname" />
+      <el-table-column label="结果" align="center" prop="result">
+        <template slot-scope="scope">
+          <span>
+            <el-tag type="primary" v-if="scope.row.result === 1"> <!-- 进行中 -->
+              {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
+            </el-tag>
+             <el-tag type="success" v-if="scope.row.result === 2"> <!-- 通过 -->
+              {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
+            </el-tag>
+             <el-tag type="danger" v-if="scope.row.result === 3"> <!-- 不通过 -->
+              {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
+            </el-tag>
+             <el-tag type="info" v-if="scope.row.result === 4"> <!-- 撤回 -->
+              {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
+            </el-tag>
+          </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="审批意见" align="center" prop="comment" width="200" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="审批时间" align="center" prop="endTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.endTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="耗时" align="center" prop="durationInMillis" width="180">
+        <template slot-scope="scope">
+          <span>{{ getDateStar(scope.row.durationInMillis) }}</span>
+        </template>
+      </el-table-column>
+      <!-- TODO 耗时 -->
+      <el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <!-- TODO 权限、颜色 -->
+          <el-button size="mini" type="text" icon="el-icon-edit">详情</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页组件 -->
+    <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
+                @pagination="getList"/>
+
+  </div>
+</template>
+
+<script>
+import {getDoneTaskPage} from '@/api/bpm/task'
+import {getDate} from "@/utils/dateUtils";
+
+export default {
+  name: "Done",
+  components: {
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 待办任务列表
+      list: [],
+      // 查询参数
+      dateRangeCreateTime: [],
+      queryParams: {
+        pageNo: 1,
+        pageSize: 10,
+        name: null,
+      },
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询列表 */
+    getList() {
+      this.loading = true;
+      // 处理查询参数
+      let params = {...this.queryParams};
+      this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
+      getDoneTaskPage(params).then(response => {
+        this.list = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNo = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRangeCreateTime = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    getDateStar(ms) {
+      return getDate(ms);
+    }
+  }
+};
+</script>

+ 122 - 0
yudao-admin-ui/src/views/bpm/task/todo.vue

@@ -0,0 +1,122 @@
+<template>
+  <div class="app-container">
+
+    <!-- 搜索工作栏 -->
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="流程名" prop="name">
+        <el-input v-model="queryParams.name" placeholder="请输入流程名" clearable size="small" @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="创建时间">
+        <el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
+                        type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 列表 -->
+    <el-table v-loading="loading" :data="list">
+      <el-table-column label="任务编号" align="center" prop="id" width="320" />
+      <el-table-column label="任务名称" align="center" prop="name" />
+      <el-table-column label="所属流程" align="center" prop="processInstance.name" />
+      <el-table-column label="流程发起人" align="center" prop="processInstance.startUserNickname" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="version" width="80">
+        <template slot-scope="scope">
+          <el-tag type="success" v-if="scope.row.suspensionState === 1">激活</el-tag>
+          <el-tag type="warning" v-if="scope.row.suspensionState === 2">挂起</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <!-- TODO 权限、颜色 -->
+          <el-button size="mini" type="text" icon="el-icon-edit">审批</el-button>
+          <el-button size="mini" type="text" icon="el-icon-edit" @click="audit(scope.row, true)">通过</el-button>
+          <el-button size="mini" type="text" icon="el-icon-edit"  @click="audit(scope.row, false)">不通过</el-button>
+          <el-button size="mini" type="text" icon="el-icon-edit" v-if="scope.row.suspensionState === 2">激活</el-button>
+          <el-button size="mini" type="text" icon="el-icon-edit" v-if="scope.row.suspensionState === 1">挂起</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页组件 -->
+    <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
+                @pagination="getList"/>
+
+  </div>
+</template>
+
+<script>
+import {approveTask, getTodoTaskPage, rejectTask} from '@/api/bpm/task'
+
+export default {
+  name: "Todo",
+  components: {
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 待办任务列表
+      list: [],
+      // 查询参数
+      dateRangeCreateTime: [],
+      queryParams: {
+        pageNo: 1,
+        pageSize: 10,
+        name: null,
+      },
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询列表 */
+    getList() {
+      this.loading = true;
+      // 处理查询参数
+      let params = {...this.queryParams};
+      this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
+      getTodoTaskPage(params).then(response => {
+        this.list = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNo = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRangeCreateTime = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    audit(row, pass) {
+      if (pass) {
+        approveTask({
+          id: row.id,
+          comment: '通过'
+        })
+      } else {
+        rejectTask({
+          id: row.id,
+          comment: '不通过'
+        })
+      }
+    }
+  }
+};
+</script>

+ 0 - 286
yudao-admin-ui/src/views/oa/todo/index.vue

@@ -1,286 +0,0 @@
-<template>
-  <div class="app-container">
-
-    <!-- 搜索工作栏 -->
-    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="状态" prop="status">
-        <el-select v-model="queryParams.status" placeholder="请选择状态">
-          <el-option
-            v-for="dict in leaveStatusData"
-            :key="parseInt(dict.value)"
-            :label="dict.label"
-            :value="parseInt(dict.value)"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-      </el-form-item>
-    </el-form>
-
-
-
-    <!-- 列表 -->
-    <el-table v-loading="loading" :data="list">
-      <el-table-column label="任务Id" align="center" prop="id" />
-      <el-table-column label="流程名称" align="center" prop="processName" />
-      <el-table-column label="任务状态" align="center"  :formatter="statusFormat" prop="status" />
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-        <template slot-scope="scope">
-          <el-button size="mini" type="text" icon="el-icon-edit" v-if="scope.row.status == 1"  @click="handleClaim(scope.row)">签收</el-button>
-          <el-button size="mini" type="text" icon="el-icon-edit" v-if="scope.row.status == 2"  @click="getTaskFormKey(scope.row)">办理</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-    <!-- 分页组件 -->
-    <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
-                @pagination="getList"/>
-
-    <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
-      <el-tabs tab-position="left" style="height: 500px;">
-        <el-tab-pane label="详情">
-          <el-form ref="form" :model="handleTask.formObject"  label-width="80px">
-            <el-form-item label="状态" >
-              {{ getDictDataLabel(DICT_TYPE.OA_LEAVE_STATUS, handleTask.formObject.status) }}
-            </el-form-item>
-            <el-form-item label="申请人id" >{{handleTask.formObject.userId}}</el-form-item>
-            <el-form-item label="开始时间" >{{ parseTime(handleTask.formObject.startTime) }}</el-form-item>
-            <el-form-item label="结束时间" prop="endTime">{{ parseTime(handleTask.formObject.endTime) }}</el-form-item>
-            <el-form-item label="请假类型" prop="leaveType">
-              {{ getDictDataLabel(DICT_TYPE.OA_LEAVE_TYPE, handleTask.formObject.leaveType) }}
-            </el-form-item>
-            <el-form-item label="原因" prop="reason">{{handleTask.formObject.reason}}</el-form-item>
-            <el-form-item label="申请时间" prop="applyTime">{{ parseTime(handleTask.formObject.applyTime) }}</el-form-item>
-          </el-form>
-        </el-tab-pane>
-        <el-tab-pane label="任务处理">
-          <el-steps :active="handleTask.historyTask.length-1" simple finish-status="success">
-            <el-step :title="item.stepName" icon="el-icon-edit" v-for="(item) in handleTask.historyTask" ></el-step>
-          </el-steps>
-          <br/>
-          <el-steps direction="vertical" :active="handleTask.historyTask.length-1" finish-status="success" space="60px">
-            <el-step :title="item.stepName" :description="item.comment" v-for="(item) in handleTask.historyTask" ></el-step>
-          </el-steps>
-          <br/>
-          <el-form ref="taskForm" :model="task"  label-width="80px" v-show="handleTask.taskVariable !=''">
-              <el-form-item label="处理意见" prop="approved">
-                <el-select v-model="task.approved" placeholder="处理意见">
-                  <el-option
-                    v-for="dict in approvedData"
-                    :key="parseInt(dict.value)"
-                    :label="dict.label"
-                    :value="parseInt(dict.value)"
-                  />
-                </el-select>
-              </el-form-item>
-              <el-input
-                type="textarea"
-                :rows="2"
-                v-model="task.comment">
-              </el-input>
-          </el-form>
-          <br/>
-          <el-button type="primary" @click="submitTask">提交</el-button>
-        </el-tab-pane>
-      </el-tabs>
-    </el-dialog>
-  </div>
-</template>
-
-<script>
-import { completeTask, taskSteps, getTaskFormKey,deleteLeave, getLeave, getTodoTaskPage, claimTask } from "@/api/oa/todo";
-import { getDictDataLabel, getDictDatas, DICT_TYPE } from '@/utils/dict'
-export default {
-  name: "Todo",
-  components: {
-  },
-  data() {
-    return {
-      // 遮罩层
-      loading: true,
-      // 显示搜索条件
-      showSearch: true,
-      // 总条数
-      total: 0,
-      // 请假申请列表
-      list: [],
-      // 弹出层标题
-      title: "",
-      // 是否显示弹出层
-      open: false,
-      // 查询参数
-      queryParams: {
-        pageNo: 1,
-        pageSize: 10
-      },
-      // 表单参数
-      form: {},
-      handleTask: {
-        historyTask:[{
-            stepName:"步骤一"
-          }
-        ],
-        taskVariable: "",
-        formObject: {}
-      },
-      steps:[{
-        stepName:"步骤一"
-      }],
-      task: {
-        approved : 1,
-        variables: {},
-        taskId: undefined,
-        comment: ""
-      },
-      rules: {
-      },
-      leaveTypeDictData: getDictDatas(DICT_TYPE.OA_LEAVE_TYPE),
-      leaveStatusData: getDictDatas(DICT_TYPE.OA_LEAVE_STATUS),
-      approvedData: [
-        {
-          value: 1,
-          label: '同意'
-        },
-        {
-          value: 0,
-          label: '不同意'
-        }
-      ]
-    };
-  },
-  created() {
-    this.getList();
-  },
-  methods: {
-    /** 查询列表 */
-    getList() {
-      this.loading = true;
-      // 处理查询参数
-      let params = {...this.queryParams};
-      // 执行查询
-      getTodoTaskPage(params).then(response => {
-        this.list = response.data.list;
-        this.total = response.data.total;
-        this.loading = false;
-      });
-    },
-    /** 取消按钮 */
-    cancel() {
-      this.open = false;
-      this.reset();
-    },
-    /** 表单重置 */
-    reset() {
-      this.form = {
-        id: undefined,
-        processInstanceId: undefined,
-        status: undefined,
-        userId: undefined,
-        startTime: undefined,
-        endTime: undefined,
-        leaveType: undefined,
-        reason: undefined,
-        applyTime: undefined,
-      };
-      this.resetForm("form");
-    },
-
-    statusFormat(row, column) {
-      return row.status == 1 ? "未签收" : "已签收";
-    },
-    /** 搜索按钮操作 */
-    handleQuery() {
-      this.queryParams.pageNo = 1;
-      this.getList();
-    },
-    /** 重置按钮操作 */
-    resetQuery() {
-      this.dateRangeStartTime = [];
-      this.dateRangeEndTime = [];
-      this.dateRangeApplyTime = [];
-      this.resetForm("queryForm");
-      this.handleQuery();
-    },
-    getTaskFormKey(row) {
-      const taskId = row.id;
-      const data = {
-        taskId : taskId
-      }
-      getTaskFormKey(data).then(response => {
-        const resp = response.data;
-        const path = resp.formKey;
-        const taskId = resp.id;
-        const businessKey =  resp.businessKey;
-        const route = {
-          path: path,
-          query: {
-            businessKey: businessKey,
-            taskId:taskId,
-            processInstanceId : resp.processInstanceId
-          }
-        }
-        this.$router.replace(route);
-      });
-    },
-    handleLeaveApprove(row) {
-      this.reset();
-      const businessKey = row.businessKey;
-      const taskId = row.id;
-      const processKey = row.processKey;
-      const data = {
-        taskId : taskId,
-        businessKey: businessKey,
-        processKey: processKey
-      }
-      taskSteps(data).then(response => {
-        this.form = {};
-        this.handleTask = response.data;
-        this.task.taskId = taskId;
-        this.open = true;
-        this.title = "任务办理";
-      });
-    },
-    /** 任务签收操作 */
-    handleClaim(row) {
-      this.reset();
-      const id = row.id;
-      claimTask(id).then(() => {
-        this.getList();
-        this.msgSuccess("签收成功");
-      });
-    },
-    /** 提交任务 */
-    submitTask() {
-      const taskVariableName = this.handleTask.taskVariable;
-      if (taskVariableName != "") {
-        if (this.task.approved == 1) {
-          this.task.variables[taskVariableName] = true;
-        }
-        if (this.task.approved == 0) {
-          this.task.variables[taskVariableName] = false;
-        }
-      }
-      completeTask(this.task).then(response => {
-        this.msgSuccess("执行任务成功");
-        this.open = false;
-        this.getList();
-      })
-    },
-    /** 删除按钮操作 */
-    handleDelete(row) {
-      const id = row.id;
-      this.$confirm('是否确认删除请假申请编号为"' + id + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return deleteLeave(id);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        })
-    }
-  }
-};
-</script>

+ 3 - 1
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java

@@ -25,7 +25,9 @@ public interface WebFilterOrderEnum {
 
     // Spring Security Filter 默认为 -100,可见 org.springframework.boot.autoconfigure.security.SecurityProperties 配置属性类
 
-    int TENANT_SECURITY_FILTER = -99; // 需要保证在 Spring Security 过滤器后
+    int TENANT_SECURITY_FILTER = -99; // 需要保证在 Spring Security 过滤器后面
+
+    int ACTIVITI_FILTER = -98; // 需要保证在 Spring Security 过滤后面
 
     int DEMO_FILTER = Integer.MAX_VALUE;
 

+ 4 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageResult.java

@@ -35,4 +35,8 @@ public final class PageResult<T> implements Serializable {
         return new PageResult<>(0L);
     }
 
+    public static <T> PageResult<T> empty(Long total) {
+        return new PageResult<>(total);
+    }
+
 }

+ 9 - 0
yudao-framework/yudao-spring-boot-starter-activiti/pom.xml

@@ -37,6 +37,14 @@
             <artifactId>yudao-common</artifactId>
         </dependency>
 
+        <!-- Web 相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-security</artifactId>
+        </dependency>
+
+
+
         <dependency>
             <groupId>org.mybatis</groupId>
             <artifactId>mybatis</artifactId>
@@ -72,6 +80,7 @@
             <artifactId>activiti-image-generator</artifactId>
             <version>${activiti.version}</version>
         </dependency>
+
     </dependencies>
 
 </project>

+ 11 - 0
yudao-framework/yudao-spring-boot-starter-activiti/src/main/java/cn/iocoder/yudao/framework/activiti/config/YudaoActivitiConfiguration.java

@@ -1,9 +1,12 @@
 package cn.iocoder.yudao.framework.activiti.config;
 
+import cn.iocoder.yudao.framework.activiti.core.web.ActivitiWebFilter;
+import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
 import org.activiti.image.ProcessDiagramGenerator;
 import org.activiti.image.impl.DefaultProcessDiagramGenerator;
 import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
 import org.apache.ibatis.session.SqlSessionFactory;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
@@ -26,4 +29,12 @@ public class YudaoActivitiConfiguration {
         return springProcessEngineConfiguration -> springProcessEngineConfiguration.setSqlSessionFactory(sqlSessionFactory);
     }
 
+    @Bean
+    public FilterRegistrationBean<ActivitiWebFilter> activitiWebFilter() {
+        FilterRegistrationBean<ActivitiWebFilter> registrationBean = new FilterRegistrationBean<>();
+        registrationBean.setFilter(new ActivitiWebFilter());
+        registrationBean.setOrder(WebFilterOrderEnum.ACTIVITI_FILTER);
+        return registrationBean;
+    }
+
 }

+ 40 - 0
yudao-framework/yudao-spring-boot-starter-activiti/src/main/java/cn/iocoder/yudao/framework/activiti/core/util/ActivitiUtils.java

@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.framework.activiti.core.util;
+
+import cn.hutool.core.util.ReflectUtil;
+import com.alibaba.ttl.TransmittableThreadLocal;
+import org.activiti.engine.history.HistoricProcessInstance;
+import org.activiti.engine.impl.identity.Authentication;
+import org.activiti.engine.impl.persistence.entity.HistoricProcessInstanceEntityImpl;
+import org.activiti.engine.impl.persistence.entity.HistoricScopeInstanceEntityImpl;
+
+/**
+ * Activiti 工具类
+ *
+ * @author 芋道源码
+ */
+public class ActivitiUtils {
+
+    static {
+        setAuthenticationThreadLocal();
+    }
+
+    // ========== Authentication 相关 ==========
+
+    /**
+     * 反射修改 Authentication 的 authenticatedUserIdThreadLocal 静态变量,使用 TTL 线程变量
+     * 目的:保证 @Async 等异步执行时,变量丢失的问题
+     */
+    private static void setAuthenticationThreadLocal() {
+        ReflectUtil.setFieldValue(Authentication.class, "authenticatedUserIdThreadLocal",
+                new TransmittableThreadLocal<String>());
+    }
+
+    public static void setAuthenticatedUserId(Long userId) {
+        Authentication.setAuthenticatedUserId(String.valueOf(userId));
+    }
+
+    public static void clearAuthenticatedUserId() {
+        Authentication.setAuthenticatedUserId(null);
+    }
+
+}

+ 37 - 0
yudao-framework/yudao-spring-boot-starter-activiti/src/main/java/cn/iocoder/yudao/framework/activiti/core/web/ActivitiWebFilter.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.framework.activiti.core.web;
+
+import cn.iocoder.yudao.framework.activiti.core.util.ActivitiUtils;
+import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * Activiti Web 过滤器,将 userId 设置到 {@link org.activiti.engine.impl.identity.Authentication} 中
+ *
+ * @author 芋道源码
+ */
+public class ActivitiWebFilter extends OncePerRequestFilter {
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
+            throws ServletException, IOException {
+        try {
+            // 设置工作流的用户
+            Long userId = SecurityFrameworkUtils.getLoginUserId();
+            if (userId != null) {
+                ActivitiUtils.setAuthenticatedUserId(userId);
+            }
+            // 过滤
+            chain.doFilter(request, response);
+        } finally {
+            // 清理
+            ActivitiUtils.clearAuthenticatedUserId();
+        }
+    }
+
+}

+ 1 - 0
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/dataobject/BaseDO.java

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.mybatis.core.dataobject;
 import com.baomidou.mybatisplus.annotation.FieldFill;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableLogic;
+import lombok.Builder;
 import lombok.Data;
 
 import java.io.Serializable;

+ 5 - 0
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java

@@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.Collection;
 import java.util.List;
 
 /**
@@ -44,4 +45,8 @@ public interface BaseMapperX<T> extends BaseMapper<T> {
         return selectList(new QueryWrapper<T>().eq(field, value));
     }
 
+    default List<T> selectList(String field, Collection<?> values) {
+        return selectList(new QueryWrapper<T>().in(field, values));
+    }
+
 }

+ 0 - 9
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java

@@ -98,15 +98,6 @@ public class SecurityFrameworkUtils {
         // 原因是,Spring Security 的 Filter 在 ApiAccessLogFilter 后面,在它记录访问日志时,线上上下文已经没有用户编号等信息
         WebFrameworkUtils.setLoginUserId(request, loginUser.getId());
         WebFrameworkUtils.setLoginUserType(request, loginUser.getUserType());
-//        // TODO @jason:使用 userId 会不会更合适哈?
-//        // TODO @芋艿:activiti 需要使用 ttl 上下文
-//        // TODO @jason:清理问题
-//        if (Objects.equals(UserTypeEnum.ADMIN.getValue(), loginUser.getUserType())) {
-//            org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(loginUser.getUsername());
-//        }
-//        // TODO @芋道源码 该值被赋值给 user task 中assignee , username 显示更直白一点
-//        // TODO @jason:有办法设置 userId,然后 activiti 有地方读取到 username 么?毕竟 username 只是 User 的登陆账号,并不能绝对像 userId 代表一个用户
-//        org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(loginUser.getUsername());
     }
 
 }

+ 5 - 1
更新日志.md

@@ -27,7 +27,11 @@
 ### ⭐ New Features
 
 * 【优化】引入 form generator 0.2.0 版本,并重构相关代码
-* 【新增】新增流程表单,支持动态进行表单的配置
+* 【新增】流程表单,支持动态进行表单的配置
+* 【新增】流程模型的管理,支持新增、导入、编辑、删除、发布流程模型
+* 【新增】我的流程的管理,支持发起流程
+* 【新增】待办任务的管理,支持任务的审批通过与不通过
+* 【新增】已办任务的管理,支持详情的查看
 * 【新增】引入 bpmn-process-designer 0.0.1 版本,提供流程设计器的能力
 
 ### 🐞 Bug Fixes

Some files were not shown because too many files changed in this diff