37 Commits

Author SHA1 Message Date
疯狂的狮子Li
58ea6c899f Merge remote-tracking branch 'origin/dev' into warm-flow-future
# Conflicts:
#	ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java
#	ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActTaskMapper.xml
2024-09-11 14:05:46 +08:00
gssong
a084520280 update 调整流程实例,待办查询 2024-08-25 17:45:23 +08:00
gssong
41c43f2a67 remove 删除无用校验 2024-08-24 11:58:26 +08:00
gssong
d26772983c add 添加待办人查询 2024-08-24 11:34:46 +08:00
gssong
6fdea13932 Merge branch 'dev' into warm-flow-future 2024-08-24 11:17:42 +08:00
gssong
c21e0db622 update 调整字段错误,流程导入 2024-08-23 23:47:50 +08:00
gssong
3adf918067 add 添加流程激活/挂起接口 升级warm-flow到1.2.4 2024-08-23 21:37:53 +08:00
gssong
0195163181 add 添加历史流程定义查询 调整流程发布 2024-08-17 11:18:53 +08:00
疯狂的狮子Li
fb30169da8 Merge remote-tracking branch 'origin/dev' into warm-flow-future 2024-08-15 20:41:44 +08:00
疯狂的狮子Li
7be5d23451 Merge remote-tracking branch 'origin/dev' into warm-flow-future 2024-08-12 13:40:11 +08:00
疯狂的狮子Li
c7f250d967 Merge remote-tracking branch 'origin/dev' into warm-flow-future
# Conflicts:
#	ruoyi-admin/src/main/resources/application.yml
#	ruoyi-modules/ruoyi-workflow/pom.xml
#	ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java
#	ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java
#	ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java
#	ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java
#	ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java
#	ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java
#	ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java
#	ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java
2024-08-07 13:24:25 +08:00
疯狂的狮子Li
8cb5a901e6 Merge remote-tracking branch 'origin/dev' into warm-flow-future
# Conflicts:
#	ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java
#	ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java
2024-08-04 23:01:04 +08:00
疯狂的狮子Li
36ea21128f update 优化 TenantSpringCacheManager 处理逻辑 2024-08-04 19:26:39 +08:00
疯狂的狮子Li
838a1ef43a fix 修复 一级缓存key未区分租户问题 2024-08-04 19:26:39 +08:00
疯狂的狮子Li
acc4499e3f update 优化 角色权限判断 2024-08-04 19:26:39 +08:00
疯狂的狮子Li
5bcdea061f update 更新 readme 2024-08-04 19:26:39 +08:00
疯狂的狮子Li
333db7ea78 update 优化 增加删除标志位常量优化查询代码 2024-08-04 19:26:36 +08:00
疯狂的狮子Li
3e426aa194 fix 修复 登出无法正确删除对应的租户数据问题 2024-08-04 19:26:33 +08:00
疯狂的狮子Li
68886a5f89 update 优化 sse 拦截网络中断io异常 2024-08-04 19:26:33 +08:00
疯狂的狮子Li
c90e84faa6 fix 修复 登录错误锁定不区分租户问题 2024-08-04 19:26:33 +08:00
疯狂的狮子Li
b0d1a7a7a6 update 优化 sse 关闭连接各种异常问题 2024-08-04 19:26:26 +08:00
疯狂的狮子Li
c66b7098bb update 优化 监控使用独立web依赖 2024-08-04 19:26:26 +08:00
疯狂的狮子Li
072d660763 fix 修复 代码生成 错误匹配表名问题 2024-08-04 19:26:26 +08:00
疯狂的狮子Li
609dcf8426 update 优化 适配 anyline 新改动 2024-08-04 19:26:26 +08:00
疯狂的狮子Li
1df0a2cf2b update anyline 8.7.2-20240728 2024-08-04 19:26:26 +08:00
疯狂的狮子Li
c92dda2af6 update 脱敏策略优化增加密码 2024-08-04 19:26:26 +08:00
疯狂的狮子Li
a2df703031 add 新增 更多脱敏策略 2024-08-04 19:26:26 +08:00
疯狂的狮子Li
6b0d0d5520 update 优化oss查询代码 2024-08-04 19:26:26 +08:00
疯狂的狮子Li
9c2c060fec update 优化 sse发送消息 增加token有效期判断 2024-08-04 19:26:26 +08:00
疯狂的狮子Li
4c59ba1b49 fix 修复 登出后重新登录 sse推送报错问题 2024-08-04 19:26:26 +08:00
疯狂的狮子Li
a7e9c3b704 fix 修复 代码生成 数据源切换问题 2024-08-04 19:26:26 +08:00
疯狂的狮子Li
d8bac74291 update anyline 8.7.2-20240726 2024-08-04 19:26:26 +08:00
疯狂的狮子Li
80bd118964 fix 修复 代码生成 表结构缓存问题 2024-08-04 19:26:26 +08:00
疯狂的狮子Li
714a123a6e update snailjob 1.1.0 => 1.1.1 2024-08-04 19:26:26 +08:00
疯狂的狮子Li
833db6c36f fix 修复 代码生成 表结构缓存问题 2024-08-04 19:26:26 +08:00
疯狂的狮子Li
f194ad5d94 update 优化 sse 自动装配 2024-08-04 19:26:26 +08:00
gssong
efb628be5f 初始化添加warm-flow 2024-08-04 13:47:48 +08:00
128 changed files with 2515 additions and 7540 deletions

View File

@@ -2,7 +2,7 @@
<configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
<deployment type="dockerfile">
<settings>
<option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.2.3" />
<option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.2.2" />
<option name="buildOnly" value="true" />
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" />
</settings>

View File

@@ -2,11 +2,11 @@
<configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="演示机">
<deployment type="dockerfile">
<settings>
<option name="imageTag" value="ruoyi/ruoyi-server:5.2.3" />
<option name="imageTag" value="ruoyi/ruoyi-server:5.2.2" />
<option name="buildOnly" value="true" />
<option name="sourceFilePath" value="ruoyi-admin/Dockerfile" />
</settings>
</deployment>
<method v="2" />
</configuration>
</component>
</component>

View File

@@ -2,7 +2,7 @@
<configuration default="false" name="ruoyi-snailjob-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
<deployment type="dockerfile">
<settings>
<option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.2.3" />
<option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.2.2" />
<option name="buildOnly" value="true" />
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-snailjob-server/Dockerfile" />
</settings>

View File

