多模块重构 8:bom 模块的调整

This commit is contained in:
YunaiV
2022-01-31 22:55:48 +08:00
parent d45213fe2a
commit 510917c5ed
179 changed files with 91 additions and 103 deletions

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-bpm</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yudao-module-bpm-impl-activiti</artifactId>
<name>${artifactId}</name>
<description>
bpm-activiti 模块,基于 Activiti 7 实现工作流
</description>
<dependencies>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-bpm-base</artifactId>
<version>${revision}</version>
</dependency>
<!-- 工作流相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-activiti</artifactId>
</dependency>
<!-- Test 测试相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,97 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition;
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;
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.io.IOException;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "流程模型")
@RestController
@RequestMapping("/bpm/model")
@Validated
public class BpmModelController {
@Resource
private BpmModelService bpmModelService;
@GetMapping("/page")
@ApiOperation(value = "获得模型分页")
public CommonResult<PageResult<BpmModelPageItemRespVO>> getModelPage(ModelPageReqVO pageVO) {
return success(bpmModelService.getModelPage(pageVO));
}
@GetMapping("/get")
@ApiOperation("获得模型")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = String.class)
@PreAuthorize("@ss.hasPermission('bpm:model:query')")
public CommonResult<BpmModelRespVO> getModel(@RequestParam("id") String id) {
BpmModelRespVO model = bpmModelService.getModel(id);
return success(model);
}
@PostMapping("/create")
@ApiOperation(value = "新建模型")
@PreAuthorize("@ss.hasPermission('bpm:model:create')")
public CommonResult<String> createModel(@Valid @RequestBody BpmModelCreateReqVO createRetVO) {
return success(bpmModelService.createModel(createRetVO, null));
}
@PostMapping("/import")
@ApiOperation(value = "导入模型")
@PreAuthorize("@ss.hasPermission('bpm:model:import')")
public CommonResult<String> importModel(@Valid BpmModeImportReqVO importReqVO) throws IOException {
BpmModelCreateReqVO createReqVO = BpmModelConvert.INSTANCE.convert(importReqVO);
// 读取文件
String bpmnXml = IoUtils.readUtf8(importReqVO.getBpmnFile().getInputStream(), false);
return success(bpmModelService.createModel(createReqVO, bpmnXml));
}
@PutMapping("/update")
@ApiOperation(value = "修改模型")
@PreAuthorize("@ss.hasPermission('bpm:model:update')")
public CommonResult<Boolean> updateModel(@Valid @RequestBody BpmModelUpdateReqVO modelVO) {
bpmModelService.updateModel(modelVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除模型")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = String.class)
@PreAuthorize("@ss.hasPermission('bpm:model:delete')")
public CommonResult<Boolean> deleteModel(@RequestParam("id") String id) {
bpmModelService.deleteModel(id);
return success(true);
}
@PostMapping("/deploy")
@ApiOperation(value = "部署模型")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = String.class)
@PreAuthorize("@ss.hasPermission('bpm:model:deploy')")
public CommonResult<Boolean> deployModel(@RequestParam("id") String id) {
bpmModelService.deployModel(id);
return success(true);
}
@PutMapping("/update-state")
@ApiOperation(value = "修改模型的状态", notes = "实际更新的部署的流程定义的状态")
@PreAuthorize("@ss.hasPermission('bpm:model:update')")
public CommonResult<Boolean> updateModelState(@Valid @RequestBody BpmModelUpdateStateReqVO reqVO) {
bpmModelService.updateModelState(reqVO.getId(), reqVO.getState());
return success(true);
}
}

View File

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

View File

@@ -0,0 +1,60 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition;
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;
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.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "流程定义")
@RestController
@RequestMapping("/bpm/process-definition")
@Validated
public class BpmProcessDefinitionController {
@Resource
private BpmProcessDefinitionService bpmDefinitionService;
@GetMapping ("/page")
@ApiOperation(value = "获得流程定义分页")
@PreAuthorize("@ss.hasPermission('bpm:process-definition:query')")
public CommonResult<PageResult<BpmProcessDefinitionPageItemRespVO>> getProcessDefinitionPage(
BpmProcessDefinitionPageReqVO pageReqVO) {
return success(bpmDefinitionService.getProcessDefinitionPage(pageReqVO));
}
@GetMapping ("/list")
@ApiOperation(value = "获得流程定义列表")
@PreAuthorize("@ss.hasPermission('bpm:process-definition:query')")
public CommonResult<List<BpmProcessDefinitionRespVO>> getProcessDefinitionList(
BpmProcessDefinitionListReqVO listReqVO) {
return success(bpmDefinitionService.getProcessDefinitionList(listReqVO));
}
@GetMapping ("/get-bpmn-xml")
@ApiOperation(value = "获得流程定义的 BPMN XML")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = String.class)
@PreAuthorize("@ss.hasPermission('bpm:process-definition:query')")
public CommonResult<String> getProcessDefinitionBpmnXML(@RequestParam("id") String id) {
String bpmnXML = bpmDefinitionService.getProcessDefinitionBpmnXML(id);
return success(bpmnXML);
}
}

View File

@@ -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}}

View File

@@ -0,0 +1,59 @@
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 io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
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/task-assign-rule")
@Validated
public class BpmTaskAssignRuleController {
@Resource
private BpmTaskAssignRuleService taskAssignRuleService;
@GetMapping("/list")
@ApiOperation(value = "获得任务分配规则列表")
@ApiImplicitParams({
@ApiImplicitParam(name = "modelId", value = "模型编号", example = "1024", dataTypeClass = String.class),
@ApiImplicitParam(name = "processDefinitionId", value = "刘晨定义的编号", example = "2048", dataTypeClass = String.class)
})
@PreAuthorize("@ss.hasPermission('bpm:task-assign-rule:query')")
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")
@ApiOperation(value = "创建任务分配规则")
@PreAuthorize("@ss.hasPermission('bpm:task-assign-rule:create')")
public CommonResult<Long> createTaskAssignRule(@Valid @RequestBody BpmTaskAssignRuleCreateReqVO reqVO) {
return success(taskAssignRuleService.createTaskAssignRule(reqVO));
}
@PutMapping("/update")
@ApiOperation(value = "更新任务分配规则")
@PreAuthorize("@ss.hasPermission('bpm:task-assign-rule:update')")
public CommonResult<Boolean> updateTaskAssignRule(@Valid @RequestBody BpmTaskAssignRuleUpdateReqVO reqVO) {
taskAssignRuleService.updateTaskAssignRule(reqVO);
return success(true);
}
}

View File

@@ -0,0 +1,22 @@
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 org.springframework.web.multipart.MultipartFile;
import javax.validation.constraints.NotNull;
@ApiModel(value = "流程模型的导入 Request VO", description = "相比流程模型的新建来说,只是多了一个 bpmnFile 文件")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmModeImportReqVO extends BpmModelCreateReqVO {
@ApiModelProperty(value = "BPMN 文件", required = true)
@NotNull(message = "BPMN 文件不能为空")
private MultipartFile bpmnFile;
}

View File

@@ -0,0 +1,41 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
/**
* 流程模型 Base VO提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
@Data
public class BpmModelBaseVO {
@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;
@ApiModelProperty(value = "流程分类", notes = "参见 bpm_model_category 数据字典", example = "1")
@NotEmpty(message = "流程分类不能为空")
private String category;
@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;
}

View File

@@ -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;
}

View File

@@ -0,0 +1,49 @@
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 java.util.Date;
@ApiModel("流程模型的分页的每一项 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmModelPageItemRespVO extends BpmModelBaseVO {
@ApiModelProperty(value = "编号", required = true, example = "1024")
private String id;
@ApiModelProperty(value = "表单名字", example = "请假表单")
private String formName;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
/**
* 最新部署的流程定义
*/
private ProcessDefinition processDefinition;
@ApiModel("流程定义")
@Data
public static class ProcessDefinition {
@ApiModelProperty(value = "编号", required = true, example = "1024")
private String id;
@ApiModelProperty(value = "版本", required = true, example = "1")
private Integer version;
@ApiModelProperty(value = "部署时间", required = true)
private Date deploymentTime;
@ApiModelProperty(value = "中断状态", required = true, example = "1", notes = "参见 SuspensionState 枚举")
private Integer suspensionState;
}
}

View File

@@ -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 java.util.Date;
@ApiModel("流程模型的创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmModelRespVO extends BpmModelBaseVO {
@ApiModelProperty(value = "编号", required = true, example = "1024")
private String id;
@ApiModelProperty(value = "BPMN XML", required = true)
private String bpmnXml;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
}

View File

@@ -0,0 +1,40 @@
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 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;
}

View File

@@ -0,0 +1,21 @@
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 javax.validation.constraints.NotNull;
@ApiModel("流程模型更新状态 Request VO")
@Data
public class BpmModelUpdateStateReqVO {
@ApiModelProperty(value = "编号", required = true, example = "1024")
@NotNull(message = "编号不能为空")
private String id;
@ApiModelProperty(value = "状态", required = true, example = "1", notes = "见 SuspensionState 枚举")
@NotNull(message = "状态不能为空")
private Integer state;
}

View File

@@ -0,0 +1,26 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ApiModel("流程模型分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ModelPageReqVO extends PageParam {
@ApiModelProperty(value = "标识", example = "process1641042089407", notes = "精准匹配")
private String key;
@ApiModelProperty(value = "名字", example = "芋道", notes = "模糊匹配")
private String name;
@ApiModelProperty(value = "流程分类", notes = "参见 bpm_model_category 数据字典", example = "1")
private String category;
}

View File

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

View File

@@ -0,0 +1,23 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.Date;
@ApiModel("流程定义的分页的每一项 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmProcessDefinitionPageItemRespVO extends BpmProcessDefinitionRespVO {
@ApiModelProperty(value = "表单名字", example = "请假表单")
private String formName;
@ApiModelProperty(value = "部署时间", required = true)
private Date deploymentTime;
}

View File

@@ -0,0 +1,19 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel("流程定义分页 Request VO")
public class BpmProcessDefinitionPageReqVO extends PageParam {
@ApiModelProperty(value = "标识", example = "process1641042089407", notes = "精准匹配")
private String key;
}

View File

