Browse Source

!63 工作流的任务分配规则的实现
Merge pull request !63 from 芋道源码/feature/activiti

芋道源码 3 years ago
parent
commit
70fe3d31bd
100 changed files with 2180 additions and 360 deletions
  1. 65 0
      sql/activiti.sql
  2. 23 2
      sql/ruoyi-vue-pro.sql
  3. 5 5
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/BpmFormController.java
  4. 7 7
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/BpmModelController.java
  5. 4 4
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/BpmProcessDefinitionController.java
  6. 4 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/BpmTaskAssignRuleController.http
  7. 45 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/BpmTaskAssignRuleController.java
  8. 89 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/BpmUserGroupController.java
  9. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/form/BpmFormBaseVO.java
  10. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/form/BpmFormCreateReqVO.java
  11. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/form/BpmFormPageReqVO.java
  12. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/form/BpmFormRespVO.java
  13. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/form/BpmFormSimpleRespVO.java
  14. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/form/BpmFormUpdateReqVO.java
  15. 31 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/group/BpmUserGroupBaseVO.java
  16. 14 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/group/BpmUserGroupCreateReqVO.java
  17. 31 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/group/BpmUserGroupPageReqVO.java
  18. 19 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/group/BpmUserGroupRespVO.java
  19. 18 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/group/BpmUserGroupUpdateReqVO.java
  20. 3 3
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/model/BpmModeImportReqVO.java
  21. 10 2
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/model/BpmModelBaseVO.java
  22. 26 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/model/BpmModelCreateReqVO.java
  23. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/model/BpmModelPageItemRespVO.java
  24. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/model/BpmModelRespVO.java
  25. 43 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/model/BpmModelUpdateReqVO.java
  26. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/model/BpmModelUpdateStateReqVO.java
  27. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/model/ModelPageReqVO.java
  28. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/process/BpmProcessDefinitionListReqVO.java
  29. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/process/BpmProcessDefinitionPageItemRespVO.java
  30. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/process/BpmProcessDefinitionPageReqVO.java
  31. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/process/BpmProcessDefinitionRespVO.java
  32. 14 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/rule/BpmTaskAssignRuleBaseVO.java
  33. 14 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/rule/BpmTaskAssignRuleCreateReqVO.java
  34. 17 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/rule/BpmTaskAssignRuleRespVO.java
  35. 12 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/rule/BpmTaskAssignRuleUpdateReqVO.java
  36. 21 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/rule/BpmUserGroupSimpleRespVO.java
  37. 0 21
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/vo/BpmModelCreateReqVO.java
  38. 0 25
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/vo/BpmModelUpdateReqVO.java
  39. 6 6
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/definition/BpmFormConvert.java
  40. 51 32
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/definition/BpmModelConvert.java
  41. 5 7
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/definition/BpmProcessDefinitionConvert.java
  42. 44 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/definition/BpmTaskAssignRuleConvert.java
  43. 37 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/definition/BpmUserGroupConvert.java
  44. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmFormDO.java
  45. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmFormDataDO.java
  46. 7 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmProcessDefinitionExtDO.java
  47. 86 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmTaskAssignRuleDO.java
  48. 5 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmTaskMessageRuleDO.java
  49. 52 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmUserGroupDO.java
  50. 3 3
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmFormMapper.java
  51. 35 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmTaskAssignRuleMapper.java
  52. 32 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmUserGroupMapper.java
  53. 15 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/BpmErrorCodeConstants.java
  54. 21 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/definition/BpmModelFormTypeEnum.java
  55. 37 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/definition/BpmTaskAssignRuleTypeEnum.java
  56. 28 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/definition/BpmTaskRuleScriptEnum.java
  57. 0 26
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/BpmActivitiConfiguration.java
  58. 70 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/config/BpmActivitiConfiguration.java
  59. 60 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/behavior/BpmActivityBehaviorFactory.java
  60. 195 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/behavior/BpmUserTaskActivitiBehavior.java
  61. 7 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/behavior/package-info.java
  62. 34 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/behavior/script/BpmTaskAssignScript.java
  63. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/listener/BpmProcessInstanceEventListener.java
  64. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/listener/BpmTackActivitiEventListener.java
  65. 15 4
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/listener/BpmTaskEventListener.java
  66. 7 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/listener/package-info.java
  67. 0 62
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/config/UserGroupManagerService.java
  68. 0 31
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/config/UserGroupsProvider.java
  69. 5 6
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/BpmFormService.java
  70. 13 3
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/BpmModelService.java
  71. 4 4
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/BpmProcessDefinitionService.java
  72. 71 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/BpmTaskAssignRuleService.java
  73. 82 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/BpmUserGroupService.java
  74. 31 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/dto/BpmDefinitionCreateReqDTO.java
  75. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/dto/BpmFormFieldRespDTO.java
  76. 39 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/dto/BpmModelMetaInfoRespDTO.java
  77. 9 9
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmFormServiceImpl.java
  78. 90 23
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmModelServiceImpl.java
  79. 16 13
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmProcessDefinitionServiceImpl.java
  80. 178 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmTaskAssignRuleServiceImpl.java
  81. 114 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmUserGroupServiceImpl.java
  82. 0 23
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/model/dto/BpmModelMetaInfoRespDTO.java
  83. 2 2
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmProcessInstanceServiceImpl.java
  84. 5 3
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/dept/vo/dept/SysDeptBaseVO.java
  85. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/permission/SysPermissionController.java
  86. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/permission/SysRoleController.java
  87. 21 3
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/user/SysUserController.java
  88. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/user/SysUserProfileController.java
  89. 1 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/user/vo/user/SysUserExcelVO.java
  90. 21 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/user/vo/user/SysUserSimpleRespVO.java
  91. 1 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/user/SysUserConvert.java
  92. 5 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/dataobject/dept/SysDeptDO.java
  93. 6 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/dict/SysDictDataMapper.java
  94. 9 2
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/permission/SysUserRoleMapper.java
  95. 9 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/user/SysUserMapper.java
  96. 3 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysDictTypeConstants.java
  97. 3 1
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysErrorCodeConstants.java
  98. 17 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/dept/SysDeptService.java
  99. 9 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/dept/SysPostService.java
  100. 27 0
      yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/dept/impl/SysDeptServiceImpl.java

File diff suppressed because it is too large
+ 65 - 0
sql/activiti.sql


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


+ 5 - 5
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/form/BpmFormController.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/BpmFormController.java

@@ -1,9 +1,9 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.form;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition;
 
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.*;
-import cn.iocoder.yudao.adminserver.modules.bpm.convert.form.BpmFormConvert;
-import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
-import cn.iocoder.yudao.adminserver.modules.bpm.service.form.BpmFormService;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.*;
+import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmFormConvert;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmFormDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmFormService;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import io.swagger.annotations.Api;

+ 7 - 7
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/BpmModelController.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/BpmModelController.java