@@ -9,7 +9,7 @@
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE)
[![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
<br>
[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.2.3-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.2.2-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.2-blue.svg)]()
[![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]()
[![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]()

55
pom.xml
View File

@@ -13,44 +13,46 @@
<description>RuoYi-Vue-Plus多租户管理系统</description>
<properties>
<revision>5.2.3</revision>
<spring-boot.version>3.2.11</spring-boot.version>
<revision>5.2.2</revision>
<spring-boot.version>3.2.9</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>17</java.version>
<mybatis.version>3.5.16</mybatis.version>
<springdoc.version>2.6.0</springdoc.version>
<therapi-javadoc.version>0.15.0</therapi-javadoc.version>
<easyexcel.version>4.0.3</easyexcel.version>
<easyexcel.version>4.0.2</easyexcel.version>
<velocity.version>2.3</velocity.version>
<satoken.version>1.39.0</satoken.version>
<mybatis-plus.version>3.5.8</mybatis-plus.version>
<mybatis-plus.version>3.5.7</mybatis-plus.version>
<p6spy.version>3.9.1</p6spy.version>
<hutool.version>5.8.31</hutool.version>
<okhttp.version>4.10.0</okhttp.version>
<spring-boot-admin.version>3.2.3</spring-boot-admin.version>
<redisson.version>3.37.0</redisson.version>
<redisson.version>3.34.1</redisson.version>
<lock4j.version>2.2.7</lock4j.version>
<dynamic-ds.version>4.3.1</dynamic-ds.version>
<snailjob.version>1.1.2</snailjob.version>
<mapstruct-plus.version>1.4.5</mapstruct-plus.version>
<mapstruct-plus.version>1.4.4</mapstruct-plus.version>
<mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
<lombok.version>1.18.34</lombok.version>
<bouncycastle.version>1.76</bouncycastle.version>
<justauth.version>1.16.6</justauth.version>
<!-- 离线IP地址定位库 -->
<ip2region.version>2.7.0</ip2region.version>
<undertow.version>2.3.15.Final</undertow.version>
<!-- OSS 配置 -->
<aws.sdk.version>2.28.22</aws.sdk.version>
<aws.crt.version>0.31.3</aws.crt.version>
<aws.sdk.version>2.25.15</aws.sdk.version>
<aws.crt.version>0.29.13</aws.crt.version>
<!-- SMS 配置 -->
<sms4j.version>3.3.3</sms4j.version>
<sms4j.version>3.3.2</sms4j.version>
<!-- 限制框架中的fastjson版本 -->
<fastjson.version>1.2.83</fastjson.version>
<!-- 面向运行时的D-ORM依赖 -->
<anyline.version>8.7.2-20241022</anyline.version>
<anyline.version>8.7.2-20240808</anyline.version>
<!--工作流配置-->
<flowable.version>7.0.1</flowable.version>
<warm-flow>1.2.4</warm-flow>
<!-- 插件版本 -->
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
@@ -119,13 +121,12 @@
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-bom</artifactId>
<version>${flowable.version}</version>
<type>pom</type>
<scope>import</scope>
<groupId>io.github.minliuhua</groupId>
<artifactId>warm-flow-mybatis-plus-sb-starter</artifactId>
<version>${warm-flow}</version>
</dependency>
<!-- JustAuth 的依赖配置-->
<dependency>
<groupId>me.zhyd.oauth</groupId>
@@ -229,6 +230,12 @@
<version>${p6spy.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp.version}</version>
</dependency>
<!-- AWS SDK for Java 2.x -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
@@ -310,6 +317,22 @@
<version>${ip2region.version}</version>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-core</artifactId>
<version>${undertow.version}</version>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId>
<version>${undertow.version}</version>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-websockets-jsr</artifactId>
<version>${undertow.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>

View File

@@ -25,8 +25,6 @@ snail-job:
namespace: ${spring.profiles.active}
# 随主应用端口飘逸
port: 2${server.port}
# 客户端ip指定
host:
--- # 数据源配置
spring:

View File

@@ -28,8 +28,6 @@ snail-job:
namespace: ${spring.profiles.active}
# 随主应用端口飘逸
port: 2${server.port}
# 客户端ip指定
host:
--- # 数据源配置
spring:

View File

@@ -223,10 +223,9 @@ xss:
# 过滤开关
enabled: true
# 排除链接(多个用逗号分隔)
excludeUrls:
- /system/notice
- /workflow/model/save
- /workflow/model/editModelXml
excludes: /system/notice
# 匹配链接
urlPatterns: /system/*,/monitor/*,/tool/*
# 全局线程池相关配置
# 如使用JDK21请直接使用虚拟线程 不要开启此配置
@@ -271,24 +270,21 @@ websocket:
# 设置访问源地址
allowedOrigins: '*'
--- #flowable配置
flowable:
# 开关 用于启动/停用工作流
enabled: true
process.enabled: ${flowable.enabled}
eventregistry.enabled: ${flowable.enabled}
async-executor-activate: false #关闭定时任务JOB
# 将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时会自动将数据库表结构升级至新版本。
database-schema-update: true
activity-font-name: 宋体
label-font-name: 宋体
annotation-font-name: 宋体
# 关闭各个模块生成表,目前只使用工作流基础表
idm:
enabled: false
cmmn:
enabled: false
dmn:
enabled: false
app:
enabled: false
--- # warm-flow工作流配置
warm-flow:
# 是否显示banner图默认是
banner: true
# 填充器 (可配置文件注入,也可用@Bean/@Component方式
data-fill-handler-path: com.ruoyi.system.handle.CustomDataFillHandler
# 全局租户处理器(可配置文件注入,也可用@Bean/@Component方式
tenant_handler_path: com.ruoyi.system.handle.CustomTenantHandler
# 是否开启逻辑删除
logic_delete: false
# 逻辑删除字段值开启后默认为2
logic_delete_value: 2
# 逻辑未删除字段开启后默认为0
logic_not_delete_value: 0
# 数据源类型, mybatis模块对orm进一步的封装, 由于各数据库分页语句存在差异,
# 当配置此参数时, 以此参数结果为基准, 未配置时, 取DataSource中数据源类型,
# 兜底为mysql数据库
data_source_type: mysql

View File

@@ -14,7 +14,7 @@
</description>
<properties>
<revision>5.2.3</revision>
<revision>5.2.2</revision>
</properties>
<dependencyManagement>

View File

@@ -1,62 +0,0 @@
package org.dromara.common.core.exception;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.io.Serial;
/**
* sse 特制异常
*
* @author LionLi
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public final class SseException extends RuntimeException {
@Serial
private static final long serialVersionUID = 1L;
/**
* 错误码
*/
private Integer code;
/**
* 错误提示
*/
private String message;
/**
* 错误明细,内部调试错误
*/
private String detailMessage;
public SseException(String message) {
this.message = message;
}
public SseException(String message, Integer code) {
this.message = message;
this.code = code;
}
@Override
public String getMessage() {
return message;
}
public SseException setMessage(String message) {
this.message = message;
return this;
}
public SseException setDetailMessage(String detailMessage) {
this.detailMessage = detailMessage;
return this;
}
}

View File

@@ -16,7 +16,7 @@ public interface WorkflowService {
* @param businessKeys 业务id
* @return 结果
*/
boolean deleteRunAndHisInstance(List<String> businessKeys);
boolean deleteInstance(List<Long> businessKeys);
/**
* 获取当前流程状态

View File

@@ -17,10 +17,7 @@ import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.util.ClassUtils;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@@ -37,7 +34,7 @@ public class EncryptorManager {
/**
* 缓存加密器
*/
Map<Integer, IEncryptor> encryptorMap = new ConcurrentHashMap<>();
Map<EncryptContext, IEncryptor> encryptorMap = new ConcurrentHashMap<>();
/**
* 类加密字段缓存
@@ -70,12 +67,11 @@ public class EncryptorManager {
* @param encryptContext 加密执行者需要的相关配置参数
*/
public IEncryptor registAndGetEncryptor(EncryptContext encryptContext) {
int key = encryptContext.hashCode();
if (encryptorMap.containsKey(key)) {
return encryptorMap.get(key);
if (encryptorMap.containsKey(encryptContext)) {
return encryptorMap.get(encryptContext);
}
IEncryptor encryptor = ReflectUtil.newInstance(encryptContext.getAlgorithm().getClazz(), encryptContext);
encryptorMap.put(key, encryptor);
encryptorMap.put(encryptContext, encryptor);
return encryptor;
}
@@ -85,7 +81,7 @@ public class EncryptorManager {
* @param encryptContext 加密执行者需要的相关配置参数
*/
public void removeEncryptor(EncryptContext encryptContext) {
this.encryptorMap.remove(encryptContext.hashCode());
this.encryptorMap.remove(encryptContext);
}
/**

View File

@@ -99,7 +99,7 @@ public class CryptoFilter implements Filter {
}
}
} catch (Exception e) {
return null;
throw new RuntimeException(e);
}
return null;
}

View File

@@ -159,7 +159,8 @@ public class LogAspect {
private void setRequestValue(JoinPoint joinPoint, OperLogEvent operLog, String[] excludeParamNames) throws Exception {
Map<String, String> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
String requestMethod = operLog.getRequestMethod();
if (MapUtil.isEmpty(paramsMap) && StringUtils.equalsAny(requestMethod, HttpMethod.PUT.name(), HttpMethod.POST.name(), HttpMethod.DELETE.name())) {
if (MapUtil.isEmpty(paramsMap)
&& HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
operLog.setOperParam(StringUtils.substring(params, 0, 2000));
} else {

View File

@@ -18,7 +18,9 @@ import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 自定义 Mapper 接口, 实现 自定义扩展
@@ -67,7 +69,9 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
* @return 插入操作是否成功的布尔值
*/
default boolean insertBatch(Collection<T> entityList) {
return Db.saveBatch(entityList);
Db.saveBatch(entityList);
// 临时解决 新版本 mp 插入状态判断错误问题
return true;
}
/**
@@ -77,7 +81,9 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
* @return 更新操作是否成功的布尔值
*/
default boolean updateBatchById(Collection<T> entityList) {
return Db.updateBatchById(entityList);
Db.updateBatchById(entityList);
// 临时解决 新版本 mp 插入状态判断错误问题
return true;
}
/**
@@ -87,7 +93,9 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
* @return 插入或更新操作是否成功的布尔值
*/
default boolean insertOrUpdateBatch(Collection<T> entityList) {
return Db.saveOrUpdateBatch(entityList);
Db.saveOrUpdateBatch(entityList);
// 临时解决 新版本 mp 插入状态判断错误问题
return true;
}
/**
@@ -98,7 +106,9 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
* @return 插入操作是否成功的布尔值
*/
default boolean insertBatch(Collection<T> entityList, int batchSize) {
return Db.saveBatch(entityList, batchSize);
Db.saveBatch(entityList, batchSize);
// 临时解决 新版本 mp 插入状态判断错误问题
return true;
}
/**
@@ -109,7 +119,9 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
* @return 更新操作是否成功的布尔值
*/
default boolean updateBatchById(Collection<T> entityList, int batchSize) {
return Db.updateBatchById(entityList, batchSize);
Db.updateBatchById(entityList, batchSize);
// 临时解决 新版本 mp 插入状态判断错误问题
return true;
}
/**
@@ -120,7 +132,9 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
* @return 插入或更新操作是否成功的布尔值
*/
default boolean insertOrUpdateBatch(Collection<T> entityList, int batchSize) {
return Db.saveOrUpdateBatch(entityList, batchSize);
Db.saveOrUpdateBatch(entityList, batchSize);
// 临时解决 新版本 mp 插入状态判断错误问题
return true;
}
/**
@@ -155,8 +169,8 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
* @param idList 主键ID集合
* @return 查询到的VO对象列表
*/
default List<V> selectVoByIds(Collection<? extends Serializable> idList) {
return selectVoByIds(idList, this.currentVoClass());
default List<V> selectVoBatchIds(Collection<? extends Serializable> idList) {
return selectVoBatchIds(idList, this.currentVoClass());
}
/**
@@ -167,8 +181,8 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
* @param <C> VO类的类型
* @return 查询到的VO对象列表经过转换为指定的VO类后返回
*/
default <C> List<C> selectVoByIds(Collection<? extends Serializable> idList, Class<C> voClass) {
List<T> list = this.selectByIds(idList);
default <C> List<C> selectVoBatchIds(Collection<? extends Serializable> idList, Class<C> voClass) {
List<T> list = this.selectBatchIds(idList);
if (CollUtil.isEmpty(list)) {
return CollUtil.newArrayList();
}

View File

@@ -6,8 +6,8 @@ import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import org.apache.ibatis.io.Resources;
import org.dromara.common.core.domain.dto.RoleDTO;
@@ -106,7 +106,7 @@ public class PlusDataPermissionHandler {
try {
Expression expression = CCJSqlParserUtil.parseExpression(dataFilterSql);
// 数据权限使用单独的括号 防止与其他条件冲突
ParenthesedExpressionList<Expression> parenthesis = new ParenthesedExpressionList<>(expression);
Parenthesis parenthesis = new Parenthesis(expression);
if (ObjectUtil.isNotNull(where)) {
return new AndExpression(where, parenthesis);
} else {

View File

@@ -62,8 +62,8 @@ public class DataBaseHelper {
// charindex(',100,' , ',0,100,101,') <> 0
return "charindex(',%s,' , ','+%s+',') <> 0".formatted(var, var2);
} else if (dataBasyType == DataBaseType.POSTGRE_SQL) {
// (select strpos(',0,100,101,' , ',100,')) <> 0
return "(select strpos(','||%s||',' , ',%s,')) <> 0".formatted(var2, var);
// (select position(',100,' in ',0,100,101,')) <> 0
return "(select position(',%s,' in ','||%s||',')) <> 0".formatted(var, var2);
} else if (dataBasyType == DataBaseType.ORACLE) {
// instr(',0,100,101,' , ',100,') <> 0
return "instr(','||%s||',' , ',%s,') <> 0".formatted(var2, var);

View File

@@ -15,12 +15,12 @@ import org.dromara.common.oss.properties.OssProperties;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.core.ResponseInputStream;
import software.amazon.awssdk.core.async.AsyncRequestBody;
import software.amazon.awssdk.core.async.AsyncResponseTransformer;
import software.amazon.awssdk.core.async.BlockingInputStreamAsyncRequestBody;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3AsyncClient;
import software.amazon.awssdk.services.s3.S3Configuration;
import software.amazon.awssdk.services.s3.crt.S3CrtHttpConfiguration;
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
import software.amazon.awssdk.services.s3.model.NoSuchBucketException;
import software.amazon.awssdk.services.s3.model.S3Exception;
@@ -83,8 +83,8 @@ public class OssClient {
StaticCredentialsProvider credentialsProvider = StaticCredentialsProvider.create(
AwsBasicCredentials.create(properties.getAccessKey(), properties.getSecretKey()));
//使用对象存储服务时要求明确配置访问样式(路径样式或虚拟托管样式)。需要启用路径样式访问
boolean isStyle = true;
//MinIO 使用 HTTPS 限制使用域名访问,站点填域名。需要启用路径样式访问
boolean isStyle = !StringUtils.containsAny(properties.getEndpoint(), OssConstant.CLOUD_SERVICE);
//创建AWS基于 CRT 的 S3 客户端
this.client = S3AsyncClient.crtBuilder()
@@ -95,9 +95,6 @@ public class OssClient {
.minimumPartSizeInBytes(10 * 1025 * 1024L)
.checksumValidationEnabled(false)
.forcePathStyle(isStyle)
.httpConfiguration(S3CrtHttpConfiguration.builder()
.connectionTimeout(Duration.ofSeconds(60)) // 设置连接超时
.build())
.build();
//AWS基于 CRT 的 S3 AsyncClient 实例用作 S3 传输管理器的底层客户端
@@ -181,9 +178,7 @@ public class OssClient {
.key(key)
.contentMD5(StringUtils.isNotEmpty(md5Digest) ? md5Digest : null)
.contentType(contentType)
// 用于设置对象的访问控制列表ACL。不同云厂商对ACL的支持和实现方式有所不同
// 因此根据具体的云服务提供商你可能需要进行不同的配置自行开启阿里云有acl权限配置腾讯云没有acl权限配置
//.acl(getAccessPolicy().getObjectCannedACL())
.acl(getAccessPolicy().getObjectCannedACL())
.build())
.addTransferListener(LoggingTransferListener.create())
.source(filePath).build());
@@ -220,10 +215,7 @@ public class OssClient {
}
try {
// 创建异步请求体length如果为空会报错
BlockingInputStreamAsyncRequestBody body = BlockingInputStreamAsyncRequestBody.builder()
.contentLength(length)
.subscribeTimeout(Duration.ofSeconds(30))
.build();
BlockingInputStreamAsyncRequestBody body = AsyncRequestBody.forBlockingInputStream(length);
// 使用 transferManager 进行上传
Upload upload = transferManager.upload(
@@ -232,9 +224,7 @@ public class OssClient {
y -> y.bucket(properties.getBucketName())
.key(key)
.contentType(contentType)
// 用于设置对象的访问控制列表ACL。不同云厂商对ACL的支持和实现方式有所不同
// 因此根据具体的云服务提供商你可能需要进行不同的配置自行开启阿里云有acl权限配置腾讯云没有acl权限配置
//.acl(getAccessPolicy().getObjectCannedACL())
.acl(getAccessPolicy().getObjectCannedACL())
.build())
.build());

View File

@@ -44,7 +44,6 @@ public class CaffeineCacheDecorator implements Cache {
}
@SuppressWarnings("unchecked")
@Override
public <T> T get(Object key, Class<T> type) {
Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key, type));
return (T) o;
@@ -56,7 +55,6 @@ public class CaffeineCacheDecorator implements Cache {
cache.put(key, value);
}
@Override
public ValueWrapper putIfAbsent(Object key, Object value) {
CAFFEINE.invalidate(getUniqueKey(key));
return cache.putIfAbsent(key, value);
@@ -67,7 +65,6 @@ public class CaffeineCacheDecorator implements Cache {
evictIfPresent(key);
}
@Override
public boolean evictIfPresent(Object key) {
boolean b = cache.evictIfPresent(key);
if (b) {
@@ -81,7 +78,6 @@ public class CaffeineCacheDecorator implements Cache {
cache.clear();
}
@Override
public boolean invalidate() {
return cache.invalidate();
}

View File

@@ -1,15 +1,19 @@
package org.dromara.common.redis.utils;
import org.dromara.common.core.utils.SpringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.dromara.common.core.utils.SpringUtils;
import org.redisson.api.RMap;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import java.util.Set;
/**
* 缓存操作工具类
* 缓存操作工具类 {@link }
*
* @author Michelle.Chung
* @date 2022/8/13
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@SuppressWarnings(value = {"unchecked"})
@@ -17,6 +21,16 @@ public class CacheUtils {
private static final CacheManager CACHE_MANAGER = SpringUtils.getBean(CacheManager.class);
/**
* 获取缓存组内所有的KEY
*
* @param cacheNames 缓存组名称
*/
public static Set<Object> keys(String cacheNames) {
RMap<Object, Object> rmap = (RMap<Object, Object>) CACHE_MANAGER.getCache(cacheNames).getNativeCache();
return rmap.keySet();
}
/**
* 获取缓存值
*

View File

@@ -517,7 +517,7 @@ public class RedisUtils {
}
/**
* 获得缓存的基本对象列表(全局匹配忽略租户 自行拼接租户id)
* 获得缓存的基本对象列表
*
* @param pattern 字符串前缀
* @return 对象列表
@@ -528,7 +528,7 @@ public class RedisUtils {
}
/**
* 删除缓存的基本对象列表(全局匹配忽略租户 自行拼接租户id)
* 删除缓存的基本对象列表
*
* @param pattern 字符串前缀
*/

View File

@@ -7,11 +7,9 @@ import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.SseException;
import org.dromara.common.core.utils.ServletUtils;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
@@ -52,20 +50,11 @@ public class SecurityConfig implements WebMvcConfigurer {
.match(allUrlHandler.getUrls())
// 对未排除的路径进行检查
.check(() -> {
HttpServletRequest request = ServletUtils.getRequest();
// 检查是否登录 是否有token
try {
StpUtil.checkLogin();
} catch (NotLoginException e) {
if (request.getRequestURI().contains("sse")) {
throw new SseException(e.getMessage(), e.getCode());
} else {
throw e;
}
}
StpUtil.checkLogin();
// 检查 header 与 param 里的 clientid 与 token 里的是否一致
String headerCid = request.getHeader(LoginHelper.CLIENT_KEY);
String headerCid = ServletUtils.getRequest().getHeader(LoginHelper.CLIENT_KEY);
String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY);
String clientId = StpUtil.getExtra(LoginHelper.CLIENT_KEY).toString();
if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) {

View File

@@ -1,11 +1,14 @@
package org.dromara.common.sse.core;
import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.sse.dto.SseMessageDto;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
@@ -121,13 +124,25 @@ public class SseEmitterManager {
* @param sseMessageDto 要发布的SSE消息对象
*/
public void publishMessage(SseMessageDto sseMessageDto) {
SseMessageDto broadcastMessage = new SseMessageDto();
broadcastMessage.setMessage(sseMessageDto.getMessage());
broadcastMessage.setUserIds(sseMessageDto.getUserIds());
RedisUtils.publish(SSE_TOPIC, broadcastMessage, consumer -> {
log.info("SSE发送主题订阅消息topic:{} session keys:{} message:{}",
SSE_TOPIC, sseMessageDto.getUserIds(), sseMessageDto.getMessage());
});
List<Long> unsentUserIds = new ArrayList<>();
// 当前服务内用户,直接发送消息
for (Long userId : sseMessageDto.getUserIds()) {
if (USER_TOKEN_EMITTERS.containsKey(userId)) {
sendMessage(userId, sseMessageDto.getMessage());
continue;
}
unsentUserIds.add(userId);
}
// 不在当前服务内用户,发布订阅消息
if (CollUtil.isNotEmpty(unsentUserIds)) {
SseMessageDto broadcastMessage = new SseMessageDto();
broadcastMessage.setMessage(sseMessageDto.getMessage());
broadcastMessage.setUserIds(unsentUserIds);
RedisUtils.publish(SSE_TOPIC, broadcastMessage, consumer -> {
log.info("SSE发送主题订阅消息topic:{} session keys:{} message:{}",
SSE_TOPIC, unsentUserIds, sseMessageDto.getMessage());
});
}
}
/**

View File

@@ -35,8 +35,7 @@ public class TenantKeyPrefixHandler extends KeyPrefixHandler {
}
String tenantId = TenantHelper.getTenantId();
if (StringUtils.isBlank(tenantId)) {
log.debug("无法获取有效的租户id -> Null");
return super.map(name);
log.error("无法获取有效的租户id -> Null");
}
if (StringUtils.startsWith(name, tenantId + "")) {
// 如果存在则直接返回
@@ -62,8 +61,7 @@ public class TenantKeyPrefixHandler extends KeyPrefixHandler {
}
String tenantId = TenantHelper.getTenantId();
if (StringUtils.isBlank(tenantId)) {
log.debug("无法获取有效的租户id -> Null");
return super.unmap(name);
log.error("无法获取有效的租户id -> Null");
}
if (StringUtils.startsWith(unmap, tenantId + "")) {
// 如果存在则删除

View File

@@ -1,5 +1,6 @@
package org.dromara.common.tenant.helper;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
@@ -129,7 +130,7 @@ public class TenantHelper {
if (!isEnable()) {
return;
}
if (!LoginHelper.isLogin() || !global) {
if (!isLogin() || !global) {
TEMP_DYNAMIC_TENANT.set(tenantId);
return;
}
@@ -146,7 +147,7 @@ public class TenantHelper {
if (!isEnable()) {
return null;
}
if (!LoginHelper.isLogin()) {
if (!isLogin()) {
return TEMP_DYNAMIC_TENANT.get();
}
// 如果线程内有值 优先返回
@@ -166,7 +167,7 @@ public class TenantHelper {
if (!isEnable()) {
return;
}
if (!LoginHelper.isLogin()) {
if (!isLogin()) {
TEMP_DYNAMIC_TENANT.remove();
return;
}
@@ -217,4 +218,13 @@ public class TenantHelper {
return tenantId;
}
private static boolean isLogin() {
try {
StpUtil.checkLogin();
return true;
} catch (Exception e) {
return false;
}
}
}

View File

@@ -43,6 +43,19 @@
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-core</artifactId>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-websockets-jsr</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>

View File

@@ -1,15 +1,19 @@
package org.dromara.common.web.config;
import jakarta.servlet.DispatcherType;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.web.config.properties.XssProperties;
import org.dromara.common.web.filter.RepeatableFilter;
import org.dromara.common.web.filter.XssFilter;
import jakarta.servlet.DispatcherType;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import java.util.HashMap;
import java.util.Map;
/**
* Filter配置
*
@@ -19,21 +23,26 @@ import org.springframework.context.annotation.Bean;
@EnableConfigurationProperties(XssProperties.class)
public class FilterConfig {
@SuppressWarnings({"rawtypes", "unchecked"})
@Bean
@ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
public FilterRegistrationBean<XssFilter> xssFilterRegistration() {
FilterRegistrationBean<XssFilter> registration = new FilterRegistrationBean<>();
public FilterRegistrationBean xssFilterRegistration(XssProperties xssProperties) {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setDispatcherTypes(DispatcherType.REQUEST);
registration.setFilter(new XssFilter());
registration.addUrlPatterns("/*");
registration.addUrlPatterns(StringUtils.split(xssProperties.getUrlPatterns(), StringUtils.SEPARATOR));
registration.setName("xssFilter");
registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE + 1);
registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
Map<String, String> initParameters = new HashMap<>();
initParameters.put("excludes", xssProperties.getExcludes());
registration.setInitParameters(initParameters);
return registration;
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Bean
public FilterRegistrationBean<RepeatableFilter> someFilterRegistration() {
FilterRegistrationBean<RepeatableFilter> registration = new FilterRegistrationBean<>();
public FilterRegistrationBean someFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new RepeatableFilter());
registration.addUrlPatterns("/*");
registration.setName("repeatableFilter");

View File

@@ -3,9 +3,6 @@ package org.dromara.common.web.config.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.ArrayList;
import java.util.List;
/**
* xss过滤 配置属性
*
@@ -16,13 +13,18 @@ import java.util.List;
public class XssProperties {
/**
* Xss开关
* 过滤开关
*/
private Boolean enabled;
private String enabled;
/**
* 排除路径
* 排除链接(多个用逗号分隔)
*/
private List<String> excludeUrls = new ArrayList<>();
private String excludes;
/**
* 匹配链接
*/
private String urlPatterns;
}

View File

@@ -1,8 +1,6 @@
package org.dromara.common.web.filter;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.web.config.properties.XssProperties;
import org.springframework.http.HttpMethod;
import jakarta.servlet.*;
@@ -25,8 +23,13 @@ public class XssFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
XssProperties properties = SpringUtils.getBean(XssProperties.class);
excludes.addAll(properties.getExcludeUrls());
String tempExcludes = filterConfig.getInitParameter("excludes");
if (StringUtils.isNotEmpty(tempExcludes)) {
String[] url = tempExcludes.split(StringUtils.SEPARATOR);
for (int i = 0; url != null && i < url.length; i++) {
excludes.add(url[i]);
}
}
}
@Override

View File

@@ -14,7 +14,6 @@ import jakarta.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
* XSS过滤处理
@@ -29,33 +28,6 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
super(request);
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if (value != null) {
return HtmlUtil.cleanHtmlTag(value).trim();
}
return value;
}
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> valueMap = super.getParameterMap();
for (Map.Entry<String, String[]> entry : valueMap.entrySet()) {
String[] values = entry.getValue();
if (values != null) {
int length = values.length;
String[] escapseValues = new String[length];
for (int i = 0; i < length; i++) {
// 防xss攻击和过滤前后空格
escapseValues[i] = HtmlUtil.cleanHtmlTag(values[i]).trim();
}
valueMap.put(entry.getKey(), escapseValues);
}
}
return valueMap;
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
@@ -68,7 +40,7 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
}
return escapseValues;
}
return values;
return super.getParameterValues(name);
}
@Override

View File

@@ -9,10 +9,9 @@ import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.exception.SseException;
import org.dromara.common.core.exception.base.BaseException;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.core.utils.StringUtils;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
@@ -56,25 +55,20 @@ public class GlobalExceptionHandler {
return ObjectUtil.isNotNull(code) ? R.fail(code, e.getMessage()) : R.fail(e.getMessage());
}
/**
* 认证失败
*/
@ResponseStatus(org.springframework.http.HttpStatus.UNAUTHORIZED)
@ExceptionHandler(SseException.class)
public String handleNotLoginException(SseException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',认证失败'{}',无法访问系统资源", requestURI, e.getMessage());
return JsonUtils.toJsonString(R.fail(HttpStatus.HTTP_UNAUTHORIZED, "认证失败,无法访问系统资源"));
}
/**
* servlet异常
*/
@ExceptionHandler(ServletException.class)
public R<Void> handleServletException(ServletException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',发生未知异常.", requestURI, e);
return R.fail(e.getMessage());
if (StringUtils.contains(e.getMessage(), "NotLoginException")) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',认证失败'{}',无法访问系统资源", requestURI, e.getMessage());
return R.fail(HttpStatus.HTTP_UNAUTHORIZED, "认证失败,无法访问系统资源");
} else {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',发生未知异常.", requestURI, e);
return R.fail(e.getMessage());
}
}
/**
@@ -176,7 +170,7 @@ public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public R<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error(e.getMessage());
String message = StreamUtils.join(e.getBindingResult().getAllErrors(), DefaultMessageSourceResolvable::getDefaultMessage, ", ");
String message = e.getBindingResult().getFieldError().getDefaultMessage();
return R.fail(message);
}

View File

@@ -2,7 +2,6 @@ package org.dromara.common.web.interceptor;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
@@ -65,11 +64,9 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
StopWatch stopWatch = KEY_CACHE.get();
if (ObjectUtil.isNotNull(stopWatch)) {
stopWatch.stop();
log.info("[PLUS]结束请求 => URL[{}],耗时:[{}]毫秒", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime());
KEY_CACHE.remove();
}
stopWatch.stop();
log.info("[PLUS]结束请求 => URL[{}],耗时:[{}]毫秒", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime());
KEY_CACHE.remove();
}
/**

View File

@@ -16,18 +16,6 @@
<groupId>com.aizuda</groupId>
<artifactId>snail-job-server-starter</artifactId>
<version>${snailjob.version}</version>
<exclusions>
<exclusion>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.13.9</version>
</dependency>
<dependency>

View File

@@ -48,7 +48,7 @@ public interface TestDemoMapper extends BaseMapperPlus<TestDemo, TestDemoVo> {
@DataColumn(key = "deptName", value = "dept_id"),
@DataColumn(key = "userName", value = "user_id")
}, joinStr = "AND")
List<TestDemo> selectByIds(@Param(Constants.COLL) Collection<? extends Serializable> idList);
List<TestDemo> selectBatchIds(@Param(Constants.COLL) Collection<? extends Serializable> idList);
@Override
@DataPermission({

View File

@@ -101,7 +101,7 @@ public class TestDemoServiceImpl implements ITestDemoService {
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// 做一些业务上的校验,判断是否需要校验
List<TestDemo> list = baseMapper.selectByIds(ids);
List<TestDemo> list = baseMapper.selectBatchIds(ids);
if (list.size() != ids.size()) {
throw new ServiceException("您没有删除权限!");
}

View File

@@ -56,13 +56,13 @@ public interface GenConstants {
* 数据库时间类型
*/
String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp", "year", "interval",
"smalldatetime", "datetime2", "datetimeoffset", "timestamptz"};
"smalldatetime", "datetime2", "datetimeoffset"};
/**
* 数据库数字类型
*/
String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "int2", "int4", "int8", "number", "integer",
"bit", "bigint", "float", "float4", "float8", "double", "decimal", "numeric", "real", "double precision",
String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer",
"bit", "bigint", "float", "double", "decimal", "numeric", "real", "double precision",
"smallserial", "serial", "bigserial", "money", "smallmoney"};
/**

View File

@@ -2,8 +2,10 @@ package org.dromara.generator.mapper;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.generator.domain.GenTable;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -38,14 +40,6 @@ public interface GenTableMapper extends BaseMapperPlus<GenTable, GenTable> {
*/
GenTable selectGenTableByName(String tableName);
/**
* 查询指定数据源下的所有表名列表
*
* @param dataName 数据源名称,用于选择不同的数据源
* @return 当前数据库中的表名列表
*
* @DS("") 使用默认数据源执行查询操作
*/
@DS("")
List<String> selectTableNameList(String dataName);
}

View File

@@ -3,7 +3,6 @@ package org.dromara.system.listener;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.http.HtmlUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import jakarta.validation.ConstraintViolation;
@@ -83,7 +82,7 @@ public class SysUserImportListener extends AnalysisEventListener<SysUserImportVo
}
} catch (Exception e) {
failureNum++;
String msg = "<br/>" + failureNum + "、账号 " + HtmlUtil.cleanHtmlTag(userVo.getUserName()) + " 导入失败:";
String msg = "<br/>" + failureNum + "、账号 " + userVo.getUserName() + " 导入失败:";
String message = e.getMessage();
if (e instanceof ConstraintViolationException cvException) {
message = StreamUtils.join(cvException.getConstraintViolations(), ConstraintViolation::getMessage, ", ");

View File

@@ -244,7 +244,7 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
if (isValid) {
// 做一些业务上的校验,判断是否需要校验
}
List<SysOss> list = baseMapper.selectByIds(ids);
List<SysOss> list = baseMapper.selectBatchIds(ids);
for (SysOss sysOss : list) {
OssClient storage = OssFactory.instance(sysOss.getService());
storage.delete(sysOss.getUrl());

View File

@@ -1,7 +1,6 @@
package org.dromara.system.service.impl;
import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
@@ -204,7 +203,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
String numbers = RandomUtil.randomNumbers(6);
// 判断是否存在,如果存在则重新生成
if (tenantIds.contains(numbers)) {
return generateTenantId(tenantIds);
generateTenantId(tenantIds);
}
return numbers;
}
@@ -269,9 +268,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
@CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId")
@Override
public int updateTenantStatus(SysTenantBo bo) {
SysTenant tenant = new SysTenant();
tenant.setId(bo.getId());
tenant.setStatus(bo.getStatus());
SysTenant tenant = MapstructUtils.convert(bo, SysTenant.class);
return baseMapper.updateById(tenant);
}
@@ -414,48 +411,43 @@ public class SysTenantServiceImpl implements ISysTenantService {
Map<String, SysDictData> map = StreamUtils.toIdentityMap(dataListTenant, SysDictData::getDictValue);
for (SysDictData dictData : dataList) {
if (!map.containsKey(dictData.getDictValue())) {
SysDictData data = BeanUtil.toBean(dictData, SysDictData.class);
// 设置字典编码为 null
data.setDictCode(null);
data.setTenantId(tenantId);
data.setCreateTime(null);
data.setUpdateTime(null);
dictData.setDictCode(null);
dictData.setTenantId(tenantId);
dictData.setCreateTime(null);
dictData.setUpdateTime(null);
set.add(tenantId);
saveDataList.add(data);
saveDataList.add(dictData);
}
}
} else {
SysDictType type = BeanUtil.toBean(dictType, SysDictType.class);
type.setDictId(null);
type.setTenantId(tenantId);
type.setCreateTime(null);
type.setUpdateTime(null);
dictType.setDictId(null);
dictType.setTenantId(tenantId);
dictType.setCreateTime(null);
dictType.setUpdateTime(null);
set.add(tenantId);
saveTypeList.add(type);
saveTypeList.add(dictType);
if (CollUtil.isNotEmpty(dataList)) {
// 筛选出 dictType 对应的 data
for (SysDictData dictData : dataList) {
SysDictData data = BeanUtil.toBean(dictData, SysDictData.class);
// 设置字典编码为 null
data.setDictCode(null);
data.setTenantId(tenantId);
data.setCreateTime(null);
data.setUpdateTime(null);
dictData.setDictCode(null);
dictData.setTenantId(tenantId);
dictData.setCreateTime(null);
dictData.setUpdateTime(null);
set.add(tenantId);
saveDataList.add(data);
}
saveDataList.addAll(dataList);
}
}
}
}
TenantHelper.ignore(() -> {
if (CollUtil.isNotEmpty(saveTypeList)) {
dictTypeMapper.insertBatch(saveTypeList);
}
if (CollUtil.isNotEmpty(saveDataList)) {
dictDataMapper.insertBatch(saveDataList);
}
});
if (CollUtil.isNotEmpty(saveTypeList)) {
dictTypeMapper.insertBatch(saveTypeList);
}
if (CollUtil.isNotEmpty(saveDataList)) {
dictDataMapper.insertBatch(saveDataList);
}
for (String tenantId : set) {
TenantHelper.dynamic(tenantId, () -> CacheUtils.clear(CacheNames.SYS_DICT));
}

View File

@@ -18,54 +18,6 @@
<dependencies>
<!--引入flowable依赖-->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-autoconfigure</artifactId>
<exclusions>
<exclusion>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-security</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-configurator</artifactId>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 绘制flowable流程图 -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-image-generator</artifactId>
</dependency>
<!-- flowable json 转换 -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-json-converter</artifactId>
<version>6.8.0</version>
</dependency>
<!-- svg转png图片工具-->
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-all</artifactId>
<version>1.17</version>
<exclusions>
<exclusion>
<groupId>xalan</groupId>
<artifactId>xalan</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-websocket</artifactId>
@@ -113,6 +65,10 @@
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-security</artifactId>
</dependency>
<dependency>
<groupId>io.github.minliuhua</groupId>
<artifactId>warm-flow-mybatis-plus-sb-starter</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,25 @@
package org.dromara.workflow.config;
import com.warm.flow.core.handler.TenantHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.dromara.common.satoken.utils.LoginHelper;
/**
* 任务状态枚举
*
* @author may
*/
@Configuration
public class WarmFlowConfig {
/**
* 全局租户处理器(可配置文件注入,也可用@Bean/@Component方式
*/
@Bean
public TenantHandler tenantHandler() {
return LoginHelper::getTenantId;
}
}

View File

@@ -1,148 +0,0 @@
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.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.web.core.BaseController;
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.beans.factory.annotation.Autowired;
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 {
@Autowired(required = false)
private RepositoryService repositoryService;
private final IActModelService actModelService;
/**
* 分页查询模型
*
* @param modelBo 模型参数
*/
@GetMapping("/list")
public TableDataInfo<Model> page(ModelBo modelBo, PageQuery pageQuery) {
return actModelService.page(modelBo, pageQuery);
}
/**
* 新增模型
*
* @param modelBo 模型请求对象
*/
@Log(title = "模型管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/save")
public R<Void> saveNewModel(@Validated(AddGroup.class) @RequestBody ModelBo modelBo) {
return toAjax(actModelService.saveNewModel(modelBo));
}
/**
* 查询模型
*
* @param id 模型id
*/
@GetMapping("/getInfo/{id}")
public R<ModelVo> 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<Void> update(@RequestBody ModelBo modelBo) {
return toAjax(actModelService.update(modelBo));
}
/**
* 编辑XMl模型
*
* @param modelBo 模型数据
*/
@Log(title = "模型管理", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping(value = "/editModelXml")
public R<Void> 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<Void> 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<Void> 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<String> modelIds,
HttpServletResponse response) {
actModelService.exportZip(modelIds, response);
}
/**
* 复制模型
*
* @param modelBo 模型数据
*/
@PostMapping("/copyModel")
public R<Void> copyModel(@RequestBody ModelBo modelBo) {
return toAjax(actModelService.copyModel(modelBo));
}
}

View File

@@ -1,147 +0,0 @@
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<ProcessDefinitionVo> page(ProcessDefinitionBo bo, PageQuery pageQuery) {
return actProcessDefinitionService.page(bo, pageQuery);
}
/**
* 查询历史流程定义列表
*
* @param key 流程定义key
*/
@GetMapping("/getListByKey/{key}")
public R<List<ProcessDefinitionVo>> getListByKey(@NotEmpty(message = "流程定义key不能为空") @PathVariable String key) {
return R.ok("操作成功", actProcessDefinitionService.getListByKey(key));
}
/**
* 查看流程定义图片
*
* @param processDefinitionId 流程定义id
*/
@GetMapping("/definitionImage/{processDefinitionId}")
public R<String> definitionImage(@PathVariable String processDefinitionId) {
return R.ok("操作成功", actProcessDefinitionService.definitionImage(processDefinitionId));
}
/**
* 查看流程定义xml文件
*
* @param processDefinitionId 流程定义id
*/
@GetMapping("/definitionXml/{processDefinitionId}")
public R<Map<String, Object>> definitionXml(@NotBlank(message = "流程定义id不能为空") @PathVariable String processDefinitionId) {
Map<String, Object> map = new HashMap<>();
String xmlStr = actProcessDefinitionService.definitionXml(processDefinitionId);
map.put("xml", Arrays.asList(xmlStr.split("\n")));
map.put("xmlStr", xmlStr);
return R.ok(map);
}
/**
* 删除流程定义
*
* @param deploymentIds 部署id
* @param processDefinitionIds 流程定义id
*/
@Log(title = "流程定义管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{deploymentIds}/{processDefinitionIds}")
public R<Void> deleteDeployment(@NotNull(message = "流程部署id不能为空") @PathVariable List<String> deploymentIds,
@NotNull(message = "流程定义id不能为空") @PathVariable List<String> processDefinitionIds) {
return toAjax(actProcessDefinitionService.deleteDeployment(deploymentIds, processDefinitionIds));
}
/**
* 激活或者挂起流程定义
*
* @param processDefinitionId 流程定义id
*/
@Log(title = "流程定义管理", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/updateDefinitionState/{processDefinitionId}")
public R<Void> updateDefinitionState(@NotBlank(message = "流程定义id不能为空") @PathVariable String processDefinitionId) {
return toAjax(actProcessDefinitionService.updateDefinitionState(processDefinitionId));
}
/**
* 迁移流程定义
*
* @param currentProcessDefinitionId 当前流程定义id
* @param fromProcessDefinitionId 需要迁移到的流程定义id
*/
@Log(title = "流程定义管理", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/migrationDefinition/{currentProcessDefinitionId}/{fromProcessDefinitionId}")
public R<Void> migrationDefinition(@NotBlank(message = "当前流程定义id") @PathVariable String currentProcessDefinitionId,
@NotBlank(message = "需要迁移到的流程定义id") @PathVariable String fromProcessDefinitionId) {
return toAjax(actProcessDefinitionService.migrationDefinition(currentProcessDefinitionId, fromProcessDefinitionId));
}
/**
* 流程定义转换为模型
*
* @param processDefinitionId 流程定义id
*/
@Log(title = "流程定义管理", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/convertToModel/{processDefinitionId}")
public R<Void> convertToModel(@NotEmpty(message = "流程定义id不能为空") @PathVariable String processDefinitionId) {
return toAjax(actProcessDefinitionService.convertToModel(processDefinitionId));
}
/**
* 通过zip或xml部署流程定义
*
* @param file 文件
* @param categoryCode 分类
*/
@Log(title = "流程定义管理", businessType = BusinessType.INSERT)
@PostMapping("/deployByFile")
public void deployByFile(@RequestParam("file") MultipartFile file, @RequestParam("categoryCode") String categoryCode) {
actProcessDefinitionService.deployByFile(file, categoryCode);
}
}

View File

@@ -1,160 +0,0 @@
package org.dromara.workflow.controller;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
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.ProcessInstanceBo;
import org.dromara.workflow.domain.bo.ProcessInvalidBo;
import org.dromara.workflow.domain.bo.TaskUrgingBo;
import org.dromara.workflow.domain.vo.ActHistoryInfoVo;
import org.dromara.workflow.domain.vo.ProcessInstanceVo;
import org.dromara.workflow.service.IActProcessInstanceService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* 流程实例管理 控制层
*
* @author may
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/workflow/processInstance")
public class ActProcessInstanceController extends BaseController {
private final IActProcessInstanceService actProcessInstanceService;
/**
* 分页查询正在运行的流程实例
*
* @param bo 参数
*/
@GetMapping("/getPageByRunning")
public TableDataInfo<ProcessInstanceVo> getPageByRunning(ProcessInstanceBo bo, PageQuery pageQuery) {
return actProcessInstanceService.getPageByRunning(bo, pageQuery);
}
/**
* 分页查询已结束的流程实例
*
* @param bo 参数
*/
@GetMapping("/getPageByFinish")
public TableDataInfo<ProcessInstanceVo> getPageByFinish(ProcessInstanceBo bo, PageQuery pageQuery) {
return actProcessInstanceService.getPageByFinish(bo, pageQuery);
}
/**
* 通过业务id获取历史流程图
*
* @param businessKey 业务id
*/
@GetMapping("/getHistoryImage/{businessKey}")
public R<String> getHistoryImage(@NotBlank(message = "业务id不能为空") @PathVariable String businessKey) {
return R.ok("操作成功", actProcessInstanceService.getHistoryImage(businessKey));
}
/**
* 通过业务id获取历史流程图运行中历史等节点
*
* @param businessKey 业务id
*/
@GetMapping("/getHistoryList/{businessKey}")
public R<Map<String, Object>> getHistoryList(@NotBlank(message = "业务id不能为空") @PathVariable String businessKey) {
return R.ok("操作成功", actProcessInstanceService.getHistoryList(businessKey));
}
/**
* 获取审批记录
*
* @param businessKey 业务id
*/
@GetMapping("/getHistoryRecord/{businessKey}")
public R<List<ActHistoryInfoVo>> getHistoryRecord(@NotBlank(message = "业务id不能为空") @PathVariable String businessKey) {
return R.ok(actProcessInstanceService.getHistoryRecord(businessKey));
}
/**
* 作废流程实例,不会删除历史记录(删除运行中的实例)
*
* @param processInvalidBo 参数
*/
@Log(title = "流程实例管理", businessType = BusinessType.DELETE)
@RepeatSubmit()
@PostMapping("/deleteRunInstance")
public R<Void> deleteRunInstance(@Validated(AddGroup.class) @RequestBody ProcessInvalidBo processInvalidBo) {
return toAjax(actProcessInstanceService.deleteRunInstance(processInvalidBo));
}
/**
* 运行中的实例 删除程实例,删除历史记录,删除业务与流程关联信息
*
* @param businessKeys 业务id
*/
@Log(title = "流程实例管理", businessType = BusinessType.DELETE)
@RepeatSubmit()
@DeleteMapping("/deleteRunAndHisInstance/{businessKeys}")
public R<Void> deleteRunAndHisInstance(@NotNull(message = "业务id不能为空") @PathVariable String[] businessKeys) {
return toAjax(actProcessInstanceService.deleteRunAndHisInstance(Arrays.asList(businessKeys)));
}
/**
* 已完成的实例 删除程实例,删除历史记录,删除业务与流程关联信息
*
* @param businessKeys 业务id
*/
@Log(title = "流程实例管理", businessType = BusinessType.DELETE)
@RepeatSubmit()
@DeleteMapping("/deleteFinishAndHisInstance/{businessKeys}")
public R<Void> deleteFinishAndHisInstance(@NotNull(message = "业务id不能为空") @PathVariable String[] businessKeys) {
return toAjax(actProcessInstanceService.deleteFinishAndHisInstance(Arrays.asList(businessKeys)));
}
/**
* 撤销流程申请
*
* @param businessKey 业务id
*/
@Log(title = "流程实例管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/cancelProcessApply/{businessKey}")
public R<Void> cancelProcessApply(@NotBlank(message = "业务id不能为空") @PathVariable String businessKey) {
return toAjax(actProcessInstanceService.cancelProcessApply(businessKey));
}
/**
* 分页查询当前登录人单据
*
* @param bo 参数
*/
@GetMapping("/getPageByCurrent")
public TableDataInfo<ProcessInstanceVo> getPageByCurrent(ProcessInstanceBo bo, PageQuery pageQuery) {
return actProcessInstanceService.getPageByCurrent(bo, pageQuery);
}
/**
* 任务催办(给当前任务办理人发送站内信,邮件,短信等)
*
* @param taskUrgingBo 任务催办
*/
@Log(title = "流程实例管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/taskUrging")
public R<Void> taskUrging(@RequestBody TaskUrgingBo taskUrgingBo) {
return toAjax(actProcessInstanceService.taskUrging(taskUrgingBo));
}
}

View File

@@ -1,295 +0,0 @@
package org.dromara.workflow.controller;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
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.workflow.domain.WfTaskBackNode;
import org.dromara.workflow.domain.bo.*;
import org.dromara.workflow.domain.vo.TaskVo;
import org.dromara.workflow.domain.vo.VariableVo;
import org.dromara.workflow.service.IActTaskService;
import org.dromara.workflow.service.IWfTaskBackNodeService;
import org.dromara.workflow.utils.QueryUtils;
import org.flowable.engine.TaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* 任务管理 控制层
*
* @author may
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/workflow/task")
public class ActTaskController extends BaseController {
@Autowired(required = false)
private TaskService taskService;
private final IActTaskService actTaskService;
private final IWfTaskBackNodeService wfTaskBackNodeService;
/**
* 启动任务
*
* @param startProcessBo 启动流程参数
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/startWorkFlow")
public R<Map<String, Object>> startWorkFlow(@Validated(AddGroup.class) @RequestBody StartProcessBo startProcessBo) {
Map<String, Object> map = actTaskService.startWorkFlow(startProcessBo);
return R.ok("提交成功", map);
}
/**
* 办理任务
*
* @param completeTaskBo 办理任务参数
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/completeTask")
public R<Void> completeTask(@Validated(AddGroup.class) @RequestBody CompleteTaskBo completeTaskBo) {
return toAjax(actTaskService.completeTask(completeTaskBo));
}
/**
* 查询当前用户的待办任务
*
* @param taskBo 参数
*/
@GetMapping("/getPageByTaskWait")
public TableDataInfo<TaskVo> getPageByTaskWait(TaskBo taskBo, PageQuery pageQuery) {
return actTaskService.getPageByTaskWait(taskBo, pageQuery);
}
/**
* 查询当前租户所有待办任务
*
* @param taskBo 参数
*/
@GetMapping("/getPageByAllTaskWait")
public TableDataInfo<TaskVo> getPageByAllTaskWait(TaskBo taskBo, PageQuery pageQuery) {
return actTaskService.getPageByAllTaskWait(taskBo, pageQuery);
}
/**
* 查询当前用户的已办任务
*
* @param taskBo 参数
*/
@GetMapping("/getPageByTaskFinish")
public TableDataInfo<TaskVo> getPageByTaskFinish(TaskBo taskBo, PageQuery pageQuery) {
return actTaskService.getPageByTaskFinish(taskBo, pageQuery);
}
/**
* 查询当前用户的抄送
*
* @param taskBo 参数
*/
@GetMapping("/getPageByTaskCopy")
public TableDataInfo<TaskVo> getPageByTaskCopy(TaskBo taskBo, PageQuery pageQuery) {
return actTaskService.getPageByTaskCopy(taskBo, pageQuery);
}
/**
* 查询当前租户所有已办任务
*
* @param taskBo 参数
*/
@GetMapping("/getPageByAllTaskFinish")
public TableDataInfo<TaskVo> getPageByAllTaskFinish(TaskBo taskBo, PageQuery pageQuery) {
return actTaskService.getPageByAllTaskFinish(taskBo, pageQuery);
}
/**
* 签收(拾取)任务
*
* @param taskId 任务id
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/claim/{taskId}")
public R<Void> claimTask(@NotBlank(message = "任务id不能为空") @PathVariable String taskId) {
try {
taskService.claim(taskId, Convert.toStr(LoginHelper.getUserId()));
return R.ok();
} catch (Exception e) {
e.printStackTrace();
return R.fail("签收任务失败:" + e.getMessage());
}
}
/**
* 归还(拾取的)任务
*
* @param taskId 任务id
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/returnTask/{taskId}")
public R<Void> returnTask(@NotBlank(message = "任务id不能为空") @PathVariable String taskId) {
try {
taskService.setAssignee(taskId, null);
return R.ok();
} catch (Exception e) {
e.printStackTrace();
return R.fail("归还任务失败:" + e.getMessage());
}
}
/**
* 委派任务
*
* @param delegateBo 参数
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/delegateTask")
public R<Void> delegateTask(@Validated({AddGroup.class}) @RequestBody DelegateBo delegateBo) {
return toAjax(actTaskService.delegateTask(delegateBo));
}
/**
* 终止任务
*
* @param terminationBo 参数
*/
@Log(title = "任务管理", businessType = BusinessType.DELETE)
@RepeatSubmit()
@PostMapping("/terminationTask")
public R<Void> terminationTask(@RequestBody TerminationBo terminationBo) {
return toAjax(actTaskService.terminationTask(terminationBo));
}
/**
* 转办任务
*
* @param transmitBo 参数
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/transferTask")
public R<Void> transferTask(@Validated({AddGroup.class}) @RequestBody TransmitBo transmitBo) {
return toAjax(actTaskService.transferTask(transmitBo));
}
/**
* 会签任务加签
*
* @param addMultiBo 参数
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/addMultiInstanceExecution")
public R<Void> addMultiInstanceExecution(@Validated({AddGroup.class}) @RequestBody AddMultiBo addMultiBo) {
return toAjax(actTaskService.addMultiInstanceExecution(addMultiBo));
}
/**
* 会签任务减签
*
* @param deleteMultiBo 参数
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/deleteMultiInstanceExecution")
public R<Void> deleteMultiInstanceExecution(@Validated({AddGroup.class}) @RequestBody DeleteMultiBo deleteMultiBo) {
return toAjax(actTaskService.deleteMultiInstanceExecution(deleteMultiBo));
}
/**
* 驳回审批
*
* @param backProcessBo 参数
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/backProcess")
public R<String> backProcess(@Validated({AddGroup.class}) @RequestBody BackProcessBo backProcessBo) {
return R.ok("操作成功", actTaskService.backProcess(backProcessBo));
}
/**
* 获取当前任务
*
* @param taskId 任务id
*/
@GetMapping("/getTaskById/{taskId}")
public R<TaskVo> getTaskById(@PathVariable String taskId) {
return R.ok(QueryUtils.getTask(taskId));
}
/**
* 修改任务办理人
*
* @param taskIds 任务id
* @param userId 办理人id
*/
@Log(title = "任务管理", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/updateAssignee/{taskIds}/{userId}")
public R<Void> updateAssignee(@PathVariable String[] taskIds, @PathVariable String userId) {
return toAjax(actTaskService.updateAssignee(taskIds, userId));
}
/**
* 查询流程变量
*
* @param taskId 任务id
*/
@GetMapping("/getInstanceVariable/{taskId}")
public R<List<VariableVo>> getProcessInstVariable(@PathVariable String taskId) {
return R.ok(actTaskService.getInstanceVariable(taskId));
}
/**
* 获取可驳回得任务节点
*
* @param processInstanceId 流程实例id
*/
@GetMapping("/getTaskNodeList/{processInstanceId}")
public R<List<WfTaskBackNode>> getNodeList(@PathVariable String processInstanceId) {
return R.ok(CollUtil.reverse(wfTaskBackNodeService.getListByInstanceId(processInstanceId)));
}
/**
* 查询工作流任务用户选择加签人员
*
* @param taskId 任务id
*/
@GetMapping("/getTaskUserIdsByAddMultiInstance/{taskId}")
public R<String> getTaskUserIdsByAddMultiInstance(@PathVariable String taskId) {
return R.ok("操作成功", actTaskService.getTaskUserIdsByAddMultiInstance(taskId));
}
/**
* 查询工作流选择减签人员
*
* @param taskId 任务id
*/
@GetMapping("/getListByDeleteMultiInstance/{taskId}")
public R<List<TaskVo>> getListByDeleteMultiInstance(@PathVariable String taskId) {
return R.ok(actTaskService.getListByDeleteMultiInstance(taskId));
}
}

View File

@@ -0,0 +1,200 @@
package org.dromara.workflow.controller;
import com.warm.flow.core.entity.Definition;
import com.warm.flow.core.service.DefService;
import com.warm.flow.orm.entity.FlowDefinition;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
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.vo.FlowDefinitionVo;
import org.dromara.workflow.service.IFlwDefinitionService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
/**
* 流程定义管理 控制层
*
* @author may
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/workflow/definition")
public class FlwDefinitionController extends BaseController {
private final IFlwDefinitionService iFlwDefinitionService;
private final DefService defService;
/**
* 分页查询
*
* @param flowDefinition 参数
*/
@GetMapping("/list")
public TableDataInfo<FlowDefinitionVo> page(FlowDefinition flowDefinition, PageQuery pageQuery) {
return iFlwDefinitionService.page(flowDefinition, pageQuery);
}
/**
* 获取历史流程定义列表
*
* @param flowCode 参数
*/
@GetMapping("/getHisListByKey/{flowCode}")
public R<List<FlowDefinitionVo>> getHisListByKey(@PathVariable String flowCode) {
return R.ok(iFlwDefinitionService.getHisListByKey(flowCode));
}
/**
* 获取流程定义详细信息
*
* @param id 流程定义id
*/
@GetMapping(value = "/{id}")
public R<Definition> getInfo(@PathVariable Long id) {
return R.ok(defService.getById(id));
}
/**
* 新增流程定义
*
* @param flowDefinition 参数
*/
@Log(title = "流程定义", businessType = BusinessType.INSERT)
@PostMapping
@Transactional(rollbackFor = Exception.class)
public R<Boolean> add(@RequestBody FlowDefinition flowDefinition) {
return R.ok(defService.checkAndSave(flowDefinition));
}
/**
* 修改流程定义
*
* @param flowDefinition 参数
*/
@Log(title = "流程定义", businessType = BusinessType.UPDATE)
@PutMapping
@Transactional(rollbackFor = Exception.class)
public R<Boolean> edit(@RequestBody FlowDefinition flowDefinition) {
return R.ok(defService.updateById(flowDefinition));
}
/**
* 发布流程定义
*
* @param id 流程定义id
*/
@Log(title = "流程定义", businessType = BusinessType.INSERT)
@PutMapping("/publish/{id}")
@Transactional(rollbackFor = Exception.class)
public R<Boolean> publish(@PathVariable Long id) {
return R.ok(defService.publish(id));
}
/**
* 取消发布流程定义
*
* @param id 流程定义id
*/
@Log(title = "流程定义", businessType = BusinessType.INSERT)
@PutMapping("/unPublish/{id}")
@Transactional(rollbackFor = Exception.class)
public R<Boolean> unPublish(@PathVariable Long id) {
return R.ok(defService.unPublish(id));
}
/**
* 删除流程定义
*/
@Log(title = "流程定义", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
@Transactional(rollbackFor = Exception.class)
public R<Boolean> remove(@PathVariable List<Long> ids) {
return R.ok(defService.removeDef(ids));
}
/**
* 复制流程定义
*
* @param id 流程定义id
*/
@Log(title = "流程定义", businessType = BusinessType.INSERT)
@GetMapping("/copyDef/{id}")
@Transactional(rollbackFor = Exception.class)
public R<Boolean> copyDef(@PathVariable Long id) {
return R.ok(defService.copyDef(id));
}
/**
* 导入流程定义
*
* @param file 文件
*/
@Log(title = "流程定义", businessType = BusinessType.IMPORT)
@PostMapping("/importDefinition")
@Transactional(rollbackFor = Exception.class)
public R<Boolean> importDefinition(MultipartFile file) {
return R.ok(iFlwDefinitionService.importXml(file));
}
/**
* 导出流程定义
*
* @param id 流程定义id
* @param response 响应
* @throws IOException 异常
*/
@Log(title = "流程定义", businessType = BusinessType.EXPORT)
@PostMapping("/exportDefinition/{id}")
public void exportDefinition(@PathVariable Long id, HttpServletResponse response) throws IOException {
iFlwDefinitionService.exportDefinition(id, response);
}
/**
* 获取流程定义xml字符串
*
* @param id 流程定义id
*/
@GetMapping("/xmlString/{id}")
public R<String> xmlString(@PathVariable Long id) {
return R.ok(defService.xmlString(id));
}
/**
* 查询流程图
*
* @param instanceId 流程实例id
* @throws IOException 异常
*/
@GetMapping("/flowChart/{instanceId}")
public R<String> flowChart(@PathVariable Long instanceId) throws IOException {
return R.ok(defService.flowChart(instanceId));
}
/**
* 激活/挂起流程定义
*
* @param id 流程定义id
* @param active 激活/挂起
*/
@PutMapping("/updateDefinitionState/{id}/{active}")
public R<Boolean> active(@PathVariable Long id, @PathVariable boolean active) {
if (active) {
return R.ok(defService.unActive(id));
} else {
return R.ok(defService.active(id));
}
}
}

View File

@@ -0,0 +1,97 @@
package org.dromara.workflow.controller;
import com.warm.flow.core.entity.Instance;
import com.warm.flow.core.service.InsService;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
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.vo.FlowInstanceVo;
import org.dromara.workflow.service.IFlwInstanceService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 流程实例管理 控制层
*
* @author may
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/workflow/processInstance")
public class FlwInstanceController extends BaseController {
private final IFlwInstanceService flwInstanceService;
private final InsService insService;
/**
* 分页查询正在运行的流程实例
*
* @param instance 参数
* @param pageQuery 分页
*/
@GetMapping("/getPageByRunning")
public TableDataInfo<FlowInstanceVo> getPageByRunning(Instance instance, PageQuery pageQuery) {
return flwInstanceService.getPageByRunning(instance, pageQuery);
}
/**
* 分页查询已结束的流程实例
*
* @param instance 参数
* @param pageQuery 分页
*/
@GetMapping("/getPageByFinish")
public TableDataInfo<FlowInstanceVo> getPageByFinish(Instance instance, PageQuery pageQuery) {
return flwInstanceService.getPageByFinish(instance, pageQuery);
}
/**
* 按照业务id删除流程实例
*
* @param businessIds 业务id
*/
@DeleteMapping("/deleteByBusinessIds/{businessIds}")
public R<Void> deleteByBusinessIds(@PathVariable List<Long> businessIds) {
return toAjax(flwInstanceService.deleteByBusinessIds(businessIds));
}
/**
* 按照实例id删除流程实例
*
* @param instanceIds 实例id
*/
@DeleteMapping("/deleteByInstanceIds/{instanceIds}")
public R<Void> deleteByInstanceIds(@PathVariable List<Long> instanceIds) {
return toAjax(flwInstanceService.deleteByInstanceIds(instanceIds));
}
/**
* 撤销流程
*
* @param businessId 业务id
*/
@PutMapping("/cancelProcessApply/{businessId}")
public R<Void> cancelProcessApply(@PathVariable String businessId) {
return toAjax(flwInstanceService.cancelProcessApply(businessId));
}
/**
* 激活/挂起流程定义
*
* @param id 流程定义id
* @param active 激活/挂起
*/
@PutMapping("/active/{id}/{active}")
public R<Boolean> active(@PathVariable Long id, @PathVariable boolean active) {
if (active) {
return R.ok(insService.unActive(id));
} else {
return R.ok(insService.active(id));
}
}
}

View File

@@ -0,0 +1,244 @@
package org.dromara.workflow.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.warm.flow.core.dto.FlowParams;
import com.warm.flow.core.dto.ModifyHandler;
import com.warm.flow.core.entity.Instance;
import com.warm.flow.core.entity.Task;
import com.warm.flow.core.enums.CooperateType;
import com.warm.flow.core.enums.FlowStatus;
import com.warm.flow.core.service.InsService;
import com.warm.flow.core.service.TaskService;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
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.workflow.domain.bo.*;
import org.dromara.workflow.domain.vo.FlowHisTaskVo;
import org.dromara.workflow.domain.vo.FlowTaskVo;
import org.dromara.workflow.service.IFlwTaskService;
import org.dromara.workflow.utils.WorkflowUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Collections;
import java.util.Map;
/**
* 任务管理 控制层
*
* @author may
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/workflow/task")
public class FlwTaskController extends BaseController {
private final IFlwTaskService flwTaskService;
private final TaskService taskService;
private final InsService insService;
/**
* 启动任务
*
* @param startProcessBo 启动流程参数
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/startWorkFlow")
public R<Map<String, Object>> startWorkFlow(@Validated(AddGroup.class) @RequestBody StartProcessBo startProcessBo) {
Map<String, Object> map = flwTaskService.startWorkFlow(startProcessBo);
return R.ok("提交成功", map);
}
/**
* 办理任务
*
* @param completeTaskBo 办理任务参数
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/completeTask")
public R<Void> completeTask(@Validated(AddGroup.class) @RequestBody CompleteTaskBo completeTaskBo) {
return toAjax(flwTaskService.completeTask(completeTaskBo));
}
/**
* 查询当前用户的待办任务
*
* @param flowTaskBo 参数
* @param pageQuery 分页
*/
@GetMapping("/getPageByTaskWait")
public TableDataInfo<FlowTaskVo> getPageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
return flwTaskService.getPageByTaskWait(flowTaskBo, pageQuery);
}
/**
* 查询当前用户的已办任务
*
* @param flowTaskBo 参数
* @param pageQuery 分页
*/
@GetMapping("/getPageByTaskFinish")
public TableDataInfo<FlowHisTaskVo> getPageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
return flwTaskService.getPageByTaskFinish(flowTaskBo, pageQuery);
}
/**
* 查询当前用户的抄送
*
* @param flowTaskBo 参数
* @param pageQuery 分页
*/
@GetMapping("/getPageByTaskCopy")
public TableDataInfo<FlowTaskVo> getPageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery) {
return flwTaskService.getPageByTaskCopy(flowTaskBo, pageQuery);
}
/**
* 根据taskId查询代表任务
*
* @param taskId 任务id
*/
@GetMapping("/getTaskById/{taskId}")
public R<FlowTaskVo> getTaskById(@PathVariable Long taskId) {
Task task = taskService.getById(taskId);
if (ObjectUtil.isNotNull(task)) {
FlowTaskVo flowTaskVo = BeanUtil.toBean(task, FlowTaskVo.class);
Instance instance = insService.getById(task.getInstanceId());
flowTaskVo.setFlowStatus(instance.getFlowStatus());
flowTaskVo.setFlowStatusName(FlowStatus.getValueByKey(instance.getFlowStatus()));
return R.ok(flowTaskVo);
}
return R.fail();
}
/**
* 终止任务
*
* @param bo 参数
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/terminationTask")
public R<Instance> terminationTask(@RequestBody TerminationBo bo) {
FlowParams flowParams = new FlowParams();
flowParams.handler(String.valueOf(LoginHelper.getUserId()));
flowParams.message(bo.getComment());
flowParams.permissionFlag(WorkflowUtils.permissionList());
return R.ok(taskService.termination(bo.getTaskId(), flowParams));
}
/**
* 委派任务
*
* @param bo 参数
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/delegateTask")
public R<Void> delegateTask(@Validated({AddGroup.class}) @RequestBody DelegateBo bo) {
return toAjax(taskService.depute(
bo.getTaskId(),
String.valueOf(LoginHelper.getUserId()),
WorkflowUtils.permissionList(),
bo.getUserIds(),
bo.getMessage()));
}
/**
* 转办任务
*
* @param bo 参数
*/
@Log(title = "任务管理", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping("/transferTask")
public R<Void> transferTask(@Validated({AddGroup.class}) @RequestBody TransferBo bo) {
return toAjax(taskService.transfer(
bo.getTaskId(),
String.valueOf(LoginHelper.getUserId()),
WorkflowUtils.permissionList(),
bo.getUserIds(),
bo.getMessage()));
}
/**
* 加签
*
* @param bo 参数
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/addSignature")
public R<Void> addSignature(@Validated({AddGroup.class}) @RequestBody AddSignatureBo bo) {
return toAjax(taskService.addSignature(
bo.getTaskId(),
String.valueOf(LoginHelper.getUserId()),
WorkflowUtils.permissionList(),
bo.getUserIds(),
bo.getMessage()));
}
/**
* 减签
*
* @param bo 参数
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/reductionSignature")
public R<Void> reductionSignature(@Validated({AddGroup.class}) @RequestBody ReductionSignatureBo bo) {
return toAjax(taskService.reductionSignature(
bo.getTaskId(),
String.valueOf(LoginHelper.getUserId()),
WorkflowUtils.permissionList(),
bo.getUserIds(),
bo.getMessage()));
}
/**
* 修改任务办理人
*
* @param taskId 任务id
* @param userId 办理人id
*/
@Log(title = "任务管理", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/updateAssignee/{taskId}/{userId}")
public R<Void> updateAssignee(@PathVariable Long taskId, @PathVariable String userId) {
ModifyHandler modifyHandler = new ModifyHandler()
.setTaskId(taskId)
.setAddHandlers(Collections.singletonList(userId))
.setPermissionFlag(WorkflowUtils.permissionList())
.setCooperateType(CooperateType.APPROVAL.getKey())
.setMessage("修改任务办理人")
.setCurUser(String.valueOf(LoginHelper.getUserId()))
.setIgnore(false);
return toAjax(taskService.updateHandler(modifyHandler));
}
/**
* 驳回审批
*
* @param bo 参数
*/
@Log(title = "任务管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/backProcess")
public R<Void> backProcess(@Validated({AddGroup.class}) @RequestBody BackProcessBo bo) {
return toAjax(flwTaskService.backProcess(bo));
}
}

View File

@@ -1,152 +0,0 @@
package org.dromara.workflow.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 流程实例对象 act_hi_procinst
*
* @author may
* @date 2023-07-22
*/
@Data
@TableName("act_hi_procinst")
public class ActHiProcinst implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
@TableId(value = "ID_")
private String id;
/**
*
*/
@TableField(value = "REV_")
private Long rev;
/**
*
*/
@TableField(value = "PROC_INST_ID_")
private String procInstId;
/**
*
*/
@TableField(value = "BUSINESS_KEY_")
private String businessKey;
/**
*
*/
@TableField(value = "PROC_DEF_ID_")
private String procDefId;
/**
*
*/
@TableField(value = "START_TIME_")
private Date startTime;
/**
*
*/
@TableField(value = "END_TIME_")
private Date endTime;
/**
*
*/
@TableField(value = "DURATION_")
private Long duration;
/**
*
*/
@TableField(value = "START_USER_ID_")
private String startUserId;
/**
*
*/
@TableField(value = "START_ACT_ID_")
private String startActId;
/**
*
*/
@TableField(value = "END_ACT_ID_")
private String endActId;
/**
*
*/
@TableField(value = "SUPER_PROCESS_INSTANCE_ID_")
private String superProcessInstanceId;
/**
*
*/
@TableField(value = "DELETE_REASON_")
private String deleteReason;
/**
*
*/
@TableField(value = "TENANT_ID_")
private String tenantId;
/**
*
*/
@TableField(value = "NAME_")
private String name;
/**
*
*/
@TableField(value = "CALLBACK_ID_")
private String callbackId;
/**
*
*/
@TableField(value = "CALLBACK_TYPE_")
private String callbackType;
/**
*
*/
@TableField(value = "REFERENCE_ID_")
private String referenceId;
/**
*
*/
@TableField(value = "REFERENCE_TYPE_")
private String referenceType;
/**
*
*/
@TableField(value = "PROPAGATED_STAGE_INST_ID_")
private String propagatedStageInstId;
/**
*
*/
@TableField(value = "BUSINESS_STATUS_")
private String businessStatus;
}

View File

@@ -1,193 +0,0 @@
package org.dromara.workflow.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
import java.io.Serial;
/**
* 流程历史任务对象 act_hi_taskinst
*
* @author may
* @date 2024-03-02
*/
@Data
@TableName("act_hi_taskinst")
public class ActHiTaskinst implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
@TableId(value = "ID_")
private String id;
/**
* 版本
*/
@TableField(value = "REV_")
private Long rev;
/**
* 流程定义id
*/
@TableField(value = "PROC_DEF_ID_")
private String procDefId;
/**
*
*/
@TableField(value = "TASK_DEF_ID_")
private String taskDefId;
/**
* 任务节点id
*/
@TableField(value = "TASK_DEF_KEY_")
private String taskDefKey;
/**
* 流程实例id
*/
@TableField(value = "PROC_INST_ID_")
private String procInstId;
/**
* 流程执行id
*/
@TableField(value = "EXECUTION_ID")
private String executionId;
/**
*
*/
@TableField(value = "SCOPE_ID_")
private String scopeId;
/**
*
*/
@TableField(value = "SUB_SCOPE_ID_")
private String subScopeId;
/**
* 先用当前字段标识抄送类型
*/
@TableField(value = "SCOPE_TYPE_")
private String scopeType;
/**
*
*/
@TableField(value = "SCOPE_DEFINITION_ID_")
private String scopeDefinitionId;
/**
*
*/
@TableField(value = "PROPAGATED_STAGE_INST_ID_")
private String propagatedStageInstId;
/**
* 任务名称
*/
@TableField(value = "NAME_")
private String name;
/**
* 父级id
*/
@TableField(value = "PARENT_TASK_ID_")
private String parentTaskId;
/**
* 描述
*/
@TableField(value = "DESCRIPTION_")
private String description;
/**
* 办理人
*/
@TableField(value = "OWNER_")
private String owner;
/**
* 办理人
*/
@TableField(value = "ASSIGNEE_")
private String assignee;
/**
* 开始事件
*/
@TableField(value = "START_TIME_")
private Date startTime;
/**
* 认领时间
*/
@TableField(value = "CLAIM_TIME_")
private Date claimTime;
/**
* 结束时间
*/
@TableField(value = "END_TIME_")
private Date endTime;
/**
* 持续时间
*/
@TableField(value = "DURATION_")
private Long duration;
/**
* 删除原因
*/
@TableField(value = "DELETE_REASON_")
private String deleteReason;
/**
* 优先级
*/
@TableField(value = "PRIORITY_")
private Long priority;
/**
* 到期时间
*/
@TableField(value = "DUE_DATE_")
private Date dueDate;
/**
*
*/
@TableField(value = "FORM_KEY_")
private String formKey;
/**
* 分类
*/
@TableField(value = "CATEGORY_")
private String category;
/**
* 最后修改时间
*/
@TableField(value = "LAST_UPDATED_TIME_")
private Date lastUpdatedTime;
/**
* 租户id
*/
@TableField(value = "TENANT_ID_")
private String tenantId;
}

View File

@@ -45,7 +45,7 @@ public class WfDefinitionConfig extends BaseEntity {
/**
* 流程版本
*/
private Integer version;
private String version;
/**
* 备注

View File

@@ -1,61 +0,0 @@
package org.dromara.workflow.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.tenant.core.TenantEntity;
import java.io.Serial;
/**
* 节点驳回记录 wf_task_back_node
*
* @author may
* @date 2024-03-13
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("wf_task_back_node")
public class WfTaskBackNode extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id")
private Long id;
/**
* 实例id
*/
private String instanceId;
/**
* 节点id
*/
private String nodeId;
/**
* 节点名称
*/
private String nodeName;
/**
* 排序
*/
private Integer orderNo;
/**
* 节点类型
*/
private String taskType;
/**
* 办理人
*/
private String assignee;
}

View File

@@ -0,0 +1,38 @@
package org.dromara.workflow.domain.bo;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.dromara.common.core.validate.AddGroup;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 加签请求对象
*
* @author may
*/
@Data
public class AddSignatureBo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 加签人id
*/
@NotNull(message = "加签id不能为空", groups = {AddGroup.class})
private List<String> userIds;
/**
* 任务id
*/
@NotNull(message = "任务id不能为空", groups = {AddGroup.class})
private Long taskId;
/**
* 意见
*/
private String message;
}

View File

@@ -1,12 +1,16 @@
package org.dromara.workflow.domain.bo;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.dromara.common.core.validate.AddGroup;
import java.io.Serial;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
@@ -23,8 +27,8 @@ public class BackProcessBo implements Serializable {
/**
* 任务ID
*/
@NotBlank(message = "任务ID不能为空", groups = AddGroup.class)
private String taskId;
@NotNull(message = "任务ID不能为空", groups = AddGroup.class)
private Long taskId;
/**
* 消息类型
@@ -35,10 +39,23 @@ public class BackProcessBo implements Serializable {
* 驳回的节点id(目前未使用,直接驳回到申请人)
*/
@NotBlank(message = "驳回的节点不能为空", groups = AddGroup.class)
private String targetActivityId;
private String targetNodeCode;
/**
* 办理意见
*/
private String message;
/**
* 流程变量
*/
private Map<String, Object> variables;
public Map<String, Object> getVariables() {
if (variables == null) {
return new HashMap<>(16);
}
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
return variables;
}
}

View File

@@ -1,6 +1,7 @@
package org.dromara.workflow.domain.bo;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.workflow.domain.vo.WfCopy;
@@ -26,8 +27,8 @@ public class CompleteTaskBo implements Serializable {
/**
* 任务id
*/
@NotBlank(message = "任务id不能为空", groups = {AddGroup.class})
private String taskId;
@NotNull(message = "任务id不能为空", groups = {AddGroup.class})
private Long taskId;
/**
* 附件id

View File

@@ -1,11 +1,12 @@
package org.dromara.workflow.domain.bo;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.dromara.common.core.validate.AddGroup;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 委派任务请求对象
@@ -21,18 +22,17 @@ public class DelegateBo implements Serializable {
/**
* 委派人id
*/
@NotBlank(message = "委派人id不能为空", groups = {AddGroup.class})
private String userId;
/**
* 委派人名称
*/
@NotBlank(message = "委派人名称不能为空", groups = {AddGroup.class})
private String nickName;
@NotNull(message = "委派人id不能为空", groups = {AddGroup.class})
private List<String> userIds;
/**
* 任务id
*/
@NotBlank(message = "任务id不能为空", groups = {AddGroup.class})
private String taskId;
@NotNull(message = "任务id不能为空", groups = {AddGroup.class})
private Long taskId;
/**
* 意见
*/
private String message;
}

View File

@@ -0,0 +1,41 @@
package org.dromara.workflow.domain.bo;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 任务请求对象
*
* @author may
*/
@Data
public class FlowInstanceBo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务名称
*/
private String nodeName;
/**
* 流程定义名称
*/
private String flowName;
/**
* 流程定义编码
*/
private String flowCode;
/**
* 流程实例id
*/
private Long instanceId;
private List<String> permissionList;
}

View File

@@ -0,0 +1,42 @@
package org.dromara.workflow.domain.bo;
import jakarta.validation.constraints.Future;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 任务请求对象
*
* @author may
*/
@Data
public class FlowTaskBo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务名称
*/
private String nodeName;
/**
* 流程定义名称
*/
private String flowName;
/**
* 流程定义编码
*/
private String flowCode;
/**
* 流程实例id
*/
private Long instanceId;
private List<String> permissionList;
}

View File

@@ -11,7 +11,7 @@ import java.io.Serializable;
* @author may
*/
@Data
public class ProcessInstanceBo implements Serializable {
public class InstanceBo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;

View File

@@ -0,0 +1,38 @@
package org.dromara.workflow.domain.bo;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.dromara.common.core.validate.AddGroup;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 减签请求对象
*
* @author may
*/
@Data
public class ReductionSignatureBo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 减签人id
*/
@NotNull(message = "减签id不能为空", groups = {AddGroup.class})
private List<String> userIds;
/**
* 任务id
*/
@NotNull(message = "任务id不能为空", groups = {AddGroup.class})
private Long taskId;
/**
* 意见
*/
private String message;
}

View File

@@ -1,6 +1,6 @@
package org.dromara.workflow.domain.bo;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.dromara.common.core.validate.AddGroup;
@@ -21,8 +21,8 @@ public class TerminationBo implements Serializable {
/**
* 任务id
*/
@NotBlank(message = "任务id为空", groups = AddGroup.class)
private String taskId;
@NotNull(message = "任务id为空", groups = AddGroup.class)
private Long taskId;
/**
* 审批意见

View File

@@ -1,11 +1,12 @@
package org.dromara.workflow.domain.bo;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.dromara.common.core.validate.AddGroup;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 终转办务请求对象
@@ -13,25 +14,25 @@ import java.io.Serializable;
* @author may
*/
@Data
public class TransmitBo implements Serializable {
public class TransferBo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务id
*/
@NotBlank(message = "任务id为空", groups = AddGroup.class)
private String taskId;
/**
* 转办人id
*/
@NotBlank(message = "转办人不能为空", groups = AddGroup.class)
private String userId;
@NotNull(message = "转办人id不能为空", groups = {AddGroup.class})
private List<String> userIds;
/**
* 审批意见
* 任务id
*/
private String comment;
@NotNull(message = "任务id不能为空", groups = {AddGroup.class})
private Long taskId;
/**
* 意见
*/
private String message;
}

View File

@@ -47,8 +47,8 @@ public class WfDefinitionConfigBo extends BaseEntity {
/**
* 流程版本
*/
@NotNull(message = "流程版本不能为空", groups = {AddGroup.class})
private Integer version;
@NotBlank(message = "流程版本不能为空", groups = {AddGroup.class})
private String version;
/**
* 备注

View File

@@ -3,7 +3,6 @@ package org.dromara.workflow.domain.vo;
import lombok.Data;
import org.dromara.common.translation.annotation.Translation;
import org.dromara.common.translation.constant.TransConstant;
import org.flowable.engine.task.Attachment;
import java.io.Serial;
import java.io.Serializable;
@@ -85,9 +84,4 @@ public class ActHistoryInfoVo implements Serializable {
* 审批信息
*/
private String comment;
/**
* 审批附件
*/
private List<Attachment> attachmentList;
}

View File

@@ -0,0 +1,6 @@
package org.dromara.workflow.domain.vo;
import com.warm.flow.orm.entity.FlowDefinition;
public class FlowDefinitionVo extends FlowDefinition {
}

View File

@@ -0,0 +1,161 @@
package org.dromara.workflow.domain.vo;
import lombok.Data;
import org.dromara.common.translation.annotation.Translation;
import org.dromara.common.translation.constant.TransConstant;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* 历史任务视图
*
* @author may
*/
@Data
public class FlowHisTaskVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private Long id;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
/**
* 租户ID
*/
private String tenantId;
/**
* 删除标记
*/
private String delFlag;
/**
* 对应flow_definition表的id
*/
private Long definitionId;
/**
* 流程名称
*/
private String flowName;
/**
* 流程实例表id
*/
private Long instanceId;
/**
* 任务表id
*/
private Long taskId;
/**
* 协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签)
*/
private Integer cooperateType;
/**
* 业务id
*/
private String businessId;
/**
* 开始节点编码
*/
private String nodeCode;
/**
* 开始节点名称
*/
private String nodeName;
/**
* 开始节点类型0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关
*/
private Integer nodeType;
/**
* 目标节点编码
*/
private String targetNodeCode;
/**
* 结束节点名称
*/
private String targetNodeName;
/**
* 审批者
*/
private String approver;
/**
* 协作人(只有转办、会签、票签、委派)
*/
private String collaborator;
/**
* 权限标识 permissionFlag的list形式
*/
private List<String> permissionList;
/**
* 跳转类型PASS通过 REJECT退回 NONE无动作
*/
private String skipType;
/**
* 流程状态1审批中 2 审批通过 9已退回 10失效
*/
private Integer flowStatus;
/**
* 审批意见
*/
private String message;
/**
* 业务详情 存业务类的json
*/
private String ext;
/**
* 创建者
*/
private String createBy;
/**
* 审批表单是否自定义Y是 2否
*/
private String formCustom;
/**
* 审批表单路径
*/
private String formPath;
/**
* 流程定义编码
*/
private String flowCode;
/**
* 审批者
*/
@Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "approver")
private String approverName;
}

View File

@@ -0,0 +1,111 @@
package org.dromara.workflow.domain.vo;
import lombok.Data;
import java.util.Date;
/**
* 流程实例视图
*
* @author may
*/
@Data
public class FlowInstanceVo {
private Long id;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
/**
* 租户ID
*/
private String tenantId;
/**
* 删除标记
*/
private String delFlag;
/**
* 对应flow_definition表的id
*/
private Long definitionId;
/**
* 流程名称
*/
private String flowName;
/**
* 流程名称
*/
private String flowCode;
/**
* 业务id
*/
private String businessId;
/**
* 节点类型0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关
*/
private Integer nodeType;
/**
* 流程节点编码 每个流程的nodeCode是唯一的,即definitionId+nodeCode唯一,在数据库层面做了控制
*/
private String nodeCode;
/**
* 流程节点名称
*/
private String nodeName;
/**
* 流程变量
*/
private String variable;
/**
* 流程状态0待提交 1审批中 2 审批通过 3自动通过 8已完成 9已退回 10失效
*/
private Integer flowStatus;
/**
* 流程激活状态0挂起 1激活
*/
private Integer activityStatus;
/**
* 创建者
*/
private String createBy;
/**
* 审批表单是否自定义Y是 2否
*/
private String formCustom;
/**
* 审批表单是否自定义Y是 2否
*/
private String formPath;
/**
* 扩展字段,预留给业务系统使用
*/
private String ext;
/**
* 流程定义版本
*/
private String version;
}

View File

@@ -0,0 +1,124 @@
package org.dromara.workflow.domain.vo;
import com.warm.flow.core.entity.User;
import lombok.Data;
import org.dromara.common.core.domain.dto.UserDTO;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* 任务视图
*
* @author may
*/
@Data
public class FlowTaskVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private Long id;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
/**
* 租户ID
*/
private String tenantId;
/**
* 删除标记
*/
private String delFlag;
/**
* 对应flow_definition表的id
*/
private Long definitionId;
/**
* 流程实例表id
*/
private Long instanceId;
/**
* 流程名称
*/
private String flowName;
/**
* 业务id
*/
private String businessId;
/**
* 节点编码
*/
private String nodeCode;
/**
* 节点名称
*/
private String nodeName;
/**
* 节点类型0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关
*/
private Integer nodeType;
/**
* 权限标识 permissionFlag的list形式
*/
private List<String> permissionList;
/**
* 流程用户列表
*/
private List<User> userList;
/**
* 审批表单是否自定义Y是 2否
*/
private String formCustom;
/**
* 审批表单
*/
private String formPath;
/**
* 流程定义编码
*/
private String flowCode;
/**
* 流程版本号
*/
private String version;
/**
* 流程状态
*/
private Integer flowStatus;
/**
* 流程状态
*/
private String flowStatusName;
/**
* 办理人
*/
private List<UserDTO> userDTOList;
}

View File

@@ -53,7 +53,7 @@ public class WfDefinitionConfigVo implements Serializable {
* 流程版本
*/
@ExcelProperty(value = "流程版本")
private Integer version;
private String version;
/**
* 备注

View File

@@ -1,108 +0,0 @@
package org.dromara.workflow.flowable;
import org.flowable.bpmn.model.AssociationDirection;
import org.flowable.image.impl.DefaultProcessDiagramCanvas;
import java.awt.*;
import java.awt.geom.Line2D;
import java.awt.geom.RoundRectangle2D;
public class CustomDefaultProcessDiagramCanvas extends DefaultProcessDiagramCanvas {
//设置高亮线的颜色 这里我设置成绿色
protected static Color HIGHLIGHT_SEQUENCEFLOW_COLOR = Color.GREEN;
public CustomDefaultProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
super(width, height, minX, minY, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
}
/**
* 画线颜色设置
*/
public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, String connectionType,
AssociationDirection associationDirection, boolean highLighted, double scaleFactor) {
Paint originalPaint = g.getPaint();
Stroke originalStroke = g.getStroke();
g.setPaint(CONNECTION_COLOR);
if (connectionType.equals("association")) {
g.setStroke(ASSOCIATION_STROKE);
} else if (highLighted) {
//设置线的颜色
g.setPaint(HIGHLIGHT_SEQUENCEFLOW_COLOR);
g.setStroke(HIGHLIGHT_FLOW_STROKE);
}
for (int i = 1; i < xPoints.length; i++) {
Integer sourceX = xPoints[i - 1];
Integer sourceY = yPoints[i - 1];
Integer targetX = xPoints[i];
Integer targetY = yPoints[i];
Line2D.Double line = new Line2D.Double(sourceX, sourceY, targetX, targetY);
g.draw(line);
}
if (isDefault) {
Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
drawDefaultSequenceFlowIndicator(line, scaleFactor);
}
if (conditional) {
Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
drawConditionalSequenceFlowIndicator(line, scaleFactor);
}
if (associationDirection == AssociationDirection.ONE || associationDirection == AssociationDirection.BOTH) {
Line2D.Double line = new Line2D.Double(xPoints[xPoints.length - 2], yPoints[xPoints.length - 2], xPoints[xPoints.length - 1], yPoints[xPoints.length - 1]);
drawArrowHead(line, scaleFactor);
}
if (associationDirection == AssociationDirection.BOTH) {
Line2D.Double line = new Line2D.Double(xPoints[1], yPoints[1], xPoints[0], yPoints[0]);
drawArrowHead(line, scaleFactor);
}
g.setPaint(originalPaint);
g.setStroke(originalStroke);
}
/**
* 高亮节点设置
*/
public void drawHighLight(int x, int y, int width, int height) {
Paint originalPaint = g.getPaint();
Stroke originalStroke = g.getStroke();
//设置高亮节点的颜色
g.setPaint(HIGHLIGHT_COLOR);
g.setStroke(THICK_TASK_BORDER_STROKE);
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
g.draw(rect);
g.setPaint(originalPaint);
g.setStroke(originalStroke);
}
/**
* @description: 高亮节点红色
* @param: x
* @param: y
* @param: width
* @param: height
* @return: void
* @author: gssong
* @date: 2022/4/12
*/
public void drawHighLightRed(int x, int y, int width, int height) {
Paint originalPaint = g.getPaint();
Stroke originalStroke = g.getStroke();
//设置高亮节点的颜色
g.setPaint(Color.green);
g.setStroke(THICK_TASK_BORDER_STROKE);
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
g.draw(rect);
g.setPaint(originalPaint);
g.setStroke(originalStroke);
}
}

