!549 ♥️发布 5.2.0-BETA2 公测版本

Merge pull request !549 from 疯狂的狮子Li/dev
This commit is contained in:
疯狂的狮子Li 2024-06-06 03:13:46 +00:00 committed by Gitee
commit 456620b638
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
70 changed files with 860 additions and 673 deletions

11
pom.xml
View File

@ -13,8 +13,8 @@
<description>RuoYi-Vue-Plus多租户管理系统</description>
<properties>
<revision>5.2.0-BETA</revision>
<spring-boot.version>3.2.5</spring-boot.version>
<revision>5.2.0-BETA2</revision>
<spring-boot.version>3.2.6</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>17</java.version>
@ -34,7 +34,7 @@
<lock4j.version>2.2.7</lock4j.version>
<dynamic-ds.version>4.3.0</dynamic-ds.version>
<alibaba-ttl.version>2.14.4</alibaba-ttl.version>
<snailjob.version>1.0.0-beta1</snailjob.version>
<snailjob.version>1.0.0-beta3</snailjob.version>
<mapstruct-plus.version>1.3.6</mapstruct-plus.version>
<mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
<lombok.version>1.18.32</lombok.version>
@ -50,6 +50,8 @@
<sms4j.version>3.2.1</sms4j.version>
<!-- 限制框架中的fastjson版本 -->
<fastjson.version>1.2.83</fastjson.version>
<!--工作流配置-->
<flowable.version>7.0.0</flowable.version>
<!-- 插件版本 -->
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
@ -57,9 +59,6 @@
<maven-compiler-plugin.verison>3.11.0</maven-compiler-plugin.verison>
<maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>
<flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version>
<!--工作流配置-->
<flowable.version>7.0.0</flowable.version>
</properties>
<profiles>

View File

@ -97,21 +97,6 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
</dependency>
<!-- SnailJob client -->
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>snail-job-client-starter</artifactId>
</dependency>
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>snail-job-client-job-core</artifactId>
</dependency>
<!-- skywalking 整合 logback -->
<!-- <dependency>-->
<!-- <groupId>org.apache.skywalking</groupId>-->

View File

@ -12,7 +12,7 @@ spring.boot.admin.client:
snail-job:
enabled: true
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
group-name: "ruoyi_group"
group: "ruoyi_group"
# SnailJob 接入验证令牌 详见 script/sql/snail_job.sql `sj_group_config` 表
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
server:
@ -21,7 +21,6 @@ snail-job:
# 详见 script/sql/snail_job.sql `sj_namespace` 表
namespace: ${spring.profiles.active}
--- # 数据源配置
spring:
datasource:
@ -102,6 +101,7 @@ spring.data:
# 是否开启ssl
ssl.enabled: false
# redisson 配置
redisson:
# redis key前缀
keyPrefix:

View File

@ -15,7 +15,7 @@ spring.boot.admin.client:
snail-job:
enabled: false
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
group-name: "ruoyi_group"
group: "ruoyi_group"
# SnailJob 接入验证令牌 详见 script/sql/snail_job.sql `sj_group_config` 表
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
server:
@ -104,6 +104,7 @@ spring.data:
# 是否开启ssl
ssl.enabled: false
# redisson 配置
redisson:
# redis key前缀
keyPrefix:

View File

@ -14,7 +14,7 @@
</description>
<properties>
<revision>5.2.0-BETA</revision>
<revision>5.2.0-BETA2</revision>
</properties>
<dependencyManagement>

View File

@ -0,0 +1,41 @@
package org.dromara.common.core.domain.event;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 总体流程监听
*
* @author may
*/
@Data
public class ProcessEvent implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 流程定义key
*/
private String key;
/**
* 业务id
*/
private String businessKey;
/**
* 状态
*/
private String status;
/**
* 当为true时为申请人节点办理
*/
private boolean submit;
}

View File

@ -0,0 +1,35 @@
package org.dromara.common.core.domain.event;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 流程办理监听
*
* @author may
*/
@Data
public class ProcessTaskEvent implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 流程定义key与流程节点标识(拼接方式流程定义key_流程节点)
*/
private String keyNode;
/**
* 任务id
*/
private String taskId;
/**
* 业务id
*/
private String businessKey;
}

View File

@ -1,4 +1,4 @@
package org.dromara.workflow.common.enums;
package org.dromara.common.core.enums;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;

View File

@ -0,0 +1,76 @@
package org.dromara.common.core.service;
import java.util.List;
import java.util.Map;
/**
* 通用 工作流服务
*
* @author may
*/
public interface WorkflowService {
/**
* 运行中的实例 删除程实例删除历史记录删除业务与流程关联信息
*
* @param businessKeys 业务id
* @return 结果
*/
boolean deleteRunAndHisInstance(List<String> businessKeys);
/**
* 获取当前流程状态
*
* @param taskId 任务id
*/
String getBusinessStatusByTaskId(String taskId);
/**
* 获取当前流程状态
*
* @param businessKey 业务id
*/
String getBusinessStatus(String businessKey);
/**
* 设置流程变量(全局变量)
*
* @param taskId 任务id
* @param variableName 变量名称
* @param value 变量值
*/
void setVariable(String taskId, String variableName, Object value);
/**
* 设置流程变量(全局变量)
*
* @param taskId 任务id
* @param variables 流程变量
*/
void setVariables(String taskId, Map<String, Object> variables);
/**
* 设置流程变量(本地变量,非全局变量)
*
* @param taskId 任务id
* @param variableName 变量名称
* @param value 变量值
*/
void setVariableLocal(String taskId, String variableName, Object value);
/**
* 设置流程变量(本地变量,非全局变量)
*
* @param taskId 任务id
* @param variables 流程变量
*/
void setVariablesLocal(String taskId, Map<String, Object> variables);
/**
* 按照业务id查询流程实例id
*
* @param businessKey 业务id
* @return 结果
*/
String getInstanceIdByBusinessKey(String businessKey);
}

View File