@@ -0,0 +1,52 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.process;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
@ApiModel("流程定义 Response VO")
@Data
public class BpmProcessDefinitionRespVO {
@ApiModelProperty(value = "编号", required = true, example = "1024")
private String id;
@ApiModelProperty(value = "版本", required = true, example = "1")
private Integer version;
@ApiModelProperty(value = "流程名称", required = true, example = "芋道")
@NotEmpty(message = "流程名称不能为空")
private String name;
@ApiModelProperty(value = "流程描述", example = "我是描述")
private String description;
@ApiModelProperty(value = "流程分类", notes = "参见 bpm_model_category 数据字典", example = "1")
@NotEmpty(message = "流程分类不能为空")
private String category;
@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 = "表单的配置", required = true,
notes = "JSON 字符串。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空")
private String formConf;
@ApiModelProperty(value = "表单项的数组", required = true,
notes = "JSON 字符串的数组。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空")
private List<String> formFields;
@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;
@ApiModelProperty(value = "中断状态", required = true, example = "1", notes = "参见 SuspensionState 枚举")
private Integer suspensionState;
}

View File

@@ -0,0 +1,25 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Set;
/**
* 流程任务分配规则 Base VO提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
@Data
public class BpmTaskAssignRuleBaseVO {
@ApiModelProperty(value = "规则类型", required = true, example = "bpm_task_assign_rule_type")
@NotNull(message = "规则类型不能为空")
private Integer type;
@ApiModelProperty(value = "规则值数组", required = true, example = "1,2,3")
@NotNull(message = "规则值数组不能为空")
private Set<Long> options;
}

View File

@@ -0,0 +1,25 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule;
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 BpmTaskAssignRuleCreateReqVO extends BpmTaskAssignRuleBaseVO {
@ApiModelProperty(value = "流程模型的编号", required = true, example = "1024")
@NotEmpty(message = "流程模型的编号不能为空")
private String modelId;
@ApiModelProperty(value = "流程任务定义的编号", required = true, example = "2048")
@NotEmpty(message = "流程任务定义的编号不能为空")
private String taskDefinitionKey;
}

View File

@@ -0,0 +1,29 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ApiModel("流程任务分配规则的 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmTaskAssignRuleRespVO extends BpmTaskAssignRuleBaseVO {
@ApiModelProperty(value = "任务分配规则的编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "流程模型的编号", required = true, example = "2048")
private String modelId;
@ApiModelProperty(value = "流程定义的编号", required = true, example = "4096")
private String processDefinitionId;
@ApiModelProperty(value = "流程任务定义的编号", required = true, example = "2048")
private String taskDefinitionKey;
@ApiModelProperty(value = "流程任务定义的名字", required = true, example = "关注芋道")
private String taskDefinitionName;
}

View File

@@ -0,0 +1,22 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.rule;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotNull;
import java.util.Set;
@ApiModel("流程任务分配规则的更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmTaskAssignRuleUpdateReqVO extends BpmTaskAssignRuleBaseVO {
@ApiModelProperty(value = "任务分配规则的编号", required = true, example = "1024")
@NotNull(message = "任务分配规则的编号不能为空")
private Long id;
}

View File

@@ -0,0 +1,12 @@
### 请求 /bpm/oa/leave/create 接口 => 成功
POST {{baseUrl}}/bpm/oa/leave/create
Content-Type: application/json
tenant-id: 1
Authorization: Bearer {{token}}
{
"startTime": "2022-03-01",
"endTime": "2022-03-05",
"type": 1,
"reason": "我要请假啦啦啦!"
}

View File

@@ -0,0 +1,63 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.oa;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.oa.vo.BpmOALeaveCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.oa.vo.BpmOALeavePageReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.oa.vo.BpmOALeaveRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.convert.oa.BpmOALeaveConvert;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.leave.BpmOALeaveDO;
import cn.iocoder.yudao.adminserver.modules.bpm.service.oa.BpmOALeaveService;
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 static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
/**
* OA 请假申请 Controller用于演示自己存储数据接入工作流的例子
*
* @author jason
* @author 芋道源码
*/
@Api(tags = "OA 请假申请")
@RestController
@RequestMapping("/bpm/oa/leave")
@Validated
public class BpmOALeaveController {
@Resource
private BpmOALeaveService leaveService;
@PostMapping("/create")
@PreAuthorize("@ss.hasPermission('bpm:oa-leave:create')")
@ApiOperation("创建请求申请")
public CommonResult<Long> createLeave(@Valid @RequestBody BpmOALeaveCreateReqVO createReqVO) {
return success(leaveService.createLeave(getLoginUserId(), createReqVO));
}
@GetMapping("/get")
@PreAuthorize("@ss.hasPermission('bpm:oa-leave:query')")
@ApiOperation("获得请假申请")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
public CommonResult<BpmOALeaveRespVO> getLeave(@RequestParam("id") Long id) {
BpmOALeaveDO leave = leaveService.getLeave(id);
return success(BpmOALeaveConvert.INSTANCE.convert(leave));
}
@GetMapping("/page")
@PreAuthorize("@ss.hasPermission('bpm:oa-leave:query')")
@ApiOperation("获得请假申请分页")
public CommonResult<PageResult<BpmOALeaveRespVO>> getLeavePage(@Valid BpmOALeavePageReqVO pageVO) {
PageResult<BpmOALeaveDO> pageResult = leaveService.getLeavePage(getLoginUserId(), pageVO);
return success(BpmOALeaveConvert.INSTANCE.convertPage(pageResult));
}
}

View File