View File

@@ -1,61 +0,0 @@
package org.dromara.workflow.flowable.cmd;
import cn.hutool.core.collection.CollUtil;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
import org.flowable.engine.impl.util.CommandContextUtil;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.dromara.workflow.common.constant.FlowConstant.NUMBER_OF_INSTANCES;
/**
* 串行加签
*
* @author may
*/
public class AddSequenceMultiInstanceCmd implements Command<Void> {
/**
* 执行id
*/
private final String executionId;
/**
* 会签人员集合KEY
*/
private final String assigneeList;
/**
* 加签人员
*/
private final List<Long> assignees;
public AddSequenceMultiInstanceCmd(String executionId, String assigneeList, List<Long> assignees) {
this.executionId = executionId;
this.assigneeList = assigneeList;
this.assignees = assignees;
}
@Override
public Void execute(CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager();
ExecutionEntity entity = executionEntityManager.findById(executionId);
// 多实例任务总数加 assignees.size()
if (entity.getVariable(NUMBER_OF_INSTANCES) instanceof Integer nrOfInstances) {
entity.setVariable(NUMBER_OF_INSTANCES, nrOfInstances + assignees.size());
}
// 设置流程变量
if (entity.getVariable(assigneeList) instanceof List<?> userIds) {
CollUtil.addAll(userIds, assignees);
Map<String, Object> variables = new HashMap<>(16);
variables.put(assigneeList, userIds);
entity.setVariables(variables);
}
return null;
}
}

