diff --git a/bpmn/模型.zip b/bpmn/模型.zip
new file mode 100644
index 00000000..f232cda1
Binary files /dev/null and b/bpmn/模型.zip differ
diff --git a/config/nacos/datasource.yml b/config/nacos/datasource.yml
index ee003009..f3d8fdea 100644
--- a/config/nacos/datasource.yml
+++ b/config/nacos/datasource.yml
@@ -13,6 +13,10 @@ datasource:
url: jdbc:mysql://localhost:3306/ry-job?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
username: root
password: password
+ workflow:
+ url: jdbc:mysql://localhost:3306/ry-workflow?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
+ username: root
+ password: password
# system-oracle:
# url: jdbc:oracle:thin:@//localhost:1521/XE
# username: ROOT
diff --git a/config/nacos/ruoyi-gateway.yml b/config/nacos/ruoyi-gateway.yml
index f818254f..4c449977 100644
--- a/config/nacos/ruoyi-gateway.yml
+++ b/config/nacos/ruoyi-gateway.yml
@@ -5,6 +5,7 @@ security:
enabled: true
excludeUrls:
- /system/notice
+ - /workflow/model/editModelXml
# 不校验白名单
ignore:
whites:
@@ -59,6 +60,11 @@ spring:
- Path=/resource/**
filters:
- StripPrefix=1
+ # workflow服务
+ - id: ruoyi-workflow
+ uri: lb://ruoyi-workflow
+ predicates:
+ - Path=/workflow/**
# 演示服务
- id: ruoyi-demo
uri: lb://ruoyi-demo
diff --git a/config/nacos/ruoyi-workflow.yml b/config/nacos/ruoyi-workflow.yml
new file mode 100644
index 00000000..d87a2119
--- /dev/null
+++ b/config/nacos/ruoyi-workflow.yml
@@ -0,0 +1,44 @@
+spring:
+ datasource:
+ dynamic:
+ # 设置默认的数据源或者数据源组,默认值即为 master
+ primary: master
+ seata: false
+ datasource:
+ # 主库数据源
+ master:
+ type: ${spring.datasource.type}
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: ${datasource.workflow.url}
+ username: ${datasource.workflow.username}
+ password: ${datasource.workflow.password}
+# oracle:
+# type: ${spring.datasource.type}
+# driverClassName: oracle.jdbc.OracleDriver
+# url: ${datasource.system-oracle.url}
+# username: ${datasource.system-oracle.username}
+# password: ${datasource.system-oracle.password}
+# postgres:
+# type: ${spring.datasource.type}
+# driverClassName: org.postgresql.Driver
+# url: ${datasource.system-postgres.url}
+# username: ${datasource.system-postgres.username}
+# password: ${datasource.system-postgres.password}
+
+--- #flowable配置
+flowable:
+ async-executor-activate: false #关闭定时任务JOB
+ # 将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。
+ database-schema-update: false
+ activity-font-name: 宋体
+ label-font-name: 宋体
+ annotation-font-name: 宋体
+ # 关闭各个模块生成表,目前只使用工作流基础表
+ idm:
+ enabled: false
+ cmmn:
+ enabled: false
+ dmn:
+ enabled: false
+ app:
+ enabled: false
diff --git a/pom.xml b/pom.xml
index 61c186ab..a1285710 100644
--- a/pom.xml
+++ b/pom.xml
@@ -62,6 +62,11 @@
3.11.0
3.1.2
1.3.0
+
+
+ 7.0.0
+ 6.8.0
+ 1.10
@@ -161,6 +166,27 @@
import
+
+ org.flowable
+ flowable-bom
+ ${flowable.version}
+ pom
+ import
+
+
+
+ org.flowable
+ flowable-json-converter
+ ${flowable-json-convertor.version}
+
+
+
+
+ org.apache.xmlgraphics
+ batik-all
+ ${xmlgraphics.version}
+
+
cn.dev33
sa-token-core
diff --git a/ruoyi-api/pom.xml b/ruoyi-api/pom.xml
index 2701751b..8b5f0b9e 100644
--- a/ruoyi-api/pom.xml
+++ b/ruoyi-api/pom.xml
@@ -12,6 +12,7 @@
ruoyi-api-bom
ruoyi-api-system
ruoyi-api-resource
+ ruoyi-api-workflow
ruoyi-api
diff --git a/ruoyi-api/ruoyi-api-bom/pom.xml b/ruoyi-api/ruoyi-api-bom/pom.xml
index b0e99d37..2229c4a2 100644
--- a/ruoyi-api/ruoyi-api-bom/pom.xml
+++ b/ruoyi-api/ruoyi-api-bom/pom.xml
@@ -34,6 +34,13 @@
${revision}
+
+
+ org.dromara
+ ruoyi-api-workflow
+ ${revision}
+
+
diff --git a/ruoyi-api/ruoyi-api-resource/src/main/java/org/dromara/resource/api/RemoteFileService.java b/ruoyi-api/ruoyi-api-resource/src/main/java/org/dromara/resource/api/RemoteFileService.java
index 6ab788e4..2204de62 100644
--- a/ruoyi-api/ruoyi-api-resource/src/main/java/org/dromara/resource/api/RemoteFileService.java
+++ b/ruoyi-api/ruoyi-api-resource/src/main/java/org/dromara/resource/api/RemoteFileService.java
@@ -3,6 +3,8 @@ package org.dromara.resource.api;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.resource.api.domain.RemoteFile;
+import java.util.List;
+
/**
* 文件服务
*
@@ -26,4 +28,11 @@ public interface RemoteFileService {
*/
String selectUrlByIds(String ossIds);
+ /**
+ * 通过ossId查询列表
+ *
+ * @param ossIds ossId串逗号分隔
+ * @return 列表
+ */
+ List selectByIds(String ossIds);
}
diff --git a/ruoyi-api/ruoyi-api-resource/src/main/java/org/dromara/resource/api/RemoteFileServiceMock.java b/ruoyi-api/ruoyi-api-resource/src/main/java/org/dromara/resource/api/RemoteFileServiceMock.java
index c689f2d1..2b79e22f 100644
--- a/ruoyi-api/ruoyi-api-resource/src/main/java/org/dromara/resource/api/RemoteFileServiceMock.java
+++ b/ruoyi-api/ruoyi-api-resource/src/main/java/org/dromara/resource/api/RemoteFileServiceMock.java
@@ -4,6 +4,8 @@ import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.resource.api.domain.RemoteFile;
+import java.util.List;
+
/**
* 文件服务(降级处理)
*
@@ -34,4 +36,10 @@ public class RemoteFileServiceMock implements RemoteFileService {
return StringUtils.EMPTY;
}
+ @Override
+ public List selectByIds(String ossIds) {
+ log.warn("服务调用异常 -> 降级处理");
+ return List.of();
+ }
+
}
diff --git a/ruoyi-api/ruoyi-api-resource/src/main/java/org/dromara/resource/api/domain/RemoteFile.java b/ruoyi-api/ruoyi-api-resource/src/main/java/org/dromara/resource/api/domain/RemoteFile.java
index ecc4b16a..7140fe63 100644
--- a/ruoyi-api/ruoyi-api-resource/src/main/java/org/dromara/resource/api/domain/RemoteFile.java
+++ b/ruoyi-api/ruoyi-api-resource/src/main/java/org/dromara/resource/api/domain/RemoteFile.java
@@ -31,4 +31,14 @@ public class RemoteFile implements Serializable {
*/
private String url;
+ /**
+ * 原名
+ */
+ private String originalName;
+
+ /**
+ * 文件后缀名
+ */
+ private String fileSuffix;
+
}
diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemoteUserService.java b/ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemoteUserService.java
index 8c1de9d1..a03241ea 100644
--- a/ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemoteUserService.java
+++ b/ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemoteUserService.java
@@ -3,9 +3,12 @@ package org.dromara.system.api;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.exception.user.UserException;
import org.dromara.system.api.domain.bo.RemoteUserBo;
+import org.dromara.system.api.domain.dto.UserDTO;
import org.dromara.system.api.model.LoginUser;
import org.dromara.system.api.model.XcxLoginUser;
+import java.util.List;
+
/**
* 用户服务
*
@@ -105,4 +108,19 @@ public interface RemoteUserService {
*/
void recordLoginInfo(Long userId, String ip);
+ /**
+ * 通过用户ID查询用户列表
+ *
+ * @param userIds 用户ids
+ * @return 用户列表
+ */
+ List selectListByIds(List userIds);
+
+ /**
+ * 通过角色ID查询用户ID
+ *
+ * @param roleIds 角色ids
+ * @return 用户ids
+ */
+ List selectUserIdsByRoleIds(List roleIds);
}
diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/domain/dto/UserDTO.java b/ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/domain/dto/UserDTO.java
new file mode 100644
index 00000000..6badbb61
--- /dev/null
+++ b/ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/domain/dto/UserDTO.java
@@ -0,0 +1,73 @@
+package org.dromara.system.api.domain.dto;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 用户
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@NoArgsConstructor
+public class UserDTO implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 用户ID
+ */
+ private Long userId;
+
+ /**
+ * 部门ID
+ */
+ private Long deptId;
+
+ /**
+ * 用户账号
+ */
+ private String userName;
+
+ /**
+ * 用户昵称
+ */
+ private String nickName;
+
+ /**
+ * 用户类型(sys_user系统用户)
+ */
+ private String userType;
+
+ /**
+ * 用户邮箱
+ */
+ private String email;
+
+ /**
+ * 手机号码
+ */
+ private String phonenumber;
+
+ /**
+ * 用户性别(0男 1女 2未知)
+ */
+ private String sex;
+
+ /**
+ * 帐号状态(0正常 1停用)
+ */
+ private String status;
+
+ /**
+ * 创建时间
+ */
+ private Date createTime;
+
+}
diff --git a/ruoyi-api/ruoyi-api-workflow/pom.xml b/ruoyi-api/ruoyi-api-workflow/pom.xml
new file mode 100644
index 00000000..13992051
--- /dev/null
+++ b/ruoyi-api/ruoyi-api-workflow/pom.xml
@@ -0,0 +1,33 @@
+
+
+
+ org.dromara
+ ruoyi-api
+ ${revision}
+
+ 4.0.0
+
+ ruoyi-api-workflow
+
+
+ ruoyi-api-resource 资源服务接口模块
+
+
+
+
+
+
+ org.dromara
+ ruoyi-common-core
+
+
+
+ org.dromara
+ ruoyi-common-translation
+
+
+
+
+
diff --git a/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/RemoteWorkflowService.java b/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/RemoteWorkflowService.java
new file mode 100644
index 00000000..1a61d511
--- /dev/null
+++ b/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/RemoteWorkflowService.java
@@ -0,0 +1,86 @@
+package org.dromara.workflow.api.domain;
+
+import org.dromara.workflow.api.domain.dto.BusinessInstanceDTO;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 通用 工作流服务
+ *
+ * @Author ZETA
+ * @Date 2024/6/3
+ */
+public interface RemoteWorkflowService {
+
+ /**
+ * 运行中的实例 删除程实例,删除历史记录,删除业务与流程关联信息
+ *
+ * @param businessKeys 业务id
+ * @return 结果
+ */
+ boolean deleteRunAndHisInstance(List businessKeys);
+
+ /**
+ * 获取当前流程状态
+ *
+ * @param taskId 任务id
+ */
+ String getBusinessStatusByTaskId(String taskId);
+
+ /**
+ * 获取当前流程状态
+ *
+ * @param businessKey 业务id
+ */
+ String getBusinessStatus(String businessKey);
+
+ /**
+ * 获取流程实例对象
+ *
+ * @param businessKey 业务id
+ */
+ BusinessInstanceDTO getBusinessInstance(String businessKey);
+
+ /**
+ * 获取流程实例对象
+ *
+ * @param businessKeys 业务id集合
+ */
+ List getBusinessInstance(List businessKeys);
+
+ /**
+ * 设置流程变量(全局变量)
+ *
+ * @param taskId 任务id
+ * @param variableName 变量名称
+ * @param value 变量值
+ */
+ void setVariable(String taskId, String variableName, Object value);
+
+ /**
+ * 设置流程变量(全局变量)
+ *
+ * @param taskId 任务id
+ * @param variables 流程变量
+ */
+ void setVariables(String taskId, Map variables);
+
+ /**
+ * 设置流程变量(本地变量,非全局变量)
+ *
+ * @param taskId 任务id
+ * @param variableName 变量名称
+ * @param value 变量值
+ */
+ void setVariableLocal(String taskId, String variableName, Object value);
+
+ /**
+ * 设置流程变量(本地变量,非全局变量)
+ *
+ * @param taskId 任务id
+ * @param variables 流程变量
+ */
+ void setVariablesLocal(String taskId, Map variables);
+
+}
diff --git a/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/bo/ProcessInstanceBo.java b/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/bo/ProcessInstanceBo.java
new file mode 100644
index 00000000..76d4cb01
--- /dev/null
+++ b/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/bo/ProcessInstanceBo.java
@@ -0,0 +1,43 @@
+package org.dromara.workflow.api.domain.bo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 流程实例请求对象
+ *
+ * @author may
+ */
+@Data
+public class ProcessInstanceBo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 流程名称
+ */
+ private String name;
+
+ /**
+ * 流程key
+ */
+ private String key;
+
+ /**
+ * 任务发起人
+ */
+ private String startUserId;
+
+ /**
+ * 业务id
+ */
+ private String businessKey;
+
+ /**
+ * 模型分类
+ */
+ private String categoryCode;
+}
diff --git a/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/bo/ProcessInvalidBo.java b/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/bo/ProcessInvalidBo.java
new file mode 100644
index 00000000..baf779b5
--- /dev/null
+++ b/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/bo/ProcessInvalidBo.java
@@ -0,0 +1,31 @@
+package org.dromara.workflow.api.domain.bo;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import org.dromara.common.core.validate.AddGroup;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 流程实例作废请求对象
+ *
+ * @author may
+ */
+@Data
+public class ProcessInvalidBo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 业务id
+ */
+ @NotBlank(message = "业务id不能为空", groups = {AddGroup.class})
+ private String businessKey;
+
+ /**
+ * 作废原因
+ */
+ private String deleteReason;
+}
diff --git a/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/bo/TaskUrgingBo.java b/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/bo/TaskUrgingBo.java
new file mode 100644
index 00000000..000d3b8b
--- /dev/null
+++ b/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/bo/TaskUrgingBo.java
@@ -0,0 +1,34 @@
+package org.dromara.workflow.api.domain.bo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 任务催办
+ *
+ * @author may
+ */
+@Data
+public class TaskUrgingBo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 流程实例id
+ */
+ private String processInstanceId;
+
+ /**
+ * 消息类型
+ */
+ private List messageType;
+
+ /**
+ * 催办内容(为空默认系统内置信息)
+ */
+ private String message;
+}
diff --git a/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/dto/BusinessInstanceDTO.java b/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/dto/BusinessInstanceDTO.java
new file mode 100644
index 00000000..30c3e5de
--- /dev/null
+++ b/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/dto/BusinessInstanceDTO.java
@@ -0,0 +1,72 @@
+package org.dromara.workflow.api.domain.dto;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 业务与流程实例关联对象
+ *
+ * @Author ZETA
+ * @Date 2024/6/3
+ */
+@Data
+@NoArgsConstructor
+public class BusinessInstanceDTO implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 流程实例id
+ */
+ private String id;
+
+ /**
+ * 流程定义id
+ */
+ private String processDefinitionId;
+
+ /**
+ * 流程定义名称
+ */
+ private String name;
+
+ /**
+ * 业务id
+ */
+ private String businessKey;
+
+ /**
+ * 租户id
+ */
+ private String tenantId;
+
+ /**
+ * 启动时间
+ */
+ private Date startTime;
+
+ /**
+ * 结束时间
+ */
+ private Date endTime;
+
+ /**
+ * 启动人id
+ */
+ private String startUserId;
+
+ /**
+ * 流程状态
+ */
+ private String businessStatus;
+
+ /**
+ * 流程状态
+ */
+ private String businessStatusName;
+}
diff --git a/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/event/ProcessEvent.java b/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/event/ProcessEvent.java
new file mode 100644
index 00000000..e758ffe0
--- /dev/null
+++ b/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/event/ProcessEvent.java
@@ -0,0 +1,47 @@
+package org.dromara.workflow.api.domain.event;
+
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 总体流程监听
+ *
+ * @author may
+ */
+
+@Data
+public class ProcessEvent implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 流程定义key
+ */
+ private String key;
+
+ /**
+ * 业务id
+ */
+ private String businessKey;
+
+ /**
+ * 状态
+ */
+ private String status;
+
+ /**
+ * 当为true时为申请人节点办理
+ */
+ private boolean submit;
+
+ /**
+ * 请求体
+ */
+ private HttpServletRequest request;
+
+
+}
diff --git a/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/event/ProcessTaskEvent.java b/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/event/ProcessTaskEvent.java
new file mode 100644
index 00000000..e64b994b
--- /dev/null
+++ b/ruoyi-api/ruoyi-api-workflow/src/main/java/org/dromara/workflow/api/domain/event/ProcessTaskEvent.java
@@ -0,0 +1,41 @@
+package org.dromara.workflow.api.domain.event;
+
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 流程办理监听
+ *
+ * @author may
+ */
+
+@Data
+public class ProcessTaskEvent implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 流程定义key与流程节点标识(拼接方式:流程定义key_流程节点)
+ */
+ private String keyNode;
+
+ /**
+ * 任务id
+ */
+ private String taskId;
+
+ /**
+ * 业务id
+ */
+ private String businessKey;
+
+ /**
+ * 请求体
+ */
+ private HttpServletRequest request;
+
+}
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java
index 8ef4a578..b7e18bb3 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java
@@ -4,10 +4,11 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.Data;
+import lombok.NoArgsConstructor;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.sql.SqlUtil;
-import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
@@ -21,6 +22,7 @@ import java.util.List;
*/
@Data
+@NoArgsConstructor
public class PageQuery implements Serializable {
@Serial
@@ -56,6 +58,13 @@ public class PageQuery implements Serializable {
*/
public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE;
+ public static final PageQuery DEFAULT_PAGE = new PageQuery(DEFAULT_PAGE_NUM, DEFAULT_PAGE_SIZE);
+
+ private PageQuery(Integer pageNum, Integer pageSize) {
+ this.pageSize = pageSize;
+ this.pageNum = pageNum;
+ }
+
public Page build() {
Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM);
Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE);
@@ -111,4 +120,8 @@ public class PageQuery implements Serializable {
return list;
}
+ public Integer getFirstNum() {
+ return (pageNum - 1) * pageSize;
+ }
+
}
diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/NicknameTranslationImpl.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/NicknameTranslationImpl.java
index b73478ec..9b60a233 100644
--- a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/NicknameTranslationImpl.java
+++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/NicknameTranslationImpl.java
@@ -21,6 +21,6 @@ public class NicknameTranslationImpl implements TranslationInterface {
@Override
public String translation(Object key, String other) {
- return remoteUserService.selectNicknameById((Long) key);
+ return remoteUserService.selectNicknameById(Long.valueOf(String.valueOf(key)));
}
}
diff --git a/ruoyi-example/ruoyi-demo/pom.xml b/ruoyi-example/ruoyi-demo/pom.xml
index 390cb57d..1b359c06 100644
--- a/ruoyi-example/ruoyi-demo/pom.xml
+++ b/ruoyi-example/ruoyi-demo/pom.xml
@@ -108,6 +108,7 @@
spring-boot-starter-test
test
+
diff --git a/ruoyi-modules/pom.xml b/ruoyi-modules/pom.xml
index 0980f601..c9063627 100644
--- a/ruoyi-modules/pom.xml
+++ b/ruoyi-modules/pom.xml
@@ -13,6 +13,7 @@
ruoyi-gen
ruoyi-job
ruoyi-resource
+ ruoyi-workflow
ruoyi-modules
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteFileServiceImpl.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteFileServiceImpl.java
index a785b0ef..e9fed20a 100644
--- a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteFileServiceImpl.java
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteFileServiceImpl.java
@@ -1,20 +1,27 @@
package org.dromara.resource.dubbo;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.bean.copier.CopyOptions;
+import cn.hutool.core.convert.Convert;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.oss.core.OssClient;
import org.dromara.common.oss.entity.UploadResult;
import org.dromara.common.oss.factory.OssFactory;
import org.dromara.resource.api.RemoteFileService;
-import org.dromara.resource.api.domain.RemoteFile;
import org.dromara.resource.domain.bo.SysOssBo;
+import org.dromara.resource.domain.vo.SysOssVo;
import org.dromara.resource.service.ISysOssService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.resource.api.domain.RemoteFile;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import java.util.List;
+import java.util.Map;
+
/**
* 文件请求处理
*
@@ -68,4 +75,15 @@ public class RemoteFileServiceImpl implements RemoteFileService {
return sysOssService.selectUrlByIds(ossIds);
}
+ /**
+ * 通过ossId查询列表
+ *
+ * @param ossIds ossId串逗号分隔
+ * @return 列表
+ */
+ public List selectByIds(String ossIds){
+ List sysOssVos = sysOssService.listByIds(StringUtils.splitTo(ossIds, Convert::toLong));
+ return BeanUtil.copyToList(sysOssVos, RemoteFile.class,
+ CopyOptions.create().setFieldMapping(Map.of("fileName", "name")));
+ }
}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteUserServiceImpl.java
index 754baeaa..60d70f32 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteUserServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteUserServiceImpl.java
@@ -14,6 +14,7 @@ import org.dromara.common.mybatis.helper.DataPermissionHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.api.RemoteUserService;
import org.dromara.system.api.domain.bo.RemoteUserBo;
+import org.dromara.system.api.domain.dto.UserDTO;
import org.dromara.system.api.model.LoginUser;
import org.dromara.system.api.model.RoleDTO;
import org.dromara.system.api.model.XcxLoginUser;
@@ -234,4 +235,15 @@ public class RemoteUserServiceImpl implements RemoteUserService {
DataPermissionHelper.ignore(() -> userMapper.updateById(sysUser));
}
+ @Override
+ public List selectListByIds(List userIds) {
+ List sysUserVos = userService.selectUserByIds(userIds, null);
+ return BeanUtil.copyToList(sysUserVos, UserDTO.class);
+ }
+
+ @Override
+ public List selectUserIdsByRoleIds(List roleIds) {
+ return userService.selectUserIdsByRoleIds(roleIds);
+ }
+
}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java
index ab37e3c5..5be2997c 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java
@@ -252,4 +252,11 @@ public interface ISysUserService {
*/
List selectUserListByDept(Long deptId);
+ /**
+ * 通过角色ID查询用户ID
+ *
+ * @param roleIds 角色ids
+ * @return 用户ids
+ */
+ List selectUserIdsByRoleIds(List roleIds);
}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
index 93325b11..7632cde7 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
@@ -553,6 +553,13 @@ public class SysUserServiceImpl implements ISysUserService {
return baseMapper.selectVoList(lqw);
}
+ @Override
+ public List selectUserIdsByRoleIds(List roleIds) {
+ List userRoles = userRoleMapper.selectList(
+ new LambdaQueryWrapper().in(SysUserRole::getRoleId, roleIds));
+ return StreamUtils.toList(userRoles, SysUserRole::getUserId);
+ }
+
/**
* 通过用户ID查询用户账户
*
diff --git a/ruoyi-modules/ruoyi-workflow/pom.xml b/ruoyi-modules/ruoyi-workflow/pom.xml
new file mode 100644
index 00000000..479b783d
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/pom.xml
@@ -0,0 +1,138 @@
+
+
+
+ org.dromara
+ ruoyi-modules
+ ${revision}
+
+ 4.0.0
+
+ ruoyi-workflow
+
+
+ 工作流模块
+
+
+
+
+
+ org.dromara
+ ruoyi-common-nacos
+
+
+
+
+ org.flowable
+ flowable-spring-boot-autoconfigure
+
+
+ org.flowable
+ flowable-spring-security
+
+
+
+
+
+ org.flowable
+ flowable-spring-configurator
+
+
+
+ org.flowable
+ flowable-spring-boot-starter-actuator
+
+
+
+
+ org.flowable
+ flowable-image-generator
+
+
+
+
+ org.flowable
+ flowable-json-converter
+ 6.8.0
+
+
+
+
+ org.apache.xmlgraphics
+ batik-all
+
+
+ xalan
+ xalan
+
+
+
+
+
+ org.dromara
+ ruoyi-common-websocket
+
+
+
+ org.dromara
+ ruoyi-common-mail
+
+
+
+ org.dromara
+ ruoyi-common-sms
+
+
+
+ org.dromara
+ ruoyi-common-mybatis
+
+
+ org.dromara
+ ruoyi-common-web
+
+
+ org.dromara
+ ruoyi-common-log
+
+
+ org.dromara
+ ruoyi-common-idempotent
+
+
+ org.dromara
+ ruoyi-common-excel
+
+
+ org.dromara
+ ruoyi-common-translation
+
+
+ org.dromara
+ ruoyi-common-tenant
+
+
+
+ org.dromara
+ ruoyi-common-dubbo
+
+
+
+ org.dromara
+ ruoyi-common-tenant
+
+
+
+ org.dromara
+ ruoyi-common-security
+
+
+
+ org.dromara
+ ruoyi-api-workflow
+
+
+
+
+
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/RuoYiWorkflowApplication.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/RuoYiWorkflowApplication.java
new file mode 100644
index 00000000..2ae9d2c7
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/RuoYiWorkflowApplication.java
@@ -0,0 +1,22 @@
+package org.dromara.workflow;
+
+import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
+
+/**
+ * 系统模块
+ *
+ * @author ruoyi
+ */
+@EnableDubbo
+@SpringBootApplication
+public class RuoYiWorkflowApplication {
+ public static void main(String[] args) {
+ SpringApplication application = new SpringApplication(RuoYiWorkflowApplication.class);
+ application.setApplicationStartup(new BufferingApplicationStartup(2048));
+ application.run(args);
+ System.out.println("(♥◠‿◠)ノ゙ 工作流模块启动成功 ლ(´ڡ`ლ)゙ ");
+ }
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java
new file mode 100644
index 00000000..c3fcafa8
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java
@@ -0,0 +1,137 @@
+package org.dromara.workflow.common.constant;
+
+
+/**
+ * 工作流常量
+ *
+ * @author may
+ */
+public interface FlowConstant {
+
+ String MESSAGE_CURRENT_TASK_IS_NULL = "当前任务不存在或你不是任务办理人!";
+
+ String MESSAGE_SUSPENDED = "当前任务已挂起不可审批!";
+
+ /**
+ * 连线
+ */
+ String SEQUENCE_FLOW = "sequenceFlow";
+
+ /**
+ * 并行网关
+ */
+ String PARALLEL_GATEWAY = "parallelGateway";
+
+ /**
+ * 排它网关
+ */
+ String EXCLUSIVE_GATEWAY = "exclusiveGateway";
+
+ /**
+ * 包含网关
+ */
+ String INCLUSIVE_GATEWAY = "inclusiveGateway";
+
+ /**
+ * 结束节点
+ */
+ String END_EVENT = "endEvent";
+
+
+ /**
+ * 流程委派标识
+ */
+ String PENDING = "PENDING";
+
+ /**
+ * 候选人标识
+ */
+ String CANDIDATE = "candidate";
+
+ /**
+ * 会签任务总数
+ */
+ String NUMBER_OF_INSTANCES = "nrOfInstances";
+
+ /**
+ * 正在执行的会签总数
+ */
+ String NUMBER_OF_ACTIVE_INSTANCES = "nrOfActiveInstances";
+
+ /**
+ * 已完成的会签任务总数
+ */
+ String NUMBER_OF_COMPLETED_INSTANCES = "nrOfCompletedInstances";
+
+ /**
+ * 循环的索引值,可以使用elementIndexVariable属性修改loopCounter的变量名
+ */
+ String LOOP_COUNTER = "loopCounter";
+
+ String ZIP = "ZIP";
+
+ /**
+ * 业务与流程实例关联对象
+ */
+ String BUSINESS_INSTANCE_DTO = "businessInstanceDTO";
+
+ /**
+ * 流程定义配置
+ */
+ String WF_DEFINITION_CONFIG_VO = "wfDefinitionConfigVo";
+
+ /**
+ * 节点配置
+ */
+ String WF_NODE_CONFIG_VO = "wfNodeConfigVo";
+
+ /**
+ * 流程发起人
+ */
+ String INITIATOR = "initiator";
+
+ /**
+ * 流程实例id
+ */
+ String PROCESS_INSTANCE_ID = "processInstanceId";
+
+ /**
+ * 业务id
+ */
+ String BUSINESS_KEY = "businessKey";
+
+ /**
+ * 流程定义id
+ */
+ String PROCESS_DEFINITION_ID = "processDefinitionId";
+
+ /**
+ * 开启跳过表达式变量
+ */
+ String FLOWABLE_SKIP_EXPRESSION_ENABLED = "_FLOWABLE_SKIP_EXPRESSION_ENABLED";
+
+ /**
+ * 模型标识key命名规范正则表达式
+ */
+ String MODEL_KEY_PATTERN = "^[a-zA-Z][a-zA-Z0-9_]{0,254}$";
+
+ /**
+ * 用户任务
+ */
+ String USER_TASK = "userTask";
+
+ /**
+ * 会签
+ */
+ String MULTI_INSTANCE = "multiInstance";
+
+ /**
+ * 是
+ */
+ String TRUE = "0";
+
+ /**
+ * 否
+ */
+ String FALSE = "1";
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/BusinessStatusEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/BusinessStatusEnum.java
new file mode 100644
index 00000000..6eb6ffe6
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/BusinessStatusEnum.java
@@ -0,0 +1,152 @@
+package org.dromara.workflow.common.enums;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.StringUtils;
+
+import java.util.Arrays;
+
+/**
+ * 业务状态枚举
+ *
+ * @author may
+ */
+@Getter
+@AllArgsConstructor
+public enum BusinessStatusEnum {
+ /**
+ * 已撤销
+ */
+ CANCEL("cancel", "已撤销"),
+ /**
+ * 草稿
+ */
+ DRAFT("draft", "草稿"),
+ /**
+ * 待审核
+ */
+ WAITING("waiting", "待审核"),
+ /**
+ * 已完成
+ */
+ FINISH("finish", "已完成"),
+ /**
+ * 已作废
+ */
+ INVALID("invalid", "已作废"),
+ /**
+ * 已退回
+ */
+ BACK("back", "已退回"),
+ /**
+ * 已终止
+ */
+ TERMINATION("termination", "已终止");
+
+ /**
+ * 状态
+ */
+ private final String status;
+
+ /**
+ * 描述
+ */
+ private final String desc;
+
+ /**
+ * 获取业务状态
+ *
+ * @param status 状态
+ */
+ public static String findByStatus(String status) {
+ if (StringUtils.isBlank(status)) {
+ return StrUtil.EMPTY;
+ }
+ return Arrays.stream(BusinessStatusEnum.values())
+ .filter(statusEnum -> statusEnum.getStatus().equals(status))
+ .findFirst()
+ .map(BusinessStatusEnum::getDesc)
+ .orElse(StrUtil.EMPTY);
+ }
+
+ /**
+ * 启动流程校验
+ *
+ * @param status 状态
+ */
+ public static void checkStartStatus(String status) {
+ if (WAITING.getStatus().equals(status)) {
+ throw new ServiceException("该单据已提交过申请,正在审批中!");
+ } else if (FINISH.getStatus().equals(status)) {
+ throw new ServiceException("该单据已完成申请!");
+ } else if (INVALID.getStatus().equals(status)) {
+ throw new ServiceException("该单据已作废!");
+ } else if (TERMINATION.getStatus().equals(status)) {
+ throw new ServiceException("该单据已终止!");
+ } else if (StringUtils.isBlank(status)) {
+ throw new ServiceException("流程状态为空!");
+ }
+ }
+
+ /**
+ * 撤销流程校验
+ *
+ * @param status 状态
+ */
+ public static void checkCancelStatus(String status) {
+ if (CANCEL.getStatus().equals(status)) {
+ throw new ServiceException("该单据已撤销!");
+ } else if (FINISH.getStatus().equals(status)) {
+ throw new ServiceException("该单据已完成申请!");
+ } else if (INVALID.getStatus().equals(status)) {
+ throw new ServiceException("该单据已作废!");
+ } else if (TERMINATION.getStatus().equals(status)) {
+ throw new ServiceException("该单据已终止!");
+ } else if (BACK.getStatus().equals(status)) {
+ throw new ServiceException("该单据已退回!");
+ } else if (StringUtils.isBlank(status)) {
+ throw new ServiceException("流程状态为空!");
+ }
+ }
+
+ /**
+ * 驳回流程校验
+ *
+ * @param status 状态
+ */
+ public static void checkBackStatus(String status) {
+ if (BACK.getStatus().equals(status)) {
+ throw new ServiceException("该单据已退回!");
+ } else if (FINISH.getStatus().equals(status)) {
+ throw new ServiceException("该单据已完成申请!");
+ } else if (INVALID.getStatus().equals(status)) {
+ throw new ServiceException("该单据已作废!");
+ } else if (TERMINATION.getStatus().equals(status)) {
+ throw new ServiceException("该单据已终止!");
+ } else if (CANCEL.getStatus().equals(status)) {
+ throw new ServiceException("该单据已撤销!");
+ } else if (StringUtils.isBlank(status)) {
+ throw new ServiceException("流程状态为空!");
+ }
+ }
+
+ /**
+ * 作废,终止流程校验
+ *
+ * @param status 状态
+ */
+ public static void checkInvalidStatus(String status) {
+ if (FINISH.getStatus().equals(status)) {
+ throw new ServiceException("该单据已完成申请!");
+ } else if (INVALID.getStatus().equals(status)) {
+ throw new ServiceException("该单据已作废!");
+ } else if (TERMINATION.getStatus().equals(status)) {
+ throw new ServiceException("该单据已终止!");
+ } else if (StringUtils.isBlank(status)) {
+ throw new ServiceException("流程状态为空!");
+ }
+ }
+}
+
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/FormTypeEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/FormTypeEnum.java
new file mode 100644
index 00000000..083ab7b8
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/FormTypeEnum.java
@@ -0,0 +1,54 @@
+package org.dromara.workflow.common.enums;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Arrays;
+
+/**
+ * 任务状态枚举
+ *
+ * @author may
+ */
+@Getter
+@AllArgsConstructor
+public enum FormTypeEnum {
+ /**
+ * 自定义表单
+ */
+ STATIC("static", "自定义表单"),
+ /**
+ * 动态表单
+ */
+ DYNAMIC("dynamic", "动态表单");
+
+ /**
+ * 类型
+ */
+ private final String type;
+
+ /**
+ * 描述
+ */
+ private final String desc;
+
+ /**
+ * 表单类型
+ *
+ * @param formType 表单类型
+ */
+ public static String findByType(String formType) {
+ if (StringUtils.isBlank(formType)) {
+ return StrUtil.EMPTY;
+ }
+
+ return Arrays.stream(FormTypeEnum.values())
+ .filter(statusEnum -> statusEnum.getType().equals(formType))
+ .findFirst()
+ .map(FormTypeEnum::getDesc)
+ .orElse(StrUtil.EMPTY);
+ }
+}
+
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java
new file mode 100644
index 00000000..a2829582
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java
@@ -0,0 +1,51 @@
+package org.dromara.workflow.common.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 消息类型枚举
+ *
+ * @author may
+ */
+@Getter
+@AllArgsConstructor
+public enum MessageTypeEnum {
+ /**
+ * 站内信
+ */
+ SYSTEM_MESSAGE("1", "站内信"),
+ /**
+ * 邮箱
+ */
+ EMAIL_MESSAGE("2", "邮箱"),
+ /**
+ * 短信
+ */
+ SMS_MESSAGE("3", "短信");
+
+ private final String code;
+
+ private final String desc;
+
+ private final static Map MESSAGE_TYPE_ENUM_MAP = new ConcurrentHashMap<>(MessageTypeEnum.values().length);
+
+ static {
+ for (MessageTypeEnum messageType : MessageTypeEnum.values()) {
+ MESSAGE_TYPE_ENUM_MAP.put(messageType.code, messageType);
+ }
+ }
+
+ /**
+ * 根据消息类型 code 获取 MessageTypeEnum
+ * @param code 消息类型code
+ * @return MessageTypeEnum
+ */
+ public static MessageTypeEnum getByCode(String code) {
+ return MESSAGE_TYPE_ENUM_MAP.get(code);
+ }
+}
+
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java
new file mode 100644
index 00000000..7b2f55c2
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java
@@ -0,0 +1,94 @@
+package org.dromara.workflow.common.enums;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Arrays;
+
+/**
+ * 任务状态枚举
+ *
+ * @author may
+ */
+@Getter
+@AllArgsConstructor
+public enum TaskStatusEnum {
+ /**
+ * 撤销
+ */
+ CANCEL("cancel", "撤销"),
+ /**
+ * 通过
+ */
+ PASS("pass", "通过"),
+ /**
+ * 待审核
+ */
+ WAITING("waiting", "待审核"),
+ /**
+ * 作废
+ */
+ INVALID("invalid", "作废"),
+ /**
+ * 退回
+ */
+ BACK("back", "退回"),
+ /**
+ * 终止
+ */
+ TERMINATION("termination", "终止"),
+ /**
+ * 转办
+ */
+ TRANSFER("transfer", "转办"),
+ /**
+ * 委托
+ */
+ PENDING("pending", "委托"),
+ /**
+ * 抄送
+ */
+ COPY("copy", "抄送"),
+ /**
+ * 加签
+ */
+ SIGN("sign", "加签"),
+ /**
+ * 减签
+ */
+ SIGN_OFF("sign_off", "减签"),
+ /**
+ * 超时
+ */
+ TIMEOUT("timeout", "超时");
+
+ /**
+ * 状态
+ */
+ private final String status;
+
+ /**
+ * 描述
+ */
+ private final String desc;
+
+ /**
+ * 任务业务状态
+ *
+ * @param status 状态
+ */
+ public static String findByStatus(String status) {
+ if (StringUtils.isBlank(status)) {
+ return StrUtil.EMPTY;
+ }
+
+ return Arrays.stream(TaskStatusEnum.values())
+ .filter(statusEnum -> statusEnum.getStatus().equals(status))
+ .findFirst()
+ .map(TaskStatusEnum::getDesc)
+ .orElse(StrUtil.EMPTY);
+ }
+}
+
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java
new file mode 100644
index 00000000..b96f3432
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java
@@ -0,0 +1,154 @@
+package org.dromara.workflow.controller;
+
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.resource.api.RemoteFileService;
+import org.dromara.resource.api.domain.RemoteFile;
+import org.dromara.system.api.model.LoginUser;
+import org.dromara.workflow.domain.bo.ModelBo;
+import org.dromara.workflow.domain.vo.ModelVo;
+import org.dromara.workflow.service.IActModelService;
+import org.flowable.engine.RepositoryService;
+import org.flowable.engine.repository.Model;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 模型管理 控制层
+ *
+ * @author may
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/workflow/model")
+public class ActModelController extends BaseController {
+
+ private final RepositoryService repositoryService;
+
+ private final IActModelService actModelService;
+
+
+ /**
+ * 分页查询模型
+ *
+ * @param modelBo 模型参数
+ */
+ @GetMapping("/list")
+ public TableDataInfo page(ModelBo modelBo, PageQuery pageQuery) {
+ RemoteFileService bean = SpringUtils.getBean(RemoteFileService.class);
+ List remoteFiles = bean.selectByIds("1");
+ return actModelService.page(modelBo, pageQuery);
+ }
+
+ /**
+ * 新增模型
+ *
+ * @param modelBo 模型请求对象
+ */
+ @Log(title = "模型管理", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping("/save")
+ public R saveNewModel(@Validated(AddGroup.class) @RequestBody ModelBo modelBo) {
+ return toAjax(actModelService.saveNewModel(modelBo));
+ }
+
+ /**
+ * 查询模型
+ *
+ * @param id 模型id
+ */
+ @GetMapping("/getInfo/{id}")
+ public R getInfo(@NotBlank(message = "模型id不能为空") @PathVariable String id) {
+ return R.ok(actModelService.getInfo(id));
+ }
+
+ /**
+ * 修改模型信息
+ *
+ * @param modelBo 模型数据
+ */
+ @Log(title = "模型管理", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping(value = "/update")
+ public R update(@RequestBody ModelBo modelBo) {
+ return toAjax(actModelService.update(modelBo));
+ }
+
+ /**
+ * 编辑XMl模型
+ *
+ * @param modelBo 模型数据
+ */
+ @Log(title = "模型管理", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping(value = "/editModelXml")
+ public R editModel(@Validated(EditGroup.class) @RequestBody ModelBo modelBo) {
+ return toAjax(actModelService.editModelXml(modelBo));
+ }
+
+ /**
+ * 删除流程模型
+ *
+ * @param ids 模型id
+ */
+ @Log(title = "模型管理", businessType = BusinessType.DELETE)
+ @RepeatSubmit()
+ @DeleteMapping("/{ids}")
+ @Transactional(rollbackFor = Exception.class)
+ public R delete(@NotEmpty(message = "主键不能为空") @PathVariable String[] ids) {
+ Arrays.stream(ids).parallel().forEachOrdered(repositoryService::deleteModel);
+ return R.ok();
+ }
+
+ /**
+ * 模型部署
+ *
+ * @param id 模型id
+ */
+ @Log(title = "模型管理", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping("/modelDeploy/{id}")
+ public R deploy(@NotBlank(message = "模型id不能为空") @PathVariable("id") String id) {
+ return toAjax(actModelService.modelDeploy(id));
+ }
+
+ /**
+ * 导出模型zip压缩包
+ *
+ * @param modelIds 模型id
+ * @param response 相应
+ */
+ @GetMapping("/export/zip/{modelIds}")
+ public void exportZip(@NotEmpty(message = "模型id不能为空") @PathVariable List modelIds,
+ HttpServletResponse response) {
+ actModelService.exportZip(modelIds, response);
+ }
+
+ /**
+ * 复制模型
+ *
+ * @param modelBo 模型数据
+ */
+ @PostMapping("/copyModel")
+ public R copyModel(@RequestBody ModelBo modelBo) {
+ return toAjax(actModelService.copyModel(modelBo));
+ }
+}
diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessDefinitionController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessDefinitionController.java
new file mode 100644
index 00000000..5198bd16
--- /dev/null
+++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessDefinitionController.java
@@ -0,0 +1,147 @@
+package org.dromara.workflow.controller;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.workflow.domain.bo.ProcessDefinitionBo;
+import org.dromara.workflow.domain.vo.ProcessDefinitionVo;
+import org.dromara.workflow.service.IActProcessDefinitionService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * 流程定义管理 控制层
+ *
+ * @author may
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/workflow/processDefinition")
+public class ActProcessDefinitionController extends BaseController {
+
+ private final IActProcessDefinitionService actProcessDefinitionService;
+
+ /**
+ * 分页查询
+ *
+ * @param bo 参数
+ */
+ @GetMapping("/list")
+ public TableDataInfo page(ProcessDefinitionBo bo, PageQuery pageQuery) {
+ return actProcessDefinitionService.page(bo, pageQuery);
+ }
+
+ /**
+ * 查询历史流程定义列表
+ *
+ * @param key 流程定义key
+ */
+ @GetMapping("/getListByKey/{key}")
+ public R> getListByKey(@NotEmpty(message = "流程定义key不能为空") @PathVariable String key) {
+ return R.ok("操作成功", actProcessDefinitionService.getListByKey(key));
+ }
+
+ /**
+ * 查看流程定义图片
+ *
+ * @param processDefinitionId 流程定义id
+ */
+ @GetMapping("/definitionImage/{processDefinitionId}")
+ public R definitionImage(@PathVariable String processDefinitionId) {
+ return R.ok("操作成功", actProcessDefinitionService.definitionImage(processDefinitionId));
+ }
+
+ /**
+ * 查看流程定义xml文件
+ *
+ * @param processDefinitionId 流程定义id
+ */
+ @GetMapping("/definitionXml/{processDefinitionId}")
+ public R