@@ -0,0 +1,33 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.oa.vo;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
* 请假申请 Base VO提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
@Data
public class BpmOALeaveBaseVO {
@ApiModelProperty(value = "请假的开始时间", required = true)
@NotNull(message = "开始时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date startTime;
@ApiModelProperty(value = "请假的结束时间", required = true)
@NotNull(message = "结束时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date endTime;
@ApiModelProperty(value = "请假类型", required = true, example = "1", notes = "参见 bpm_oa_type 枚举")
private Integer type;
@ApiModelProperty(value = "原因", required = true, example = "阅读芋道源码")
private String reason;
}

View File

@@ -0,0 +1,21 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.oa.vo;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.AssertTrue;
@ApiModel("请假申请创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmOALeaveCreateReqVO extends BpmOALeaveBaseVO {
@AssertTrue(message = "结束时间,需要在开始时间之后")
public boolean isEndTimeValid() {
return !getEndTime().before(getStartTime());
}
}

View File

@@ -0,0 +1,34 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.oa.vo;
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 BpmOALeavePageReqVO extends PageParam {
@ApiModelProperty(value = "状态", example = "1", notes = "参见 bpm_process_instance_result 枚举")
private Integer result;
@ApiModelProperty(value = "请假类型", example = "1", notes = "参见 bpm_oa_type")
private Integer type;
@ApiModelProperty(value = "原因", example = "阅读芋道源码", notes = "模糊匹配")
private String reason;
@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;
}

View File

@@ -0,0 +1,32 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.oa.vo;
import lombok.*;
import io.swagger.annotations.*;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("请假申请 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmOALeaveRespVO extends BpmOALeaveBaseVO {
@ApiModelProperty(value = "请假表单主键", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 bpm_process_instance_result 枚举")
private Integer result;
@ApiModelProperty(value = "申请时间", required = true)
@NotNull(message = "申请时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date createTime;
@ApiModelProperty(value = "流程id")
private String processInstanceId;
}

View File

@@ -0,0 +1,55 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.task;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.activity.BpmActivityRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmActivityService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
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.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "流程活动实例")
@RestController
@RequestMapping("/bpm/activity")
@Validated
public class BpmActivityController {
@Resource
private BpmActivityService activityService;
@GetMapping("/list")
@ApiOperation(value = "生成指定流程实例的高亮流程图",
notes = "只高亮进行中的任务。不过要注意,该接口暂时没用,通过前端的 ProcessViewer.vue 界面的 highlightDiagram 方法生成")
@ApiImplicitParam(name = "id", value = "流程实例的编号", required = true, dataTypeClass = String.class)
@PreAuthorize("@ss.hasPermission('bpm:task:query')")
public CommonResult<List<BpmActivityRespVO>> getActivityList(
@RequestParam("processInstanceId") String processInstanceId) {
return success(activityService.getActivityListByProcessInstanceId(processInstanceId));
}
@GetMapping("/generate-highlight-diagram")
@ApiOperation(value = "生成指定流程实例的高亮流程图",
notes = "只高亮进行中的任务。不过要注意,该接口暂时没用,通过前端的 ProcessViewer.vue 界面的 highlightDiagram 方法生成")
@ApiImplicitParam(name = "id", value = "流程实例的编号", required = true, dataTypeClass = String.class)
@PreAuthorize("@ss.hasPermission('bpm:task:query')")
public void generateHighlightDiagram(@RequestParam("processInstanceId") String processInstanceId,
HttpServletResponse response) throws IOException {
byte[] bytes = activityService.generateHighlightDiagram(processInstanceId);
ServletUtils.writeAttachment(response, StrUtil.format("流程图-{}.svg", processInstanceId), bytes);
}
}

View File

@@ -0,0 +1,29 @@
### 请求 /bpm/process-instance/create 接口 => 成功
POST {{baseUrl}}/bpm/process-instance/create
Content-Type: application/json
tenant-id: 1
Authorization: Bearer {{token}}
{
"processDefinitionId": "gateway_test:2:00e52d8e-701b-11ec-aca9-a2380e71991a",
"variables": {
"a": 1,
"b": "2"
}
}
### 请求 /bpm/process-instance/cancel 接口 => 成功
DELETE {{baseUrl}}/bpm/process-instance/cancel
Content-Type: application/json
tenant-id: 1
Authorization: Bearer {{token}}
{
"id": "b9220387-7088-11ec-bcae-a2380e71991a",
"reason": "我就取消"
}
### 请求 /bpm/process-instance/get 接口 => 成功
GET {{baseUrl}}/bpm/process-instance/get?id=537cceb3-768c-11ec-afcd-a2380e71991a
tenant-id: 1
Authorization: Bearer {{token}}

View File

@@ -0,0 +1,60 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.task;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.*;
import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmProcessInstanceService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.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 static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@Api(tags = "流程实例") // 流程实例,通过流程定义创建的一次“申请”
@RestController
@RequestMapping("/bpm/process-instance")
@Validated
public class BpmProcessInstanceController {
@Resource
private BpmProcessInstanceService processInstanceService;
@PostMapping("/create")
@ApiOperation("新建流程实例")
@PreAuthorize("@ss.hasPermission('bpm:process-instance:query')")
public CommonResult<String> createProcessInstance(@Valid @RequestBody BpmProcessInstanceCreateReqVO createReqVO) {
return success(processInstanceService.createProcessInstance(getLoginUserId(), createReqVO));
}
@DeleteMapping("/cancel")
@ApiOperation(value = "取消流程实例", notes = "撤回发起的流程")
@PreAuthorize("@ss.hasPermission('bpm:process-instance:cancel')")
public CommonResult<Boolean> cancelProcessInstance(@Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) {
processInstanceService.cancelProcessInstance(getLoginUserId(), cancelReqVO);
return success(true);
}
@GetMapping("/my-page")
@ApiOperation(value = "获得我的实例分页列表", notes = "在【我的流程】菜单中,进行调用")
@PreAuthorize("@ss.hasPermission('bpm:process-instance:query')")
public CommonResult<PageResult<BpmProcessInstancePageItemRespVO>> getMyProcessInstancePage(
@Valid BpmProcessInstanceMyPageReqVO pageReqVO) {
return success(processInstanceService.getMyProcessInstancePage(getLoginUserId(), pageReqVO));
}
@GetMapping("/get")
@ApiOperation(value = "获得指定流程实例", notes = "在【流程详细】界面中,进行调用")
@ApiImplicitParam(name = "id", value = "流程实例的编号", required = true, dataTypeClass = String.class)
@PreAuthorize("@ss.hasPermission('bpm:process-instance:query')")
public CommonResult<BpmProcessInstanceRespVO> getProcessInstance(@RequestParam("id") String id) {
return success(processInstanceService.getProcessInstanceVO(id));
}
}

View File

@@ -0,0 +1,14 @@
### 请求 /bpm/task/todo-page 接口 => 成功
GET {{baseUrl}}/bpm/task/todo-page
tenant-id: 1
Authorization: Bearer {{token}}
### 请求 /bpm/task/done-page 接口 => 成功
GET {{baseUrl}}/bpm/task/done-page?pageSize=100
tenant-id: 1
Authorization: Bearer {{token}}
### 请求 /bpm/task/list-by-process-instance-id 接口 => 成功
GET {{baseUrl}}/bpm/task/list-by-process-instance-id?processInstanceId=537cceb3-768c-11ec-afcd-a2380e71991a
tenant-id: 1
Authorization: Bearer {{token}}

View File

@@ -0,0 +1,80 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.task;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.*;
import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmTaskService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.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.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
@Api(tags = "流程任务实例")
@RestController
@RequestMapping("/bpm/task")
@Validated
public class BpmTaskController {
@Resource
private BpmTaskService taskService;
@GetMapping("todo-page")
@ApiOperation("获取 Todo 待办任务分页")
@PreAuthorize("@ss.hasPermission('bpm:task:query')")
public CommonResult<PageResult<BpmTaskTodoPageItemRespVO>> getTodoTaskPage(@Valid BpmTaskTodoPageReqVO pageVO) {
return success(taskService.getTodoTaskPage(getLoginUserId(), pageVO));
}
@GetMapping("done-page")
@ApiOperation("获取 Done 已办任务分页")
@PreAuthorize("@ss.hasPermission('bpm:task:query')")
public CommonResult<PageResult<BpmTaskDonePageItemRespVO>> getTodoTaskPage(@Valid BpmTaskDonePageReqVO pageVO) {
return success(taskService.getDoneTaskPage(getLoginUserId(), pageVO));
}
@PutMapping("/approve")
@ApiOperation("通过任务")
@PreAuthorize("@ss.hasPermission('bpm:task:update')")
public CommonResult<Boolean> approveTask(@Valid @RequestBody BpmTaskApproveReqVO reqVO) {
taskService.approveTask(getLoginUserId(), reqVO);
return success(true);
}
@PutMapping("/reject")
@ApiOperation("不通过任务")
@PreAuthorize("@ss.hasPermission('bpm:task:update')")
public CommonResult<Boolean> rejectTask(@Valid @RequestBody BpmTaskRejectReqVO reqVO) {
taskService.rejectTask(getLoginUserId(), reqVO);
return success(true);
}
@PutMapping("/update-assignee")
@ApiOperation(value = "更新任务的负责人", notes = "用于【流程详情】的【转派】按钮")
@PreAuthorize("@ss.hasPermission('bpm:task:update')")
public CommonResult<Boolean> updateTaskAssignee(@Valid @RequestBody BpmTaskUpdateAssigneeReqVO reqVO) {
taskService.updateTaskAssignee(getLoginUserId(), reqVO);
return success(true);
}
@GetMapping("/list-by-process-instance-id")
@ApiOperation(value = "获得指定流程实例的任务列表", notes = "包括完成的、未完成的")
@ApiImplicitParam(name = "processInstanceId", value = "流程实例的编号", required = true, dataTypeClass = String.class)
@PreAuthorize("@ss.hasPermission('bpm:task:query')")
public CommonResult<List<BpmTaskRespVO>> getTaskListByProcessInstanceId(
@RequestParam("processInstanceId") String processInstanceId) {
return success(taskService.getTaskListByProcessInstanceId(processInstanceId));
}
}

View File

@@ -0,0 +1,26 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.activity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
@ApiModel("流程活动的 Response VO")
@Data
public class BpmActivityRespVO {
@ApiModelProperty(value = "流程活动的标识", required = true, example = "1024")
private String key;
@ApiModelProperty(value = "流程活动的类型", required = true, example = "StartEvent")
private String type;
@ApiModelProperty(value = "流程活动的开始时间", required = true)
private Date startTime;
@ApiModelProperty(value = "流程活动的结束时间", required = true)
private Date endTime;
@ApiModelProperty(value = "关联的流程任务的编号", example = "2048", notes = "关联的流程任务,只有 UserTask 等类型才有")
private String taskId;
}

View File

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

View File

@@ -0,0 +1,21 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import java.util.Map;
@ApiModel("流程实例的创建 Request VO")
@Data
public class BpmProcessInstanceCreateReqVO {
@ApiModelProperty(value = "流程定义的编号", required = true, example = "1024")
@NotEmpty(message = "流程定义编号不能为空")
private String processDefinitionId;
@ApiModelProperty(value = "变量实例")
private Map<String, Object> variables;
}

View File

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

View File

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

View File

@@ -0,0 +1,97 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ApiModel("流程实例的 Response VO")
@Data
public class BpmProcessInstanceRespVO {
@ApiModelProperty(value = "流程实例的编号", required = true, example = "1024")
private String id;
@ApiModelProperty(value = "流程名称", required = true, example = "芋道")
private String name;
@ApiModelProperty(value = "流程分类", required = true, notes = "参见 bpm_model_category 数据字典", example = "1")
private String category;
@ApiModelProperty(value = "流程实例的状态", required = true, notes = "参见 bpm_process_instance_status", example = "1")
private Integer status;
@ApiModelProperty(value = "流程实例的结果", required = true, notes = "参见 bpm_process_instance_result", example = "2")
private Integer result;
@ApiModelProperty(value = "提交时间", required = true)
private Date createTime;
@ApiModelProperty(value = "结束时间", required = true)
private Date endTime;
@ApiModelProperty(value = "提交的表单值", required = true)
private Map<String, Object> formVariables;
@ApiModelProperty(value = "业务的唯一标识", example = "1", notes = "例如说,请假申请的编号")
private String businessKey;
/**
* 发起流程的用户
*/
private User startUser;
/**
* 流程定义
*/
private ProcessDefinition processDefinition;
@ApiModel("用户信息")
@Data
public static class User {
@ApiModelProperty(value = "用户编号", required = true, example = "1")
private Long id;
@ApiModelProperty(value = "用户昵称", required = true, example = "芋艿")
private String nickname;
@ApiModelProperty(value = "部门编号", required = true, example = "1")
private Long deptId;
@ApiModelProperty(value = "部门名称", required = true, example = "研发部")
private String deptName;
}
@ApiModel("流程定义信息")
@Data
public static class ProcessDefinition {
@ApiModelProperty(value = "编号", required = true, example = "1024")
private String id;
@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 = "表单的配置", required = true,
notes = "JSON 字符串。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空")
private String formConf;
@ApiModelProperty(value = "表单项的数组", required = true,
notes = "JSON 字符串的数组。在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空")
private List<String> formFields;
@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;
@ApiModelProperty(value = "BPMN XML", required = true)
private String bpmnXml;
}
}

View File

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

View File

@@ -0,0 +1,27 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.Date;
@ApiModel("流程任务的 Done 已完成的分页项 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmTaskDonePageItemRespVO extends BpmTaskTodoPageItemRespVO {
@ApiModelProperty(value = "结束时间", required = true)
private Date endTime;
@ApiModelProperty(value = "持续时间", required = true, example = "1000")
private Long durationInMillis;
@ApiModelProperty(value = "任务结果", required = true, notes = "参见 bpm_process_instance_result", example = "2")
private Integer result;
@ApiModelProperty(value = "审批建议", required = true, example = "不请假了!")
private String comment;
}

View File

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

View File

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

View File

@@ -0,0 +1,41 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.List;
@ApiModel("流程任务的 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmTaskRespVO extends BpmTaskDonePageItemRespVO {
@ApiModelProperty(value = "任务定义的标识", required = true, example = "user-001")
private String definitionKey;
/**
* 审核的用户信息
*/
private User assigneeUser;
@ApiModel("用户信息")
@Data
public static class User {
@ApiModelProperty(value = "用户编号", required = true, example = "1")
private Long id;
@ApiModelProperty(value = "用户昵称", required = true, example = "芋艿")
private String nickname;
@ApiModelProperty(value = "部门编号", required = true, example = "1")
private Long deptId;
@ApiModelProperty(value = "部门名称", required = true, example = "研发部")
private String deptName;
}
}

View File

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

View File

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

View File

@@ -0,0 +1,25 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import net.bytebuddy.implementation.bind.annotation.Empty;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@ApiModel("流程任务的更新负责人的 Request VO")
@Data
public class BpmTaskUpdateAssigneeReqVO {
@ApiModelProperty(value = "任务编号", required = true, example = "1024")
@NotEmpty(message = "任务编号不能为空")
private String id;
@ApiModelProperty(value = "新审批人的用户编号", required = true, example = "2048")
@NotNull(message = "新审批人的用户编号不能为空")
private Long assigneeUserId;
}

View File

@@ -0,0 +1,142 @@
package cn.iocoder.yudao.adminserver.modules.bpm.convert.definition;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.definition.vo.model.*;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmModelMetaInfoRespDTO;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
import cn.iocoder.yudao.coreservice.modules.bpm.api.form.dto.BpmFormDTO;
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;
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
*
* @author yunlongn
*/
@Mapper
public interface BpmModelConvert {
BpmModelConvert INSTANCE = Mappers.getMapper(BpmModelConvert.class);
default List<BpmModelPageItemRespVO> convertList(List<Model> list, Map<Long, BpmFormDTO> formMap,
Map<String, Deployment> deploymentMap,
Map<String, ProcessDefinition> processDefinitionMap) {
return CollectionUtils.convertList(list, model -> {
BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
BpmFormDTO form = metaInfo != null ? formMap.get(metaInfo.getFormId()) : null;
Deployment deployment = model.getDeploymentId() != null ? deploymentMap.get(model.getDeploymentId()) : null;
ProcessDefinition processDefinition = model.getDeploymentId() != null ? processDefinitionMap.get(model.getDeploymentId()) : null;
return convert(model, form, deployment, processDefinition);
});
}
default BpmModelPageItemRespVO convert(Model model, BpmFormDTO form, Deployment deployment, ProcessDefinition processDefinition) {
BpmModelPageItemRespVO modelRespVO = new BpmModelPageItemRespVO();
modelRespVO.setId(model.getId());
modelRespVO.setCreateTime(model.getCreateTime());
// 通用 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() ?
SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode());
modelRespVO.getProcessDefinition().setDeploymentTime(deployment.getDeploymentTime());
}
return modelRespVO;
}
default BpmModelRespVO convert(Model model) {
BpmModelRespVO modelRespVO = new BpmModelRespVO();
modelRespVO.setId(model.getId());
modelRespVO.setCreateTime(model.getCreateTime());
// 通用 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 BpmProcessDefinitionCreateReqDTO convert2(Model model, BpmFormDTO form) {
BpmProcessDefinitionCreateReqDTO createReqDTO = new BpmProcessDefinitionCreateReqDTO();
createReqDTO.setModelId(model.getId());
createReqDTO.setName(model.getName());
createReqDTO.setKey(model.getKey());
createReqDTO.setCategory(model.getCategory());
BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
// metaInfo
copyTo(metaInfo, createReqDTO);
// form
if (form != null) {
createReqDTO.setFormConf(form.getConf());
createReqDTO.setFormFields(form.getFields());
}
return createReqDTO;
}
void copyTo(BpmModelMetaInfoRespDTO from, @MappingTarget BpmProcessDefinitionCreateReqDTO to);
default void copy(Model model, BpmModelCreateReqVO bean) {
model.setName(bean.getName());
model.setKey(bean.getKey());
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(buildMetaInfoStr(JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class),
bean.getDescription(), bean.getFormType(), bean.getFormId(),
bean.getFormCustomCreatePath(), bean.getFormCustomViewPath()));
}
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);
BpmModelCreateReqVO convert(BpmModeImportReqVO bean);
}