View File

@@ -1,66 +0,0 @@
package org.dromara.workflow.flowable.cmd;
import cn.hutool.core.collection.CollUtil;
import org.dromara.common.core.domain.dto.OssDTO;
import org.dromara.common.core.service.OssService;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.impl.persistence.entity.AttachmentEntity;
import org.flowable.engine.impl.persistence.entity.AttachmentEntityManager;
import org.flowable.engine.impl.util.CommandContextUtil;
import java.util.Date;
import java.util.List;
/**
* 附件上传
*
* @author may
*/
public class AttachmentCmd implements Command<Boolean> {
private final String fileId;
private final String taskId;
private final String processInstanceId;
private final OssService ossService;
public AttachmentCmd(String fileId, String taskId, String processInstanceId, OssService ossService) {
this.fileId = fileId;
this.taskId = taskId;
this.processInstanceId = processInstanceId;
this.ossService = ossService;
}
@Override
public Boolean execute(CommandContext commandContext) {
try {
if (StringUtils.isNotBlank(fileId)) {
List<OssDTO> ossList = ossService.selectByIds(fileId);
if (CollUtil.isNotEmpty(ossList)) {
for (OssDTO oss : ossList) {
AttachmentEntityManager attachmentEntityManager = CommandContextUtil.getAttachmentEntityManager();
AttachmentEntity attachmentEntity = attachmentEntityManager.create();
attachmentEntity.setRevision(1);
attachmentEntity.setUserId(LoginHelper.getUserId().toString());
attachmentEntity.setName(oss.getOriginalName());
attachmentEntity.setDescription(oss.getOriginalName());
attachmentEntity.setType(oss.getFileSuffix());
attachmentEntity.setTaskId(taskId);
attachmentEntity.setProcessInstanceId(processInstanceId);
attachmentEntity.setContentId(oss.getOssId().toString());
attachmentEntity.setTime(new Date());
attachmentEntityManager.insert(attachmentEntity);
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return true;
}
}

View File

@@ -1,36 +0,0 @@
package org.dromara.workflow.flowable.cmd;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
import org.flowable.engine.impl.util.CommandContextUtil;
import java.io.Serializable;
/**
* 删除执行数据
*
* @author may
*/
public class DeleteExecutionCmd implements Command<Void>, Serializable {
/**
* 执行id
*/
private final String executionId;
public DeleteExecutionCmd(String executionId) {
this.executionId = executionId;
}
@Override
public Void execute(CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager();
ExecutionEntity entity = executionEntityManager.findById(executionId);
if (entity != null) {
executionEntityManager.deleteExecutionAndRelatedData(entity, "", false, false);
}
return null;
}
}

View File

@@ -1,83 +0,0 @@
package org.dromara.workflow.flowable.cmd;
import cn.hutool.core.util.ObjectUtil;
import lombok.AllArgsConstructor;
import org.dromara.common.core.utils.StreamUtils;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
import org.flowable.engine.impl.util.CommandContextUtil;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.dromara.workflow.common.constant.FlowConstant.LOOP_COUNTER;
import static org.dromara.workflow.common.constant.FlowConstant.NUMBER_OF_INSTANCES;
/**
* 串行减签
*
* @author may
*/
@AllArgsConstructor
public class DeleteSequenceMultiInstanceCmd implements Command<Void> {
/**
* 当前节点审批人员id
*/
private final String currentUserId;
/**
* 执行id
*/
private final String executionId;
/**
* 会签人员集合KEY
*/
private final String assigneeList;
/**
* 减签人员
*/
private final List<Long> assignees;
@Override
@SuppressWarnings("unchecked")
public Void execute(CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager();
ExecutionEntity entity = executionEntityManager.findById(executionId);
// 设置流程变量
List<Long> userIds = new ArrayList<>();
List<Object> variable = (List<Object>) entity.getVariable(assigneeList);
for (Object o : variable) {
userIds.add(Long.valueOf(o.toString()));
}
List<Long> userIdList = new ArrayList<>();
userIds.forEach(e -> {
Long userId = StreamUtils.findFirst(assignees, id -> ObjectUtil.equals(id, e));
if (userId == null) {
userIdList.add(e);
}
});
// 当前任务执行位置
int loopCounterIndex = -1;
for (int i = 0; i < userIdList.size(); i++) {
Long userId = userIdList.get(i);
if (currentUserId.equals(userId.toString())) {
loopCounterIndex = i;
}
}
Map<String, Object> variables = new HashMap<>(16);
variables.put(NUMBER_OF_INSTANCES, userIdList.size());
variables.put(assigneeList, userIdList);
variables.put(LOOP_COUNTER, loopCounterIndex);
entity.setVariables(variables);
return null;
}
}

View File

@@ -1,39 +0,0 @@
package org.dromara.workflow.flowable.cmd;
import org.dromara.common.core.utils.StreamUtils;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
import org.flowable.engine.impl.util.CommandContextUtil;
import java.io.Serializable;
import java.util.List;
/**
* 获取并行网关执行后保留的执行实例数据
*
* @author may
*/
public class ExecutionChildByExecutionIdCmd implements Command<List<ExecutionEntity>>, Serializable {
/**
* 当前任务执行实例id
*/
private final String executionId;
public ExecutionChildByExecutionIdCmd(String executionId) {
this.executionId = executionId;
}
@Override
public List<ExecutionEntity> execute(CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager();
// 获取当前执行数据
ExecutionEntity executionEntity = executionEntityManager.findById(executionId);
// 通过当前执行数据的父执行,查询所有子执行数据
List<ExecutionEntity> allChildrenExecution =
executionEntityManager.collectChildren(executionEntity.getParent());
return StreamUtils.filter(allChildrenExecution, e -> !e.isActive());
}
}

View File

@@ -1,37 +0,0 @@
package org.dromara.workflow.flowable.cmd;
import org.dromara.common.core.exception.ServiceException;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.impl.persistence.entity.HistoricProcessInstanceEntity;
import org.flowable.engine.impl.persistence.entity.HistoricProcessInstanceEntityManager;
import org.flowable.engine.impl.util.CommandContextUtil;
/**
* 修改流程状态
*
* @author may
*/
public class UpdateBusinessStatusCmd implements Command<Boolean> {
private final String processInstanceId;
private final String status;
public UpdateBusinessStatusCmd(String processInstanceId, String status) {
this.processInstanceId = processInstanceId;
this.status = status;
}
@Override
public Boolean execute(CommandContext commandContext) {
try {
HistoricProcessInstanceEntityManager manager = CommandContextUtil.getHistoricProcessInstanceEntityManager();
HistoricProcessInstanceEntity processInstance = manager.findById(processInstanceId);
processInstance.setBusinessStatus(status);
manager.update(processInstance);
return true;
} catch (Exception e) {
throw new ServiceException(e.getMessage());
}
}
}

View File

@@ -1,51 +0,0 @@
package org.dromara.workflow.flowable.cmd;
import org.dromara.common.core.exception.ServiceException;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.task.service.HistoricTaskService;
import org.flowable.task.service.impl.persistence.entity.HistoricTaskInstanceEntity;
import java.util.Date;
import java.util.List;
/**
* 修改流程历史
*
* @author may
*/
public class UpdateHiTaskInstCmd implements Command<Boolean> {
private final List<String> taskIds;
private final String processDefinitionId;
private final String processInstanceId;
public UpdateHiTaskInstCmd(List<String> taskIds, String processDefinitionId, String processInstanceId) {
this.taskIds = taskIds;
this.processDefinitionId = processDefinitionId;
this.processInstanceId = processInstanceId;
}
@Override
public Boolean execute(CommandContext commandContext) {
try {
HistoricTaskService historicTaskService = CommandContextUtil.getHistoricTaskService();
for (String taskId : taskIds) {
HistoricTaskInstanceEntity historicTask = historicTaskService.getHistoricTask(taskId);
if (historicTask != null) {
historicTask.setProcessDefinitionId(processDefinitionId);
historicTask.setProcessInstanceId(processInstanceId);
historicTask.setCreateTime(new Date());
CommandContextUtil.getHistoricTaskService().updateHistoricTask(historicTask, true);
}
}
return true;
} catch (Exception e) {
throw new ServiceException(e.getMessage());
}
}
}

View File

@@ -1,32 +0,0 @@
package org.dromara.workflow.flowable.config;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import org.dromara.workflow.flowable.handler.TaskTimeoutJobHandler;
import org.flowable.spring.SpringProcessEngineConfiguration;
import org.flowable.spring.boot.EngineConfigurationConfigurer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import java.util.Collections;
/**
* flowable配置
*
* @author may
*/
@Configuration
public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {
@Autowired
private GlobalFlowableListener globalFlowableListener;
@Autowired
private IdentifierGenerator identifierGenerator;
@Override
public void configure(SpringProcessEngineConfiguration processEngineConfiguration) {
processEngineConfiguration.setIdGenerator(() -> identifierGenerator.nextId(null).toString());
processEngineConfiguration.setEventListeners(Collections.singletonList(globalFlowableListener));
processEngineConfiguration.addCustomJobHandler(new TaskTimeoutJobHandler());
}
}

View File

@@ -1,139 +0,0 @@
package org.dromara.workflow.flowable.config;
import cn.hutool.core.collection.CollUtil;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.workflow.common.enums.TaskStatusEnum;
import org.dromara.workflow.flowable.handler.TaskTimeoutJobHandler;
import org.dromara.workflow.utils.QueryUtils;
import org.flowable.bpmn.model.BoundaryEvent;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.common.engine.api.delegate.event.*;
import org.flowable.common.engine.impl.cfg.TransactionState;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.task.Comment;
import org.flowable.job.service.TimerJobService;
import org.flowable.job.service.impl.persistence.entity.JobEntity;
import org.flowable.job.service.impl.persistence.entity.TimerJobEntity;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
/**
* 引擎调度监听
*
* @author may
*/
@Component
public class GlobalFlowableListener implements FlowableEventListener {
@Autowired
@Lazy
private TaskService taskService;
@Autowired
@Lazy
private RuntimeService runtimeService;
@Autowired
@Lazy
private RepositoryService repositoryService;
@Value("${flowable.async-executor-activate}")
private boolean asyncExecutorActivate;
@Override
public void onEvent(FlowableEvent flowableEvent) {
if (flowableEvent instanceof FlowableEngineEvent flowableEngineEvent) {
FlowableEngineEventType engineEventType = (FlowableEngineEventType) flowableEvent.getType();
switch (engineEventType) {
case JOB_EXECUTION_SUCCESS -> jobExecutionSuccess((FlowableEngineEntityEvent) flowableEngineEvent);
case TASK_DUEDATE_CHANGED, TASK_CREATED -> {
FlowableEntityEvent flowableEntityEvent = (FlowableEntityEvent) flowableEngineEvent;
Object entityObject = flowableEntityEvent.getEntity();
TaskEntity task = (TaskEntity) entityObject;
if (asyncExecutorActivate && task.getDueDate() != null && task.getDueDate().after(new Date())) {
//删除之前已经存在的定时任务
TimerJobService timerJobService = CommandContextUtil.getTimerJobService();
List<TimerJobEntity> timerJobEntityList = timerJobService.findTimerJobsByProcessInstanceId(task.getProcessInstanceId());
if (!CollUtil.isEmpty(timerJobEntityList)) {
for (TimerJobEntity timerJobEntity : timerJobEntityList) {
String taskId = timerJobEntity.getJobHandlerConfiguration();
if (task.getId().equals(taskId)) {
timerJobService.deleteTimerJob(timerJobEntity);
}
}
}
//创建job对象
TimerJobEntity timer = timerJobService.createTimerJob();
timer.setTenantId(TenantHelper.getTenantId());
//设置job类型
timer.setJobType(JobEntity.JOB_TYPE_TIMER);
timer.setJobHandlerType(TaskTimeoutJobHandler.TYPE);
timer.setDuedate(task.getDueDate());
timer.setProcessInstanceId(task.getProcessInstanceId());
//设置任务id
timer.setJobHandlerConfiguration(task.getId());
//保存并触发事件
timerJobService.scheduleTimerJob(timer);
}
}
}
}
}
@Override
public boolean isFailOnException() {
return true;
}
@Override
public boolean isFireOnTransactionLifecycleEvent() {
return false;
}
@Override
public String getOnTransaction() {
return TransactionState.COMMITTED.name();
}
/**
* 处理边界定时事件自动审批记录
*
* @param event 事件
*/
protected void jobExecutionSuccess(FlowableEngineEntityEvent event) {
if (event != null && StringUtils.isNotBlank(event.getExecutionId())) {
Execution execution = runtimeService.createExecutionQuery().executionId(event.getExecutionId()).singleResult();
if (execution != null) {
BpmnModel bpmnModel = repositoryService.getBpmnModel(event.getProcessDefinitionId());
FlowElement flowElement = bpmnModel.getFlowElement(execution.getActivityId());
if (flowElement instanceof BoundaryEvent) {
String attachedToRefId = ((BoundaryEvent) flowElement).getAttachedToRefId();
List<Execution> list = runtimeService.createExecutionQuery().activityId(attachedToRefId).list();
for (Execution ex : list) {
Task task = QueryUtils.taskQuery().executionId(ex.getId()).singleResult();
if (task != null) {
List<Comment> taskComments = taskService.getTaskComments(task.getId());
if (CollUtil.isEmpty(taskComments)) {
taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), "超时自动审批!");
}
}
}
}
}
}
}
}

View File

@@ -1,50 +0,0 @@
package org.dromara.workflow.flowable.handler;
import org.dromara.common.core.domain.event.ProcessEvent;
import org.dromara.common.core.domain.event.ProcessTaskEvent;
import org.dromara.common.core.utils.SpringUtils;
import org.springframework.stereotype.Component;
/**
* 流程监听服务
*
* @author may
* @date 2024-06-02
*/
@Component
public class FlowProcessEventHandler {
/**
* 总体流程监听(例如: 提交 退回 撤销 终止 作废等)
*
* @param key 流程key
* @param businessKey 业务id
* @param status 状态
* @param submit 当为true时为申请人节点办理
*/
public void processHandler(String key, String businessKey, String status, boolean submit) {
ProcessEvent processEvent = new ProcessEvent();
processEvent.setKey(key);
processEvent.setBusinessKey(businessKey);
processEvent.setStatus(status);
processEvent.setSubmit(submit);
SpringUtils.context().publishEvent(processEvent);
}
/**
* 执行办理任务监听
*
* @param key 流程key
* @param taskDefinitionKey 审批节点key
* @param taskId 任务id
* @param businessKey 业务id
*/
public void processTaskHandler(String key, String taskDefinitionKey, String taskId, String businessKey) {
ProcessTaskEvent processTaskEvent = new ProcessTaskEvent();
processTaskEvent.setKey(key);
processTaskEvent.setTaskDefinitionKey(taskDefinitionKey);
processTaskEvent.setTaskId(taskId);
processTaskEvent.setBusinessKey(businessKey);
SpringUtils.context().publishEvent(processTaskEvent);
}
}

View File

@@ -1,37 +0,0 @@
package org.dromara.workflow.flowable.handler;
import org.dromara.workflow.common.enums.TaskStatusEnum;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.jobexecutor.TimerEventHandler;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.job.service.JobHandler;
import org.flowable.job.service.impl.persistence.entity.JobEntity;
import org.flowable.task.api.Task;
import org.flowable.variable.api.delegate.VariableScope;
/**
* 办理超时(过期)任务
*
* @author may
*/
public class TaskTimeoutJobHandler extends TimerEventHandler implements JobHandler {
public static final String TYPE = "taskTimeout";
@Override
public String getType() {
return TYPE;
}
@Override
public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) {
TaskService taskService = CommandContextUtil.getProcessEngineConfiguration(commandContext)
.getTaskService();
Task task = taskService.createTaskQuery().taskId(configuration).singleResult();
if (task != null) {
taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.TIMEOUT.getStatus(), "超时自动审批!");
taskService.complete(configuration);
}
}
}