@@ -1,8 +1,8 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.model;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition;
 
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo.*;
-import cn.iocoder.yudao.adminserver.modules.bpm.convert.model.BpmModelConvert;
-import cn.iocoder.yudao.adminserver.modules.bpm.service.model.BpmModelService;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model.*;
+import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmModelConvert;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmModelService;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.io.IoUtils;
@@ -47,7 +47,7 @@ public class BpmModelController {
     @ApiOperation(value = "新建模型")
     @PreAuthorize("@ss.hasPermission('bpm:model:create')")
     public CommonResult<String> createModel(@Valid @RequestBody BpmModelCreateReqVO createRetVO) {
-        return success(bpmModelService.createModel(createRetVO));
+        return success(bpmModelService.createModel(createRetVO, null));
     }
 
     @PostMapping("/import")
@@ -56,8 +56,8 @@ public class BpmModelController {
     public CommonResult<String> importModel(@Valid BpmModeImportReqVO importReqVO) throws IOException {
         BpmModelCreateReqVO createReqVO = BpmModelConvert.INSTANCE.convert(importReqVO);
         // 读取文件
-        createReqVO.setBpmnXml(IoUtils.readUtf8(importReqVO.getBpmnFile().getInputStream(), false));
-        return success(bpmModelService.createModel(createReqVO));
+        String bpmnXml = IoUtils.readUtf8(importReqVO.getBpmnFile().getInputStream(), false);
+        return success(bpmModelService.createModel(createReqVO, bpmnXml));
     }
 
     @PutMapping("/update")

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

@@ -1,9 +1,9 @@
 package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition;
 
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionListReqVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageItemRespVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageReqVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionListReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionPageReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionRespVO;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;

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

@@ -0,0 +1,4 @@
+### 请求 /bpm/task-assign-rule/list 接口 => 成功
+GET {{baseUrl}}/bpm/task-assign-rule/list?processDefinitionId=leave:9:59689ba0-7284-11ec-965c-a2380e71991a
+tenant-id: 1
+Authorization: Bearer {{token}}

+ 45 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/BpmTaskAssignRuleController.java

@@ -0,0 +1,45 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmTaskAssignRuleService;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import io.swagger.annotations.Api;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Api(tags = "任务分配规则")
+@RestController
+@RequestMapping("/bpm/task-assign-rule")
+@Validated
+public class BpmTaskAssignRuleController {
+
+    @Resource
+    private BpmTaskAssignRuleService taskAssignRuleService;
+
+    @GetMapping("/list")
+    public CommonResult<List<BpmTaskAssignRuleRespVO>> getTaskAssignRuleList(
+            @RequestParam(value = "modelId", required = false) String modelId,
+            @RequestParam(value = "processDefinitionId", required = false) String processDefinitionId) {
+        return success(taskAssignRuleService.getTaskAssignRuleList(modelId, processDefinitionId));
+    }
+
+    @PostMapping("/create")
+    public CommonResult<Long> createTaskAssignRule(@Valid @RequestBody BpmTaskAssignRuleCreateReqVO reqVO) {
+        return success(taskAssignRuleService.createTaskAssignRule(reqVO));
+    }
+
+    @PutMapping("/update")
+    public CommonResult<Boolean> updateTaskAssignRule(@Valid @RequestBody BpmTaskAssignRuleUpdateReqVO reqVO) {
+        taskAssignRuleService.updateTaskAssignRule(reqVO);
+        return success(true);
+    }
+
+}

+ 89 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/BpmUserGroupController.java

@@ -0,0 +1,89 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupCreateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupPageReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupUpdateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmUserGroupConvert;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmUserGroupDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmUserGroupService;
+import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.user.SysUserSimpleRespVO;
+import cn.iocoder.yudao.adminserver.modules.system.convert.user.SysUserConvert;
+import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Api(tags = "用户组")
+@RestController
+@RequestMapping("/bpm/user-group")
+@Validated
+public class BpmUserGroupController {
+
+    @Resource
+    private BpmUserGroupService userGroupService;
+
+    @PostMapping("/create")
+    @ApiOperation("创建用户组")
+    @PreAuthorize("@ss.hasPermission('bpm:user-group:create')")
+    public CommonResult<Long> createUserGroup(@Valid @RequestBody BpmUserGroupCreateReqVO createReqVO) {
+        return success(userGroupService.createUserGroup(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @ApiOperation("更新用户组")
+    @PreAuthorize("@ss.hasPermission('bpm:user-group:update')")
+    public CommonResult<Boolean> updateUserGroup(@Valid @RequestBody BpmUserGroupUpdateReqVO updateReqVO) {
+        userGroupService.updateUserGroup(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @ApiOperation("删除用户组")
+    @ApiImplicitParam(name = "id", value = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('bpm:user-group:delete')")
+    public CommonResult<Boolean> deleteUserGroup(@RequestParam("id") Long id) {
+        userGroupService.deleteUserGroup(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @ApiOperation("获得用户组")
+    @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
+    @PreAuthorize("@ss.hasPermission('bpm:user-group:query')")
+    public CommonResult<BpmUserGroupRespVO> getUserGroup(@RequestParam("id") Long id) {
+        BpmUserGroupDO userGroup = userGroupService.getUserGroup(id);
+        return success(BpmUserGroupConvert.INSTANCE.convert(userGroup));
+    }
+
+    @GetMapping("/page")
+    @ApiOperation("获得用户组分页")
+    @PreAuthorize("@ss.hasPermission('bpm:user-group:query')")
+    public CommonResult<PageResult<BpmUserGroupRespVO>> getUserGroupPage(@Valid BpmUserGroupPageReqVO pageVO) {
+        PageResult<BpmUserGroupDO> pageResult = userGroupService.getUserGroupPage(pageVO);
+        return success(BpmUserGroupConvert.INSTANCE.convertPage(pageResult));
+    }
+
+    @GetMapping("/list-all-simple")
+    @ApiOperation(value = "获取用户组精简信息列表", notes = "只包含被开启的用户组,主要用于前端的下拉选项")
+    public CommonResult<List<BpmUserGroupRespVO>> getSimpleUserGroups() {
+        // 获用户门列表,只要开启状态的
+        List<BpmUserGroupDO> list = userGroupService.getUserGroupListByStatus(CommonStatusEnum.ENABLE.getStatus());
+        // 排序后,返回给前端
+        return success(BpmUserGroupConvert.INSTANCE.convertList2(list));
+    }
+
+}

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/form/vo/BpmFormBaseVO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/form/BpmFormBaseVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form;
 
 import lombok.*;
 import io.swagger.annotations.*;

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/form/vo/BpmFormCreateReqVO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/form/BpmFormCreateReqVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form;
 
 import lombok.*;
 import io.swagger.annotations.*;

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/form/vo/BpmFormPageReqVO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/form/BpmFormPageReqVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form;
 
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import io.swagger.annotations.ApiModel;

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/form/vo/BpmFormRespVO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/form/BpmFormRespVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/form/vo/BpmFormSimpleRespVO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/form/BpmFormSimpleRespVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/form/vo/BpmFormUpdateReqVO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/form/BpmFormUpdateReqVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form;
 
 import lombok.*;
 import io.swagger.annotations.*;

+ 31 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/group/BpmUserGroupBaseVO.java

@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import javax.validation.constraints.*;
+
+/**
+* 用户组 Base VO,提供给添加、修改、详细的子 VO 使用
+* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+*/
+@Data
+public class BpmUserGroupBaseVO {
+
+    @ApiModelProperty(value = "组名", required = true, example = "芋道")
+    @NotNull(message = "组名不能为空")
+    private String name;
+
+    @ApiModelProperty(value = "描述", required = true, example = "芋道源码")
+    @NotNull(message = "描述不能为空")
+    private String description;
+
+    @ApiModelProperty(value = "成员编号数组", required = true, example = "1,2,3")
+    @NotNull(message = "成员编号数组不能为空")
+    private Set<Long> memberUserIds;
+
+    @ApiModelProperty(value = "状态", required = true, example = "1")
+    @NotNull(message = "状态不能为空")
+    private Integer status;
+
+}

+ 14 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/group/BpmUserGroupCreateReqVO.java

@@ -0,0 +1,14 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import javax.validation.constraints.*;
+
+@ApiModel("用户组创建 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class BpmUserGroupCreateReqVO extends BpmUserGroupBaseVO {
+
+}

+ 31 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/group/BpmUserGroupPageReqVO.java

@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@ApiModel("用户组分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class BpmUserGroupPageReqVO extends PageParam {
+
+    @ApiModelProperty(value = "组名", example = "芋道")
+    private String name;
+
+    @ApiModelProperty(value = "状态", example = "1")
+    private Integer status;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "开始创建时间")
+    private Date beginCreateTime;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "结束创建时间")
+    private Date endCreateTime;
+
+}

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

@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+
+@ApiModel("用户组 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class BpmUserGroupRespVO extends BpmUserGroupBaseVO {
+
+    @ApiModelProperty(value = "编号", required = true, example = "1024")
+    private Long id;
+
+    @ApiModelProperty(value = "创建时间", required = true)
+    private Date createTime;
+
+}

+ 18 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/group/BpmUserGroupUpdateReqVO.java

@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import javax.validation.constraints.*;
+
+@ApiModel("用户组更新 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class BpmUserGroupUpdateReqVO extends BpmUserGroupBaseVO {
+
+    @ApiModelProperty(value = "编号", required = true, example = "1024")
+    @NotNull(message = "编号不能为空")
+    private Long id;
+
+}

+ 3 - 3
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/vo/BpmModeImportReqVO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/model/BpmModeImportReqVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -9,11 +9,11 @@ import org.springframework.web.multipart.MultipartFile;
 
 import javax.validation.constraints.NotNull;
 
-@ApiModel("流程模型的导入 Request VO")
+@ApiModel(value = "流程模型的导入 Request VO", description = "相比流程模型的新建来说,只是多了一个 bpmnFile 文件")
 @Data
 @EqualsAndHashCode(callSuper = true)
 @ToString(callSuper = true)
-public class BpmModeImportReqVO extends BpmModelBaseVO {
+public class BpmModeImportReqVO extends BpmModelCreateReqVO {
 
     @ApiModelProperty(value = "BPMN 文件", required = true)
     @NotNull(message = "BPMN 文件不能为空")

+ 10 - 2
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/vo/BpmModelBaseVO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/model/BpmModelBaseVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model;
 
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -27,7 +27,15 @@ public class BpmModelBaseVO {
     @NotEmpty(message = "流程分类不能为空")
     private String category;
 
-    @ApiModelProperty(value = "表单编号", example = "1024")
+    @ApiModelProperty(value = "表单类型", notes = "参见 bpm_model_form_type 数据字典", example = "1")
+    private Integer formType;
+    @ApiModelProperty(value = "表单编号", example = "1024", notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空")
     private Long formId;
+    @ApiModelProperty(value = "自定义表单的提交路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/create",
+            notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空")
+    private String formCustomCreatePath;
+    @ApiModelProperty(value = "自定义表单的查看路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/view",
+            notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空")
+    private String formCustomViewPath;
 
 }

+ 26 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/model/BpmModelCreateReqVO.java

@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import javax.validation.constraints.NotEmpty;
+
+@ApiModel("流程模型的创建 Request VO")
+@Data
+public class BpmModelCreateReqVO {
+
+    @ApiModelProperty(value = "流程标识", required = true, example = "process_yudao")
+    @NotEmpty(message = "流程标识不能为空")
+    private String key;
+
+    @ApiModelProperty(value = "流程名称", required = true, example = "芋道")
+    @NotEmpty(message = "流程名称不能为空")
+    private String name;
+
+    @ApiModelProperty(value = "流程描述", example = "我是描述")
+    private String description;
+
+}

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/vo/BpmModelPageItemRespVO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/model/BpmModelPageItemRespVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/vo/BpmModelRespVO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/model/BpmModelRespVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;

+ 43 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/model/BpmModelUpdateReqVO.java

@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmModelFormTypeEnum;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import javax.validation.constraints.NotEmpty;
+
+@ApiModel("流程模型的更新 Request VO")
+@Data
+public class BpmModelUpdateReqVO {
+
+    @ApiModelProperty(value = "编号", required = true, example = "1024")
+    @NotEmpty(message = "编号不能为空")
+    private String id;
+
+    @ApiModelProperty(value = "流程名称", example = "芋道")
+    private String name;
+
+    @ApiModelProperty(value = "流程描述", example = "我是描述")
+    private String description;
+
+    @ApiModelProperty(value = "流程分类", notes = "参见 bpm_model_category 数据字典", example = "1")
+    private String category;
+
+    @ApiModelProperty(value = "BPMN XML", required = true)
+    private String bpmnXml;
+
+    @ApiModelProperty(value = "表单类型", notes = "参见 bpm_model_form_type 数据字典", example = "1")
+    private Integer formType;
+    @ApiModelProperty(value = "表单编号", example = "1024", notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空")
+    private Long formId;
+    @ApiModelProperty(value = "自定义表单的提交路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/create",
+            notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空")
+    private String formCustomCreatePath;
+    @ApiModelProperty(value = "自定义表单的查看路径,使用 Vue 的路由地址", example = "/bpm/oa/leave/view",
+            notes = "在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空")
+    private String formCustomViewPath;
+
+}

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/vo/BpmModelUpdateStateReqVO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/model/BpmModelUpdateStateReqVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/model/vo/ModelPageReqVO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/model/ModelPageReqVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model;
 
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import io.swagger.annotations.ApiModel;

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/BpmProcessDefinitionListReqVO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/process/BpmProcessDefinitionListReqVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process;
 
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import io.swagger.annotations.ApiModel;

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

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/BpmProcessDefinitionPageReqVO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/process/BpmProcessDefinitionPageReqVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process;
 
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import io.swagger.annotations.ApiModel;

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/BpmProcessDefinitionRespVO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/process/BpmProcessDefinitionRespVO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo;
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;

+ 14 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/rule/BpmTaskAssignRuleBaseVO.java

@@ -0,0 +1,14 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule;
+
+import lombok.Data;
+
+import java.util.Set;
+
+@Data
+public class BpmTaskAssignRuleBaseVO {
+
+    private Integer type;
+
+    private Set<Long> options;
+
+}

+ 14 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/rule/BpmTaskAssignRuleCreateReqVO.java

@@ -0,0 +1,14 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class BpmTaskAssignRuleCreateReqVO extends BpmTaskAssignRuleBaseVO {
+
+    private String modelId;
+
+    private String taskDefinitionKey;
+
+}

+ 17 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/rule/BpmTaskAssignRuleRespVO.java

@@ -0,0 +1,17 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule;
+
+import lombok.Data;
+
+@Data
+public class BpmTaskAssignRuleRespVO extends BpmTaskAssignRuleBaseVO {
+
+    private Long id;
+
+    private String modelId;
+
+    private String processDefinitionId;
+
+    private String taskDefinitionKey;
+    private String taskDefinitionName;
+
+}

+ 12 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/rule/BpmTaskAssignRuleUpdateReqVO.java

@@ -0,0 +1,12 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule;
+
+import lombok.Data;
+
+import java.util.Set;
+
+@Data
+public class BpmTaskAssignRuleUpdateReqVO extends BpmTaskAssignRuleBaseVO {
+
+    private Long id;
+
+}

+ 21 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/definition/vo/rule/BpmUserGroupSimpleRespVO.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@ApiModel("用户组精简信息 Response VO")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class BpmUserGroupSimpleRespVO {
+
+    @ApiModelProperty(value = "用户组编号", required = true, example = "1024")
+    private Long id;
+
+    @ApiModelProperty(value = "用户组名字", required = true, example = "芋道")
+    private String name;
+
+}

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

@@ -1,21 +0,0 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-import javax.validation.constraints.NotEmpty;
-
-@ApiModel("流程模型的创建 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class BpmModelCreateReqVO extends BpmModelBaseVO {
-
-    @ApiModelProperty(value = "BPMN XML", required = true)
-    @NotEmpty(message = "BPMN XML 不能为空")
-    private String bpmnXml;
-
-}

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

@@ -1,25 +0,0 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-import javax.validation.constraints.NotEmpty;
-
-@ApiModel("流程模型的更新 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class BpmModelUpdateReqVO extends BpmModelBaseVO {
-
-    @ApiModelProperty(value = "编号", required = true, example = "1024")
-    @NotEmpty(message = "编号不能为空")
-    private String id;
-
-    @ApiModelProperty(value = "BPMN XML", required = true)
-    @NotEmpty(message = "BPMN XML 不能为空")
-    private String bpmnXml;
-
-}

+ 6 - 6
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/form/BpmFormConvert.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/definition/BpmFormConvert.java

@@ -1,10 +1,10 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.convert.form;
+package cn.iocoder.yudao.adminserver.modules.bpm.convert.definition;
 
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormCreateReqVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormRespVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormSimpleRespVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormUpdateReqVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormCreateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormSimpleRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormUpdateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmFormDO;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import org.mapstruct.Mapper;
 import org.mapstruct.factory.Mappers;

+ 51 - 32
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/model/BpmModelConvert.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/definition/BpmModelConvert.java

@@ -1,9 +1,10 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.convert.model;
+package cn.iocoder.yudao.adminserver.modules.bpm.convert.definition;
 
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo.*;
-import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model.*;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmFormDO;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmDefinitionCreateReqDTO;
-import cn.iocoder.yudao.adminserver.modules.bpm.service.model.dto.BpmModelMetaInfoRespDTO;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmModelMetaInfoRespDTO;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 import org.activiti.engine.impl.persistence.entity.SuspensionState;
@@ -11,14 +12,16 @@ import org.activiti.engine.repository.Deployment;
 import org.activiti.engine.repository.Model;
 import org.activiti.engine.repository.ProcessDefinition;
 import org.mapstruct.Mapper;
+import org.mapstruct.MappingTarget;
 import org.mapstruct.factory.Mappers;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 
 /**
- * 流程定义 Convert
+ * 流程模型 Convert
  *
  * @author yunlongn
  */
@@ -42,18 +45,15 @@ public interface BpmModelConvert {
     default BpmModelPageItemRespVO convert(Model model, BpmFormDO form, Deployment deployment, ProcessDefinition processDefinition) {
         BpmModelPageItemRespVO modelRespVO = new BpmModelPageItemRespVO();
         modelRespVO.setId(model.getId());
-        modelRespVO.setName(model.getName());
-        modelRespVO.setKey(model.getKey());
-        modelRespVO.setCategory(model.getCategory());
         modelRespVO.setCreateTime(model.getCreateTime());
-        BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
-        if (metaInfo != null) {
-            modelRespVO.setDescription(metaInfo.getDescription());
-        }
+        // 通用 copy
+        copyTo(model, modelRespVO);
+        // Form
         if (form != null) {
             modelRespVO.setFormId(form.getId());
             modelRespVO.setFormName(form.getName());
         }
+        // ProcessDefinition
         modelRespVO.setProcessDefinition(this.convert(processDefinition));
         if (modelRespVO.getProcessDefinition() != null) {
             modelRespVO.getProcessDefinition().setSuspensionState(processDefinition.isSuspended() ?
@@ -66,49 +66,68 @@ public interface BpmModelConvert {
     default BpmModelRespVO convert(Model model) {
         BpmModelRespVO modelRespVO = new BpmModelRespVO();
         modelRespVO.setId(model.getId());
-        modelRespVO.setName(model.getName());
-        modelRespVO.setKey(model.getKey());
-        modelRespVO.setCategory(model.getCategory());
         modelRespVO.setCreateTime(model.getCreateTime());
-        BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
-        if (metaInfo != null) {
-            modelRespVO.setFormId(metaInfo.getFormId());
-            modelRespVO.setDescription(metaInfo.getDescription());
-        }
+        // 通用 copy
+        copyTo(model, modelRespVO);
         return modelRespVO;
     }
 
+    default void copyTo(Model model, BpmModelBaseVO to) {
+        to.setName(model.getName());
+        to.setKey(model.getKey());
+        to.setCategory(model.getCategory());
+        // metaInfo
+        BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
+        copyTo(metaInfo, to);
+    }
+
+    void copyTo(BpmModelMetaInfoRespDTO from, @MappingTarget BpmModelBaseVO to);
+
     default BpmDefinitionCreateReqDTO convert2(Model model) {
         BpmDefinitionCreateReqDTO createReqDTO = new BpmDefinitionCreateReqDTO();
+        createReqDTO.setModelId(model.getId());
         createReqDTO.setName(model.getName());
         createReqDTO.setKey(model.getKey());
         createReqDTO.setCategory(model.getCategory());
         BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
-        if (metaInfo != null) {
-            createReqDTO.setDescription(metaInfo.getDescription());
-            createReqDTO.setFormId(metaInfo.getFormId());
-        }
+        // metaInfo
+        copyTo(metaInfo, createReqDTO);
         return createReqDTO;
     }
 
+    void copyTo(BpmModelMetaInfoRespDTO from, @MappingTarget BpmDefinitionCreateReqDTO to);
+
     default void copy(Model model, BpmModelCreateReqVO bean) {
         model.setName(bean.getName());
         model.setKey(bean.getKey());
-        model.setCategory(bean.getCategory());
-        model.setMetaInfo(JsonUtils.toJsonString(this.buildMetaInfo(bean.getDescription(), bean.getFormId())));
+        model.setMetaInfo(buildMetaInfoStr(null, bean.getDescription(), null, null,
+                null, null));
     }
 
     default void copy(Model model, BpmModelUpdateReqVO bean) {
         model.setName(bean.getName());
         model.setCategory(bean.getCategory());
-        model.setMetaInfo(JsonUtils.toJsonString(this.buildMetaInfo(bean.getDescription(), bean.getFormId())));
+        model.setMetaInfo(buildMetaInfoStr(JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class),
+                bean.getDescription(), bean.getFormType(), bean.getFormId(),
+                bean.getFormCustomCreatePath(), bean.getFormCustomViewPath()));
     }
 
-    default BpmModelMetaInfoRespDTO buildMetaInfo(String description, Long formId) {
-        BpmModelMetaInfoRespDTO metaInfo = new BpmModelMetaInfoRespDTO();
-        metaInfo.setDescription(description);
-        metaInfo.setFormId(formId);
-        return metaInfo;
+    default String buildMetaInfoStr(BpmModelMetaInfoRespDTO metaInfo, String description, Integer formType,
+                                    Long formId, String formCustomCreatePath, String formCustomViewPath) {
+        if (metaInfo == null) {
+            metaInfo = new BpmModelMetaInfoRespDTO();
+        }
+        // 只有非空,才进行设置,避免更新时的覆盖
+        if (StrUtil.isNotEmpty(description)) {
+            metaInfo.setDescription(description);
+        }
+        if (Objects.nonNull(formType)) {
+            metaInfo.setFormType(formType);
+            metaInfo.setFormId(formId);
+            metaInfo.setFormCustomCreatePath(formCustomCreatePath);
+            metaInfo.setFormCustomViewPath(formCustomViewPath);
+        }
+        return JsonUtils.toJsonString(metaInfo);
     }
 
     BpmModelPageItemRespVO.ProcessDefinition convert(ProcessDefinition bean);

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

@@ -1,9 +1,9 @@
 package cn.iocoder.yudao.adminserver.modules.bpm.convert.definition;
 
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageItemRespVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionRespVO;
 import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
-import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmFormDO;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmDefinitionCreateReqDTO;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import org.activiti.engine.impl.persistence.entity.SuspensionState;
@@ -11,13 +11,11 @@ import org.activiti.engine.repository.Deployment;
 import org.activiti.engine.repository.ProcessDefinition;
 import org.mapstruct.Mapper;
 import org.mapstruct.Mapping;
-import org.mapstruct.Mappings;
 import org.mapstruct.Named;
 import org.mapstruct.factory.Mappers;
 
 import java.util.List;
 import java.util.Map;
-import java.util.function.Function;
 
 /**
  * Bpm 流程定义的 Convert
@@ -25,9 +23,9 @@ import java.util.function.Function;
  * @author yunlong.li
  */
 @Mapper
-public interface BpmDefinitionConvert {
+public interface BpmProcessDefinitionConvert {
 
-    BpmDefinitionConvert INSTANCE = Mappers.getMapper(BpmDefinitionConvert.class);
+    BpmProcessDefinitionConvert INSTANCE = Mappers.getMapper(BpmProcessDefinitionConvert.class);
 
     default List<BpmProcessDefinitionPageItemRespVO> convertList(List<ProcessDefinition> list, Map<String, Deployment> deploymentMap,
                                                                  Map<String, BpmProcessDefinitionExtDO> processDefinitionDOMap, Map<Long, BpmFormDO> formMap) {

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

@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.convert.definition;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import org.activiti.bpmn.model.UserTask;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+@Mapper
+public interface BpmTaskAssignRuleConvert {
+
+    BpmTaskAssignRuleConvert INSTANCE = Mappers.getMapper(BpmTaskAssignRuleConvert.class);
+
+    default List<BpmTaskAssignRuleRespVO> convertList(List<UserTask> tasks, List<BpmTaskAssignRuleDO> rules) {
+        Map<String, BpmTaskAssignRuleDO> ruleMap = CollectionUtils.convertMap(rules, BpmTaskAssignRuleDO::getTaskDefinitionKey);
+        // 以 UserTask 为主维度,原因是:流程图编辑后,一些规则实际就没用了。
+        return CollectionUtils.convertList(tasks, task -> {
+            BpmTaskAssignRuleRespVO respVO = convert(ruleMap.get(task.getId()));
+            if (respVO == null) {
+                respVO = new BpmTaskAssignRuleRespVO();
+                respVO.setTaskDefinitionKey(task.getId());
+            }
+            respVO.setTaskDefinitionName(task.getName());
+            return respVO;
+        });
+    }
+
+    BpmTaskAssignRuleRespVO convert(BpmTaskAssignRuleDO bean);
+
+    BpmTaskAssignRuleDO convert(BpmTaskAssignRuleCreateReqVO bean);
+
+    BpmTaskAssignRuleDO convert(BpmTaskAssignRuleUpdateReqVO bean);
+
+    List<BpmTaskAssignRuleDO> convertList2(List<BpmTaskAssignRuleRespVO> list);
+
+}

+ 37 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/definition/BpmUserGroupConvert.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.convert.definition;
+
+import java.util.*;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupCreateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupUpdateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmUserGroupDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.Named;
+import org.mapstruct.factory.Mappers;
+
+/**
+ * 用户组 Convert
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface BpmUserGroupConvert {
+
+    BpmUserGroupConvert INSTANCE = Mappers.getMapper(BpmUserGroupConvert.class);
+
+    BpmUserGroupDO convert(BpmUserGroupCreateReqVO bean);
+
+    BpmUserGroupDO convert(BpmUserGroupUpdateReqVO bean);
+
+    BpmUserGroupRespVO convert(BpmUserGroupDO bean);
+
+    List<BpmUserGroupRespVO> convertList(List<BpmUserGroupDO> list);
+
+    PageResult<BpmUserGroupRespVO> convertPage(PageResult<BpmUserGroupDO> page);
+
+    @Named("convertList2")
+    List<BpmUserGroupRespVO> convertList2(List<BpmUserGroupDO> list);
+}

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/form/BpmFormDO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmFormDO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form;
+package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition;
 
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import com.baomidou.mybatisplus.annotation.TableField;

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/form/BpmFormDataDO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmFormDataDO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form;
+package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition;
 
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import com.baomidou.mybatisplus.annotation.TableField;

+ 7 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmProcessDefinitionExtDO.java

@@ -1,10 +1,10 @@
 package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition;
 
-import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.*;
+import org.activiti.engine.repository.Model;
 import org.activiti.engine.repository.ProcessDefinition;
 
 /**
@@ -33,6 +33,12 @@ public class BpmProcessDefinitionExtDO extends BaseDO {
      * 关联 {@link ProcessDefinition#getId()}
      */
     private String processDefinitionId;
+    /**
+     * 流程模型的编号
+     *
+     * 关联 {@link Model#getId()}
+     */
+    private String modelId;
     /**
      * 描述
      */

+ 86 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmTaskAssignRuleDO.java

@@ -0,0 +1,86 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmTaskRuleScriptEnum;
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+import org.activiti.engine.repository.Model;
+import org.activiti.engine.repository.ProcessDefinition;
+import org.activiti.engine.task.Task;
+
+import java.util.Set;
+
+/**
+ * Bpm 任务分配的规则表,用于自定义配置每个任务的负责人、候选人的分配规则。
+ * 也就是说,废弃 BPMN 原本的 UserTask 设置的 assignee、candidateUsers 等配置,而是通过使用该规则进行计算对应的负责人。
+ *
+ * 1. 默认情况下,{@link #processDefinitionId} 为 {@link #PROCESS_DEFINITION_ID_NULL} 值,表示贵改则与流程模型关联
+ * 2. 在流程模型部署后,会将他的所有规则记录,复制出一份新部署出来的流程定义,通过设置 {@link #processDefinitionId} 为新的流程定义的编号进行关联
+ *
+ * @author 芋道源码
+ */
+@TableName(value = "bpm_task_assign_rule", autoResultMap = true)
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class BpmTaskAssignRuleDO extends BaseDO {
+
+    /**
+     * {@link #processDefinitionId} 空串,用于标识属于流程模型,而不属于流程定义
+     */
+    public static final String PROCESS_DEFINITION_ID_NULL = "";
+
+    /**
+     * 编号
+     */
+    @TableId
+    private Long id;
+
+    /**
+     * 流程模型编号
+     *
+     * 关联 {@link Model#getId()}
+     */
+    private String modelId;
+    /**
+     * 流程定义编号
+     *
+     * 关联 {@link ProcessDefinition#getId()}
+     */
+    private String processDefinitionId;
+    /**
+     * 流程任务的定义 Key
+     *
+     * 关联 {@link Task#getTaskDefinitionKey()}
+     */
+    private String taskDefinitionKey;
+
+    /**
+     * 规则类型
+     *
+     * 枚举 {@link BpmTaskAssignRuleTypeEnum}
+     */
+    @TableField("`type`")
+    private Integer type;
+    /**
+     * 规则值数组,一般关联指定表的编号
+     * 根据 type 不同,对应的值是不同的:
+     *
+     * 1. {@link BpmTaskAssignRuleTypeEnum#ROLE} 时:角色编号
+     * 2. {@link BpmTaskAssignRuleTypeEnum#DEPT_MEMBER} 时:部门编号
+     * 3. {@link BpmTaskAssignRuleTypeEnum#DEPT_LEADER} 时:部门编号
+     * 4. {@link BpmTaskAssignRuleTypeEnum#USER} 时:用户编号
+     * 5. {@link BpmTaskAssignRuleTypeEnum#USER_GROUP} 时:用户组编号
+     * 6. {@link BpmTaskAssignRuleTypeEnum#SCRIPT} 时:脚本编号,目前通过 {@link BpmTaskRuleScriptEnum#getId()} 标识
+     */
+    @TableField(typeHandler = JsonLongSetTypeHandler.class)
+    private Set<Long> options;
+
+}

+ 5 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmTaskMessageRuleDO.java

@@ -0,0 +1,5 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition;
+
+// TODO 芋艿:先埋个坑。任务消息的配置规则。说白了,就是不同的
+public class BpmTaskMessageRuleDO {
+}

+ 52 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmUserGroupDO.java

@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.util.Set;
+
+/**
+ * Bpm 用户组
+ *
+ * @author 芋道源码
+ */
+@TableName(value = "bpm_user_group", autoResultMap = true)
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class BpmUserGroupDO extends BaseDO {
+
+    /**
+     * 编号,自增
+     */
+    @TableId
+    private Long id;
+    /**
+     * 组名
+     */
+    private String name;
+    /**
+     * 描述
+     */
+    private String description;
+    /**
+     * 状态
+     *
+     * 枚举 {@link CommonStatusEnum}
+     */
+    private Integer status;
+    /**
+     * 成员用户编号数组
+     */
+    @TableField(typeHandler = JsonLongSetTypeHandler.class)
+    private Set<Long> memberUserIds;
+
+}

+ 3 - 3
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/form/BpmFormMapper.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmFormMapper.java

@@ -1,8 +1,8 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.form;
+package cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition;
 
 
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormPageReqVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormPageReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmFormDO;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;

+ 35 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmTaskAssignRuleMapper.java

@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.lang.Nullable;
+
+import java.util.List;
+
+@Mapper
+public interface BpmTaskAssignRuleMapper extends BaseMapperX<BpmTaskAssignRuleDO> {
+
+    default List<BpmTaskAssignRuleDO> selectListByProcessDefinitionId(String processDefinitionId,
+                                                                      @Nullable String taskDefinitionKey) {
+        return selectList(new QueryWrapperX<BpmTaskAssignRuleDO>()
+                .eq("process_definition_id", processDefinitionId)
+                .eqIfPresent("task_definition_key", taskDefinitionKey));
+    }
+
+    default List<BpmTaskAssignRuleDO> selectListByModelId(String modelId) {
+        return selectList(new QueryWrapperX<BpmTaskAssignRuleDO>()
+                .eq("model_id", modelId)
+                .eq("process_definition_id", BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL));
+    }
+
+    default BpmTaskAssignRuleDO selectListByModelIdAndTaskDefinitionKey(String modelId,
+                                                                        String taskDefinitionKey) {
+        return selectOne(new QueryWrapperX<BpmTaskAssignRuleDO>()
+                .eq("model_id", modelId)
+                .eq("process_definition_id", BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL)
+                .eq("task_definition_key", taskDefinitionKey));
+    }
+
+}

+ 32 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmUserGroupMapper.java

@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupPageReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmUserGroupDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 用户组 Mapper
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface BpmUserGroupMapper extends BaseMapperX<BpmUserGroupDO> {
+
+    default PageResult<BpmUserGroupDO> selectPage(BpmUserGroupPageReqVO reqVO) {
+        return selectPage(reqVO, new QueryWrapperX<BpmUserGroupDO>()
+                .likeIfPresent("name", reqVO.getName())
+                .eqIfPresent("status", reqVO.getStatus())
+                .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
+                .orderByDesc("id"));
+    }
+
+    default List<BpmUserGroupDO> selectListByStatus(Integer status) {
+        return selectList("status", status);
+    }
+
+}

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

@@ -25,6 +25,9 @@ public interface BpmErrorCodeConstants {
     ErrorCode MODEL_KEY_EXISTS = new ErrorCode(1009002000, "已经存在流程标识为【{}】的流程");
     ErrorCode MODEL_NOT_EXISTS = new ErrorCode(1009002001, "流程模型不存在");
     ErrorCode MODEL_KEY_VALID = new ErrorCode(1009002002, "流程标识格式不正确,需要以字母或下划线开头,后接任意字母、数字、中划线、下划线、句点!");
+    ErrorCode MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG = new ErrorCode(1009002003, "部署流程失败,原因:流程表单未配置,请点击【修改流程】按钮进行配置");
+    ErrorCode MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG = new ErrorCode(1009002004, "部署流程失败," +
+            "原因:用户任务({})未配置分配规则,请点击【修改流程】按钮进行配置");
 
     // ========== 流程定义 1-009-003-000 ==========
     ErrorCode PROCESS_DEFINITION_KEY_NOT_MATCH = new ErrorCode(1009003000, "流程定义的标识期望是({}),当前是({}),请修改 BPMN 流程图");
@@ -37,11 +40,22 @@ public interface BpmErrorCodeConstants {
     ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS = new ErrorCode(1009004001, "流程取消失败,流程不处于运行中");
     ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF = new ErrorCode(1009004002, "流程取消失败,该流程不是你发起的");
 
-    // ========== 流程实例 1-009-005-000 ==========
+    // ========== 流程任务 1-009-005-000 ==========
     ErrorCode TASK_COMPLETE_FAIL_NOT_EXISTS = new ErrorCode(1009004000, "审批任务失败,原因:该任务不处于未审批");
 
+    // ========== 流程任务分配规则 1-009-006-000 ==========
+    ErrorCode TASK_ASSIGN_RULE_EXISTS = new ErrorCode(1009006000, "流程({}) 的任务({}) 已经存在分配规则");
+    ErrorCode TASK_ASSIGN_RULE_NOT_EXISTS = new ErrorCode(1009006001, "流程任务分配规则不存在");
+    ErrorCode TASK_UPDATE_FAIL_NOT_MODEL = new ErrorCode(1009006002, "只有流程模型的任务分配规则,才允许被修改");
+    ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1009006003, "操作失败,原因:找不到任务的审批人!");
+    ErrorCode TASK_ASSIGN_SCRIPT_NOT_EXISTS = new ErrorCode(1009006004, "操作失败,原因:任务分配脚本({}) 不存在");
+
     // ========== 动态表单模块 1-009-010-000 ==========
     ErrorCode FORM_NOT_EXISTS = new ErrorCode(1009010000, "动态表单不存在");
     ErrorCode FORM_FIELD_REPEAT = new ErrorCode(1009010000, "表单项({}) 和 ({}) 使用了相同的字段名({})");
 
+    // ========== 用户组模块 1-009-011-000 ==========
+    ErrorCode USER_GROUP_NOT_EXISTS = new ErrorCode(1009011000, "用户组不存在");
+    ErrorCode USER_GROUP_IS_DISABLE = new ErrorCode(1009011001, "名字为【{}】的用户组已被禁用");
+
 }

+ 21 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/definition/BpmModelFormTypeEnum.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.enums.definition;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * BPM 模型的表单类型的枚举
+ *
+ * @author 芋道源码
+ */
+@Getter
+@AllArgsConstructor
+public enum BpmModelFormTypeEnum {
+
+    NORMAL(10, "流程表单"), // 对应 BpmFormDO
+    CUSTOM(20, "业务表单") // 业务自己定义的表单,自己进行数据的存储
+    ;
+
+    private final Integer type;
+    private final String desc;
+}

+ 37 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/definition/BpmTaskAssignRuleTypeEnum.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.enums.definition;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * BPM 任务分配规则的类型枚举
+ *
+ * @author 芋道源码
+ */
+@Getter
+@AllArgsConstructor
+public enum BpmTaskAssignRuleTypeEnum {
+
+    ROLE(10, "角色"),
+
+    DEPT_MEMBER(20, "部门的成员"), // 包括负责人
+    DEPT_LEADER(21, "部门的负责人"),
+    POST(22, "岗位"),
+
+    USER(30, "用户"),
+
+    USER_GROUP(40, "用户组"),
+
+    SCRIPT(50, "自定义脚本"), // 例如说,发起人所在部门的领导、发起人所在部门的领导的领导
+    ;
+
+    /**
+     * 类型
+     */
+    private final Integer type;
+    /**
+     * 描述
+     */
+    private final String desc;
+
+}

+ 28 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/definition/BpmTaskRuleScriptEnum.java

@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.enums.definition;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * BPM 任务规则的脚本枚举
+ * 目前暂时通过 TODO 硬编码,未来可以考虑 Groovy 动态脚本的方式
+ *
+ * @author 芋道源码
+ */
+@Getter
+@AllArgsConstructor
+public enum BpmTaskRuleScriptEnum {
+
+    ONE(1L, ""),
+    TWO(2L, "");
+
+    /**
+     * 脚本编号
+     */
+    private final Long id;
+    /**
+     * 脚本描述
+     */
+    private final String desc;
+
+}

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

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

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

@@ -0,0 +1,70 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.config;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.BpmActivityBehaviorFactory;
+import cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.script.BpmTaskAssignScript;
+import cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.listener.BpmTackActivitiEventListener;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmTaskAssignRuleService;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmUserGroupService;
+import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService;
+import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
+import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
+import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.activiti.spring.boot.ProcessEngineAutoConfiguration.BEHAVIOR_FACTORY_MAPPING_CONFIGURER;
+
+/**
+ * BPM 模块的 Activiti 配置类
+ */
+@Configuration
+public class BpmActivitiConfiguration {
+
+    /**
+     * BPM 模块的 ProcessEngineConfigurationConfigurer 实现类,主要设置各种监听器
+     */
+    @Bean
+    public ProcessEngineConfigurationConfigurer bpmProcessEngineConfigurationConfigurer(
+            BpmTackActivitiEventListener taskActivitiEventListener) {
+        return configuration -> {
+            // 注册监听器,例如说 BpmActivitiEventListener
+            configuration.setEventListeners(Collections.singletonList(taskActivitiEventListener));
+        };
+    }
+
+    /**
+     * 用于设置自定义的 ActivityBehaviorFactory 实现的 ProcessEngineConfigurationConfigurer 实现类
+     *
+     * 目的:覆盖 {@link org.activiti.spring.boot.ProcessEngineAutoConfiguration} 的
+     *      defaultActivityBehaviorFactoryMappingConfigurer 方法创建的 Bean
+     */
+    @Bean(name = BEHAVIOR_FACTORY_MAPPING_CONFIGURER)
+    public ProcessEngineConfigurationConfigurer defaultActivityBehaviorFactoryMappingConfigurer(
+            BpmActivityBehaviorFactory bpmActivityBehaviorFactory) {
+        return configuration -> {
+            // 设置 ActivityBehaviorFactory 实现类,用于流程任务的审核人的自定义
+            configuration.setActivityBehaviorFactory(bpmActivityBehaviorFactory);
+        };
+    }
+
+    @Bean
+    public BpmActivityBehaviorFactory bpmActivityBehaviorFactory(BpmTaskAssignRuleService taskRuleService,
+                                                                 SysPermissionService permissionService,
+                                                                 SysDeptService deptService,
+                                                                 BpmUserGroupService userGroupService,
+                                                                 SysUserService userService,
+                                                                 List<BpmTaskAssignScript> scripts) {
+        BpmActivityBehaviorFactory bpmActivityBehaviorFactory = new BpmActivityBehaviorFactory();
+        bpmActivityBehaviorFactory.setBpmTaskRuleService(taskRuleService);
+        bpmActivityBehaviorFactory.setPermissionService(permissionService);
+        bpmActivityBehaviorFactory.setDeptService(deptService);
+        bpmActivityBehaviorFactory.setUserGroupService(userGroupService);
+        bpmActivityBehaviorFactory.setUserService(userService);
+        bpmActivityBehaviorFactory.setScripts(scripts);
+        return bpmActivityBehaviorFactory;
+    }
+
+}

+ 60 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/behavior/BpmActivityBehaviorFactory.java

@@ -0,0 +1,60 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.script.BpmTaskAssignScript;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmTaskAssignRuleService;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmUserGroupService;
+import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService;
+import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
+import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.Setter;
+import lombok.ToString;
+import org.activiti.bpmn.model.UserTask;
+import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
+import org.activiti.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFactory;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 自定义的 ActivityBehaviorFactory 实现类,目的如下:
+ * 1. 自定义 {@link #createUserTaskActivityBehavior(UserTask)}:实现自定义的流程任务的 assignee 负责人的分配
+ *
+ * @author 芋道源码
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory {
+
+    @Setter
+    private BpmTaskAssignRuleService bpmTaskRuleService;
+    @Setter
+    private SysPermissionService permissionService;
+    @Setter
+    private SysDeptService deptService;
+    @Setter
+    private BpmUserGroupService userGroupService;
+    @Setter
+    private SysUserService userService;
+    @Setter
+    private List<BpmTaskAssignScript> scripts;
+
+    @Override
+    public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) {
+        BpmUserTaskActivitiBehavior userTaskActivityBehavior = new BpmUserTaskActivitiBehavior(userTask);
+        userTaskActivityBehavior.setBpmTaskRuleService(bpmTaskRuleService);
+        userTaskActivityBehavior.setPermissionService(permissionService);
+        userTaskActivityBehavior.setDeptService(deptService);
+        userTaskActivityBehavior.setUserGroupService(userGroupService);
+        userTaskActivityBehavior.setUserService(userService);
+        userTaskActivityBehavior.setScripts(scripts);
+        return userTaskActivityBehavior;
+    }
+
+    // TODO 芋艿:并行任务 ParallelMultiInstanceBehavior
+
+    // TODO 芋艿:并行任务 SequentialMultiInstanceBehavior
+
+}

+ 195 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/behavior/BpmUserTaskActivitiBehavior.java

@@ -0,0 +1,195 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmUserGroupDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
+import cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.script.BpmTaskAssignScript;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmTaskAssignRuleService;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmUserGroupService;
+import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO;
+import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService;
+import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
+import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
+import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import com.google.common.annotations.VisibleForTesting;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.activiti.bpmn.model.UserTask;
+import org.activiti.engine.ActivitiException;
+import org.activiti.engine.delegate.DelegateExecution;
+import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
+import org.activiti.engine.impl.el.ExpressionManager;
+import org.activiti.engine.impl.persistence.entity.TaskEntity;
+import org.activiti.engine.impl.persistence.entity.TaskEntityManager;
+
+import java.util.*;
+
+import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.TASK_ASSIGN_SCRIPT_NOT_EXISTS;
+import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.TASK_CREATE_FAIL_NO_CANDIDATE_USER;
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.*;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
+
+/**
+ * 自定义的流程任务的 assignee 负责人的分配
+ *
+ * @author 芋道源码
+ */
+@Slf4j
+public class BpmUserTaskActivitiBehavior extends UserTaskActivityBehavior {
+
+    @Setter
+    private BpmTaskAssignRuleService bpmTaskRuleService;
+    @Setter
+    private SysPermissionService permissionService;
+    @Setter
+    private SysDeptService deptService;
+    @Setter
+    private BpmUserGroupService userGroupService;
+    @Setter
+    private SysUserService userService;
+    /**
+     * 任务分配脚本
+     */
+    private Map<Long, BpmTaskAssignScript> scriptMap = Collections.emptyMap();
+
+    public BpmUserTaskActivitiBehavior(UserTask userTask) {
+        super(userTask);
+    }
+
+    public void setScripts(List<BpmTaskAssignScript> scripts) {
+        this.scriptMap = convertMap(scripts, script -> script.getEnum().getId());
+    }
+
+    @Override
+    protected void handleAssignments(TaskEntityManager taskEntityManager,
+                                     String assignee, String owner, List<String> candidateUsers, List<String> candidateGroups,
+                                     TaskEntity task, ExpressionManager expressionManager, DelegateExecution execution) {
+        // 获得任务的规则
+        BpmTaskAssignRuleDO rule = getTaskRule(task);
+        // 获得任务的候选用户们
+        Set<Long> candidateUserIds = calculateTaskCandidateUsers(task, rule);
+        // 设置负责人
+        Long assigneeUserId = chooseTaskAssignee(candidateUserIds);
+        taskEntityManager.changeTaskAssignee(task, String.valueOf(assigneeUserId));
+        // 设置候选人们
+        candidateUserIds.remove(assigneeUserId); // 已经成为负责人了,就不要在扮演候选人了
+        if (CollUtil.isNotEmpty(candidateUserIds)) {
+            task.addCandidateUsers(convertSet(candidateUserIds, String::valueOf));
+        }
+    }
+
+    private BpmTaskAssignRuleDO getTaskRule(TaskEntity task) {
+        List<BpmTaskAssignRuleDO> taskRules = bpmTaskRuleService.getTaskAssignRuleListByProcessDefinitionId(task.getProcessDefinitionId(),
+                task.getTaskDefinitionKey());
+        if (CollUtil.isEmpty(taskRules)) {
+            throw new ActivitiException(StrUtil.format("流程任务({}/{}/{}) 找不到符合的任务规则",
+                    task.getId(), task.getProcessDefinitionId(), task.getTaskDefinitionKey()));
+        }
+        if (taskRules.size() > 1) {
+            throw new ActivitiException(StrUtil.format("流程任务({}/{}/{}) 找到过多任务规则({})",
+                    task.getId(), task.getProcessDefinitionId(), task.getTaskDefinitionKey(), taskRules.size()));
+        }
+        return taskRules.get(0);
+    }
+
+    private Long chooseTaskAssignee(Set<Long> candidateUserIds) {
+        // TODO 芋艿:未来可以优化下,改成轮询的策略
+        int index = RandomUtil.randomInt(candidateUserIds.size());
+        return CollUtil.get(candidateUserIds, index);
+    }
+
+    @VisibleForTesting
+    Set<Long> calculateTaskCandidateUsers(TaskEntity task, BpmTaskAssignRuleDO rule) {
+        Set<Long> assigneeUserIds = null;
+        if (Objects.equals(BpmTaskAssignRuleTypeEnum.ROLE.getType(), rule.getType())) {
+            assigneeUserIds = calculateTaskCandidateUsersByRole(task, rule);
+        } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), rule.getType())) {
+            assigneeUserIds = calculateTaskCandidateUsersByDeptMember(task, rule);
+        } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), rule.getType())) {
+            assigneeUserIds = calculateTaskCandidateUsersByDeptLeader(task, rule);
+        } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.POST.getType(), rule.getType())) {
+            assigneeUserIds = calculateTaskCandidateUsersByPost(task, rule);
+        } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER.getType(), rule.getType())) {
+            assigneeUserIds = calculateTaskCandidateUsersByUser(task, rule);
+        } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), rule.getType())) {
+            assigneeUserIds = calculateTaskCandidateUsersByUserGroup(task, rule);
+        } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), rule.getType())) {
+            assigneeUserIds = calculateTaskCandidateUsersByScript(task, rule);
+        }
+
+        // 移除被禁用的用户
+        removeDisableUsers(assigneeUserIds);
+        // 如果候选人为空,抛出异常 TODO 芋艿:没候选人的策略选择。1 - 挂起;2 - 直接结束;3 - 强制一个兜底人
+        if (CollUtil.isEmpty(assigneeUserIds)) {
+            log.error("[calculateTaskCandidateUsers][流程任务({}/{}/{}) 任务规则({}) 找不到候选人]",
+                    task.getId(), task.getProcessDefinitionId(), task.getTaskDefinitionKey(), toJsonString(rule));
+            throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER);
+        }
+        return assigneeUserIds;
+    }
+
+    private Set<Long> calculateTaskCandidateUsersByRole(TaskEntity task, BpmTaskAssignRuleDO rule) {
+        return permissionService.getUserRoleIdListByRoleIds(rule.getOptions());
+    }
+
+    private Set<Long> calculateTaskCandidateUsersByDeptMember(TaskEntity task, BpmTaskAssignRuleDO rule) {
+        List<SysUserDO> users = userService.getUsersByDeptIds(rule.getOptions());
+        return convertSet(users, SysUserDO::getId);
+    }
+
+    private Set<Long> calculateTaskCandidateUsersByDeptLeader(TaskEntity task, BpmTaskAssignRuleDO rule) {
+        List<SysDeptDO> depts = deptService.getDepts(rule.getOptions());
+        return convertSet(depts, SysDeptDO::getLeaderUserId);
+    }
+
+    private Set<Long> calculateTaskCandidateUsersByPost(TaskEntity task, BpmTaskAssignRuleDO rule) {
+        List<SysUserDO> users = userService.getUsersByPostIds(rule.getOptions());
+        return convertSet(users, SysUserDO::getId);
+    }
+
+    private Set<Long> calculateTaskCandidateUsersByUser(TaskEntity task, BpmTaskAssignRuleDO rule) {
+        return rule.getOptions();
+    }
+
+    private Set<Long> calculateTaskCandidateUsersByUserGroup(TaskEntity task, BpmTaskAssignRuleDO rule) {
+        List<BpmUserGroupDO> userGroups = userGroupService.getUserGroupList(rule.getOptions());
+        Set<Long> userIds = new HashSet<>();
+        userGroups.forEach(bpmUserGroupDO -> userIds.addAll(bpmUserGroupDO.getMemberUserIds()));
+        return userIds;
+    }
+
+    private Set<Long> calculateTaskCandidateUsersByScript(TaskEntity task, BpmTaskAssignRuleDO rule) {
+        // 获得对应的脚本
+        List<BpmTaskAssignScript> scripts = new ArrayList<>(rule.getOptions().size());
+        rule.getOptions().forEach(id -> {
+            BpmTaskAssignScript script = scriptMap.get(id);
+            if (script == null) {
+                throw exception(TASK_ASSIGN_SCRIPT_NOT_EXISTS, id);
+            }
+            scripts.add(script);
+        });
+        // 逐个计算任务
+        Set<Long> userIds = new HashSet<>();
+        scripts.forEach(script -> CollUtil.addAll(userIds, script.calculateTaskCandidateUsers(task)));
+        return userIds;
+    }
+
+    @VisibleForTesting
+    void removeDisableUsers(Set<Long> assigneeUserIds) {
+        if (CollUtil.isEmpty(assigneeUserIds)) {
+            return;
+        }
+        Map<Long, SysUserDO> userMap = userService.getUserMap(assigneeUserIds);
+        assigneeUserIds.removeIf(id -> {
+            SysUserDO user = userMap.get(id);
+            return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus());
+        });
+    }
+
+}

+ 7 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/behavior/package-info.java

@@ -0,0 +1,7 @@
+/**
+ * 拓展 {@link org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior} 实现,基于 {@link cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO} 实现自定义的任务分配规则。
+ * 原因:BPMN 默认的 assign、candidateUsers、candidateGroups 拓展起来有一定的难度,所以选择放弃它们,使用自己定义的规则。
+ *
+ * @author 芋道源码
+ */
+package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior;

+ 34 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/behavior/script/BpmTaskAssignScript.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.script;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmTaskRuleScriptEnum;
+import org.activiti.engine.impl.persistence.entity.TaskEntity;
+
+import java.util.List;
+
+/**
+ * Bpm 任务分配的自定义 Script 脚本
+ * 使用场景:
+ * 1. 设置审批人为发起人
+ * 2. 设置审批人为发起人的 Leader
+ * 3. 甚至审批人为发起人的 Leader 的 Leader
+ *
+ * @author 芋道源码
+ */
+public interface BpmTaskAssignScript {
+
+    /**
+     * 基于流程任务,获得任务的候选用户们
+     *
+     * @param task 任务
+     * @return 候选人用户的编号数组
+     */
+    List<Long> calculateTaskCandidateUsers(TaskEntity task);
+
+    /**
+     * 获得枚举值
+     *
+     * @return 枚举值
+     */
+    BpmTaskRuleScriptEnum getEnum();
+
+}

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/listener/BpmProcessInstanceEventListener.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/listener/BpmProcessInstanceEventListener.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.service.task.listener;
+package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.listener;
 
 import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmProcessInstanceService;

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/listener/BpmTackActivitiEventListener.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/listener/BpmTackActivitiEventListener.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.service.task.listener;
+package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.listener;
 
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;

+ 15 - 4
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/listener/BpmTaskEventListener.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/listener/BpmTaskEventListener.java

@@ -1,10 +1,14 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.service.task.listener;
+package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.listener;
 
 import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmTaskExtDO;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmTaskService;
+import org.activiti.api.model.shared.event.RuntimeEvent;
+import org.activiti.api.process.model.ProcessInstance;
+import org.activiti.api.process.model.events.ProcessRuntimeEvent;
 import org.activiti.api.task.model.Task;
 import org.activiti.api.task.model.events.TaskRuntimeEvent;
 import org.activiti.api.task.runtime.events.listener.TaskEventListener;
+import org.activiti.api.task.runtime.events.listener.TaskRuntimeEventListener;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Component;
 
@@ -16,15 +20,22 @@ import javax.annotation.Resource;
  * @author 芋道源码
  */
 @Component
-public class BpmTaskEventListener<T extends TaskRuntimeEvent<? extends Task>>
-        implements TaskEventListener<T> {
+public class BpmTaskEventListener<T extends RuntimeEvent<?, ?>>
+        implements TaskRuntimeEventListener<T> {
 
     @Resource
     @Lazy // 解决循环依赖
     private BpmTaskService taskService;
 
     @Override
-    public void onEvent(T event) {
+    @SuppressWarnings("unchecked")
+    public void onEvent(T rawEvent) {
+        // 由于 TaskRuntimeEventListener 无法保证只监听 TaskRuntimeEvent 事件,所以通过这样的方式
+        if (!(rawEvent instanceof TaskRuntimeEvent)) {
+            return;
+        }
+        TaskRuntimeEvent<Task> event = (TaskRuntimeEvent<Task>) rawEvent;
+
         // 创建时,插入拓展表
         if (event.getEventType() == TaskRuntimeEvent.TaskEvents.TASK_CREATED) {
             taskService.createTaskExt(event.getEntity());

+ 7 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/listener/package-info.java

@@ -0,0 +1,7 @@
+/**
+ * 自定义各种 Activiti 的监听器,实现流程示例、流程任务的拓展表信息的同步
+ * 例如说,{@link org.activiti.api.task.model.Task} 新建时,我们也要新建对应的 {@link cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmTaskExtDO} 记录
+ *
+ * @author 芋道源码
+ */
+package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.listener;

+ 0 - 62
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/config/UserGroupManagerService.java

@@ -1,62 +0,0 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.service.config;
-
-
-import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysPostService;
-import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
-import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
-import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
-import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
-import cn.iocoder.yudao.framework.security.core.LoginUser;
-import org.activiti.api.runtime.shared.identity.UserGroupManager;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.stereotype.Service;
-
-
-import javax.annotation.Resource;
-import java.util.*;
-import java.util.stream.Collectors;
-
-import static java.util.Collections.singleton;
-
-@Service
-public class UserGroupManagerService implements UserGroupManager {
-
-    @Resource
-    private  UserDetailsService userDetailsService;
-
-    @Resource
-    private SysUserService userService;
-
-    @Resource
-    private SysPostService  sysPostService;
-
-    /**
-     * 暂时使用岗位来代替
-     * @param userId
-     * @return
-     */
-    @Override
-    public List<String> getUserGroups(String userId) {
-//        final LoginUser loginUser = (LoginUser) userDetailsService.loadUserByUsername(userId);
-//        final Long id = loginUser.getId();
-        final SysUserDO user = userService.getUserByUsername(userId);
-        return  sysPostService.getPosts(user.getPostIds()).stream().map(post -> post.getCode()).collect(Collectors.toList());
-
-    }
-
-    @Override
-    public List<String> getUserRoles(String userId) {
-       return Arrays.asList("ROLE_ACTIVITI_USER");
-    }
-
-    @Override
-    public List<String> getGroups() {
-        throw new UnsupportedOperationException("getGroups is now un supported");
-    }
-
-    @Override
-    public List<String> getUsers() {
-        throw new UnsupportedOperationException("getGroups is now un supported");
-    }
-}

+ 0 - 31
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/config/UserGroupsProvider.java

@@ -1,31 +0,0 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.service.config;
-
-import cn.iocoder.yudao.framework.security.core.LoginUser;
-import org.activiti.api.runtime.shared.security.PrincipalGroupsProvider;
-import org.springframework.security.core.Authentication;
-import org.springframework.stereotype.Service;
-
-import java.security.Principal;
-import java.util.Collections;
-import java.util.List;
-
-@Service
-public class UserGroupsProvider implements PrincipalGroupsProvider {
-
-    @Override
-    public List<String> getGroups(Principal principal) {
-
-        if(principal instanceof Authentication){
-            Authentication authentication = (Authentication) principal;
-            final Object user = authentication.getPrincipal();
-            if(  user instanceof LoginUser){
-                return ((LoginUser) user).getGroups();
-            }else{
-                return Collections.emptyList();
-            }
-        }else{
-            return Collections.emptyList();
-        }
-
-    }
-}

+ 5 - 6
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/form/BpmFormService.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/BpmFormService.java

@@ -1,13 +1,12 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.service.form;
+package cn.iocoder.yudao.adminserver.modules.bpm.service.definition;
 
 import cn.hutool.core.collection.CollUtil;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormCreateReqVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormPageReqVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormUpdateReqVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormCreateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormPageReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormUpdateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmFormDO;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
-import org.activiti.engine.repository.Model;
 
 import javax.validation.Valid;
 import java.util.Collection;

+ 13 - 3
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/model/BpmModelService.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/BpmModelService.java

@@ -1,7 +1,8 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.service.model;
+package cn.iocoder.yudao.adminserver.modules.bpm.service.definition;
 
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo.*;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model.*;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import org.activiti.bpmn.model.BpmnModel;
 
 import javax.validation.Valid;
 
@@ -32,9 +33,10 @@ public interface BpmModelService {
      * 创建流程模型
      *
      * @param modelVO 创建信息
+     * @param bpmnXml BPMN XML
      * @return 创建的流程模型的编号
      */
-    String createModel(@Valid BpmModelCreateReqVO modelVO);
+    String createModel(@Valid BpmModelCreateReqVO modelVO, String bpmnXml);
 
     /**
      * 修改流程模型
@@ -65,4 +67,12 @@ public interface BpmModelService {
      */
     void updateModelState(String id, Integer state);
 
+    /**
+     * 获得流程模型编号对应的 BPMN Model
+     *
+     * @param id 流程模型编号
+     * @return BPMN Model
+     */
+    BpmnModel getBpmnModel(String id);
+
 }

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

@@ -1,9 +1,9 @@
 package cn.iocoder.yudao.adminserver.modules.bpm.service.definition;
 
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionListReqVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageItemRespVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageReqVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionListReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionPageReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionRespVO;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmDefinitionCreateReqDTO;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;

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

@@ -0,0 +1,71 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.service.definition;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
+import org.activiti.engine.repository.ProcessDefinition;
+import org.springframework.lang.Nullable;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * BPM 任务分配规则 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface BpmTaskAssignRuleService {
+
+    /**
+     * 获得流程定义的任务分配规则数组
+     *
+     * @param processDefinitionId 流程定义的编号
+     * @param taskDefinitionKey 流程任务定义的 Key。允许空
+     * @return 任务规则数组
+     */
+    List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId,
+                                                                         @Nullable String taskDefinitionKey);
+
+    /**
+     * 获得流程模型的任务规则数组
+     *
+     * @param modelId 流程模型的编号
+     * @return 任务规则数组
+     */
+    List<BpmTaskAssignRuleDO> getTaskAssignRuleListByModelId(String modelId);
+
+    /**
+     * 获得流程定义的任务分配规则数组
+     *
+     * @param modelId 流程模型的编号
+     * @param processDefinitionId 流程定义的编号
+     * @return 任务规则数组
+     */
+    List<BpmTaskAssignRuleRespVO> getTaskAssignRuleList(String modelId, String processDefinitionId);
+
+    /**
+     * 创建任务分配规则
+     *
+     * @param reqVO 创建信息
+     * @return 规则编号
+     */
+    Long createTaskAssignRule(@Valid BpmTaskAssignRuleCreateReqVO reqVO);
+
+    /**
+     * 更新任务分配规则
+     *
+     * @param reqVO 创建信息
+     */
+    void updateTaskAssignRule(@Valid BpmTaskAssignRuleUpdateReqVO reqVO);
+
+    /**
+     * 将流程流程模型的任务分配规则,复制一份给流程定义
+     * 目的:每次流程模型部署时,都会生成一个新的流程定义,此时考虑到每次部署的流程不可变性,所以需要复制一份给该流程定义
+     *
+     * @param fromModelId 流程模型编号
+     * @param toProcessDefinitionId 流程定义编号
+     */
+    void copyTaskAssignRules(String fromModelId, String toProcessDefinitionId);
+
+}

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

@@ -0,0 +1,82 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.service.definition;
+
+import java.util.*;
+import javax.validation.*;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupCreateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupPageReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupUpdateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmUserGroupDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+/**
+ * 用户组 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface BpmUserGroupService {
+
+    /**
+     * 创建用户组
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createUserGroup(@Valid BpmUserGroupCreateReqVO createReqVO);
+
+    /**
+     * 更新用户组
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateUserGroup(@Valid BpmUserGroupUpdateReqVO updateReqVO);
+
+    /**
+     * 删除用户组
+     *
+     * @param id 编号
+     */
+    void deleteUserGroup(Long id);
+
+    /**
+     * 获得用户组
+     *
+     * @param id 编号
+     * @return 用户组
+     */
+    BpmUserGroupDO getUserGroup(Long id);
+
+    /**
+     * 获得用户组列表
+     *
+     * @param ids 编号
+     * @return 用户组列表
+     */
+    List<BpmUserGroupDO> getUserGroupList(Collection<Long> ids);
+
+    /**
+     * 获得指定状态的用户组列表
+     *
+     * @param status 状态
+     * @return 用户组列表
+     */
+    List<BpmUserGroupDO> getUserGroupListByStatus(Integer status);
+
+    /**
+     * 获得用户组分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 用户组分页
+     */
+    PageResult<BpmUserGroupDO> getUserGroupPage(BpmUserGroupPageReqVO pageReqVO);
+
+    /**
+     * 校验用户组们是否有效。如下情况,视为无效:
+     * 1. 用户组编号不存在
+     * 2. 用户组被禁用
+     *
+     * @param ids 用户组编号数组
+     */
+    void validUserGroups(Set<Long> ids);
+
+}

+ 31 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/dto/BpmDefinitionCreateReqDTO.java

@@ -1,8 +1,10 @@
 package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto;
 
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmModelFormTypeEnum;
 import lombok.Data;
 
 import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
 
 /**
  * 流程定义创建 Request DTO
@@ -10,6 +12,13 @@ import javax.validation.constraints.NotEmpty;
 @Data
 public class BpmDefinitionCreateReqDTO {
 
+    // ========== 模型相关 ==========
+
+    /**
+     * 流程模型的编号
+     */
+    @NotEmpty(message = "流程模型编号不能为空")
+    private String modelId;
     /**
      * 流程标识
      */
@@ -35,9 +44,30 @@ public class BpmDefinitionCreateReqDTO {
      */
     @NotEmpty(message = "BPMN XML 不能为空")
     private String bpmnXml;
+
+    // ========== 表单相关 ==========
+
+    /**
+     * 表单类型
+     */
+    @NotNull(message = "表单类型不能为空")
+    private Integer formType;
     /**
-     * 动态表单编号,允许空
+     * 动态表单编号
+     * 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时
      */
     private Long formId;
+    /**
+     * 自定义表单的提交路径,使用 Vue 的路由地址
+     * 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时
+     */
+    private String formCustomCreatePath;
+    /**
+     * 自定义表单的查看路径,使用 Vue 的路由地址
+     * 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时
+     */
+    private String formCustomViewPath;
+
+
 
 }

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/form/dto/BpmFormFieldRespDTO.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/dto/BpmFormFieldRespDTO.java

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.service.form.dto;
+package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.Data;

+ 39 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/dto/BpmModelMetaInfoRespDTO.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto;
+
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmModelFormTypeEnum;
+import lombok.Data;
+
+/**
+ * BPM 流程 MetaInfo Response DTO
+ * 主要用于 {@link org.activiti.engine.repository.Model#setMetaInfo(String)} 的存储
+ *
+ * @author 芋道源码
+ */
+@Data
+public class BpmModelMetaInfoRespDTO {
+
+    /**
+     * 流程描述
+     */
+    private String description;
+    /**
+     * 表单类型
+     */
+    private Integer formType;
+    /**
+     * 表单编号
+     * 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时
+     */
+    private Long formId;
+    /**
+     * 自定义表单的提交路径,使用 Vue 的路由地址
+     * 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时
+     */
+    private String formCustomCreatePath;
+    /**
+     * 自定义表单的查看路径,使用 Vue 的路由地址
+     * 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时
+     */
+    private String formCustomViewPath;
+
+}

+ 9 - 9
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/form/impl/BpmFormServiceImpl.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmFormServiceImpl.java

@@ -1,14 +1,14 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.service.form.impl;
+package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.impl;
 
 import cn.hutool.core.lang.Assert;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormCreateReqVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormPageReqVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.form.vo.BpmFormUpdateReqVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.convert.form.BpmFormConvert;
-import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
-import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.form.BpmFormMapper;
-import cn.iocoder.yudao.adminserver.modules.bpm.service.form.BpmFormService;
-import cn.iocoder.yudao.adminserver.modules.bpm.service.form.dto.BpmFormFieldRespDTO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormCreateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormPageReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.form.BpmFormUpdateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmFormConvert;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmFormDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition.BpmFormMapper;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmFormService;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmFormFieldRespDTO;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 import org.springframework.stereotype.Service;

+ 90 - 23
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/model/impl/BpmModelServiceImpl.java → yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmModelServiceImpl.java

@@ -1,26 +1,35 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.service.model.impl;
+package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.impl;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.StrUtil;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.model.vo.*;
-import cn.iocoder.yudao.adminserver.modules.bpm.convert.model.BpmModelConvert;
-import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model.*;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmModelConvert;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmFormDO;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmTaskAssignRuleService;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmDefinitionCreateReqDTO;
-import cn.iocoder.yudao.adminserver.modules.bpm.service.form.BpmFormService;
-import cn.iocoder.yudao.adminserver.modules.bpm.service.model.BpmModelService;
-import cn.iocoder.yudao.adminserver.modules.bpm.service.model.dto.BpmModelMetaInfoRespDTO;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmFormService;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmModelService;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmModelMetaInfoRespDTO;
+import cn.iocoder.yudao.framework.activiti.core.util.ActivitiUtils;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
 import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
 import lombok.extern.slf4j.Slf4j;
+import org.activiti.bpmn.converter.BpmnXMLConverter;
+import org.activiti.bpmn.model.BpmnModel;
 import org.activiti.engine.RepositoryService;
 import org.activiti.engine.impl.persistence.entity.SuspensionState;
+import org.activiti.engine.impl.util.io.StringStreamSource;
 import org.activiti.engine.repository.Deployment;
 import org.activiti.engine.repository.Model;
 import org.activiti.engine.repository.ModelQuery;
 import org.activiti.engine.repository.ProcessDefinition;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.ObjectUtils;
@@ -31,9 +40,11 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Consumer;
 
 import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.*;
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
 
 /**
@@ -50,9 +61,12 @@ public class BpmModelServiceImpl implements BpmModelService {
     @Resource
     private RepositoryService repositoryService;
     @Resource
-    private BpmFormService bpmFormService;
+    private BpmFormService formService;
     @Resource
-    private BpmProcessDefinitionService bpmProcessDefinitionService;
+    private BpmProcessDefinitionService processDefinitionService;
+    @Resource
+    @Lazy // 解决循环依赖
+    private BpmTaskAssignRuleService taskAssignRuleService;
 
     @Override
     public PageResult<BpmModelPageItemRespVO> getModelPage(ModelPageReqVO pageVO) {
@@ -75,14 +89,14 @@ public class BpmModelServiceImpl implements BpmModelService {
             BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
             return metaInfo != null ? metaInfo.getFormId() : null;
         });
-        Map<Long, BpmFormDO> formMap = bpmFormService.getFormMap(formIds);
+        Map<Long, BpmFormDO> formMap = formService.getFormMap(formIds);
 
         // 获得 Deployment Map
         Set<String> deploymentIds = new HashSet<>();
         models.forEach(model -> CollectionUtils.addIfNotNull(deploymentIds, model.getDeploymentId()));
-        Map<String, Deployment> deploymentMap = bpmProcessDefinitionService.getDeploymentMap(deploymentIds);
+        Map<String, Deployment> deploymentMap = processDefinitionService.getDeploymentMap(deploymentIds);
         // 获得 ProcessDefinition Map
-        List<ProcessDefinition> processDefinitions = bpmProcessDefinitionService.getProcessDefinitionListByDeploymentIds(deploymentIds);
+        List<ProcessDefinition> processDefinitions = processDefinitionService.getProcessDefinitionListByDeploymentIds(deploymentIds);
         Map<String, ProcessDefinition> processDefinitionMap = convertMap(processDefinitions, ProcessDefinition::getDeploymentId);
 
         // 拼接结果
@@ -105,7 +119,7 @@ public class BpmModelServiceImpl implements BpmModelService {
 
     @Override
     @Transactional(rollbackFor = Exception.class) // 因为进行多个 activiti 操作,所以开启事务
-    public String createModel(BpmModelCreateReqVO createReqVO) {
+    public String createModel(BpmModelCreateReqVO createReqVO, String bpmnXml) {
         checkKeyNCName(createReqVO.getKey());
         // 校验流程标识已经存在
         Model keyModel = this.getModelByKey(createReqVO.getKey());
@@ -118,15 +132,14 @@ public class BpmModelServiceImpl implements BpmModelService {
         BpmModelConvert.INSTANCE.copy(model, createReqVO);
         // 保存流程定义
         repositoryService.saveModel(model);
-        // 添加 BPMN XML
-        repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(createReqVO.getBpmnXml()));
+        // 保存 BPMN XML
+        saveModelBpmnXml(model, bpmnXml);
         return model.getId();
     }
 
     @Override
     @Transactional(rollbackFor = Exception.class) // 因为进行多个 activiti 操作,所以开启事务
     public void updateModel(BpmModelUpdateReqVO updateReqVO) {
-        checkKeyNCName(updateReqVO.getKey());
         // 校验流程模型存在
         Model model = repositoryService.getModel(updateReqVO.getId());
         if (model == null) {
@@ -138,7 +151,14 @@ public class BpmModelServiceImpl implements BpmModelService {
         // 更新模型
         repositoryService.saveModel(model);
         // 更新 BPMN XML
-        repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(updateReqVO.getBpmnXml()));
+        saveModelBpmnXml(model, updateReqVO.getBpmnXml());
+    }
+
+    private void saveModelBpmnXml(Model model, String bpmnXml) {
+        if (StrUtil.isEmpty(bpmnXml)) {
+            return;
+        }
+        repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(bpmnXml));
     }
 
     @Override
@@ -149,28 +169,60 @@ public class BpmModelServiceImpl implements BpmModelService {
         if (ObjectUtils.isEmpty(model)) {
             throw exception(MODEL_NOT_EXISTS);
         }
+        // 校验流程图
         byte[] bpmnBytes = repositoryService.getModelEditorSource(model.getId());
         if (bpmnBytes == null) {
             throw exception(MODEL_NOT_EXISTS);
         }
+        // TODO 芋艿:校验流程图的有效性;例如说,是否有开始的元素,是否有结束的元素;
+        // 校验表单已配
+        BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
+        if (metaInfo == null || metaInfo.getFormType() == null) {
+            throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG);
+        }
+        // 校验任务分配规则已配置
+        checkTaskAssignRuleAllConfig(id);
 
         // 创建流程定义
         BpmDefinitionCreateReqDTO definitionCreateReqDTO = BpmModelConvert.INSTANCE.convert2(model)
                 .setBpmnXml(StrUtil.utf8Str(bpmnBytes));
-        String definitionId = bpmProcessDefinitionService.createProcessDefinition(definitionCreateReqDTO);
+        String definitionId = processDefinitionService.createProcessDefinition(definitionCreateReqDTO);
 
         // 将老的流程定义进行挂起。也就是说,只有最新部署的流程定义,才可以发起任务。
         if (StrUtil.isNotEmpty(model.getDeploymentId())) {
-            ProcessDefinition oldDefinition = bpmProcessDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId());
+            ProcessDefinition oldDefinition = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId());
             if (oldDefinition != null) {
-                bpmProcessDefinitionService.updateProcessDefinitionState(oldDefinition.getId(), SuspensionState.SUSPENDED.getStateCode());
+                processDefinitionService.updateProcessDefinitionState(oldDefinition.getId(), SuspensionState.SUSPENDED.getStateCode());
             }
         }
 
         // 更新 model 的 deploymentId,进行关联
-        ProcessDefinition definition = bpmProcessDefinitionService.getProcessDefinition(definitionId);
+        ProcessDefinition definition = processDefinitionService.getProcessDefinition(definitionId);
         model.setDeploymentId(definition.getDeploymentId());
         repositoryService.saveModel(model);
+
+        // 复制任务分配规则
+        taskAssignRuleService.copyTaskAssignRules(id, definition.getId());
+    }
+
+    /**
+     * 校验流程模型的任务分配规则全部都配置了
+     * 目的:如果有规则未配置,会导致流程任务找不到负责人,进而流程无法进行下去!
+     *
+     * @param id 流程模型编号
+     */
+    private void checkTaskAssignRuleAllConfig(String id) {
+        // 一个用户任务都没配置,所以无需配置规则
+        List<BpmTaskAssignRuleRespVO> taskAssignRules = taskAssignRuleService.getTaskAssignRuleList(id, null);
+        if (CollUtil.isEmpty(taskAssignRules)) {
+            return;
+        }
+        // 校验未配置规则的任务
+        taskAssignRules.forEach(rule -> {
+            if (CollUtil.isEmpty(rule.getOptions())) {
+                throw exception(MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG, rule.getTaskDefinitionName());
+            }
+        });
     }
 
     @Override
@@ -192,13 +244,22 @@ public class BpmModelServiceImpl implements BpmModelService {
             throw exception(MODEL_NOT_EXISTS);
         }
         // 校验流程定义存在
-        ProcessDefinition definition = bpmProcessDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId());
+        ProcessDefinition definition = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId());
         if (definition == null) {
             throw exception(PROCESS_DEFINITION_NOT_EXISTS);
         }
 
         // 更新状态
-        bpmProcessDefinitionService.updateProcessDefinitionState(definition.getId(), state);
+        processDefinitionService.updateProcessDefinitionState(definition.getId(), state);
+    }
+
+    @Override
+    public BpmnModel getBpmnModel(String id) {
+        byte[] bpmnBytes = repositoryService.getModelEditorSource(id);
+        if (ArrayUtil.isEmpty(bpmnBytes)) {
+            return null;
+        }
+        return ActivitiUtils.buildBpmnModel(bpmnBytes);
     }
 
     private Model getModelByKey(String key) {
@@ -211,4 +272,10 @@ public class BpmModelServiceImpl implements BpmModelService {
         }
     }
 
+    public static void main(String[] args) {
+        // 创建转换对象
+        BpmnXMLConverter converter = new BpmnXMLConverter();
+        BpmnModel bpmnModel = converter.convertToBpmnModel(new StringStreamSource(""), true, true);
+    }
+
 }

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

@@ -2,17 +2,17 @@ package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.impl;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.StrUtil;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionListReqVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageItemRespVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionPageReqVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.BpmProcessDefinitionRespVO;
-import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmDefinitionConvert;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionListReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionPageReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process.BpmProcessDefinitionRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmProcessDefinitionConvert;
 import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
-import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.form.BpmFormDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmFormDO;
 import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition.BpmProcessDefinitionExtMapper;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
 import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmDefinitionCreateReqDTO;
-import cn.iocoder.yudao.adminserver.modules.bpm.service.form.BpmFormService;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmFormService;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
@@ -90,7 +90,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
 
         // 拼接结果
         long definitionCount = definitionQuery.count();
-        return new PageResult<>(BpmDefinitionConvert.INSTANCE.convertList(processDefinitions, deploymentMap,
+        return new PageResult<>(BpmProcessDefinitionConvert.INSTANCE.convertList(processDefinitions, deploymentMap,
                 processDefinitionDOMap, formMap), definitionCount);
     }
 
@@ -112,7 +112,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
         Map<String, BpmProcessDefinitionExtDO> processDefinitionDOMap = CollectionUtils.convertMap(processDefinitionDOs,
                 BpmProcessDefinitionExtDO::getProcessDefinitionId);
         // 执行查询,并返回
-        return BpmDefinitionConvert.INSTANCE.convertList3(processDefinitions, processDefinitionDOMap);
+        return BpmProcessDefinitionConvert.INSTANCE.convertList3(processDefinitions, processDefinitionDOMap);
     }
 
     @Override
@@ -121,6 +121,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
         if (bpmnModel == null) {
             return null;
         }
+        // TODO 芋艿:重构到 activi util 里
         byte[] bpmnBytes = BPMN_XML_CONVERTER.convertToXML(bpmnModel);
         return StrUtil.utf8Str(bpmnBytes);
     }
@@ -179,7 +180,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
         // 创建 Deployment 部署
         Deployment deploy = repositoryService.createDeployment()
                 .key(createReqDTO.getKey()).name(createReqDTO.getName()).category(createReqDTO.getCategory())
-                .addString(createReqDTO.getName() + BPMN_FILE_SUFFIX, createReqDTO.getBpmnXml())
+                .addString(createReqDTO.getKey() + BPMN_FILE_SUFFIX, createReqDTO.getBpmnXml())
                 .deploy();
 
         // 设置 ProcessDefinition 的 category 分类
@@ -196,7 +197,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
         }
 
         // 插入拓展表
-        BpmProcessDefinitionExtDO definitionDO = BpmDefinitionConvert.INSTANCE.convert2(createReqDTO)
+        BpmProcessDefinitionExtDO definitionDO = BpmProcessDefinitionConvert.INSTANCE.convert2(createReqDTO)
                 .setProcessDefinitionId(definition.getId());
         processDefinitionMapper.insert(definitionDO);
         return definition.getId();
@@ -206,12 +207,14 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
     public void updateProcessDefinitionState(String id, Integer state) {
         // 激活
         if (Objects.equals(SuspensionState.ACTIVE.getStateCode(), state)) {
-            repositoryService.activateProcessDefinitionById(id, true, null);
+            repositoryService.activateProcessDefinitionById(id, false, null);
             return;
         }
         // 挂起
         if (Objects.equals(SuspensionState.SUSPENDED.getStateCode(), state)) {
-            repositoryService.suspendProcessDefinitionById(id, true, null);
+            // suspendProcessInstances = false,进行中的任务,不进行挂起。
+            // 原因:只要新的流程不允许发起即可,老流程继续可以执行。
+            repositoryService.suspendProcessDefinitionById(id, false, null);
             return;
         }
         log.error("[updateProcessDefinitionState][流程定义({}) 修改未知状态({})]", id, state);

+ 178 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmTaskAssignRuleServiceImpl.java

@@ -0,0 +1,178 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleRespVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmTaskAssignRuleConvert;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper;
+import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmModelService;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmTaskAssignRuleService;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmUserGroupService;
+import cn.iocoder.yudao.adminserver.modules.system.enums.SysDictTypeConstants;
+import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService;
+import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysPostService;
+import cn.iocoder.yudao.adminserver.modules.system.service.dict.SysDictDataService;
+import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysRoleService;
+import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
+import cn.iocoder.yudao.framework.activiti.core.util.ActivitiUtils;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.activiti.bpmn.model.BpmnModel;
+import org.activiti.bpmn.model.UserTask;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.*;
+import static cn.iocoder.yudao.adminserver.modules.system.enums.SysDictTypeConstants.BPM_TASK_ASSIGN_RULE_TYPE;
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+
+/**
+ * BPM 任务分配规则 Service 实现类
+ */
+@Service
+@Validated
+@Slf4j
+public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
+
+    @Resource
+    private BpmTaskAssignRuleMapper taskRuleMapper;
+
+    @Resource
+    @Lazy // 解决循环依赖
+    private BpmModelService modelService;
+    @Resource
+    @Lazy // 解决循环依赖
+    private BpmProcessDefinitionService processDefinitionService;
+    @Resource
+    private SysRoleService roleService;
+    @Resource
+    private SysDeptService deptService;
+    @Resource
+    private SysPostService postService;
+    @Resource
+    private SysUserService userService;
+    @Resource
+    private BpmUserGroupService userGroupService;
+    @Resource
+    private SysDictDataService dictDataService;
+
+    @Override
+    public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId,
+                                                                                String taskDefinitionKey) {
+        return taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, taskDefinitionKey);
+    }
+
+    @Override
+    public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByModelId(String modelId) {
+        return taskRuleMapper.selectListByModelId(modelId);
+    }
+
+    @Override
+    public List<BpmTaskAssignRuleRespVO> getTaskAssignRuleList(String modelId, String processDefinitionId) {
+        // 获得规则
+        List<BpmTaskAssignRuleDO> rules = Collections.emptyList();
+        BpmnModel model = null;
+        if (StrUtil.isNotEmpty(modelId)) {
+            rules = getTaskAssignRuleListByModelId(modelId);
+            model = modelService.getBpmnModel(modelId);
+        } else if (StrUtil.isNotEmpty(processDefinitionId)) {
+            rules = getTaskAssignRuleListByProcessDefinitionId(processDefinitionId, null);
+            model = processDefinitionService.getBpmnModel(processDefinitionId);
+        }
+        if (model == null) {
+            return Collections.emptyList();
+        }
+
+        // 获得用户任务,只有用户任务才可以设置分配规则
+        List<UserTask> userTasks = ActivitiUtils.getBpmnModelElements(model, UserTask.class);
+        if (CollUtil.isEmpty(userTasks)) {
+            return Collections.emptyList();
+        }
+
+        // 转换数据
+        return BpmTaskAssignRuleConvert.INSTANCE.convertList(userTasks, rules);
+    }
+
+    @Override
+    public Long createTaskAssignRule(BpmTaskAssignRuleCreateReqVO reqVO) {
+        // 校验参数
+        validTaskAssignRuleOptions(reqVO.getType(), reqVO.getOptions());
+        // 校验是否已经配置
+        BpmTaskAssignRuleDO existRule = taskRuleMapper.selectListByModelIdAndTaskDefinitionKey(
+                reqVO.getModelId(), reqVO.getTaskDefinitionKey());
+        if (existRule != null) {
+            throw exception(TASK_ASSIGN_RULE_EXISTS, reqVO.getModelId(), reqVO.getTaskDefinitionKey());
+        }
+
+        // 存储
+        BpmTaskAssignRuleDO rule = BpmTaskAssignRuleConvert.INSTANCE.convert(reqVO)
+                .setProcessDefinitionId(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL); // 只有流程模型,才允许新建
+        taskRuleMapper.insert(rule);
+        return rule.getId();
+    }
+
+    @Override
+    public void updateTaskAssignRule(BpmTaskAssignRuleUpdateReqVO reqVO) {
+        // 校验参数
+        validTaskAssignRuleOptions(reqVO.getType(), reqVO.getOptions());
+        // 校验是否存在
+        BpmTaskAssignRuleDO existRule = taskRuleMapper.selectById(reqVO.getId());
+        if (existRule == null) {
+            throw exception(TASK_ASSIGN_RULE_NOT_EXISTS);
+        }
+        // 只允许修改流程模型的规则
+        if (!Objects.equals(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL, existRule.getProcessDefinitionId())) {
+            throw exception(TASK_UPDATE_FAIL_NOT_MODEL);
+        }
+
+        // 执行更新
+        taskRuleMapper.updateById(BpmTaskAssignRuleConvert.INSTANCE.convert(reqVO));
+    }
+
+    @Override
+    public void copyTaskAssignRules(String fromModelId, String toProcessDefinitionId) {
+        List<BpmTaskAssignRuleRespVO> rules = getTaskAssignRuleList(fromModelId, null);
+        if (CollUtil.isEmpty(rules)) {
+            return;
+        }
+        // 开始复制
+        List<BpmTaskAssignRuleDO> newRules = BpmTaskAssignRuleConvert.INSTANCE.convertList2(rules);
+        newRules.forEach(rule -> rule.setProcessDefinitionId(toProcessDefinitionId).setId(null)
+                .setCreateTime(null).setUpdateTime(null));
+        taskRuleMapper.insertBatch(newRules);
+    }
+
+    private void validTaskAssignRuleOptions(Integer type, Set<Long> options) {
+        if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.ROLE.getType())) {
+            roleService.validRoles(options);
+        } else if (ObjectUtils.equalsAny(type, BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(),
+                BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType())) {
+            deptService.validDepts(options);
+        } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.POST.getType())) {
+            postService.validPosts(options);
+        } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.USER.getType())) {
+            userService.validUsers(options);
+        } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.USER_GROUP.getType())) {
+            userGroupService.validUserGroups(options);
+        } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.SCRIPT.getType())) {
+            dictDataService.validDictDatas(SysDictTypeConstants.BPM_TASK_ASSIGN_SCRIPT,
+                    CollectionUtils.convertSet(options, String::valueOf));
+        } else {
+            throw new IllegalArgumentException(StrUtil.format("未知的规则类型({})", type));
+        }
+    }
+
+}