View File

@@ -0,0 +1,83 @@
package cn.iocoder.yudao.adminserver.modules.bpm.convert.definition;
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.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
import cn.iocoder.yudao.coreservice.modules.bpm.api.form.dto.BpmFormDTO;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import org.activiti.engine.impl.persistence.entity.SuspensionState;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
/**
* Bpm 流程定义的 Convert
*
* @author yunlong.li
*/
@Mapper
public interface BpmProcessDefinitionConvert {
BpmProcessDefinitionConvert INSTANCE = Mappers.getMapper(BpmProcessDefinitionConvert.class);
default List<BpmProcessDefinitionPageItemRespVO> convertList(List<ProcessDefinition> list, Map<String, Deployment> deploymentMap,
Map<String, BpmProcessDefinitionExtDO> processDefinitionDOMap, Map<Long, BpmFormDTO> formMap) {
return CollectionUtils.convertList(list, definition -> {
Deployment deployment = definition.getDeploymentId() != null ? deploymentMap.get(definition.getDeploymentId()) : null;
BpmProcessDefinitionExtDO definitionDO = processDefinitionDOMap.get(definition.getId());
BpmFormDTO form = definitionDO != null ? formMap.get(definitionDO.getFormId()) : null;
return convert(definition, deployment, definitionDO, form);
});
}
default BpmProcessDefinitionPageItemRespVO convert(ProcessDefinition bean, Deployment deployment,
BpmProcessDefinitionExtDO processDefinitionExtDO, BpmFormDTO form) {
BpmProcessDefinitionPageItemRespVO respVO = convert(bean);
respVO.setSuspensionState(bean.isSuspended() ? SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode());
if (deployment != null) {
respVO.setDeploymentTime(deployment.getDeploymentTime());
}
if (form != null) {
respVO.setFormName(form.getName());
}
// 复制通用属性
copyTo(processDefinitionExtDO, respVO);
return respVO;
}
BpmProcessDefinitionPageItemRespVO convert(ProcessDefinition bean);
BpmProcessDefinitionExtDO convert2(BpmProcessDefinitionCreateReqDTO bean);
default List<BpmProcessDefinitionRespVO> convertList3(List<ProcessDefinition> list,
Map<String, BpmProcessDefinitionExtDO> processDefinitionDOMap) {
return CollectionUtils.convertList(list, processDefinition -> {
BpmProcessDefinitionRespVO respVO = convert3(processDefinition);
BpmProcessDefinitionExtDO processDefinitionExtDO = processDefinitionDOMap.get(processDefinition.getId());
// 复制通用属性
copyTo(processDefinitionExtDO, respVO);
return respVO;
});
}
@Mapping(source = "suspended", target = "suspensionState", qualifiedByName = "convertSuspendedToSuspensionState")
BpmProcessDefinitionRespVO convert3(ProcessDefinition bean);
@Named("convertSuspendedToSuspensionState")
default Integer convertSuspendedToSuspensionState(boolean suspended) {
return suspended ? SuspensionState.SUSPENDED.getStateCode() :
SuspensionState.ACTIVE.getStateCode();
}
@Mapping(source = "from.id", target = "to.id", ignore = true)
void copyTo(BpmProcessDefinitionExtDO from, @MappingTarget BpmProcessDefinitionRespVO to);
}

View File

@@ -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);
}

View File

@@ -0,0 +1,57 @@
package cn.iocoder.yudao.adminserver.modules.bpm.convert.message;
import cn.iocoder.yudao.adminserver.modules.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO;
import cn.iocoder.yudao.adminserver.modules.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO;
import cn.iocoder.yudao.adminserver.modules.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.SysUserDO;
import org.activiti.api.task.model.Task;
import org.activiti.engine.runtime.ProcessInstance;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
@Mapper
public interface BpmMessageConvert {
BpmMessageConvert INSTANCE = Mappers.getMapper(BpmMessageConvert.class);
default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, SysUserDO startUser, Task task) {
BpmMessageSendWhenTaskCreatedReqDTO reqDTO = new BpmMessageSendWhenTaskCreatedReqDTO();
copyTo(processInstance, reqDTO);
copyTo(startUser, reqDTO);
copyTo(task, reqDTO);
return reqDTO;
}
@Mapping(source = "name", target = "processInstanceName")
void copyTo(ProcessInstance from, @MappingTarget BpmMessageSendWhenTaskCreatedReqDTO to);
@Mappings({
@Mapping(source = "id", target = "startUserId"),
@Mapping(source = "nickname", target = "startUserNickname")
})
void copyTo(SysUserDO from, @MappingTarget BpmMessageSendWhenTaskCreatedReqDTO to);
@Mappings({
@Mapping(source = "id", target = "taskId"),
@Mapping(source = "name", target = "taskName"),
@Mapping(source = "assignee", target = "assigneeUserId")
})
void copyTo(Task task, @MappingTarget BpmMessageSendWhenTaskCreatedReqDTO to);
default BpmMessageSendWhenProcessInstanceRejectReqDTO convert(ProcessInstance processInstance, String comment) {
BpmMessageSendWhenProcessInstanceRejectReqDTO reqDTO = new BpmMessageSendWhenProcessInstanceRejectReqDTO();
copyTo(processInstance, reqDTO);
reqDTO.setComment(comment);
return reqDTO;
}
@Mapping(source = "name", target = "processInstanceName")
void copyTo(ProcessInstance from, @MappingTarget BpmMessageSendWhenProcessInstanceRejectReqDTO to);
@Mappings({
@Mapping(source = "id", target = "processInstanceId"),
@Mapping(source = "name", target = "processInstanceName"),
@Mapping(source = "initiator", target = "startUserId")
})
BpmMessageSendWhenProcessInstanceApproveReqDTO convert(org.activiti.api.process.model.ProcessInstance processInstance);
}

View File

@@ -0,0 +1,30 @@
package cn.iocoder.yudao.adminserver.modules.bpm.convert.oa;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.oa.vo.BpmOALeaveCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.oa.vo.BpmOALeaveRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.leave.BpmOALeaveDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* 请假申请 Convert
*
* @author 芋艿
*/
@Mapper
public interface BpmOALeaveConvert {
BpmOALeaveConvert INSTANCE = Mappers.getMapper(BpmOALeaveConvert.class);
BpmOALeaveDO convert(BpmOALeaveCreateReqVO bean);
BpmOALeaveRespVO convert(BpmOALeaveDO bean);
List<BpmOALeaveRespVO> convertList(List<BpmOALeaveDO> list);
PageResult<BpmOALeaveRespVO> convertPage(PageResult<BpmOALeaveDO> page);
}

View File

@@ -0,0 +1,6 @@
/**
* 提供 POJO 类的实体转换
*
* 目前使用 MapStruct 框架
*/
package cn.iocoder.yudao.adminserver.modules.bpm.convert;

View File

@@ -0,0 +1,33 @@
package cn.iocoder.yudao.adminserver.modules.bpm.convert.task;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.activity.BpmActivityRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmTaskExtDO;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import org.activiti.engine.history.HistoricActivityInstance;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
/**
* BPM 活动 Convert
*
* @author 芋道源码
*/
@Mapper
public interface BpmActivityConvert {
BpmActivityConvert INSTANCE = Mappers.getMapper(BpmActivityConvert.class);
List<BpmActivityRespVO> convertList(List<HistoricActivityInstance> list);
@Mappings({
@Mapping(source = "activityId", target = "key"),
@Mapping(source = "activityType", target = "type")
})
BpmActivityRespVO convert(HistoricActivityInstance bean);
}