View File

@@ -1,16 +0,0 @@
package org.dromara.workflow.mapper;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.workflow.domain.ActHiProcinst;
/**
* 流程实例Mapper接口
*
* @author may
* @date 2023-07-22
*/
@InterceptorIgnore(tenantLine = "true")
public interface ActHiProcinstMapper extends BaseMapperPlus<ActHiProcinst, ActHiProcinst> {
}

View File

@@ -1,16 +0,0 @@
package org.dromara.workflow.mapper;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import org.dromara.workflow.domain.ActHiTaskinst;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 流程历史任务Mapper接口
*
* @author may
* @date 2024-03-02
*/
@InterceptorIgnore(tenantLine = "true")
public interface ActHiTaskinstMapper extends BaseMapperPlus<ActHiTaskinst, ActHiTaskinst> {
}

View File

@@ -1,47 +0,0 @@
package org.dromara.workflow.mapper;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.workflow.domain.vo.TaskVo;
/**
* 任务信息Mapper接口
*
* @author may
* @date 2024-03-02
*/
@InterceptorIgnore(tenantLine = "true")
public interface ActTaskMapper extends BaseMapperPlus<TaskVo, TaskVo> {
/**
* 获取待办信息
*
* @param page 分页
* @param queryWrapper 条件
* @return 结果
*/
Page<TaskVo> getTaskWaitByPage(@Param("page") Page<TaskVo> page, @Param(Constants.WRAPPER) Wrapper<TaskVo> queryWrapper);
/**
* 获取已办
*
* @param page 分页
* @param queryWrapper 条件
* @return 结果
*/
Page<TaskVo> getTaskFinishByPage(@Param("page") Page<TaskVo> page, @Param(Constants.WRAPPER) Wrapper<TaskVo> queryWrapper);
/**
* 查询当前用户的抄送
*
* @param page 分页
* @param queryWrapper 条件
* @return 结果
*/
Page<TaskVo> getTaskCopyByPage(@Param("page") Page<TaskVo> page, @Param(Constants.WRAPPER) QueryWrapper<TaskVo> queryWrapper);
}

