feat:增加 bpm 工作流的能力
This commit is contained in:
33
yudao-module-bpm/yudao-module-bpm-api/pom.xml
Normal file
33
yudao-module-bpm/yudao-module-bpm-api/pom.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?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.cloud</groupId>
|
||||
<artifactId>yudao-module-bpm</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>yudao-module-bpm-api</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
bpm 模块 API,暴露给其它模块调用
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.cloud</groupId>
|
||||
<artifactId>yudao-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 参数校验 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* bpm API 包,定义暴露给其它模块的 API
|
||||
*/
|
||||
package cn.iocoder.yudao.module.bpm.api;
|
||||
@@ -0,0 +1,23 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.task;
|
||||
|
||||
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
/**
|
||||
* 流程实例 Api 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface BpmProcessInstanceApi {
|
||||
|
||||
/**
|
||||
* 创建流程实例(提供给内部)
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param reqDTO 创建信息
|
||||
* @return 实例的编号
|
||||
*/
|
||||
String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO reqDTO);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package cn.iocoder.yudao.module.bpm.api.task.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程实例的创建 Request DTO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class BpmProcessInstanceCreateReqDTO {
|
||||
|
||||
/**
|
||||
* 流程定义的标识
|
||||
*/
|
||||
@NotEmpty(message = "流程定义的标识不能为空")
|
||||
private String processDefinitionKey;
|
||||
/**
|
||||
* 变量实例
|
||||
*/
|
||||
private Map<String, Object> variables;
|
||||
|
||||
/**
|
||||
* 业务的唯一标识
|
||||
*
|
||||
* 例如说,请假申请的编号。通过它,可以查询到对应的实例
|
||||
*/
|
||||
@NotEmpty(message = "业务的唯一标识")
|
||||
private String businessKey;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package cn.iocoder.yudao.module.bpm.enums;
|
||||
|
||||
/**
|
||||
* BPM 字典类型的枚举类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface DictTypeConstants {
|
||||
|
||||
String TASK_ASSIGN_RULE_TYPE = "bpm_task_assign_rule_type"; // 任务分配规则类型
|
||||
String TASK_ASSIGN_SCRIPT = "bpm_task_assign_script"; // 任务分配自定义脚本
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package cn.iocoder.yudao.module.bpm.enums;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
||||
|
||||
/**
|
||||
* 工作流 错误码枚举类
|
||||
*
|
||||
* 工作流系统,使用 1-009-000-000 段
|
||||
*/
|
||||
public interface ErrorCodeConstants {
|
||||
|
||||
// ========== 通用流程处理 模块 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(1009005000, "审批任务失败,原因:该任务不处于未审批");
|
||||
ErrorCode TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF = new ErrorCode(1009005001, "审批任务失败,原因:该任务的审批人不是你");
|
||||
|
||||
// ========== 流程任务分配规则 1-009-006-000 ==========
|
||||
ErrorCode TASK_ASSIGN_RULE_EXISTS = new ErrorCode(1009006000, "流程({}) 的任务({}) 已经存在分配规则");
|
||||
ErrorCode TASK_ASSIGN_RULE_NOT_EXISTS = new ErrorCode(1009006001, "流程任务分配规则不存在");
|
||||
ErrorCode TASK_UPDATE_FAIL_NOT_MODEL = new ErrorCode(1009006002, "只有流程模型的任务分配规则,才允许被修改");
|
||||
ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1009006003, "操作失败,原因:找不到任务的审批人!");
|
||||
ErrorCode TASK_ASSIGN_SCRIPT_NOT_EXISTS = new ErrorCode(1009006004, "操作失败,原因:任务分配脚本({}) 不存在");
|
||||
|
||||
// ========== 动态表单模块 1-009-010-000 ==========
|
||||
ErrorCode FORM_NOT_EXISTS = new ErrorCode(1009010000, "动态表单不存在");
|
||||
ErrorCode FORM_FIELD_REPEAT = new ErrorCode(1009010001, "表单项({}) 和 ({}) 使用了相同的字段名({})");
|
||||
|
||||
// ========== 用户组模块 1-009-011-000 ==========
|
||||
ErrorCode USER_GROUP_NOT_EXISTS = new ErrorCode(1009011000, "用户组不存在");
|
||||
ErrorCode USER_GROUP_IS_DISABLE = new ErrorCode(1009011001, "名字为【{}】的用户组已被禁用");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package cn.iocoder.yudao.module.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;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package cn.iocoder.yudao.module.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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package cn.iocoder.yudao.module.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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.iocoder.yudao.module.bpm.enums.message;
|
||||
|
||||
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"); // 任务被分配时,发送给审批人
|
||||
|
||||
/**
|
||||
* 短信模板的标识
|
||||
*
|
||||
* 关联 SmsTemplateDO 的 code 属性
|
||||
*/
|
||||
private final String smsTemplateCode;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package cn.iocoder.yudao.module.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("主动取消任务,原因:{}"),
|
||||
|
||||
// ========== 流程任务的独有原因 ==========
|
||||
MULTI_TASK_END("系统自动取消,原因:多任务审批已经满足条件,无需审批该任务"), // 多实例满足 condition 而结束时,其它任务实例任务会被取消,对应的删除原因是 MI_END
|
||||
|
||||
;
|
||||
|
||||
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, "不通过任务,原因:");
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 Flowable 的删除原因,翻译成对应的中文原因
|
||||
*
|
||||
* @param reason 原始原因
|
||||
* @return 原因
|
||||
*/
|
||||
public static String translateReason(String reason) {
|
||||
if (StrUtil.isEmpty(reason)) {
|
||||
return reason;
|
||||
}
|
||||
switch (reason) {
|
||||
case "MI_END": return MULTI_TASK_END.getReason();
|
||||
default: return reason;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package cn.iocoder.yudao.module.bpm.enums.task;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 流程实例的结果
|
||||
*
|
||||
* @author jason
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum BpmProcessInstanceResultEnum {
|
||||
|
||||
PROCESS(1, "处理中"),
|
||||
APPROVE(2, "通过"),
|
||||
REJECT(3, "不通过"),
|
||||
CANCEL(4, "已取消"),
|
||||
|
||||
// ========== 流程任务独有的状态 ==========
|
||||
|
||||
BACK(5, "退回/驳回");
|
||||
|
||||
/**
|
||||
* 结果
|
||||
*
|
||||
* 如果新增时,注意 {@link #isEndResult(Integer)} 是否需要变更
|
||||
*/
|
||||
private final Integer result;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
/**
|
||||
* 判断该结果是否已经处于 End 最终结果
|
||||
*
|
||||
* 主要用于一些结果更新的逻辑,如果已经是最终结果,就不再进行更新
|
||||
*
|
||||
* @param result 结果
|
||||
* @return 是否
|
||||
*/
|
||||
public static boolean isEndResult(Integer result) {
|
||||
return ObjectUtils.equalsAny(result, APPROVE.getResult(), REJECT.getResult(), CANCEL.getResult(), BACK.getResult());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package cn.iocoder.yudao.module.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;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user