View File

@@ -0,0 +1,117 @@
package cn.iocoder.yudao.adminserver.modules.bpm.convert.task;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstancePageItemRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.instance.BpmProcessInstanceRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
import cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.event.BpmProcessInstanceResultEvent;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.SysDeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
/**
* 流程实例 Convert
*
* @author 芋道源码
*/
@Mapper
public interface BpmProcessInstanceConvert {
BpmProcessInstanceConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceConvert.class);
default BpmProcessInstanceExtDO convert3(ProcessInstance instance, ProcessDefinition definition) {
BpmProcessInstanceExtDO ext = new BpmProcessInstanceExtDO();
copyTo(instance, ext);
copyTo(definition, ext);
return ext;
}
@Mappings({
@Mapping(source = "from.id", target = "id", ignore = true),
@Mapping(source = "from.startTime", target = "createTime"),
})
void copyTo(ProcessInstance from, @MappingTarget BpmProcessInstanceExtDO to);
@Mapping(source = "from.id", target = "id", ignore = true)
void copyTo(ProcessDefinition from, @MappingTarget BpmProcessInstanceExtDO to);
default PageResult<BpmProcessInstancePageItemRespVO> convertPage(PageResult<BpmProcessInstanceExtDO> page,
Map<String, List<Task>> taskMap) {
List<BpmProcessInstancePageItemRespVO> list = convertList(page.getList());
list.forEach(respVO -> respVO.setTasks(convertList2(taskMap.get(respVO.getId()))));
return new PageResult<>(list, page.getTotal());
}
List<BpmProcessInstancePageItemRespVO> convertList(List<BpmProcessInstanceExtDO> list);
List<BpmProcessInstancePageItemRespVO.Task> convertList2(List<Task> tasks);
@Mapping(source = "processInstanceId", target = "id")
BpmProcessInstancePageItemRespVO convert(BpmProcessInstanceExtDO bean);
@Mappings({
@Mapping(source = "id", target = "processInstanceId"),
@Mapping(source = "id", target = "id", ignore = true),
@Mapping(source = "startDate", target = "createTime"),
@Mapping(source = "initiator", target = "startUserId"),
@Mapping(source = "status", target = "status", ignore = true)
})
BpmProcessInstanceExtDO convert(org.activiti.api.process.model.ProcessInstance bean);
default BpmProcessInstanceRespVO convert2(HistoricProcessInstance processInstance, BpmProcessInstanceExtDO processInstanceExt,
ProcessDefinition processDefinition, BpmProcessDefinitionExtDO processDefinitionExt,
String bpmnXml, SysUserDO startUser, SysDeptDO dept) {
BpmProcessInstanceRespVO respVO = convert2(processInstance);
copyTo(processInstanceExt, respVO);
// definition
respVO.setProcessDefinition(convert2(processDefinition));
copyTo(processDefinitionExt, respVO.getProcessDefinition());
respVO.getProcessDefinition().setBpmnXml(bpmnXml);
// user
if (startUser != null) {
respVO.setStartUser(convert2(startUser));
if (dept != null) {
respVO.getStartUser().setDeptName(dept.getName());
}
}
return respVO;
}
BpmProcessInstanceRespVO convert2(HistoricProcessInstance bean);
@Mapping(source = "from.id", target = "to.id", ignore = true)
void copyTo(BpmProcessInstanceExtDO from, @MappingTarget BpmProcessInstanceRespVO to);
BpmProcessInstanceRespVO.ProcessDefinition convert2(ProcessDefinition bean);
@Mapping(source = "from.id", target = "to.id", ignore = true)
void copyTo(BpmProcessDefinitionExtDO from, @MappingTarget BpmProcessInstanceRespVO.ProcessDefinition to);
BpmProcessInstanceRespVO.User convert2(SysUserDO bean);
default BpmProcessInstanceResultEvent convert(Object source, ProcessInstance instance, Integer result) {
BpmProcessInstanceResultEvent event = new BpmProcessInstanceResultEvent(source);
event.setId(instance.getId());
event.setProcessDefinitionKey(instance.getProcessDefinitionKey());
event.setBusinessKey(instance.getBusinessKey());
event.setResult(result);
return event;
}
default BpmProcessInstanceResultEvent convert(Object source, HistoricProcessInstance instance, Integer result) {
BpmProcessInstanceResultEvent event = new BpmProcessInstanceResultEvent(source);
event.setId(instance.getId());
event.setProcessDefinitionKey(instance.getProcessDefinitionKey());
event.setBusinessKey(instance.getBusinessKey());
event.setResult(result);
return event;
}
}

View File

@@ -0,0 +1,126 @@
package cn.iocoder.yudao.adminserver.modules.bpm.convert.task;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.BpmTaskDonePageItemRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.BpmTaskRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.BpmTaskTodoPageItemRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmTaskExtDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.SysDeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.persistence.entity.SuspensionState;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.mapstruct.*;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
/**
* Bpm 任务 Convert
*
* @author 芋道源码
*/
@Mapper
public interface BpmTaskConvert {
BpmTaskConvert INSTANCE = Mappers.getMapper(BpmTaskConvert.class);
default List<BpmTaskTodoPageItemRespVO> convertList1(List<Task> tasks, Map<String, ProcessInstance> processInstanceMap,
Map<Long, SysUserDO> userMap) {
return CollectionUtils.convertList(tasks, task -> {
BpmTaskTodoPageItemRespVO respVO = convert1(task);
ProcessInstance processInstance = processInstanceMap.get(task.getProcessInstanceId());
if (processInstance != null) {
SysUserDO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
respVO.setProcessInstance(convert(processInstance, startUser));
}
return respVO;
});
}
@Mapping(source = "suspended", target = "suspensionState", qualifiedByName = "convertSuspendedToSuspensionState")
BpmTaskTodoPageItemRespVO convert1(Task bean);
@Named("convertSuspendedToSuspensionState")
default Integer convertSuspendedToSuspensionState(boolean suspended) {
return suspended ? SuspensionState.SUSPENDED.getStateCode() :
SuspensionState.ACTIVE.getStateCode();
}
default List<BpmTaskDonePageItemRespVO> convertList2(List<HistoricTaskInstance> tasks, Map<String, BpmTaskExtDO> bpmTaskExtDOMap,
Map<String, HistoricProcessInstance> historicProcessInstanceMap,
Map<Long, SysUserDO> userMap) {
return CollectionUtils.convertList(tasks, task -> {
BpmTaskDonePageItemRespVO respVO = convert2(task);
BpmTaskExtDO taskExtDO = bpmTaskExtDOMap.get(task.getId());
copyTo(taskExtDO, respVO);
HistoricProcessInstance processInstance = historicProcessInstanceMap.get(task.getProcessInstanceId());
if (processInstance != null) {
SysUserDO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
respVO.setProcessInstance(convert(processInstance, startUser));
}
return respVO;
});
}
BpmTaskDonePageItemRespVO convert2(HistoricTaskInstance bean);
@Mappings({
@Mapping(source = "id", target = "taskId"),
@Mapping(source = "assignee", target = "assigneeUserId"),
@Mapping(source = "createdDate", target = "createTime")
})
BpmTaskExtDO convert(org.activiti.api.task.model.Task bean);
default List<BpmTaskRespVO> convertList3(List<HistoricTaskInstance> tasks, Map<String, BpmTaskExtDO> bpmTaskExtDOMap,
HistoricProcessInstance processInstance, Map<Long, SysUserDO> userMap,
Map<Long, SysDeptDO> deptMap) {
return CollectionUtils.convertList(tasks, task -> {
BpmTaskRespVO respVO = convert3(task);
BpmTaskExtDO taskExtDO = bpmTaskExtDOMap.get(task.getId());
copyTo(taskExtDO, respVO);
if (processInstance != null) {
SysUserDO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
respVO.setProcessInstance(convert(processInstance, startUser));
}
SysUserDO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee()));
if (assignUser != null) {
respVO.setAssigneeUser(convert3(assignUser));
SysDeptDO dept = deptMap.get(assignUser.getDeptId());
if (dept != null) {
respVO.getAssigneeUser().setDeptName(dept.getName());
}
}
return respVO;
});
}
@Mapping(source = "taskDefinitionKey", target = "definitionKey")
BpmTaskRespVO convert3(HistoricTaskInstance bean);
BpmTaskRespVO.User convert3(SysUserDO bean);
void copyTo(BpmTaskExtDO from, @MappingTarget BpmTaskDonePageItemRespVO to);
@Mappings({
@Mapping(source = "processInstance.id", target = "id"),
@Mapping(source = "processInstance.name", target = "name"),
@Mapping(source = "processInstance.startUserId", target = "startUserId"),
@Mapping(source = "processInstance.processDefinitionId", target = "processDefinitionId"),
@Mapping(source = "startUser.nickname", target = "startUserNickname")
})
BpmTaskTodoPageItemRespVO.ProcessInstance convert(ProcessInstance processInstance, SysUserDO startUser);
@Mappings({
@Mapping(source = "processInstance.id", target = "id"),
@Mapping(source = "processInstance.name", target = "name"),
@Mapping(source = "processInstance.startUserId", target = "startUserId"),
@Mapping(source = "processInstance.processDefinitionId", target = "processDefinitionId"),
@Mapping(source = "startUser.nickname", target = "startUserNickname")
})
BpmTaskTodoPageItemRespVO.ProcessInstance convert(HistoricProcessInstance processInstance, SysUserDO startUser);
}

View File