@ -21,7 +21,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
@AutoConfiguration
@ConditionalOnProperty(prefix = "snail-job", name = "enabled", havingValue = "true")
@EnableScheduling
@EnableSnailJob(group = "${snail-job.group-name}")
@EnableSnailJob
public class SnailJobConfig {
@EventListener(SnailClientStartingEvent.class)

View File

@ -162,13 +162,14 @@ public class OssClient {
/**
* 上传文件到 Amazon S3并返回上传结果
*
* @param filePath 本地文件路径
* @param key Amazon S3 中的对象键
* @param md5Digest 本地文件的 MD5 哈希值可选
* @param filePath 本地文件路径
* @param key Amazon S3 中的对象键
* @param md5Digest 本地文件的 MD5 哈希值可选
* @param contentType 文件内容类型
* @return UploadResult 包含上传后的文件信息
* @throws OssException 如果上传失败抛出自定义异常
*/
public UploadResult upload(Path filePath, String key, String md5Digest) {
public UploadResult upload(Path filePath, String key, String md5Digest, String contentType) {
try {
// 构建上传请求对象
FileUpload fileUpload = transferManager.uploadFile(
@ -176,6 +177,7 @@ public class OssClient {
y -> y.bucket(properties.getBucketName())
.key(key)
.contentMD5(StringUtils.isNotEmpty(md5Digest) ? md5Digest : null)
.contentType(contentType)
.build())
.addTransferListener(LoggingTransferListener.create())
.source(filePath).build());
@ -201,10 +203,11 @@ public class OssClient {
* @param inputStream 要上传的输入流
* @param key Amazon S3 中的对象键
* @param length 输入流的长度
* @param contentType 文件内容类型
* @return UploadResult 包含上传后的文件信息
* @throws OssException 如果上传失败抛出自定义异常
*/
public UploadResult upload(InputStream inputStream, String key, Long length) {
public UploadResult upload(InputStream inputStream, String key, Long length, String contentType) {
// 如果输入流不是 ByteArrayInputStream则将其读取为字节数组再创建 ByteArrayInputStream
if (!(inputStream instanceof ByteArrayInputStream)) {
inputStream = new ByteArrayInputStream(IoUtil.readBytes(inputStream));
@ -219,6 +222,7 @@ public class OssClient {
.putObjectRequest(
y -> y.bucket(properties.getBucketName())
.key(key)
.contentType(contentType)
.build())
.build());
@ -335,7 +339,7 @@ public class OssClient {
* @throws OssException 如果上传失败抛出自定义异常
*/
public UploadResult uploadSuffix(byte[] data, String suffix) {
return upload(new ByteArrayInputStream(data), getPath(properties.getPrefix(), suffix), Long.valueOf(data.length));
return upload(new ByteArrayInputStream(data), getPath(properties.getPrefix(), suffix), Long.valueOf(data.length), FileUtils.getMimeType(suffix));
}
/**
@ -348,7 +352,7 @@ public class OssClient {
* @throws OssException 如果上传失败抛出自定义异常
*/
public UploadResult uploadSuffix(InputStream inputStream, String suffix, Long length) {
return upload(inputStream, getPath(properties.getPrefix(), suffix), length);
return upload(inputStream, getPath(properties.getPrefix(), suffix), length, FileUtils.getMimeType(suffix));
}
/**
@ -360,7 +364,7 @@ public class OssClient {
* @throws OssException 如果上传失败抛出自定义异常
*/
public UploadResult uploadSuffix(File file, String suffix) {
return upload(file.toPath(), getPath(properties.getPrefix(), suffix), null);
return upload(file.toPath(), getPath(properties.getPrefix(), suffix), null, FileUtils.getMimeType(suffix));
}
/**

View File

@ -48,7 +48,10 @@ public class OssFactory {
}
OssProperties properties = JsonUtils.parseObject(json, OssProperties.class);
// 使用租户标识避免多个租户相同key实例覆盖
String key = properties.getTenantId() + ":" + configKey;
String key = configKey;
if (StringUtils.isNotBlank(properties.getTenantId())) {
key = properties.getTenantId() + ":" + configKey;
}
OssClient client = CLIENT_CACHE.get(key);
// 客户端不存在或配置不相同则重新构建
if (client == null || !client.checkPropertiesSame(properties)) {

View File

@ -23,7 +23,7 @@ public class RedisExceptionHandler {
@ExceptionHandler(LockFailureException.class)
public R<Void> handleLockFailureException(LockFailureException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("获取锁失败了'{}',发生Lock4j异常." + requestURI, e.getMessage());
log.error("获取锁失败了'{}',发生Lock4j异常.", requestURI, e);
return R.fail(HttpStatus.HTTP_UNAVAILABLE, "业务处理中,请稍后再试...");
}

View File

@ -2,7 +2,6 @@ package org.dromara.common.satoken.core.dao;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.util.SaFoxUtil;
import cn.hutool.core.lang.Console;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.dromara.common.redis.utils.RedisUtils;
@ -54,7 +53,7 @@ public class PlusSaTokenDao implements SaTokenDao {
} else {
RedisUtils.setCacheObject(key, value, Duration.ofSeconds(timeout));
}
CAFFEINE.put(key, value);
CAFFEINE.invalidate(key);
}
/**
@ -64,7 +63,7 @@ public class PlusSaTokenDao implements SaTokenDao {
public void update(String key, String value) {
if (RedisUtils.hasKey(key)) {
RedisUtils.setCacheObject(key, value, true);
CAFFEINE.put(key, value);
CAFFEINE.invalidate(key);
}
}
@ -117,7 +116,7 @@ public class PlusSaTokenDao implements SaTokenDao {
} else {
RedisUtils.setCacheObject(key, object, Duration.ofSeconds(timeout));
}
CAFFEINE.put(key, object);
CAFFEINE.invalidate(key);
}
/**
@ -127,7 +126,7 @@ public class PlusSaTokenDao implements SaTokenDao {
public void updateObject(String key, Object object) {
if (RedisUtils.hasKey(key)) {
RedisUtils.setCacheObject(key, object, true);
CAFFEINE.put(key, object);
CAFFEINE.invalidate(key);
}
}

View File

@ -1,6 +1,7 @@
package org.dromara.common.sms.config;
import org.dromara.common.sms.core.dao.PlusSmsDao;
import org.dromara.common.sms.handler.SmsExceptionHandler;
import org.dromara.sms4j.api.dao.SmsDao;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
@ -21,4 +22,12 @@ public class SmsAutoConfiguration {
return new PlusSmsDao();
}
/**
* 异常处理器
*/
@Bean
public SmsExceptionHandler smsExceptionHandler() {
return new SmsExceptionHandler();
}
}

View File

@ -0,0 +1,30 @@
package org.dromara.common.sms.handler;
import cn.hutool.http.HttpStatus;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.sms4j.comm.exception.SmsBlendException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* SMS异常处理器
*
* @author AprilWind
*/
@Slf4j
@RestControllerAdvice
public class SmsExceptionHandler {
/**
* sms异常
*/
@ExceptionHandler(SmsBlendException.class)
public R<Void> handleSmsBlendException(SmsBlendException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',发生sms短信异常.", requestURI, e);
return R.fail(HttpStatus.HTTP_INTERNAL_ERROR, "短信发送失败,请稍后再试...");
}
}

View File

@ -35,7 +35,7 @@ public class TenantConfig {
@ConditionalOnBean(MybatisPlusConfig.class)
@AutoConfiguration(after = {MybatisPlusConfig.class})
static class MybatisPlusConfigation {
static class MybatisPlusConfiguration {
/**
* 多租户插件

View File

@ -1,6 +1,5 @@
package org.dromara.common.tenant.helper;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.convert.Convert;
import com.alibaba.ttl.TransmittableThreadLocal;
@ -79,22 +78,28 @@ public class TenantHelper {
}
}
public static void setDynamic(String tenantId) {
setDynamic(tenantId, false);
}
/**
* 设置动态租户(一直有效 需要手动清理)
* <p>
* 如果为未登录状态下 那么只在当前线程内生效
*
* @param tenantId 租户id
* @param global 是否全局生效
*/
public static void setDynamic(String tenantId) {
public static void setDynamic(String tenantId, boolean global) {
if (!isEnable()) {
return;
}
if (!isLogin()) {
if (!isLogin() || !global) {
TEMP_DYNAMIC_TENANT.set(tenantId);
return;
}
String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
RedisUtils.setCacheObject(cacheKey, tenantId);
SaHolder.getStorage().set(cacheKey, tenantId);
}
/**
@ -109,13 +114,13 @@ public class TenantHelper {
if (!isLogin()) {
return TEMP_DYNAMIC_TENANT.get();
}
String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
String tenantId = (String) SaHolder.getStorage().get(cacheKey);
// 如果线程内有值 优先返回
String tenantId = TEMP_DYNAMIC_TENANT.get();
if (StringUtils.isNotBlank(tenantId)) {
return tenantId;
}
String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
tenantId = RedisUtils.getCacheObject(cacheKey);
SaHolder.getStorage().set(cacheKey, tenantId);
return tenantId;
}
@ -130,9 +135,9 @@ public class TenantHelper {
TEMP_DYNAMIC_TENANT.remove();
return;
}
TEMP_DYNAMIC_TENANT.remove();
String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
RedisUtils.deleteObject(cacheKey);
SaHolder.getStorage().delete(cacheKey);
}
/**

View File

@ -27,17 +27,20 @@ public class WebSocketConfig {
@Bean
public WebSocketConfigurer webSocketConfigurer(HandshakeInterceptor handshakeInterceptor,
WebSocketHandler webSocketHandler,
WebSocketProperties webSocketProperties) {
WebSocketHandler webSocketHandler, WebSocketProperties webSocketProperties) {
// 如果WebSocket的路径为空则设置默认路径为 "/websocket"
if (StrUtil.isBlank(webSocketProperties.getPath())) {
webSocketProperties.setPath("/websocket");
}
// 如果允许跨域访问的地址为空则设置为 "*"表示允许所有来源的跨域请求
if (StrUtil.isBlank(webSocketProperties.getAllowedOrigins())) {
webSocketProperties.setAllowedOrigins("*");
}
// 返回一个WebSocketConfigurer对象用于配置WebSocket
return registry -> registry
// 添加WebSocket处理程序和拦截器到指定路径设置允许的跨域来源
.addHandler(webSocketHandler, webSocketProperties.getPath())
.addInterceptors(handshakeInterceptor)
.setAllowedOrigins(webSocketProperties.getAllowedOrigins());

View File

@ -6,6 +6,7 @@ package org.dromara.common.websocket.constant;
* @author zendwang
*/
public interface WebSocketConstants {
/**
* websocketSession中的参数的key
*/

View File

@ -31,33 +31,42 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler {
}
/**
* 处理发送来的文本消息
* 处理接收到的文本消息
*
* @param session
* @param message
* @throws Exception
* @param session WebSocket会话
* @param message 接收到的文本消息
* @throws Exception 处理消息过程中可能抛出的异常
*/
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
// 从WebSocket会话中获取登录用户信息
LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY);
List<Long> userIds = List.of(loginUser.getUserId());
// 创建WebSocket消息DTO对象
WebSocketMessageDto webSocketMessageDto = new WebSocketMessageDto();
webSocketMessageDto.setSessionKeys(userIds);
webSocketMessageDto.setSessionKeys(List.of(loginUser.getUserId()));
webSocketMessageDto.setMessage(message.getPayload());
WebSocketUtils.publishMessage(webSocketMessageDto);
}
/**
* 处理接收到的二进制消息
*
* @param session WebSocket会话
* @param message 接收到的二进制消息
* @throws Exception 处理消息过程中可能抛出的异常
*/
@Override
protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
super.handleBinaryMessage(session, message);
}
/**
* 心跳监测的回复
* 处理接收到的Pong消息心跳监测
*
* @param session
* @param message
* @throws Exception
* @param session WebSocket会话
* @param message 接收到的Pong消息
* @throws Exception 处理消息过程中可能抛出的异常
*/
@Override
protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
@ -65,11 +74,11 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler {
}
/**
* 连接出错时
* 处理WebSocket传输错误
*
* @param session
* @param exception
* @throws Exception
* @param session WebSocket会话
* @param exception 发生的异常
* @throws Exception 处理过程中可能抛出的异常
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
@ -77,10 +86,10 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler {
}
/**
* 连接关闭后
* 在WebSocket连接关闭后执行清理操作
*
* @param session
* @param status
* @param session WebSocket会话
* @param status 关闭状态信息
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
@ -90,9 +99,9 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler {
}
/**
* 是否支持分消息
* 指示处理程序是否支持接收部分消息
*
* @return
* @return 如果支持接收部分消息则返回true否则返回false
*/
@Override
public boolean supportsPartialMessages() {

View File

@ -18,24 +18,52 @@ public class WebSocketSessionHolder {
private static final Map<Long, WebSocketSession> USER_SESSION_MAP = new ConcurrentHashMap<>();
/**
* 将WebSocket会话添加到用户会话Map中
*
* @param sessionKey 会话键用于检索会话
* @param session 要添加的WebSocket会话
*/
public static void addSession(Long sessionKey, WebSocketSession session) {
USER_SESSION_MAP.put(sessionKey, session);
}
/**
* 从用户会话Map中移除指定会话键对应的WebSocket会话
*
* @param sessionKey 要移除的会话键
*/
public static void removeSession(Long sessionKey) {
if (USER_SESSION_MAP.containsKey(sessionKey)) {
USER_SESSION_MAP.remove(sessionKey);
}
}
/**
* 根据会话键从用户会话Map中获取WebSocket会话
*
* @param sessionKey 要获取的会话键
* @return 与给定会话键对应的WebSocket会话如果不存在则返回null
*/
public static WebSocketSession getSessions(Long sessionKey) {
return USER_SESSION_MAP.get(sessionKey);
}
/**
* 获取存储在用户会话Map中所有WebSocket会话的会话键集合
*
* @return 所有WebSocket会话的会话键集合
*/
public static Set<Long> getSessionsAll() {
return USER_SESSION_MAP.keySet();
}
/**
* 检查给定的会话键是否存在于用户会话Map中
*
* @param sessionKey 要检查的会话键
* @return 如果存在对应的会话键则返回true否则返回false
*/
public static Boolean existSession(Long sessionKey) {
return USER_SESSION_MAP.containsKey(sessionKey);
}

View File

@ -1,8 +1,8 @@
package org.dromara.common.websocket.interceptor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.satoken.utils.LoginHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.socket.WebSocketHandler;
@ -21,13 +21,13 @@ import static org.dromara.common.websocket.constant.WebSocketConstants.LOGIN_USE
public class PlusWebSocketInterceptor implements HandshakeInterceptor {
/**
* 握手前
* WebSocket握手执行的前置处理方法
*
* @param request request
* @param response response
* @param wsHandler wsHandler
* @param attributes attributes
* @return 是否握手成功
* @param request WebSocket握手请求
* @param response WebSocket握手响应
* @param wsHandler WebSocket处理程序
* @param attributes 与WebSocket会话关联的属性
* @return 如果允许握手继续进行则返回true否则返回false
*/
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) {
@ -37,15 +37,16 @@ public class PlusWebSocketInterceptor implements HandshakeInterceptor {
}
/**
* 握手后
* WebSocket握手成功执行的后置处理方法
*
* @param request request
* @param response response
* @param wsHandler wsHandler
* @param exception 异常
* @param request WebSocket握手请求
* @param response WebSocket握手响应
* @param wsHandler WebSocket处理程序
* @param exception 握手过程中可能出现的异常
*/
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
// 在这个方法中可以执行一些握手成功后的后续处理逻辑比如记录日志或者其他操作
}
}

View File

@ -1,9 +1,9 @@
package org.dromara.common.websocket.listener;
import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.websocket.holder.WebSocketSessionHolder;
import org.dromara.common.websocket.utils.WebSocketUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.Ordered;
@ -16,8 +16,15 @@ import org.springframework.core.Ordered;
@Slf4j
public class WebSocketTopicListener implements ApplicationRunner, Ordered {
/**
* 在Spring Boot应用程序启动时初始化WebSocket主题订阅监听器
*
* @param args 应用程序参数
* @throws Exception 初始化过程中可能抛出的异常
*/
@Override
public void run(ApplicationArguments args) throws Exception {
// 订阅WebSocket消息
WebSocketUtils.subscribeMessage((message) -> {
log.info("WebSocket主题订阅收到消息session keys={} message={}", message.getSessionKeys(), message.getMessage());
// 如果key不为空就按照key发消息 如果为空就群发

View File

@ -29,10 +29,10 @@ import static org.dromara.common.websocket.constant.WebSocketConstants.WEB_SOCKE
public class WebSocketUtils {
/**
* 发送消息
* 向指定的WebSocket会话发送消息
*
* @param sessionKey session主键 一般为用户id
* @param message 消息文本
* @param sessionKey 要发送消息的用户id
* @param message 要发送的消息内容
*/
public static void sendMessage(Long sessionKey, String message) {
WebSocketSession session = WebSocketSessionHolder.getSessions(sessionKey);
@ -40,18 +40,18 @@ public class WebSocketUtils {
}
/**
* 订阅消息
* 订阅WebSocket消息主题并提供一个消费者函数来处理接收到的消息
*
* @param consumer 自定义处理
* @param consumer 处理WebSocket消息的消费者函数
*/
public static void subscribeMessage(Consumer<WebSocketMessageDto> consumer) {
RedisUtils.subscribe(WEB_SOCKET_TOPIC, WebSocketMessageDto.class, consumer);
}
/**
* 发布订阅消息
* 发布WebSocket订阅消息
*
* @param webSocketMessage 消息对象
* @param webSocketMessage 要发布的WebSocket消息对象
*/
public static void publishMessage(WebSocketMessageDto webSocketMessage) {
List<Long> unsentSessionKeys = new ArrayList<>();
@ -76,9 +76,9 @@ public class WebSocketUtils {
}
/**
* 发布订阅的消息(群发)
* 向所有的WebSocket会话发布订阅的消息(群发)
*
* @param message 消息内容
* @param message 要发布的消息内容
*/
public static void publishAll(String message) {
WebSocketMessageDto broadcastMessage = new WebSocketMessageDto();
@ -88,14 +88,31 @@ public class WebSocketUtils {
});
}
/**
* 向指定的WebSocket会话发送Pong消息
*
* @param session 要发送Pong消息的WebSocket会话
*/
public static void sendPongMessage(WebSocketSession session) {
sendMessage(session, new PongMessage());
}
/**
* 向指定的WebSocket会话发送文本消息
*
* @param session WebSocket会话
* @param message 要发送的文本消息内容
*/
public static void sendMessage(WebSocketSession session, String message) {
sendMessage(session, new TextMessage(message));
}
/**
* 向指定的WebSocket会话发送WebSocket消息对象
*
* @param session WebSocket会话
* @param message 要发送的WebSocket消息对象
*/
private static void sendMessage(WebSocketSession session, WebSocketMessage<?> message) {
if (session == null || !session.isOpen()) {
log.warn("[send] session会话已经关闭");

View File

@ -3,10 +3,12 @@ package org.dromara.system.controller.system;
import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.file.MimeTypeUtils;
import org.dromara.common.encrypt.annotation.ApiEncrypt;
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.satoken.utils.LoginHelper;
@ -19,9 +21,7 @@ import org.dromara.system.domain.vo.ProfileVo;
import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysOssService;
import org.dromara.system.service.ISysRoleService;
import org.dromara.system.service.ISysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -57,12 +57,14 @@ public class SysProfileController extends BaseController {
}
/**
* 修改用户
* 修改用户信息
*/
@RepeatSubmit
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> updateProfile(@RequestBody SysUserProfileBo profile) {
public R<Void> updateProfile(@Validated @RequestBody SysUserProfileBo profile) {
SysUserBo user = BeanUtil.toBean(profile, SysUserBo.class);
user.setUserId(LoginHelper.getUserId());
String username = LoginHelper.getUsername();
if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
return R.fail("修改用户'" + username + "'失败,手机号码已存在");
@ -70,7 +72,6 @@ public class SysProfileController extends BaseController {
if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
return R.fail("修改用户'" + username + "'失败,邮箱账号已存在");
}
user.setUserId(LoginHelper.getUserId());
if (userService.updateUserProfile(user) > 0) {
return R.ok();
}
@ -82,6 +83,7 @@ public class SysProfileController extends BaseController {
*
* @param bo 新旧密码
*/
@RepeatSubmit
@ApiEncrypt
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
@PutMapping("/updatePwd")
@ -106,6 +108,7 @@ public class SysProfileController extends BaseController {
*
* @param avatarfile 用户头像
*/
@RepeatSubmit
@Log(title = "用户头像", businessType = BusinessType.UPDATE)
@PostMapping(value = "/avatar", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R<AvatarVo> avatar(@RequestPart("avatarfile") MultipartFile avatarfile) {

View File

@ -144,7 +144,7 @@ public class SysTenantController extends BaseController {
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
@GetMapping("/dynamic/{tenantId}")
public R<Void> dynamicTenant(@NotBlank(message = "租户ID不能为空") @PathVariable String tenantId) {
TenantHelper.setDynamic(tenantId);
TenantHelper.setDynamic(tenantId, true);
return R.ok();
}

View File

@ -1,14 +1,16 @@
package org.dromara.system.domain.bo;
import org.dromara.common.core.xss.Xss;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.sensitive.annotation.Sensitive;
import org.dromara.common.sensitive.core.SensitiveStrategy;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.dromara.common.core.constant.RegexConstants;
import org.dromara.common.core.xss.Xss;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.sensitive.annotation.Sensitive;
import org.dromara.common.sensitive.core.SensitiveStrategy;
/**
* 个人信息业务处理
@ -21,11 +23,6 @@ import lombok.NoArgsConstructor;
@EqualsAndHashCode(callSuper = true)
public class SysUserProfileBo extends BaseEntity {
/**
* 用户ID
*/
private Long userId;
/**
* 用户昵称
*/
@ -44,6 +41,7 @@ public class SysUserProfileBo extends BaseEntity {
/**
* 手机号码
*/
@Pattern(regexp = RegexConstants.MOBILE, message = "手机号格式不正确")
@Sensitive(strategy = SensitiveStrategy.PHONE)
private String phonenumber;

View File

@ -37,6 +37,7 @@ import org.dromara.system.domain.vo.SysUserExportVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.mapper.*;
import org.dromara.system.service.ISysUserService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -338,6 +339,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
* @return 结果
*/
@Override
@CacheEvict(cacheNames = CacheNames.SYS_NICKNAME, key = "#user.userId")
@Transactional(rollbackFor = Exception.class)
public int updateUser(SysUserBo user) {
// 新增用户与角色管理
@ -386,6 +388,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
* @param user 用户信息
* @return 结果
*/
@CacheEvict(cacheNames = CacheNames.SYS_NICKNAME, key = "#user.userId")
@Override
public int updateUserProfile(SysUserBo user) {
return baseMapper.update(null,
@ -636,7 +639,10 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
if (CollUtil.isEmpty(userIds)) {
return List.of();
}
List<SysUserVo> list = this.selectUserByIds(userIds, null);
List<SysUserVo> list = baseMapper.selectVoList(new LambdaQueryWrapper<SysUser>()
.select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName)
.eq(SysUser::getStatus, UserConstants.USER_NORMAL)
.in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds));
return BeanUtil.copyToList(list, UserDTO.class);
}

View File

@ -0,0 +1,3 @@
# 工作流说明
工作流目前在未成熟阶段 后续仍会经历重构 甚至重写(生产使用前请慎重考虑后续是否要更新维护)

View File

@ -109,7 +109,10 @@
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-tenant</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-security</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,27 +0,0 @@
package org.dromara.workflow.annotation;
import java.lang.annotation.*;
/**
* 流程任务监听注解
*
* @author may
* @date 2023-12-27
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface FlowListenerAnnotation {
/**
* 流程定义key
*/
String processDefinitionKey();
/**
* 节点id
*/
String taskDefId() default "";
}

View File

@ -71,9 +71,9 @@ public interface FlowConstant {
String ZIP = "ZIP";
/**
* 流程实例对象
* 业务与流程实例关联对象
*/
String PROCESS_INSTANCE_VO = "processInstanceVo";
String BUSINESS_INSTANCE_DTO = "businessInstanceDTO";
/**
* 流程定义配置

View File

@ -58,33 +58,33 @@ public class ActProcessInstanceController extends BaseController {
}
/**
* 通过流程实例id获取历史流程图
* 通过业务id获取历史流程图
*
* @param processInstanceId 流程实例id
* @param businessKey 业务id
*/
@GetMapping("/getHistoryImage/{processInstanceId}")
public R<String> getHistoryImage(@NotBlank(message = "流程实例id不能为空") @PathVariable String processInstanceId) {
return R.ok("操作成功", actProcessInstanceService.getHistoryImage(processInstanceId));
@GetMapping("/getHistoryImage/{businessKey}")
public R<String> getHistoryImage(@NotBlank(message = "业务id不能为空") @PathVariable String businessKey) {
return R.ok("操作成功", actProcessInstanceService.getHistoryImage(businessKey));
}
/**
* 通过流程实例id获取历史流程图运行中历史等节点
* 通过业务id获取历史流程图运行中历史等节点
*
* @param processInstanceId 流程实例id
* @param businessKey 业务id
*/
@GetMapping("/getHistoryList/{processInstanceId}")
public R<Map<String, Object>> getHistoryList(@NotBlank(message = "流程实例id不能为空") @PathVariable String processInstanceId) {
return R.ok("操作成功", actProcessInstanceService.getHistoryList(processInstanceId));
@GetMapping("/getHistoryList/{businessKey}")
public R<Map<String, Object>> getHistoryList(@NotBlank(message = "业务id不能为空") @PathVariable String businessKey) {
return R.ok("操作成功", actProcessInstanceService.getHistoryList(businessKey));
}
/**
* 获取审批记录
*
* @param processInstanceId 流程实例id
* @param businessKey 业务id
*/
@GetMapping("/getHistoryRecord/{processInstanceId}")
public R<List<ActHistoryInfoVo>> getHistoryRecord(@NotBlank(message = "流程实例id不能为空") @PathVariable String processInstanceId) {
return R.ok(actProcessInstanceService.getHistoryRecord(processInstanceId));
@GetMapping("/getHistoryRecord/{businessKey}")
public R<List<ActHistoryInfoVo>> getHistoryRecord(@NotBlank(message = "业务id不能为空") @PathVariable String businessKey) {
return R.ok(actProcessInstanceService.getHistoryRecord(businessKey));
}
/**
@ -102,37 +102,37 @@ public class ActProcessInstanceController extends BaseController {
/**
* 运行中的实例 删除程实例删除历史记录删除业务与流程关联信息
*
* @param processInstanceIds 流程实例id
* @param businessKeys 业务id
*/
@Log(title = "流程实例管理", businessType = BusinessType.DELETE)
@RepeatSubmit()
@DeleteMapping("/deleteRunAndHisInstance/{processInstanceIds}")
public R<Void> deleteRunAndHisInstance(@NotNull(message = "流程实例id不能为空") @PathVariable String[] processInstanceIds) {
return toAjax(actProcessInstanceService.deleteRunAndHisInstance(Arrays.asList(processInstanceIds)));
@DeleteMapping("/deleteRunAndHisInstance/{businessKeys}")
public R<Void> deleteRunAndHisInstance(@NotNull(message = "业务id不能为空") @PathVariable String[] businessKeys) {
return toAjax(actProcessInstanceService.deleteRunAndHisInstance(Arrays.asList(businessKeys)));
}
/**
* 已完成的实例 删除程实例删除历史记录删除业务与流程关联信息
*
* @param processInstanceIds 流程实例id
* @param businessKeys 业务id
*/
@Log(title = "流程实例管理", businessType = BusinessType.DELETE)
@RepeatSubmit()
@DeleteMapping("/deleteFinishAndHisInstance/{processInstanceIds}")
public R<Void> deleteFinishAndHisInstance(@NotNull(message = "流程实例id不能为空") @PathVariable String[] processInstanceIds) {
return toAjax(actProcessInstanceService.deleteFinishAndHisInstance(Arrays.asList(processInstanceIds)));
@DeleteMapping("/deleteFinishAndHisInstance/{businessKeys}")
public R<Void> deleteFinishAndHisInstance(@NotNull(message = "业务id不能为空") @PathVariable String[] businessKeys) {
return toAjax(actProcessInstanceService.deleteFinishAndHisInstance(Arrays.asList(businessKeys)));
}
/**
* 撤销流程申请
*
* @param processInstanceId 流程实例id
* @param businessKey 业务id
*/
@Log(title = "流程实例管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/cancelProcessApply/{processInstanceId}")
public R<Void> cancelProcessApply(@NotBlank(message = "流程实例id不能为空") @PathVariable String processInstanceId) {
return toAjax(actProcessInstanceService.cancelProcessApply(processInstanceId));
@PostMapping("/cancelProcessApply/{businessKey}")
public R<Void> cancelProcessApply(@NotBlank(message = "业务id不能为空") @PathVariable String businessKey) {
return toAjax(actProcessInstanceService.cancelProcessApply(businessKey));
}
/**

View File

@ -225,7 +225,7 @@ public class ActTaskController extends BaseController {
@RepeatSubmit()
@PostMapping("/backProcess")
public R<String> backProcess(@Validated({AddGroup.class}) @RequestBody BackProcessBo backProcessBo) {
return R.ok(actTaskService.backProcess(backProcessBo));
return R.ok("操作成功", actTaskService.backProcess(backProcessBo));
}
/**
@ -279,7 +279,7 @@ public class ActTaskController extends BaseController {
*/
@GetMapping("/getTaskUserIdsByAddMultiInstance/{taskId}")
public R<String> getTaskUserIdsByAddMultiInstance(@PathVariable String taskId) {
return R.ok(actTaskService.getTaskUserIdsByAddMultiInstance(taskId));
return R.ok("操作成功", actTaskService.getTaskUserIdsByAddMultiInstance(taskId));
}
/**

View File

@ -32,7 +32,7 @@ import java.util.List;
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/leave")
@RequestMapping("/workflow/leave")
public class TestLeaveController extends BaseController {
private final ITestLeaveService testLeaveService;
@ -40,7 +40,7 @@ public class TestLeaveController extends BaseController {
/**
* 查询请假列表
*/
@SaCheckPermission("demo:leave:list")
@SaCheckPermission("workflow:leave:list")
@GetMapping("/list")
public TableDataInfo<TestLeaveVo> list(TestLeaveBo bo, PageQuery pageQuery) {
return testLeaveService.queryPageList(bo, pageQuery);
@ -49,7 +49,7 @@ public class TestLeaveController extends BaseController {
/**
* 导出请假列表
*/
@SaCheckPermission("demo:leave:export")
@SaCheckPermission("workflow:leave:export")
@Log(title = "请假", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(TestLeaveBo bo, HttpServletResponse response) {
@ -62,7 +62,7 @@ public class TestLeaveController extends BaseController {
*
* @param id 主键
*/
@SaCheckPermission("demo:leave:query")
@SaCheckPermission("workflow:leave:query")
@GetMapping("/{id}")
public R<TestLeaveVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
@ -72,7 +72,7 @@ public class TestLeaveController extends BaseController {
/**
* 新增请假
*/
@SaCheckPermission("demo:leave:add")
@SaCheckPermission("workflow:leave:add")
@Log(title = "请假", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
@ -83,7 +83,7 @@ public class TestLeaveController extends BaseController {
/**
* 修改请假
*/
@SaCheckPermission("demo:leave:edit")
@SaCheckPermission("workflow:leave:edit")
@Log(title = "请假", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
@ -96,7 +96,7 @@ public class TestLeaveController extends BaseController {
*
* @param ids 主键串
*/
@SaCheckPermission("demo:leave:remove")
@SaCheckPermission("workflow:leave:remove")
@Log(title = "请假", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")

View File

@ -54,5 +54,10 @@ public class TestLeave extends BaseEntity {
*/
private String remark;
/**
* 状态
*/
private String status;
}

View File

@ -19,10 +19,10 @@ public class ProcessInvalidBo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 流程实例id
* 业务id
*/
@NotBlank(message = "流程实例id不能为空", groups = {AddGroup.class})
private String processInstanceId;
@NotBlank(message = "业务id不能为空", groups = {AddGroup.class})
private String businessKey;
/**
* 作废原因

View File

@ -71,5 +71,10 @@ public class TestLeaveBo extends BaseEntity {
*/
private String remark;
/**
* 状态
*/
private String status;
}

View File

@ -36,6 +36,10 @@ public class ActHistoryInfoVo implements Serializable {
* 流程实例id
*/
private String processInstanceId;
/**
* 版本
*/
private Integer version;
/**
* 开始时间
*/

View File

@ -62,9 +62,9 @@ public class TestLeaveVo implements Serializable {
private String remark;
/**
* 流程实例对象
* 状态
*/
private ProcessInstanceVo processInstanceVo;
@ExcelProperty(value = "状态")
private String status;
}

View File

@ -0,0 +1,48 @@
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 keyNode 流程定义key与流程节点标识(拼接方式流程定义key_流程节点)
* @param taskId 任务id
* @param businessKey 业务id
*/
public void processTaskHandler(String keyNode, String taskId, String businessKey) {
ProcessTaskEvent processTaskEvent = new ProcessTaskEvent();
processTaskEvent.setKeyNode(keyNode);
processTaskEvent.setTaskId(taskId);
processTaskEvent.setBusinessKey(businessKey);
SpringUtils.context().publishEvent(processTaskEvent);
}
}

View File

@ -8,7 +8,6 @@ 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.task.api.TaskQuery;
import org.flowable.variable.api.delegate.VariableScope;
/**

View File

@ -1,73 +0,0 @@
package org.dromara.workflow.flowable.strategy;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.workflow.annotation.FlowListenerAnnotation;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* 流程任务监听策略
*
* @author may
* @date 2023-12-27
*/
@Component
public class FlowEventStrategy implements BeanPostProcessor {
private final Map<String, FlowTaskEventHandler> flowTaskEventHandlers = new HashMap<>();
private final Map<String, FlowProcessEventHandler> flowProcessEventHandlers = new HashMap<>();
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof FlowTaskEventHandler) {
FlowListenerAnnotation annotation = bean.getClass().getAnnotation(FlowListenerAnnotation.class);
if (null != annotation) {
if (StringUtils.isNotBlank(annotation.processDefinitionKey()) && StringUtils.isNotBlank(annotation.taskDefId())) {
String id = annotation.processDefinitionKey() + "_" + annotation.taskDefId();
if (!flowTaskEventHandlers.containsKey(id)) {
flowTaskEventHandlers.put(id, (FlowTaskEventHandler) bean);
}
}
}
}
if (bean instanceof FlowProcessEventHandler) {
FlowListenerAnnotation annotation = bean.getClass().getAnnotation(FlowListenerAnnotation.class);
if (null != annotation) {
if (StringUtils.isNotBlank(annotation.processDefinitionKey()) && StringUtils.isBlank(annotation.taskDefId())) {
if (!flowProcessEventHandlers.containsKey(annotation.processDefinitionKey())) {
flowProcessEventHandlers.put(annotation.processDefinitionKey(), (FlowProcessEventHandler) bean);
}
}
}
}
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
/**
* 获取可执行bean
*
* @param key key
*/
public FlowTaskEventHandler getTaskHandler(String key) {
if (!flowTaskEventHandlers.containsKey(key)) {
return null;
}
return flowTaskEventHandlers.get(key);
}
/**
* 获取可执行bean
*
* @param key key
*/
public FlowProcessEventHandler getProcessHandler(String key) {
if (!flowProcessEventHandlers.containsKey(key)) {
return null;
}
return flowProcessEventHandlers.get(key);
}
}

View File

@ -1,20 +0,0 @@
package org.dromara.workflow.flowable.strategy;
/**
* 流程监听
*
* @author may
* @date 2023-12-27
*/
public interface FlowProcessEventHandler {
/**
* 执行办理任务监听
*
* @param businessKey 业务id
* @param status 状态
* @param submit 当为true时为申请人节点办理
*/
void handleProcess(String businessKey, String status, boolean submit);
}

View File

@ -1,19 +0,0 @@
package org.dromara.workflow.flowable.strategy;
/**
* 流程任务监听
*
* @author may
* @date 2023-12-27
*/
public interface FlowTaskEventHandler {
/**
* 执行办理任务监听
*
* @param taskId 任务ID
* @param businessKey 业务id
*/
void handleTask(String taskId, String businessKey);
}

View File

@ -1,31 +0,0 @@
package org.dromara.workflow.listener;
import lombok.extern.slf4j.Slf4j;
import org.dromara.workflow.annotation.FlowListenerAnnotation;
import org.dromara.workflow.flowable.strategy.FlowProcessEventHandler;
import org.springframework.stereotype.Component;
/**
* 自定义监听测试
*
* @author may
* @date 2023-12-27
*/
@Slf4j
@Component
@FlowListenerAnnotation(processDefinitionKey = "leave1")
public class TestCustomProcessHandler implements FlowProcessEventHandler {
/**
* 执行办理任务监听
*
* @param businessKey 业务id
* @param status 状态
* @param submit 当为true时为申请人节点办理
*/
@Override
public void handleProcess(String businessKey, String status, boolean submit) {
log.info("业务ID:" + businessKey + ",状态:" + status);
}
}

View File

@ -1,23 +0,0 @@
package org.dromara.workflow.listener;
import lombok.extern.slf4j.Slf4j;
import org.dromara.workflow.annotation.FlowListenerAnnotation;
import org.dromara.workflow.flowable.strategy.FlowTaskEventHandler;
import org.springframework.stereotype.Component;
/**
* 自定义监听测试
*
* @author may
* @date 2023-12-27
*/
@Slf4j
@Component
@FlowListenerAnnotation(processDefinitionKey = "leave1", taskDefId = "Activity_14633hx")
public class TestCustomTaskHandler implements FlowTaskEventHandler {
@Override
public void handleTask(String taskId, String businessKey) {
log.info("任务ID:" + taskId + ",业务ID:" + businessKey);
}
}

View File

@ -1,28 +0,0 @@
package org.dromara.workflow.listener;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.workflow.utils.QueryUtils;
import org.flowable.engine.TaskService;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.flowable.task.api.Task;
import org.springframework.stereotype.Component;
/**
* 流程实例监听测试
*
* @author may
* @date 2023-12-12
*/
@Slf4j
@RequiredArgsConstructor
@Component("testLeaveExecutionListener")
public class TestLeaveExecutionListener implements ExecutionListener {
@Override
public void notify(DelegateExecution execution) {
Task task = QueryUtils.taskQuery().executionId(execution.getId()).singleResult();
log.info("执行监听【" + task.getName() + "");
}
}

View File

@ -1,21 +0,0 @@
package org.dromara.workflow.listener;
import lombok.extern.slf4j.Slf4j;
import org.flowable.task.service.delegate.DelegateTask;
import org.flowable.task.service.delegate.TaskListener;
import org.springframework.stereotype.Component;
/**
* 流程任务监听测试
*
* @author may
* @date 2023-12-12
*/
@Slf4j
@Component("testLeaveTaskListener")
public class TestLeaveTaskListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
log.info("执行监听【" + delegateTask.getName() + "");
}
}

View File

@ -20,18 +20,18 @@ public interface IActProcessInstanceService {
/**
* 通过流程实例id获取历史流程图
*
* @param processInstanceId 流程实例id
* @param businessKey 流程实例id
* @return 结果
*/
String getHistoryImage(String processInstanceId);
String getHistoryImage(String businessKey);
/**
* 通过流程实例id获取历史流程图运行中历史等节点
* 通过业务id获取历史流程图运行中历史等节点
*
* @param processInstanceId 流程实例id
* @param businessKey 业务id
* @return 结果
*/
Map<String, Object> getHistoryList(String processInstanceId);
Map<String, Object> getHistoryList(String businessKey);
/**
* 分页查询正在运行的流程实例
@ -54,10 +54,10 @@ public interface IActProcessInstanceService {
/**
* 获取审批记录
*
* @param processInstanceId 流程实例id
* @param businessKey 业务id
* @return 结果
*/
List<ActHistoryInfoVo> getHistoryRecord(String processInstanceId);
List<ActHistoryInfoVo> getHistoryRecord(String businessKey);
/**
* 作废流程实例不会删除历史记录(删除运行中的实例)
@ -70,34 +70,26 @@ public interface IActProcessInstanceService {
/**
* 运行中的实例 删除程实例删除历史记录删除业务与流程关联信息
*
* @param processInstanceIds 流程实例id
* @return 结果
*/
boolean deleteRunAndHisInstance(List<String> processInstanceIds);
/**
* 按照业务id删除 运行中的实例 删除程实例删除历史记录删除业务与流程关联信息
*
* @param businessKeys 业务id
* @return 结果
*/
boolean deleteRunAndHisInstanceByBusinessKeys(List<String> businessKeys);
boolean deleteRunAndHisInstance(List<String> businessKeys);
/**
* 已完成的实例 删除程实例删除历史记录删除业务与流程关联信息
*
* @param processInstanceIds 流程实例id
* @param businessKeys 业务id
* @return 结果
*/
boolean deleteFinishAndHisInstance(List<String> processInstanceIds);
boolean deleteFinishAndHisInstance(List<String> businessKeys);
/**
* 撤销流程申请
*
* @param processInstanceId 流程实例id
* @param businessKey 业务id
* @return 结果
*/
boolean cancelProcessApply(String processInstanceId);
boolean cancelProcessApply(String businessKey);
/**
* 分页查询当前登录人单据

View File

@ -16,7 +16,7 @@ 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.workflow.common.constant.FlowConstant;
import org.dromara.workflow.common.enums.BusinessStatusEnum;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.workflow.common.enums.TaskStatusEnum;
import org.dromara.workflow.domain.ActHiProcinst;
import org.dromara.workflow.domain.bo.ProcessInstanceBo;
@ -26,8 +26,7 @@ import org.dromara.workflow.domain.vo.*;
import org.dromara.workflow.flowable.CustomDefaultProcessDiagramGenerator;
import org.dromara.workflow.flowable.cmd.DeleteExecutionCmd;
import org.dromara.workflow.flowable.cmd.ExecutionChildByExecutionIdCmd;
import org.dromara.workflow.flowable.strategy.FlowEventStrategy;
import org.dromara.workflow.flowable.strategy.FlowProcessEventHandler;
import org.dromara.workflow.flowable.handler.FlowProcessEventHandler;
import org.dromara.workflow.service.IActHiProcinstService;
import org.dromara.workflow.service.IActProcessInstanceService;
import org.dromara.workflow.service.IWfNodeConfigService;
@ -75,9 +74,9 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService
private final TaskService taskService;
private final IActHiProcinstService actHiProcinstService;
private final ManagementService managementService;
private final FlowEventStrategy flowEventStrategy;
private final IWfTaskBackNodeService wfTaskBackNodeService;
private final IWfNodeConfigService wfNodeConfigService;
private final FlowProcessEventHandler flowProcessEventHandler;
@Value("${flowable.activity-font-name}")
private String activityFontName;
@ -184,28 +183,28 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService
}
/**
* 通过流程实例id获取历史流程图
* 通过业务id获取历史流程图
*
* @param processInstanceId 流程实例id
* @param businessKey 业务id
*/
@SneakyThrows
@Override
public String getHistoryImage(String processInstanceId) {
public String getHistoryImage(String businessKey) {
String processDefinitionId;
// 获取当前的流程实例
ProcessInstance processInstance = QueryUtils.instanceQuery(processInstanceId).singleResult();
ProcessInstance processInstance = QueryUtils.businessKeyQuery(businessKey).singleResult();
// 如果流程已经结束则得到结束节点
if (Objects.isNull(processInstance)) {
HistoricProcessInstance pi = QueryUtils.hisInstanceQuery(processInstanceId).singleResult();
HistoricProcessInstance pi = QueryUtils.hisInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
processDefinitionId = pi.getProcessDefinitionId();
} else {
// 根据流程实例ID获得当前处于活动状态的ActivityId合集
ProcessInstance pi = QueryUtils.instanceQuery(processInstanceId).singleResult();
ProcessInstance pi = QueryUtils.instanceQuery(processInstance.getProcessInstanceId()).singleResult();
processDefinitionId = pi.getProcessDefinitionId();
}
// 获得活动的节点
List<HistoricActivityInstance> highLightedFlowList = QueryUtils.hisActivityInstanceQuery(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();
List<HistoricActivityInstance> highLightedFlowList = QueryUtils.hisActivityInstanceQuery(processInstance.getProcessInstanceId()).orderByHistoricActivityInstanceStartTime().asc().list();
List<String> highLightedFlows = new ArrayList<>();
List<String> highLightedNodes = new ArrayList<>();
@ -240,15 +239,16 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService
}
/**
* 通过流程实例id获取历史流程图运行中历史等节点
* 通过业务id获取历史流程图运行中历史等节点
*
* @param processInstanceId 流程实例id
* @param businessKey 业务id
*/
@Override
public Map<String, Object> getHistoryList(String processInstanceId) {
public Map<String, Object> getHistoryList(String businessKey) {
Map<String, Object> map = new HashMap<>();
List<Map<String, Object>> taskList = new ArrayList<>();
HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(processInstanceId).singleResult();
HistoricProcessInstance historicProcessInstance = QueryUtils.hisBusinessKeyQuery(businessKey).singleResult();
String processInstanceId = historicProcessInstance.getId();
StringBuilder xml = new StringBuilder();
ProcessDefinition processDefinition = repositoryService.getProcessDefinition(historicProcessInstance.getProcessDefinitionId());
// 获取节点
@ -280,7 +280,7 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService
}
}
map.put("taskList", taskList);
List<ActHistoryInfoVo> historyTaskList = getHistoryTaskList(processInstanceId);
List<ActHistoryInfoVo> historyTaskList = getHistoryTaskList(processInstanceId, processDefinition.getVersion());
map.put("historyList", historyTaskList);
InputStream inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName());
xml.append(IoUtil.read(inputStream, StandardCharsets.UTF_8));
@ -292,8 +292,9 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService
* 获取历史任务节点信息
*
* @param processInstanceId 流程实例id
* @param version 版本
*/
private List<ActHistoryInfoVo> getHistoryTaskList(String processInstanceId) {
private List<ActHistoryInfoVo> getHistoryTaskList(String processInstanceId, Integer version) {
//查询任务办理记录
List<HistoricTaskInstance> list = QueryUtils.hisTaskInstanceQuery(processInstanceId).orderByHistoricTaskInstanceEndTime().desc().list();
list = StreamUtils.sorted(list, Comparator.comparing(HistoricTaskInstance::getEndTime, Comparator.nullsFirst(Date::compareTo)).reversed());
@ -305,27 +306,48 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService
if (ObjectUtil.isNotEmpty(historicTaskInstance.getDurationInMillis())) {
actHistoryInfoVo.setRunDuration(getDuration(historicTaskInstance.getDurationInMillis()));
}
actHistoryInfoVo.setVersion(version);
actHistoryInfoVoList.add(actHistoryInfoVo);
}
List<ActHistoryInfoVo> historyInfoVoList = new ArrayList<>();
Map<String, List<ActHistoryInfoVo>> groupByKey = StreamUtils.groupByKey(actHistoryInfoVoList, ActHistoryInfoVo::getTaskDefinitionKey);
for (Map.Entry<String, List<ActHistoryInfoVo>> entry : groupByKey.entrySet()) {
ActHistoryInfoVo historyInfoVo = new ActHistoryInfoVo();
BeanUtils.copyProperties(entry.getValue().get(0), historyInfoVo);
actHistoryInfoVoList.stream().filter(e -> e.getTaskDefinitionKey().equals(entry.getKey()) && e.getEndTime() == null).findFirst()
.ifPresent(e -> {
historyInfoVo.setStatus("待处理");
historyInfoVo.setStartTime(e.getStartTime());
historyInfoVo.setEndTime(null);
historyInfoVo.setRunDuration(null);
if (ObjectUtil.isEmpty(e.getAssignee())) {
ParticipantVo participantVo = WorkflowUtils.getCurrentTaskParticipant(e.getId());
if (entry.getValue().size() > 1) {
List<ActHistoryInfoVo> historyInfoVos = StreamUtils.filter(entry.getValue(), e -> StringUtils.isNotBlank(e.getAssignee()));
if (CollUtil.isNotEmpty(historyInfoVos)) {
ActHistoryInfoVo infoVo = historyInfoVos.get(0);
BeanUtils.copyProperties(infoVo, historyInfoVo);
historyInfoVo.setStatus(infoVo.getEndTime() == null ? "待处理" : "已处理");
historyInfoVo.setStartTime(infoVo.getStartTime());
historyInfoVo.setEndTime(infoVo.getEndTime() == null ? null : infoVo.getEndTime());
historyInfoVo.setRunDuration(infoVo.getEndTime() == null ? null : infoVo.getRunDuration());
if (ObjectUtil.isEmpty(infoVo.getAssignee())) {
ParticipantVo participantVo = WorkflowUtils.getCurrentTaskParticipant(infoVo.getId());
if (ObjectUtil.isNotEmpty(participantVo) && CollUtil.isNotEmpty(participantVo.getCandidate())) {
historyInfoVo.setAssignee(StreamUtils.join(participantVo.getCandidate(), Convert::toStr));
}
}
});
}
} else {
actHistoryInfoVoList.stream().filter(e -> e.getTaskDefinitionKey().equals(entry.getKey())).findFirst()
.ifPresent(e -> {
BeanUtils.copyProperties(e, historyInfoVo);
historyInfoVo.setStatus(e.getEndTime() == null ? "待处理" : "已处理");
historyInfoVo.setStartTime(e.getStartTime());
historyInfoVo.setEndTime(e.getEndTime() == null ? null : e.getEndTime());
historyInfoVo.setRunDuration(e.getEndTime() == null ? null : e.getRunDuration());
if (ObjectUtil.isEmpty(e.getAssignee())) {
ParticipantVo participantVo = WorkflowUtils.getCurrentTaskParticipant(e.getId());
if (ObjectUtil.isNotEmpty(participantVo) && CollUtil.isNotEmpty(participantVo.getCandidate())) {
historyInfoVo.setAssignee(StreamUtils.join(participantVo.getCandidate(), Convert::toStr));
}
}
});
}
historyInfoVoList.add(historyInfoVo);
}
return historyInfoVoList;
}
@ -333,13 +355,15 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService
/**
* 获取审批记录
*
* @param processInstanceId 流程实例id
* @param businessKey 业务id
*/
@Override
public List<ActHistoryInfoVo> getHistoryRecord(String processInstanceId) {
public List<ActHistoryInfoVo> getHistoryRecord(String businessKey) {
// 查询任务办理记录
List<HistoricTaskInstance> list = QueryUtils.hisTaskInstanceQuery(processInstanceId).orderByHistoricTaskInstanceEndTime().desc().list();
List<HistoricTaskInstance> list = QueryUtils.hisTaskBusinessKeyQuery(businessKey).orderByHistoricTaskInstanceEndTime().desc().list();
list = StreamUtils.sorted(list, Comparator.comparing(HistoricTaskInstance::getEndTime, Comparator.nullsFirst(Date::compareTo)).reversed());
HistoricProcessInstance historicProcessInstance = QueryUtils.hisBusinessKeyQuery(businessKey).singleResult();
String processInstanceId = historicProcessInstance.getId();
List<ActHistoryInfoVo> actHistoryInfoVoList = new ArrayList<>();
List<Comment> processInstanceComments = taskService.getProcessInstanceComments(processInstanceId);
//附件
@ -440,7 +464,8 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService
@Transactional(rollbackFor = Exception.class)
public boolean deleteRunInstance(ProcessInvalidBo processInvalidBo) {
try {
List<Task> list = QueryUtils.taskQuery(processInvalidBo.getProcessInstanceId()).list();
List<Task> list = QueryUtils.taskQuery().processInstanceBusinessKey(processInvalidBo.getBusinessKey()).list();
String processInstanceId = list.get(0).getProcessInstanceId();
List<Task> subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId()));
if (CollUtil.isNotEmpty(subTasks)) {
subTasks.forEach(e -> taskService.deleteTask(e.getId()));
@ -452,14 +477,13 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService
for (Task task : StreamUtils.filter(list, e -> StringUtils.isBlank(e.getParentTaskId()))) {
taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.INVALID.getStatus(), deleteReason);
}
HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(processInvalidBo.getProcessInstanceId()).singleResult();
HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(processInstanceId).singleResult();
BusinessStatusEnum.checkInvalidStatus(historicProcessInstance.getBusinessStatus());
runtimeService.updateBusinessStatus(processInvalidBo.getProcessInstanceId(), BusinessStatusEnum.INVALID.getStatus());
runtimeService.deleteProcessInstance(processInvalidBo.getProcessInstanceId(), deleteReason);
FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(historicProcessInstance.getProcessDefinitionKey());
if (processHandler != null) {
processHandler.handleProcess(historicProcessInstance.getBusinessKey(), BusinessStatusEnum.INVALID.getStatus(), false);
}
runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.INVALID.getStatus());
runtimeService.deleteProcessInstance(processInstanceId, deleteReason);
//流程作废监听
flowProcessEventHandler.processHandler(historicProcessInstance.getProcessDefinitionKey(),
historicProcessInstance.getBusinessKey(), BusinessStatusEnum.INVALID.getStatus(), false);
return true;
} catch (Exception e) {
e.printStackTrace();
@ -470,40 +494,11 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService
/**
* 运行中的实例 删除程实例删除历史记录删除业务与流程关联信息
*
* @param processInstanceIds 流程实例id
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean deleteRunAndHisInstance(List<String> processInstanceIds) {
try {
// 1.删除运行中流程实例
List<Task> list = QueryUtils.taskQuery(processInstanceIds).list();
List<Task> subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId()));
if (CollUtil.isNotEmpty(subTasks)) {
subTasks.forEach(e -> taskService.deleteTask(e.getId()));
}
runtimeService.bulkDeleteProcessInstances(processInstanceIds, LoginHelper.getUserId() + "删除了当前流程申请");
// 2.删除历史记录
List<HistoricProcessInstance> historicProcessInstanceList = QueryUtils.hisInstanceQuery(new HashSet<>(processInstanceIds)).list();
if (ObjectUtil.isNotEmpty(historicProcessInstanceList)) {
historyService.bulkDeleteHistoricProcessInstances(processInstanceIds);
}
wfTaskBackNodeService.deleteByInstanceIds(processInstanceIds);
return true;
} catch (Exception e) {
e.printStackTrace();
throw new ServiceException(e.getMessage());
}
}
/**
* 按照业务id删除 运行中的实例 删除程实例删除历史记录删除业务与流程关联信息
*
* @param businessKeys 业务id
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean deleteRunAndHisInstanceByBusinessKeys(List<String> businessKeys) {
public boolean deleteRunAndHisInstance(List<String> businessKeys) {
try {
// 1.删除运行中流程实例
List<ActHiProcinst> actHiProcinsts = actHiProcinstService.selectByBusinessKeyIn(businessKeys);
@ -534,12 +529,18 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService
/**
* 已完成的实例 删除程实例删除历史记录删除业务与流程关联信息
*
* @param processInstanceIds 流程实例id
* @param businessKeys 业务id
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean deleteFinishAndHisInstance(List<String> processInstanceIds) {
public boolean deleteFinishAndHisInstance(List<String> businessKeys) {
try {
List<ActHiProcinst> actHiProcinsts = actHiProcinstService.selectByBusinessKeyIn(businessKeys);
if (CollUtil.isEmpty(actHiProcinsts)) {
log.warn("当前业务ID:{}查询到流程实例为空!", businessKeys);
return false;
}
List<String> processInstanceIds = StreamUtils.toList(actHiProcinsts, ActHiProcinst::getId);
historyService.bulkDeleteHistoricProcessInstances(processInstanceIds);
wfTaskBackNodeService.deleteByInstanceIds(processInstanceIds);
return true;
@ -552,13 +553,13 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService
/**
* 撤销流程申请
*
* @param processInstanceId 流程实例id
* @param businessKey 业务id
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean cancelProcessApply(String processInstanceId) {
public boolean cancelProcessApply(String businessKey) {
try {
ProcessInstance processInstance = QueryUtils.instanceQuery(processInstanceId)
ProcessInstance processInstance = QueryUtils.businessKeyQuery(businessKey)
.startedBy(String.valueOf(LoginHelper.getUserId())).singleResult();
if (ObjectUtil.isNull(processInstance)) {
throw new ServiceException("您不是流程发起人,撤销失败!");
@ -566,13 +567,14 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService
if (processInstance.isSuspended()) {
throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
}
String processInstanceId = processInstance.getId();
BusinessStatusEnum.checkCancelStatus(processInstance.getBusinessStatus());
List<Task> taskList = QueryUtils.taskQuery(processInstanceId).list();
for (Task task : taskList) {
taskService.setAssignee(task.getId(), null);
taskService.addComment(task.getId(), processInstanceId, TaskStatusEnum.CANCEL.getStatus(), LoginHelper.getLoginUser().getNickname() + ":撤销申请");
}
HistoricTaskInstance historicTaskInstance = QueryUtils.hisTaskInstanceQuery().finished().orderByHistoricTaskInstanceEndTime().asc().list().get(0);
HistoricTaskInstance historicTaskInstance = QueryUtils.hisTaskInstanceQuery(processInstanceId).finished().orderByHistoricTaskInstanceEndTime().asc().list().get(0);
List<String> nodeIds = StreamUtils.toList(taskList, Task::getTaskDefinitionKey);
runtimeService.createChangeActivityStateBuilder()
.processInstanceId(processInstanceId)
@ -588,10 +590,9 @@ public class ActProcessInstanceServiceImpl implements IActProcessInstanceService
managementService.executeCommand(deleteExecutionCmd);
}
runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.CANCEL.getStatus());
FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(processInstance.getProcessDefinitionKey());
if (processHandler != null) {
processHandler.handleProcess(processInstance.getBusinessKey(), BusinessStatusEnum.CANCEL.getStatus(), false);
}
//流程作废监听
flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(),
processInstance.getBusinessKey(), BusinessStatusEnum.CANCEL.getStatus(), false);
return true;
} catch (Exception e) {
e.printStackTrace();

View File

@ -18,16 +18,14 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.workflow.common.constant.FlowConstant;
import org.dromara.workflow.common.enums.BusinessStatusEnum;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.workflow.common.enums.TaskStatusEnum;
import org.dromara.workflow.domain.ActHiTaskinst;
import org.dromara.workflow.domain.WfTaskBackNode;
import org.dromara.workflow.domain.bo.*;
import org.dromara.workflow.domain.vo.*;
import org.dromara.workflow.flowable.cmd.*;
import org.dromara.workflow.flowable.strategy.FlowEventStrategy;
import org.dromara.workflow.flowable.strategy.FlowProcessEventHandler;
import org.dromara.workflow.flowable.strategy.FlowTaskEventHandler;
import org.dromara.workflow.flowable.handler.FlowProcessEventHandler;
import org.dromara.workflow.mapper.ActHiTaskinstMapper;
import org.dromara.workflow.mapper.ActTaskMapper;
import org.dromara.workflow.service.IActTaskService;
@ -75,13 +73,13 @@ public class ActTaskServiceImpl implements IActTaskService {
private final HistoryService historyService;
private final IdentityService identityService;
private final ManagementService managementService;
private final FlowEventStrategy flowEventStrategy;
private final ActTaskMapper actTaskMapper;
private final IWfTaskBackNodeService wfTaskBackNodeService;
private final ActHiTaskinstMapper actHiTaskinstMapper;
private final IWfNodeConfigService wfNodeConfigService;
private final IWfDefinitionConfigService wfDefinitionConfigService;
private final UserService userService;
private final FlowProcessEventHandler flowProcessEventHandler;
/**
* 启动任务
@ -159,15 +157,8 @@ public class ActTaskServiceImpl implements IActTaskService {
@Transactional(rollbackFor = Exception.class)
public boolean completeTask(CompleteTaskBo completeTaskBo) {
try {
List<RoleDTO> roles = LoginHelper.getLoginUser().getRoles();
String userId = String.valueOf(LoginHelper.getUserId());
TaskQuery taskQuery = QueryUtils.taskQuery();
taskQuery.taskId(completeTaskBo.getTaskId()).taskCandidateOrAssigned(userId);
if (CollUtil.isNotEmpty(roles)) {
List<String> groupIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId()));
taskQuery.taskCandidateGroupIn(groupIds);
}
Task task = taskQuery.singleResult();
Task task = WorkflowUtils.getTaskByCurrentUser(completeTaskBo.getTaskId());
if (task == null) {
throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
}
@ -186,19 +177,15 @@ public class ActTaskServiceImpl implements IActTaskService {
//附件上传
AttachmentCmd attachmentCmd = new AttachmentCmd(completeTaskBo.getFileId(), task.getId(), task.getProcessInstanceId());
managementService.executeCommand(attachmentCmd);
FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(processInstance.getProcessDefinitionKey());
String businessStatus = WorkflowUtils.getBusinessStatus(task.getProcessInstanceId());
String businessStatus = WorkflowUtils.getBusinessStatus(processInstance.getBusinessKey());
//流程提交监听
if (BusinessStatusEnum.DRAFT.getStatus().equals(businessStatus) || BusinessStatusEnum.BACK.getStatus().equals(businessStatus) || BusinessStatusEnum.CANCEL.getStatus().equals(businessStatus)) {
if (processHandler != null) {
processHandler.handleProcess(processInstance.getBusinessKey(), businessStatus, true);
}
flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(), processInstance.getBusinessKey(), businessStatus, true);
}
runtimeService.updateBusinessStatus(task.getProcessInstanceId(), BusinessStatusEnum.WAITING.getStatus());
String key = processInstance.getProcessDefinitionKey() + "_" + task.getTaskDefinitionKey();
FlowTaskEventHandler taskHandler = flowEventStrategy.getTaskHandler(key);
if (taskHandler != null) {
taskHandler.handleTask(task.getId(), processInstance.getBusinessKey());
}
//办理监听
String keyNode = processInstance.getProcessDefinitionKey() + "_" + task.getTaskDefinitionKey();
flowProcessEventHandler.processTaskHandler(keyNode, task.getId(), processInstance.getBusinessKey());
//办理意见
taskService.addComment(completeTaskBo.getTaskId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), StringUtils.isBlank(completeTaskBo.getMessage()) ? "同意" : completeTaskBo.getMessage());
//办理任务
@ -214,9 +201,8 @@ public class ActTaskServiceImpl implements IActTaskService {
if (pi == null) {
UpdateBusinessStatusCmd updateBusinessStatusCmd = new UpdateBusinessStatusCmd(task.getProcessInstanceId(), BusinessStatusEnum.FINISH.getStatus());
managementService.executeCommand(updateBusinessStatusCmd);
if (processHandler != null) {
processHandler.handleProcess(processInstance.getBusinessKey(), BusinessStatusEnum.FINISH.getStatus(), false);
}
flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(), processInstance.getBusinessKey(),
BusinessStatusEnum.FINISH.getStatus(), false);
} else {
List<Task> list = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
for (Task t : list) {
@ -470,8 +456,8 @@ public class ActTaskServiceImpl implements IActTaskService {
@Override
@Transactional(rollbackFor = Exception.class)
public boolean delegateTask(DelegateBo delegateBo) {
TaskQuery query = QueryUtils.taskQuery();
TaskEntity task = (TaskEntity) query.taskId(delegateBo.getTaskId()).taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())).singleResult();
Task task = WorkflowUtils.getTaskByCurrentUser(delegateBo.getTaskId());
if (ObjectUtil.isEmpty(task)) {
throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
}
@ -527,10 +513,9 @@ public class ActTaskServiceImpl implements IActTaskService {
runtimeService.updateBusinessStatus(task.getProcessInstanceId(), BusinessStatusEnum.TERMINATION.getStatus());
runtimeService.deleteProcessInstance(task.getProcessInstanceId(), StrUtil.EMPTY);
}
FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(historicProcessInstance.getProcessDefinitionKey());
if (processHandler != null) {
processHandler.handleProcess(historicProcessInstance.getBusinessKey(), BusinessStatusEnum.TERMINATION.getStatus(), false);
}
//流程终止监听
flowProcessEventHandler.processHandler(historicProcessInstance.getProcessDefinitionKey(),
historicProcessInstance.getBusinessKey(), BusinessStatusEnum.TERMINATION.getStatus(), false);
return true;
} catch (Exception e) {
throw new ServiceException(e.getMessage());
@ -544,7 +529,7 @@ public class ActTaskServiceImpl implements IActTaskService {
*/
@Override
public boolean transferTask(TransmitBo transmitBo) {
Task task = QueryUtils.taskQuery().taskId(transmitBo.getTaskId()).taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId())).singleResult();
Task task = WorkflowUtils.getTaskByCurrentUser(transmitBo.getTaskId());
if (ObjectUtil.isEmpty(task)) {
throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
}
@ -669,9 +654,9 @@ public class ActTaskServiceImpl implements IActTaskService {
@Override
@Transactional(rollbackFor = Exception.class)
public String backProcess(BackProcessBo backProcessBo) {
TaskQuery query = QueryUtils.taskQuery();
String userId = String.valueOf(LoginHelper.getUserId());
Task task = query.taskId(backProcessBo.getTaskId()).taskCandidateOrAssigned(userId).singleResult();
Task task = WorkflowUtils.getTaskByCurrentUser(backProcessBo.getTaskId());
if (ObjectUtil.isEmpty(task)) {
throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
}
@ -705,7 +690,9 @@ public class ActTaskServiceImpl implements IActTaskService {
MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
if (multiInstance == null && taskList.size() > 1) {
List<Task> tasks = StreamUtils.filter(taskList, e -> !e.getTaskDefinitionKey().equals(task.getTaskDefinitionKey()));
actHiTaskinstMapper.deleteBatchIds(StreamUtils.toList(tasks, Task::getId));
if (CollUtil.isNotEmpty(tasks)) {
actHiTaskinstMapper.deleteBatchIds(StreamUtils.toList(tasks, Task::getId));
}
}
@ -728,10 +715,8 @@ public class ActTaskServiceImpl implements IActTaskService {
WfTaskBackNode wfTaskBackNode = wfTaskBackNodeService.getListByInstanceIdAndNodeId(task.getProcessInstanceId(), backProcessBo.getTargetActivityId());
if (ObjectUtil.isNotNull(wfTaskBackNode) && wfTaskBackNode.getOrderNo() == 0) {
runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.BACK.getStatus());
FlowProcessEventHandler processHandler = flowEventStrategy.getProcessHandler(processInstance.getProcessDefinitionKey());
if (processHandler != null) {
processHandler.handleProcess(processInstance.getBusinessKey(), BusinessStatusEnum.BACK.getStatus(), false);
}
flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(),
processInstance.getBusinessKey(), BusinessStatusEnum.BACK.getStatus(), false);
}
//删除驳回后的流程节点
wfTaskBackNodeService.deleteBackTaskNode(processInstanceId, backProcessBo.getTargetActivityId());

View File

@ -1,10 +1,14 @@
package org.dromara.workflow.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.event.ProcessEvent;
import org.dromara.common.core.domain.event.ProcessTaskEvent;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.common.core.service.WorkflowService;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
@ -15,9 +19,8 @@ import org.dromara.workflow.domain.TestLeave;
import org.dromara.workflow.domain.bo.TestLeaveBo;
import org.dromara.workflow.domain.vo.TestLeaveVo;
import org.dromara.workflow.mapper.TestLeaveMapper;
import org.dromara.workflow.service.IActProcessInstanceService;
import org.dromara.workflow.service.ITestLeaveService;
import org.dromara.workflow.utils.WorkflowUtils;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -32,19 +35,18 @@ import java.util.List;
*/
@RequiredArgsConstructor
@Service
@Slf4j
public class TestLeaveServiceImpl implements ITestLeaveService {
private final TestLeaveMapper baseMapper;
private final IActProcessInstanceService actProcessInstanceService;
private final WorkflowService workflowService;
/**
* 查询请假
*/
@Override
public TestLeaveVo queryById(Long id) {
TestLeaveVo testLeaveVo = baseMapper.selectVoById(id);
WorkflowUtils.setProcessInstanceVo(testLeaveVo, String.valueOf(id));
return testLeaveVo;
return baseMapper.selectVoById(id);
}
/**
@ -54,13 +56,7 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
public TableDataInfo<TestLeaveVo> queryPageList(TestLeaveBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<TestLeave> lqw = buildQueryWrapper(bo);
Page<TestLeaveVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
TableDataInfo<TestLeaveVo> build = TableDataInfo.build(result);
List<TestLeaveVo> rows = build.getRows();
if (CollUtil.isNotEmpty(rows)) {
List<String> ids = StreamUtils.toList(rows, e -> String.valueOf(e.getId()));
WorkflowUtils.setProcessInstanceListVo(rows, ids, "id");
}
return build;
return TableDataInfo.build(result);
}
/**
@ -87,13 +83,14 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
@Override
public TestLeaveVo insertByBo(TestLeaveBo bo) {
TestLeave add = MapstructUtils.convert(bo, TestLeave.class);
if (StringUtils.isBlank(add.getStatus())) {
add.setStatus(BusinessStatusEnum.DRAFT.getStatus());
}
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
TestLeaveVo testLeaveVo = MapstructUtils.convert(add, TestLeaveVo.class);
WorkflowUtils.setProcessInstanceVo(testLeaveVo, String.valueOf(add.getId()));
return testLeaveVo;
return MapstructUtils.convert(add, TestLeaveVo.class);
}
/**
@ -103,9 +100,7 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
public TestLeaveVo updateByBo(TestLeaveBo bo) {
TestLeave update = MapstructUtils.convert(bo, TestLeave.class);
baseMapper.updateById(update);
TestLeaveVo testLeaveVo = MapstructUtils.convert(update, TestLeaveVo.class);
WorkflowUtils.setProcessInstanceVo(testLeaveVo, String.valueOf(update.getId()));
return testLeaveVo;
return MapstructUtils.convert(update, TestLeaveVo.class);
}
/**
@ -115,7 +110,38 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
@Transactional(rollbackFor = Exception.class)
public Boolean deleteWithValidByIds(Collection<Long> ids) {
List<String> idList = StreamUtils.toList(ids, String::valueOf);
actProcessInstanceService.deleteRunAndHisInstanceByBusinessKeys(idList);
workflowService.deleteRunAndHisInstance(idList);
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 总体流程监听(例如: 提交 退回 撤销 终止 作废等)
*
* @param processEvent 参数
*/
@EventListener(condition = "#processEvent.key=='leave1'")
public void processHandler(ProcessEvent processEvent) {
log.info("当前任务执行了{}", processEvent.toString());
TestLeave testLeave = baseMapper.selectById(Long.valueOf(processEvent.getBusinessKey()));
testLeave.setStatus(processEvent.getStatus());
if (processEvent.isSubmit()) {
testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus());
}
baseMapper.updateById(testLeave);
}
/**
* 执行办理任务监听
*
* @param processTaskEvent 参数
*/
@EventListener(condition = "#processTaskEvent.keyNode=='leave1_Activity_14633hx'")
public void processTaskHandler(ProcessTaskEvent processTaskEvent) {
log.info("当前任务执行了{}", processTaskEvent.toString());
TestLeave testLeave = baseMapper.selectById(Long.valueOf(processTaskEvent.getBusinessKey()));
testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus());
baseMapper.updateById(testLeave);
}
}

View File

@ -0,0 +1,119 @@
package org.dromara.workflow.service.impl;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.service.WorkflowService;
import org.dromara.workflow.domain.ActHiProcinst;
import org.dromara.workflow.service.IActHiProcinstService;
import org.dromara.workflow.service.IActProcessInstanceService;
import org.dromara.workflow.utils.WorkflowUtils;
import org.flowable.engine.RuntimeService;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
/**
* 通用 工作流服务实现
*
* @author may
*/
@RequiredArgsConstructor
@Service
public class WorkflowServiceImpl implements WorkflowService {
private final IActProcessInstanceService iActProcessInstanceService;
private final RuntimeService runtimeService;
private final IActHiProcinstService iActHiProcinstService;
/**
* 运行中的实例 删除程实例删除历史记录删除业务与流程关联信息
*
* @param businessKeys 业务id
* @return 结果
*/
@Override
public boolean deleteRunAndHisInstance(List<String> businessKeys) {
return iActProcessInstanceService.deleteRunAndHisInstance(businessKeys);
}
/**
* 获取当前流程状态
*
* @param taskId 任务id
*/
@Override
public String getBusinessStatusByTaskId(String taskId) {
return WorkflowUtils.getBusinessStatusByTaskId(taskId);
}
/**
* 获取当前流程状态
*
* @param businessKey 业务id
*/
@Override
public String getBusinessStatus(String businessKey) {
return WorkflowUtils.getBusinessStatus(businessKey);
}
/**
* 设置流程变量(全局变量)
*
* @param taskId 任务id
* @param variableName 变量名称
* @param value 变量值
*/
@Override
public void setVariable(String taskId, String variableName, Object value) {
runtimeService.setVariable(taskId, variableName, value);
}
/**
* 设置流程变量(全局变量)
*
* @param taskId 任务id
* @param variables 流程变量
*/
@Override
public void setVariables(String taskId, Map<String, Object> variables) {
runtimeService.setVariables(taskId, variables);
}
/**
* 设置流程变量(本地变量,非全局变量)
*
* @param taskId 任务id
* @param variableName 变量名称
* @param value 变量值
*/
@Override
public void setVariableLocal(String taskId, String variableName, Object value) {
runtimeService.setVariableLocal(taskId, variableName, value);
}
/**
* 设置流程变量(本地变量,非全局变量)
*
* @param taskId 任务id
* @param variables 流程变量
*/
@Override
public void setVariablesLocal(String taskId, Map<String, Object> variables) {
runtimeService.setVariablesLocal(taskId, variables);
}
/**
* 按照业务id查询流程实例id
*
* @param businessKey 业务id
* @return 结果
*/
@Override
public String getInstanceIdByBusinessKey(String businessKey) {
ActHiProcinst actHiProcinst = iActHiProcinstService.selectByBusinessKey(businessKey);
if (actHiProcinst == null) {
return StrUtil.EMPTY;
}
return actHiProcinst.getId();
}
}

View File

@ -12,6 +12,7 @@ import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.repository.DeploymentQuery;
import org.flowable.engine.repository.ModelQuery;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.runtime.ProcessInstanceQuery;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
@ -75,6 +76,10 @@ public class QueryUtils {
return hisTaskInstanceQuery().processInstanceId(processInstanceId);
}
public static HistoricTaskInstanceQuery hisTaskBusinessKeyQuery(String businessKey) {
return hisTaskInstanceQuery().processInstanceBusinessKey(businessKey);
}
public static ProcessInstanceQuery instanceQuery() {
ProcessInstanceQuery query = PROCESS_ENGINE.getRuntimeService().createProcessInstanceQuery();
if (TenantHelper.isEnable()) {
@ -87,6 +92,10 @@ public class QueryUtils {
return instanceQuery().processInstanceId(processInstanceId);
}
public static ProcessInstanceQuery businessKeyQuery(String businessKey) {
return instanceQuery().processInstanceBusinessKey(businessKey);
}
public static ProcessInstanceQuery instanceQuery(Set<String> processInstanceIds) {
return instanceQuery().processInstanceIds(processInstanceIds);
}
@ -103,6 +112,10 @@ public class QueryUtils {
return hisInstanceQuery().processInstanceId(processInstanceId);
}
public static HistoricProcessInstanceQuery hisBusinessKeyQuery(String businessKey) {
return hisInstanceQuery().processInstanceBusinessKey(businessKey);
}
public static HistoricProcessInstanceQuery hisInstanceQuery(Set<String> processInstanceIds) {
return hisInstanceQuery().processInstanceIds(processInstanceIds);
}
@ -145,9 +158,11 @@ public class QueryUtils {
if (task == null) {
return null;
}
ProcessInstance processInstance = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult();
TaskVo taskVo = BeanUtil.toBean(task, TaskVo.class);
taskVo.setBusinessKey(processInstance.getBusinessKey());
taskVo.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null);
String businessStatus = WorkflowUtils.getBusinessStatus(taskVo.getProcessInstanceId());
String businessStatus = WorkflowUtils.getBusinessStatus(taskVo.getBusinessKey());
taskVo.setBusinessStatus(businessStatus);
return taskVo;
}

View File

@ -1,34 +1,30 @@
package org.dromara.workflow.utils;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.dromara.common.core.domain.dto.RoleDTO;
import org.dromara.common.core.domain.dto.UserDTO;
import org.dromara.common.core.service.UserService;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.reflect.ReflectUtils;
import org.dromara.common.mail.utils.MailUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.common.websocket.dto.WebSocketMessageDto;
import org.dromara.common.websocket.utils.WebSocketUtils;
import org.dromara.workflow.common.constant.FlowConstant;
import org.dromara.workflow.common.enums.BusinessStatusEnum;
import org.dromara.workflow.common.enums.MessageTypeEnum;
import org.dromara.workflow.common.enums.TaskStatusEnum;
import org.dromara.workflow.domain.ActHiProcinst;
import org.dromara.workflow.domain.ActHiTaskinst;
import org.dromara.workflow.domain.vo.MultiInstanceVo;
import org.dromara.workflow.domain.vo.ParticipantVo;
import org.dromara.workflow.domain.vo.ProcessInstanceVo;
import org.dromara.workflow.flowable.cmd.UpdateHiTaskInstCmd;
import org.dromara.workflow.mapper.ActHiTaskinstMapper;
import org.dromara.workflow.service.IActHiProcinstService;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.common.engine.api.delegate.Expression;
@ -38,13 +34,12 @@ import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
import org.flowable.identitylink.api.history.HistoricIdentityLink;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import java.util.*;
import static org.dromara.workflow.common.constant.FlowConstant.PROCESS_INSTANCE_VO;
/**
* 工作流工具
*
@ -54,8 +49,6 @@ import static org.dromara.workflow.common.constant.FlowConstant.PROCESS_INSTANCE
public class WorkflowUtils {
private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class);
private static final UserService USER_SERVICE = SpringUtils.getBean(UserService.class);
private static final IActHiProcinstService ACT_HI_PROCINST_SERVICE = SpringUtils.getBean(IActHiProcinstService.class);
private static final ActHiTaskinstMapper ACT_HI_TASKINST_MAPPER = SpringUtils.getBean(ActHiTaskinstMapper.class);
/**
@ -133,6 +126,7 @@ public class WorkflowUtils {
* @param taskId 任务id
*/
public static ParticipantVo getCurrentTaskParticipant(String taskId) {
UserService userService = SpringUtils.getBean(UserService.class);
ParticipantVo participantVo = new ParticipantVo();
List<HistoricIdentityLink> linksForTask = PROCESS_ENGINE.getHistoryService().getHistoricIdentityLinksForTask(taskId);
Task task = QueryUtils.taskQuery().taskId(taskId).singleResult();
@ -140,10 +134,10 @@ public class WorkflowUtils {
List<HistoricIdentityLink> groupList = StreamUtils.filter(linksForTask, e -> StringUtils.isNotBlank(e.getGroupId()));
if (CollUtil.isNotEmpty(groupList)) {
List<Long> groupIds = StreamUtils.toList(groupList, e -> Long.valueOf(e.getGroupId()));
List<Long> userIds = USER_SERVICE.selectUserIdsByRoleIds(groupIds);
List<Long> userIds = userService.selectUserIdsByRoleIds(groupIds);
if (CollUtil.isNotEmpty(userIds)) {
participantVo.setGroupIds(groupIds);
List<UserDTO> userList = USER_SERVICE.selectListByIds(userIds);
List<UserDTO> userList = userService.selectListByIds(userIds);
if (CollUtil.isNotEmpty(userList)) {
List<Long> userIdList = StreamUtils.toList(userList, UserDTO::getUserId);
List<String> nickNames = StreamUtils.toList(userList, UserDTO::getNickName);
@ -162,7 +156,7 @@ public class WorkflowUtils {
}
}
List<UserDTO> userList = USER_SERVICE.selectListByIds(userIdList);
List<UserDTO> userList = userService.selectListByIds(userIdList);
if (CollUtil.isNotEmpty(userList)) {
List<Long> userIds = StreamUtils.toList(userList, UserDTO::getUserId);
List<String> nickNames = StreamUtils.toList(userList, UserDTO::getNickName);
@ -225,70 +219,11 @@ public class WorkflowUtils {
/**
* 获取当前流程状态
*
* @param processInstanceId 流程实例id
*/
public static String getBusinessStatus(String processInstanceId) {
HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(processInstanceId).singleResult();
return historicProcessInstance.getBusinessStatus();
}
/**
* 设置流程实例对象
*
* @param obj 业务对象
* @param businessKey 业务id
*/
public static void setProcessInstanceVo(Object obj, String businessKey) {
if (StringUtils.isBlank(businessKey) || obj == null) {
return;
}
ActHiProcinst actHiProcinst = ACT_HI_PROCINST_SERVICE.selectByBusinessKey(businessKey);
if (actHiProcinst == null) {
ProcessInstanceVo processInstanceVo = new ProcessInstanceVo();
processInstanceVo.setBusinessStatus(BusinessStatusEnum.DRAFT.getStatus());
ReflectUtils.invokeSetter(obj, PROCESS_INSTANCE_VO, processInstanceVo);
return;
}
ProcessInstanceVo processInstanceVo = BeanUtil.toBean(actHiProcinst, ProcessInstanceVo.class);
processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstanceVo.getBusinessStatus()));
ReflectUtils.invokeSetter(obj, PROCESS_INSTANCE_VO, processInstanceVo);
}
/**
* 设置流程实例对象
*
* @param obj 业务对象
* @param idList 业务id
* @param fieldName 主键属性名称
*/
public static void setProcessInstanceListVo(Object obj, List<String> idList, String fieldName) {
if (CollUtil.isEmpty(idList) || obj == null) {
return;
}
List<ActHiProcinst> actHiProcinstList = ACT_HI_PROCINST_SERVICE.selectByBusinessKeyIn(idList);
if (obj instanceof Collection<?> collection) {
for (Object o : collection) {
String fieldValue = ReflectUtils.invokeGetter(o, fieldName).toString();
if (CollUtil.isEmpty(actHiProcinstList)) {
ProcessInstanceVo processInstanceVo = new ProcessInstanceVo();
processInstanceVo.setBusinessStatus(BusinessStatusEnum.DRAFT.getStatus());
processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstanceVo.getBusinessStatus()));
ReflectUtils.invokeSetter(o, PROCESS_INSTANCE_VO, processInstanceVo);
} else {
ActHiProcinst actHiProcinst = actHiProcinstList.stream().filter(e -> e.getBusinessKey().equals(fieldValue)).findFirst().orElse(null);
if (ObjectUtil.isNotEmpty(actHiProcinst)) {
ProcessInstanceVo processInstanceVo = BeanUtil.toBean(actHiProcinst, ProcessInstanceVo.class);
processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstanceVo.getBusinessStatus()));
ReflectUtils.invokeSetter(o, PROCESS_INSTANCE_VO, processInstanceVo);
} else {
ProcessInstanceVo processInstanceVo = new ProcessInstanceVo();
processInstanceVo.setBusinessStatus(BusinessStatusEnum.DRAFT.getStatus());
processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstanceVo.getBusinessStatus()));
ReflectUtils.invokeSetter(o, PROCESS_INSTANCE_VO, processInstanceVo);
}
}
}
}
public static String getBusinessStatus(String businessKey) {
HistoricProcessInstance historicProcessInstance = QueryUtils.hisBusinessKeyQuery(businessKey).singleResult();
return historicProcessInstance.getBusinessStatus();
}
/**
@ -300,6 +235,7 @@ public class WorkflowUtils {
* @param message 消息内容为空则发送默认配置的消息内容
*/
public static void sendMessage(List<Task> list, String name, List<String> messageType, String message) {
UserService userService = SpringUtils.getBean(UserService.class);
Set<Long> userIds = new HashSet<>();
if (StringUtils.isBlank(message)) {
message = "有新的【" + name + "】单据已经提交至您的待办,请您及时处理。";
@ -307,7 +243,7 @@ public class WorkflowUtils {
for (Task t : list) {
ParticipantVo taskParticipant = WorkflowUtils.getCurrentTaskParticipant(t.getId());
if (CollUtil.isNotEmpty(taskParticipant.getGroupIds())) {
List<Long> userIdList = USER_SERVICE.selectUserIdsByRoleIds(taskParticipant.getGroupIds());
List<Long> userIdList = userService.selectUserIdsByRoleIds(taskParticipant.getGroupIds());
if (CollUtil.isNotEmpty(userIdList)) {
userIds.addAll(userIdList);
}
@ -318,7 +254,7 @@ public class WorkflowUtils {
}
}
if (CollUtil.isNotEmpty(userIds)) {
List<UserDTO> userList = USER_SERVICE.selectListByIds(new ArrayList<>(userIds));
List<UserDTO> userList = userService.selectListByIds(new ArrayList<>(userIds));
for (String code : messageType) {
MessageTypeEnum messageTypeEnum = MessageTypeEnum.getByCode(code);
if (ObjectUtil.isNotEmpty(messageTypeEnum)) {
@ -340,4 +276,22 @@ public class WorkflowUtils {
}
}
}
/**
* 根据任务id查询 当前用户的任务检查 当前人员 是否是该 taskId 的办理人
*
* @param taskId 任务id
* @return 结果
*/
public static Task getTaskByCurrentUser(String taskId) {
TaskQuery taskQuery = QueryUtils.taskQuery();
taskQuery.taskId(taskId).taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId()));
List<RoleDTO> roles = LoginHelper.getLoginUser().getRoles();
if (CollUtil.isNotEmpty(roles)) {
List<String> groupIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId()));
taskQuery.taskCandidateGroupIn(groupIds);
}
return taskQuery.singleResult();
}
}

Binary file not shown.

View File

@ -27,6 +27,7 @@ create table test_leave
end_date datetime not null comment '结束时间',
leave_days int(10) not null comment '请假天数',
remark varchar(255) null comment '请假原因',
status varchar(255) null comment '状态',
create_dept bigint null comment '创建部门',
create_by bigint null comment '创建者',
create_time datetime null comment '创建时间',
@ -112,7 +113,7 @@ create table wf_form_manage
)
comment '表单管理';
insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/demo/leaveEdit/index', NULL, '000000', 103, 1, sysdate(), 1, sysdate());
insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/workflow/leaveEdit/index', NULL, '000000', 103, 1, sysdate(), 1, sysdate());
create table wf_node_config
(
@ -134,12 +135,12 @@ create table wf_node_config
comment '节点配置';
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'demo:leave:list', '#', 103, 1, sysdate(), NULL, NULL, '请假申请菜单');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:query', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:add', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:edit', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:remove', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:export', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, sysdate(), NULL, NULL, '请假申请菜单');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, sysdate(), NULL, NULL, '');
INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '业务状态', 'wf_business_status', 103, 1, sysdate(), NULL, NULL, '业务状态列表');
INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '表单类型', 'wf_form_type', 103, 1, sysdate(), NULL, NULL, '表单类型列表');

View File

@ -30,6 +30,7 @@ create table TEST_LEAVE
END_DATE DATE,
LEAVE_DAYS NUMBER(10),
REMARK VARCHAR2(255),
STATUS VARCHAR2(255),
CREATE_DEPT NUMBER(20),
CREATE_BY NUMBER(20),
CREATE_TIME DATE,
@ -45,6 +46,7 @@ comment on column TEST_LEAVE.START_DATE is '开始时间';
comment on column TEST_LEAVE.END_DATE is '结束时间';
comment on column TEST_LEAVE.LEAVE_DAYS is '请假天数';
comment on column TEST_LEAVE.REMARK is '请假原因';
comment on column TEST_LEAVE.STATUS is '状态';
comment on column TEST_LEAVE.CREATE_DEPT is '创建部门';
comment on column TEST_LEAVE.CREATE_BY is '创建者';
comment on column TEST_LEAVE.CREATE_TIME is '创建时间';
@ -182,7 +184,7 @@ comment on column WF_FORM_MANAGE.CREATE_TIME is '创建时间';
comment on column WF_FORM_MANAGE.UPDATE_BY is '更新者';
comment on column WF_FORM_MANAGE.UPDATE_TIME is '更新时间';
insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/demo/leaveEdit/index', NULL, '000000', 103, 1, sysdate, 1, sysdate);
insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/workflow/leaveEdit/index', NULL, '000000', 103, 1, sysdate, 1, sysdate);
create table WF_NODE_CONFIG
(
@ -218,12 +220,12 @@ comment on column WF_NODE_CONFIG.CREATE_TIME is '创建时间';
comment on column WF_NODE_CONFIG.UPDATE_BY is '更新者';
comment on column WF_NODE_CONFIG.UPDATE_TIME is '更新时间';
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'demo:leave:list', '#', 103, 1, sysdate, NULL, NULL, '请假申请菜单');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:query', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:add', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:edit', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:remove', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:export', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, sysdate, NULL, NULL, '请假申请菜单');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, sysdate, NULL, NULL, '');
INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '业务状态', 'wf_business_status', 103, 1, sysdate, NULL, NULL, '业务状态列表');
INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '表单类型', 'wf_form_type', 103, 1, sysdate, NULL, NULL, '表单类型列表');

View File

@ -443,7 +443,6 @@ insert into sys_menu values('107', '通知公告', '1', '8', 'notice',
insert into sys_menu values('108', '日志管理', '1', '9', 'log', '', '', 1, 0, 'M', '0', '0', '', 'log', 103, 1, sysdate, null, null, '日志管理菜单');
insert into sys_menu values('109', '在线用户', '2', '1', 'online', 'monitor/online/index', '', 1, 0, 'C', '0', '0', 'monitor:online:list', 'online', 103, 1, sysdate, null, null, '在线用户菜单');
insert into sys_menu values('113', '缓存监控', '2', '5', 'cache', 'monitor/cache/index', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis', 103, 1, sysdate, null, null, '缓存监控菜单');
insert into sys_menu values('114', '表单构建', '3', '1', 'build', 'tool/build/index', '', 1, 0, 'C', '0', '0', 'tool:build:list', 'build', 103, 1, sysdate, null, null, '表单构建菜单');
insert into sys_menu values('115', '代码生成', '3', '2', 'gen', 'tool/gen/index', '', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 103, 1, sysdate, null, null, '代码生成菜单');
insert into sys_menu values('121', '租户管理', '6', '1', 'tenant', 'system/tenant/index', '', 1, 0, 'C', '0', '0', 'system:tenant:list', 'list', 103, 1, sysdate, null, null, '租户管理菜单');
insert into sys_menu values('122', '租户套餐管理', '6', '2', 'tenantPackage', 'system/tenantPackage/index', '', 1, 0, 'C', '0', '0', 'system:tenantPackage:list', 'form', 103, 1, sysdate, null, null, '租户套餐管理菜单');

View File

@ -29,6 +29,7 @@ create table test_leave
end_date timestamp,
leave_days bigint,
remark varchar(255),
status varchar(255),
create_dept bigint,
create_by bigint,
create_time timestamp,
@ -49,6 +50,8 @@ comment on column test_leave.end_date is '结束时间';
comment on column test_leave.remark is '请假原因';
comment on column test_leave.status is '状态';
comment on column test_leave.create_dept is '创建部门';
comment on column test_leave.create_by is '创建者';
@ -251,7 +254,7 @@ comment on column wf_form_manage.update_by is '修改者';
comment on column wf_form_manage.update_time is '修改时间';
insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/demo/leaveEdit/index', NULL, '000000', 103, 1, now(), 1, now());
insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/workflow/leaveEdit/index', NULL, '000000', 103, 1, now(), 1, now());
create table wf_node_config
(
@ -300,12 +303,12 @@ comment on column wf_node_config.update_by is '修改者';
comment on column wf_node_config.update_time is '修改时间';
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'demo:leave:list', '#', 103, 1, now(), NULL, NULL, '请假申请菜单');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:query', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:add', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:edit', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:remove', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:export', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, now(), NULL, NULL, '请假申请菜单');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, now(), NULL, NULL, '');
INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '业务状态', 'wf_business_status', 103, 1, now(), NULL, NULL, '业务状态列表');
INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '表单类型', 'wf_form_type', 103, 1, now(), NULL, NULL, '表单类型列表');

View File

@ -444,7 +444,6 @@ insert into sys_menu values('107', '通知公告', '1', '8', 'notice',
insert into sys_menu values('108', '日志管理', '1', '9', 'log', '', '', '1', '0', 'M', '0', '0', '', 'log', 103, 1, now(), null, null, '日志管理菜单');
insert into sys_menu values('109', '在线用户', '2', '1', 'online', 'monitor/online/index', '', '1', '0', 'C', '0', '0', 'monitor:online:list', 'online', 103, 1, now(), null, null, '在线用户菜单');
insert into sys_menu values('113', '缓存监控', '2', '5', 'cache', 'monitor/cache/index', '', '1', '0', 'C', '0', '0', 'monitor:cache:list', 'redis', 103, 1, now(), null, null, '缓存监控菜单');
insert into sys_menu values('114', '表单构建', '3', '1', 'build', 'tool/build/index', '', '1', '0', 'C', '0', '0', 'tool:build:list', 'build', 103, 1, now(), null, null, '表单构建菜单');
insert into sys_menu values('115', '代码生成', '3', '2', 'gen', 'tool/gen/index', '', '1', '0', 'C', '0', '0', 'tool:gen:list', 'code', 103, 1, now(), null, null, '代码生成菜单');
insert into sys_menu values('121', '租户管理', '6', '1', 'tenant', 'system/tenant/index', '', '1', '0', 'C', '0', '0', 'system:tenant:list', 'list', 103, 1, now(), null, null, '租户管理菜单');
insert into sys_menu values('122', '租户套餐管理', '6', '2', 'tenantPackage', 'system/tenantPackage/index', '', '1', '0', 'C', '0', '0', 'system:tenantPackage:list', 'form', 103, 1, now(), null, null, '租户套餐管理菜单');

View File

@ -278,7 +278,6 @@ insert into sys_menu values('107', '通知公告', '1', '8', 'notice',
insert into sys_menu values('108', '日志管理', '1', '9', 'log', '', '', 1, 0, 'M', '0', '0', '', 'log', 103, 1, sysdate(), null, null, '日志管理菜单');
insert into sys_menu values('109', '在线用户', '2', '1', 'online', 'monitor/online/index', '', 1, 0, 'C', '0', '0', 'monitor:online:list', 'online', 103, 1, sysdate(), null, null, '在线用户菜单');
insert into sys_menu values('113', '缓存监控', '2', '5', 'cache', 'monitor/cache/index', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis', 103, 1, sysdate(), null, null, '缓存监控菜单');
insert into sys_menu values('114', '表单构建', '3', '1', 'build', 'tool/build/index', '', 1, 0, 'C', '0', '0', 'tool:build:list', 'build', 103, 1, sysdate(), null, null, '表单构建菜单');
insert into sys_menu values('115', '代码生成', '3', '2', 'gen', 'tool/gen/index', '', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 103, 1, sysdate(), null, null, '代码生成菜单');
insert into sys_menu values('121', '租户管理', '6', '1', 'tenant', 'system/tenant/index', '', 1, 0, 'C', '0', '0', 'system:tenant:list', 'list', 103, 1, sysdate(), null, null, '租户管理菜单');
insert into sys_menu values('122', '租户套餐管理', '6', '2', 'tenantPackage', 'system/tenantPackage/index', '', 1, 0, 'C', '0', '0', 'system:tenantPackage:list', 'form', 103, 1, sysdate(), null, null, '租户套餐管理菜单');

View File

@ -28,6 +28,7 @@ create table test_leave
end_date datetime2 not null,
leave_days int not null,
remark nvarchar(255),
status nvarchar(255),
create_dept bigint,
create_by bigint,
create_time datetime2,
@ -61,6 +62,9 @@ go
exec sp_addextendedproperty 'MS_Description', N'请假原因', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'remark'
go
exec sp_addextendedproperty 'MS_Description', N'状态', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'status'
go
exec sp_addextendedproperty 'MS_Description', N'创建部门', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN',
'create_dept'
go
@ -221,6 +225,7 @@ create table wf_definition_config
unique,
process_key nvarchar(255) not null,
version bigint not null,
remark nvarchar(500) DEFAULT ('') null,
tenant_id nvarchar(20),
create_dept bigint,
create_by bigint,
@ -252,6 +257,10 @@ exec sp_addextendedproperty 'MS_Description', N'流程版本', 'SCHEMA', 'dbo',
'version'
go
exec sp_addextendedproperty 'MS_Description', N'备注', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
'remark'
go
exec sp_addextendedproperty 'MS_Description', N'租户编号', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
'tenant_id'
go
@ -334,7 +343,7 @@ exec sp_addextendedproperty 'MS_Description', N'更新时间', 'SCHEMA', 'dbo',
'update_time'
go
insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/demo/leaveEdit/index', NULL, '000000', 103, 1, getdate(), 1, getdate());
insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '请假申请', 'static', '/workflow/leaveEdit/index', NULL, '000000', 103, 1, getdate(), 1, getdate());
create table wf_node_config
(
@ -406,12 +415,12 @@ exec sp_addextendedproperty 'MS_Description', N'更新时间', 'SCHEMA', 'dbo',
'update_time'
go
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'demo:leave:list', '#', 103, 1, getdate(), NULL, NULL, '请假申请菜单');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:query', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:add', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:edit', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:remove', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'demo:leave:export', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, getdate(), NULL, NULL, '请假申请菜单');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '请假申请查询', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '请假申请新增', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '请假申请修改', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '请假申请删除', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '请假申请导出', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, getdate(), NULL, NULL, '');
INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '业务状态', 'wf_business_status', 103, 1, getdate(), NULL, NULL, '业务状态列表');
INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '表单类型', 'wf_form_type', 103, 1, getdate(), NULL, NULL, '表单类型列表');

View File

@ -1678,8 +1678,6 @@ INSERT sys_menu VALUES (109, N'在线用户', 2, 1, N'online', N'monitor/online/
GO
INSERT sys_menu VALUES (113, N'缓存监控', 2, 5, N'cache', N'monitor/cache/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:cache:list', N'redis', 103, 1, getdate(), NULL, NULL, N'缓存监控菜单')
GO
INSERT sys_menu VALUES (114, N'表单构建', 3, 1, N'build', N'tool/build/index', N'', 1, 0, N'C', N'0', N'0', N'tool:build:list', N'build', 103, 1, getdate(), NULL, NULL, N'表单构建菜单')
GO
INSERT sys_menu VALUES (115, N'代码生成', 3, 2, N'gen', N'tool/gen/index', N'', 1, 0, N'C', N'0', N'0', N'tool:gen:list', N'code', 103, 1, getdate(), NULL, NULL, N'代码生成菜单')
GO
INSERT sys_menu VALUES (121, N'租户管理', 6, 1, N'tenant', N'system/tenant/index', N'', 1, 0, N'C', N'0', N'0', N'system:tenant:list', N'code', 103, 1, getdate(), NULL, NULL, N'租户管理菜单')

View File

@ -6,4 +6,4 @@ ALTER TABLE sys_post ADD (post_category VARCHAR2(100) DEFAULT NULL) COMMENT '岗
COMMENT ON COLUMN sys_post.post_category IS '岗位类别编码';
UPDATE sys_post SET dept_id = 100;
UPDATE sys_post SET dept_id = 103 where post_id = 1;
UPDATE sys_menu SET path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob控制台菜单' WHERE menu_id = 120;
UPDATE sys_menu SET menu_name = 'SnailJob控制台', path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob控制台菜单' WHERE menu_id = 120;

View File

@ -6,4 +6,4 @@ ALTER TABLE sys_post ADD COLUMN post_category varchar(100) default null::varchar
COMMENT ON COLUMN sys_post.post_category IS '岗位类别编码';
UPDATE sys_post SET dept_id = 100;
UPDATE sys_post SET dept_id = 103 where post_id = 1;
UPDATE sys_menu SET path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob控制台菜单' WHERE menu_id = 120;
UPDATE sys_menu SET menu_name = 'SnailJob控制台', path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob控制台菜单' WHERE menu_id = 120;

View File

@ -25,5 +25,5 @@ UPDATE sys_post SET dept_id = 100
GO
UPDATE sys_post SET dept_id = 103 where post_id = 1
GO
UPDATE sys_menu SET path = N'snailjob', component = N'monitor/snailjob/index', perms = N'monitor:snailjob:list', remark = N'SnailJob控制台菜单' WHERE menu_id = 120
GO
UPDATE sys_menu SET menu_name = N'SnailJob控制台', path = N'snailjob', component = N'monitor/snailjob/index', perms = N'monitor:snailjob:list', remark = N'SnailJob控制台菜单' WHERE menu_id = 120
GO

View File

@ -2,4 +2,4 @@ ALTER TABLE sys_dept ADD dept_category VARCHAR(100) DEFAULT NULL COMMENT '部门
ALTER TABLE sys_post ADD dept_id BIGINT(20) NOT NULL COMMENT '部门id', ADD post_category VARCHAR(100) DEFAULT NULL COMMENT '岗位类别编码';
UPDATE sys_post SET dept_id = 100;
UPDATE sys_post SET dept_id = 103 where post_id = 1;
UPDATE sys_menu SET path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob控制台菜单' WHERE menu_id = 120;
UPDATE sys_menu SET menu_name = 'SnailJob控制台', path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob控制台菜单' WHERE menu_id = 120;