Commit 8a3488f3d1fcf55558fa9ce7ef14d777c917fe17

Authored by 芋道源码
Committed by Gitee
2 parents 2a900380 9734eacf

!62 工作流的流程任务相关

Merge pull request !62 from 芋道源码/feature/activiti
Showing 81 changed files with 3165 additions and 2080 deletions
sql/ruoyi-vue-pro.sql
No preview for this file type
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/BpmProcessDefinitionController.http 0 → 100644
  1 +### 请求 /bpm/process-definition/list 接口 => 成功
  2 +GET {{baseUrl}}/bpm/process-definition/list?suspensionState=1
  3 +tenant-id: 1
  4 +Authorization: Bearer {{token}}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/BpmProcessDefinitionController.java
1 1 package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition;
2 2  
  3 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionListReqVO;
3 4 import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageItemRespVO;
4 5 import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageReqVO;
  6 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionRespVO;
5 7 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
6 8 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
7 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
... ... @@ -17,6 +19,8 @@ import org.springframework.web.bind.annotation.RestController;
17 19  
18 20 import javax.annotation.Resource;
19 21  
  22 +import java.util.List;
  23 +
20 24 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
21 25  
22 26 @Api(tags = "流程定义")
... ... @@ -36,14 +40,11 @@ public class BpmProcessDefinitionController {
36 40 return success(bpmDefinitionService.getProcessDefinitionPage(pageReqVO));
37 41 }
38 42  
39   - // TODO 芋艿:需要重写该方法
40   - @GetMapping(value = "/getStartForm")
41   - public CommonResult<String> getStartForm(@RequestParam("processKey") String processKey){
42   -// final ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().
43   -// processDefinitionKey(processKey).latestVersion().singleResult();
44   -// processRuntime.processDefinition(processDefinition.getId()).getFormKey();
45   - // TODO 这样查似乎有问题??, 暂时写死
46   - return success("/flow/leave/apply");
  43 + @GetMapping ("/list")
  44 + @ApiOperation(value = "获得流程定义列表")
  45 + public CommonResult<List<BpmProcessDefinitionRespVO>> getProcessDefinitionList(
  46 + BpmProcessDefinitionListReqVO listReqVO) {
  47 + return success(bpmDefinitionService.getProcessDefinitionList(listReqVO));
47 48 }
48 49  
49 50 @GetMapping ("/get-bpmn-xml")
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/vo/TodoTaskPageReqVO.java renamed to yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/BpmProcessDefinitionListReqVO.java
1   -package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo;
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 4 import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
5 6 import lombok.Data;
6 7 import lombok.EqualsAndHashCode;
7 8 import lombok.ToString;
8 9  
9   -@ApiModel("待办任务申请分页 Request VO")
10 10 @Data
11   -@EqualsAndHashCode(callSuper = true)
12 11 @ToString(callSuper = true)
13   -public class TodoTaskPageReqVO extends PageParam {
  12 +@EqualsAndHashCode(callSuper = true)
  13 +@ApiModel("流程定义列表 Request VO")
  14 +public class BpmProcessDefinitionListReqVO extends PageParam {
  15 +
  16 + @ApiModelProperty(value = "中断状态", example = "1", notes = "参见 SuspensionState 枚举")
  17 + private Integer suspensionState;
14 18  
15   - private String assignee;
16 19 }
... ...
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
20 20 @ApiModelProperty(value = "部署时间", required = true)
21 21 private Date deploymentTime;
22 22  
23   -
24 23 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmProcessInstanceController.http
1   -### 请求 /login 接口 => 成功
  1 +### 请求 /bpm/process-instance/create 接口 => 成功
2 2 POST {{baseUrl}}/bpm/process-instance/create
3 3 Content-Type: application/json
4 4 tenant-id: 1
5 5 Authorization: Bearer {{token}}
6 6  
7 7 {
8   - "processDefinitionId": "leave:7:20ada39c-6c95-11ec-88b1-cacd34981f8e",
  8 + "processDefinitionId": "gateway_test:2:00e52d8e-701b-11ec-aca9-a2380e71991a",
9 9 "variables": {
10 10 "a": 1,
11 11 "b": "2"
12 12 }
13 13 }
  14 +
  15 +### 请求 /bpm/process-instance/cancel 接口 => 成功
  16 +DELETE {{baseUrl}}/bpm/process-instance/cancel
  17 +Content-Type: application/json
  18 +tenant-id: 1
  19 +Authorization: Bearer {{token}}
  20 +
  21 +{
  22 + "id": "b9220387-7088-11ec-bcae-a2380e71991a",
  23 + "reason": "我就取消"
  24 +}
  25 +
  26 +### 请求 /bpm/process-instance/my-page 接口 => 成功
  27 +GET {{baseUrl}}/bpm/process-instance/my-page
  28 +tenant-id: 1
  29 +Authorization: Bearer {{token}}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmProcessInstanceController.java
1 1 package cn.iocoder.yudao.adminserver.modules.bpm.controller.task;
2 2  
  3 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceCancelReqVO;
3 4 import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceCreateReqVO;
  5 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceMyPageReqVO;
  6 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstancePageItemRespVO;
4 7 import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmProcessInstanceService;
5 8 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  9 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 10 import io.swagger.annotations.Api;
7 11 import io.swagger.annotations.ApiOperation;
8 12 import org.springframework.validation.annotation.Validated;
9   -import org.springframework.web.bind.annotation.PostMapping;
10   -import org.springframework.web.bind.annotation.RequestBody;
11   -import org.springframework.web.bind.annotation.RequestMapping;
12   -import org.springframework.web.bind.annotation.RestController;
  13 +import org.springframework.web.bind.annotation.*;
13 14  
14 15 import javax.annotation.Resource;
15 16 import javax.validation.Valid;
... ... @@ -26,10 +27,26 @@ public class BpmProcessInstanceController {
26 27 @Resource
27 28 private BpmProcessInstanceService processInstanceService;
28 29  
  30 + // TODO 芋艿:权限
  31 +
29 32 @PostMapping("/create")
30 33 @ApiOperation("新建流程实例")
31 34 public CommonResult<String> createProcessInstance(@Valid @RequestBody BpmProcessInstanceCreateReqVO createReqVO) {
32 35 return success(processInstanceService.createProcessInstance(getLoginUserId(), createReqVO));
33 36 }
34 37  
  38 + @DeleteMapping("/cancel")
  39 + @ApiOperation(value = "取消流程实例", notes = "撤回发起的流程")
  40 + public CommonResult<Boolean> cancelProcessInstance(@Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) {
  41 + processInstanceService.cancelProcessInstance(getLoginUserId(), cancelReqVO);
  42 + return success(true);
  43 + }
  44 +
  45 + @GetMapping("/my-page")
  46 + @ApiOperation(value = "获得我的实例分页列表", notes = "在【我的流程】菜单中,进行调用")
  47 + public CommonResult<PageResult<BpmProcessInstancePageItemRespVO>> getMyProcessInstancePage(
  48 + @Valid BpmProcessInstanceMyPageReqVO pageReqVO) {
  49 + return success(processInstanceService.getMyProcessInstancePage(getLoginUserId(), pageReqVO));
  50 + }
  51 +
35 52 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmTaskController.http 0 → 100644
  1 +### 请求 /bpm/task/todo-page 接口 => 成功
  2 +GET {{baseUrl}}/bpm/task/todo-page
  3 +tenant-id: 1
  4 +Authorization: Bearer {{token}}
  5 +
  6 +### 请求 /bpm/task/done-page 接口 => 成功
  7 +GET {{baseUrl}}/bpm/task/done-page?pageSize=100
  8 +tenant-id: 1
  9 +Authorization: Bearer {{token}}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/TaskController.java renamed to yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmTaskController.java
1   -package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow;
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.controller.task;
2 2  
3   -import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*;
  3 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.*;
4 4 import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmTaskService;
5 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 7 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
8 8 import io.swagger.annotations.Api;
9 9 import io.swagger.annotations.ApiOperation;
  10 +import org.springframework.validation.annotation.Validated;
10 11 import org.springframework.web.bind.annotation.*;
11 12  
12 13 import javax.annotation.Resource;
... ... @@ -16,48 +17,53 @@ import java.io.IOException;
16 17 import java.util.List;
17 18  
18 19 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  20 +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
19 21  
20   -// TODO @json:swagger 和 validation 的注解,后续要补全下哈。可以等 workflow 基本写的差不多之后
21   -@Api(tags = "工作流待办任务")
  22 +@Api(tags = "流程任务")
22 23 @RestController
23   -@RequestMapping("/workflow/task")
24   -public class TaskController {
  24 +@RequestMapping("/bpm/task")
  25 +@Validated
  26 +public class BpmTaskController {
25 27  
26 28 @Resource
27   - private BpmTaskService bpmTaskService;
  29 + private BpmTaskService taskService;
28 30  
29   - @GetMapping("/todo/page")
30   - @ApiOperation("获取待办任务分页")
31   - public CommonResult<PageResult<TodoTaskRespVO>> getTodoTaskPage(@Valid TodoTaskPageReqVO pageVO) {
32   - return success(bpmTaskService.getTodoTaskPage(pageVO));
33   - }
  31 + // TODO 芋艿:权限、validation;
34 32  
35   - @GetMapping("/claim")
36   - @ApiOperation("签收任务")
37   - public CommonResult<Boolean> claimTask(@RequestParam("id") String taskId) {
38   - bpmTaskService.claimTask(taskId);
39   - return success(true);
  33 + @GetMapping("todo-page")
  34 + @ApiOperation("获取 Todo 待办任务分页")
  35 + public CommonResult<PageResult<BpmTaskTodoPageItemRespVO>> getTodoTaskPage(@Valid BpmTaskTodoPageReqVO pageVO) {
  36 + return success(taskService.getTodoTaskPage(getLoginUserId(), pageVO));
40 37 }
41 38  
42   - @PostMapping("/task-steps")
43   - public CommonResult<TaskHandleVO> getTaskSteps(@RequestBody TaskQueryReqVO taskQuery) {
44   - return success(bpmTaskService.getTaskSteps(taskQuery));
  39 + @GetMapping("done-page")
  40 + @ApiOperation("获取 Done 已办任务分页")
  41 + public CommonResult<PageResult<BpmTaskDonePageItemRespVO>> getTodoTaskPage(@Valid BpmTaskDonePageReqVO pageVO) {
  42 + return success(taskService.getDoneTaskPage(getLoginUserId(), pageVO));
45 43 }
46 44  
47   - @PostMapping("/formKey")
48   - public CommonResult<TodoTaskRespVO> getTaskFormKey(@RequestBody TaskQueryReqVO taskQuery) {
49   - return success(bpmTaskService.getTaskFormKey(taskQuery));
  45 + @PutMapping("/approve")
  46 + @ApiOperation("通过任务")
  47 + public CommonResult<Boolean> approveTask(@Valid @RequestBody BpmTaskApproveReqVO reqVO) {
  48 + taskService.approveTask(reqVO);
  49 + return success(true);
50 50 }
51 51  
52   - @PostMapping("/complete")
53   - public CommonResult<Boolean> complete(@RequestBody TaskReqVO taskReq) {
54   - bpmTaskService.completeTask(taskReq);
  52 + @PutMapping("/reject")
  53 + @ApiOperation("不通过任务")
  54 + public CommonResult<Boolean> rejectTask(@Valid @RequestBody BpmTaskRejectReqVO reqVO) {
  55 + taskService.rejectTask(reqVO);
55 56 return success(true);
56 57 }
57 58  
  59 + @PostMapping("/task-steps")
  60 + public CommonResult<TaskHandleVO> getTaskSteps(@RequestBody TaskQueryReqVO taskQuery) {
  61 + return success(taskService.getTaskSteps(taskQuery));
  62 + }
  63 +
58 64 @GetMapping("/process/history-steps")
59 65 public CommonResult<List<TaskStepVO>> getHistorySteps(@RequestParam("id") String processInstanceId) {
60   - return success(bpmTaskService.getHistorySteps(processInstanceId));
  66 + return success(taskService.getHistorySteps(processInstanceId));
61 67 }
62 68  
63 69 /**
... ... @@ -66,7 +72,7 @@ public class TaskController {
66 72 */
67 73 @GetMapping("/process/highlight-img")
68 74 public void getHighlightImg(@RequestParam String processInstanceId, HttpServletResponse response) throws IOException {
69   - FileResp fileResp = bpmTaskService.getHighlightImg(processInstanceId);
  75 + FileResp fileResp = taskService.getHighlightImg(processInstanceId);
70 76 ServletUtils.writeAttachment(response, fileResp.getFileName(), fileResp.getFileByte());
71 77 }
72 78  
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstanceCancelReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +import javax.validation.constraints.NotEmpty;
  8 +import javax.validation.constraints.NotNull;
  9 +import java.util.Map;
  10 +
  11 +@ApiModel("流程实例的取消 Request VO")
  12 +@Data
  13 +public class BpmProcessInstanceCancelReqVO {
  14 +
  15 + @ApiModelProperty(value = "流程实例的编号", required = true, example = "1024")
  16 + @NotEmpty(message = "流程实例的编号不能为空")
  17 + private String id;
  18 +
  19 + @ApiModelProperty(value = "取消原因", required = true, example = "不请假了!")
  20 + @NotEmpty(message = "取消原因不能为空")
  21 + private String reason;
  22 +
  23 +}
... ...
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;
9 9  
10 10 @ApiModel("流程实例的创建 Request VO")
11 11 @Data
12   -//@EqualsAndHashCode(callSuper = true)
13   -//@ToString(callSuper = true)
14 12 public class BpmProcessInstanceCreateReqVO {
15 13  
16 14 @ApiModelProperty(value = "流程定义的编号", required = true, example = "1024")
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstanceMyPageReqVO.java
1 1 package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.ToString;
  9 +import org.springframework.format.annotation.DateTimeFormat;
4 10  
  11 +import java.util.Date;
  12 +
  13 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  14 +
  15 +@ApiModel("流程实例的分页 Item Response VO")
  16 +@Data
  17 +@EqualsAndHashCode(callSuper = true)
  18 +@ToString(callSuper = true)
5 19 public class BpmProcessInstanceMyPageReqVO extends PageParam {
  20 +
  21 + @ApiModelProperty(value = "流程名称", example = "芋道")
  22 + private String name;
  23 +
  24 + @ApiModelProperty(value = "流程定义的编号", example = "2048")
  25 + private String processDefinitionId;
  26 +
  27 + @ApiModelProperty(value = "流程实例的状态", notes = "参见 bpm_process_instance_status", example = "1")
  28 + private Integer status;
  29 +
  30 + @ApiModelProperty(value = "流程实例的结果", notes = "参见 bpm_process_instance_result", example = "2")
  31 + private Integer result;
  32 +
  33 + @ApiModelProperty(value = "流程分类", notes = "参见 bpm_model_category 数据字典", example = "1")
  34 + private String category;
  35 +
  36 + @ApiModelProperty(value = "开始的创建时间")
  37 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  38 + private Date beginCreateTime;
  39 +
  40 + @ApiModelProperty(value = "结束的创建时间")
  41 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  42 + private Date endCreateTime;
  43 +
6 44 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/instance/BpmProcessInstancePageItemRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +import java.util.Date;
  8 +import java.util.List;
  9 +
  10 +@ApiModel("流程实例的分页 Item Response VO")
  11 +@Data
  12 +public class BpmProcessInstancePageItemRespVO {
  13 +
  14 + @ApiModelProperty(value = "流程实例的编号", required = true, example = "1024")
  15 + private String id;
  16 +
  17 + @ApiModelProperty(value = "流程名称", required = true, example = "芋道")
  18 + private String name;
  19 +
  20 + @ApiModelProperty(value = "流程定义的编号", required = true, example = "2048")
  21 + private String processDefinitionId;
  22 +
  23 + @ApiModelProperty(value = "流程分类", required = true, notes = "参见 bpm_model_category 数据字典", example = "1")
  24 + private String category;
  25 +
  26 + @ApiModelProperty(value = "流程实例的状态", required = true, notes = "参见 bpm_process_instance_status", example = "1")
  27 + private Integer status;
  28 +
  29 + @ApiModelProperty(value = "流程实例的结果", required = true, notes = "参见 bpm_process_instance_result", example = "2")
  30 + private Integer result;
  31 +
  32 + @ApiModelProperty(value = "提交时间", required = true)
  33 + private Date createTime;
  34 +
  35 + @ApiModelProperty(value = "结束时间", required = true)
  36 + private Date endTime;
  37 +
  38 + /**
  39 + * 当前任务
  40 + */
  41 + private List<Task> tasks;
  42 +
  43 + @ApiModel("流程任务")
  44 + @Data
  45 + public static class Task {
  46 +
  47 + @ApiModelProperty(value = "流程任务的编号", required = true, example = "1024")
  48 + private String id;
  49 +
  50 + @ApiModelProperty(value = "任务名称", required = true, example = "芋道")
  51 + private String name;
  52 +
  53 + }
  54 +
  55 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskApproveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import javax.validation.constraints.NotEmpty;
  10 +import javax.validation.constraints.NotNull;
  11 +import java.util.Map;
  12 +
  13 +@ApiModel("通过流程任务的 Request VO")
  14 +@Data
  15 +public class BpmTaskApproveReqVO {
  16 +
  17 + @ApiModelProperty(value = "任务编号", required = true, example = "1024")
  18 + @NotEmpty(message = "任务编号不能为空")
  19 + private String id;
  20 +
  21 + @ApiModelProperty(value = "审批意见", required = true, example = "不错不错!")
  22 + @NotEmpty(message = "审批意见不能为空")
  23 + private String comment;
  24 +
  25 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskDonePageItemRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +import java.util.Date;
  8 +
  9 +@ApiModel("流程任务的 Done 已完成的分页项 Response VO")
  10 +@Data
  11 +public class BpmTaskDonePageItemRespVO {
  12 +
  13 + @ApiModelProperty(value = "任务编号", required = true, example = "1024")
  14 + private String id;
  15 +
  16 + @ApiModelProperty(value = "任务名字", required = true, example = "芋道")
  17 + private String name;
  18 +
  19 + @ApiModelProperty(value = "接收时间", required = true)
  20 + private Date claimTime;
  21 +
  22 + @ApiModelProperty(value = "创建时间", required = true)
  23 + private Date createTime;
  24 + @ApiModelProperty(value = "结束时间", required = true)
  25 + private Date endTime;
  26 + @ApiModelProperty(value = "持续时间", required = true, example = "1000")
  27 + private Long durationInMillis;
  28 +
  29 + @ApiModelProperty(value = "任务结果", required = true, notes = "参见 bpm_process_instance_result", example = "2")
  30 + private Integer result;
  31 + @ApiModelProperty(value = "审批建议", required = true, example = "不请假了!")
  32 + private String comment;
  33 +
  34 + /**
  35 + * 所属流程实例
  36 + */
  37 + private ProcessInstance processInstance;
  38 +
  39 + @Data
  40 + @ApiModel("流程实例")
  41 + public static class ProcessInstance {
  42 +
  43 + @ApiModelProperty(value = "流程实例编号", required = true, example = "1024")
  44 + private String id;
  45 +
  46 + @ApiModelProperty(value = "流程实例名称", required = true, example = "芋道")
  47 + private String name;
  48 +
  49 + @ApiModelProperty(value = "发起人的用户编号", required = true, example = "1024")
  50 + private Long startUserId;
  51 +
  52 + @ApiModelProperty(value = "发起人的用户昵称", required = true, example = "芋艿")
  53 + private String startUserNickname;
  54 +
  55 + @ApiModelProperty(value = "流程定义的编号", required = true, example = "2048")
  56 + private String processDefinitionId;
  57 +
  58 + }
  59 +
  60 +
  61 + // 任务编号、流程名称、任务节点、流程发起人、接收时间、审批时间、耗时【名称、开始时间】「流程记录、撤回」
  62 + // 任务编号、任务名称、所属流程、委托代办人、流程发起人、优先级、审批操作、审批意见、耗时、创建时间【名称、开始时间】「申请详情」
  63 +
  64 + // 任务编号、任务名称、流程名称、流程发起人、接收时间、审批时间、耗时【名称、接收时间】「详情」TODO 撤回
  65 +
  66 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskDonePageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.ToString;
  9 +import org.springframework.format.annotation.DateTimeFormat;
  10 +
  11 +import java.util.Date;
  12 +
  13 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  14 +
  15 +@ApiModel("流程任务的 Done 已办的分页 Request VO")
  16 +@Data
  17 +@EqualsAndHashCode(callSuper = true)
  18 +@ToString(callSuper = true)
  19 +public class BpmTaskDonePageReqVO extends PageParam {
  20 +
  21 + @ApiModelProperty(value = "流程任务名", example = "芋道")
  22 + private String name;
  23 +
  24 + @ApiModelProperty(value = "开始的创建收间")
  25 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  26 + private Date beginCreateTime;
  27 +
  28 + @ApiModelProperty(value = "结束的创建时间")
  29 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  30 + private Date endCreateTime;
  31 +
  32 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskRejectReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +import javax.validation.constraints.NotEmpty;
  8 +
  9 +@ApiModel("不通过流程任务的 Request VO")
  10 +@Data
  11 +public class BpmTaskRejectReqVO {
  12 +
  13 + @ApiModelProperty(value = "任务编号", required = true, example = "1024")
  14 + @NotEmpty(message = "任务编号不能为空")
  15 + private String id;
  16 +
  17 + @ApiModelProperty(value = "审批意见", required = true, example = "不错不错!")
  18 + @NotEmpty(message = "审批意见不能为空")
  19 + private String comment;
  20 +
  21 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskTodoPageItemRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +import java.util.Date;
  8 +
  9 +@ApiModel("流程任务的 Running 进行中的分页项 Response VO")
  10 +@Data
  11 +public class BpmTaskTodoPageItemRespVO {
  12 +
  13 + @ApiModelProperty(value = "任务编号", required = true, example = "1024")
  14 + private String id;
  15 +
  16 + @ApiModelProperty(value = "任务名字", required = true, example = "芋道")
  17 + private String name;
  18 +
  19 + @ApiModelProperty(value = "接收时间", required = true)
  20 + private Date claimTime;
  21 +
  22 + @ApiModelProperty(value = "创建时间", required = true)
  23 + private Date createTime;
  24 +
  25 + @ApiModelProperty(value = "激活状态", required = true, example = "1", notes = "参见 SuspensionState 枚举")
  26 + private Integer suspensionState;
  27 +
  28 + /**
  29 + * 所属流程实例
  30 + */
  31 + private ProcessInstance processInstance;
  32 +
  33 + @Data
  34 + @ApiModel("流程实例")
  35 + public static class ProcessInstance {
  36 +
  37 + @ApiModelProperty(value = "流程实例编号", required = true, example = "1024")
  38 + private String id;
  39 +
  40 + @ApiModelProperty(value = "流程实例名称", required = true, example = "芋道")
  41 + private String name;
  42 +
  43 + @ApiModelProperty(value = "发起人的用户编号", required = true, example = "1024")
  44 + private Long startUserId;
  45 +
  46 + @ApiModelProperty(value = "发起人的用户昵称", required = true, example = "芋艿")
  47 + private String startUserNickname;
  48 +
  49 + @ApiModelProperty(value = "流程定义的编号", required = true, example = "2048")
  50 + private String processDefinitionId;
  51 +
  52 + }
  53 +
  54 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/BpmTaskTodoPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.ToString;
  9 +import org.springframework.format.annotation.DateTimeFormat;
  10 +
  11 +import java.util.Date;
  12 +
  13 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  14 +
  15 +@ApiModel("流程任务的 TODO 待办的分页 Request VO")
  16 +@Data
  17 +@EqualsAndHashCode(callSuper = true)
  18 +@ToString(callSuper = true)
  19 +public class BpmTaskTodoPageReqVO extends PageParam {
  20 +
  21 + @ApiModelProperty(value = "流程任务名", example = "芋道")
  22 + private String name;
  23 +
  24 + @ApiModelProperty(value = "开始的创建收间")
  25 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  26 + private Date beginCreateTime;
  27 +
  28 + @ApiModelProperty(value = "结束的创建时间")
  29 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  30 + private Date endCreateTime;
  31 +
  32 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/vo/FileResp.java renamed to yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/FileResp.java
1   -package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo;
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
2 2  
3 3 import lombok.Data;
4 4  
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/vo/TaskHandleVO.java renamed to yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/TaskHandleVO.java
1   -package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo;
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
2 2  
3 3 import lombok.Data;
4 4 import lombok.ToString;
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/vo/TaskQueryReqVO.java renamed to yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/TaskQueryReqVO.java
1   -package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo;
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
2 2  
3 3 import lombok.Data;
4 4 import lombok.ToString;
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/vo/TaskStepVO.java renamed to yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/TaskStepVO.java
1   -package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo;
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
2 2  
3 3 import lombok.Data;
4 4 import lombok.ToString;
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/vo/TaskReqVO.java deleted
1   -package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo;
2   -
3   -import lombok.Data;
4   -import lombok.ToString;
5   -
6   -import java.util.Map;
7   -
8   -@Data
9   -@ToString
10   -public class TaskReqVO {
11   -
12   - private String taskId;
13   -
14   - private Map<String,Object> variables;
15   -
16   - private String comment;
17   -}
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/vo/TodoTaskRespVO.java deleted
1   -package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo;
2   -
3   -import io.swagger.annotations.ApiModel;
4   -import lombok.Data;
5   -import lombok.ToString;
6   -
7   -@ApiModel("待办任务 Response VO")
8   -@Data
9   -@ToString
10   -public class TodoTaskRespVO {
11   -
12   - // TODO @jason:swagger 注解。这样接口文档才完整哈
13   -
14   - private String id;
15   -
16   -
17   - private String processInstanceId;
18   -
19   - /**
20   - * 1:未签收
21   - * 2:已签收
22   - */
23   - private Integer status;
24   -
25   -
26   - private String processName;
27   -
28   -
29   - private String processKey;
30   -
31   -
32   - private String businessKey;
33   -
34   -
35   - private String formKey;
36   -
37   -}
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/definition/BpmDefinitionConvert.java
1 1 package cn.iocoder.yudao.adminserver.modules.bpm.convert.definition;
2 2  
3 3 import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageItemRespVO;
4   -import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionDO;
  4 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionRespVO;
  5 +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
5 6 import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
6 7 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmDefinitionCreateReqDTO;
7 8 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
... ... @@ -9,10 +10,14 @@ import org.activiti.engine.impl.persistence.entity.SuspensionState;
9 10 import org.activiti.engine.repository.Deployment;
10 11 import org.activiti.engine.repository.ProcessDefinition;
11 12 import org.mapstruct.Mapper;
  13 +import org.mapstruct.Mapping;
  14 +import org.mapstruct.Mappings;
  15 +import org.mapstruct.Named;
12 16 import org.mapstruct.factory.Mappers;
13 17  
14 18 import java.util.List;
15 19 import java.util.Map;
  20 +import java.util.function.Function;
16 21  
17 22 /**
18 23 * Bpm 流程定义的 Convert
... ... @@ -25,17 +30,17 @@ public interface BpmDefinitionConvert {
25 30 BpmDefinitionConvert INSTANCE = Mappers.getMapper(BpmDefinitionConvert.class);
26 31  
27 32 default List<BpmProcessDefinitionPageItemRespVO> convertList(List<ProcessDefinition> list, Map<String, Deployment> deploymentMap,
28   - Map<String, BpmProcessDefinitionDO> processDefinitionDOMap, Map<Long, BpmFormDO> formMap) {
  33 + Map<String, BpmProcessDefinitionExtDO> processDefinitionDOMap, Map<Long, BpmFormDO> formMap) {
29 34 return CollectionUtils.convertList(list, definition -> {
30 35 Deployment deployment = definition.getDeploymentId() != null ? deploymentMap.get(definition.getDeploymentId()) : null;
31   - BpmProcessDefinitionDO definitionDO = processDefinitionDOMap.get(definition.getId());
  36 + BpmProcessDefinitionExtDO definitionDO = processDefinitionDOMap.get(definition.getId());
32 37 BpmFormDO form = definitionDO != null ? formMap.get(definitionDO.getFormId()) : null;
33 38 return convert(definition, deployment, definitionDO, form);
34 39 });
35 40 }
36 41  
37 42 default BpmProcessDefinitionPageItemRespVO convert(ProcessDefinition bean, Deployment deployment,
38   - BpmProcessDefinitionDO processDefinitionDO, BpmFormDO form) {
  43 + BpmProcessDefinitionExtDO processDefinitionDO, BpmFormDO form) {
39 44 BpmProcessDefinitionPageItemRespVO respVO = convert(bean);
40 45 respVO.setSuspensionState(bean.isSuspended() ? SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode());
41 46 if (deployment != null) {
... ... @@ -53,6 +58,27 @@ public interface BpmDefinitionConvert {
53 58  
54 59 BpmProcessDefinitionPageItemRespVO convert(ProcessDefinition bean);
55 60  
56   - BpmProcessDefinitionDO convert2(BpmDefinitionCreateReqDTO bean);
  61 + BpmProcessDefinitionExtDO convert2(BpmDefinitionCreateReqDTO bean);
  62 +
  63 + default List<BpmProcessDefinitionRespVO> convertList3(List<ProcessDefinition> list,
  64 + Map<String, BpmProcessDefinitionExtDO> processDefinitionDOMap) {
  65 + return CollectionUtils.convertList(list, processDefinition -> {
  66 + BpmProcessDefinitionRespVO respVO = convert3(processDefinition);
  67 + BpmProcessDefinitionExtDO processDefinitionExtDO = processDefinitionDOMap.get(processDefinition.getId());
  68 + if (processDefinitionExtDO != null) {
  69 + respVO.setFormId(processDefinitionExtDO.getFormId());
  70 + }
  71 + return respVO;
  72 + });
  73 + }
  74 +
  75 + @Mapping(source = "suspended", target = "suspensionState", qualifiedByName = "convertSuspendedToSuspensionState")
  76 + BpmProcessDefinitionRespVO convert3(ProcessDefinition bean);
  77 +
  78 + @Named("convertSuspendedToSuspensionState")
  79 + default Integer convertSuspendedToSuspensionState(boolean suspended) {
  80 + return suspended ? SuspensionState.SUSPENDED.getStateCode() :
  81 + SuspensionState.ACTIVE.getStateCode();
  82 + }
57 83  
58 84 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/task/BpmProcessInstanceConvert.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.convert.task;
  2 +
  3 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstancePageItemRespVO;
  4 +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import org.activiti.engine.repository.ProcessDefinition;
  7 +import org.activiti.engine.runtime.ProcessInstance;
  8 +import org.activiti.engine.task.Task;
  9 +import org.mapstruct.Mapper;
  10 +import org.mapstruct.Mapping;
  11 +import org.mapstruct.Mappings;
  12 +import org.mapstruct.factory.Mappers;
  13 +
  14 +import java.sql.SQLXML;
  15 +import java.util.List;
  16 +import java.util.Map;
  17 +import java.util.function.Consumer;
  18 +
  19 +/**
  20 + * 流程实例 Convert
  21 + *
  22 + * @author 芋道源码
  23 + */
  24 +@Mapper
  25 +public interface BpmProcessInstanceConvert {
  26 +
  27 + BpmProcessInstanceConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceConvert.class);
  28 +
  29 + @Mappings({
  30 + @Mapping(source = "instance.startUserId", target = "startUserId"),
  31 + @Mapping(source = "instance.id", target = "processInstanceId"),
  32 + @Mapping(source = "instance.startTime", target = "createTime"),
  33 + @Mapping(source = "definition.id", target = "processDefinitionId"),
  34 + @Mapping(source = "definition.name", target = "name"),
  35 + @Mapping(source = "definition.category", target = "category")
  36 + })
  37 + BpmProcessInstanceExtDO convert(ProcessInstance instance, ProcessDefinition definition);
  38 +
  39 + default PageResult<BpmProcessInstancePageItemRespVO> convertPage(PageResult<BpmProcessInstanceExtDO> page,
  40 + Map<String, List<Task>> taskMap) {
  41 + List<BpmProcessInstancePageItemRespVO> list = convertList(page.getList());
  42 + list.forEach(respVO -> respVO.setTasks(convertList2(taskMap.get(respVO.getId()))));
  43 + return new PageResult<>(list, page.getTotal());
  44 + }
  45 +
  46 + List<BpmProcessInstancePageItemRespVO> convertList(List<BpmProcessInstanceExtDO> list);
  47 +
  48 + List<BpmProcessInstancePageItemRespVO.Task> convertList2(List<Task> tasks);
  49 +
  50 + @Mapping(source = "processInstanceId", target = "id")
  51 + BpmProcessInstancePageItemRespVO convert(BpmProcessInstanceExtDO bean);
  52 +
  53 + @Mappings({
  54 + @Mapping(source = "id", target = "processInstanceId"),
  55 + @Mapping(source = "startDate", target = "createTime"),
  56 + @Mapping(source = "initiator", target = "startUserId"),
  57 + @Mapping(source = "status", target = "status", ignore = true)
  58 + })
  59 + BpmProcessInstanceExtDO convert(org.activiti.api.process.model.ProcessInstance bean);
  60 +
  61 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/task/BpmTaskConvert.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.convert.task;
  2 +
  3 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.BpmTaskDonePageItemRespVO;
  4 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.BpmTaskTodoPageItemRespVO;
  5 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.TaskStepVO;
  6 +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmTaskExtDO;
  7 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
  8 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  9 +import org.activiti.engine.history.HistoricActivityInstance;
  10 +import org.activiti.engine.history.HistoricProcessInstance;
  11 +import org.activiti.engine.history.HistoricTaskInstance;
  12 +import org.activiti.engine.impl.persistence.entity.SuspensionState;
  13 +import org.activiti.engine.runtime.ProcessInstance;
  14 +import org.activiti.engine.task.Task;
  15 +import org.mapstruct.Mapper;
  16 +import org.mapstruct.Mapping;
  17 +import org.mapstruct.Mappings;
  18 +import org.mapstruct.Named;
  19 +import org.mapstruct.factory.Mappers;
  20 +
  21 +import java.util.List;
  22 +import java.util.Map;
  23 +
  24 +/**
  25 + * Bpm 任务 Convert
  26 + *
  27 + * @author 芋道源码
  28 + */
  29 +@Mapper
  30 +public interface BpmTaskConvert {
  31 +
  32 + BpmTaskConvert INSTANCE = Mappers.getMapper(BpmTaskConvert.class);
  33 +
  34 + @Mappings(value = {
  35 + @Mapping(source = "activityName", target = "stepName"),
  36 + @Mapping(source = "assignee", target = "assignee")
  37 + })
  38 + TaskStepVO convert(HistoricActivityInstance instance);
  39 +
  40 + default List<BpmTaskTodoPageItemRespVO> convertList(List<Task> tasks, Map<String, ProcessInstance> processInstanceMap,
  41 + Map<Long, SysUserDO> userMap) {
  42 + return CollectionUtils.convertList(tasks, task -> {
  43 + ProcessInstance processInstance = processInstanceMap.get(task.getProcessInstanceId());
  44 + return convert(task, processInstance, userMap.get(Long.valueOf(processInstance.getStartUserId())));
  45 + });
  46 + }
  47 +
  48 + @Mappings({
  49 + @Mapping(source = "task.id", target = "id"),
  50 + @Mapping(source = "task.name", target = "name"),
  51 + @Mapping(source = "task.claimTime", target = "claimTime"),
  52 + @Mapping(source = "task.createTime", target = "createTime"),
  53 + @Mapping(source = "task.suspended", target = "suspensionState", qualifiedByName = "convertSuspendedToSuspensionState"),
  54 + @Mapping(source = "processInstance.id", target = "processInstance.id"),
  55 + @Mapping(source = "processInstance.name", target = "processInstance.name"),
  56 + @Mapping(source = "processInstance.startUserId", target = "processInstance.startUserId"),
  57 + @Mapping(source = "processInstance.processDefinitionId", target = "processInstance.processDefinitionId"),
  58 + @Mapping(source = "user.nickname", target = "processInstance.startUserNickname")
  59 + })
  60 + BpmTaskTodoPageItemRespVO convert(Task task, ProcessInstance processInstance, SysUserDO user);
  61 +
  62 + @Named("convertSuspendedToSuspensionState")
  63 + default Integer convertSuspendedToSuspensionState(boolean suspended) {
  64 + return suspended ? SuspensionState.SUSPENDED.getStateCode() :
  65 + SuspensionState.ACTIVE.getStateCode();
  66 + }
  67 +
  68 + default List<BpmTaskDonePageItemRespVO> convertList2(List<HistoricTaskInstance> tasks, Map<String, BpmTaskExtDO> bpmTaskExtDOMap,
  69 + Map<String, HistoricProcessInstance> historicProcessInstanceMap,
  70 + Map<Long, SysUserDO> userMap) {
  71 + return CollectionUtils.convertList(tasks, task -> {
  72 + BpmTaskExtDO taskExtDO = bpmTaskExtDOMap.get(task.getId());
  73 + HistoricProcessInstance processInstance = historicProcessInstanceMap.get(task.getProcessInstanceId());
  74 + SysUserDO userDO = userMap.get(Long.valueOf(processInstance.getStartUserId()));
  75 + return convert(task, taskExtDO, processInstance, userDO);
  76 + });
  77 + }
  78 +
  79 + @Mappings({
  80 + @Mapping(source = "task.id", target = "id"),
  81 + @Mapping(source = "task.name", target = "name"),
  82 + @Mapping(source = "task.claimTime", target = "claimTime"),
  83 + @Mapping(source = "task.createTime", target = "createTime"),
  84 + @Mapping(source = "task.endTime", target = "endTime"),
  85 + @Mapping(source = "task.durationInMillis", target = "durationInMillis"),
  86 + @Mapping(source = "taskExtDO.result", target = "result"),
  87 + @Mapping(source = "taskExtDO.comment", target = "comment"),
  88 + @Mapping(source = "processInstance.id", target = "processInstance.id"),
  89 + @Mapping(source = "processInstance.name", target = "processInstance.name"),
  90 + @Mapping(source = "processInstance.startUserId", target = "processInstance.startUserId"),
  91 + @Mapping(source = "processInstance.processDefinitionId", target = "processInstance.processDefinitionId"),
  92 + @Mapping(source = "user.nickname", target = "processInstance.startUserNickname")
  93 + })
  94 + BpmTaskDonePageItemRespVO convert(HistoricTaskInstance task, BpmTaskExtDO taskExtDO, HistoricProcessInstance processInstance, SysUserDO user);
  95 +
  96 + @Mappings({
  97 + @Mapping(source = "id", target = "taskId"),
  98 + @Mapping(source = "assignee", target = "assigneeUserId"),
  99 + @Mapping(source = "createdDate", target = "createTime")
  100 + })
  101 + BpmTaskExtDO convert(org.activiti.api.task.model.Task bean);
  102 +
  103 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/workflow/TaskConvert.java deleted
1   -package cn.iocoder.yudao.adminserver.modules.bpm.convert.workflow;
2   -
3   -import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.TaskStepVO;
4   -import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.TodoTaskRespVO;
5   -import org.activiti.api.task.model.Task;
6   -import org.activiti.engine.history.HistoricActivityInstance;
7   -import org.activiti.engine.repository.ProcessDefinition;
8   -import org.mapstruct.Mapper;
9   -import org.mapstruct.Mapping;
10   -import org.mapstruct.Mappings;
11   -import org.mapstruct.Named;
12   -import org.mapstruct.factory.Mappers;
13   -
14   -@Mapper
15   -public interface TaskConvert {
16   - TaskConvert INSTANCE = Mappers.getMapper(TaskConvert.class);
17   -
18   - @Mappings(value = {
19   - @Mapping(source = "task.id", target = "id"),
20   - @Mapping(source = "task.businessKey", target = "businessKey"),
21   - @Mapping(source = "task.assignee", target = "status",qualifiedByName = "convertAssigneeToStatus"),
22   - @Mapping(source = "definition.name", target = "processName"),
23   - @Mapping(source = "definition.key", target = "processKey"),
24   - @Mapping(source = "definition.id", target = "processInstanceId")
25   - })
26   - TodoTaskRespVO convert(Task task, ProcessDefinition definition);
27   -
28   - @Mappings(value = {
29   - @Mapping(source = "assignee", target = "status",qualifiedByName = "convertAssigneeToStatus")
30   - })
31   - TodoTaskRespVO convert(Task task);
32   -
33   - @Named("convertAssigneeToStatus")
34   - default Integer convertAssigneeToStatus(String assignee) {
35   - //TODO 不应该通过 assignee 定义状态 需要定义更多的状态
36   - return assignee == null ? 1 : 2;
37   - }
38   -
39   - @Mappings(value = {
40   - @Mapping(source = "activityName", target = "stepName"),
41   - @Mapping(source = "assignee", target = "assignee")
42   - })
43   - TaskStepVO convert(HistoricActivityInstance instance);
44   -}
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmProcessDefinitionDO.java renamed to 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;
9 9  
10 10 /**
11 11 * Bpm 流程定义的拓展表
12   - * 主要解决 主要进行 Activiti {@link ProcessDefinition} 不支持拓展字段,所以新建拓展表
  12 + * 主要解决 Activiti {@link ProcessDefinition} 不支持拓展字段,所以新建拓展表
13 13 *
14 14 * @author 芋道源码
15 15 */
16   -@TableName(value = "bpm_process_definition", autoResultMap = true)
  16 +@TableName(value = "bpm_process_definition_ext", autoResultMap = true)
17 17 @Data
18 18 @EqualsAndHashCode(callSuper = true)
19 19 @ToString(callSuper = true)
20 20 @Builder
21 21 @NoArgsConstructor
22 22 @AllArgsConstructor
23   -public class BpmProcessDefinitionDO extends BaseDO {
  23 +public class BpmProcessDefinitionExtDO extends BaseDO {
24 24  
25 25 /**
26 26 * 编号
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/task/BpmProcessInstanceExtDO.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task;
  2 +
  3 +import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum;
  4 +import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceStatusEnum;
  5 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  6 +import com.baomidou.mybatisplus.annotation.TableName;
  7 +import lombok.Data;
  8 +import lombok.EqualsAndHashCode;
  9 +import lombok.ToString;
  10 +import org.activiti.engine.history.HistoricProcessInstance;
  11 +import org.activiti.engine.repository.ProcessDefinition;
  12 +import org.activiti.engine.runtime.ProcessInstance;
  13 +
  14 +import java.util.Date;
  15 +
  16 +/**
  17 + * Bpm 流程实例的拓展表
  18 + * 主要解决 Activiti {@link ProcessInstance} 和 {@link HistoricProcessInstance} 不支持拓展字段,所以新建拓展表
  19 + *
  20 + * @author 芋道源码
  21 + */
  22 +@TableName(value = "bpm_process_instance_ext", autoResultMap = true)
  23 +@Data
  24 +@EqualsAndHashCode(callSuper = true)
  25 +@ToString(callSuper = true)
  26 +//@Builder
  27 +//@NoArgsConstructor
  28 +//@AllArgsConstructor
  29 +public class BpmProcessInstanceExtDO extends BaseDO {
  30 +
  31 + /**
  32 + * 发起流程的用户编号
  33 + *
  34 + * 冗余 {@link HistoricProcessInstance#getStartUserId()}
  35 + */
  36 + private Long startUserId;
  37 + /**
  38 + * 流程实例的名字
  39 + *
  40 + * 冗余 {@link ProcessInstance#getName()} 为了筛选
  41 + */
  42 + private String name;
  43 + /**
  44 + * 流程实例的编号
  45 + *
  46 + * 关联 {@link ProcessInstance#getId()}
  47 + */
  48 + private String processInstanceId;
  49 + /**
  50 + * 流程定义的编号
  51 + *
  52 + * 关联 {@link ProcessDefinition#getId()}
  53 + */
  54 + private String processDefinitionId;
  55 + /**
  56 + * 流程分类
  57 + *
  58 + * 冗余 {@link ProcessDefinition#getCategory()}
  59 + * 数据字典 bpm_model_category
  60 + */
  61 + private String category;
  62 + /**
  63 + * 流程实例的状态
  64 + *
  65 + * 枚举 {@link BpmProcessInstanceStatusEnum}
  66 + */
  67 + private Integer status;
  68 + /**
  69 + * 流程实例的结果
  70 + *
  71 + * 枚举 {@link BpmProcessInstanceResultEnum}
  72 + */
  73 + private Integer result;
  74 + /**
  75 + * 结束时间
  76 + *
  77 + * 冗余 {@link HistoricProcessInstance#getEndTime()}
  78 + */
  79 + private Date endTime;
  80 +
  81 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/task/BpmTaskExtDO.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task;
  2 +
  3 +import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum;
  4 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import com.baomidou.mybatisplus.annotation.TableName;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.ToString;
  9 +import org.activiti.engine.history.HistoricTaskInstance;
  10 +import org.activiti.engine.repository.ProcessDefinition;
  11 +import org.activiti.engine.runtime.ProcessInstance;
  12 +import org.activiti.engine.task.Task;
  13 +
  14 +import java.util.Date;
  15 +
  16 +/**
  17 + * Bpm 流程任务的拓展表
  18 + * 主要解决 Activiti {@link Task} 和 {@link HistoricTaskInstance} 不支持拓展字段,所以新建拓展表
  19 + *
  20 + * @author 芋道源码
  21 + */
  22 +@TableName(value = "bpm_task_ext", autoResultMap = true)
  23 +@Data
  24 +@EqualsAndHashCode(callSuper = true)
  25 +@ToString(callSuper = true)
  26 +//@Builder
  27 +//@NoArgsConstructor
  28 +//@AllArgsConstructor
  29 +public class BpmTaskExtDO extends BaseDO {
  30 +
  31 + /**
  32 + * 任务的审批人
  33 + *
  34 + * 冗余 {@link Task#getAssignee()}
  35 + */
  36 + private Long assigneeUserId;
  37 + /**
  38 + * 任务的名字
  39 + *
  40 + * 冗余 {@link Task#getName()} 为了筛选
  41 + */
  42 + private String name;
  43 + /**
  44 + * 任务的编号
  45 + *
  46 + * 关联 {@link Task#getId()}
  47 + */
  48 + private String taskId;
  49 + /**
  50 + * 任务的结果
  51 + *
  52 + * 枚举 {@link BpmProcessInstanceResultEnum}
  53 + */
  54 + private Integer result;
  55 + /**
  56 + * 审批建议
  57 + */
  58 + private String comment;
  59 + /**
  60 + * 任务的结束时间
  61 + *
  62 + * 冗余 {@link HistoricTaskInstance#getEndTime()}
  63 + */
  64 + private Date endTime;
  65 +
  66 + /**
  67 + * 流程实例的编号
  68 + *
  69 + * 关联 {@link ProcessInstance#getId()}
  70 + */
  71 + private String processInstanceId;
  72 + /**
  73 + * 流程定义的编号
  74 + *
  75 + * 关联 {@link ProcessDefinition#getId()}
  76 + */
  77 + private String processDefinitionId;
  78 +
  79 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/task/package-info.java deleted
1   -/**
2   - * TODO 芋艿:工作流创建后的定义
3   - */
4   -package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task;
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmProcessDefinitionMapper.java renamed to yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmProcessDefinitionExtMapper.java
1 1 package cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition;
2 2  
3   -import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionDO;
  3 +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
4 4 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
5 5 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
6 6 import org.apache.ibatis.annotations.Mapper;
... ... @@ -9,10 +9,10 @@ import java.util.Collection;
9 9 import java.util.List;
10 10  
11 11 @Mapper
12   -public interface BpmProcessDefinitionMapper extends BaseMapper<BpmProcessDefinitionDO> {
  12 +public interface BpmProcessDefinitionExtMapper extends BaseMapper<BpmProcessDefinitionExtDO> {
13 13  
14   - default List<BpmProcessDefinitionDO> selectListByProcessDefinitionIds(Collection<String> processDefinitionIds) {
15   - return selectList(new QueryWrapper<BpmProcessDefinitionDO>().in("process_definition_id", processDefinitionIds));
  14 + default List<BpmProcessDefinitionExtDO> selectListByProcessDefinitionIds(Collection<String> processDefinitionIds) {
  15 + return selectList(new QueryWrapper<BpmProcessDefinitionExtDO>().in("process_definition_id", processDefinitionIds));
16 16 }
17 17  
18 18 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/task/BpmProcessInstanceExtMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.task;
  2 +
  3 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceMyPageReqVO;
  4 +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  7 +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
  8 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +
  11 +@Mapper
  12 +public interface BpmProcessInstanceExtMapper extends BaseMapperX<BpmProcessInstanceExtDO> {
  13 +
  14 + default PageResult<BpmProcessInstanceExtDO> selectPage(Long userId, BpmProcessInstanceMyPageReqVO reqVO) {
  15 + return selectPage(reqVO, new QueryWrapperX<BpmProcessInstanceExtDO>()
  16 + .eqIfPresent("start_user_id", userId)
  17 + .likeIfPresent("name", reqVO.getName())
  18 + .eqIfPresent("process_definition_id", reqVO.getProcessDefinitionId())
  19 + .eqIfPresent("category", reqVO.getCategory())
  20 + .eqIfPresent("status", reqVO.getStatus())
  21 + .eqIfPresent("result", reqVO.getResult())
  22 + .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
  23 + .orderByDesc("id"));
  24 + }
  25 +
  26 + default void updateByProcessInstanceId(BpmProcessInstanceExtDO updateObj) {
  27 + update(updateObj, new QueryWrapper<BpmProcessInstanceExtDO>()
  28 + .eq("process_instance_id", updateObj.getProcessInstanceId()));
  29 + }
  30 +
  31 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/task/BpmTaskExtMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.task;
  2 +
  3 +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmTaskExtDO;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  6 +import org.apache.ibatis.annotations.Mapper;
  7 +
  8 +import java.util.Collection;
  9 +import java.util.List;
  10 +
  11 +@Mapper
  12 +public interface BpmTaskExtMapper extends BaseMapperX<BpmTaskExtDO> {
  13 +
  14 + default void updateByTaskId(BpmTaskExtDO entity) {
  15 + update(entity, new QueryWrapper<BpmTaskExtDO>().eq("task_id", entity.getTaskId()));
  16 + }
  17 +
  18 + default List<BpmTaskExtDO> selectListByTaskIds(Collection<String> taskIds) {
  19 + return selectList("task_id", taskIds);
  20 + }
  21 +
  22 +}
... ...
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;
10 10 public interface BpmErrorCodeConstants {
11 11  
12 12 // ========== 通用流程处理 模块 1-009-000-000 ==========
13   - ErrorCode PROCESS_INSTANCE_NOT_EXISTS = new ErrorCode(1009000001, "流程实例不存在");
14 13 ErrorCode HIGHLIGHT_IMG_ERROR = new ErrorCode(1009000002, "获取高亮流程图异常");
15 14  
16 15 // ========== OA 流程模块 1-009-001-000 ==========
... ... @@ -34,7 +33,12 @@ public interface BpmErrorCodeConstants {
34 33 ErrorCode PROCESS_DEFINITION_IS_SUSPENDED = new ErrorCode(1009003002, "流程定义处于挂起状态");
35 34  
36 35 // ========== 流程实例 1-009-004-000 ==========
  36 + ErrorCode PROCESS_INSTANCE_NOT_EXISTS = new ErrorCode(1009004000, "流程实例不存在");
  37 + ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS = new ErrorCode(1009004001, "流程取消失败,流程不处于运行中");
  38 + ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF = new ErrorCode(1009004002, "流程取消失败,该流程不是你发起的");
37 39  
  40 + // ========== 流程实例 1-009-005-000 ==========
  41 + ErrorCode TASK_COMPLETE_FAIL_NOT_EXISTS = new ErrorCode(1009004000, "审批任务失败,原因:该任务不处于未审批");
38 42  
39 43 // ========== 动态表单模块 1-009-010-000 ==========
40 44 ErrorCode FORM_NOT_EXISTS = new ErrorCode(1009010000, "动态表单不存在");
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/task/BpmProcessInstanceDeleteReasonEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.enums.task;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * 流程实例的删除原因
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +@Getter
  12 +@AllArgsConstructor
  13 +public enum BpmProcessInstanceDeleteReasonEnum {
  14 +
  15 + REJECT_TASK("驳回任务");
  16 +
  17 + private final String reason;
  18 +
  19 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/task/BpmProcessInstanceResultEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.enums.task;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * 流程实例的结果
  8 + *
  9 + * @author jason
  10 + */
  11 +@Getter
  12 +@AllArgsConstructor
  13 +public enum BpmProcessInstanceResultEnum {
  14 +
  15 + PROCESS(1, "处理中"),
  16 + APPROVE(2, "通过"),
  17 + REJECT(3, "不通过"),
  18 + CANCEL(4, "已取消");
  19 +
  20 + /**
  21 + * 结果
  22 + */
  23 + private final Integer result;
  24 + /**
  25 + * 描述
  26 + */
  27 + private final String desc;
  28 +
  29 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/FlowStatusEnum.java renamed to yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/task/BpmProcessInstanceStatusEnum.java
1   -package cn.iocoder.yudao.adminserver.modules.bpm.enums;
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.enums.task;
2 2  
3 3 import lombok.AllArgsConstructor;
4 4 import lombok.Getter;
5 5  
6 6 /**
7   - * 流程状态
  7 + * 流程实例的状态
  8 + *
  9 + * @author 芋道源码
8 10 */
9 11 @Getter
10 12 @AllArgsConstructor
11   -public enum FlowStatusEnum {
  13 +public enum BpmProcessInstanceStatusEnum {
12 14  
13   - HANDLE(1, "处理中"),
14   -
15   - PASS(2, "审批通过"),
16   -
17   - REJECTED(3, "审批不通过");
  15 + RUNNING(1, "进行中"),
  16 + FINISH(2, "已完成");
18 17  
19 18 /**
20 19 * 状态
21 20 */
22 21 private final Integer status;
23   -
24   -
25 22 /**
26 23 * 描述
27 24 */
28 25 private final String desc;
  26 +
29 27 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/BpmActivitiConfiguration.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti;
  2 +
  3 +import cn.iocoder.yudao.adminserver.modules.bpm.service.task.listener.BpmTackActivitiEventListener;
  4 +import org.activiti.spring.SpringProcessEngineConfiguration;
  5 +import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
  6 +import org.springframework.context.annotation.Configuration;
  7 +
  8 +import javax.annotation.Resource;
  9 +import java.util.Collections;
  10 +
  11 +/**
  12 + * BPM 模块的 Activiti 配置类
  13 + */
  14 +@Configuration
  15 +public class BpmActivitiConfiguration implements ProcessEngineConfigurationConfigurer {
  16 +
  17 + @Resource
  18 + private BpmTackActivitiEventListener taskActivitiEventListener;
  19 +
  20 + @Override
  21 + public void configure(SpringProcessEngineConfiguration configuration) {
  22 + // 注册监听器,例如说 BpmActivitiEventListener
  23 + configuration.setEventListeners(Collections.singletonList(taskActivitiEventListener));
  24 + }
  25 +
  26 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/package-info.java 0 → 100644
  1 +/**
  2 + * 属于 bpm 模块的 framework 封装
  3 + *
  4 + * @author 芋道源码
  5 + */
  6 +package cn.iocoder.yudao.adminserver.modules.bpm.framework;
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/BpmProcessDefinitionService.java
1 1 package cn.iocoder.yudao.adminserver.modules.bpm.service.definition;
2 2  
  3 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionListReqVO;
3 4 import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageItemRespVO;
4 5 import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageReqVO;
  6 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionRespVO;
5 7 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmDefinitionCreateReqDTO;
6 8 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 9 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
... ... @@ -31,6 +33,14 @@ public interface BpmProcessDefinitionService {
31 33 PageResult<BpmProcessDefinitionPageItemRespVO> getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageReqVO);
32 34  
33 35 /**
  36 + * 获得流程定义列表
  37 + *
  38 + * @param listReqVO 列表入参
  39 + * @return 流程定义列表
  40 + */
  41 + List<BpmProcessDefinitionRespVO> getProcessDefinitionList(BpmProcessDefinitionListReqVO listReqVO);
  42 +
  43 + /**
34 44 * 获得流程定义对应的 BPMN XML
35 45 *
36 46 * @param id 流程定义编号
... ... @@ -55,6 +65,16 @@ public interface BpmProcessDefinitionService {
55 65 ProcessDefinition getProcessDefinition(String id);
56 66  
57 67 /**
  68 + * 获得编号对应的 ProcessDefinition
  69 + *
  70 + * 相比 {@link #getProcessDefinition(String)} 方法,category 的取值是正确
  71 + *
  72 + * @param id 编号
  73 + * @return 流程定义
  74 + */
  75 + ProcessDefinition getProcessDefinition2(String id);
  76 +
  77 + /**
58 78 * 获得 id 对应的 Deployment
59 79 *
60 80 * @param id 部署编号
... ...
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;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionListReqVO;
5 6 import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageItemRespVO;
6 7 import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageReqVO;
  8 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionRespVO;
7 9 import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmDefinitionConvert;
8   -import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionDO;
  10 +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
9 11 import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
10   -import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition.BpmProcessDefinitionMapper;
  12 +import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition.BpmProcessDefinitionExtMapper;
11 13 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
12 14 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmDefinitionCreateReqDTO;
13 15 import cn.iocoder.yudao.adminserver.modules.bpm.service.form.BpmFormService;
... ... @@ -56,7 +58,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
56 58 private BpmFormService bpmFormService;
57 59  
58 60 @Resource
59   - private BpmProcessDefinitionMapper processDefinitionMapper;
  61 + private BpmProcessDefinitionExtMapper processDefinitionMapper;
60 62  
61 63 @Override
62 64 public PageResult<BpmProcessDefinitionPageItemRespVO> getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageVO) {
... ... @@ -77,14 +79,13 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
77 79 Map<String, Deployment> deploymentMap = getDeploymentMap(deploymentIds);
78 80  
79 81 // 获得 BpmProcessDefinitionDO Map
80   - List<BpmProcessDefinitionDO> processDefinitionDOs = Collections.emptyList();
81   - processDefinitionDOs = processDefinitionMapper.selectListByProcessDefinitionIds(
  82 + List<BpmProcessDefinitionExtDO> processDefinitionDOs = processDefinitionMapper.selectListByProcessDefinitionIds(
82 83 convertList(processDefinitions, ProcessDefinition::getId));
83   - Map<String, BpmProcessDefinitionDO> processDefinitionDOMap = CollectionUtils.convertMap(processDefinitionDOs,
84   - BpmProcessDefinitionDO::getProcessDefinitionId);
  84 + Map<String, BpmProcessDefinitionExtDO> processDefinitionDOMap = CollectionUtils.convertMap(processDefinitionDOs,
  85 + BpmProcessDefinitionExtDO::getProcessDefinitionId);
85 86  
86 87 // 获得 Form Map
87   - Set<Long> formIds = CollectionUtils.convertSet(processDefinitionDOs, BpmProcessDefinitionDO::getFormId);
  88 + Set<Long> formIds = CollectionUtils.convertSet(processDefinitionDOs, BpmProcessDefinitionExtDO::getFormId);
88 89 Map<Long, BpmFormDO> formMap = bpmFormService.getFormMap(formIds);
89 90  
90 91 // 拼接结果
... ... @@ -94,6 +95,27 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
94 95 }
95 96  
96 97 @Override
  98 + public List<BpmProcessDefinitionRespVO> getProcessDefinitionList(BpmProcessDefinitionListReqVO listReqVO) {
  99 + // 拼接查询条件
  100 + ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery();
  101 + if (Objects.equals(SuspensionState.SUSPENDED.getStateCode(), listReqVO.getSuspensionState())) {
  102 + definitionQuery.suspended();
  103 + } else if (Objects.equals(SuspensionState.ACTIVE.getStateCode(), listReqVO.getSuspensionState())) {
  104 + definitionQuery.active();
  105 + }
  106 + // 执行查询
  107 + List<ProcessDefinition> processDefinitions = definitionQuery.list();
  108 +
  109 + // 获得 BpmProcessDefinitionDO Map
  110 + List<BpmProcessDefinitionExtDO> processDefinitionDOs = processDefinitionMapper.selectListByProcessDefinitionIds(
  111 + convertList(processDefinitions, ProcessDefinition::getId));
  112 + Map<String, BpmProcessDefinitionExtDO> processDefinitionDOMap = CollectionUtils.convertMap(processDefinitionDOs,
  113 + BpmProcessDefinitionExtDO::getProcessDefinitionId);
  114 + // 执行查询,并返回
  115 + return BpmDefinitionConvert.INSTANCE.convertList3(processDefinitions, processDefinitionDOMap);
  116 + }
  117 +
  118 + @Override
97 119 public String getProcessDefinitionBpmnXML(String id) {
98 120 BpmnModel bpmnModel = repositoryService.getBpmnModel(id);
99 121 if (bpmnModel == null) {
... ... @@ -114,6 +136,11 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
114 136 }
115 137  
116 138 @Override
  139 + public ProcessDefinition getProcessDefinition2(String id) {
  140 + return repositoryService.createProcessDefinitionQuery().processDefinitionId(id).singleResult();
  141 + }
  142 +
  143 + @Override
117 144 public Deployment getDeployment(String id) {
118 145 if (StrUtil.isEmpty(id)) {
119 146 return null;
... ... @@ -169,7 +196,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
169 196 }
170 197  
171 198 // 插入拓展表
172   - BpmProcessDefinitionDO definitionDO = BpmDefinitionConvert.INSTANCE.convert2(createReqDTO)
  199 + BpmProcessDefinitionExtDO definitionDO = BpmDefinitionConvert.INSTANCE.convert2(createReqDTO)
173 200 .setProcessDefinitionId(definition.getId());
174 201 processDefinitionMapper.insert(definitionDO);
175 202 return definition.getId();
... ...
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;
2 2  
3 3 import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.leave.OALeaveDO;
4 4 import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.oa.OALeaveMapper;
5   -import cn.iocoder.yudao.adminserver.modules.bpm.enums.FlowStatusEnum;
  5 +import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum;
6 6 import org.activiti.engine.delegate.DelegateExecution;
7 7 import org.activiti.engine.delegate.ExecutionListener;
8 8 import org.springframework.stereotype.Component;
... ... @@ -29,9 +29,9 @@ public class LeaveApplyEndProcessor implements ExecutionListener {
29 29 OALeaveDO updateDo = new OALeaveDO();
30 30 updateDo.setId(Long.valueOf(businessKey));
31 31 if (Objects.equals(approved, true)) {
32   - updateDo.setStatus(FlowStatusEnum.PASS.getStatus());
  32 + updateDo.setStatus(BpmProcessInstanceResultEnum.APPROVE.getResult());
33 33 } else {
34   - updateDo.setStatus(FlowStatusEnum.REJECTED.getStatus());
  34 + updateDo.setStatus(BpmProcessInstanceResultEnum.REJECT.getResult());
35 35 }
36 36  
37 37 leaveMapper.updateById(updateDo);
... ...
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.*;
6 6 import cn.iocoder.yudao.adminserver.modules.bpm.convert.oa.OALeaveConvert;
7 7 import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.leave.OALeaveDO;
8 8 import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.oa.OALeaveMapper;
9   -import cn.iocoder.yudao.adminserver.modules.bpm.enums.FlowStatusEnum;
  9 +import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum;
10 10 import cn.iocoder.yudao.adminserver.modules.bpm.service.oa.OALeaveService;
11 11 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysPostDO;
12 12 import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.dept.SysPostMapper;
... ... @@ -62,7 +62,7 @@ public class OALeaveServiceImpl implements OALeaveService {
62 62 public Long createLeave(OALeaveCreateReqVO createReqVO) {
63 63 // 插入 OA 请假单
64 64 OALeaveDO leave = OALeaveConvert.INSTANCE.convert(createReqVO);
65   - leave.setStatus(FlowStatusEnum.HANDLE.getStatus());
  65 + leave.setStatus(BpmProcessInstanceResultEnum.PROCESS.getResult());
66 66 // TODO @jason:应该是存储 userId??
67 67 leave.setUserId(SecurityFrameworkUtils.getLoginUser().getUsername());
68 68 leaveMapper.insert(leave);
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmProcessInstanceService.java
1 1 package cn.iocoder.yudao.adminserver.modules.bpm.service.task;
2 2  
  3 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceCancelReqVO;
3 4 import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceCreateReqVO;
  5 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceMyPageReqVO;
  6 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstancePageItemRespVO;
  7 +import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum;
  8 +import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum;
  9 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  10 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  11 +import org.activiti.engine.history.HistoricProcessInstance;
  12 +import org.activiti.engine.runtime.ProcessInstance;
4 13  
5 14 import javax.validation.Valid;
  15 +import java.util.List;
  16 +import java.util.Map;
  17 +import java.util.Set;
6 18  
7 19 /**
8 20 * 流程实例 Service 接口
... ... @@ -20,4 +32,120 @@ public interface BpmProcessInstanceService {
20 32 */
21 33 String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO);
22 34  
  35 + /**
  36 + * 取消流程实例
  37 + *
  38 + * @param userId 用户编号
  39 + * @param cancelReqVO 取消信息
  40 + */
  41 + void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO);
  42 +
  43 + /**
  44 + * 删除流程实例
  45 + *
  46 + * @param id 流程编号
  47 + * @param reason 删除原因。可选 {@link BpmProcessInstanceDeleteReasonEnum}
  48 + */
  49 + @Deprecated
  50 + void deleteProcessInstance(String id, String reason);
  51 +
  52 + /**
  53 + * 更新流程实例的结果
  54 + * 1. 如果更新为已拒绝时,会进行任务的删除
  55 + *
  56 + * @param id 流程编号
  57 + * @param result 结果,{@link BpmProcessInstanceResultEnum}
  58 + */
  59 + void updateProcessInstanceResult(String id, Integer result);
  60 +
  61 + /**
  62 + * 获得流程实例的分页
  63 + *
  64 + * @param userId 用户编号
  65 + * @param pageReqVO 分页请求
  66 + * @return 流程实例的分页
  67 + */
  68 + PageResult<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId,
  69 + @Valid BpmProcessInstanceMyPageReqVO pageReqVO);
  70 +
  71 + /**
  72 + * 获得流程实例
  73 + *
  74 + * @param id 流程实例的编号
  75 + * @return 流程实例
  76 + */
  77 + ProcessInstance getProcessInstance(String id);
  78 +
  79 + /**
  80 + * 获得流程实例列表
  81 + *
  82 + * @param ids 流程实例的编号集合
  83 + * @return 流程实例列表
  84 + */
  85 + List<ProcessInstance> getProcessInstances(Set<String> ids);
  86 +
  87 + /**
  88 + * 获得流程实例 Map
  89 + *
  90 + * @param ids 流程实例的编号集合
  91 + * @return 流程实例列表 Map
  92 + */
  93 + default Map<String, ProcessInstance> getProcessInstanceMap(Set<String> ids) {
  94 + return CollectionUtils.convertMap(getProcessInstances(ids), ProcessInstance::getProcessInstanceId);
  95 + }
  96 +
  97 + /**
  98 + * 获得历史的流程实例
  99 + *
  100 + * @param id 流程实例的编号
  101 + * @return 历史的流程实例
  102 + */
  103 + HistoricProcessInstance getHistoricProcessInstance(String id);
  104 +
  105 + /**
  106 + * 获得历史的流程实例列表
  107 + *
  108 + * @param ids 流程实例的编号集合
  109 + * @return 历史的流程实例列表
  110 + */
  111 + List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids);
  112 +
  113 + /**
  114 + * 获得历史的流程实例 Map
  115 + *
  116 + * @param ids 流程实例的编号集合
  117 + * @return 历史的流程实例列表 Map
  118 + */
  119 + default Map<String, HistoricProcessInstance> getHistoricProcessInstanceMap(Set<String> ids) {
  120 + return CollectionUtils.convertMap(getHistoricProcessInstances(ids), HistoricProcessInstance::getId);
  121 + }
  122 +
  123 + /**
  124 + * 创建 ProcessInstance 拓展记录
  125 + *
  126 + * @param instance 流程任务
  127 + */
  128 + void createProcessInstanceExt(org.activiti.api.process.model.ProcessInstance instance);
  129 +
  130 + /**
  131 + * 更新 ProcessInstance 拓展记录
  132 + *
  133 + * @param instance 流程任务
  134 + */
  135 + void updateProcessInstanceExt(org.activiti.api.process.model.ProcessInstance instance);
  136 +
  137 + /**
  138 + * 更新 ProcessInstance 拓展记录为取消
  139 + *
  140 + * @param instance 流程任务
  141 + */
  142 + void updateProcessInstanceExtCancel(org.activiti.api.process.model.ProcessInstance instance);
  143 +
  144 + /**
  145 + * 更新 ProcessInstance 拓展记录为完成
  146 + *
  147 + * @param instance 流程任务
  148 + */
  149 + void updateProcessInstanceExtComplete(org.activiti.api.process.model.ProcessInstance instance);
  150 +
23 151 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java
1 1 package cn.iocoder.yudao.adminserver.modules.bpm.service.task;
2 2  
3   -import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*;
  3 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.*;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  6 +import org.activiti.engine.task.Task;
5 7  
  8 +import javax.validation.Valid;
6 9 import java.util.List;
  10 +import java.util.Map;
7 11  
8 12 /**
9   - * 工作流用户任务服务接口
  13 + * 流程任务 Service 接口
  14 + *
  15 + * @author jason
  16 + * @author 芋道源码
10 17 */
11 18 public interface BpmTaskService {
12 19  
  20 + /**
  21 + * 获得流程任务列表
  22 + *
  23 + * @param processInstanceId 流程实例的编号
  24 + * @return 流程任务列表
  25 + */
  26 + List<Task> getTasksByProcessInstanceId(String processInstanceId);
  27 +
  28 + /**
  29 + * 获得流程任务列表
  30 + *
  31 + * @param processInstanceIds 流程实例的编号数组
  32 + * @return 流程任务列表
  33 + */
  34 + List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds);
  35 +
  36 + /**
  37 + * 获得流程任务 Map
  38 + *
  39 + * @param processInstanceIds 流程实例的编号数组
  40 + * @return 流程任务 Map
  41 + */
  42 + default Map<String, List<Task>> getTaskMapByProcessInstanceIds(List<String> processInstanceIds) {
  43 + return CollectionUtils.convertMultiMap(getTasksByProcessInstanceIds(processInstanceIds),
  44 + Task::getProcessInstanceId);
  45 + }
13 46  
14 47 /**
15   - * 获取当前用户的待办任务, 分页
  48 + * 获得待办的流程任务分页
  49 + *
  50 + * @param userId 用户编号
  51 + * @param pageReqVO 分页请求
  52 + * @return 流程任务分页
16 53 */
17   - PageResult<TodoTaskRespVO> getTodoTaskPage(TodoTaskPageReqVO pageReqVO);
  54 + PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageReqVO);
18 55  
19 56 /**
20   - * 签收任务
21   - * @param taskId 用户任务id
  57 + * 获得已办的流程任务分页
  58 + *
  59 + * @param userId 用户编号
  60 + * @param pageReqVO 分页请求
  61 + * @return 流程任务分页
22 62 */
23   - void claimTask(String taskId);
  63 + PageResult<BpmTaskDonePageItemRespVO> getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageReqVO);
24 64  
25 65 /**
26   - * 工作流,完成 userTask, 完成用户任务 一般传入参数 1。是否同意(variables). 2. 评论(comment)
27   - * variables 变量名 和 评论 由前台传入
28   - * @param taskReq 任务参数
  66 + * 将流程任务分配给指定用户
  67 + *
  68 + * @param id 流程任务编号
  69 + * @param userId 用户编号
29 70 */
30   - void completeTask(TaskReqVO taskReq);
  71 + void updateTaskAssign(String id, Long userId);
  72 +
  73 + /**
  74 + * 通过任务
  75 + *
  76 + * @param reqVO 通过请求
  77 + */
  78 + void approveTask(@Valid BpmTaskApproveReqVO reqVO);
  79 +
  80 + /**
  81 + * 不通过任务
  82 + *
  83 + * @param reqVO 不通过请求
  84 + */
  85 + void rejectTask(@Valid BpmTaskRejectReqVO reqVO);
31 86  
32 87 /**
33 88 * 根据任务id, 查询已经完成的用户任务,未完成的用户任务
34 89 * @param taskQuery 查询参数 一般 taskId
35 90 */
  91 + @Deprecated
36 92 TaskHandleVO getTaskSteps(TaskQueryReqVO taskQuery);
37 93  
38 94 /**
39 95 * 根据流程实例id, 查询历史用户任务,包括已完成,未完成
40 96 * @param processInstanceId 流程实例id
41 97 */
  98 + @Deprecated
42 99 List<TaskStepVO> getHistorySteps(String processInstanceId);
43 100  
44 101 /**
45   - * 获取用户任务的 formKey, 对应外置表单, 需要根据formKey 对应业务表单
46   - * @param taskQuery 查询参数 ,一般taskId
47   - */
48   - TodoTaskRespVO getTaskFormKey(TaskQueryReqVO taskQuery);
49   -
50   -
51   - /**
52 102 * 返回高亮的流转进程
53 103 * @param processInstanceId 实例Id
54 104 * @return {@link FileResp} 返回文件
55 105 */
56 106 FileResp getHighlightImg(String processInstanceId);
  107 +
  108 + // ========== Task 拓展表相关 ==========
  109 +
  110 + /**
  111 + * 创建 Task 拓展记录
  112 + *
  113 + * @param task 任务实体
  114 + */
  115 + void createTaskExt(org.activiti.api.task.model.Task task);
  116 +
  117 + /**
  118 + * 更新 Task 拓展记录
  119 + *
  120 + * @param task 任务实体
  121 + */
  122 + void updateTaskExt(org.activiti.api.task.model.Task task);
  123 +
  124 + /**
  125 + * 更新 Task 拓展记录为取消
  126 + *
  127 + * @param task 任务实体
  128 + */
  129 + void updateTaskExtCancel(org.activiti.api.task.model.Task task);
  130 +
  131 + /**
  132 + * 更新 Task 拓展记录为完成
  133 + *
  134 + * @param task 任务实体
  135 + */
  136 + void updateTaskExtComplete(org.activiti.api.task.model.Task task);
  137 +
57 138 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmProcessInstanceServiceImpl.java
1 1 package cn.iocoder.yudao.adminserver.modules.bpm.service.task.impl;
2 2  
3   -import cn.hutool.core.lang.Assert;
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceCancelReqVO;
4 5 import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceCreateReqVO;
  6 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceMyPageReqVO;
  7 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstancePageItemRespVO;
  8 +import cn.iocoder.yudao.adminserver.modules.bpm.convert.task.BpmProcessInstanceConvert;
  9 +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
  10 +import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.task.BpmProcessInstanceExtMapper;
  11 +import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum;
  12 +import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum;
  13 +import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceStatusEnum;
5 14 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
6 15 import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmProcessInstanceService;
  16 +import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmTaskService;
7 17 import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
8   -import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
  18 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
9 19 import lombok.extern.slf4j.Slf4j;
10 20 import org.activiti.engine.HistoryService;
11   -import org.activiti.engine.RepositoryService;
12 21 import org.activiti.engine.RuntimeService;
13   -import org.activiti.engine.TaskService;
14   -import org.activiti.engine.history.HistoricProcessInstanceQuery;
15   -import org.activiti.engine.impl.identity.Authentication;
  22 +import org.activiti.engine.history.HistoricProcessInstance;
16 23 import org.activiti.engine.repository.ProcessDefinition;
17 24 import org.activiti.engine.runtime.ProcessInstance;
18 25 import org.activiti.engine.task.Task;
  26 +import org.springframework.context.annotation.Lazy;
19 27 import org.springframework.stereotype.Service;
  28 +import org.springframework.transaction.annotation.Transactional;
20 29 import org.springframework.validation.annotation.Validated;
21 30  
22 31 import javax.annotation.Resource;
23   -import java.util.Map;
  32 +import java.util.*;
24 33  
25   -import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.PROCESS_DEFINITION_IS_SUSPENDED;
26   -import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.PROCESS_DEFINITION_NOT_EXISTS;
  34 +import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.*;
27 35 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  36 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
28 37  
29 38 /**
30 39 * 流程实例 Service 实现类
... ... @@ -44,20 +53,23 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
44 53 public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService {
45 54  
46 55 @Resource
47   - private RepositoryService repositoryService;
48   - @Resource
49 56 private RuntimeService runtimeService;
50 57 @Resource
51   - private TaskService taskService;
52   - @Resource
53 58 private HistoryService historyService;
54 59  
55 60 @Resource
56 61 private SysUserService userService;
57 62 @Resource
  63 + @Lazy // 解决循环依赖
  64 + private BpmTaskService taskService;
  65 + @Resource
58 66 private BpmProcessDefinitionService processDefinitionService;
59 67  
  68 + @Resource
  69 + private BpmProcessInstanceExtMapper processInstanceExtMapper;
  70 +
60 71 @Override
  72 + @Transactional(rollbackFor = Exception.class)
61 73 public String createProcessInstance(Long userId, BpmProcessInstanceCreateReqVO createReqVO) {
62 74 // 校验流程定义
63 75 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId());
... ... @@ -68,33 +80,141 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
68 80 throw exception(PROCESS_DEFINITION_IS_SUSPENDED);
69 81 }
70 82  
71   - // 设置流程发起人
72   - Authentication.setAuthenticatedUserId(String.valueOf(userId));
73   -
74 83 // 创建流程实例
75 84 Map<String, Object> variables = createReqVO.getVariables();
76   - variables.put("INITIATOR", userId); // TODO 芋艿:初始化人员
77 85 ProcessInstance instance = runtimeService.startProcessInstanceById(createReqVO.getProcessDefinitionId(), variables);
  86 + // 设置流程名字
  87 + runtimeService.setProcessInstanceName(instance.getId(), definition.getName());
  88 +
  89 + // TODO 芋艿:临时使用, 保证分配
  90 + List<Task> tasks = taskService.getTasksByProcessInstanceId(instance.getId());
  91 + tasks.forEach(task -> taskService.updateTaskAssign(task.getId(), userId));
78 92  
79 93 // 添加初始的评论 TODO 芋艿:在思考下
80   - Task task = taskService.createTaskQuery().processInstanceId(instance.getId()).singleResult();
81   - if (task != null) {
82   - SysUserDO user = userService.getUser(userId);
83   - Assert.notNull(user, "用户({})不存在", userId);
84   - String type = "normal";
85   - taskService.addComment(task.getId(), instance.getProcessInstanceId(), type,
86   - String.format("%s 发起流程申请", user.getNickname()));
87   - // TODO 芋艿:应该不用下面两个步骤
88   -// taskService.setAssignee(task.getId(), String.valueOf(userId));
89   -// taskService.complete(task.getId(), variables);
90   - }
  94 +// Task task = taskService.createTaskQuery().processInstanceId(instance.getId()).singleResult();
  95 +// if (task != null) {
  96 +// SysUserDO user = userService.getUser(userId);
  97 +// Assert.notNull(user, "用户({})不存在", userId);
  98 +// String type = "normal";
  99 +// taskService.addComment(task.getId(), instance.getProcessInstanceId(), type,
  100 +// String.format("%s 发起流程申请", user.getNickname()));
  101 +// // TODO 芋艿:应该不用下面两个步骤
  102 +//// taskService.setAssignee(task.getId(), String.valueOf(userId));
  103 +//// taskService.complete(task.getId(), variables);
  104 +// }
91 105 return instance.getId();
92 106 }
93 107  
94   - public void getMyProcessInstancePage(Long userId) {
95   - HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery()
96   - .startedBy(String.valueOf(userId)) // 发起人是自己
97   - .orderByProcessInstanceStartTime().desc(); // 按照发起时间倒序
  108 + @Override
  109 + @Transactional(rollbackFor = Exception.class)
  110 + public void cancelProcessInstance(Long userId, BpmProcessInstanceCancelReqVO cancelReqVO) {
  111 + // 校验流程实例存在
  112 + ProcessInstance instance = getProcessInstance(cancelReqVO.getId());
  113 + if (instance == null) {
  114 + throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS);
  115 + }
  116 + // 只能取消自己的
  117 + if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) {
  118 + throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF);
  119 + }
  120 +
  121 + // 通过删除流程实例,实现流程实例的取消
  122 + runtimeService.deleteProcessInstance(cancelReqVO.getId(), cancelReqVO.getReason());
  123 + }
  124 +
  125 + @Override
  126 + public void deleteProcessInstance(String id, String reason) {
  127 + runtimeService.deleteProcessInstance(id, reason);
  128 + }
  129 +
  130 + @Override
  131 + @Transactional(rollbackFor = Exception.class)
  132 + public void updateProcessInstanceResult(String id, Integer result) {
  133 + // 删除流程实例,以实现驳回任务时,取消整个审批流程
  134 + if (Objects.equals(result, BpmProcessInstanceResultEnum.REJECT.getResult())) {
  135 + deleteProcessInstance(id, BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.getReason());
  136 + }
  137 + // 更新 status + result
  138 + processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(id)
  139 + .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()).setResult(result));
  140 + }
  141 +
  142 + @Override
  143 + public PageResult<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId,
  144 + BpmProcessInstanceMyPageReqVO pageReqVO) {
  145 + // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页
  146 + PageResult<BpmProcessInstanceExtDO> pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO);
  147 + if (CollUtil.isEmpty(pageResult.getList())) {
  148 + return new PageResult<>(pageResult.getTotal());
  149 + }
  150 +
  151 + // 获得流程 Task Map
  152 + List<String> processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId);
  153 + Map<String, List<Task>> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds);
  154 + // 转换返回
  155 + return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap);
  156 + }
  157 +
  158 + @Override
  159 + public List<ProcessInstance> getProcessInstances(Set<String> ids) {
  160 + return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list();
  161 + }
  162 +
  163 + @Override
  164 + public ProcessInstance getProcessInstance(String id) {
  165 + return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult();
  166 + }
  167 +
  168 + /**
  169 + * 获得历史的流程实例
  170 + *
  171 + * @param id 流程实例的编号
  172 + * @return 历史的流程实例
  173 + */
  174 + @Override
  175 + public HistoricProcessInstance getHistoricProcessInstance(String id) {
  176 + return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult();
  177 + }
  178 +
  179 + @Override
  180 + public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) {
  181 + return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list();
  182 + }
  183 +
  184 + @Override
  185 + public void createProcessInstanceExt(org.activiti.api.process.model.ProcessInstance instance) {
  186 + // 获得流程定义
  187 + ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId());
  188 + // 插入 BpmProcessInstanceExtDO 对象
  189 + BpmProcessInstanceExtDO instanceExtDO = BpmProcessInstanceConvert.INSTANCE.convert(instance)
  190 + .setCategory(definition.getCategory())
  191 + .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus())
  192 + .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
  193 + processInstanceExtMapper.insert(instanceExtDO);
  194 + }
  195 +
  196 + @Override
  197 + public void updateProcessInstanceExt(org.activiti.api.process.model.ProcessInstance instance) {
  198 + BpmProcessInstanceExtDO instanceExtDO = BpmProcessInstanceConvert.INSTANCE.convert(instance);
  199 + processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);
  200 + }
  201 +
  202 + @Override
  203 + public void updateProcessInstanceExtCancel(org.activiti.api.process.model.ProcessInstance instance) {
  204 + BpmProcessInstanceExtDO instanceExtDO = BpmProcessInstanceConvert.INSTANCE.convert(instance)
  205 + .setEndTime(new Date()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置
  206 + .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus())
  207 + .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult());
  208 + processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);
  209 + }
  210 +
  211 + @Override
  212 + public void updateProcessInstanceExtComplete(org.activiti.api.process.model.ProcessInstance instance) {
  213 + BpmProcessInstanceExtDO instanceExtDO = BpmProcessInstanceConvert.INSTANCE.convert(instance)
  214 + .setEndTime(new Date()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置
  215 + .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus())
  216 + .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过
  217 + processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);
98 218 }
99 219  
100 220 }
... ...
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;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.io.IoUtil;
5   -import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*;
6   -import cn.iocoder.yudao.adminserver.modules.bpm.convert.workflow.TaskConvert;
  5 +import cn.hutool.core.util.StrUtil;
  6 +import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.*;
  7 +import cn.iocoder.yudao.adminserver.modules.bpm.convert.task.BpmTaskConvert;
  8 +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmTaskExtDO;
  9 +import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.task.BpmTaskExtMapper;
  10 +import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum;
  11 +import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmProcessInstanceService;
7 12 import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmTaskService;
  13 +import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
  14 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
8 15 import cn.iocoder.yudao.framework.common.pojo.PageResult;
9 16 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
10   -import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
  17 +import cn.iocoder.yudao.framework.common.util.object.PageUtils;
11 18 import lombok.extern.slf4j.Slf4j;
12   -import org.activiti.api.runtime.shared.query.Page;
13   -import org.activiti.api.runtime.shared.query.Pageable;
14   -import org.activiti.api.task.model.Task;
15   -import org.activiti.api.task.model.builders.ClaimTaskPayloadBuilder;
16   -import org.activiti.api.task.model.builders.TaskPayloadBuilder;
17   -import org.activiti.api.task.runtime.TaskRuntime;
18 19 import org.activiti.bpmn.constants.BpmnXMLConstants;
19 20 import org.activiti.bpmn.model.BpmnModel;
20 21 import org.activiti.bpmn.model.FlowNode;
... ... @@ -22,100 +23,210 @@ import org.activiti.bpmn.model.SequenceFlow;
22 23 import org.activiti.engine.HistoryService;
23 24 import org.activiti.engine.RepositoryService;
24 25 import org.activiti.engine.RuntimeService;
  26 +import org.activiti.engine.TaskService;
25 27 import org.activiti.engine.history.HistoricActivityInstance;
26 28 import org.activiti.engine.history.HistoricProcessInstance;
  29 +import org.activiti.engine.history.HistoricTaskInstance;
  30 +import org.activiti.engine.history.HistoricTaskInstanceQuery;
27 31 import org.activiti.engine.repository.ProcessDefinition;
28 32 import org.activiti.engine.runtime.ProcessInstance;
29 33 import org.activiti.engine.task.Comment;
  34 +import org.activiti.engine.task.Task;
  35 +import org.activiti.engine.task.TaskQuery;
30 36 import org.activiti.image.ProcessDiagramGenerator;
  37 +import org.springframework.context.annotation.Lazy;
31 38 import org.springframework.stereotype.Service;
32 39 import org.springframework.transaction.annotation.Transactional;
33 40 import org.springframework.util.ObjectUtils;
34 41  
35 42 import javax.annotation.Resource;
  43 +import javax.validation.Valid;
36 44 import java.io.IOException;
37 45 import java.io.InputStream;
38   -import java.util.ArrayList;
39   -import java.util.List;
40   -import java.util.Map;
41   -import java.util.Optional;
42   -import java.util.stream.Collectors;
43   -
44   -import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.HIGHLIGHT_IMG_ERROR;
45   -import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS;
46   -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  46 +import java.util.*;
47 47  
  48 +import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.*;
  49 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  50 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  51 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  52 +
  53 +/**
  54 + * 流程任务 Service 实现类
  55 + *
  56 + * @author jason
  57 + * @author 芋道源码
  58 + */
48 59 @Slf4j
49 60 @Service
50 61 public class BpmTaskServiceImpl implements BpmTaskService {
51 62  
52 63 @Resource
53   - private TaskRuntime taskRuntime;
54   -
  64 + private TaskService taskService;
55 65 @Resource
56   - private org.activiti.engine.TaskService activitiTaskService;
57   -
  66 + private RuntimeService runtimeService;
58 67 @Resource
59 68 private HistoryService historyService;
60   -
61 69 @Resource
62 70 private RepositoryService repositoryService;
63 71  
64 72 @Resource
65   - private RuntimeService runtimeService;
  73 + private ProcessDiagramGenerator processDiagramGenerator;
66 74  
67 75 @Resource
68   - private ProcessDiagramGenerator processDiagramGenerator;
  76 + private SysUserService userService;
  77 + @Resource
  78 + @Lazy // 解决循环依赖
  79 + private BpmProcessInstanceService processInstanceService;
  80 +
  81 + @Resource
  82 + private BpmTaskExtMapper taskExtMapper;
69 83  
70 84 @Override
71   - public PageResult<TodoTaskRespVO> getTodoTaskPage(TodoTaskPageReqVO pageReqVO) {
72   - // TODO @jason:封装一个方法,用于转换成 activiti 的分页对象
73   - final Pageable pageable = Pageable.of((pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize(), pageReqVO.getPageSize());
74   - Page<Task> pageTasks = taskRuntime.tasks(pageable);
75   - int totalItems = pageTasks.getTotalItems();
76   - List<Task> tasks = pageTasks.getContent();
77   - final List<TodoTaskRespVO> respVOList = tasks.stream().map(task -> {
78   - ProcessDefinition definition = repositoryService.getProcessDefinition(task.getProcessDefinitionId());
79   - return TaskConvert.INSTANCE.convert(task, definition);
80   - }).collect(Collectors.toList());
81   - return new PageResult<>(respVOList, (long)totalItems);
  85 + public List<Task> getTasksByProcessInstanceId(String processInstanceId) {
  86 + return taskService.createTaskQuery().processInstanceId(processInstanceId).list();
82 87 }
83 88  
  89 + @Override
  90 + public List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds) {
  91 + if (CollUtil.isEmpty(processInstanceIds)) {
  92 + return Collections.emptyList();
  93 + }
  94 + return taskService.createTaskQuery().processInstanceIdIn(processInstanceIds).list();
  95 + }
84 96  
85 97 @Override
86   - public void claimTask(String taskId) {
87   - taskRuntime.claim(new ClaimTaskPayloadBuilder()
88   - .withTaskId(taskId)
89   - .withAssignee(SecurityFrameworkUtils.getLoginUser().getUsername())
90   - .build());
  98 + public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) {
  99 + // 查询待办任务
  100 + TaskQuery taskQuery = taskService.createTaskQuery()
  101 + .taskAssignee(String.valueOf(userId)) // 分配给自己
  102 + .orderByTaskCreateTime().desc(); // 创建时间倒序
  103 + if (StrUtil.isNotBlank(pageVO.getName())) {
  104 + taskQuery.taskNameLike("%" + pageVO.getName() + "%");
  105 + }
  106 + if (pageVO.getBeginCreateTime() != null) {
  107 + taskQuery.taskCreatedAfter(pageVO.getBeginCreateTime());
  108 + }
  109 + if (pageVO.getEndCreateTime() != null) {
  110 + taskQuery.taskCreatedBefore(pageVO.getEndCreateTime());
  111 + }
  112 + // 执行查询
  113 + List<Task> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
  114 + if (CollUtil.isEmpty(tasks)) {
  115 + return PageResult.empty(taskQuery.count());
  116 + }
  117 +
  118 + // 获得 ProcessInstance Map
  119 + Map<String, ProcessInstance> processInstanceMap = processInstanceService.getProcessInstanceMap(
  120 + convertSet(tasks, Task::getProcessInstanceId));
  121 + // 获得 User Map
  122 + Map<Long, SysUserDO> userMap = userService.getUserMap(
  123 + convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
  124 + // 拼接结果
  125 + return new PageResult<>(BpmTaskConvert.INSTANCE.convertList(tasks, processInstanceMap, userMap),
  126 + taskQuery.count());
91 127 }
92 128  
  129 + @Override
  130 + public PageResult<BpmTaskDonePageItemRespVO> getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageVO) {
  131 + // 查询已办任务
  132 + HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery()
  133 + .finished() // 已完成
  134 + .taskAssignee(String.valueOf(userId)) // 分配给自己
  135 + .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序
  136 + if (StrUtil.isNotBlank(pageVO.getName())) {
  137 + taskQuery.taskNameLike("%" + pageVO.getName() + "%");
  138 + }
  139 + if (pageVO.getBeginCreateTime() != null) {
  140 + taskQuery.taskCreatedAfter(pageVO.getBeginCreateTime());
  141 + }
  142 + if (pageVO.getEndCreateTime() != null) {
  143 + taskQuery.taskCreatedBefore(pageVO.getEndCreateTime());
  144 + }
  145 + // 执行查询
  146 + List<HistoricTaskInstance> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
  147 + if (CollUtil.isEmpty(tasks)) {
  148 + return PageResult.empty(taskQuery.count());
  149 + }
93 150  
  151 + // 获得 TaskExtDO Map
  152 + List<BpmTaskExtDO> bpmTaskExtDOs = taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId));
  153 + Map<String, BpmTaskExtDO> bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId);
  154 + // 获得 ProcessInstance Map
  155 + Map<String, HistoricProcessInstance> historicProcessInstanceMap = processInstanceService.getHistoricProcessInstanceMap(
  156 + convertSet(tasks, HistoricTaskInstance::getProcessInstanceId));
  157 + // 获得 User Map
  158 + Map<Long, SysUserDO> userMap = userService.getUserMap(
  159 + convertSet(historicProcessInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
  160 + // 拼接结果
  161 + return new PageResult<>(BpmTaskConvert.INSTANCE.convertList2(tasks, bpmTaskExtDOMap, historicProcessInstanceMap, userMap),
  162 + taskQuery.count());
  163 + }
94 164  
95 165 @Override
96   - @Transactional
97   - public void completeTask(TaskReqVO taskReq) {
98   - final Task task = taskRuntime.task(taskReq.getTaskId());
  166 + public void updateTaskAssign(String id, Long userId) {
  167 + taskService.setAssignee(id, String.valueOf(userId));
  168 + }
  169 +
  170 + @Override
  171 + @Transactional(rollbackFor = Exception.class)
  172 + public void approveTask(BpmTaskApproveReqVO reqVO) {
  173 + // 校验任务存在
  174 + Task task = getTask(reqVO.getId());
  175 + if (task == null) {
  176 + throw exception(TASK_COMPLETE_FAIL_NOT_EXISTS);
  177 + }
  178 + // 校验流程实例存在
  179 + ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
  180 + if (instance == null) {
  181 + throw exception(PROCESS_INSTANCE_NOT_EXISTS);
  182 + }
99 183  
100   - activitiTaskService.addComment(taskReq.getTaskId(), task.getProcessInstanceId(), taskReq.getComment());
  184 + // 完成任务,审批通过
  185 + taskService.complete(task.getId(), instance.getProcessVariables()); // TODO 芋艿:variables 的选择
  186 + // 更新任务拓展表为通过
  187 + taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId())
  188 + .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()).setComment(reqVO.getComment()));
101 189  
102   - taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(taskReq.getTaskId())
103   - .withVariables(taskReq.getVariables())
104   - .build());
  190 + // TODO 芋艿:添加评论
  191 +// taskService.addComment(task.getId(), task.getProcessInstanceId(), reqVO.getComment());
105 192 }
106 193  
  194 + @Override
  195 + @Transactional(rollbackFor = Exception.class)
  196 + public void rejectTask(@Valid BpmTaskRejectReqVO reqVO) {
  197 + // 校验任务存在
  198 + Task task = getTask(reqVO.getId());
  199 + if (task == null) {
  200 + throw exception(TASK_COMPLETE_FAIL_NOT_EXISTS);
  201 + }
  202 + // 校验流程实例存在
  203 + ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
  204 + if (instance == null) {
  205 + throw exception(PROCESS_INSTANCE_NOT_EXISTS);
  206 + }
  207 +
  208 + // 更新流程实例为不通过
  209 + processInstanceService.updateProcessInstanceResult(instance.getProcessInstanceId(),
  210 + BpmProcessInstanceResultEnum.REJECT.getResult());
107 211  
  212 + // 更新任务拓展表为不通过
  213 + taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId())
  214 + .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()).setComment(reqVO.getComment()));
  215 +
  216 + // TODO 芋艿:添加评论
  217 +// taskService.addComment(task.getId(), task.getProcessInstanceId(), reqVO.getComment());
  218 + }
108 219  
109 220 @Override
110 221 public TaskHandleVO getTaskSteps(TaskQueryReqVO taskQuery) {
111   - TaskHandleVO handleVO = new TaskHandleVO();
112   - final Task task = taskRuntime.task(taskQuery.getTaskId());
113   - List<TaskStepVO> steps = getTaskSteps(task.getProcessInstanceId());
114   - handleVO.setHistoryTask(steps);
115   - return handleVO;
  222 +// TaskHandleVO handleVO = new TaskHandleVO();
  223 +// final Task task = taskRuntime.task(taskQuery.getTaskId());
  224 +// List<TaskStepVO> steps = getTaskSteps(task.getProcessInstanceId());
  225 +// handleVO.setHistoryTask(steps);
  226 +// return handleVO;
  227 + return null;
116 228 }
117 229  
118   -
119 230 private List<TaskStepVO> getTaskSteps(String processInstanceId) {
120 231 // 获得已完成的活动
121 232 List<HistoricActivityInstance> finished = historyService.createHistoricActivityInstanceQuery()
... ... @@ -126,10 +237,10 @@ public class BpmTaskServiceImpl implements BpmTaskService {
126 237 // 获得对应的步骤
127 238 List<TaskStepVO> steps = new ArrayList<>();
128 239 finished.forEach(instance -> {
129   - TaskStepVO stepVO = TaskConvert.INSTANCE.convert(instance);
  240 + TaskStepVO stepVO = BpmTaskConvert.INSTANCE.convert(instance);
130 241 stepVO.setStatus(1); // TODO @jason:1 这个 magic number 要枚举起来。
131 242 // TODO @jason:可以考虑把 comments 读取后,在统一调用 convert 拼接。另外 Comment 是废弃的类,有没其它可以使用的哈?
132   - List<Comment> comments = activitiTaskService.getTaskComments(instance.getTaskId());
  243 + List<Comment> comments = taskService.getTaskComments(instance.getTaskId());
133 244 if (!CollUtil.isEmpty(comments)) {
134 245 stepVO.setComment(Optional.ofNullable(comments.get(0)).map(Comment::getFullMessage).orElse(""));
135 246 }
... ... @@ -144,7 +255,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
144 255 .unfinished().list();
145 256 // 获得对应的步骤
146 257 for (HistoricActivityInstance instance : unfinished) {
147   - TaskStepVO stepVO = TaskConvert.INSTANCE.convert(instance);
  258 + TaskStepVO stepVO = BpmTaskConvert.INSTANCE.convert(instance);
148 259 stepVO.setComment("");
149 260 stepVO.setStatus(0);
150 261 steps.add(stepVO);
... ... @@ -159,12 +270,6 @@ public class BpmTaskServiceImpl implements BpmTaskService {
159 270 }
160 271  
161 272 @Override
162   - public TodoTaskRespVO getTaskFormKey(TaskQueryReqVO taskQuery) {
163   - final Task task = taskRuntime.task(taskQuery.getTaskId());
164   - return TaskConvert.INSTANCE.convert(task);
165   - }
166   -
167   - @Override
168 273 public FileResp getHighlightImg(String processInstanceId) {
169 274 // 查询历史
170 275 //TODO 云扬四海 貌似流程结束后,点击审批进度会报错
... ... @@ -172,7 +277,8 @@ public class BpmTaskServiceImpl implements BpmTaskService {
172 277 HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
173 278 // 如果不存在实例。 说明数据异常
174 279 if (hpi == null) {
175   - throw exception(PROCESS_INSTANCE_NOT_EXISTS);
  280 +// throw exception(PROCESS_INSTANCE_NOT_EXISTS);
  281 + throw new RuntimeException("不存在");
176 282 }
177 283 // 如果有结束时间 返回model的流程图
178 284 if (!ObjectUtils.isEmpty(hpi.getEndTime())) {
... ... @@ -285,4 +391,41 @@ public class BpmTaskServiceImpl implements BpmTaskService {
285 391 }
286 392 return highLightedFlowIds;
287 393 }
  394 +
  395 + private Task getTask(String id) {
  396 + return taskService.createTaskQuery().taskId(id).singleResult();
  397 + }
  398 +
  399 + // ========== Task 拓展表相关 ==========
  400 +
  401 + @Override
  402 + public void createTaskExt(org.activiti.api.task.model.Task task) {
  403 + // 插入 BpmTaskExtDO 记录
  404 + BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert(task)
  405 + .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
  406 + taskExtMapper.insert(taskExtDO);
  407 + }
  408 +
  409 + @Override
  410 + public void updateTaskExt(org.activiti.api.task.model.Task task) {
  411 + BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert(task);
  412 + taskExtMapper.updateByTaskId(taskExtDO);
  413 + }
  414 +
  415 + @Override
  416 + public void updateTaskExtCancel(org.activiti.api.task.model.Task task) {
  417 + BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert(task)
  418 + .setEndTime(new Date()) // 由于 Task 里没有办法拿到 endTime,所以这里设置
  419 + .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult());
  420 + taskExtMapper.updateByTaskId(taskExtDO);
  421 + }
  422 +
  423 + @Override
  424 + public void updateTaskExtComplete(org.activiti.api.task.model.Task task) {
  425 + BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert(task)
  426 + .setEndTime(task.getCompletedDate())
  427 + .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult());
  428 + taskExtMapper.updateByTaskId(taskExtDO);
  429 + }
  430 +
288 431 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/listener/BpmProcessInstanceEventListener.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.service.task.listener;
  2 +
  3 +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
  4 +import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmProcessInstanceService;
  5 +import org.activiti.api.model.shared.event.RuntimeEvent;
  6 +import org.activiti.api.process.model.ProcessInstance;
  7 +import org.activiti.api.process.model.events.ProcessRuntimeEvent;
  8 +import org.activiti.api.process.runtime.events.listener.ProcessEventListener;
  9 +import org.activiti.api.process.runtime.events.listener.ProcessRuntimeEventListener;
  10 +import org.activiti.api.task.model.events.TaskRuntimeEvent;
  11 +import org.springframework.context.annotation.Lazy;
  12 +import org.springframework.stereotype.Component;
  13 +
  14 +import javax.annotation.Resource;
  15 +
  16 +/**
  17 + * 监听 {@link ProcessInstance} 的开始与完成,创建与更新对应的 {@link BpmProcessInstanceExtDO} 记录
  18 + *
  19 + * @author 芋道源码
  20 + */
  21 +@Component
  22 +public class BpmProcessInstanceEventListener<T extends RuntimeEvent<?, ?>>
  23 + implements ProcessRuntimeEventListener<T> {
  24 +
  25 + @Resource
  26 + @Lazy // 解决循环依赖
  27 + private BpmProcessInstanceService processInstanceService;
  28 +
  29 + @Override
  30 + @SuppressWarnings("unchecked")
  31 + public void onEvent(T rawEvent) {
  32 + // 由于 ProcessRuntimeEventListener 无法保证只监听 ProcessRuntimeEvent 事件,所以通过这样的方式
  33 + if (!(rawEvent instanceof ProcessRuntimeEvent)) {
  34 + return;
  35 + }
  36 + ProcessRuntimeEvent<ProcessInstance> event = (ProcessRuntimeEvent<ProcessInstance>) rawEvent;
  37 +
  38 + // 创建时,插入拓展表
  39 + if (event.getEventType() == ProcessRuntimeEvent.ProcessEvents.PROCESS_CREATED) {
  40 + processInstanceService.createProcessInstanceExt(event.getEntity());
  41 + return;
  42 + }
  43 + // 取消时,更新拓展表为取消
  44 + if (event.getEventType() == ProcessRuntimeEvent.ProcessEvents.PROCESS_CANCELLED) {
  45 + processInstanceService.updateProcessInstanceExtCancel(event.getEntity());
  46 + return;
  47 + }
  48 + // 完成时,更新拓展表为已完成
  49 + if (event.getEventType() == ProcessRuntimeEvent.ProcessEvents.PROCESS_COMPLETED) {
  50 + processInstanceService.updateProcessInstanceExtComplete(event.getEntity());
  51 + return;
  52 + }
  53 +
  54 + // 其它事件,进行更新拓展表
  55 + processInstanceService.updateProcessInstanceExt(event.getEntity());
  56 + }
  57 +
  58 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/listener/BpmTackActivitiEventListener.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.service.task.listener;
  2 +
  3 +import cn.hutool.core.util.StrUtil;
  4 +import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
  5 +import org.activiti.api.process.runtime.events.listener.ProcessRuntimeEventListener;
  6 +import org.activiti.api.task.runtime.events.listener.TaskEventListener;
  7 +import org.activiti.engine.delegate.event.ActivitiEvent;
  8 +import org.activiti.engine.delegate.event.ActivitiEventListener;
  9 +import org.activiti.engine.delegate.event.ActivitiEventType;
  10 +import org.activiti.engine.delegate.event.impl.ActivitiEntityEventImpl;
  11 +import org.activiti.engine.impl.persistence.entity.TaskEntity;
  12 +import org.activiti.engine.repository.ProcessDefinition;
  13 +import org.springframework.context.annotation.Lazy;
  14 +import org.springframework.stereotype.Component;
  15 +
  16 +import javax.annotation.Resource;
  17 +
  18 +/**
  19 + * 监听 {@link TaskEntity} 相关的事件,设置相关属性。
  20 + * 目的:解决 {@link TaskEventListener} 无法解决的场景
  21 + *
  22 + * @author 芋道源码
  23 + */
  24 +@Component
  25 +public class BpmTackActivitiEventListener implements ActivitiEventListener {
  26 +
  27 + @Resource
  28 + @Lazy // 解决循环依赖
  29 + private BpmProcessDefinitionService processDefinitionService;
  30 +
  31 + @Override
  32 + public void onEvent(ActivitiEvent event) {
  33 + // Task 创建时,设置其分类,解决 TaskService 未提供 name 的设置方法
  34 + if (ActivitiEventType.TASK_CREATED == event.getType()) {
  35 + TaskEntity task = ((TaskEntity) ((ActivitiEntityEventImpl) event).getEntity());
  36 + if (StrUtil.isNotEmpty(task.getCategory())) {
  37 + return;
  38 + }
  39 + // 设置 name
  40 + ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition2(task.getProcessDefinitionId());
  41 + if (processDefinition == null) {
  42 + return;
  43 + }
  44 + task.setCategory(processDefinition.getCategory());
  45 + }
  46 + }
  47 +
  48 + @Override
  49 + public boolean isFailOnException() {
  50 + return true;
  51 + }
  52 +
  53 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/listener/BpmTaskEventListener.java 0 → 100644
  1 +package cn.iocoder.yudao.adminserver.modules.bpm.service.task.listener;
  2 +
  3 +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmTaskExtDO;
  4 +import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmTaskService;
  5 +import org.activiti.api.task.model.Task;
  6 +import org.activiti.api.task.model.events.TaskRuntimeEvent;
  7 +import org.activiti.api.task.runtime.events.listener.TaskEventListener;
  8 +import org.springframework.context.annotation.Lazy;
  9 +import org.springframework.stereotype.Component;
  10 +
  11 +import javax.annotation.Resource;
  12 +
  13 +/**
  14 + * 监听 {@link Task} 的开始与完成,创建与更新对应的 {@link BpmTaskExtDO} 记录
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +@Component
  19 +public class BpmTaskEventListener<T extends TaskRuntimeEvent<? extends Task>>
  20 + implements TaskEventListener<T> {
  21 +
  22 + @Resource
  23 + @Lazy // 解决循环依赖
  24 + private BpmTaskService taskService;
  25 +
  26 + @Override
  27 + public void onEvent(T event) {
  28 + // 创建时,插入拓展表
  29 + if (event.getEventType() == TaskRuntimeEvent.TaskEvents.TASK_CREATED) {
  30 + taskService.createTaskExt(event.getEntity());
  31 + return;
  32 + }
  33 +
  34 + // 取消时,更新拓展表为取消
  35 + if (event.getEventType() == TaskRuntimeEvent.TaskEvents.TASK_CANCELLED) {
  36 + taskService.updateTaskExtCancel(event.getEntity());
  37 + return;
  38 + }
  39 + // 完成时,更新拓展表为已完成。要注意,在调用 delete ProcessInstance 才会触发该逻辑
  40 + if (event.getEventType() == TaskRuntimeEvent.TaskEvents.TASK_COMPLETED) {
  41 + taskService.updateTaskExtComplete(event.getEntity());
  42 + return;
  43 + }
  44 +
  45 + // 其它事件,进行更新拓展表
  46 + taskService.updateTaskExt(event.getEntity());
  47 + }
  48 +
  49 +}
... ...
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 {
176 176  
177 177 @Override
178 178 public List<SysUserDO> getUsers(Collection<Long> ids) {
  179 + if (CollUtil.isEmpty(ids)) {
  180 + return Collections.emptyList();
  181 + }
179 182 return userMapper.selectBatchIds(ids);
180 183 }
181 184  
... ...
yudao-admin-ui/package.json
... ... @@ -85,7 +85,7 @@
85 85 "@vue/compiler-sfc": "^3.0.1",
86 86 "@vue/eslint-config-prettier": "^5.0.0",
87 87 "axios": "^0.21.1",
88   - "bpmn-js": "^7.4.0",
  88 + "bpmn-js": "^8.8.3",
89 89 "bpmn-js-properties-panel": "^0.37.2",
90 90 "camunda-bpmn-moddle": "^4.4.1",
91 91 "compression-webpack-plugin": "^6.1.1",
... ...
yudao-admin-ui/src/api/bpm/definition.js
... ... @@ -8,6 +8,14 @@ export function getProcessDefinitionPage(query) {
8 8 })
9 9 }
10 10  
  11 +export function getProcessDefinitionList(query) {
  12 + return request({
  13 + url: '/bpm/process-definition/list',
  14 + method: 'get',
  15 + params: query
  16 + })
  17 +}
  18 +
11 19 export function getProcessDefinitionBpmnXML(id) {
12 20 return request({
13 21 url: '/bpm/process-definition/get-bpmn-xml?id=' + id,
... ...
yudao-admin-ui/src/api/bpm/processInstance.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function getMyProcessInstancePage(query) {
  4 + return request({
  5 + url: '/bpm/process-instance/my-page',
  6 + method: 'get',
  7 + params: query
  8 + })
  9 +}
  10 +
  11 +export function createProcessInstance(data) {
  12 + return request({
  13 + url: '/bpm/process-instance/create',
  14 + method: 'POST',
  15 + data: data
  16 + })
  17 +}
  18 +
  19 +export function cancelProcessInstance(id, reason) {
  20 + return request({
  21 + url: '/bpm/process-instance/cancel',
  22 + method: 'DELETE',
  23 + data: {
  24 + id,
  25 + reason
  26 + }
  27 + })
  28 +}
... ...
yudao-admin-ui/src/api/bpm/task.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function getTodoTaskPage(query) {
  4 + return request({
  5 + url: '/bpm/task/todo-page',
  6 + method: 'get',
  7 + params: query
  8 + })
  9 +}
  10 +
  11 +export function getDoneTaskPage(query) {
  12 + return request({
  13 + url: '/bpm/task/done-page',
  14 + method: 'get',
  15 + params: query
  16 + })
  17 +}
  18 +
  19 +export function completeTask(data) {
  20 + return request({
  21 + url: '/bpm/task/complete',
  22 + method: 'PUT',
  23 + data: data
  24 + })
  25 +}
  26 +
  27 +export function approveTask(data) {
  28 + return request({
  29 + url: '/bpm/task/approve',
  30 + method: 'PUT',
  31 + data: data
  32 + })
  33 +}
  34 +
  35 +export function rejectTask(data) {
  36 + return request({
  37 + url: '/bpm/task/reject',
  38 + method: 'PUT',
  39 + data: data
  40 + })
  41 +}
... ...
yudao-admin-ui/src/components/bpmnProcessDesigner/package/designer/plugins/palette/index.js
... ... @@ -14,7 +14,6 @@
14 14 // paletteProvider: ["type", PaletteProvider]
15 15 // };
16 16  
17   -// custom/index.js
18 17 import CustomPalette from "./CustomPalette";
19 18  
20 19 export default {
... ...
yudao-admin-ui/src/components/bpmnProcessDesigner/package/penal/base/ElementBaseInfo.vue
1 1 <template>
2 2 <div class="panel-tab__content">
3 3 <el-form size="mini" label-width="90px" :model="model" :rules="rules" @submit.native.prevent>
4   - <el-form-item label="流程标识" prop="key">
5   - <el-input v-model="model.key" placeholder="请输入流标标识"
6   - :disabled="model.id !== undefined && model.id.length > 0" @change="handleKeyUpdate" />
7   - </el-form-item>
8   - <el-form-item label="流程名称" prop="name">
9   - <el-input v-model="model.name" placeholder="请输入流程名称" clearable @change="handleNameUpdate" />
10   - </el-form-item>
11   - <el-form-item label="流程分类" prop="category">
12   - <el-select v-model="model.category" placeholder="请选择流程分类" clearable style="width: 100%">
13   - <el-option v-for="dict in categoryDictDatas" :key="dict.value" :label="dict.label" :value="dict.value"/>
14   - </el-select>
15   - </el-form-item>
16   - <el-form-item label="流程表单" prop="formId">
17   - <el-select v-model="model.formId" placeholder="请选择流程表单,非必选哟!" clearable style="width: 100%">
18   - <el-option v-for="form in forms" :key="form.id" :label="form.name" :value="form.id"/>
19   - </el-select>
20   - </el-form-item>
21   - <el-form-item label="流程描述" prop="description">
22   - <el-input type="textarea" v-model="model.description" clearable @change="handleDescriptionUpdate" />
23   - </el-form-item>
  4 + <div v-if="elementBaseInfo.$type === 'bpmn:Process'"> <!-- 如果是 Process 信息的时候,使用自定义表单 -->
  5 + <el-form-item label="流程标识" prop="key">
  6 + <el-input v-model="model.key" placeholder="请输入流标标识"
  7 + :disabled="model.id !== undefined && model.id.length > 0" @change="handleKeyUpdate" />
  8 + </el-form-item>
  9 + <el-form-item label="流程名称" prop="name">
  10 + <el-input v-model="model.name" placeholder="请输入流程名称" clearable @change="handleNameUpdate" />
  11 + </el-form-item>
  12 + <el-form-item label="流程分类" prop="category">
  13 + <el-select v-model="model.category" placeholder="请选择流程分类" clearable style="width: 100%">
  14 + <el-option v-for="dict in categoryDictDatas" :key="dict.value" :label="dict.label" :value="dict.value"/>
  15 + </el-select>
  16 + </el-form-item>
  17 + <el-form-item label="流程表单" prop="formId">
  18 + <el-select v-model="model.formId" placeholder="请选择流程表单,非必选哟!" clearable style="width: 100%">
  19 + <el-option v-for="form in forms" :key="form.id" :label="form.name" :value="form.id"/>
  20 + </el-select>
  21 + </el-form-item>
  22 + <el-form-item label="流程描述" prop="description">
  23 + <el-input type="textarea" v-model="model.description" clearable @change="handleDescriptionUpdate" />
  24 + </el-form-item>
  25 + </div>
  26 + <div v-else>
  27 + <el-form-item label="ID">
  28 + <el-input v-model="elementBaseInfo.id" clearable @change="updateBaseInfo('id')"/>
  29 + </el-form-item>
  30 + <el-form-item label="名称">
  31 + <el-input v-model="elementBaseInfo.name" clearable @change="updateBaseInfo('name')" />
  32 + </el-form-item>
  33 + </div>
24 34 </el-form>
25 35 </div>
26 36 </template>
... ...
yudao-admin-ui/src/components/parser/Parser.vue
... ... @@ -173,8 +173,13 @@ export default {
173 173 submitForm() {
174 174 this.$refs[this.formConf.formRef].validate(valid => {
175 175 if (!valid) return false
176   - // 触发sumit事件
177   - this.$emit('submit', this[this.formConf.formModel])
  176 + // 触发 submit 事件
  177 + // update by 芋道源码
  178 + // this.$emit('submit', this[this.formConf.formModel])
  179 + this.$emit('submit', {
  180 + conf: this.formConfCopy,
  181 + values: this[this.formConf.formModel]
  182 + })
178 183 return true
179 184 })
180 185 }
... ...
yudao-admin-ui/src/router/index.js
... ... @@ -188,6 +188,18 @@ export const constantRoutes = [
188 188 meta: { title: '流程定义' }
189 189 }
190 190 ]
  191 + }, {
  192 + path: '/bpm',
  193 + component: Layout,
  194 + hidden: true,
  195 + children: [
  196 + {
  197 + path: 'process-instance/create',
  198 + component: (resolve) => require(['@/views/bpm/processInstance/create'], resolve),
  199 + name: '发起流程',
  200 + meta: { title: '发起流程' }
  201 + }
  202 + ]
191 203 },
192 204 ]
193 205  
... ...
yudao-admin-ui/src/utils/dateUtils.js 0 → 100644
  1 +/**
  2 + * 将毫秒,转换成时间字符串。例如说,xx 分钟
  3 + *
  4 + * @param ms 毫秒
  5 + * @returns {string} 字符串
  6 + */
  7 +export function getDate(ms) {
  8 + const day = Math.floor(ms / (24 * 60 * 60 * 1000));
  9 + const hour = Math.floor((ms / (60 * 60 * 1000) - day * 24));
  10 + const minute = Math.floor(((ms / (60 * 1000)) - day * 24 * 60 - hour * 60));
  11 + const second = Math.floor((ms / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60));
  12 + if (day > 0) {
  13 + return day + "天" + hour + "小时" + minute + "分钟";
  14 + }
  15 + if (hour > 0) {
  16 + return hour + "小时" + minute + "分钟";
  17 + }
  18 + if (minute > 0) {
  19 + return minute + "分钟";
  20 + }
  21 + if (second > 0) {
  22 + return second + "秒";
  23 + } else {
  24 + return 0 + "秒";
  25 + }
  26 +}
... ...
yudao-admin-ui/src/utils/dict.js
... ... @@ -36,6 +36,8 @@ export const DICT_TYPE = {
36 36  
37 37 // bpm
38 38 BPM_MODEL_CATEGORY: 'bpm_model_category',
  39 + BPM_PROCESS_INSTANCE_STATUS: 'bpm_process_instance_status',
  40 + BPM_PROCESS_INSTANCE_RESULT: 'bpm_process_instance_result',
39 41 OA_LEAVE_STATUS: 'flow_status',
40 42 OA_LEAVE_TYPE: 'oa_leave_type'
41 43 }
... ...
yudao-admin-ui/src/views/bpm/definition/index.vue
... ... @@ -29,7 +29,7 @@
29 29 <el-tag size="medium" type="warning" v-else>未部署</el-tag>
30 30 </template>
31 31 </el-table-column>
32   - <el-table-column label="激活状态" align="center" prop="version" width="80">
  32 + <el-table-column label="状态" align="center" prop="version" width="80">
33 33 <template slot-scope="scope">
34 34 <el-tag type="success" v-if="scope.row.suspensionState === 1">激活</el-tag>
35 35 <el-tag type="warning" v-if="scope.row.suspensionState === 2">挂起</el-tag>
... ...
yudao-admin-ui/src/views/bpm/model/modelEditor.vue
... ... @@ -175,17 +175,8 @@ export default {
175 175  
176 176 .my-process-designer {
177 177 height: calc(100vh - 84px);
178   - //height: 800px !important; // TODO 芋艿:bjs 容器的高度不对,临时改下
179   - //z-index: 0 !important;
180   - //pointer-events: none !important;
181 178 }
182   -.process-panel__container { // TODO 芋艿:右边的位置不对,临时改下
183   - //margin-top: -800px !important;
184   - //float: right;
185   - //margin-left: 800px !important;
186   - //height: 800px;
187   - //z-index: 2147483647 !important;
188   - //cursor:pointer !important;
  179 +.process-panel__container {
189 180 position: absolute;
190 181 right: 0;
191 182 top: 55px;
... ...
yudao-admin-ui/src/views/bpm/processInstance/create.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 + <!-- 第一步,通过流程定义的列表,选择对应的流程 -->
  4 + <div v-if="!selectProcessInstance">
  5 + <el-table v-loading="loading" :data="list">
  6 + <el-table-column label="流程名称" align="center" prop="name" width="200">
  7 + <template slot-scope="scope">
  8 + <el-button type="text" @click="handleBpmnDetail(scope.row)">
  9 + <span>{{ scope.row.name }}</span>
  10 + </el-button>
  11 + </template>
  12 + </el-table-column>
  13 + <el-table-column label="流程分类" align="center" prop="category" width="100">
  14 + <template slot-scope="scope">
  15 + <span>{{ getDictDataLabel(DICT_TYPE.BPM_MODEL_CATEGORY, scope.row.category) }}</span>
  16 + </template>
  17 + </el-table-column>
  18 + <el-table-column label="流程版本" align="center" prop="processDefinition.version" width="80">
  19 + <template slot-scope="scope">
  20 + <el-tag size="medium" v-if="scope.row">v{{ scope.row.version }}</el-tag>
  21 + </template>
  22 + </el-table-column>
  23 + <el-table-column label="流程描述" align="center" prop="description" width="300" show-overflow-tooltip />
  24 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  25 + <template slot-scope="scope">
  26 + <el-button type="text" size="small" icon="el-icon-plus" @click="handleSelect(scope.row)">选择</el-button>
  27 + </template>
  28 + </el-table-column>
  29 + </el-table>
  30 + </div>
  31 + <!-- 第二步,填写表单,进行流程的提交 -->
  32 + <div v-else>
  33 + <el-card class="box-card" >
  34 + <div slot="header" class="clearfix">
  35 + <span class="el-icon-document">{{ selectProcessInstance.name }}</span>
  36 + <el-button style="float: right;" type="primary" @click="selectProcessInstance = undefined">选择其它流程</el-button>
  37 + </div>
  38 + <el-col :span="16" :offset="6">
  39 + <div>
  40 + <parser :key="new Date().getTime()" :form-conf="detailForm" @submit="submitForm" />
  41 + </div>
  42 + </el-col>
  43 + </el-card>
  44 + <el-card class="box-card">
  45 + <div slot="header" class="clearfix">
  46 + <span class="el-icon-picture-outline">流程图</span>
  47 + </div>
  48 + <my-process-viewer key="designer" v-model="bpmnXML" v-bind="bpmnControlForm" />
  49 + </el-card>
  50 + </div>
  51 +
  52 + </div>
  53 +</template>
  54 +
  55 +<script>
  56 +import {getProcessDefinitionBpmnXML, getProcessDefinitionList} from "@/api/bpm/definition";
  57 +import {DICT_TYPE, getDictDatas} from "@/utils/dict";
  58 +import {getForm} from "@/api/bpm/form";
  59 +import {decodeFields} from "@/utils/formGenerator";
  60 +import Parser from '@/components/parser/Parser'
  61 +import {createProcessInstance} from "@/api/bpm/processInstance";
  62 +
  63 +export default {
  64 + name: "processDefinition",
  65 + components: {
  66 + Parser
  67 + },
  68 + data() {
  69 + return {
  70 + // 遮罩层
  71 + loading: true,
  72 + // 总条数
  73 + total: 0,
  74 + // 表格数据
  75 + list: [],
  76 +
  77 + // 流程表单详情
  78 + detailForm: {
  79 + fields: []
  80 + },
  81 +
  82 + // BPMN 数据
  83 + bpmnXML: null,
  84 + bpmnControlForm: {
  85 + prefix: "activiti"
  86 + },
  87 +
  88 + // 流程表单
  89 + selectProcessInstance: undefined, // 选择的流程实例
  90 +
  91 + // 数据字典
  92 + categoryDictDatas: getDictDatas(DICT_TYPE.BPM_MODEL_CATEGORY),
  93 + };
  94 + },
  95 + created() {
  96 + this.getList();
  97 + },
  98 + methods: {
  99 + /** 查询流程定义列表 */
  100 + getList() {
  101 + this.loading = true;
  102 + getProcessDefinitionList({
  103 + suspensionState: 1
  104 + }).then(response => {
  105 + this.list = response.data
  106 + this.loading = false
  107 + }
  108 + );
  109 + },
  110 + /** 处理选择流程的按钮操作 **/
  111 + handleSelect(row) {
  112 + // 如果无表单,则无法发起流程
  113 + if (!row.formId) {
  114 + this.$message.error('该流程未绑定表单,无法发起流程!请重新选择你要发起的流程');
  115 + return;
  116 + }
  117 + // 设置选择的流程
  118 + this.selectProcessInstance = row;
  119 +
  120 + // 加载对应的表单
  121 + getForm(row.formId).then(response => {
  122 + // 设置值
  123 + const data = response.data
  124 + this.detailForm = {
  125 + ...JSON.parse(data.conf),
  126 + fields: decodeFields(data.fields)
  127 + }
  128 + });
  129 +
  130 + // 加载流程图
  131 + getProcessDefinitionBpmnXML(row.id).then(response => {
  132 + this.bpmnXML = response.data
  133 + })
  134 + },
  135 + /** 提交按钮 */
  136 + submitForm(params) {
  137 + if (!params) {
  138 + return;
  139 + }
  140 + // 设置表单禁用
  141 + const conf = params.conf;
  142 + conf.disabled = true; // 表单禁用
  143 + conf.formBtns = false; // 按钮隐藏
  144 +
  145 + // 提交表单,创建流程
  146 + const variables = params.values;
  147 + createProcessInstance({
  148 + processDefinitionId: this.selectProcessInstance.id,
  149 + variables: variables
  150 + }).then(response => {
  151 + this.msgSuccess("发起流程成功");
  152 + // 关闭当前窗口
  153 + this.$store.dispatch("tagsView/delView", this.$route);
  154 + this.$router.go(-1);
  155 + }).catch(() => {
  156 + conf.disabled = false; // 表单开启
  157 + conf.formBtns = true; // 按钮展示
  158 + })
  159 + },
  160 + }
  161 +};
  162 +</script>
  163 +
  164 +<style lang="scss">
  165 +.my-process-designer {
  166 + height: calc(100vh - 200px);
  167 +}
  168 +
  169 +.box-card {
  170 + width: 100%;
  171 + margin-bottom: 20px;
  172 +}
  173 +</style>
... ...
yudao-admin-ui/src/views/bpm/processInstance/index.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 +
  4 + <!-- 搜索工作栏 -->
  5 + <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
  6 + <el-form-item label="流程名" prop="name">
  7 + <el-input v-model="queryParams.name" placeholder="请输入流程名" clearable size="small" @keyup.enter.native="handleQuery"/>
  8 + </el-form-item>
  9 + <el-form-item label="所属流程" prop="processDefinitionId">
  10 + <el-input v-model="queryParams.processDefinitionId" placeholder="请输入流程定义的编号" clearable size="small" @keyup.enter.native="handleQuery"/>
  11 + </el-form-item>
  12 + <el-form-item label="流程分类" prop="category">
  13 + <el-select v-model="queryParams.category" placeholder="请选择流程分类" clearable size="small">
  14 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.BPM_MODEL_CATEGORY)"
  15 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  16 + </el-select>
  17 + </el-form-item>
  18 + <el-form-item label="提交时间">
  19 + <el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
  20 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
  21 + </el-form-item>
  22 + <el-form-item label="状态" prop="status">
  23 + <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
  24 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS)"
  25 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  26 + </el-select>
  27 + </el-form-item>
  28 + <el-form-item label="结果" prop="result">
  29 + <el-select v-model="queryParams.result" placeholder="请选择流结果" clearable size="small">
  30 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT)"
  31 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  32 + </el-select>
  33 + </el-form-item>
  34 + <el-form-item>
  35 + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  36 + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  37 + </el-form-item>
  38 + </el-form>
  39 +
  40 + <!-- 操作工具栏 -->
  41 + <el-row :gutter="10" class="mb8">
  42 + <el-col :span="1.5">
  43 + <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">发起流程</el-button>
  44 + </el-col>
  45 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  46 + </el-row>
  47 +
  48 + <!-- 列表 -->
  49 + <el-table v-loading="loading" :data="list">
  50 + <el-table-column label="编号" align="center" prop="id" width="320" />
  51 + <el-table-column label="流程名" align="center" prop="name" />
  52 + <el-table-column label="流程分类" align="center" prop="category">
  53 + <template slot-scope="scope">
  54 + <span>{{ getDictDataLabel(DICT_TYPE.BPM_MODEL_CATEGORY, scope.row.category) }}</span>
  55 + </template>
  56 + </el-table-column>
  57 + <el-table-column label="当前审批任务" align="center" prop="tasks">
  58 + <template slot-scope="scope">
  59 + <el-button v-for="task in scope.row.tasks" type="text" @click="handleFormDetail(task.id)">
  60 + <span>{{ task.name }}</span>
  61 + </el-button>
  62 + </template>
  63 + </el-table-column>
  64 + <el-table-column label="状态" align="center" prop="status">
  65 + <template slot-scope="scope">
  66 + <span>
  67 + <el-tag type="primary" v-if="scope.row.status === 1"> <!-- 进行中 -->
  68 + {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS, scope.row.status) }}
  69 + </el-tag>
  70 + <el-tag type="success" v-if="scope.row.status === 2"> <!-- 已结束 -->
  71 + {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS, scope.row.status) }}
  72 + </el-tag>
  73 + </span>
  74 + </template>
  75 + </el-table-column>
  76 + <el-table-column label="结果" align="center" prop="result">
  77 + <template slot-scope="scope">
  78 + <span>
  79 + <el-tag type="primary" v-if="scope.row.result === 1"> <!-- 进行中 -->
  80 + {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
  81 + </el-tag>
  82 + <el-tag type="success" v-if="scope.row.result === 2"> <!-- 通过 -->
  83 + {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
  84 + </el-tag>
  85 + <el-tag type="danger" v-if="scope.row.result === 3"> <!-- 不通过 -->
  86 + {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
  87 + </el-tag>
  88 + <el-tag type="info" v-if="scope.row.result === 4"> <!-- 撤回 -->
  89 + {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
  90 + </el-tag>
  91 + </span>
  92 + </template>
  93 + </el-table-column>
  94 + <el-table-column label="提交时间" align="center" prop="createTime" width="180">
  95 + <template slot-scope="scope">
  96 + <span>{{ parseTime(scope.row.createTime) }}</span>
  97 + </template>
  98 + </el-table-column>
  99 + <el-table-column label="结束时间" align="center" prop="createTime" width="180">
  100 + <template slot-scope="scope">
  101 + <span>{{ parseTime(scope.row.endTime) }}</span>
  102 + </template>
  103 + </el-table-column>
  104 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  105 + <template slot-scope="scope">
  106 + <!-- TODO 芋艿:权限 -->
  107 + <el-button type="text" size="small" icon="el-icon-delete" v-if="scope.row.result === 1"
  108 + @click="handleCancel(scope.row)">取消</el-button>
  109 + </template>
  110 + </el-table-column>
  111 + </el-table>
  112 + <!-- 分页组件 -->
  113 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  114 + @pagination="getList"/>
  115 +
  116 + </div>
  117 +</template>
  118 +
  119 +<script>
  120 +import {
  121 + getMyProcessInstancePage,
  122 + createProcessInstanceExt,
  123 + updateProcessInstanceExt,
  124 + deleteProcessInstanceExt,
  125 + getProcessInstanceExt,
  126 + getProcessInstanceExtPage,
  127 + exportProcessInstanceExtExcel, cancelProcessInstance
  128 +} from "@/api/bpm/processInstance";
  129 +import {deleteErrorCode} from "@/api/system/errorCode";
  130 +
  131 +export default {
  132 + name: "ProcessInstanceExt",
  133 + components: {
  134 + },
  135 + data() {
  136 + return {
  137 + // 遮罩层
  138 + loading: true,
  139 + // 显示搜索条件
  140 + showSearch: true,
  141 + // 总条数
  142 + total: 0,
  143 + // 工作流的流程实例的拓展列表
  144 + list: [],
  145 + // 是否显示弹出层
  146 + dateRangeCreateTime: [],
  147 + // 查询参数
  148 + queryParams: {
  149 + pageNo: 1,
  150 + pageSize: 10,
  151 + name: null,
  152 + processDefinitionId: null,
  153 + category: null,
  154 + status: null,
  155 + result: null,
  156 + }
  157 + };
  158 + },
  159 + created() {
  160 + this.getList();
  161 + },
  162 + methods: {
  163 + /** 查询列表 */
  164 + getList() {
  165 + this.loading = true;
  166 + // 处理查询参数
  167 + let params = {...this.queryParams};
  168 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  169 + // 执行查询
  170 + getMyProcessInstancePage(params).then(response => {
  171 + this.list = response.data.list;
  172 + this.total = response.data.total;
  173 + this.loading = false;
  174 + });
  175 + },
  176 + /** 搜索按钮操作 */
  177 + handleQuery() {
  178 + this.queryParams.pageNo = 1;
  179 + this.getList();
  180 + },
  181 + /** 重置按钮操作 */
  182 + resetQuery() {
  183 + this.dateRangeCreateTime = [];
  184 + this.resetForm("queryForm");
  185 + this.handleQuery();
  186 + },
  187 + /** 新增按钮操作 **/
  188 + handleAdd() {
  189 + this.$router.push({ path: "/bpm/process-instance/create"})
  190 + },
  191 + /** 取消按钮操作 */
  192 + handleCancel(row) {
  193 + const id = row.id;
  194 + this.$prompt('请输出取消原因?', "取消流程", {
  195 + type: 'warning',
  196 + confirmButtonText: "确定",
  197 + cancelButtonText: "取消",
  198 + inputPattern: /^[\s\S]*.*[^\s][\s\S]*$/, // 判断非空,且非空格
  199 + inputErrorMessage: "取消原因不能为空",
  200 + }).then(({ value }) => {
  201 + return cancelProcessInstance(id, value);
  202 + }).then(() => {
  203 + this.getList();
  204 + this.msgSuccess("取消成功");
  205 + })
  206 + },
  207 + }
  208 +};
  209 +</script>
... ...
yudao-admin-ui/src/views/bpm/task/done.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 +
  4 + <!-- 搜索工作栏 -->
  5 + <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
  6 + <el-form-item label="流程名" prop="name">
  7 + <el-input v-model="queryParams.name" placeholder="请输入流程名" clearable size="small" @keyup.enter.native="handleQuery"/>
  8 + </el-form-item>
  9 + <el-form-item label="创建时间">
  10 + <el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
  11 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
  12 + </el-form-item>
  13 + <el-form-item>
  14 + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  15 + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  16 + </el-form-item>
  17 + </el-form>
  18 +
  19 + <!-- 列表 -->
  20 + <el-table v-loading="loading" :data="list">
  21 + <el-table-column label="任务编号" align="center" prop="id" width="320" fixed />
  22 + <el-table-column label="任务名称" align="center" prop="name" width="200" />
  23 + <el-table-column label="所属流程" align="center" prop="processInstance.name" width="200" />
  24 + <el-table-column label="流程发起人" align="center" prop="processInstance.startUserNickname" />
  25 + <el-table-column label="结果" align="center" prop="result">
  26 + <template slot-scope="scope">
  27 + <span>
  28 + <el-tag type="primary" v-if="scope.row.result === 1"> <!-- 进行中 -->
  29 + {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
  30 + </el-tag>
  31 + <el-tag type="success" v-if="scope.row.result === 2"> <!-- 通过 -->
  32 + {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
  33 + </el-tag>
  34 + <el-tag type="danger" v-if="scope.row.result === 3"> <!-- 不通过 -->
  35 + {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
  36 + </el-tag>
  37 + <el-tag type="info" v-if="scope.row.result === 4"> <!-- 撤回 -->
  38 + {{ getDictDataLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT, scope.row.result) }}
  39 + </el-tag>
  40 + </span>
  41 + </template>
  42 + </el-table-column>
  43 + <el-table-column label="审批意见" align="center" prop="comment" width="200" />
  44 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  45 + <template slot-scope="scope">
  46 + <span>{{ parseTime(scope.row.createTime) }}</span>
  47 + </template>
  48 + </el-table-column>
  49 + <el-table-column label="审批时间" align="center" prop="endTime" width="180">
  50 + <template slot-scope="scope">
  51 + <span>{{ parseTime(scope.row.endTime) }}</span>
  52 + </template>
  53 + </el-table-column>
  54 + <el-table-column label="耗时" align="center" prop="durationInMillis" width="180">
  55 + <template slot-scope="scope">
  56 + <span>{{ getDateStar(scope.row.durationInMillis) }}</span>
  57 + </template>
  58 + </el-table-column>
  59 + <!-- TODO 耗时 -->
  60 + <el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
  61 + <template slot-scope="scope">
  62 + <!-- TODO 权限、颜色 -->
  63 + <el-button size="mini" type="text" icon="el-icon-edit">详情</el-button>
  64 + </template>
  65 + </el-table-column>
  66 + </el-table>
  67 + <!-- 分页组件 -->
  68 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  69 + @pagination="getList"/>
  70 +
  71 + </div>
  72 +</template>
  73 +
  74 +<script>
  75 +import {getDoneTaskPage} from '@/api/bpm/task'
  76 +import {getDate} from "@/utils/dateUtils";
  77 +
  78 +export default {
  79 + name: "Done",
  80 + components: {
  81 + },
  82 + data() {
  83 + return {
  84 + // 遮罩层
  85 + loading: true,
  86 + // 显示搜索条件
  87 + showSearch: true,
  88 + // 总条数
  89 + total: 0,
  90 + // 待办任务列表
  91 + list: [],
  92 + // 查询参数
  93 + dateRangeCreateTime: [],
  94 + queryParams: {
  95 + pageNo: 1,
  96 + pageSize: 10,
  97 + name: null,
  98 + },
  99 + };
  100 + },
  101 + created() {
  102 + this.getList();
  103 + },
  104 + methods: {
  105 + /** 查询列表 */
  106 + getList() {
  107 + this.loading = true;
  108 + // 处理查询参数
  109 + let params = {...this.queryParams};
  110 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  111 + getDoneTaskPage(params).then(response => {
  112 + this.list = response.data.list;
  113 + this.total = response.data.total;
  114 + this.loading = false;
  115 + });
  116 + },
  117 + /** 搜索按钮操作 */
  118 + handleQuery() {
  119 + this.queryParams.pageNo = 1;
  120 + this.getList();
  121 + },
  122 + /** 重置按钮操作 */
  123 + resetQuery() {
  124 + this.dateRangeCreateTime = [];
  125 + this.resetForm("queryForm");
  126 + this.handleQuery();
  127 + },
  128 + getDateStar(ms) {
  129 + return getDate(ms);
  130 + }
  131 + }
  132 +};
  133 +</script>
... ...
yudao-admin-ui/src/views/bpm/task/todo.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 +
  4 + <!-- 搜索工作栏 -->
  5 + <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
  6 + <el-form-item label="流程名" prop="name">
  7 + <el-input v-model="queryParams.name" placeholder="请输入流程名" clearable size="small" @keyup.enter.native="handleQuery"/>
  8 + </el-form-item>
  9 + <el-form-item label="创建时间">
  10 + <el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
  11 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
  12 + </el-form-item>
  13 + <el-form-item>
  14 + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  15 + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  16 + </el-form-item>
  17 + </el-form>
  18 +
  19 + <!-- 列表 -->
  20 + <el-table v-loading="loading" :data="list">
  21 + <el-table-column label="任务编号" align="center" prop="id" width="320" />
  22 + <el-table-column label="任务名称" align="center" prop="name" />
  23 + <el-table-column label="所属流程" align="center" prop="processInstance.name" />
  24 + <el-table-column label="流程发起人" align="center" prop="processInstance.startUserNickname" />
  25 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  26 + <template slot-scope="scope">
  27 + <span>{{ parseTime(scope.row.createTime) }}</span>
  28 + </template>
  29 + </el-table-column>
  30 + <el-table-column label="状态" align="center" prop="version" width="80">
  31 + <template slot-scope="scope">
  32 + <el-tag type="success" v-if="scope.row.suspensionState === 1">激活</el-tag>
  33 + <el-tag type="warning" v-if="scope.row.suspensionState === 2">挂起</el-tag>
  34 + </template>
  35 + </el-table-column>
  36 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  37 + <template slot-scope="scope">
  38 + <!-- TODO 权限、颜色 -->
  39 + <el-button size="mini" type="text" icon="el-icon-edit">审批</el-button>
  40 + <el-button size="mini" type="text" icon="el-icon-edit" @click="audit(scope.row, true)">通过</el-button>
  41 + <el-button size="mini" type="text" icon="el-icon-edit" @click="audit(scope.row, false)">不通过</el-button>
  42 + <el-button size="mini" type="text" icon="el-icon-edit" v-if="scope.row.suspensionState === 2">激活</el-button>
  43 + <el-button size="mini" type="text" icon="el-icon-edit" v-if="scope.row.suspensionState === 1">挂起</el-button>
  44 + </template>
  45 + </el-table-column>
  46 + </el-table>
  47 + <!-- 分页组件 -->
  48 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  49 + @pagination="getList"/>
  50 +
  51 + </div>
  52 +</template>
  53 +
  54 +<script>
  55 +import {approveTask, getTodoTaskPage, rejectTask} from '@/api/bpm/task'
  56 +
  57 +export default {
  58 + name: "Todo",
  59 + components: {
  60 + },
  61 + data() {
  62 + return {
  63 + // 遮罩层
  64 + loading: true,
  65 + // 显示搜索条件
  66 + showSearch: true,
  67 + // 总条数
  68 + total: 0,
  69 + // 待办任务列表
  70 + list: [],
  71 + // 查询参数
  72 + dateRangeCreateTime: [],
  73 + queryParams: {
  74 + pageNo: 1,
  75 + pageSize: 10,
  76 + name: null,
  77 + },
  78 + };
  79 + },
  80 + created() {
  81 + this.getList();
  82 + },
  83 + methods: {
  84 + /** 查询列表 */
  85 + getList() {
  86 + this.loading = true;
  87 + // 处理查询参数
  88 + let params = {...this.queryParams};
  89 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  90 + getTodoTaskPage(params).then(response => {
  91 + this.list = response.data.list;
  92 + this.total = response.data.total;
  93 + this.loading = false;
  94 + });
  95 + },
  96 + /** 搜索按钮操作 */
  97 + handleQuery() {
  98 + this.queryParams.pageNo = 1;
  99 + this.getList();
  100 + },
  101 + /** 重置按钮操作 */
  102 + resetQuery() {
  103 + this.dateRangeCreateTime = [];
  104 + this.resetForm("queryForm");
  105 + this.handleQuery();
  106 + },
  107 + audit(row, pass) {
  108 + if (pass) {
  109 + approveTask({
  110 + id: row.id,
  111 + comment: '通过'
  112 + })
  113 + } else {
  114 + rejectTask({
  115 + id: row.id,
  116 + comment: '不通过'
  117 + })
  118 + }
  119 + }
  120 + }
  121 +};
  122 +</script>
... ...
yudao-admin-ui/src/views/oa/todo/index.vue deleted
1   -<template>
2   - <div class="app-container">
3   -
4   - <!-- 搜索工作栏 -->
5   - <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
6   - <el-form-item label="状态" prop="status">
7   - <el-select v-model="queryParams.status" placeholder="请选择状态">
8   - <el-option
9   - v-for="dict in leaveStatusData"
10   - :key="parseInt(dict.value)"
11   - :label="dict.label"
12   - :value="parseInt(dict.value)"
13   - />
14   - </el-select>
15   - </el-form-item>
16   - <el-form-item>
17   - <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
18   - <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
19   - </el-form-item>
20   - </el-form>
21   -
22   -
23   -
24   - <!-- 列表 -->
25   - <el-table v-loading="loading" :data="list">
26   - <el-table-column label="任务Id" align="center" prop="id" />
27   - <el-table-column label="流程名称" align="center" prop="processName" />
28   - <el-table-column label="任务状态" align="center" :formatter="statusFormat" prop="status" />
29   - <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
30   - <template slot-scope="scope">
31   - <el-button size="mini" type="text" icon="el-icon-edit" v-if="scope.row.status == 1" @click="handleClaim(scope.row)">签收</el-button>
32   - <el-button size="mini" type="text" icon="el-icon-edit" v-if="scope.row.status == 2" @click="getTaskFormKey(scope.row)">办理</el-button>
33   - </template>
34   - </el-table-column>
35   - </el-table>
36   - <!-- 分页组件 -->
37   - <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
38   - @pagination="getList"/>
39   -
40   - <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
41   - <el-tabs tab-position="left" style="height: 500px;">
42   - <el-tab-pane label="详情">
43   - <el-form ref="form" :model="handleTask.formObject" label-width="80px">
44   - <el-form-item label="状态" >
45   - {{ getDictDataLabel(DICT_TYPE.OA_LEAVE_STATUS, handleTask.formObject.status) }}
46   - </el-form-item>
47   - <el-form-item label="申请人id" >{{handleTask.formObject.userId}}</el-form-item>
48   - <el-form-item label="开始时间" >{{ parseTime(handleTask.formObject.startTime) }}</el-form-item>
49   - <el-form-item label="结束时间" prop="endTime">{{ parseTime(handleTask.formObject.endTime) }}</el-form-item>
50   - <el-form-item label="请假类型" prop="leaveType">
51   - {{ getDictDataLabel(DICT_TYPE.OA_LEAVE_TYPE, handleTask.formObject.leaveType) }}
52   - </el-form-item>
53   - <el-form-item label="原因" prop="reason">{{handleTask.formObject.reason}}</el-form-item>
54   - <el-form-item label="申请时间" prop="applyTime">{{ parseTime(handleTask.formObject.applyTime) }}</el-form-item>
55   - </el-form>
56   - </el-tab-pane>
57   - <el-tab-pane label="任务处理">
58   - <el-steps :active="handleTask.historyTask.length-1" simple finish-status="success">
59   - <el-step :title="item.stepName" icon="el-icon-edit" v-for="(item) in handleTask.historyTask" ></el-step>
60   - </el-steps>
61   - <br/>
62   - <el-steps direction="vertical" :active="handleTask.historyTask.length-1" finish-status="success" space="60px">
63   - <el-step :title="item.stepName" :description="item.comment" v-for="(item) in handleTask.historyTask" ></el-step>
64   - </el-steps>
65   - <br/>
66   - <el-form ref="taskForm" :model="task" label-width="80px" v-show="handleTask.taskVariable !=''">
67   - <el-form-item label="处理意见" prop="approved">
68   - <el-select v-model="task.approved" placeholder="处理意见">
69   - <el-option
70   - v-for="dict in approvedData"
71   - :key="parseInt(dict.value)"
72   - :label="dict.label"
73   - :value="parseInt(dict.value)"
74   - />
75   - </el-select>
76   - </el-form-item>
77   - <el-input
78   - type="textarea"
79   - :rows="2"
80   - v-model="task.comment">
81   - </el-input>
82   - </el-form>
83   - <br/>
84   - <el-button type="primary" @click="submitTask">提交</el-button>
85   - </el-tab-pane>
86   - </el-tabs>
87   - </el-dialog>
88   - </div>
89   -</template>
90   -
91   -<script>
92   -import { completeTask, taskSteps, getTaskFormKey,deleteLeave, getLeave, getTodoTaskPage, claimTask } from "@/api/oa/todo";
93   -import { getDictDataLabel, getDictDatas, DICT_TYPE } from '@/utils/dict'
94   -export default {
95   - name: "Todo",
96   - components: {
97   - },
98   - data() {
99   - return {
100   - // 遮罩层
101   - loading: true,
102   - // 显示搜索条件
103   - showSearch: true,
104   - // 总条数
105   - total: 0,
106   - // 请假申请列表
107   - list: [],
108   - // 弹出层标题
109   - title: "",
110   - // 是否显示弹出层
111   - open: false,
112   - // 查询参数
113   - queryParams: {
114   - pageNo: 1,
115   - pageSize: 10
116   - },
117   - // 表单参数
118   - form: {},
119   - handleTask: {
120   - historyTask:[{
121   - stepName:"步骤一"
122   - }
123   - ],
124   - taskVariable: "",
125   - formObject: {}
126   - },
127   - steps:[{
128   - stepName:"步骤一"
129   - }],
130   - task: {
131   - approved : 1,
132   - variables: {},
133   - taskId: undefined,
134   - comment: ""
135   - },
136   - rules: {
137   - },
138   - leaveTypeDictData: getDictDatas(DICT_TYPE.OA_LEAVE_TYPE),
139   - leaveStatusData: getDictDatas(DICT_TYPE.OA_LEAVE_STATUS),
140   - approvedData: [
141   - {
142   - value: 1,
143   - label: '同意'
144   - },
145   - {
146   - value: 0,
147   - label: '不同意'
148   - }
149   - ]
150   - };
151   - },
152   - created() {
153   - this.getList();
154   - },
155   - methods: {
156   - /** 查询列表 */
157   - getList() {
158   - this.loading = true;
159   - // 处理查询参数
160   - let params = {...this.queryParams};
161   - // 执行查询
162   - getTodoTaskPage(params).then(response => {
163   - this.list = response.data.list;
164   - this.total = response.data.total;
165   - this.loading = false;
166   - });
167   - },
168   - /** 取消按钮 */
169   - cancel() {
170   - this.open = false;
171   - this.reset();
172   - },
173   - /** 表单重置 */
174   - reset() {
175   - this.form = {
176   - id: undefined,
177   - processInstanceId: undefined,
178   - status: undefined,
179   - userId: undefined,
180   - startTime: undefined,
181   - endTime: undefined,
182   - leaveType: undefined,
183   - reason: undefined,
184   - applyTime: undefined,
185   - };
186   - this.resetForm("form");
187   - },
188   -
189   - statusFormat(row, column) {
190   - return row.status == 1 ? "未签收" : "已签收";
191   - },
192   - /** 搜索按钮操作 */
193   - handleQuery() {
194   - this.queryParams.pageNo = 1;
195   - this.getList();
196   - },
197   - /** 重置按钮操作 */
198   - resetQuery() {
199   - this.dateRangeStartTime = [];
200   - this.dateRangeEndTime = [];
201   - this.dateRangeApplyTime = [];
202   - this.resetForm("queryForm");
203   - this.handleQuery();
204   - },
205   - getTaskFormKey(row) {
206   - const taskId = row.id;
207   - const data = {
208   - taskId : taskId
209   - }
210   - getTaskFormKey(data).then(response => {
211   - const resp = response.data;
212   - const path = resp.formKey;
213   - const taskId = resp.id;
214   - const businessKey = resp.businessKey;
215   - const route = {
216   - path: path,
217   - query: {
218   - businessKey: businessKey,
219   - taskId:taskId,
220   - processInstanceId : resp.processInstanceId
221   - }
222   - }
223   - this.$router.replace(route);
224   - });
225   - },
226   - handleLeaveApprove(row) {
227   - this.reset();
228   - const businessKey = row.businessKey;
229   - const taskId = row.id;
230   - const processKey = row.processKey;
231   - const data = {
232   - taskId : taskId,
233   - businessKey: businessKey,
234   - processKey: processKey
235   - }
236   - taskSteps(data).then(response => {
237   - this.form = {};
238   - this.handleTask = response.data;
239   - this.task.taskId = taskId;
240   - this.open = true;
241   - this.title = "任务办理";
242   - });
243   - },
244   - /** 任务签收操作 */
245   - handleClaim(row) {
246   - this.reset();
247   - const id = row.id;
248   - claimTask(id).then(() => {
249   - this.getList();
250   - this.msgSuccess("签收成功");
251   - });
252   - },
253   - /** 提交任务 */
254   - submitTask() {
255   - const taskVariableName = this.handleTask.taskVariable;
256   - if (taskVariableName != "") {
257   - if (this.task.approved == 1) {
258   - this.task.variables[taskVariableName] = true;
259   - }
260   - if (this.task.approved == 0) {
261   - this.task.variables[taskVariableName] = false;
262   - }
263   - }
264   - completeTask(this.task).then(response => {
265   - this.msgSuccess("执行任务成功");
266   - this.open = false;
267   - this.getList();
268   - })
269   - },
270   - /** 删除按钮操作 */
271   - handleDelete(row) {
272   - const id = row.id;
273   - this.$confirm('是否确认删除请假申请编号为"' + id + '"的数据项?', "警告", {
274   - confirmButtonText: "确定",
275   - cancelButtonText: "取消",
276   - type: "warning"
277   - }).then(function() {
278   - return deleteLeave(id);
279   - }).then(() => {
280   - this.getList();
281   - this.msgSuccess("删除成功");
282   - })
283   - }
284   - }
285   -};
286   -</script>
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/WebFilterOrderEnum.java
... ... @@ -25,7 +25,9 @@ public interface WebFilterOrderEnum {
25 25  
26 26 // Spring Security Filter 默认为 -100,可见 org.springframework.boot.autoconfigure.security.SecurityProperties 配置属性类
27 27  
28   - int TENANT_SECURITY_FILTER = -99; // 需要保证在 Spring Security 过滤器后
  28 + int TENANT_SECURITY_FILTER = -99; // 需要保证在 Spring Security 过滤器后面
  29 +
  30 + int ACTIVITI_FILTER = -98; // 需要保证在 Spring Security 过滤后面
29 31  
30 32 int DEMO_FILTER = Integer.MAX_VALUE;
31 33  
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageResult.java
... ... @@ -35,4 +35,8 @@ public final class PageResult&lt;T&gt; implements Serializable {
35 35 return new PageResult<>(0L);
36 36 }
37 37  
  38 + public static <T> PageResult<T> empty(Long total) {
  39 + return new PageResult<>(total);
  40 + }
  41 +
38 42 }
... ...
yudao-framework/yudao-spring-boot-starter-activiti/pom.xml
... ... @@ -37,6 +37,14 @@
37 37 <artifactId>yudao-common</artifactId>
38 38 </dependency>
39 39  
  40 + <!-- Web 相关 -->
  41 + <dependency>
  42 + <groupId>cn.iocoder.boot</groupId>
  43 + <artifactId>yudao-spring-boot-starter-security</artifactId>
  44 + </dependency>
  45 +
  46 +
  47 +
40 48 <dependency>
41 49 <groupId>org.mybatis</groupId>
42 50 <artifactId>mybatis</artifactId>
... ... @@ -72,6 +80,7 @@
72 80 <artifactId>activiti-image-generator</artifactId>
73 81 <version>${activiti.version}</version>
74 82 </dependency>
  83 +
75 84 </dependencies>
76 85  
77 86 </project>
... ...
yudao-framework/yudao-spring-boot-starter-activiti/src/main/java/cn/iocoder/yudao/framework/activiti/config/YudaoActivitiConfiguration.java
1 1 package cn.iocoder.yudao.framework.activiti.config;
2 2  
  3 +import cn.iocoder.yudao.framework.activiti.core.web.ActivitiWebFilter;
  4 +import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
3 5 import org.activiti.image.ProcessDiagramGenerator;
4 6 import org.activiti.image.impl.DefaultProcessDiagramGenerator;
5 7 import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
6 8 import org.apache.ibatis.session.SqlSessionFactory;
  9 +import org.springframework.boot.web.servlet.FilterRegistrationBean;
7 10 import org.springframework.context.annotation.Bean;
8 11 import org.springframework.context.annotation.Configuration;
9 12  
... ... @@ -26,4 +29,12 @@ public class YudaoActivitiConfiguration {
26 29 return springProcessEngineConfiguration -> springProcessEngineConfiguration.setSqlSessionFactory(sqlSessionFactory);
27 30 }
28 31  
  32 + @Bean
  33 + public FilterRegistrationBean<ActivitiWebFilter> activitiWebFilter() {
  34 + FilterRegistrationBean<ActivitiWebFilter> registrationBean = new FilterRegistrationBean<>();
  35 + registrationBean.setFilter(new ActivitiWebFilter());
  36 + registrationBean.setOrder(WebFilterOrderEnum.ACTIVITI_FILTER);
  37 + return registrationBean;
  38 + }
  39 +
29 40 }
... ...
yudao-framework/yudao-spring-boot-starter-activiti/src/main/java/cn/iocoder/yudao/framework/activiti/core/util/ActivitiUtils.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.activiti.core.util;
  2 +
  3 +import cn.hutool.core.util.ReflectUtil;
  4 +import com.alibaba.ttl.TransmittableThreadLocal;
  5 +import org.activiti.engine.history.HistoricProcessInstance;
  6 +import org.activiti.engine.impl.identity.Authentication;
  7 +import org.activiti.engine.impl.persistence.entity.HistoricProcessInstanceEntityImpl;
  8 +import org.activiti.engine.impl.persistence.entity.HistoricScopeInstanceEntityImpl;
  9 +
  10 +/**
  11 + * Activiti 工具类
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +public class ActivitiUtils {
  16 +
  17 + static {
  18 + setAuthenticationThreadLocal();
  19 + }
  20 +
  21 + // ========== Authentication 相关 ==========
  22 +
  23 + /**
  24 + * 反射修改 Authentication 的 authenticatedUserIdThreadLocal 静态变量,使用 TTL 线程变量
  25 + * 目的:保证 @Async 等异步执行时,变量丢失的问题
  26 + */
  27 + private static void setAuthenticationThreadLocal() {
  28 + ReflectUtil.setFieldValue(Authentication.class, "authenticatedUserIdThreadLocal",
  29 + new TransmittableThreadLocal<String>());
  30 + }
  31 +
  32 + public static void setAuthenticatedUserId(Long userId) {
  33 + Authentication.setAuthenticatedUserId(String.valueOf(userId));
  34 + }
  35 +
  36 + public static void clearAuthenticatedUserId() {
  37 + Authentication.setAuthenticatedUserId(null);
  38 + }
  39 +
  40 +}
... ...
yudao-framework/yudao-spring-boot-starter-activiti/src/main/java/cn/iocoder/yudao/framework/activiti/core/web/ActivitiWebFilter.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.activiti.core.web;
  2 +
  3 +import cn.iocoder.yudao.framework.activiti.core.util.ActivitiUtils;
  4 +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
  5 +import org.springframework.web.filter.OncePerRequestFilter;
  6 +
  7 +import javax.servlet.FilterChain;
  8 +import javax.servlet.ServletException;
  9 +import javax.servlet.http.HttpServletRequest;
  10 +import javax.servlet.http.HttpServletResponse;
  11 +import java.io.IOException;
  12 +
  13 +/**
  14 + * Activiti Web 过滤器,将 userId 设置到 {@link org.activiti.engine.impl.identity.Authentication} 中
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +public class ActivitiWebFilter extends OncePerRequestFilter {
  19 +
  20 + @Override
  21 + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
  22 + throws ServletException, IOException {
  23 + try {
  24 + // 设置工作流的用户
  25 + Long userId = SecurityFrameworkUtils.getLoginUserId();
  26 + if (userId != null) {
  27 + ActivitiUtils.setAuthenticatedUserId(userId);
  28 + }
  29 + // 过滤
  30 + chain.doFilter(request, response);
  31 + } finally {
  32 + // 清理
  33 + ActivitiUtils.clearAuthenticatedUserId();
  34 + }
  35 + }
  36 +
  37 +}
... ...
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;
3 3 import com.baomidou.mybatisplus.annotation.FieldFill;
4 4 import com.baomidou.mybatisplus.annotation.TableField;
5 5 import com.baomidou.mybatisplus.annotation.TableLogic;
  6 +import lombok.Builder;
6 7 import lombok.Data;
7 8  
8 9 import java.io.Serializable;
... ...
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;
9 9 import com.baomidou.mybatisplus.core.metadata.IPage;
10 10 import org.apache.ibatis.annotations.Param;
11 11  
  12 +import java.util.Collection;
12 13 import java.util.List;
13 14  
14 15 /**
... ... @@ -44,4 +45,8 @@ public interface BaseMapperX&lt;T&gt; extends BaseMapper&lt;T&gt; {
44 45 return selectList(new QueryWrapper<T>().eq(field, value));
45 46 }
46 47  
  48 + default List<T> selectList(String field, Collection<?> values) {
  49 + return selectList(new QueryWrapper<T>().in(field, values));
  50 + }
  51 +
47 52 }
... ...
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 {
98 98 // 原因是,Spring Security 的 Filter 在 ApiAccessLogFilter 后面,在它记录访问日志时,线上上下文已经没有用户编号等信息
99 99 WebFrameworkUtils.setLoginUserId(request, loginUser.getId());
100 100 WebFrameworkUtils.setLoginUserType(request, loginUser.getUserType());
101   -// // TODO @jason:使用 userId 会不会更合适哈?
102   -// // TODO @芋艿:activiti 需要使用 ttl 上下文
103   -// // TODO @jason:清理问题
104   -// if (Objects.equals(UserTypeEnum.ADMIN.getValue(), loginUser.getUserType())) {
105   -// org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(loginUser.getUsername());
106   -// }
107   -// // TODO @芋道源码 该值被赋值给 user task 中assignee , username 显示更直白一点
108   -// // TODO @jason:有办法设置 userId,然后 activiti 有地方读取到 username 么?毕竟 username 只是 User 的登陆账号,并不能绝对像 userId 代表一个用户
109   -// org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(loginUser.getUsername());
110 101 }
111 102  
112 103 }
... ...
更新日志.md
... ... @@ -27,7 +27,11 @@
27 27 ### ⭐ New Features
28 28  
29 29 * 【优化】引入 form generator 0.2.0 版本,并重构相关代码
30   -* 【新增】新增流程表单,支持动态进行表单的配置
  30 +* 【新增】流程表单,支持动态进行表单的配置
  31 +* 【新增】流程模型的管理,支持新增、导入、编辑、删除、发布流程模型
  32 +* 【新增】我的流程的管理,支持发起流程
  33 +* 【新增】待办任务的管理,支持任务的审批通过与不通过
  34 +* 【新增】已办任务的管理,支持详情的查看
31 35 * 【新增】引入 bpmn-process-designer 0.0.1 版本,提供流程设计器的能力
32 36  
33 37 ### 🐞 Bug Fixes
... ...