@@ -0,0 +1,92 @@
package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition;
import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmModelFormTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.*;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import java.util.List;
/**
* Bpm 流程定义的拓展表
* 主要解决 Activiti {@link ProcessDefinition} 不支持拓展字段,所以新建拓展表
*
* @author 芋道源码
*/
@TableName(value = "bpm_process_definition_ext", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BpmProcessDefinitionExtDO extends BaseDO {
/**
* 编号
*/
@TableId
private Long id;
/**
* 流程定义的编号
*
* 关联 {@link ProcessDefinition#getId()}
*/
private String processDefinitionId;
/**
* 流程模型的编号
*
* 关联 {@link Model#getId()}
*/
private String modelId;
/**
* 描述
*/
private String description;
/**
* 表单类型
*
* 关联 {@link BpmModelFormTypeEnum}
*/
private Integer formType;
/**
* 动态表单编号
* 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时
*
* 关联 {@link BpmFormDO#getId()}
*/
private Long formId;
/**
* 表单的配置
* 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时
*
* 冗余 {@link BpmFormDO#getConf()}
*/
private String formConf;
/**
* 表单项的数组
* 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL} 时
*
* 冗余 {@link BpmFormDO#getFields()} ()}
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> formFields;
/**
* 自定义表单的提交路径,使用 Vue 的路由地址
* 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时
*/
private String formCustomCreatePath;
/**
* 自定义表单的查看路径,使用 Vue 的路由地址
* 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时
*/
private String formCustomViewPath;
}

View File

@@ -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;
}

View File

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

View File

@@ -0,0 +1,74 @@
package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.leave;
import cn.iocoder.yudao.module.system.dal.dataobject.user.SysUserDO;
import lombok.*;
import java.util.*;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import org.activiti.engine.runtime.ProcessInstance;
/**
* OA 请假申请 DO
*
* {@link #day} 请假天数,目前先简单做。一般是分成请假上午和下午,可以是 1 整天,可以是 0.5 半天
*
* @author jason
* @author 芋道源码
*/
@TableName("bpm_oa_leave")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BpmOALeaveDO extends BaseDO {
/**
* 请假表单主键
*/
@TableId
private Long id;
/**
* 申请人的用户编号
*
* 关联 {@link SysUserDO#getId()}
*/
private Long userId;
/**
* 请假类型
*/
@TableField("`type`")
private String type;
/**
* 原因
*/
private String reason;
/**
* 开始时间
*/
private Date startTime;
/**
* 结束时间
*/
private Date endTime;
/**
* 请假天数
*/
private Long day;
/**
* 请假的结果
*
* 枚举 {@link cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum}
* 考虑到简单,所以直接复用了 BpmProcessInstanceResultEnum 枚举,也可以自己定义一个枚举哈
*/
private Integer result;
/**
* 对应的流程编号
*
* 关联 {@link ProcessInstance#getId()}
*/
private String processInstanceId;
}

View File

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

View File

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

View File

@@ -0,0 +1,23 @@
package cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.List;
@Mapper
public interface BpmProcessDefinitionExtMapper extends BaseMapperX<BpmProcessDefinitionExtDO> {
default List<BpmProcessDefinitionExtDO> selectListByProcessDefinitionIds(Collection<String> processDefinitionIds) {
return selectList("process_definition_id", processDefinitionIds);
}
default BpmProcessDefinitionExtDO selectByProcessDefinitionId(String processDefinitionId) {
return selectOne("process_definition_id", processDefinitionId);
}
}

View File

@@ -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));
}
}

View File

@@ -0,0 +1,29 @@
package cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.oa;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.oa.vo.BpmOALeavePageReqVO;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.leave.BpmOALeaveDO;
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.LambdaQueryWrapperX;
import org.apache.ibatis.annotations.Mapper;
/**
* 请假申请 Mapper
*
* @author jason
* @author 芋道源码
*/
@Mapper
public interface BpmOALeaveMapper extends BaseMapperX<BpmOALeaveDO> {
default PageResult<BpmOALeaveDO> selectPage(Long userId, BpmOALeavePageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<BpmOALeaveDO>()
.eqIfPresent(BpmOALeaveDO::getUserId, userId)
.eqIfPresent(BpmOALeaveDO::getResult, reqVO.getResult())
.eqIfPresent(BpmOALeaveDO::getType, reqVO.getType())
.likeIfPresent(BpmOALeaveDO::getReason, reqVO.getReason())
.betweenIfPresent(BpmOALeaveDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
.orderByDesc(BpmOALeaveDO::getId));
}
}

View File

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

View File

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

View File

@@ -0,0 +1,58 @@
package cn.iocoder.yudao.adminserver.modules.bpm.enums;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
/**
* 工作流 错误码枚举类
*
* 工作流系统,使用 1-009-000-000 段
*/
public interface BpmErrorCodeConstants {
// ========== 通用流程处理 模块 1-009-000-000 ==========
ErrorCode HIGHLIGHT_IMG_ERROR = new ErrorCode(1009000002, "获取高亮流程图异常");
// ========== OA 流程模块 1-009-001-000 ==========
ErrorCode OA_LEAVE_NOT_EXISTS = new ErrorCode(1009001001, "请假申请不存在");
ErrorCode OA_PM_POST_NOT_EXISTS = new ErrorCode(1009001002, "项目经理岗位未设置");
ErrorCode OA_DEPART_PM_POST_NOT_EXISTS = new ErrorCode(1009001009, "部门的项目经理不存在");
ErrorCode OA_BM_POST_NOT_EXISTS = new ErrorCode(1009001004, "部门经理岗位未设置");
ErrorCode OA_DEPART_BM_POST_NOT_EXISTS = new ErrorCode(1009001005, "部门的部门经理不存在");
ErrorCode OA_HR_POST_NOT_EXISTS = new ErrorCode(1009001006, "HR岗位未设置");
ErrorCode OA_DAY_LEAVE_ERROR = new ErrorCode(1009001007, "请假天数必须>=1");
// ========== 流程模型 1-009-002-000 ==========
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, "部署流程失败," +
"原因:用户任务({})未配置分配规则,请点击【修改流程】按钮进行配置");
ErrorCode MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS = new ErrorCode(1009003005, "流程定义部署失败,原因:信息未发生变化");
// ========== 流程定义 1-009-003-000 ==========
ErrorCode PROCESS_DEFINITION_KEY_NOT_MATCH = new ErrorCode(1009003000, "流程定义的标识期望是({}),当前是({}),请修改 BPMN 流程图");
ErrorCode PROCESS_DEFINITION_NAME_NOT_MATCH = new ErrorCode(1009003001, "流程定义的名字期望是({}),当前是({}),请修改 BPMN 流程图");
ErrorCode PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1009003002, "流程定义不存在");
ErrorCode PROCESS_DEFINITION_IS_SUSPENDED = new ErrorCode(1009003003, "流程定义处于挂起状态");
ErrorCode PROCESS_DEFINITION_BPMN_MODEL_NOT_EXISTS = new ErrorCode(1009003004, "流程定义的模型不存在");
// ========== 流程实例 1-009-004-000 ==========
ErrorCode PROCESS_INSTANCE_NOT_EXISTS = new ErrorCode(1009004000, "流程实例不存在");
ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS = new ErrorCode(1009004001, "流程取消失败,流程不处于运行中");
ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF = new ErrorCode(1009004002, "流程取消失败,该流程不是你发起的");
// ========== 流程任务 1-009-005-000 ==========
ErrorCode TASK_COMPLETE_FAIL_NOT_EXISTS = new ErrorCode(1009004000, "审批任务失败,原因:该任务不处于未审批");
ErrorCode TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF = new ErrorCode(1009004001, "审批任务失败,原因:该任务的审批人不是你");
// ========== 流程任务分配规则 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, "动态表单不存在");
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -0,0 +1,30 @@
package cn.iocoder.yudao.adminserver.modules.bpm.enums.definition;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* BPM 任务规则的脚本枚举
* 目前暂时通过 TODO 芋艿:硬编码,未来可以考虑 Groovy 动态脚本的方式
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum BpmTaskRuleScriptEnum {
START_USER(10L, "流程发起人"),
LEADER_X1(20L, "流程发起人的一级领导"),
LEADER_X2(21L, "流程发起人的二级领导");
/**
* 脚本编号
*/
private final Long id;
/**
* 脚本描述
*/
private final String desc;
}

View File

@@ -0,0 +1,28 @@
package cn.iocoder.yudao.adminserver.modules.bpm.enums.message;
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SysSmsTemplateDO;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Bpm 消息的枚举
*
* @author 芋道源码
*/
@AllArgsConstructor
@Getter
public enum BpmMessageEnum {
PROCESS_INSTANCE_APPROVE("bpm_process_instance_approve"), // 流程任务被审批通过时,发送给申请人
PROCESS_INSTANCE_REJECT("bpm_process_instance_reject"), // 流程任务被审批不通过时,发送给申请人
TASK_ASSIGNED("bpm_task_assigned"); // 任务被分配时,发送给审批人
/**
* 短信模板的标识
*
* 关联 {@link SysSmsTemplateDO#getCode()}
*/
private final String smsCode;
}

View File

@@ -0,0 +1,37 @@
package cn.iocoder.yudao.adminserver.modules.bpm.enums.task;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 流程实例的删除原因
*
* @author 芋道源码
*/
@Getter
@AllArgsConstructor
public enum BpmProcessInstanceDeleteReasonEnum {
REJECT_TASK("不通过任务,原因:{}"), // 修改文案时,需要注意 isRejectReason 方法
CANCEL_TASK("主动取消任务,原因:{}");
private final String reason;
/**
* 格式化理由
*
* @param args 参数
* @return 理由
*/
public String format(Object... args) {
return StrUtil.format(reason, args);
}
// ========== 逻辑 ==========
public static boolean isRejectReason(String reason) {
return StrUtil.startWith(reason, "不通过任务,原因:");
}
}

View File

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

View File

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

View File