View File

@@ -0,0 +1,27 @@
package org.dromara.workflow.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.dromara.workflow.domain.bo.FlowInstanceBo;
import org.dromara.workflow.domain.vo.FlowInstanceVo;
/**
* 实例信息Mapper接口
*
* @author may
* @date 2024-03-02
*/
public interface FlwInstanceMapper {
/**
* 流程实例信息
*
* @param page 分页
* @param queryWrapper 条件
* @return 结果
*/
Page<FlowInstanceVo> page(@Param("page") Page<FlowInstanceVo> page,
@Param(Constants.WRAPPER) Wrapper<FlowInstanceBo> queryWrapper);
}

View File

@@ -0,0 +1,51 @@
package org.dromara.workflow.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.dromara.workflow.domain.bo.FlowTaskBo;
import org.dromara.workflow.domain.vo.FlowHisTaskVo;
import org.dromara.workflow.domain.vo.FlowTaskVo;
/**
* 任务信息Mapper接口
*
* @author may
* @date 2024-03-02
*/
public interface FlwTaskMapper {
/**
* 获取待办信息
*
* @param page 分页
* @param queryWrapper 条件
* @return 结果
*/
Page<FlowTaskVo> getTaskWaitByPage(@Param("page") Page<FlowTaskVo> page,
@Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper);
/**
* 获取已办
*
* @param page 分页
* @param queryWrapper 条件
* @param flowTaskBo 条件
* @return 结果
*/
Page<FlowHisTaskVo> getTaskFinishByPage(@Param("page") Page<FlowTaskVo> page,
@Param(Constants.WRAPPER) Wrapper<FlowTaskBo> queryWrapper,
@Param("flowTaskBo") FlowTaskBo flowTaskBo);
/**
* 查询当前用户的抄送
*
* @param page 分页
* @param queryWrapper 条件
* @return 结果
*/
Page<FlowTaskVo> getTaskCopyByPage(@Param("page") Page<FlowTaskVo> page,
@Param(Constants.WRAPPER) QueryWrapper<FlowTaskBo> queryWrapper);
}