+ 114 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmUserGroupServiceImpl.java

@@ -0,0 +1,114 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupCreateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupPageReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.group.BpmUserGroupUpdateReqVO;
+import cn.iocoder.yudao.adminserver.modules.bpm.convert.definition.BpmUserGroupConvert;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmUserGroupDO;
+import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition.BpmUserGroupMapper;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmUserGroupService;
+import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.USER_GROUP_IS_DISABLE;
+import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.USER_GROUP_NOT_EXISTS;
+import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.USER_IS_DISABLE;
+import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.USER_NOT_EXISTS;
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+
+/**
+ * 用户组 Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Validated
+public class BpmUserGroupServiceImpl implements BpmUserGroupService {
+
+    @Resource
+    private BpmUserGroupMapper userGroupMapper;
+
+    @Override
+    public Long createUserGroup(BpmUserGroupCreateReqVO createReqVO) {
+        // 插入
+        BpmUserGroupDO userGroup = BpmUserGroupConvert.INSTANCE.convert(createReqVO);
+        userGroupMapper.insert(userGroup);
+        // 返回
+        return userGroup.getId();
+    }
+
+    @Override
+    public void updateUserGroup(BpmUserGroupUpdateReqVO updateReqVO) {
+        // 校验存在
+        this.validateUserGroupExists(updateReqVO.getId());
+        // 更新
+        BpmUserGroupDO updateObj = BpmUserGroupConvert.INSTANCE.convert(updateReqVO);
+        userGroupMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteUserGroup(Long id) {
+        // 校验存在
+        this.validateUserGroupExists(id);
+        // 删除
+        userGroupMapper.deleteById(id);
+    }
+
+    private void validateUserGroupExists(Long id) {
+        if (userGroupMapper.selectById(id) == null) {
+            throw exception(USER_GROUP_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public BpmUserGroupDO getUserGroup(Long id) {
+        return userGroupMapper.selectById(id);
+    }
+
+    @Override
+    public List<BpmUserGroupDO> getUserGroupList(Collection<Long> ids) {
+        return userGroupMapper.selectBatchIds(ids);
+    }
+
+    @Override
+    public List<BpmUserGroupDO> getUserGroupListByStatus(Integer status) {
+        return userGroupMapper.selectListByStatus(status);
+    }
+
+    @Override
+    public PageResult<BpmUserGroupDO> getUserGroupPage(BpmUserGroupPageReqVO pageReqVO) {
+        return userGroupMapper.selectPage(pageReqVO);
+    }
+
+    @Override
+    public void validUserGroups(Set<Long> ids) {
+        if (CollUtil.isEmpty(ids)) {
+            return;
+        }
+        // 获得用户组信息
+        List<BpmUserGroupDO> userGroups = userGroupMapper.selectBatchIds(ids);
+        Map<Long, BpmUserGroupDO> userGroupMap = CollectionUtils.convertMap(userGroups, BpmUserGroupDO::getId);
+        // 校验
+        ids.forEach(id -> {
+            BpmUserGroupDO userGroup = userGroupMap.get(id);
+            if (userGroup == null) {
+                throw exception(USER_GROUP_NOT_EXISTS);
+            }
+            if (!CommonStatusEnum.ENABLE.getStatus().equals(userGroup.getStatus())) {
+                throw exception(USER_GROUP_IS_DISABLE, userGroup.getName());
+            }
+        });
+    }
+
+}

+ 0 - 23
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/model/dto/BpmModelMetaInfoRespDTO.java

@@ -1,23 +0,0 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.service.model.dto;
-
-import lombok.Data;
-
-/**
- * BPM 流程 MetaInfo Response DTO
- * 主要用于 {@link org.activiti.engine.repository.Model#setMetaInfo(String)} 的存储
- *
- * @author 芋道源码
- */
-@Data
-public class BpmModelMetaInfoRespDTO {
-
-    /**
-     * 流程描述
-     */
-    private String description;
-    /**
-     * 表单编号
-     */
-    private Long formId;
-
-}

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