@@ -0,0 +1,90 @@
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.event.BpmProcessInstanceResultEventPublisher;
import cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.identity.EmptyUserGroupManager;
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.coreservice.modules.bpm.api.group.BpmUserGroupServiceApi;
import cn.iocoder.yudao.module.system.service.dept.SysDeptCoreService;
import cn.iocoder.yudao.module.system.service.permission.SysPermissionCoreService;
import cn.iocoder.yudao.module.system.service.user.SysUserCoreService;
import cn.iocoder.yudao.coreservice.modules.system.service.dept.SysDeptCoreService;
import cn.iocoder.yudao.coreservice.modules.system.service.permission.SysPermissionCoreService;
import cn.iocoder.yudao.coreservice.modules.system.service.user.SysUserCoreService;
import org.activiti.api.runtime.shared.identity.UserGroupManager;
import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
import org.springframework.context.ApplicationEventPublisher;
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 {
/**
* 空用户组的 Bean
*/
@Bean
public UserGroupManager userGroupManager() {
return new EmptyUserGroupManager();
}
/**
* 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,
SysPermissionCoreService permissionCoreService,
SysDeptCoreService deptCoreService,
BpmUserGroupServiceApi userGroupServiceApi,
SysUserCoreService userCoreService,
List<BpmTaskAssignScript> scripts) {
BpmActivityBehaviorFactory bpmActivityBehaviorFactory = new BpmActivityBehaviorFactory();
bpmActivityBehaviorFactory.setBpmTaskRuleService(taskRuleService);
bpmActivityBehaviorFactory.setPermissionCoreService(permissionCoreService);
bpmActivityBehaviorFactory.setDeptCoreService(deptCoreService);
bpmActivityBehaviorFactory.setUserGroupServiceApi(userGroupServiceApi);
bpmActivityBehaviorFactory.setUserCoreService(userCoreService);
bpmActivityBehaviorFactory.setScripts(scripts);
return bpmActivityBehaviorFactory;
}
@Bean
public BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher(ApplicationEventPublisher publisher) {
return new BpmProcessInstanceResultEventPublisher(publisher);
}
}

View File

@@ -0,0 +1,59 @@
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.coreservice.modules.bpm.api.group.BpmUserGroupServiceApi;
import cn.iocoder.yudao.module.system.service.dept.SysDeptCoreService;
import cn.iocoder.yudao.module.system.service.permission.SysPermissionCoreService;
import cn.iocoder.yudao.module.system.service.user.SysUserCoreService;
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 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 SysPermissionCoreService permissionCoreService;
@Setter
private SysDeptCoreService deptCoreService;
@Setter
private BpmUserGroupServiceApi userGroupServiceApi;
@Setter
private SysUserCoreService userCoreService;
@Setter
private List<BpmTaskAssignScript> scripts;
@Override
public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) {
BpmUserTaskActivitiBehavior userTaskActivityBehavior = new BpmUserTaskActivitiBehavior(userTask);
userTaskActivityBehavior.setBpmTaskRuleService(bpmTaskRuleService);
userTaskActivityBehavior.setPermissionCoreService(permissionCoreService);
userTaskActivityBehavior.setDeptCoreService(deptCoreService);
userTaskActivityBehavior.setUserGroupServiceApi(userGroupServiceApi);
userTaskActivityBehavior.setSysUserCoreService(userCoreService);
userTaskActivityBehavior.setScripts(scripts);
return userTaskActivityBehavior;
}
// TODO 芋艿:并行任务 ParallelMultiInstanceBehavior
// TODO 芋艿:并行任务 SequentialMultiInstanceBehavior
}

View File

@@ -0,0 +1,193 @@
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.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.coreservice.modules.bpm.api.group.BpmUserGroupServiceApi;
import cn.iocoder.yudao.coreservice.modules.bpm.api.group.dto.BpmUserGroupDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.SysDeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.module.system.service.dept.SysDeptCoreService;
import cn.iocoder.yudao.module.system.service.permission.SysPermissionCoreService;
import cn.iocoder.yudao.module.system.service.user.SysUserCoreService;
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.exception;
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 负责人的分配
* 第一步,获得对应的分配规则;
* 第二步,根据分配规则,计算出分配任务的候选人。如果找不到,则直接报业务异常,不继续执行后续的流程;
* 第三步,随机选择一个候选人,则选择作为 assignee 负责人。
*
* @author 芋道源码
*/
@Slf4j
public class BpmUserTaskActivitiBehavior extends UserTaskActivityBehavior {
@Setter
private BpmTaskAssignRuleService bpmTaskRuleService;
@Setter
private SysPermissionCoreService permissionCoreService;
@Setter
private SysDeptCoreService deptCoreService;
@Setter
private BpmUserGroupServiceApi userGroupServiceApi;
@Setter
private SysUserCoreService sysUserCoreService;
/**
* 任务分配脚本
*/
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));
}
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 permissionCoreService.getUserRoleIdListByRoleIds(rule.getOptions());
}
private Set<Long> calculateTaskCandidateUsersByDeptMember(TaskEntity task, BpmTaskAssignRuleDO rule) {
List<SysUserDO> users = sysUserCoreService.getUsersByDeptIds(rule.getOptions());
return convertSet(users, SysUserDO::getId);
}
private Set<Long> calculateTaskCandidateUsersByDeptLeader(TaskEntity task, BpmTaskAssignRuleDO rule) {
List<SysDeptDO> depts = deptCoreService.getDepts(rule.getOptions());
return convertSet(depts, SysDeptDO::getLeaderUserId);
}
private Set<Long> calculateTaskCandidateUsersByPost(TaskEntity task, BpmTaskAssignRuleDO rule) {
List<SysUserDO> users = sysUserCoreService.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<BpmUserGroupDTO> userGroups = userGroupServiceApi.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 = sysUserCoreService.getUserMap(assigneeUserIds);
assigneeUserIds.removeIf(id -> {
SysUserDO user = userMap.get(id);
return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus());
});
}
}

View File

@@ -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;

View File

@@ -0,0 +1,35 @@
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;
import java.util.Set;
/**
* Bpm 任务分配的自定义 Script 脚本
* 使用场景:
* 1. 设置审批人为发起人
* 2. 设置审批人为发起人的 Leader
* 3. 甚至审批人为发起人的 Leader 的 Leader
*
* @author 芋道源码
*/
public interface BpmTaskAssignScript {
/**
* 基于流程任务,获得任务的候选用户们
*
* @param task 任务
* @return 候选人用户的编号数组
*/
Set<Long> calculateTaskCandidateUsers(TaskEntity task);
/**
* 获得枚举值
*
* @return 枚举值
*/
BpmTaskRuleScriptEnum getEnum();
}

View File

@@ -0,0 +1,62 @@
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.script.impl;
import cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.script.BpmTaskAssignScript;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.SysDeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.module.system.service.dept.SysDeptCoreService;
import cn.iocoder.yudao.module.system.service.user.SysUserCoreService;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.springframework.util.Assert;
import javax.annotation.Resource;
import java.util.Set;
import static java.util.Collections.emptySet;
/**
* 分配给发起人的 Leader 审批的 Script 实现类
* 目前 Leader 的定义是,
*
* @author 芋道源码
*/
public abstract class BpmTaskAssignLeaderAbstractScript implements BpmTaskAssignScript {
@Resource
private SysUserCoreService userCoreService;
@Resource
private SysDeptCoreService deptCoreService;
protected Set<Long> calculateTaskCandidateUsers(TaskEntity task, int level) {
Assert.isTrue(level > 0, "level 必须大于 0");
// 获得发起人
Long startUserId = Long.parseLong(task.getProcessInstance().getStartUserId());
// 获得对应 leve 的部门
SysDeptDO dept = null;
for (int i = 0; i < level; i++) {
// 获得 level 对应的部门
if (dept == null) {
dept = getStartUserDept(startUserId);
if (dept == null) { // 找不到发起人的部门,所以无法使用该规则
return emptySet();
}
} else {
SysDeptDO parentDept = deptCoreService.getDept(dept.getParentId());
if (parentDept == null) { // 找不到父级部门,所以只好结束寻找。原因是:例如说,级别比较高的人,所在部门层级比较少
break;
}
dept = parentDept;
}
}
return dept.getLeaderUserId() != null ? asSet(dept.getLeaderUserId()) : emptySet();
}
private SysDeptDO getStartUserDept(Long startUserId) {
SysUserDO startUser = userCoreService.getUser(startUserId);
if (startUser.getDeptId() == null) { // 找不到部门,所以无法使用该规则
return null;
}
return deptCoreService.getDept(startUser.getDeptId());
}
}

View File

@@ -0,0 +1,27 @@
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.script.impl;
import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmTaskRuleScriptEnum;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.springframework.stereotype.Component;
import java.util.Set;
/**
* 分配给发起人的一级 Leader 审批的 Script 实现类
*
* @author 芋道源码
*/
@Component
public class BpmTaskAssignLeaderX1Script extends BpmTaskAssignLeaderAbstractScript {
@Override
public Set<Long> calculateTaskCandidateUsers(TaskEntity task) {
return calculateTaskCandidateUsers(task, 1);
}
@Override
public BpmTaskRuleScriptEnum getEnum() {
return BpmTaskRuleScriptEnum.LEADER_X1;
}
}

View File

@@ -0,0 +1,27 @@
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.script.impl;
import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmTaskRuleScriptEnum;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.springframework.stereotype.Component;
import java.util.Set;
/**
* 分配给发起人的二级 Leader 审批的 Script 实现类
*
* @author 芋道源码
*/
@Component
public class BpmTaskAssignLeaderX2Script extends BpmTaskAssignLeaderAbstractScript {
@Override
public Set<Long> calculateTaskCandidateUsers(TaskEntity task) {
return calculateTaskCandidateUsers(task, 2);
}
@Override
public BpmTaskRuleScriptEnum getEnum() {
return BpmTaskRuleScriptEnum.LEADER_X2;
}
}

View File

@@ -0,0 +1,30 @@
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.script.impl;
import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmTaskRuleScriptEnum;
import cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.script.BpmTaskAssignScript;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.springframework.stereotype.Component;
import java.util.Set;
/**
* 分配给发起人审批的 Script 实现类
*
* @author 芋道源码
*/
@Component
public class BpmTaskAssignStartUserScript implements BpmTaskAssignScript {
@Override
public Set<Long> calculateTaskCandidateUsers(TaskEntity task) {
Long userId = Long.parseLong(task.getProcessInstance().getStartUserId());
return SetUtils.asSet(userId);
}
@Override
public BpmTaskRuleScriptEnum getEnum() {
return BpmTaskRuleScriptEnum.START_USER;
}
}

View File

@@ -0,0 +1,44 @@
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.event;
import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
import lombok.Data;
import org.springframework.context.ApplicationEvent;
import javax.validation.constraints.NotNull;
/**
* 流程实例的结果发生变化的 Event
* 定位:由于额外增加了 {@link BpmProcessInstanceExtDO#getResult()} 结果,所以增加该事件
*
* @author 芋道源码
*/
@SuppressWarnings("ALL")
@Data
public class BpmProcessInstanceResultEvent extends ApplicationEvent {
/**
* 流程实例的编号
*/
@NotNull(message = "流程实例的编号不能为空")
private String id;
/**
* 流程实例的 key
*/
@NotNull(message = "流程实例的 key 不能为空")
private String processDefinitionKey;
/**
* 流程实例的结果
*/
@NotNull(message = "流程实例的结果不能为空")
private Integer result;
/**
* 流程实例对应的业务标识
* 例如说,请假
*/
private String businessKey;
public BpmProcessInstanceResultEvent(Object source) {
super(source);
}
}