View File

@@ -1,13 +0,0 @@
package org.dromara.workflow.mapper;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.workflow.domain.WfTaskBackNode;
/**
* 节点驳回记录Mapper接口
*
* @author may
* @date 2024-03-13
*/
public interface WfTaskBackNodeMapper extends BaseMapperPlus<WfTaskBackNode, WfTaskBackNode> {
}

View File

@@ -1,31 +0,0 @@
package org.dromara.workflow.service;
import org.dromara.workflow.domain.ActHiProcinst;
import java.util.List;
/**
* 流程实例Service接口
*
* @author may
* @date 2023-07-22
*/
public interface IActHiProcinstService {
/**
* 按照业务id查询
*
* @param businessKeys 业务id
* @return 结果
*/
List<ActHiProcinst> selectByBusinessKeyIn(List<String> businessKeys);
/**
* 按照业务id查询
*
* @param businessKey 业务id
* @return 结果
*/
ActHiProcinst selectByBusinessKey(String businessKey);
}

View File

@@ -1,11 +0,0 @@
package org.dromara.workflow.service;
/**
* 流程历史任务Service接口
*
* @author may
* @date 2024-03-02
*/
public interface IActHiTaskinstService {
}

View File

@@ -1,83 +0,0 @@
package org.dromara.workflow.service;
import jakarta.servlet.http.HttpServletResponse;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.workflow.domain.bo.ModelBo;
import org.dromara.workflow.domain.vo.ModelVo;
import org.flowable.engine.repository.Model;
import java.util.List;
/**
* 模型管理 服务层
*
* @author may
*/
public interface IActModelService {
/**
* 分页查询模型
*
* @param modelBo 模型参数
* @param pageQuery 参数
* @return 返回分页列表
*/
TableDataInfo<Model> page(ModelBo modelBo, PageQuery pageQuery);
/**
* 新增模型
*
* @param modelBo 模型请求对象
* @return 结果
*/
boolean saveNewModel(ModelBo modelBo);
/**
* 查询模型
*
* @param modelId 模型id
* @return 模型数据
*/
ModelVo getInfo(String modelId);
/**
* 修改模型信息
*
* @param modelBo 模型数据
* @return 结果
*/
boolean update(ModelBo modelBo);
/**
* 编辑模型XML
*
* @param modelBo 模型数据
* @return 结果
*/
boolean editModelXml(ModelBo modelBo);
/**
* 模型部署
*
* @param id 模型id
* @return 结果
*/
boolean modelDeploy(String id);
/**
* 导出模型zip压缩包
*
* @param modelIds 模型id
* @param response 响应
*/
void exportZip(List<String> modelIds, HttpServletResponse response);
/**
* 复制模型
*
* @param modelBo 模型数据
* @return 结果
*/
boolean copyModel(ModelBo modelBo);
}