@@ -87,8 +87,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
         runtimeService.setProcessInstanceName(instance.getId(), definition.getName());
 
         // TODO 芋艿:临时使用, 保证分配
-        List<Task> tasks = taskService.getTasksByProcessInstanceId(instance.getId());
-        tasks.forEach(task -> taskService.updateTaskAssign(task.getId(), userId));
+//        List<Task> tasks = taskService.getTasksByProcessInstanceId(instance.getId());
+//        tasks.forEach(task -> taskService.updateTaskAssign(task.getId(), userId));
 
         // 添加初始的评论 TODO 芋艿:在思考下
 //        Task task = taskService.createTaskQuery().processInstanceId(instance.getId()).singleResult();

+ 5 - 3
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/dept/vo/dept/SysDeptBaseVO.java

@@ -1,5 +1,7 @@
 package cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.dept;
 
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
@@ -28,8 +30,8 @@ public class SysDeptBaseVO {
     @NotNull(message = "显示顺序不能为空")
     private Integer sort;
 
-    @ApiModelProperty(value = "负责人", example = "芋道")
-    private String leader;
+    @ApiModelProperty(value = "负责人的用户编号", example = "2048")
+    private Long leaderUserId;
 
     @ApiModelProperty(value = "联系电话", example = "15601691000")
     @Size(max = 11, message = "联系电话长度不能超过11个字符")
@@ -42,7 +44,7 @@ public class SysDeptBaseVO {
 
     @ApiModelProperty(value = "状态", required = true, example = "1", notes = "见 SysCommonStatusEnum 枚举")
     @NotNull(message = "状态不能为空")
-//    @InEnum(value = SysCommonStatusEnum.class, message = "修改状态必须是 {value}")
+//    @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
     private Integer status;
 
 }

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/permission/SysPermissionController.java

@@ -59,7 +59,7 @@ public class SysPermissionController {
     @GetMapping("/list-user-roles")
 //    @RequiresPermissions("system:permission:assign-user-role")
     public CommonResult<Set<Long>> listAdminRoles(@RequestParam("userId") Long userId) {
-        return success(permissionService.listUserRoleIs(userId));
+        return success(permissionService.getUserRoleIdListByUserId(userId));
     }
 
     @ApiOperation("赋予用户角色")

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/permission/SysRoleController.java

@@ -97,7 +97,7 @@ public class SysRoleController {
     @OperateLog(type = EXPORT)
     @PreAuthorize("@ss.hasPermission('system:role:export')")
     public void export(HttpServletResponse response, @Validated SysRoleExportReqVO reqVO) throws IOException {
-        List<SysRoleDO> list = roleService.getRoles(reqVO);
+        List<SysRoleDO> list = roleService.getRoleList(reqVO);
         List<SysRoleExcelVO> data = SysRoleConvert.INSTANCE.convertList03(list);
         // 输出
         ExcelUtils.write(response, "角色数据.xls", "角色列表", SysRoleExcelVO.class, data);

+ 21 - 3
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/user/SysUserController.java

@@ -1,7 +1,10 @@
 package cn.iocoder.yudao.adminserver.modules.system.controller.user;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.dept.SysDeptListReqVO;
+import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.dept.SysDeptSimpleRespVO;
 import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.user.*;
+import cn.iocoder.yudao.adminserver.modules.system.convert.dept.SysDeptConvert;
 import cn.iocoder.yudao.adminserver.modules.system.convert.user.SysUserConvert;
 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO;
 import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService;
@@ -32,6 +35,8 @@ import java.io.IOException;
 import java.util.*;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
 
 @Api(tags = "用户")
@@ -99,7 +104,7 @@ public class SysUserController {
         }
 
         // 获得拼接需要的数据
-        Collection<Long> deptIds = CollectionUtils.convertList(pageResult.getList(), SysUserDO::getDeptId);
+        Collection<Long> deptIds = convertList(pageResult.getList(), SysUserDO::getDeptId);
         Map<Long, SysDeptDO> deptMap = deptService.getDeptMap(deptIds);
         // 拼接结果返回
         List<SysUserPageItemRespVO> userList = new ArrayList<>(pageResult.getList().size());
@@ -111,6 +116,15 @@ public class SysUserController {
         return success(new PageResult<>(userList, pageResult.getTotal()));
     }
 
+    @GetMapping("/list-all-simple")
+    @ApiOperation(value = "获取用户精简信息列表", notes = "只包含被开启的用户,主要用于前端的下拉选项")
+    public CommonResult<List<SysUserSimpleRespVO>> getSimpleUsers() {
+        // 获用户门列表,只要开启状态的
+        List<SysUserDO> list = userService.getUsersByStatus(CommonStatusEnum.ENABLE.getStatus());
+        // 排序后,返回给前端
+        return success(SysUserConvert.INSTANCE.convertList04(list));
+    }
+
     @GetMapping("/get")
     @ApiOperation("获得用户详情")
     @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@@ -129,15 +143,19 @@ public class SysUserController {
         List<SysUserDO> users = userService.getUsers(reqVO);
 
         // 获得拼接需要的数据
-        Collection<Long> deptIds = CollectionUtils.convertList(users, SysUserDO::getDeptId);
+        Collection<Long> deptIds = convertList(users, SysUserDO::getDeptId);
         Map<Long, SysDeptDO> deptMap = deptService.getDeptMap(deptIds);
+        Map<Long, SysUserDO> deptLeaderUserMap = userService.getUserMap(convertSet(deptMap.values(), SysDeptDO::getLeaderUserId));
         // 拼接数据
         List<SysUserExcelVO> excelUsers = new ArrayList<>(users.size());
         users.forEach(user -> {
             SysUserExcelVO excelVO = SysUserConvert.INSTANCE.convert02(user);
+            // 设置部门
             MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> {
                 excelVO.setDeptName(dept.getName());
-                excelVO.setDeptLeader(dept.getLeader());
+                // 设置部门负责人的名字
+                MapUtils.findAndThen(deptLeaderUserMap, dept.getLeaderUserId(),
+                        deptLeaderUser -> excelVO.setDeptLeaderNickname(deptLeaderUser.getNickname()));
             });
             excelUsers.add(excelVO);
         });

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/user/SysUserProfileController.java

@@ -65,7 +65,7 @@ public class SysUserProfileController {
         SysUserDO user = userCoreService.getUser(getLoginUserId());
         SysUserProfileRespVO resp = SysUserConvert.INSTANCE.convert03(user);
         // 获得用户角色
-        List<SysRoleDO> userRoles = roleService.getRolesFromCache(permissionService.listUserRoleIs(user.getId()));
+        List<SysRoleDO> userRoles = roleService.getRolesFromCache(permissionService.getUserRoleIdListByUserId(user.getId()));
         resp.setRoles(SysUserConvert.INSTANCE.convertList(userRoles));
         // 获得部门信息
         if (user.getDeptId() != null) {

+ 1 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/user/vo/user/SysUserExcelVO.java

@@ -47,6 +47,6 @@ public class SysUserExcelVO {
     private String deptName;
 
     @ExcelProperty("部门负责人")
-    private String deptLeader;
+    private String deptLeaderNickname;
 
 }

+ 21 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/user/vo/user/SysUserSimpleRespVO.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.user;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@ApiModel("用户精简信息 Response VO")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class SysUserSimpleRespVO {
+
+    @ApiModelProperty(value = "用户编号", required = true, example = "1024")
+    private Long id;
+
+    @ApiModelProperty(value = "用户昵称", required = true, example = "芋道")
+    private String nickname;
+
+}

+ 1 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/user/SysUserConvert.java

@@ -45,4 +45,5 @@ public interface SysUserConvert {
 
     List<SysUserProfileRespVO.SocialUser> convertList03(List<SysSocialUserDO> list);
 
+    List<SysUserSimpleRespVO> convertList04(List<SysUserDO> list);
 }

+ 5 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/dataobject/dept/SysDeptDO.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept;
 
+import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
 import com.baomidou.mybatisplus.annotation.TableId;
@@ -11,6 +12,7 @@ import lombok.EqualsAndHashCode;
  * 部门表
  *
  * @author ruoyi
+ * @author 芋道源码
  */
 @TableName("sys_dept")
 @Data
@@ -38,8 +40,10 @@ public class SysDeptDO extends TenantBaseDO {
     private Integer sort;
     /**
      * 负责人
+     *
+     * 关联 {@link SysUserDO#getId()}
      */
-    private String leader;
+    private Long leaderUserId;
     /**
      * 联系电话
      */

+ 6 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/dict/SysDictDataMapper.java

@@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 
@@ -20,6 +21,11 @@ public interface SysDictDataMapper extends BaseMapperX<SysDictDataDO> {
                 .eq("value", value));
     }
 
+    default List<SysDictDataDO> selectByDictTypeAndValues(String dictType, Collection<String> values) {
+        return selectList(new QueryWrapper<SysDictDataDO>().eq("dict_type", dictType)
+                .in("value", values));
+    }
+
     default int selectCountByDictType(String dictType) {
         return selectCount("dict_type", dictType);
     }

+ 9 - 2
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/permission/SysUserRoleMapper.java

@@ -16,6 +16,14 @@ public interface SysUserRoleMapper extends BaseMapperX<SysUserRoleDO> {
         return selectList(new QueryWrapper<SysUserRoleDO>().eq("user_id", userId));
     }
 
+    default List<SysUserRoleDO> selectListByRoleId(Long roleId) {
+        return selectList(new QueryWrapper<SysUserRoleDO>().eq("role_id", roleId));
+    }
+
+    default List<SysUserRoleDO> selectListByRoleIds(Collection<Long> roleIds) {
+        return selectList("role_id", roleIds);
+    }
+
     default void insertList(Long userId, Collection<Long> roleIds) {
         List<SysUserRoleDO> list = roleIds.stream().map(roleId -> {
             SysUserRoleDO entity = new SysUserRoleDO();
@@ -23,8 +31,7 @@ public interface SysUserRoleMapper extends BaseMapperX<SysUserRoleDO> {
             entity.setRoleId(roleId);
             return entity;
         }).collect(Collectors.toList());
-        // TODO 芋艿,mybatis plus 增加批量插入的功能
-        list.forEach(this::insert);
+        insertBatch(list);
     }
 
     default void deleteListByUserIdAndRoleIdIds(Long userId, Collection<Long> roleIds) {

+ 9 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/user/SysUserMapper.java

@@ -55,7 +55,7 @@ public interface SysUserMapper extends BaseMapperX<SysUserDO> {
         return selectList(new QueryWrapperX<SysUserDO>().like("username", username));
     }
 
-
+    // TODO 芋艿:可废弃该方法
     default List<SysUserDO> selectListByDepartIdAndPostId(Long departId, Long postId) {
         return selectList(new QueryWrapperX<SysUserDO>()
                 .eq("status", CommonStatusEnum.ENABLE.getStatus())
@@ -64,5 +64,13 @@ public interface SysUserMapper extends BaseMapperX<SysUserDO> {
                 .likeIfPresent("post_ids", Optional.ofNullable(postId).map(t -> String.valueOf(postId)).orElse("")));
     }
 
+    default List<SysUserDO> selectListByStatus(Integer status) {
+        return selectList("status", status);
+    }
+
+    default List<SysUserDO> selectListByDeptIds(Collection<Long> deptIds) {
+        return selectList("dept_id", deptIds);
+    }
+
 }
 

+ 3 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysDictTypeConstants.java

@@ -22,4 +22,7 @@ public interface SysDictTypeConstants {
     String SMS_SEND_STATUS = "sys_sms_send_status"; // 短信发送状态
     String SMS_RECEIVE_STATUS = "sys_sms_receive_status"; // 短信接收状态
 
+    String BPM_TASK_ASSIGN_RULE_TYPE = "bpm_task_assign_rule_type"; // 任务分配规则类型
+    String BPM_TASK_ASSIGN_SCRIPT = "bpm_task_assign_script"; // 任务分配自定义脚本
+
 }

+ 3 - 1
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysErrorCodeConstants.java

@@ -31,6 +31,7 @@ public interface SysErrorCodeConstants {
     ErrorCode ROLE_NAME_DUPLICATE = new ErrorCode(1002003001, "已经存在名为【{}】的角色");
     ErrorCode ROLE_CODE_DUPLICATE = new ErrorCode(1002003002, "已经存在编码为【{}】的角色");
     ErrorCode ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE = new ErrorCode(1002003004, "不能操作类型为系统内置的角色");
+    ErrorCode ROLE_IS_DISABLE = new ErrorCode(1002003004, "名字为【{}】的角色已被禁用");
 
     // ========== 用户模块 1002004000 ==========
     ErrorCode USER_USERNAME_EXISTS = new ErrorCode(1002004000, "用户账号已经存在");
@@ -39,6 +40,7 @@ public interface SysErrorCodeConstants {
     ErrorCode USER_NOT_EXISTS = new ErrorCode(1002004003, "用户不存在");
     ErrorCode USER_IMPORT_LIST_IS_EMPTY = new ErrorCode(1002004004, "导入用户数据不能为空!");
     ErrorCode USER_PASSWORD_FAILED = new ErrorCode(1002004005, "用户密码校验失败");
+    ErrorCode USER_IS_DISABLE = new ErrorCode(1002003004, "名字为【{}】的用户已被禁用");
 
     // ========== 部门模块 1002005000 ==========
     ErrorCode DEPT_NAME_DUPLICATE = new ErrorCode(1002004001, "已经存在该名字的部门");
@@ -65,7 +67,7 @@ public interface SysErrorCodeConstants {
 
     // ========== 字典数据 1002007000 ==========
     ErrorCode DICT_DATA_NOT_EXISTS = new ErrorCode(1002007001, "当前字典数据不存在");
-    ErrorCode DICT_DATA_NOT_ENABLE = new ErrorCode(1002007002, "字典数据不处于开启状态,不允许选择");
+    ErrorCode DICT_DATA_NOT_ENABLE = new ErrorCode(1002007002, "字典数据({})不处于开启状态,不允许选择");
     ErrorCode DICT_DATA_VALUE_DUPLICATE = new ErrorCode(1002007003, "已经存在该值的字典数据");
 
     // ========== 通知公告 1002008000 ==========

+ 17 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/dept/SysDeptService.java

@@ -84,6 +84,14 @@ public interface SysDeptService {
      */
     SysDeptDO getDept(Long id);
 
+    /**
+     * 获得部门信息数组
+     *
+     * @param ids 部门编号数组
+     * @return 部门信息数组
+     */
+    List<SysDeptDO> getDepts(Collection<Long> ids);
+
     /**
      * 获得所有子部门,从缓存中
      *
@@ -93,4 +101,13 @@ public interface SysDeptService {
      */
     List<SysDeptDO> getDeptsByParentIdFromCache(Long parentId, boolean recursive);
 
+    /**
+     * 校验部门们是否有效。如下情况,视为无效:
+     * 1. 部门编号不存在
+     * 2. 部门被禁用
+     *
+     * @param ids 角色编号数组
+     */
+    void validDepts(Collection<Long> ids);
+
 }

+ 9 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/dept/SysPostService.java

@@ -86,4 +86,13 @@ public interface SysPostService {
      */
     SysPostDO getPost(Long id);
 
+    /**
+     * 校验岗位们是否有效。如下情况,视为无效:
+     * 1. 岗位编号不存在
+     * 2. 岗位被禁用
+     *
+     * @param ids 岗位编号数组
+     */
+    void validPosts(Collection<Long> ids);
+
 }

+ 27 - 0
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/dept/impl/SysDeptServiceImpl.java

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.adminserver.modules.system.service.dept.impl;
 import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.dept.SysDeptCreateReqVO;
 import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.dept.SysDeptListReqVO;
@@ -26,6 +27,7 @@ import javax.annotation.Resource;
 import java.util.*;
 
 import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.*;
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 
 /**
  * 部门 Service 实现类
@@ -180,6 +182,26 @@ public class SysDeptServiceImpl implements SysDeptService {
         return result;
     }
 
+    @Override
+    public void validDepts(Collection<Long> ids) {
+        if (CollUtil.isEmpty(ids)) {
+            return;
+        }
+        // 获得科室信息
+        List<SysDeptDO> depts = deptMapper.selectBatchIds(ids);
+        Map<Long, SysDeptDO> deptMap = CollectionUtils.convertMap(depts, SysDeptDO::getId);
+        // 校验
+        ids.forEach(id -> {
+            SysDeptDO dept = deptMap.get(id);
+            if (dept == null) {
+                throw exception(DEPT_NOT_FOUND);
+            }
+            if (!CommonStatusEnum.ENABLE.getStatus().equals(dept.getStatus())) {
+                throw exception(DEPT_NOT_ENABLE, dept.getName());
+            }
+        });
+    }
+
     /**
      * 递归获取所有的子部门,添加到 result 结果
      *
@@ -210,6 +232,11 @@ public class SysDeptServiceImpl implements SysDeptService {
         return deptMapper.selectById(id);
     }
 
+    @Override
+    public List<SysDeptDO> getDepts(Collection<Long> ids) {
+        return deptMapper.selectBatchIds(ids);
+    }
+
     private void checkCreateOrUpdate(Long id, Long parentId, String name) {
         // 校验自己存在
         checkDeptExists(id);

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