View File

@@ -0,0 +1,34 @@
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.event;
import cn.hutool.core.util.StrUtil;
import org.springframework.context.ApplicationListener;
/**
* {@link BpmProcessInstanceResultEvent} 的监听器
*
* @author 芋道源码
*/
public abstract class BpmProcessInstanceResultEventListener
implements ApplicationListener<BpmProcessInstanceResultEvent> {
@Override
public final void onApplicationEvent(BpmProcessInstanceResultEvent event) {
if (!StrUtil.equals(event.getProcessDefinitionKey(), getProcessDefinitionKey())) {
return;
}
onEvent(event);
}
/**
* @return 返回监听的流程定义 Key
*/
protected abstract String getProcessDefinitionKey();
/**
* 处理事件
*
* @param event 事件
*/
protected abstract void onEvent(BpmProcessInstanceResultEvent event);
}

View File

@@ -0,0 +1,24 @@
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.event;
import lombok.AllArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.validation.annotation.Validated;
import javax.validation.Valid;
/**
* {@link BpmProcessInstanceResultEvent} 的生产者
*
* @author 芋道源码
*/
@AllArgsConstructor
@Validated
public class BpmProcessInstanceResultEventPublisher {
private final ApplicationEventPublisher publisher;
public void sendProcessInstanceResultEvent(@Valid BpmProcessInstanceResultEvent event) {
publisher.publishEvent(event);
}
}

View File

@@ -0,0 +1,6 @@
/**
* 自定义 Event 实现,提供方便业务接入的 Listener
*
* @author 芋道源码
*/
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.event;

View File

@@ -0,0 +1,37 @@
package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.identity;
import org.activiti.api.runtime.shared.identity.UserGroupManager;
import java.util.Collections;
import java.util.List;
/**
* 空的 UserGroupManager 实现类,用于禁用 Activiti 自带的用户组实现。
* 原因是,我们使用了自己实现的任务分配规则,所以不需要 Activiti。
* 如果不去禁用,会存在一些场景下,会去查询用户所在的用户组,导致报错。
*
* @author 芋道源码
*/
public class EmptyUserGroupManager implements UserGroupManager {
@Override
public List<String> getUserGroups(String s) {
return Collections.emptyList();
}
@Override
public List<String> getUserRoles(String s) {
return Collections.emptyList();
}
@Override
public List<String> getGroups() {
return Collections.emptyList();
}
@Override
public List<String> getUsers() {
return Collections.emptyList();
}
}

View File

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

View File

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

View File

@@ -0,0 +1,66 @@
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;
import javax.annotation.Resource;
/**
* 监听 {@link Task} 的开始与完成,创建与更新对应的 {@link BpmTaskExtDO} 记录
*
* @author 芋道源码
*/
@Component
public class BpmTaskEventListener<T extends RuntimeEvent<?, ?>>
implements TaskRuntimeEventListener<T> {
@Resource
@Lazy // 解决循环依赖
private BpmTaskService taskService;
@Override
@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());
return;
}
// 取消时,更新拓展表为取消
if (event.getEventType() == TaskRuntimeEvent.TaskEvents.TASK_CANCELLED) {
taskService.updateTaskExtCancel(event.getEntity());
return;
}
// 完成时,更新拓展表为已完成。要注意,在调用 delete ProcessInstance 才会触发该逻辑
if (event.getEventType() == TaskRuntimeEvent.TaskEvents.TASK_COMPLETED) {
taskService.updateTaskExtComplete(event.getEntity());
return;
}
// 审核人修改时,进行拓展表,并额外发送通知
if (event.getEventType() == TaskRuntimeEvent.TaskEvents.TASK_ASSIGNED) {
taskService.updateTaskExtAssign(event.getEntity());
return;
}
// 其它事件,进行更新拓展表
taskService.updateTaskExt(event.getEntity());
}
}

View File

@@ -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;

View File

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

View File

@@ -0,0 +1,9 @@
/**
* bpm 包下业务流程管理Business Process Management我们放工作流的功能基于 activiti 7 版本实现。
* 例如说:流程定义、表单配置、审核中心(我的申请、我的待办、我的已办)等等
*
* bpm 解释https://baike.baidu.com/item/BPM/1933
*
* 缩写bpm
*/
package cn.iocoder.yudao.adminserver.modules.bpm;

View File

@@ -0,0 +1,78 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.definition;
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;
/**
* 流程模型接口
*
* @author yunlongn
*/
public interface BpmModelService {
/**
* 获得流程模型分页
*
* @param pageVO 分页查询
* @return 流程模型分页
*/
PageResult<BpmModelPageItemRespVO> getModelPage(ModelPageReqVO pageVO);
/**
* 获得流程模块
*
* @param id 编号
* @return 流程模型
*/
BpmModelRespVO getModel(String id);
/**
* 创建流程模型
*
* @param modelVO 创建信息
* @param bpmnXml BPMN XML
* @return 创建的流程模型的编号
*/
String createModel(@Valid BpmModelCreateReqVO modelVO, String bpmnXml);
/**
* 修改流程模型
*
* @param updateReqVO 更新信息
*/
void updateModel(@Valid BpmModelUpdateReqVO updateReqVO);
/**
* 将流程模型,部署成一个流程定义
*
* @param id 编号
*/
void deployModel(String id);
/**
* 删除模型
*
* @param id 编号
*/
void deleteModel(String id);
/**
* 修改模型的状态,实际更新的部署的流程定义的状态
*
* @param id 编号
* @param state 状态 {@link org.activiti.engine.impl.persistence.entity.SuspensionState}
*/
void updateModelState(String id, Integer state);
/**
* 获得流程模型编号对应的 BPMN Model
*
* @param id 流程模型编号
* @return BPMN Model
*/
BpmnModel getBpmnModel(String id);
}

View File

@@ -0,0 +1,161 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.definition;
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.dal.dataobject.definition.BpmProcessDefinitionExtDO;
import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 流程定义接口
*
* @author yunlong.li
* @author ZJQ
* @author 芋道源码
*/
public interface BpmProcessDefinitionService {
/**
* 获得流程定义分页
*
* @param pageReqVO 分页入参
* @return 流程定义 Page
*/
PageResult<BpmProcessDefinitionPageItemRespVO> getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageReqVO);
/**
* 获得流程定义列表
*
* @param listReqVO 列表入参
* @return 流程定义列表
*/
List<BpmProcessDefinitionRespVO> getProcessDefinitionList(BpmProcessDefinitionListReqVO listReqVO);
/**
* 获得流程定义对应的 BPMN XML
*
* @param id 流程定义编号
* @return BPMN XML
*/
String getProcessDefinitionBpmnXML(String id);
/**
* 获得 Bpmn 模型
*
* @param processDefinitionId 流程定义的编号
* @return Bpmn 模型
*/
BpmnModel getBpmnModel(String processDefinitionId);
/**
* 获得编号对应的 ProcessDefinition
*
* @param id 编号
* @return 流程定义
*/
ProcessDefinition getProcessDefinition(String id);
/**
* 获得编号对应的 ProcessDefinition
*
* 相比 {@link #getProcessDefinition(String)} 方法category 的取值是正确
*
* @param id 编号
* @return 流程定义
*/
ProcessDefinition getProcessDefinition2(String id);
/**
* 获得流程定义标识对应的激活的流程定义
*
* @param key 流程定义的标识
* @return 流程定义
*/
ProcessDefinition getActiveProcessDefinition(String key);
/**
* 获得编号对应的 BpmProcessDefinitionExtDO
*
* @param id 编号
* @return 流程定义拓展
*/
BpmProcessDefinitionExtDO getProcessDefinitionExt(String id);
/**
* 获得 id 对应的 Deployment
*
* @param id 部署编号
* @return 流程部署
*/
Deployment getDeployment(String id);
/**
* 获得 ids 对应的 Deployment 数组
*
* @param ids 部署编号的数组
* @return 流程部署的数组
*/
List<Deployment> getDeployments(Set<String> ids);
/**
* 获得 ids 对应的 Deployment Map
*
* @param ids 部署编号的数组
* @return 流程部署 Map
*/
default Map<String, Deployment> getDeploymentMap(Set<String> ids) {
return CollectionUtils.convertMap(getDeployments(ids), Deployment::getId);
}
/**
* 获得 deploymentId 对应的 ProcessDefinition
*
* @param deploymentId 部署编号
* @return 流程定义
*/
ProcessDefinition getProcessDefinitionByDeploymentId(String deploymentId);
/**
* 获得 deploymentIds 对应的 ProcessDefinition 数组
*
* @param deploymentIds 部署编号的数组
* @return 流程定义的数组
*/
List<ProcessDefinition> getProcessDefinitionListByDeploymentIds(Set<String> deploymentIds);
/**
* 获得需要创建的流程定义,是否和当前激活的流程定义相等
*
* @param createReqDTO 创建信息
* @return 是否相等
*/
boolean isProcessDefinitionEquals(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO);
/**
* 创建流程定义
*
* @param createReqDTO 创建信息
* @return 流程编号
*/
String createProcessDefinition(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO);
/**
* 更新流程定义的挂起状态
*
* @param id 流程定义的编号
* @param state 挂起状态 {@link org.activiti.engine.impl.persistence.entity.SuspensionState}
*/
void updateProcessDefinitionState(String id, Integer state);
}

View File

@@ -0,0 +1,80 @@
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 modelId 流程模型编号
* @param processDefinitionId 流程定义编号
* @return 是否相等
*/
boolean isTaskAssignRulesEquals(String modelId, String processDefinitionId);
/**
* 将流程流程模型的任务分配规则,复制一份给流程定义
* 目的:每次流程模型部署时,都会生成一个新的流程定义,此时考虑到每次部署的流程不可变性,所以需要复制一份给该流程定义
*
* @param fromModelId 流程模型编号
* @param toProcessDefinitionId 流程定义编号
*/
void copyTaskAssignRules(String fromModelId, String toProcessDefinitionId);
}

View File

@@ -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;
}

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