View File

@@ -1,91 +0,0 @@
package org.dromara.workflow.service;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.workflow.domain.bo.ProcessDefinitionBo;
import org.dromara.workflow.domain.vo.ProcessDefinitionVo;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* 流程定义 服务层
*
* @author may
*/
public interface IActProcessDefinitionService {
/**
* 分页查询
*
* @param processDefinitionBo 参数
* @param pageQuery 分页
* @return 返回分页列表
*/
TableDataInfo<ProcessDefinitionVo> page(ProcessDefinitionBo processDefinitionBo, PageQuery pageQuery);
/**
* 查询历史流程定义列表
*
* @param key 流程定义key
* @return 结果
*/
List<ProcessDefinitionVo> getListByKey(String key);
/**
* 查看流程定义图片
*
* @param processDefinitionId 流程定义id
* @return 结果
*/
String definitionImage(String processDefinitionId);
/**
* 查看流程定义xml文件
*
* @param processDefinitionId 流程定义id
* @return 结果
*/
String definitionXml(String processDefinitionId);
/**
* 删除流程定义
*
* @param deploymentIds 部署id
* @param processDefinitionIds 流程定义id
* @return 结果
*/
boolean deleteDeployment(List<String> deploymentIds, List<String> processDefinitionIds);
/**
* 激活或者挂起流程定义
*
* @param processDefinitionId 流程定义id
* @return 结果
*/
boolean updateDefinitionState(String processDefinitionId);
/**
* 迁移流程定义
*
* @param currentProcessDefinitionId 当前流程定义id
* @param fromProcessDefinitionId 需要迁移到的流程定义id
* @return 结果
*/
boolean migrationDefinition(String currentProcessDefinitionId, String fromProcessDefinitionId);
/**
* 流程定义转换为模型
*
* @param processDefinitionId 流程定义id
* @return 结果
*/
boolean convertToModel(String processDefinitionId);
/**
* 通过zip或xml部署流程定义
*
* @param file 文件
* @param categoryCode 分类
*/
void deployByFile(MultipartFile file, String categoryCode);
}

View File

@@ -1,110 +0,0 @@
package org.dromara.workflow.service;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.workflow.domain.bo.ProcessInstanceBo;
import org.dromara.workflow.domain.bo.ProcessInvalidBo;
import org.dromara.workflow.domain.bo.TaskUrgingBo;
import org.dromara.workflow.domain.vo.ActHistoryInfoVo;
import org.dromara.workflow.domain.vo.ProcessInstanceVo;
import java.util.List;
import java.util.Map;
/**
* 流程实例 服务层
*
* @author may
*/
public interface IActProcessInstanceService {
/**
* 通过流程实例id获取历史流程图
*
* @param businessKey 流程实例id
* @return 结果
*/
String getHistoryImage(String businessKey);
/**
* 通过业务id获取历史流程图运行中历史等节点
*
* @param businessKey 业务id
* @return 结果
*/
Map<String, Object> getHistoryList(String businessKey);
/**
* 分页查询正在运行的流程实例
*
* @param processInstanceBo 参数
* @param pageQuery 分页
* @return 结果
*/
TableDataInfo<ProcessInstanceVo> getPageByRunning(ProcessInstanceBo processInstanceBo, PageQuery pageQuery);
/**
* 分页查询已结束的流程实例
*
* @param processInstanceBo 参数
* @param pageQuery 分页
* @return 结果
*/
TableDataInfo<ProcessInstanceVo> getPageByFinish(ProcessInstanceBo processInstanceBo, PageQuery pageQuery);
/**
* 获取审批记录
*
* @param businessKey 业务id
* @return 结果
*/
List<ActHistoryInfoVo> getHistoryRecord(String businessKey);
/**
* 作废流程实例,不会删除历史记录(删除运行中的实例)
*
* @param processInvalidBo 参数
* @return 结果
*/
boolean deleteRunInstance(ProcessInvalidBo processInvalidBo);
/**
* 运行中的实例 删除程实例,删除历史记录,删除业务与流程关联信息
*
* @param businessKeys 业务id
* @return 结果
*/
boolean deleteRunAndHisInstance(List<String> businessKeys);
/**
* 已完成的实例 删除程实例,删除历史记录,删除业务与流程关联信息
*
* @param businessKeys 业务id
* @return 结果
*/
boolean deleteFinishAndHisInstance(List<String> businessKeys);
/**
* 撤销流程申请
*
* @param businessKey 业务id
* @return 结果
*/
boolean cancelProcessApply(String businessKey);
/**
* 分页查询当前登录人单据
*
* @param processInstanceBo 参数
* @param pageQuery 分页
* @return 结果
*/
TableDataInfo<ProcessInstanceVo> getPageByCurrent(ProcessInstanceBo processInstanceBo, PageQuery pageQuery);
/**
* 任务催办(给当前任务办理人发送站内信,邮件,短信等)
*
* @param taskUrgingBo 任务催办
* @return 结果
*/
boolean taskUrging(TaskUrgingBo taskUrgingBo);
}

View File

@@ -1,161 +0,0 @@
package org.dromara.workflow.service;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.workflow.domain.bo.*;
import org.dromara.workflow.domain.vo.TaskVo;
import org.dromara.workflow.domain.vo.VariableVo;
import java.util.List;
import java.util.Map;
/**
* 任务 服务层
*
* @author may
*/
public interface IActTaskService {
/**
* 启动任务
*
* @param startProcessBo 启动流程参数
* @return 结果
*/
Map<String, Object> startWorkFlow(StartProcessBo startProcessBo);
/**
* 办理任务
*
* @param completeTaskBo 办理任务参数
* @return 结果
*/
boolean completeTask(CompleteTaskBo completeTaskBo);
/**
* 查询当前用户的待办任务
*
* @param taskBo 参数
* @param pageQuery 分页
* @return 结果
*/
TableDataInfo<TaskVo> getPageByTaskWait(TaskBo taskBo, PageQuery pageQuery);
/**
* 查询当前租户所有待办任务
*
* @param taskBo 参数
* @param pageQuery 分页
* @return 结果
*/
TableDataInfo<TaskVo> getPageByAllTaskWait(TaskBo taskBo, PageQuery pageQuery);
/**
* 查询当前用户的已办任务
*
* @param taskBo 参数
* @param pageQuery 参数
* @return 结果
*/
TableDataInfo<TaskVo> getPageByTaskFinish(TaskBo taskBo, PageQuery pageQuery);
/**
* 查询当前用户的抄送
*
* @param taskBo 参数
* @param pageQuery 参数
* @return 结果
*/
TableDataInfo<TaskVo> getPageByTaskCopy(TaskBo taskBo, PageQuery pageQuery);
/**
* 查询当前租户所有已办任务
*
* @param taskBo 参数
* @param pageQuery 参数
* @return 结果
*/
TableDataInfo<TaskVo> getPageByAllTaskFinish(TaskBo taskBo, PageQuery pageQuery);
/**
* 委派任务
*
* @param delegateBo 参数
* @return 结果
*/
boolean delegateTask(DelegateBo delegateBo);
/**
* 终止任务
*
* @param terminationBo 参数
* @return 结果
*/
boolean terminationTask(TerminationBo terminationBo);
/**
* 转办任务
*
* @param transmitBo 参数
* @return 结果
*/
boolean transferTask(TransmitBo transmitBo);
/**
* 会签任务加签
*
* @param addMultiBo 参数
* @return 结果
*/
boolean addMultiInstanceExecution(AddMultiBo addMultiBo);
/**
* 会签任务减签
*
* @param deleteMultiBo 参数
* @return 结果
*/
boolean deleteMultiInstanceExecution(DeleteMultiBo deleteMultiBo);
/**
* 驳回审批
*
* @param backProcessBo 参数
* @return 流程实例id
*/
String backProcess(BackProcessBo backProcessBo);
/**
* 修改任务办理人
*
* @param taskIds 任务id
* @param userId 办理人id
* @return 结果
*/
boolean updateAssignee(String[] taskIds, String userId);
/**
* 查询流程变量
*
* @param taskId 任务id
* @return 结果
*/
List<VariableVo> getInstanceVariable(String taskId);
/**
* 查询工作流任务用户选择加签人员
*
* @param taskId 任务id
* @return 结果
*/
String getTaskUserIdsByAddMultiInstance(String taskId);
/**
* 查询工作流选择减签人员
*
* @param taskId 任务id
* @return 结果
*/
List<TaskVo> getListByDeleteMultiInstance(String taskId);
}

View File

@@ -0,0 +1,53 @@
package org.dromara.workflow.service;
import com.warm.flow.core.entity.Definition;
import com.warm.flow.orm.entity.FlowDefinition;
import jakarta.servlet.http.HttpServletResponse;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.workflow.domain.vo.FlowDefinitionVo;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
/**
* 流程定义 服务层
*
* @author may
*/
public interface IFlwDefinitionService {
/**
* 分页查询
*
* @param flowDefinition 参数
* @param pageQuery 分页
* @return 返回分页列表
*/
TableDataInfo<FlowDefinitionVo> page(FlowDefinition flowDefinition, PageQuery pageQuery);
/**
* 获取历史流程定义列表
*
* @param flowCode 参数
* @return 返回列表
*/
List<FlowDefinitionVo> getHisListByKey(String flowCode);
/**
* 导出流程定义
*
* @param id 流程定义id
* @param response 响应
* @throws IOException 异常
*/
void exportDefinition(Long id, HttpServletResponse response) throws IOException;
/**
* 导入流程定义
*
* @param file 文件
* @return 结果
*/
boolean importXml(MultipartFile file);
}

View File

@@ -0,0 +1,67 @@
package org.dromara.workflow.service;
import com.warm.flow.core.entity.Instance;
import com.warm.flow.orm.entity.FlowInstance;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.workflow.domain.vo.FlowInstanceVo;
import java.util.List;
/**
* 流程实例 服务层
*
* @author may
*/
public interface IFlwInstanceService {
/**
* 分页查询正在运行的流程实例
*
* @param instance 参数
* @param pageQuery 分页
* @return 结果
*/
TableDataInfo<FlowInstanceVo> getPageByRunning(Instance instance, PageQuery pageQuery);
/**
* 分页查询已结束的流程实例
*
* @param instance 参数
* @param pageQuery 分页
* @return 结果
*/
TableDataInfo<FlowInstanceVo> getPageByFinish(Instance instance, PageQuery pageQuery);
/**
* 按照业务id查询流程实例
*
* @param businessId 业务id
* @return 结果
*/
FlowInstance instanceByBusinessId(String businessId);
/**
* 按照业务id删除流程实例
*
* @param businessIds 业务id
* @return 结果
*/
boolean deleteByBusinessIds(List<Long> businessIds);
/**
* 按照实例id删除流程实例
*
* @param instanceIds 实例id
* @return 结果
*/
boolean deleteByInstanceIds(List<Long> instanceIds);
/**
* 撤销流程
*
* @param businessId 业务id
* @return 结果
*/
boolean cancelProcessApply(String businessId);
}

View File

@@ -0,0 +1,68 @@
package org.dromara.workflow.service;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.workflow.domain.bo.*;
import org.dromara.workflow.domain.vo.FlowHisTaskVo;
import org.dromara.workflow.domain.vo.FlowTaskVo;
import java.util.Map;
/**
* 任务 服务层
*
* @author may
*/
public interface IFlwTaskService {
/**
* 启动任务
*
* @param startProcessBo 启动流程参数
* @return 结果
*/
Map<String, Object> startWorkFlow(StartProcessBo startProcessBo);
/**
* 办理任务
*
* @param completeTaskBo 办理任务参数
* @return 结果
*/
boolean completeTask(CompleteTaskBo completeTaskBo);
/**
* 查询当前用户的待办任务
*
* @param flowTaskBo 参数
* @param pageQuery 分页
* @return 结果
*/
TableDataInfo<FlowTaskVo> getPageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery);
/**
* 查询当前租户所有待办任务
*
* @param flowTaskBo 参数
* @param pageQuery 分页
* @return 结果
*/
TableDataInfo<FlowHisTaskVo> getPageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery);
/**
* 查询当前用户的抄送
*
* @param flowTaskBo 参数
* @param pageQuery 分页
* @return 结果
*/
TableDataInfo<FlowTaskVo> getPageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery);
/**
* 驳回审批
*
* @param bo 参数
* @return 结果
*/
boolean backProcess(BackProcessBo bo);
}

View File

@@ -1,65 +0,0 @@
package org.dromara.workflow.service;
import org.dromara.workflow.domain.WfTaskBackNode;
import org.flowable.task.api.Task;
import java.util.List;
/**
* 节点驳回记录Service接口
*
* @author may
* @date 2024-03-13
*/
public interface IWfTaskBackNodeService {
/**
* 记录审批节点
*
* @param task 任务
*/
void recordExecuteNode(Task task);
/**
* 按流程实例id查询
*
* @param processInstanceId 流程实例id
* @return 结果
*/
List<WfTaskBackNode> getListByInstanceId(String processInstanceId);
/**
* 按照流程实例id节点id查询
*
* @param processInstanceId 流程实例id
* @param nodeId 节点id
* @return 结果
*/
WfTaskBackNode getListByInstanceIdAndNodeId(String processInstanceId, String nodeId);
/**
* 删除驳回后的节点
*
* @param processInstanceId 流程实例id
* @param targetActivityId 节点id
* @return 结果
*/
boolean deleteBackTaskNode(String processInstanceId, String targetActivityId);
/**
* 按流程实例id删除
*
* @param processInstanceId 流程实例id
* @return 结果
*/
boolean deleteByInstanceId(String processInstanceId);
/**
* 按流程实例id删除
*
* @param processInstanceIds 流程实例id
* @return 结果
*/
boolean deleteByInstanceIds(List<String> processInstanceIds);
}

View File

@@ -1,51 +0,0 @@
package org.dromara.workflow.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.workflow.domain.ActHiProcinst;
import org.dromara.workflow.mapper.ActHiProcinstMapper;
import org.dromara.workflow.service.IActHiProcinstService;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 流程实例Service业务层处理
*
* @author may
* @date 2023-07-22
*/
@RequiredArgsConstructor
@Service
public class ActHiProcinstServiceImpl implements IActHiProcinstService {
private final ActHiProcinstMapper baseMapper;
/**
* 按照业务id查询
*
* @param businessKeys 业务id
*/
@Override
public List<ActHiProcinst> selectByBusinessKeyIn(List<String> businessKeys) {
return baseMapper.selectList(new LambdaQueryWrapper<ActHiProcinst>()
.in(ActHiProcinst::getBusinessKey, businessKeys)
.eq(TenantHelper.isEnable(), ActHiProcinst::getTenantId, TenantHelper.getTenantId()));
}
/**
* 按照业务id查询
*
* @param businessKey 业务id
*/
@Override
public ActHiProcinst selectByBusinessKey(String businessKey) {
return baseMapper.selectOne(new LambdaQueryWrapper<ActHiProcinst>()
.eq(ActHiProcinst::getBusinessKey, businessKey)
.eq(TenantHelper.isEnable(), ActHiProcinst::getTenantId, TenantHelper.getTenantId()));
}
}

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