diff --git a/.run/ruoyi-monitor-admin.run.xml b/.run/ruoyi-monitor-admin.run.xml index e7d616db7..5851f8985 100644 --- a/.run/ruoyi-monitor-admin.run.xml +++ b/.run/ruoyi-monitor-admin.run.xml @@ -2,7 +2,7 @@ - diff --git a/.run/ruoyi-server.run.xml b/.run/ruoyi-server.run.xml index 2d2c4471f..61f1ddade 100644 --- a/.run/ruoyi-server.run.xml +++ b/.run/ruoyi-server.run.xml @@ -2,7 +2,7 @@ - diff --git a/.run/ruoyi-snailjob-server.run.xml b/.run/ruoyi-snailjob-server.run.xml index 5fe048db6..4df94ed28 100644 --- a/.run/ruoyi-snailjob-server.run.xml +++ b/.run/ruoyi-snailjob-server.run.xml @@ -2,7 +2,7 @@ - diff --git a/README.md b/README.md index acd14004c..6198c7d40 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,11 @@ ## 平台简介 [![码云Gitee](https://gitee.com/dromara/RuoYi-Vue-Plus/badge/star.svg?theme=blue)](https://gitee.com/dromara/RuoYi-Vue-Plus) -[![GitHub](https://img.shields.io/github/stars/dromara/RuoYi-Vue-Plus.svg?style=social&label=Stars)](https://github.com/dromara/RuoYi-Vue-Plus) +[![GitHub](https://img.shields.io/github/stars/dromara/RuoYi-Vue-Plus.svg?label=Github%20Stars)](https://github.com/dromara/RuoYi-Vue-Plus) [![Star](https://gitcode.com/dromara/RuoYi-Vue-Plus/star/badge.svg)](https://gitcode.com/dromara/RuoYi-Vue-Plus) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/5.X/LICENSE)
-[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.5.3-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus) +[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.6.0-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus) [![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.5-blue.svg)]() [![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]() [![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]() @@ -22,7 +22,7 @@ > 系统演示: [传送门](https://plus-doc.dromara.org/#/common/demo_system) > 官方前端项目地址: [gitee](https://gitee.com/JavaLionLi/plus-ui) - [github](https://github.com/JavaLionLi/plus-ui) - [gitcode](https://gitcode.com/dromara/plus-ui)
-> 成员前端项目地址: 基于vben5 [ruoyi-plus-vben5](https://gitee.com/dapppp/ruoyi-plus-vben5)
+> 成员前端项目地址: 基于vben5 [ruoyi-plus-vben5](https://github.com/imdap/ruoyi-plus-vben5)
> 成员前端项目地址: 基于soybean [ruoyi-plus-soybean](https://gitee.com/xlsea/ruoyi-plus-soybean)
> 成员项目地址: 删除多租户与工作流 [RuoYi-Vue-Plus-Single](https://gitee.com/ColorDreams/RuoYi-Vue-Plus-Single)
@@ -53,7 +53,7 @@ Topiam IAM/IDaaS身份管理平台 - https://www.topiam.cn/
| 权限注解 | 采用 Sa-Token 支持注解 登录校验、角色校验、权限校验、二级认证校验、HttpBasic校验、忽略校验
角色与权限校验支持多种条件 如 `AND` `OR` 或 `权限 OR 角色` 等复杂表达式 | 只支持是否存在匹配 | | 三方鉴权 | 采用 JustAuth 第三方登录组件 支持微信、钉钉等数十种三方认证 | 无 | | 关系数据库支持 | 原生支持 MySQL、Oracle、PostgreSQL、SQLServer
可同时使用异构切换(支持其他 mybatis-plus 支持的所有数据库 只需要增加jdbc依赖即可使用 达梦金仓等均有成功案例) | 支持 Mysql、Oracle 不支持同时使用、不支持异构切换 | -| 缓存数据库 | 支持 Redis 5-7 支持大部分新功能特性 如 分布式限流、分布式队列 | Redis 简单 get set 支持 | +| 缓存数据库 | 支持 Redis >= 6 支持大部分新功能特性 如 分布式限流、分布式队列 | Redis 简单 get set 支持 | | Redis客户端 | 采用 Redisson Redis官方推荐 基于Netty的客户端工具
支持Redis 90%以上的命令 底层优化规避很多不正确的用法 例如: keys被转换为scan
支持单机、哨兵、单主集群、多主集群等模式 | Lettuce + RedisTemplate 支持模式少 工具使用繁琐
连接池采用 common-pool Bug多经常性出问题 | | 缓存注解 | 采用 Spring-Cache 注解 对其扩展了实现支持了更多功能
例如 过期时间 最大空闲时间 组最大长度等 只需一个注解即可完成数据自动缓存 | 需手动编写Redis代码逻辑 | | ORM框架 | 采用 Mybatis-Plus 基于对象几乎不用写SQL全java操作 功能强大插件众多
例如多租户插件 分页插件 乐观锁插件等等 | 采用 Mybatis 基于XML需要手写SQL | diff --git a/pom.xml b/pom.xml index d18e0a62b..fa7295f6f 100644 --- a/pom.xml +++ b/pom.xml @@ -13,8 +13,8 @@ Dromara RuoYi-Vue-Plus多租户管理系统 - 5.5.3 - 3.5.9 + 5.6.0 + 3.5.12 UTF-8 UTF-8 17 @@ -35,10 +35,10 @@ 1.5.0 0.2.0 1.18.42 - 1.80 + 1.83 1.16.7 - 3.3.2 + 3.3.4 2.28.22 @@ -284,7 +284,7 @@ org.bouncycastle - bcprov-jdk15to18 + bcpkix-jdk18on ${bouncycastle.version} @@ -375,8 +375,7 @@ maven-compiler-plugin ${maven-compiler-plugin.version} - ${java.version} - ${java.version} + ${java.version} ${project.build.sourceEncoding} diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index d11d9f0ea..637956c2c 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -8,7 +8,7 @@ server: # undertow 配置 undertow: # HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的 - max-http-post-size: -1 + max-http-post-size: 1GB # 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理 # 每块buffer的空间大小,越小的空间被利用越充分 buffer-size: 512 diff --git a/ruoyi-admin/src/main/resources/ip2region_v4.xdb b/ruoyi-admin/src/main/resources/ip2region_v4.xdb index 6f86c7d9b..707ea3d45 100644 Binary files a/ruoyi-admin/src/main/resources/ip2region_v4.xdb and b/ruoyi-admin/src/main/resources/ip2region_v4.xdb differ diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml index dd043681c..00b7e7f41 100644 --- a/ruoyi-common/ruoyi-common-bom/pom.xml +++ b/ruoyi-common/ruoyi-common-bom/pom.xml @@ -14,7 +14,7 @@ - 5.5.3 + 5.6.0 diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java index c38f39b47..89d6ebd0b 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java @@ -52,7 +52,7 @@ public interface CacheNames { String SYS_USER_NAME = "sys_user_name#30d"; /** - * 用户名称 + * 用户昵称 */ String SYS_NICKNAME = "sys_nickname#30d"; diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowCopyDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowCopyDTO.java index 2f20b21f7..6001331d5 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowCopyDTO.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowCopyDTO.java @@ -23,8 +23,8 @@ public class FlowCopyDTO implements Serializable { private Long userId; /** - * 用户名称 + * 用户昵称 */ - private String userName; + private String nickName; } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java index fa3565789..115b42f68 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java @@ -48,7 +48,8 @@ public class StartProcessDTO implements Serializable { public Map getVariables() { if (variables == null) { - return new HashMap<>(16); + variables = new HashMap<>(16); + return variables; } variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); return variables; diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java index 43d8c3c11..4f6534ffa 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java @@ -30,7 +30,7 @@ public class UserOnlineDTO implements Serializable { private String deptName; /** - * 用户名称 + * 用户账号 */ private String userName; diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java index eefeef011..c61b1ed90 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java @@ -21,18 +21,18 @@ public interface UserService { String selectUserNameById(Long userId); /** - * 通过用户ID查询用户账户 + * 通过用户ID查询用户昵称 * * @param userId 用户ID - * @return 用户名称 + * @return 用户昵称 */ String selectNicknameById(Long userId); /** - * 通过用户ID查询用户账户 + * 通过用户ID查询用户昵称 * * @param userIds 用户ID 多个用逗号隔开 - * @return 用户名称 + * @return 用户昵称 */ String selectNicknameByIds(String userIds); @@ -93,11 +93,11 @@ public interface UserService { List selectUsersByPostIds(List postIds); /** - * 根据用户 ID 列表查询用户名称映射关系 + * 根据用户 ID 列表查询用户昵称映射关系 * * @param userIds 用户 ID 列表 - * @return Map,其中 key 为用户 ID,value 为对应的用户名称 + * @return Map,其中 key 为用户 ID,value 为对应的用户昵称 */ - Map selectUserNamesByIds(List userIds); + Map selectUserNicksByIds(List userIds); } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java index 5c74a8351..2012cd4ee 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java @@ -90,9 +90,9 @@ public class RegionUtils { try { String region = ip2Region.search(ipString); if (StringUtils.isBlank(region)) { - region = UNKNOWN_ADDRESS; + return UNKNOWN_ADDRESS; } - return region; + return StringUtils.replace(region, "0", UNKNOWN_ADDRESS); } catch (Exception e) { log.error("IP地址离线获取城市异常 {}", ipString); return UNKNOWN_ADDRESS; @@ -109,9 +109,9 @@ public class RegionUtils { try { String region = ip2Region.search(ipBytes); if (StringUtils.isBlank(region)) { - region = UNKNOWN_ADDRESS; + return UNKNOWN_ADDRESS; } - return region; + return StringUtils.replace(region, "0", UNKNOWN_ADDRESS); } catch (Exception e) { log.error("IP地址离线获取城市异常 {}", Util.ipToString(ipBytes)); return UNKNOWN_ADDRESS; diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java index 35b6ce9ea..63b5e9494 100644 --- a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java +++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java @@ -7,6 +7,8 @@ import io.swagger.v3.oas.models.security.SecurityRequirement; import lombok.RequiredArgsConstructor; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.doc.config.properties.SpringDocProperties; +import org.dromara.common.doc.core.resolver.JavadocResolver; +import org.dromara.common.doc.core.resolver.SaTokenAnnotationMetadataJavadocResolver; import org.dromara.common.doc.handler.OpenApiHandler; import org.springdoc.core.configuration.SpringDocConfiguration; import org.springdoc.core.customizers.OpenApiBuilderCustomizer; @@ -84,8 +86,9 @@ public class SpringDocConfig { SecurityService securityParser, SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils, Optional> openApiBuilderCustomisers, - Optional> serverBaseUrlCustomisers, Optional javadocProvider) { - return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider); + Optional> serverBaseUrlCustomisers, Optional javadocProvider, + List javadocResolvers) { + return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider, javadocResolvers); } /** @@ -112,6 +115,14 @@ public class SpringDocConfig { }; } + /** + * 注册SaToken JavaDoc权限注解解析器 + */ + @Bean + public JavadocResolver saTokenAnnotationJavadocResolver() { + return new SaTokenAnnotationMetadataJavadocResolver(); + } + /** * 单独使用一个类便于判断 解决springdoc路径拼接重复问题 * diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/model/SaTokenSecurityMetadata.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/model/SaTokenSecurityMetadata.java new file mode 100644 index 000000000..e0782a20c --- /dev/null +++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/model/SaTokenSecurityMetadata.java @@ -0,0 +1,175 @@ +package org.dromara.common.doc.core.model; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import lombok.Data; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 存储权限框架注解解析后的权限和角色信息 + * + * @author AprilWind + */ +@Data +@JsonInclude(Include.NON_EMPTY) +public class SaTokenSecurityMetadata { + + /** + * 权限校验信息列表(对应 @SaCheckPermission 注解) + */ + private List permissions = new ArrayList<>(); + + /** + * 角色校验信息列表(对应 @SaCheckRole 注解) + */ + private List roles = new ArrayList<>(); + + /** + * 是否忽略校验(对应 @SaIgnore 注解) + */ + private boolean ignore = false; + + /** + * 添加权限信息 + * + * @param values 权限值数组 + * @param mode 校验模式(AND/OR) + * @param type 权限类型 + * @param orRoles 或角色数组 + */ + public void addPermission(String[] values, String mode, String type, String[] orRoles) { + if (values != null && values.length > 0) { + AuthInfo authInfo = new AuthInfo(); + authInfo.setValues(values); + authInfo.setMode(mode); + authInfo.setType(type); + if (orRoles != null && orRoles.length > 0) { + authInfo.setOrValues(orRoles); + authInfo.setOrType("role"); + } + this.permissions.add(authInfo); + } + } + + /** + * 添加角色信息 + * + * @param values 角色值数组 + * @param mode 校验模式(AND/OR) + * @param type 角色类型 + */ + public void addRole(String[] values, String mode, String type) { + if (values != null && values.length > 0) { + AuthInfo authInfo = new AuthInfo(); + authInfo.setValues(values); + authInfo.setMode(mode); + authInfo.setType(type); + this.roles.add(authInfo); + } + } + + /** + * 生成 Markdown 结构的权限说明 + * + * @return Markdown 文本 + */ + public String toMarkdownString() { + StringBuilder sb = new StringBuilder(); + sb.append("

访问权限


"); + + if (ignore) { + sb.append("> **权限策略**:忽略权限检查
"); + return sb.toString(); + } + + if (!ignore && permissions.isEmpty() && roles.isEmpty()){ + sb.append("> **权限策略**:需要登录

"); + return sb.toString(); + } + + if (!permissions.isEmpty()) { + sb.append("**权限校验:**

"); + + permissions.forEach(p -> { + String permTags = Arrays.stream(p.getValues()) + .map(v -> "`" + v + "`") + .collect(Collectors.joining(p.getModeSymbol())); + + sb.append("- ").append(permTags).append("
"); + + if (p.getOrValues() != null && p.getOrValues().length > 0) { + String orTags = Arrays.stream(p.getOrValues()) + .map(v -> "`" + v + "`") + .collect(Collectors.joining(p.getModeSymbol())); + sb.append(" - 或角色:").append(orTags).append("
"); + } + }); + + sb.append("
"); + } + + if (!roles.isEmpty()) { + sb.append("**角色校验:**

"); + + roles.forEach(r -> { + + String roleTags = Arrays.stream(r.getValues()) + .map(v -> "`" + v + "`") + .collect(Collectors.joining(r.getModeSymbol())); + + sb.append("- ").append(roleTags).append("
"); + }); + } + + return sb.toString().trim(); + } + + /** + * 认证信息 + */ + @Data + @JsonInclude(Include.NON_EMPTY) + public static class AuthInfo { + + /** + * 权限或角色值数组 + */ + private String[] values; + + /** + * 校验模式(AND/OR) + */ + private String mode; + + /** + * 类型说明 + */ + private String type; + + /** + * 或权限/角色值数组(用于权限校验时的或角色校验) + */ + private String[] orValues; + + /** + * 或值的类型(role/permission) + */ + private String orType; + + /** + * 重写mode的获取方法,返回符号而非文字 + * @return AND→&,OR→|,默认→& + */ + public String getModeSymbol() { + if (mode == null) { + return " & "; // 默认AND,返回& + } + return "AND".equalsIgnoreCase(mode) ? " & " : " | "; + } + + } +} diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/AbstractMetadataJavadocResolver.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/AbstractMetadataJavadocResolver.java new file mode 100644 index 000000000..e9333c044 --- /dev/null +++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/AbstractMetadataJavadocResolver.java @@ -0,0 +1,163 @@ +package org.dromara.common.doc.core.resolver; + +import cn.hutool.core.annotation.AnnotationUtil; +import cn.hutool.core.util.ClassLoaderUtil; +import io.swagger.v3.oas.models.Operation; +import org.springframework.web.method.HandlerMethod; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.util.Map; +import java.util.function.Supplier; + +/** + * 抽象元数据 Javadoc 解析器 + * + * @param 元数据类型 + * @author 秋辞未寒 + */ +public abstract class AbstractMetadataJavadocResolver implements JavadocResolver { + + public static final int HIGHEST_PRECEDENCE = Integer.MIN_VALUE; + public static final int LOWEST_PRECEDENCE = Integer.MAX_VALUE; + + private final Supplier metadataProvider; + + private final int order; + + public AbstractMetadataJavadocResolver(Supplier metadataProvider) { + this(metadataProvider, LOWEST_PRECEDENCE); + } + + public AbstractMetadataJavadocResolver(Supplier metadataProvider, int order) { + this.metadataProvider = metadataProvider; + this.order = order; + } + + @Override + public int getOrder() { + return order; + } + + @Override + public String resolve(HandlerMethod handlerMethod, Operation operation) { + return resolve(handlerMethod, operation, metadataProvider.get()); + } + + /** + * 执行解析并返回解析到的 Javadoc 内容 + * @param handlerMethod 处理器方法 + * @param operation Swagger Operation实例 + * @param metadata 元信息 + * @return 解析到的 Javadoc 内容 + */ + public abstract String resolve(HandlerMethod handlerMethod, Operation operation, M metadata); + + /** + * 检查处理器方法所属的类上是否存在注解 + * @param handlerMethod 处理器方法 + * @param annotationClass 注解类 + * @return 是否存在注解 + */ + public boolean hasClassAnnotation(HandlerMethod handlerMethod,Class annotationClass){ + return AnnotationUtil.hasAnnotation(handlerMethod.getBeanType(), annotationClass); + } + + /** + * 检查处理器方法所属的类上是否存在注解 + * @param handlerMethod 处理器方法 + * @param annotationTypeName 注解类名称 + * @return 是否存在注解 + */ + public boolean hasClassAnnotation(HandlerMethod handlerMethod, String annotationTypeName){ + return AnnotationUtil.hasAnnotation(handlerMethod.getBeanType(), annotationTypeName); + } + + /** + * 检查处理器方法上是否存在注解 + * @param handlerMethod 处理器方法 + * @param annotationClass 注解类 + * @return 是否存在注解 + */ + public boolean hasMethodAnnotation(HandlerMethod handlerMethod,Class annotationClass){ + return AnnotationUtil.hasAnnotation(handlerMethod.getMethod(), annotationClass); + } + + /** + * 检查处理器方法上是否存在注解 + * @param handlerMethod 处理器方法 + * @param annotationTypeName 注解类名称 + * @return 是否存在注解 + */ + public boolean hasMethodAnnotation(HandlerMethod handlerMethod, String annotationTypeName){ + return AnnotationUtil.hasAnnotation(handlerMethod.getMethod(), annotationTypeName); + } + + /** + * 检查处理器方法上是否存在注解 + * @param handlerMethod 处理器方法 + * @param annotationClass 注解类 + * @return 是否存在注解 + */ + public boolean hasAnnotation(HandlerMethod handlerMethod,Class annotationClass){ + return this.hasClassAnnotation(handlerMethod, annotationClass) || this.hasMethodAnnotation(handlerMethod, annotationClass); + } + + /** + * 检查处理器方法上是否存在注解 + * @param handlerMethod 处理器方法 + * @param annotationTypeName 注解类名称 + * @return 是否存在注解 + */ + public boolean hasAnnotation(HandlerMethod handlerMethod, String annotationTypeName){ + return this.hasClassAnnotation(handlerMethod, annotationTypeName) || this.hasMethodAnnotation(handlerMethod, annotationTypeName); + } + + /** + * 获取处理器方法所属类上的注解的值 + * @param handlerMethod 处理器方法 + * @param annotationClass 注解类 + * @return 注解的值 + */ + public Map getClassAnnotationValueMap(HandlerMethod handlerMethod, Class annotationClass) { + return AnnotationUtil.getAnnotationValueMap(handlerMethod.getBeanType(), annotationClass); + } + + /** + * 获取处理器方法所属类上的注解的值 + * @param handlerMethod 处理器方法 + * @param annotationClassName 注解类名称 + * @return 注解的值 + */ + @SuppressWarnings("unchecked") + public Map getClassAnnotationValueMap(HandlerMethod handlerMethod, String annotationClassName) { + Class annotationClass = (Class) ClassLoaderUtil.loadClass(annotationClassName, false); + return AnnotationUtil.getAnnotationValueMap(handlerMethod.getBeanType(), annotationClass); + } + + /** + * 获取处理器方法上的注解的值 + * @param handlerMethod 处理器方法 + * @param annotationClass 注解类 + * @return 注解的值 + */ + public Map getMethodAnnotationValueMap(HandlerMethod handlerMethod, Class annotationClass) { + return AnnotationUtil.getAnnotationValueMap(handlerMethod.getMethod(), annotationClass); + } + + /** + * 获取处理器方法所属类上的注解的值 + * @param handlerMethod 处理器方法 + * @param annotationClassName 注解类名称 + * @return 注解的值 + */ + @SuppressWarnings("unchecked") + public Map getMethodAnnotationValueMap(HandlerMethod handlerMethod, String annotationClassName) { + Class annotationClass = (Class) ClassLoaderUtil.loadClass(annotationClassName, false); + return AnnotationUtil.getAnnotationValueMap(handlerMethod.getMethod(), annotationClass); + } + + private Map getAnnotationValueMap(AnnotatedElement annotatedElement, Class annotationClass) { + return AnnotationUtil.getAnnotationValueMap(annotatedElement, annotationClass); + } +} diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/JavadocResolver.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/JavadocResolver.java new file mode 100644 index 000000000..1e295b8a1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/JavadocResolver.java @@ -0,0 +1,51 @@ +package org.dromara.common.doc.core.resolver; + +import io.swagger.v3.oas.models.Operation; +import org.jetbrains.annotations.NotNull; +import org.springframework.core.Ordered; +import org.springframework.web.method.HandlerMethod; + +/** + * Javadoc解析器接口 + * + * @author echo + * @author 秋辞未寒 + */ +public interface JavadocResolver extends Comparable, Ordered { + + /** + * 检查解析器是否支持解析 HandlerMethod + * @param handlerMethod 处理器方法 + * @return 是否支持解析 + */ + boolean supports(HandlerMethod handlerMethod); + + /** + * 执行解析并返回解析到的 Javadoc 内容 + * @param handlerMethod 处理器方法 + * @param operation Swagger Operation实例 + * @return 解析到的 Javadoc 内容 + */ + String resolve(HandlerMethod handlerMethod, Operation operation); + + /** + * 获取解析器优先级 + */ + default int getOrder() { + return Ordered.LOWEST_PRECEDENCE; + } + + /** + * 获取解析器的名称 + * + * @return 解析器名称 + */ + default String getName() { + return this.getClass().getSimpleName(); + } + + @Override + default int compareTo(@NotNull JavadocResolver o) { + return Integer.compare(getOrder(), o.getOrder()); + } +} diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/SaTokenAnnotationMetadataJavadocResolver.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/SaTokenAnnotationMetadataJavadocResolver.java new file mode 100644 index 000000000..9e09619de --- /dev/null +++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/core/resolver/SaTokenAnnotationMetadataJavadocResolver.java @@ -0,0 +1,164 @@ +package org.dromara.common.doc.core.resolver; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ClassLoaderUtil; +import io.swagger.v3.oas.models.Operation; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.doc.core.model.SaTokenSecurityMetadata; +import org.springframework.web.method.HandlerMethod; + +import java.lang.annotation.Annotation; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +/** + * 基于JavaDoc的SaToken权限解析器 + * + * @author echo + * @author 秋辞未寒 + */ +@SuppressWarnings("unchecked") +@Slf4j +public class SaTokenAnnotationMetadataJavadocResolver extends AbstractMetadataJavadocResolver { + + /** + * 默认元数据提供者,每次解析都会创建一个新的元数据对象 + */ + public static final Supplier DEFAULT_METADATA_PROVIDER = SaTokenSecurityMetadata::new; + + private static final String BASE_CLASS_NAME = "cn.dev33.satoken.annotation"; + private static final String SA_CHECK_ROLE_CLASS_NAME = BASE_CLASS_NAME + ".SaCheckRole"; + private static final String SA_CHECK_PERMISSION_CLASS_NAME = BASE_CLASS_NAME + ".SaCheckPermission"; + private static final String SA_IGNORE_CLASS_NAME = BASE_CLASS_NAME + ".SaIgnore"; + private static final String SA_CHECK_LOGIN_NAME = BASE_CLASS_NAME + ".SaCheckLogin"; + + private static final Class SA_CHECK_ROLE_CLASS; + private static final Class SA_CHECK_PERMISSION_CLASS; + private static final Class SA_IGNORE_CLASS; + private static final Class SA_CHECK_LOGIN_CLASS; + + + static { + // 通过类加载器去加载注解类Class实例 + SA_CHECK_ROLE_CLASS = (Class) ClassLoaderUtil.loadClass(SA_CHECK_ROLE_CLASS_NAME, false); + SA_CHECK_PERMISSION_CLASS = (Class) ClassLoaderUtil.loadClass(SA_CHECK_PERMISSION_CLASS_NAME, false); + SA_IGNORE_CLASS = (Class) ClassLoaderUtil.loadClass(SA_IGNORE_CLASS_NAME, false); + SA_CHECK_LOGIN_CLASS = (Class) ClassLoaderUtil.loadClass(SA_CHECK_LOGIN_NAME, false); + if (log.isDebugEnabled()) { + log.debug("SaTokenAnnotationJavadocResolver init success, load annotation class: {}", List.of(SA_CHECK_ROLE_CLASS, SA_CHECK_PERMISSION_CLASS, SA_IGNORE_CLASS, SA_CHECK_LOGIN_CLASS)); + } + } + + public SaTokenAnnotationMetadataJavadocResolver() { + this(DEFAULT_METADATA_PROVIDER); + } + + public SaTokenAnnotationMetadataJavadocResolver(Supplier metadataProvider) { + super(metadataProvider); + } + + public SaTokenAnnotationMetadataJavadocResolver(int order) { + this(DEFAULT_METADATA_PROVIDER,order); + } + + public SaTokenAnnotationMetadataJavadocResolver(Supplier metadataProvider, int order) { + super(metadataProvider,order); + } + + @Override + public boolean supports(HandlerMethod handlerMethod) { + return hasAnnotation(handlerMethod, SA_CHECK_ROLE_CLASS) || hasAnnotation(handlerMethod, SA_CHECK_PERMISSION_CLASS) || hasAnnotation(handlerMethod, SA_IGNORE_CLASS); + } + + @Override + public String resolve(HandlerMethod handlerMethod, Operation operation, SaTokenSecurityMetadata metadata) { + // 检查是否忽略校验 + if(hasAnnotation(handlerMethod, SA_IGNORE_CLASS_NAME)){ + metadata.setIgnore(true); + return metadata.toMarkdownString(); + } + + // 解析权限校验 + resolvePermissionCheck(handlerMethod, metadata); + + // 解析角色校验 + resolveRoleCheck(handlerMethod, metadata); + return metadata.toMarkdownString(); + } + + /** + * 解析权限校验 + */ + private void resolvePermissionCheck(HandlerMethod handlerMethod, SaTokenSecurityMetadata metadata) { + // 解析获取方法上的注解角色信息 + if (hasMethodAnnotation(handlerMethod, SA_CHECK_PERMISSION_CLASS_NAME)) { + Map annotationValueMap = getMethodAnnotationValueMap(handlerMethod, SA_CHECK_PERMISSION_CLASS); + resolvePermissionAnnotation(metadata, annotationValueMap); + } + // 解析获取类上的注解角色信息 + if (hasClassAnnotation(handlerMethod, SA_CHECK_PERMISSION_CLASS_NAME)) { + Map annotationValueMap = getClassAnnotationValueMap(handlerMethod, SA_CHECK_PERMISSION_CLASS); + resolvePermissionAnnotation(metadata, annotationValueMap); + } + } + + /** + * 解析权限注解 + */ + private void resolvePermissionAnnotation(SaTokenSecurityMetadata metadata, Map annotationValueMap) { + try { + // 反射获取注解属性 + Object value = annotationValueMap.get( "value"); + Object mode = annotationValueMap.get( "mode"); + Object type = annotationValueMap.get( "type"); + Object orRole = annotationValueMap.get( "orRole"); + + String[] values = Convert.toStrArray(value); + String modeStr = mode != null ? mode.toString() : "AND"; + String typeStr = type != null ? type.toString() : ""; + String[] orRoles = Convert.toStrArray(orRole); + + metadata.addPermission(values, modeStr, typeStr, orRoles); + } catch (Exception ignore) { + // 忽略解析错误 + } + } + + /** + * 解析角色校验 + */ + private void resolveRoleCheck(HandlerMethod handlerMethod, SaTokenSecurityMetadata metadata) { + // 解析获取方法上的注解角色信息 + if (hasMethodAnnotation(handlerMethod, SA_CHECK_ROLE_CLASS_NAME)) { + Map annotationValueMap = getMethodAnnotationValueMap(handlerMethod, SA_CHECK_ROLE_CLASS); + resolveRoleAnnotation(metadata, annotationValueMap); + } + // 解析获取类上的注解角色信息 + if (hasClassAnnotation(handlerMethod, SA_CHECK_ROLE_CLASS_NAME)) { + Map annotationValueMap = getClassAnnotationValueMap(handlerMethod, SA_CHECK_ROLE_CLASS); + resolveRoleAnnotation(metadata, annotationValueMap); + } + } + + /** + * 解析角色注解 + */ + private void resolveRoleAnnotation(SaTokenSecurityMetadata metadata, Map annotationValueMap) { + try { + // 反射获取注解属性 + Object value = annotationValueMap.get("value"); + Object mode = annotationValueMap.get("mode"); + Object type = annotationValueMap.get("type"); + + String[] values = Convert.toStrArray(value); + String modeStr = mode != null ? mode.toString() : "AND"; + String typeStr = type != null ? type.toString() : ""; + + metadata.addRole(values, modeStr, typeStr); + } catch (Exception ignore) { + // 忽略解析错误 + } + } + +} diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java index 56b73694d..32be73227 100644 --- a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java +++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java @@ -12,6 +12,7 @@ import io.swagger.v3.oas.models.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.doc.core.resolver.JavadocResolver; import org.springdoc.core.customizers.OpenApiBuilderCustomizer; import org.springdoc.core.customizers.ServerBaseUrlCustomizer; import org.springdoc.core.properties.SpringDocConfigProperties; @@ -83,6 +84,11 @@ public class OpenApiHandler extends OpenAPIService { */ private final PropertyResolverUtils propertyResolverUtils; + /** + * Javadoc解析器接口 + */ + private final List javadocResolvers; + /** * The javadoc provider. */ @@ -123,7 +129,8 @@ public class OpenApiHandler extends OpenAPIService { SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils, Optional> openApiBuilderCustomizers, Optional> serverBaseUrlCustomizers, - Optional javadocProvider) { + Optional javadocProvider, + List javadocResolvers) { super(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider); if (openAPI.isPresent()) { this.openAPI = openAPI.get(); @@ -140,6 +147,7 @@ public class OpenApiHandler extends OpenAPIService { this.openApiBuilderCustomisers = openApiBuilderCustomizers; this.serverBaseUrlCustomizers = serverBaseUrlCustomizers; this.javadocProvider = javadocProvider; + this.javadocResolvers = javadocResolvers == null ? new ArrayList<>() : javadocResolvers; if (springDocConfigProperties.isUseFqn()) TypeNameResolver.std.setUseFqn(true); } @@ -220,6 +228,22 @@ public class OpenApiHandler extends OpenAPIService { securityParser.buildSecurityRequirement(securityRequirements, operation); } + if (javadocProvider.isPresent()) { + String description = javadocProvider.get().getMethodJavadocDescription(handlerMethod.getMethod()); + String summary = javadocProvider.get().getFirstSentence(description); + if (StringUtils.isNotBlank(description)){ + operation.setSummary(summary); + } + // 调用解析器提取JavaDoc中的权限信息 + if (javadocResolvers != null && !javadocResolvers.isEmpty()) { + for (JavadocResolver resolver : javadocResolvers) { + String desc = resolver.resolve(handlerMethod, operation); + description = description + desc; + } + operation.setDescription(description); + } + } + return operation; } diff --git a/ruoyi-common/ruoyi-common-encrypt/pom.xml b/ruoyi-common/ruoyi-common-encrypt/pom.xml index ed4910ef0..02b9062da 100644 --- a/ruoyi-common/ruoyi-common-encrypt/pom.xml +++ b/ruoyi-common/ruoyi-common-encrypt/pom.xml @@ -24,7 +24,7 @@ org.bouncycastle - bcprov-jdk15to18 + bcpkix-jdk18on diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java index bcc2f4c9f..617fb7979 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java @@ -6,10 +6,7 @@ import cn.hutool.core.util.ObjectUtil; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.executor.parameter.ParameterHandler; -import org.apache.ibatis.plugin.Interceptor; -import org.apache.ibatis.plugin.Intercepts; -import org.apache.ibatis.plugin.Invocation; -import org.apache.ibatis.plugin.Signature; +import org.apache.ibatis.plugin.*; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.encrypt.annotation.EncryptField; import org.dromara.common.encrypt.core.EncryptContext; @@ -42,19 +39,19 @@ public class MybatisEncryptInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { - return invocation; - } - - @Override - public Object plugin(Object target) { + Object target = invocation.getTarget(); if (target instanceof ParameterHandler parameterHandler) { - // 进行加密操作 Object parameterObject = parameterHandler.getParameterObject(); if (ObjectUtil.isNotNull(parameterObject) && !(parameterObject instanceof String)) { this.encryptHandler(parameterObject); } } - return target; + return invocation.proceed(); + } + + @Override + public Object plugin(Object target) { + return Plugin.wrap(target, this); } /** diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeHandler.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeHandler.java index 6a1a3a72d..624117585 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeHandler.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeHandler.java @@ -64,8 +64,10 @@ public class CellMergeHandler { // 当前行数据字段值 Object currentRowObjFieldVal = ReflectUtils.invokeGetter(currentRowObj, field.getName()); - // 空值跳过不处理 - if (currentRowObjFieldVal == null || "".equals(currentRowObjFieldVal)) { + // 空值视为合并中断,需要先收口上一段合并区间 + if (isBlankCell(currentRowObjFieldVal)) { + appendMergeResult(result, rowRepeatCellMap.get(field), i - 1, colNum); + rowRepeatCellMap.remove(field); continue; } @@ -78,7 +80,6 @@ public class CellMergeHandler { // 获取 单元格合并Map 中字段值 RepeatCell repeatCell = rowRepeatCellMap.get(field); Object cellValue = repeatCell.value(); - int current = repeatCell.current(); // 检查是否满足合并条件 // currentRowObj 当前行数据 @@ -86,33 +87,14 @@ public class CellMergeHandler { // cellMerge 当前行字段合并注解 boolean merge = isMerge(currentRowObj, rows.get(i - 1), cellMerge); - // 是否添加到结果集 - boolean isAddResult = false; - // 最新行 - int lastRow = i + rowIndex - 1; - // 如果当前行字段值和缓存中的字段值不相等,或不满足合并条件,则替换 if (!currentRowObjFieldVal.equals(cellValue) || !merge) { + appendMergeResult(result, repeatCell, i - 1, colNum); rowRepeatCellMap.put(field, RepeatCell.of(currentRowObjFieldVal, i)); - isAddResult = true; - } - - // 如果最后一行不能合并,检查之前的数据是否需要合并;如果最后一行可以合并,则直接合并到最后 - if (i == rows.size() - 1) { - isAddResult = true; - if (i > current) { - lastRow = i + rowIndex; - } - } - - if (isAddResult && i > current) { - //如果是同一行,则跳过合并 - if (current + rowIndex == lastRow) { - continue; - } - result.add(new CellRangeAddress(current + rowIndex, lastRow, colNum, colNum)); } } + appendMergeResult(result, rowRepeatCellMap.get(field), rows.size() - 1, colNum); + rowRepeatCellMap.remove(field); } return result; } @@ -167,6 +149,17 @@ public class CellMergeHandler { return true; } + private boolean isBlankCell(Object value) { + return value == null || StrUtil.isBlankIfStr(value); + } + + private void appendMergeResult(List result, RepeatCell repeatCell, int endIndex, int colNum) { + if (repeatCell == null || endIndex <= repeatCell.current()) { + return; + } + result.add(new CellRangeAddress(repeatCell.current() + rowIndex, endIndex + rowIndex, colNum, colNum)); + } + /** * 单元格合并 */ diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java index 8963648c0..76cfd2ad9 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java @@ -23,7 +23,7 @@ import java.util.function.Supplier; * @version 3.5.0 */ @NoArgsConstructor(access = AccessLevel.PRIVATE) -@SuppressWarnings("unchecked cast") +@SuppressWarnings("unchecked") public class DataPermissionHelper { private static final String DATA_PERMISSION_KEY = "data:permission"; diff --git a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java index 14abf896a..09f82324e 100644 --- a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java +++ b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java @@ -113,7 +113,7 @@ public class PlusSaTokenDao implements SaTokenDaoBySessionFollowObject { * @param key 键名称 * @return object */ - @SuppressWarnings("unchecked cast") + @SuppressWarnings("unchecked") @Override public T getObject(String key, Class classType) { Object o = CAFFEINE.get(key, k -> RedisUtils.getCacheObject(key)); diff --git a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java index 730bae29d..38a367a16 100644 --- a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java +++ b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java @@ -63,7 +63,7 @@ public class LoginHelper { /** * 获取用户(多级缓存) */ - @SuppressWarnings("unchecked cast") + @SuppressWarnings("unchecked") public static T getLoginUser() { SaSession session = StpUtil.getTokenSession(); if (ObjectUtil.isNull(session)) { @@ -75,7 +75,7 @@ public class LoginHelper { /** * 获取用户基于token */ - @SuppressWarnings("unchecked cast") + @SuppressWarnings("unchecked") public static T getLoginUser(String token) { SaSession session = StpUtil.getTokenSessionByToken(token); if (ObjectUtil.isNull(session)) { diff --git a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java index d454724d7..e5eed76c0 100644 --- a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java +++ b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java @@ -25,9 +25,24 @@ import java.util.Objects; @Slf4j public class SensitiveHandler extends JsonSerializer implements ContextualSerializer { - private SensitiveStrategy strategy; - private String[] roleKey; - private String[] perms; + private final SensitiveStrategy strategy; + private final String[] roleKey; + private final String[] perms; + + /** + * 提供给 jackson 创建上下文序列化器时使用 不然会报错 + */ + public SensitiveHandler() { + this.strategy = null; + this.roleKey = null; + this.perms = null; + } + + public SensitiveHandler(SensitiveStrategy strategy, String[] strings, String[] perms) { + this.strategy = strategy; + this.roleKey = strings; + this.perms = perms; + } @Override public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException { @@ -48,10 +63,7 @@ public class SensitiveHandler extends JsonSerializer implements Contextu public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { Sensitive annotation = property.getAnnotation(Sensitive.class); if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) { - this.strategy = annotation.strategy(); - this.roleKey = annotation.roleKey(); - this.perms = annotation.perms(); - return this; + return new SensitiveHandler(annotation.strategy(), annotation.roleKey(), annotation.perms()); } return prov.findValueSerializer(property.getType(), property); } diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java index c084ea1a0..50dce798a 100644 --- a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java @@ -13,7 +13,7 @@ public interface TransConstant { String USER_ID_TO_NAME = "user_id_to_name"; /** - * 用户id转用户名称 + * 用户id转用户昵称 */ String USER_ID_TO_NICKNAME = "user_id_to_nickname"; diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java index e8c03acdc..2322cdf5d 100644 --- a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java @@ -31,7 +31,18 @@ public class TranslationHandler extends JsonSerializer implements Contex */ public static final Map> TRANSLATION_MAPPER = new ConcurrentHashMap<>(); - private Translation translation; + private final Translation translation; + + /** + * 提供给 jackson 创建上下文序列化器时使用 不然会报错 + */ + public TranslationHandler() { + this.translation = null; + } + + public TranslationHandler(Translation translation) { + this.translation = translation; + } @Override public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { @@ -63,8 +74,7 @@ public class TranslationHandler extends JsonSerializer implements Contex public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { Translation translation = property.getAnnotation(Translation.class); if (Objects.nonNull(translation)) { - this.translation = translation; - return this; + return new TranslationHandler(translation); } return prov.findValueSerializer(property.getType(), property); } diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/NicknameTranslationImpl.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/NicknameTranslationImpl.java index d1720f714..06be37fcc 100644 --- a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/NicknameTranslationImpl.java +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/NicknameTranslationImpl.java @@ -7,7 +7,7 @@ import org.dromara.common.translation.constant.TransConstant; import org.dromara.common.translation.core.TranslationInterface; /** - * 用户名称翻译实现 + * 用户昵称翻译实现 * * @author may */ diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java index 84f88ff82..02ab0a1eb 100644 --- a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java @@ -1,11 +1,14 @@ package org.dromara.common.web.config; +import io.undertow.UndertowOptions; import io.undertow.server.DefaultByteBufferPool; import io.undertow.server.handlers.DisallowedMethodsHandler; import io.undertow.util.HttpString; import io.undertow.websockets.jsr.WebSocketDeploymentInfo; import org.dromara.common.core.utils.SpringUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.core.task.VirtualThreadTaskExecutor; @@ -18,6 +21,9 @@ import org.springframework.core.task.VirtualThreadTaskExecutor; @AutoConfiguration public class UndertowConfig implements WebServerFactoryCustomizer { + @Autowired + private ServerProperties serverProperties; + /** * 自定义 Undertow 配置 *

@@ -31,6 +37,11 @@ public class UndertowConfig implements WebServerFactoryCustomizer { + builder.setServerOption(UndertowOptions.MULTIPART_MAX_ENTITY_SIZE, bytes); + }); + factory.addDeploymentInfoCustomizers(deploymentInfo -> { // 配置 WebSocket 部署信息,设置 WebSocket 使用的缓冲区池 WebSocketDeploymentInfo webSocketDeploymentInfo = new WebSocketDeploymentInfo(); diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SaTokenTestController.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SaTokenTestController.java new file mode 100644 index 000000000..66fd3cd84 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SaTokenTestController.java @@ -0,0 +1,198 @@ +package org.dromara.demo.controller; + +import cn.dev33.satoken.annotation.*; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.R; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * SaToken 权限测试 接口文档输出测试 + * + * @author AprilWind + */ +@Slf4j +@RestController +@RequestMapping("/demo/saTokenDoc") +public class SaTokenTestController { + + // ====================== 基础场景:单一校验规则 ====================== + + /** + * 场景1:仅登录校验(无角色/权限限制,只需登录态) + */ + @SaCheckLogin + @GetMapping("/basic/loginOnly") + public R loginOnly() { + log.info("【场景1】仅登录校验通过"); + return R.ok("仅登录校验通过,无需角色/权限"); + } + + /** + * 场景2:单一角色校验(AND模式,默认) + */ + @SaCheckRole("admin") + @GetMapping("/basic/singleRole") + public R singleRole() { + log.info("【场景2】单一角色(admin)校验通过"); + return R.ok("拥有admin角色,校验通过"); + } + + /** + * 场景3:单一权限校验(AND模式,默认) + */ + @SaCheckPermission("system:user:view") + @GetMapping("/basic/singlePermission") + public R singlePermission() { + log.info("【场景3】单一权限(system:user:view)校验通过"); + return R.ok("拥有system:user:view权限,校验通过"); + } + + /** + * 场景4:忽略所有权限校验(SaIgnore优先级最高) + */ + @SaIgnore + @SaCheckRole("none_exist") // 该注解会被忽略 + @GetMapping("/basic/ignoreAll") + public R ignoreAll() { + log.info("【场景4】SaIgnore忽略所有权限校验"); + return R.ok("SaIgnore生效,所有权限校验被忽略"); + } + + // ====================== 进阶场景:多条件组合(AND/OR) ====================== + + /** + * 场景5:多角色AND模式(必须同时拥有所有角色) + */ + @SaCheckRole(value = {"admin", "operator"}, mode = SaMode.AND) + @GetMapping("/advance/multiRoleAnd") + public R multiRoleAnd() { + log.info("【场景5】多角色AND模式(admin+operator)校验通过"); + return R.ok("同时拥有admin和operator角色,校验通过"); + } + + /** + * 场景6:多角色OR模式(拥有任一角色即可) + */ + @SaCheckRole(value = {"admin", "test"}, mode = SaMode.OR) + @GetMapping("/advance/multiRoleOr") + public R multiRoleOr() { + log.info("【场景6】多角色OR模式(admin|test)校验通过"); + return R.ok("拥有admin或test角色,校验通过"); + } + + /** + * 场景7:多权限AND模式(必须同时拥有所有权限) + */ + @SaCheckPermission(value = {"system:user:edit", "system:log:view"}, mode = SaMode.AND) + @GetMapping("/advance/multiPermAnd") + public R multiPermAnd() { + log.info("【场景7】多权限AND模式(system:user:edit+system:log:view)校验通过"); + return R.ok("同时拥有system:user:edit和system:log:view权限,校验通过"); + } + + /** + * 场景8:多权限OR模式(拥有任一权限即可) + */ + @SaCheckPermission(value = {"system:user:add", "system:user:delete"}, mode = SaMode.OR) + @GetMapping("/advance/multiPermOr") + public R multiPermOr() { + log.info("【场景8】多权限OR模式(system:user:add|system:user:delete)校验通过"); + return R.ok("拥有system:user:add或system:user:delete权限,校验通过"); + } + + // ====================== 高级场景:通配符/混合组合 ====================== + + /** + * 场景9:权限通配符匹配(前缀匹配) + * 拥有system:user:* 即可匹配所有用户模块权限 + */ + @SaCheckPermission("system:user:*") + @GetMapping("/advanced/permWildcardPrefix") + public R permWildcardPrefix() { + log.info("【场景9】权限通配符(system:user:*)校验通过"); + return R.ok("拥有system:user:*前缀权限,校验通过"); + } + + /** + * 场景10:角色通配符匹配(前缀匹配) + * 拥有admin_* 即可匹配所有admin开头的角色 + */ + @SaCheckRole("admin_*") + @GetMapping("/advanced/roleWildcardPrefix") + public R roleWildcardPrefix() { + log.info("【场景10】角色通配符(admin_*)校验通过"); + return R.ok("拥有admin_*前缀角色,校验通过"); + } + + /** + * 场景11:权限+角色混合AND模式(所有条件必须满足) + * 需同时满足:拥有admin角色 + 拥有system:user:all权限 + */ + @SaCheckRole("admin") + @SaCheckPermission("system:user:all") + @GetMapping("/advanced/mixRolePermAnd") + public R mixRolePermAnd() { + log.info("【场景11】角色+权限混合AND(admin+system:user:all)校验通过"); + return R.ok("拥有admin角色且拥有system:user:all权限,校验通过"); + } + + /** + * 场景12:权限+角色混合OR模式(任一条件满足即可) + * 满足任一:拥有super_admin角色 | 拥有system:manage权限 + */ + @SaCheckRole(value = {"super_admin"}, mode = SaMode.OR) + @SaCheckPermission(value = {"system:manage"}, mode = SaMode.OR) + @GetMapping("/advanced/mixRolePermOr") + public R mixRolePermOr() { + log.info("【场景12】角色+权限混合OR(super_admin|system:manage)校验通过"); + return R.ok("拥有super_admin角色或system:manage权限,校验通过"); + } + + /** + * 场景13:orRole参数(权限校验失败时,兜底角色校验) + * 核心逻辑:无system:user:export权限时,检查是否有admin/operator角色 + */ + @SaCheckPermission(value = "system:user:export", orRole = {"admin", "operator"}) + @GetMapping("/advanced/permWithOrRole") + public R permWithOrRole() { + log.info("【场景13】权限+orRole兜底校验通过"); + return R.ok("拥有system:user:export权限,或拥有admin/operator角色,校验通过"); + } + + // ====================== 特殊场景:临时权限/注解覆盖 ====================== + + /** + * 场景14:SaIgnore局部覆盖(方法注解覆盖类注解,若有) + * 假设类上有@SaCheckLogin,方法上@SaIgnore会覆盖 + */ + @SaIgnore + @GetMapping("/special/ignoreOverride") + public R ignoreOverride() { + log.info("【场景14】SaIgnore覆盖类级别权限注解"); + return R.ok("方法级SaIgnore覆盖类级别权限校验"); + } + + /** + * 场景15:临时权限校验(SaCheckPermission逻辑:临时权限>永久权限) + * 注:临时权限需通过SaToken API手动设置,如 SaHolder.getStpLogic().setTempPermission("system:temp:test") + */ + @SaCheckPermission("system:temp:test") + @GetMapping("/special/tempPermission") + public R tempPermission() { + log.info("【场景15】临时权限(system:temp:test)校验通过"); + return R.ok("临时权限校验通过(需先通过API设置临时权限)"); + } + + /** + * 场景16:登录类型指定(多端登录场景,如PC/APP/小程序) + * 注:需配合SaToken多账号体系配置 + */ + @SaCheckLogin(type = "PC") // 仅校验PC端的登录态 + @GetMapping("/special/loginTypeSpecify") + public R loginTypeSpecify() { + log.info("【场景16】指定登录类型(PC)校验通过"); + return R.ok("仅PC端登录态校验通过"); + } +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestDemoController.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestDemoController.java index f31c54074..38275eab5 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestDemoController.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestDemoController.java @@ -17,7 +17,7 @@ import org.dromara.common.log.annotation.Log; import org.dromara.common.log.enums.BusinessType; import org.dromara.demo.domain.TestDemo; import org.dromara.demo.domain.bo.TestDemoBo; -import org.dromara.demo.domain.bo.TestDemoImportVo; +import org.dromara.demo.domain.vo.TestDemoImportVo; import org.dromara.demo.domain.vo.TestDemoVo; import org.dromara.demo.service.ITestDemoService; import lombok.RequiredArgsConstructor; diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/ExportDemoVo.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/ExportDemoVo.java index b42ce7679..4a6b0dfba 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/ExportDemoVo.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/ExportDemoVo.java @@ -35,8 +35,8 @@ public class ExportDemoVo implements Serializable { /** * 用户昵称 */ - @ExcelProperty(value = "用户名", index = 0) - @NotEmpty(message = "用户名不能为空", groups = AddGroup.class) + @ExcelProperty(value = "用户昵称", index = 0) + @NotEmpty(message = "用户昵称不能为空", groups = AddGroup.class) private String nickName; /** diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/bo/TestDemoImportVo.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoImportVo.java similarity index 85% rename from ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/bo/TestDemoImportVo.java rename to ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoImportVo.java index dc8b35f49..c799b6f12 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/bo/TestDemoImportVo.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoImportVo.java @@ -1,10 +1,12 @@ -package org.dromara.demo.domain.bo; +package org.dromara.demo.domain.vo; import cn.idev.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import org.dromara.demo.domain.TestDemo; /** * 测试单表业务对象 test_demo @@ -13,6 +15,7 @@ import jakarta.validation.constraints.NotNull; * @date 2021-07-26 */ @Data +@AutoMapper(target = TestDemo.class) public class TestDemoImportVo { /** diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java index 3e7bdf7bb..455f8d9e6 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java @@ -523,6 +523,9 @@ public class GenTableServiceImpl implements IGenTableService { * @param table 业务表信息 */ public void setPkColumn(GenTable table) { + if (CollUtil.isEmpty(table.getColumns())) { + throw new ServiceException("表【" + table.getTableName() + "】字段为空,请检查表结构"); + } for (GenTableColumn column : table.getColumns()) { if (column.isPk()) { table.setPkColumn(column); diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestMapJobAnnotation.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestMapJobAnnotation.java index f58d7724a..8507092f6 100644 --- a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestMapJobAnnotation.java +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestMapJobAnnotation.java @@ -21,6 +21,7 @@ import java.util.stream.IntStream; * * @author 老马 */ +@SuppressWarnings({"unchecked", "rawtypes"}) @Component @JobExecutor(name = "testMapJobAnnotation") public class TestMapJobAnnotation { diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestMapReduceAnnotation1.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestMapReduceAnnotation1.java index f926016f9..17aa9e461 100644 --- a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestMapReduceAnnotation1.java +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestMapReduceAnnotation1.java @@ -23,6 +23,7 @@ import java.util.stream.IntStream; * * @author 老马 */ +@SuppressWarnings({"unchecked", "rawtypes"}) @Component @JobExecutor(name = "testMapReduceAnnotation1") public class TestMapReduceAnnotation1 { diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java index ae6d5808c..5ad4272f2 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java @@ -83,7 +83,7 @@ public class SysDictDataController extends BaseController { } /** - * 新增字典类型 + * 新增字典数据 */ @SaCheckPermission("system:dict:add") @Log(title = "字典数据", businessType = BusinessType.INSERT) @@ -98,7 +98,7 @@ public class SysDictDataController extends BaseController { } /** - * 修改保存字典类型 + * 修改保存字典数据 */ @SaCheckPermission("system:dict:edit") @Log(title = "字典数据", businessType = BusinessType.UPDATE) @@ -113,12 +113,12 @@ public class SysDictDataController extends BaseController { } /** - * 删除字典类型 + * 删除字典数据 * * @param dictCodes 字典code串 */ @SaCheckPermission("system:dict:remove") - @Log(title = "字典类型", businessType = BusinessType.DELETE) + @Log(title = "字典数据", businessType = BusinessType.DELETE) @DeleteMapping("/{dictCodes}") public R remove(@PathVariable Long[] dictCodes) { dictDataService.deleteDictDataByIds(Arrays.asList(dictCodes)); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java index ba30eb609..f3b5f87a3 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java @@ -21,7 +21,7 @@ public class SysUserOnline { private String deptName; /** - * 用户名称 + * 用户账号 */ private String userName; diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java index c60087202..ea9751bd0 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java @@ -34,13 +34,13 @@ public class SysUserExportVo implements Serializable { /** * 用户账号 */ - @ExcelProperty(value = "登录名称") + @ExcelProperty(value = "用户账号") private String userName; /** * 用户昵称 */ - @ExcelProperty(value = "用户名称") + @ExcelProperty(value = "用户昵称") private String nickName; /** diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java index 4507f631e..f4289cba0 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java @@ -38,13 +38,13 @@ public class SysUserImportVo implements Serializable { /** * 用户账号 */ - @ExcelProperty(value = "登录名称") + @ExcelProperty(value = "用户账号") private String userName; /** * 用户昵称 */ - @ExcelProperty(value = "用户名称") + @ExcelProperty(value = "用户昵称") private String nickName; /** diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java index 9e255f992..c1f77ae8d 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java @@ -101,7 +101,7 @@ public interface ISysUserService { String selectUserPostGroup(Long userId); /** - * 校验用户名称是否唯一 + * 校验用户账号是否唯一 * * @param user 用户信息 * @return 结果 diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java index 6d4d9fea9..a7bc06949 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java @@ -229,6 +229,9 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService @Override public String getDictLabel(String dictType, String dictValue, String separator) { List datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + if (CollUtil.isEmpty(datas)) { + return StringUtils.EMPTY; + } Map map = StreamUtils.toMap(datas, SysDictDataVo::getDictValue, SysDictDataVo::getDictLabel); if (StringUtils.containsAny(dictValue, separator)) { return Arrays.stream(dictValue.split(separator)) @@ -250,6 +253,9 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService @Override public String getDictValue(String dictType, String dictLabel, String separator) { List datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + if (CollUtil.isEmpty(datas)) { + return StringUtils.EMPTY; + } Map map = StreamUtils.toMap(datas, SysDictDataVo::getDictLabel, SysDictDataVo::getDictValue); if (StringUtils.containsAny(dictLabel, separator)) { return Arrays.stream(dictLabel.split(separator)) @@ -269,6 +275,9 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService @Override public Map getAllDictByDictType(String dictType) { List list = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + if (CollUtil.isEmpty(list)) { + return new HashMap<>(); + } // 保证顺序 LinkedHashMap map = new LinkedHashMap<>(); for (SysDictDataVo vo : list) { @@ -286,6 +295,9 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService @Override public DictTypeDTO getDictType(String dictType) { SysDictTypeVo vo = SpringUtils.getAopProxy(this).selectDictTypeByType(dictType); + if (ObjectUtil.isNull(vo)) { + return null; + } return BeanUtil.toBean(vo, DictTypeDTO.class); } @@ -298,6 +310,9 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService @Override public List getDictData(String dictType) { List list = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + if (CollUtil.isEmpty(list)) { + return new ArrayList<>(); + } return BeanUtil.copyToList(list, DictDataDTO.class); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java index 0c69b1f3f..fe2f3577e 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java @@ -112,7 +112,7 @@ public class SysMenuServiceImpl implements ISysMenuService { /** * 根据用户ID查询菜单 * - * @param userId 用户名称 + * @param userId 用户ID * @return 菜单列表 */ @Override diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java index 39ad4cb91..a6a301fed 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java @@ -232,7 +232,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService { } /** - * 校验用户名称是否唯一 + * 校验用户账号是否唯一 * * @param user 用户信息 * @return 结果 @@ -497,6 +497,11 @@ public class SysUserServiceImpl implements ISysUserService, UserService { roleList.remove(SystemConstants.SUPER_ADMIN_ID); } + // 移除超管角色后若无剩余角色,说明仅选了超管角色且不允许分配,显式报错 + if (roleList.isEmpty()) { + throw new ServiceException("不允许为普通用户分配超级管理员角色,请至少选择一个其他角色"); + } + // 校验是否有权限访问这些角色(含数据权限控制) if (roleMapper.selectRoleCount(roleList) != roleList.size()) { throw new ServiceException("没有权限访问角色的数据"); @@ -594,10 +599,10 @@ public class SysUserServiceImpl implements ISysUserService, UserService { } /** - * 通过用户ID查询用户账户 + * 通过用户ID查询用户昵称 * * @param userId 用户ID - * @return 用户账户 + * @return 用户昵称 */ @Override @Cacheable(cacheNames = CacheNames.SYS_NICKNAME, key = "#userId") @@ -608,10 +613,10 @@ public class SysUserServiceImpl implements ISysUserService, UserService { } /** - * 通过用户ID查询用户账户 + * 通过用户ID查询用户昵称 * * @param userIds 用户ID 多个用逗号隔开 - * @return 用户账户 + * @return 用户昵称 */ @Override public String selectNicknameByIds(String userIds) { @@ -751,13 +756,13 @@ public class SysUserServiceImpl implements ISysUserService, UserService { } /** - * 根据用户 ID 列表查询用户名称映射关系 + * 根据用户 ID 列表查询用户昵称映射关系 * * @param userIds 用户 ID 列表 - * @return Map,其中 key 为用户 ID,value 为对应的用户名称 + * @return Map,其中 key 为用户 ID,value 为对应的用户昵称 */ @Override - public Map selectUserNamesByIds(List userIds) { + public Map selectUserNicksByIds(List userIds) { if (CollUtil.isEmpty(userIds)) { return Collections.emptyMap(); } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java index 88372f0b7..203f3f667 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java @@ -23,26 +23,6 @@ public interface FlowConstant { */ String INITIATOR_DEPT_ID = "initiatorDeptId"; - /** - * 委托 - */ - String DELEGATE_TASK = "delegateTask"; - - /** - * 转办 - */ - String TRANSFER_TASK = "transferTask"; - - /** - * 加签 - */ - String ADD_SIGNATURE = "addSignature"; - - /** - * 减签 - */ - String REDUCTION_SIGNATURE = "reductionSignature"; - /** * 流程分类Id转名称 */ diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskOperationEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskOperationEnum.java new file mode 100644 index 000000000..8c050a28f --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskOperationEnum.java @@ -0,0 +1,53 @@ +package org.dromara.workflow.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 任务操作类型枚举 + * + * @author may + */ +@Getter +@AllArgsConstructor +public enum TaskOperationEnum { + + /** + * 委派 + */ + DELEGATE_TASK("delegateTask", "委派"), + + /** + * 转办 + */ + TRANSFER_TASK("transferTask", "转办"), + + /** + * 加签 + */ + ADD_SIGNATURE("addSignature", "加签"), + + /** + * 减签 + */ + REDUCTION_SIGNATURE("reductionSignature", "减签"); + + private final String code; + private final String desc; + + private static final Map CODE_MAP = Arrays.stream(values()) + .collect(Collectors.toConcurrentMap(TaskOperationEnum::getCode, Function.identity())); + + /** + * 根据 code 获取枚举 + */ + public static TaskOperationEnum getByCode(String code) { + return CODE_MAP.get(code); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java index 54e412ae0..2b1e3be72 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java @@ -1,5 +1,6 @@ package org.dromara.workflow.controller; +import cn.dev33.satoken.annotation.SaCheckPermission; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.dromara.common.core.domain.R; @@ -45,6 +46,7 @@ public class FlwDefinitionController extends BaseController { * @param pageQuery 分页 */ @GetMapping("/list") + @SaCheckPermission("workflow:definition:list") public TableDataInfo list(FlowDefinition flowDefinition, PageQuery pageQuery) { return flwDefinitionService.queryList(flowDefinition, pageQuery); } @@ -56,6 +58,7 @@ public class FlwDefinitionController extends BaseController { * @param pageQuery 分页 */ @GetMapping("/unPublishList") + @SaCheckPermission("workflow:definition:list") public TableDataInfo unPublishList(FlowDefinition flowDefinition, PageQuery pageQuery) { return flwDefinitionService.unPublishList(flowDefinition, pageQuery); } @@ -66,6 +69,7 @@ public class FlwDefinitionController extends BaseController { * @param id 流程定义id */ @GetMapping(value = "/{id}") + @SaCheckPermission("workflow:definition:query") public R getInfo(@PathVariable Long id) { return R.ok(defService.getById(id)); } @@ -79,6 +83,7 @@ public class FlwDefinitionController extends BaseController { @PostMapping @RepeatSubmit() @Transactional(rollbackFor = Exception.class) + @SaCheckPermission("workflow:definition:add") public R add(@RequestBody FlowDefinition flowDefinition) { return R.ok(defService.checkAndSave(flowDefinition)); } @@ -92,6 +97,7 @@ public class FlwDefinitionController extends BaseController { @PutMapping @RepeatSubmit() @Transactional(rollbackFor = Exception.class) + @SaCheckPermission("workflow:definition:edit") public R edit(@RequestBody FlowDefinition flowDefinition) { return R.ok(defService.updateById(flowDefinition)); } @@ -104,6 +110,7 @@ public class FlwDefinitionController extends BaseController { @Log(title = "流程定义", businessType = BusinessType.INSERT) @PutMapping("/publish/{id}") @RepeatSubmit() + @SaCheckPermission("workflow:definition:publish") public R publish(@PathVariable Long id) { return R.ok(flwDefinitionService.publish(id)); } @@ -117,6 +124,7 @@ public class FlwDefinitionController extends BaseController { @PutMapping("/unPublish/{id}") @RepeatSubmit() @Transactional(rollbackFor = Exception.class) + @SaCheckPermission("workflow:definition:publish") public R unPublish(@PathVariable Long id) { return R.ok(defService.unPublish(id)); } @@ -126,6 +134,7 @@ public class FlwDefinitionController extends BaseController { */ @Log(title = "流程定义", businessType = BusinessType.DELETE) @DeleteMapping("/{ids}") + @SaCheckPermission("workflow:definition:remove") public R remove(@PathVariable List ids) { return toAjax(flwDefinitionService.removeDef(ids)); } @@ -139,6 +148,7 @@ public class FlwDefinitionController extends BaseController { @PostMapping("/copy/{id}") @RepeatSubmit() @Transactional(rollbackFor = Exception.class) + @SaCheckPermission("workflow:definition:copy") public R copy(@PathVariable Long id) { return R.ok(defService.copyDef(id)); } @@ -151,6 +161,7 @@ public class FlwDefinitionController extends BaseController { */ @Log(title = "流程定义", businessType = BusinessType.IMPORT) @PostMapping("/importDef") + @SaCheckPermission("workflow:definition:import") public R importDef(MultipartFile file, String category) { return R.ok(flwDefinitionService.importJson(file, category)); } @@ -164,6 +175,7 @@ public class FlwDefinitionController extends BaseController { */ @Log(title = "流程定义", businessType = BusinessType.EXPORT) @PostMapping("/exportDef/{id}") + @SaCheckPermission("workflow:definition:export") public void exportDef(@PathVariable Long id, HttpServletResponse response) throws IOException { flwDefinitionService.exportDef(id, response); } @@ -174,6 +186,7 @@ public class FlwDefinitionController extends BaseController { * @param id 流程定义id */ @GetMapping("/xmlString/{id}") + @SaCheckPermission("workflow:definition:query") public R xmlString(@PathVariable Long id) { return R.ok("操作成功", defService.exportJson(id)); } @@ -188,6 +201,7 @@ public class FlwDefinitionController extends BaseController { @PutMapping("/active/{id}") @Transactional(rollbackFor = Exception.class) @Log(title = "流程定义", businessType = BusinessType.UPDATE) + @SaCheckPermission("workflow:definition:active") public R active(@PathVariable Long id, @RequestParam boolean active) { return R.ok(active ? defService.active(id) : defService.unActive(id)); } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java index a8a5fc604..c93a40c37 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java @@ -1,5 +1,6 @@ package org.dromara.workflow.controller; +import cn.dev33.satoken.annotation.SaCheckPermission; import cn.hutool.core.convert.Convert; import lombok.RequiredArgsConstructor; import org.dromara.common.core.domain.R; @@ -46,6 +47,7 @@ public class FlwInstanceController extends BaseController { * @param pageQuery 分页 */ @GetMapping("/pageByRunning") + @SaCheckPermission("workflow:instance:list") public TableDataInfo selectRunningInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) { return flwInstanceService.selectRunningInstanceList(flowInstanceBo, pageQuery); } @@ -57,6 +59,7 @@ public class FlwInstanceController extends BaseController { * @param pageQuery 分页 */ @GetMapping("/pageByFinish") + @SaCheckPermission("workflow:instance:list") public TableDataInfo selectFinishInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) { return flwInstanceService.selectFinishInstanceList(flowInstanceBo, pageQuery); } @@ -67,6 +70,7 @@ public class FlwInstanceController extends BaseController { * @param businessId 业务id */ @GetMapping("/getInfo/{businessId}") + @SaCheckPermission("workflow:instance:query") public R getInfo(@PathVariable Long businessId) { return R.ok(flwInstanceService.queryByBusinessId(businessId)); } @@ -78,6 +82,7 @@ public class FlwInstanceController extends BaseController { */ @DeleteMapping("/deleteByBusinessIds/{businessIds}") @Log(title = "流程实例管理", businessType = BusinessType.DELETE) + @SaCheckPermission("workflow:instance:remove") public R deleteByBusinessIds(@PathVariable List businessIds) { return toAjax(flwInstanceService.deleteByBusinessIds(StreamUtils.toList(businessIds, Convert::toStr))); } @@ -89,6 +94,7 @@ public class FlwInstanceController extends BaseController { */ @DeleteMapping("/deleteByInstanceIds/{instanceIds}") @Log(title = "流程实例管理", businessType = BusinessType.DELETE) + @SaCheckPermission("workflow:instance:remove") public R deleteByInstanceIds(@PathVariable List instanceIds) { return toAjax(flwInstanceService.deleteByInstanceIds(instanceIds)); } @@ -100,6 +106,7 @@ public class FlwInstanceController extends BaseController { */ @DeleteMapping("/deleteHisByInstanceIds/{instanceIds}") @Log(title = "流程实例管理", businessType = BusinessType.DELETE) + @SaCheckPermission("workflow:instance:remove") public R deleteHisByInstanceIds(@PathVariable List instanceIds) { return toAjax(flwInstanceService.deleteHisByInstanceIds(instanceIds)); } @@ -112,6 +119,7 @@ public class FlwInstanceController extends BaseController { @RepeatSubmit() @PutMapping("/cancelProcessApply") @Log(title = "流程实例管理", businessType = BusinessType.UPDATE) + @SaCheckPermission("workflow:instance:cancel") public R cancelProcessApply(@RequestBody FlowCancelBo bo) { return toAjax(flwInstanceService.cancelProcessApply(bo)); } @@ -125,6 +133,7 @@ public class FlwInstanceController extends BaseController { @RepeatSubmit() @PutMapping("/active/{id}") @Log(title = "流程实例管理", businessType = BusinessType.UPDATE) + @SaCheckPermission("workflow:instance:active") public R active(@PathVariable Long id, @RequestParam boolean active) { return R.ok(active ? insService.active(id) : insService.unActive(id)); } @@ -136,6 +145,7 @@ public class FlwInstanceController extends BaseController { * @param pageQuery 分页 */ @GetMapping("/pageByCurrent") + @SaCheckPermission("workflow:instance:currentList") public TableDataInfo selectCurrentInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) { return flwInstanceService.selectCurrentInstanceList(flowInstanceBo, pageQuery); } @@ -146,6 +156,7 @@ public class FlwInstanceController extends BaseController { * @param businessId 业务id */ @GetMapping("/flowHisTaskList/{businessId}") + @SaCheckPermission("workflow:instance:query") public R> flowHisTaskList(@PathVariable String businessId) { return R.ok(flwInstanceService.flowHisTaskList(businessId)); } @@ -156,6 +167,7 @@ public class FlwInstanceController extends BaseController { * @param instanceId 流程实例id */ @GetMapping("/instanceVariable/{instanceId}") + @SaCheckPermission("workflow:instance:variableQuery") public R> instanceVariable(@PathVariable Long instanceId) { return R.ok(flwInstanceService.instanceVariable(instanceId)); } @@ -168,6 +180,7 @@ public class FlwInstanceController extends BaseController { @RepeatSubmit() @PutMapping("/updateVariable") @Log(title = "流程实例管理", businessType = BusinessType.UPDATE) + @SaCheckPermission("workflow:instance:variable") public R updateVariable(@Validated @RequestBody FlowVariableBo bo) { return toAjax(flwInstanceService.updateVariable(bo)); } @@ -180,6 +193,7 @@ public class FlwInstanceController extends BaseController { @Log(title = "流程实例管理", businessType = BusinessType.INSERT) @RepeatSubmit() @PostMapping("/invalid") + @SaCheckPermission("workflow:instance:invalid") public R invalid(@Validated @RequestBody FlowInvalidBo bo) { return R.ok(flwInstanceService.processInvalid(bo)); } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java index a67a1f78e..a9674b0b3 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java @@ -61,7 +61,8 @@ public class BackProcessBo implements Serializable { public Map getVariables() { if (variables == null) { - return new HashMap<>(16); + variables = new HashMap<>(16); + return variables; } variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); return variables; diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java index a45e52109..894174929 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java @@ -23,8 +23,8 @@ public class FlowCopyBo implements Serializable { private Long userId; /** - * 用户名称 + * 用户昵称 */ - private String userName; + private String nickName; } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowNextNodeBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowNextNodeBo.java index 12f0653ef..de75ba621 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowNextNodeBo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowNextNodeBo.java @@ -30,7 +30,8 @@ public class FlowNextNodeBo implements Serializable { public Map getVariables() { if (variables == null) { - return new HashMap<>(16); + variables = new HashMap<>(16); + return variables; } variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); return variables; diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java index b31f4fa14..98f33a007 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java @@ -53,7 +53,8 @@ public class StartProcessBo implements Serializable { public Map getVariables() { if (variables == null) { - return new HashMap<>(16); + variables = new HashMap<>(16); + return variables; } variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); return variables; diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java index 4348e310c..0846e73b4 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java @@ -40,6 +40,11 @@ public class TaskOperationBo implements Serializable { @NotNull(message = "任务id不能为空") private Long taskId; + /** + * 消息类型 + */ + private List messageType; + /** * 意见或备注信息(可选) */ diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCopyVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCopyVo.java index 67ef9e2c3..c58071570 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCopyVo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCopyVo.java @@ -24,10 +24,10 @@ public class FlowCopyVo implements Serializable { private Long userId; /** - * 用户名称 + * 用户昵称 */ @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "userId") - private String userName; + private String nickName; public FlowCopyVo(Long userId) { this.userId = userId; diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java index efd24ffd6..d8ba911f2 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java @@ -80,11 +80,13 @@ public class WorkflowGlobalListener implements GlobalListener { NodeExtVo nodeExt = nodeExtService.parseNodeExt(ext, variable); Set copyList = nodeExt.getCopySettings(); if (CollUtil.isNotEmpty(copyList)) { + List userIds = StreamUtils.toList(copyList, Convert::toLong); + Map nickNameMap = userService.selectUserNicksByIds(userIds); List list = StreamUtils.toList(copyList, x -> { FlowCopyBo bo = new FlowCopyBo(); Long id = Convert.toLong(x); bo.setUserId(id); - bo.setUserName(userService.selectUserNameById(id)); + bo.setNickName(nickNameMap.getOrDefault(id, StringUtils.EMPTY)); return bo; }); variable.put(FlowConstant.FLOW_COPY_LIST, list); @@ -159,7 +161,7 @@ public class WorkflowGlobalListener implements GlobalListener { flowTask.setPermissionList(List.of(userIdArray)); // 移除已处理的状态变量 variable.remove(nodeKey); - FlowEngine.insService().removeVariables(flowTask.getInstanceId(),nodeKey); + FlowEngine.insService().removeVariables(flowTask.getInstanceId(), nodeKey); } } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java index 8d4708b8e..77389bcaa 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java @@ -5,6 +5,7 @@ import cn.hutool.core.util.ObjectUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.StreamUtils; import org.dromara.common.core.utils.StringUtils; @@ -98,7 +99,14 @@ public class FlwCommonServiceImpl implements IFlwCommonService { } case EMAIL_MESSAGE -> MailUtils.sendText(emails, subject, message); case SMS_MESSAGE -> { - // TODO: 补充短信发送逻辑 +// LinkedHashMap map = new LinkedHashMap<>(1); +// // 根据具体短信服务商参数用法传参 +// map.put("code", "1234"); +// // 自动获取一个短信服务商 +// SmsBlend smsBlend = SmsFactory.getSmsBlend(); +// // 指定获取一个短信服务商 configKey +// SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); +// SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map); log.info("【短信发送 - TODO】用户数量={} 内容={}", userList.size(), message); } default -> log.warn("【消息发送】未处理的消息类型:{}", messageTypeEnum); @@ -119,6 +127,9 @@ public class FlwCommonServiceImpl implements IFlwCommonService { @Override public String applyNodeCode(Long definitionId) { List firstBetweenNode = FlowEngine.nodeService().getFirstBetweenNode(definitionId, new HashMap<>()); + if (CollUtil.isEmpty(firstBetweenNode)) { + throw new ServiceException("流程定义缺少申请人节点,请检查流程定义配置"); + } return firstBetweenNode.get(0).getNodeCode(); } } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java index 4de669da7..48147364a 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java @@ -111,8 +111,14 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService { @Override public FlowInstanceVo queryByBusinessId(Long businessId) { FlowInstance instance = this.selectInstByBusinessId(Convert.toStr(businessId)); + if (ObjectUtil.isNull(instance)) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE); + } FlowInstanceVo instanceVo = BeanUtil.toBean(instance, FlowInstanceVo.class); Definition definition = defService.getById(instanceVo.getDefinitionId()); + if (ObjectUtil.isNull(definition)) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_DEF); + } instanceVo.setFlowName(definition.getFlowName()); instanceVo.setFlowCode(definition.getFlowCode()); instanceVo.setVersion(definition.getVersion()); @@ -187,6 +193,8 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService { log.warn("未找到对应的流程实例信息,无法执行删除操作。"); return false; } + // 发送事件 + processDeleteHandler(flowInstances); return insService.remove(StreamUtils.toList(flowInstances, FlowInstance::getId)); } @@ -199,27 +207,13 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService { @Transactional(rollbackFor = Exception.class) public boolean deleteByInstanceIds(List instanceIds) { // 获取实例信息 - List instances = insService.getByIds(instanceIds); - if (CollUtil.isEmpty(instances)) { + List flowInstances = flowInstanceMapper.selectByIds(instanceIds); + if (CollUtil.isEmpty(flowInstances)) { log.warn("未找到对应的流程实例信息,无法执行删除操作。"); return false; } - // 获取定义信息 - Map definitionMap = StreamUtils.toMap( - defService.getByIds(StreamUtils.toList(instances, Instance::getDefinitionId)), - Definition::getId, - Function.identity() - ); - - // 逐一触发删除事件 - instances.forEach(instance -> { - Definition definition = definitionMap.get(instance.getDefinitionId()); - if (ObjectUtil.isNull(definition)) { - log.warn("实例 ID: {} 对应的流程定义信息未找到,跳过删除事件触发。", instance.getId()); - return; - } - flowProcessEventHandler.processDeleteHandler(definition.getFlowCode(), instance.getBusinessId()); - }); + // 发送事件 + processDeleteHandler(flowInstances); // 删除实例 return insService.remove(instanceIds); } @@ -233,26 +227,13 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService { @Transactional(rollbackFor = Exception.class) public boolean deleteHisByInstanceIds(List instanceIds) { // 获取实例信息 - List instances = insService.getByIds(instanceIds); - if (CollUtil.isEmpty(instances)) { + List flowInstances = flowInstanceMapper.selectByIds(instanceIds); + if (CollUtil.isEmpty(flowInstances)) { log.warn("未找到对应的流程实例信息,无法执行删除操作。"); return false; } - // 获取定义信息 - Map definitionMap = StreamUtils.toMap( - defService.getByIds(StreamUtils.toList(instances, Instance::getDefinitionId)), - Definition::getId, - Function.identity() - ); - // 逐一触发删除事件 - instances.forEach(instance -> { - Definition definition = definitionMap.get(instance.getDefinitionId()); - if (ObjectUtil.isNull(definition)) { - log.warn("实例 ID: {} 对应的流程定义信息未找到,跳过删除事件触发。", instance.getId()); - return; - } - flowProcessEventHandler.processDeleteHandler(definition.getFlowCode(), instance.getBusinessId()); - }); + // 发送事件 + processDeleteHandler(flowInstances); List flowTaskList = flwTaskService.selectByInstIds(instanceIds); if (CollUtil.isNotEmpty(flowTaskList)) { FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTaskList, FlowTask::getId)); @@ -263,6 +244,35 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService { return true; } + + private void processDeleteHandler(List flowInstances) { + + String userId = LoginHelper.getUserIdStr(); + for (FlowInstance flowInstance : flowInstances) { + //如果创建人与当前登陆人一致或者当前登陆人为管理员才能删除 + if (LoginHelper.isSuperAdmin() || flowInstance.getCreateBy().equals(userId)) { + continue; + } + throw new ServiceException("权限不足,无法删除流程实例信息!"); + } + // 获取定义信息 + Map definitionMap = StreamUtils.toMap( + defService.getByIds(StreamUtils.toList(flowInstances, Instance::getDefinitionId)), + Definition::getId, + Function.identity() + ); + + // 逐一触发删除事件 + flowInstances.forEach(instance -> { + Definition definition = definitionMap.get(instance.getDefinitionId()); + if (ObjectUtil.isNull(definition)) { + log.warn("实例 ID: {} 对应的流程定义信息未找到,跳过删除事件触发。", instance.getId()); + return; + } + flowProcessEventHandler.processDeleteHandler(definition.getFlowCode(), instance.getBusinessId()); + }); + } + /** * 撤销流程 * @@ -279,8 +289,11 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService { if (definition == null) { throw new ServiceException(ExceptionCons.NOT_FOUNT_DEF); } - String message = bo.getMessage(); String userIdStr = LoginHelper.getUserIdStr(); + if (!LoginHelper.isSuperAdmin() && !instance.getCreateBy().equals(userIdStr)) { + throw new ServiceException("权限不足,无法撤销流程!"); + } + String message = bo.getMessage(); BusinessStatusEnum.checkCancelStatus(instance.getFlowStatus()); FlowParams flowParams = FlowParams.build() .message(message) @@ -383,6 +396,9 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService { @Override public Map instanceVariable(Long instanceId) { FlowInstance flowInstance = flowInstanceMapper.selectById(instanceId); + if (ObjectUtil.isNull(flowInstance)) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE); + } Map variableMap = Optional.ofNullable(flowInstance.getVariableMap()).orElse(Collections.emptyMap()); List> variableList = variableMap.entrySet().stream() .map(entry -> Map.of("key", entry.getKey(), "value", entry.getValue())) diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwNodeExtServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwNodeExtServiceImpl.java index ce845dc45..8e398692c 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwNodeExtServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwNodeExtServiceImpl.java @@ -102,7 +102,7 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService * @param sources 数据来源(枚举类或字典类型) * @return 构建的 `NodeExt` 对象 */ - @SuppressWarnings("unchecked cast") + @SuppressWarnings("unchecked") private NodeExt buildNodeExt(String code, String name, int type, List sources) { NodeExt nodeExt = new NodeExt(); nodeExt.setCode(code); diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwSpelServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwSpelServiceImpl.java index 3790cdfd4..090ac81db 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwSpelServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwSpelServiceImpl.java @@ -1,6 +1,7 @@ package org.dromara.workflow.service.impl; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -9,6 +10,7 @@ import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.constant.SystemConstants; import org.dromara.common.core.domain.dto.TaskAssigneeDTO; import org.dromara.common.core.domain.model.TaskAssigneeBody; +import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.StreamUtils; import org.dromara.common.core.utils.StringUtils; @@ -125,7 +127,14 @@ public class FlwSpelServiceImpl implements IFlwSpelService { * 保存前的数据校验 */ private void validEntityBeforeSave(FlowSpel entity){ - //TODO 做一些数据校验,如唯一约束 + if (StringUtils.isNotBlank(entity.getViewSpel())) { + boolean exists = baseMapper.exists(new LambdaQueryWrapper() + .eq(FlowSpel::getViewSpel, entity.getViewSpel()) + .ne(ObjectUtil.isNotNull(entity.getId()), FlowSpel::getId, entity.getId())); + if (exists) { + throw new ServiceException("SpEL表达式已存在,请勿重复添加"); + } + } } /** @@ -137,7 +146,7 @@ public class FlwSpelServiceImpl implements IFlwSpelService { */ @Override public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { - if(isValid){ + if (isValid){ //TODO 做一些业务上的校验,判断是否需要校验 } return baseMapper.deleteByIds(ids) > 0; diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java index 9e9c091ad..8edccd03e 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java @@ -244,7 +244,7 @@ public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, Hand List longIds = StreamUtils.toList(ids, Convert::toLong); Map rawMap = switch (type) { - case USER -> userService.selectUserNamesByIds(longIds); + case USER -> userService.selectUserNicksByIds(longIds); case ROLE -> roleService.selectRoleNamesByIds(longIds); case DEPT -> deptService.selectDeptNamesByIds(longIds); case POST -> postService.selectPostNamesByIds(longIds); diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java index 0a8bdc72d..af693e6e1 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java @@ -44,8 +44,8 @@ import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper; import org.dromara.warm.flow.orm.mapper.FlowNodeMapper; import org.dromara.warm.flow.orm.mapper.FlowTaskMapper; import org.dromara.workflow.common.ConditionalOnEnable; -import org.dromara.workflow.common.constant.FlowConstant; import org.dromara.workflow.common.enums.TaskAssigneeType; +import org.dromara.workflow.common.enums.TaskOperationEnum; import org.dromara.workflow.common.enums.TaskStatusEnum; import org.dromara.workflow.domain.FlowInstanceBizExt; import org.dromara.workflow.domain.bo.*; @@ -127,6 +127,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService { // 已存在流程 BusinessStatusEnum.checkStartStatus(flowInstance.getFlowStatus()); List taskList = taskService.list(new FlowTask().setInstanceId(flowInstance.getId())); + if (CollUtil.isEmpty(taskList)) { + throw new ServiceException("流程实例缺少任务,请检查流程定义配置"); + } taskService.mergeVariable(flowInstance, variables); insService.updateById(flowInstance); StartProcessReturnDTO dto = new StartProcessReturnDTO(); @@ -143,9 +146,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService { throw new ServiceException("流程【" + startProcessBo.getFlowCode() + "】未发布,请先在流程设计器中发布流程定义"); } Dict dict = JsonUtils.parseMap(definition.getExt()); - boolean autoPass = !ObjectUtil.isNull(dict) && dict.getBool(FlowConstant.AUTO_PASS); - variables.put(FlowConstant.AUTO_PASS, autoPass); - variables.put(FlowConstant.BUSINESS_CODE, this.generateBusinessCode(bizExt)); + boolean autoPass = !ObjectUtil.isNull(dict) && dict.getBool(AUTO_PASS); + variables.put(AUTO_PASS, autoPass); + variables.put(BUSINESS_CODE, this.generateBusinessCode(bizExt)); FlowParams flowParams = FlowParams.build() .handler(startProcessBo.getHandler()) .flowCode(startProcessBo.getFlowCode()) @@ -156,6 +159,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService { this.buildFlowInstanceBizExt(instance, bizExt); // 申请人执行流程 List taskList = taskService.list(new FlowTask().setInstanceId(instance.getId())); + if (CollUtil.isEmpty(taskList)) { + throw new ServiceException("流程启动失败,未生成任务"); + } if (taskList.size() > 1) { throw new ServiceException("请检查流程第一个环节是否为申请人!"); } @@ -207,11 +213,11 @@ public class FlwTaskServiceImpl implements IFlwTaskService { List flowCopyList = completeTaskBo.getFlowCopyList(); // 设置抄送人 Map variables = completeTaskBo.getVariables(); - variables.put(FlowConstant.FLOW_COPY_LIST, flowCopyList); + variables.put(FLOW_COPY_LIST, flowCopyList); // 消息类型 - variables.put(FlowConstant.MESSAGE_TYPE, messageType); + variables.put(MESSAGE_TYPE, messageType); // 消息通知 - variables.put(FlowConstant.MESSAGE_NOTICE, notice); + variables.put(MESSAGE_NOTICE, notice); FlowTask flowTask = flowTaskMapper.selectById(taskId); @@ -219,9 +225,12 @@ public class FlwTaskServiceImpl implements IFlwTaskService { throw new ServiceException("流程任务不存在或任务已审批!"); } Instance ins = insService.getById(flowTask.getInstanceId()); + if (ObjectUtil.isNull(ins)) { + throw new ServiceException("流程实例不存在"); + } // 检查流程状态是否为草稿、已撤销或已退回状态,若是则执行流程提交监听 if (BusinessStatusEnum.isDraftOrCancelOrBack(ins.getFlowStatus())) { - variables.put(FlowConstant.SUBMIT, true); + variables.put(SUBMIT, true); } // 设置弹窗处理人 Map assigneeMap = setPopAssigneeMap(completeTaskBo.getAssigneeMap(), ins.getVariableMap()); @@ -274,9 +283,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService { flowParams. message("流程引擎自动审批!"). variable(Map.of( - FlowConstant.SUBMIT, false, - FlowConstant.FLOW_COPY_LIST, Collections.emptyList(), - FlowConstant.MESSAGE_NOTICE, StringUtils.EMPTY)); + SUBMIT, false, + FLOW_COPY_LIST, Collections.emptyList(), + MESSAGE_NOTICE, StringUtils.EMPTY)); skipTask(task.getId(), flowParams, instanceId, true); } } @@ -341,7 +350,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService { FlowParams flowParams = FlowParams.build() .skipType(SkipType.NONE.getKey()) .hisStatus(TaskStatusEnum.COPY.getStatus()) - .message("【抄送给】" + StreamUtils.join(flowCopyList, FlowCopyBo::getUserName)); + .message("【抄送给】" + StreamUtils.join(flowCopyList, FlowCopyBo::getNickName)); HisTask hisTask = hisTaskService.setSkipHisTask(task, flowNode, flowParams); hisTask.setCreateTime(updateTime); hisTask.setUpdateTime(updateTime); @@ -482,15 +491,18 @@ public class FlwTaskServiceImpl implements IFlwTaskService { throw new ServiceException("任务不存在!"); } Instance inst = insService.getById(task.getInstanceId()); + if (ObjectUtil.isNull(inst)) { + throw new ServiceException("流程实例不存在"); + } BusinessStatusEnum.checkBackStatus(inst.getFlowStatus()); Long definitionId = task.getDefinitionId(); String applyNodeCode = flwCommonService.applyNodeCode(definitionId); Map variable = new HashMap<>(); // 消息类型 - variable.put(FlowConstant.MESSAGE_TYPE, messageType); + variable.put(MESSAGE_TYPE, messageType); // 消息通知 - variable.put(FlowConstant.MESSAGE_NOTICE, notice); + variable.put(MESSAGE_NOTICE, notice); FlowParams flowParams = FlowParams.build() .nodeCode(bo.getNodeCode()) @@ -513,6 +525,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService { @Override public List getBackTaskNode(Long taskId, String nowNodeCode) { FlowTask task = flowTaskMapper.selectById(taskId); + if (ObjectUtil.isNull(task)) { + throw new ServiceException("任务不存在!"); + } List nodeCodes = nodeService.getByNodeCodes(Collections.singletonList(nowNodeCode), task.getDefinitionId()); if (!CollUtil.isNotEmpty(nodeCodes)) { return nodeCodes; @@ -597,7 +612,13 @@ public class FlwTaskServiceImpl implements IFlwTaskService { } FlowTaskVo flowTaskVo = BeanUtil.toBean(task, FlowTaskVo.class); Instance instance = insService.getById(task.getInstanceId()); + if (ObjectUtil.isNull(instance)) { + throw new ServiceException("流程实例不存在"); + } Definition definition = defService.getById(task.getDefinitionId()); + if (ObjectUtil.isNull(definition)) { + throw new ServiceException("流程定义不存在"); + } flowTaskVo.setFlowStatus(instance.getFlowStatus()); flowTaskVo.setVersion(definition.getVersion()); flowTaskVo.setFlowCode(definition.getFlowCode()); @@ -640,11 +661,23 @@ public class FlwTaskServiceImpl implements IFlwTaskService { Long taskId = bo.getTaskId(); Map variables = bo.getVariables(); Task task = taskService.getById(taskId); + if (ObjectUtil.isNull(task)) { + throw new ServiceException("任务不存在!"); + } Instance instance = insService.getById(task.getInstanceId()); + if (ObjectUtil.isNull(instance)) { + throw new ServiceException("流程实例不存在"); + } Definition definition = defService.getById(task.getDefinitionId()); + if (ObjectUtil.isNull(definition)) { + throw new ServiceException("流程定义不存在"); + } Map mergeVariable = MapUtil.mergeAll(instance.getVariableMap(), variables); // 获取下一节点列表 List nextNodeList = nodeService.getNextNodeList(task.getDefinitionId(), task.getNodeCode(), null, SkipType.PASS.getKey(), mergeVariable); + if (CollUtil.isEmpty(nextNodeList)) { + return new ArrayList<>(); + } List nextFlowNodes = BeanUtil.copyToList(nextNodeList, FlowNode.class); // 只获取中间节点 nextFlowNodes = StreamUtils.filter(nextFlowNodes, node -> NodeType.BETWEEN.getKey().equals(node.getNodeType())); @@ -719,13 +752,19 @@ public class FlwTaskServiceImpl implements IFlwTaskService { @Override @Transactional(rollbackFor = Exception.class) public boolean taskOperation(TaskOperationBo bo, String taskOperation) { + TaskOperationEnum op = TaskOperationEnum.getByCode(taskOperation); + if (op == null) { + log.error("Invalid operation type:{} ", taskOperation); + throw new ServiceException("Invalid operation type " + taskOperation); + } + FlowParams flowParams = FlowParams.build().message(bo.getMessage()); if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) { flowParams.ignore(true); } // 根据操作类型构建 FlowParams - switch (taskOperation) { + switch (op) { case DELEGATE_TASK, TRANSFER_TASK -> { ValidatorUtils.validate(bo, AddGroup.class); flowParams.addHandlers(Collections.singletonList(bo.getUserId())); @@ -738,47 +777,63 @@ public class FlwTaskServiceImpl implements IFlwTaskService { ValidatorUtils.validate(bo, EditGroup.class); flowParams.reductionHandlers(bo.getUserIds()); } - default -> { - log.error("Invalid operation type:{} ", taskOperation); - throw new ServiceException("Invalid operation type " + taskOperation); - } } Long taskId = bo.getTaskId(); Task task = taskService.getById(taskId); + if (ObjectUtil.isNull(task)) { + throw new ServiceException("任务不存在!"); + } FlowNode flowNode = getByNodeCode(task.getNodeCode(), task.getDefinitionId()); - if (ADD_SIGNATURE.equals(taskOperation) || REDUCTION_SIGNATURE.equals(taskOperation)) { + if (ObjectUtil.isNull(flowNode)) { + throw new ServiceException("流程节点不存在"); + } + if (op == TaskOperationEnum.ADD_SIGNATURE || op == TaskOperationEnum.REDUCTION_SIGNATURE) { if (CooperateType.isOrSign(flowNode.getNodeRatio())) { throw new ServiceException(task.getNodeName() + "不是会签或票签节点!"); } } + // 设置任务状态并执行对应的任务操作 - switch (taskOperation) { - //委派任务 + boolean result = false; + switch (op) { case DELEGATE_TASK -> { flowParams.hisStatus(TaskStatusEnum.DEPUTE.getStatus()); - return taskService.depute(taskId, flowParams); + result = taskService.depute(taskId, flowParams); } - //转办任务 case TRANSFER_TASK -> { flowParams.hisStatus(TaskStatusEnum.TRANSFER.getStatus()); - return taskService.transfer(taskId, flowParams); + result = taskService.transfer(taskId, flowParams); } - //加签,增加办理人 case ADD_SIGNATURE -> { flowParams.hisStatus(TaskStatusEnum.SIGN.getStatus()); - return taskService.addSignature(taskId, flowParams); + result = taskService.addSignature(taskId, flowParams); } - //减签,减少办理人 case REDUCTION_SIGNATURE -> { flowParams.hisStatus(TaskStatusEnum.SIGN_OFF.getStatus()); - return taskService.reductionSignature(taskId, flowParams); - } - default -> { - log.error("Invalid operation type:{} ", taskOperation); - throw new ServiceException("Invalid operation type " + taskOperation); + result = taskService.reductionSignature(taskId, flowParams); } } + + // 操作执行成功后再发送消息 + if (result && CollUtil.isNotEmpty(bo.getMessageType())) { + List userIdList = new ArrayList<>(); + if (StrUtil.isNotBlank(bo.getUserId())) { + userIdList.add(Convert.toLong(bo.getUserId())); + } + if (CollUtil.isNotEmpty(bo.getUserIds())) { + userIdList.addAll(StreamUtils.toList(bo.getUserIds(), Convert::toLong)); + } + if (CollUtil.isNotEmpty(userIdList)) { + flwCommonService.sendMessage( + bo.getMessageType(), + StringUtils.isNotBlank(bo.getMessage()) ? bo.getMessage() : "单据「" + op.getDesc() + "」通知", + "单据「" + op.getDesc() + "」提醒", + userService.selectListByIds(userIdList) + ); + } + } + return result; } /** diff --git a/script/docker/docker-compose.yml b/script/docker/docker-compose.yml index f40a4ff01..a22ed3163 100644 --- a/script/docker/docker-compose.yml +++ b/script/docker/docker-compose.yml @@ -65,8 +65,8 @@ services: network_mode: "host" minio: - # minio 最后一个未阉割版本 不能再进行升级 在往上的版本功能被阉割 - image: minio/minio:RELEASE.2025-04-22T22-12-26Z + # pgsty 开源社区 fork 重新维护的最新版 minio + image: pgsty/minio:RELEASE.2026-02-14T12-00-00Z container_name: minio ports: # api 端口 @@ -99,7 +99,7 @@ services: network_mode: "host" ruoyi-server1: - image: ruoyi/ruoyi-server:5.5.3 + image: ruoyi/ruoyi-server:5.6.0 container_name: ruoyi-server1 environment: # 时区上海 @@ -115,7 +115,7 @@ services: network_mode: "host" ruoyi-server2: - image: ruoyi/ruoyi-server:5.5.3 + image: ruoyi/ruoyi-server:5.6.0 container_name: ruoyi-server2 environment: # 时区上海 @@ -131,7 +131,7 @@ services: network_mode: "host" ruoyi-monitor-admin: - image: ruoyi/ruoyi-monitor-admin:5.5.3 + image: ruoyi/ruoyi-monitor-admin:5.6.0 container_name: ruoyi-monitor-admin environment: # 时区上海 @@ -143,7 +143,7 @@ services: network_mode: "host" ruoyi-snailjob-server: - image: ruoyi/ruoyi-snailjob-server:5.5.3 + image: ruoyi/ruoyi-snailjob-server:5.6.0 container_name: ruoyi-snailjob-server environment: # 时区上海 diff --git a/script/sql/oracle/oracle_ry_workflow.sql b/script/sql/oracle/oracle_ry_workflow.sql index 7f5ab22fa..3e994f3e6 100644 --- a/script/sql/oracle/oracle_ry_workflow.sql +++ b/script/sql/oracle/oracle_ry_workflow.sql @@ -473,11 +473,11 @@ INSERT INTO sys_menu VALUES ('11618', '我的任务', '0', '7', 'task', '', '', INSERT INTO sys_menu VALUES ('11619', '我的待办', '11618', '2', 'taskWaiting', 'workflow/task/taskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, SYSDATE, NULL, NULL, ''); INSERT INTO sys_menu VALUES ('11632', '我的已办', '11618', '3', 'taskFinish', 'workflow/task/taskFinish', '', '1', '1', 'C', '0', '0', '', 'finish', 103, 1, SYSDATE, NULL, NULL, ''); INSERT INTO sys_menu VALUES ('11633', '我的抄送', '11618', '4', 'taskCopyList', 'workflow/task/taskCopyList', '', '1', '1', 'C', '0', '0', '', 'my-copy', 103, 1, SYSDATE, NULL, NULL, ''); -INSERT INTO sys_menu VALUES ('11620', '流程定义', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '', 'process-definition', 103, 1, SYSDATE, NULL, NULL, ''); -INSERT INTO sys_menu VALUES ('11621', '流程实例', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11620', '流程定义', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', 'workflow:definition:list', 'process-definition', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11621', '流程实例', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', 'workflow:instance:list', 'tree-table', 103, 1, SYSDATE, NULL, NULL, ''); INSERT INTO sys_menu VALUES ('11622', '流程分类', '11616', '1', 'category', 'workflow/category/index', '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, SYSDATE, NULL, NULL, ''); -INSERT INTO sys_menu VALUES ('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', '', 'guide', 103, 1, SYSDATE, NULL, NULL, ''); -INSERT INTO sys_menu VALUES ('11630', '流程监控', '11616', '4', 'monitor', '', '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', 'workflow:instance:currentList', 'guide', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11630', '流程监控', '11616', '4', 'processMonitor', '', '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, SYSDATE, NULL, NULL, ''); INSERT INTO sys_menu VALUES ('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, SYSDATE, NULL, NULL, ''); INSERT INTO sys_menu VALUES ('11700', '流程设计', '11616', '5', 'design/index', 'workflow/processDefinition/design', '', '1', '1', 'C', '1', '0', 'workflow:leave:edit', '#', 103, 1, SYSDATE, NULL, NULL, '/workflow/processDefinition'); INSERT INTO sys_menu VALUES ('11701', '请假申请', '11616', '6', 'leaveEdit/index', 'workflow/leave/leaveEdit', '', '1', '1', 'C', '1', '0', 'workflow:leave:edit', '#', 103, 1, SYSDATE, NULL, NULL, ''); @@ -488,6 +488,26 @@ INSERT INTO sys_menu VALUES ('11625', '流程分类修改', '11622', '3', '#', ' INSERT INTO sys_menu VALUES ('11626', '流程分类删除', '11622', '4', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:remove', '#', 103, 1, SYSDATE, NULL, NULL, ''); INSERT INTO sys_menu VALUES ('11627', '流程分类导出', '11622', '5', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:export', '#', 103, 1, SYSDATE, NULL, NULL, ''); +-- 流程实例管理相关按钮 +INSERT INTO sys_menu VALUES ('11653', '流程实例查询', '11621', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:instance:query', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11654', '流程变量查询', '11621', '2', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:instance:variableQuery', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11655', '流程变量修改', '11621', '3', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:instance:variable', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11656', '流程实例激活/挂起', '11621', '4', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:instance:active', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11657', '流程实例删除', '11621', '5', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:instance:remove', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11658', '流程实例作废', '11621', '6', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:instance:invalid', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11659', '流程实例撤销', '11621', '7', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:instance:cancel', '#', 103, 1, SYSDATE, NULL, NULL, ''); + +-- 流程定义管理相关按钮 +INSERT INTO sys_menu VALUES ('11644', '流程定义查询', '11620', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:definition:query', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11645', '流程定义新增', '11620', '2', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:definition:add', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11646', '流程定义修改', '11620', '3', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:definition:edit', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11647', '流程定义删除', '11620', '4', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:definition:remove', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11648', '流程定义导出', '11620', '5', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:definition:export', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11649', '流程定义导入', '11620', '6', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:definition:import', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11650', '流程定义发布/取消发布', '11620', '7', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:definition:publish', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11651', '流程定义复制', '11620', '8', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:definition:copy', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11652', '流程定义激活/挂起', '11620', '9', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:definition:active', '#', 103, 1, SYSDATE, NULL, NULL, ''); + INSERT INTO sys_menu VALUES ('11801', '流程表达式', '11616', 2, 'spel', 'workflow/spel/index', '', 1, 0, 'C', '0', '0', 'workflow:spel:list', 'input', 103, 1, SYSDATE, 1, SYSDATE, '流程达式定义菜单'); INSERT INTO sys_menu VALUES ('11802', '流程spel表达式定义查询', '11801', 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:query', '#', 103, 1, SYSDATE, NULL, NULL, ''); INSERT INTO sys_menu VALUES ('11803', '流程spel表达式定义新增', '11801', 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:add', '#', 103, 1, SYSDATE, NULL, NULL, ''); diff --git a/script/sql/postgres/postgres_ry_workflow.sql b/script/sql/postgres/postgres_ry_workflow.sql index d6f30dfd2..380569dd7 100644 --- a/script/sql/postgres/postgres_ry_workflow.sql +++ b/script/sql/postgres/postgres_ry_workflow.sql @@ -451,11 +451,11 @@ INSERT INTO sys_menu VALUES ('11618', '我的任务', '0', '7', 'task', '', '', INSERT INTO sys_menu VALUES ('11619', '我的待办', '11618', '2', 'taskWaiting', 'workflow/task/taskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, now(), NULL, NULL, ''); INSERT INTO sys_menu VALUES ('11632', '我的已办', '11618', '3', 'taskFinish', 'workflow/task/taskFinish', '', '1', '1', 'C', '0', '0', '', 'finish', 103, 1, now(), NULL, NULL, ''); INSERT INTO sys_menu VALUES ('11633', '我的抄送', '11618', '4', 'taskCopyList', 'workflow/task/taskCopyList', '', '1', '1', 'C', '0', '0', '', 'my-copy', 103, 1, now(), NULL, NULL, ''); -INSERT INTO sys_menu VALUES ('11620', '流程定义', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '', 'process-definition', 103, 1, now(), NULL, NULL, ''); -INSERT INTO sys_menu VALUES ('11621', '流程实例', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11620', '流程定义', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', 'workflow:definition:list', 'process-definition', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11621', '流程实例', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', 'workflow:instance:list', 'tree-table', 103, 1, now(), NULL, NULL, ''); INSERT INTO sys_menu VALUES ('11622', '流程分类', '11616', '1', 'category', 'workflow/category/index', '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, now(), NULL, NULL, ''); -INSERT INTO sys_menu VALUES ('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', '', 'guide', 103, 1, now(), NULL, NULL, ''); -INSERT INTO sys_menu VALUES ('11630', '流程监控', '11616', '4', 'monitor', '', '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', 'workflow:instance:currentList', 'guide', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11630', '流程监控', '11616', '4', 'processMonitor', '', '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, now(), NULL, NULL, ''); INSERT INTO sys_menu VALUES ('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, now(), NULL, NULL, ''); INSERT INTO sys_menu VALUES ('11700', '流程设计', '11616', '5', 'design/index', 'workflow/processDefinition/design', '', '1', '1', 'C', '1', '0', 'workflow:leave:edit', '#', 103, 1, now(), NULL, NULL, '/workflow/processDefinition'); INSERT INTO sys_menu VALUES ('11701', '请假申请', '11616', '6', 'leaveEdit/index', 'workflow/leave/leaveEdit', '', '1', '1', 'C', '1', '0', 'workflow:leave:edit', '#', 103, 1, now(), NULL, NULL, ''); @@ -466,6 +466,26 @@ INSERT INTO sys_menu VALUES ('11625', '流程分类修改', '11622', '3', '#', ' INSERT INTO sys_menu VALUES ('11626', '流程分类删除', '11622', '4', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:remove', '#', 103, 1, now(), NULL, NULL, ''); INSERT INTO sys_menu VALUES ('11627', '流程分类导出', '11622', '5', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:export', '#', 103, 1, now(), NULL, NULL, ''); +-- 流程实例管理相关按钮 +INSERT INTO sys_menu VALUES ('11653', '流程实例查询', '11621', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:instance:query', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11654', '流程变量查询', '11621', '2', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:instance:variableQuery', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11655', '流程变量修改', '11621', '3', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:instance:variable', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11656', '流程实例激活/挂起', '11621', '4', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:instance:active', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11657', '流程实例删除', '11621', '5', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:instance:remove', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11658', '流程实例作废', '11621', '6', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:instance:invalid', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11659', '流程实例撤销', '11621', '7', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:instance:cancel', '#', 103, 1, now(), NULL, NULL, ''); + +-- 流程定义管理相关按钮 +INSERT INTO sys_menu VALUES ('11644', '流程定义查询', '11620', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:definition:query', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11645', '流程定义新增', '11620', '2', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:definition:add', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11646', '流程定义修改', '11620', '3', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:definition:edit', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11647', '流程定义删除', '11620', '4', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:definition:remove', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11648', '流程定义导出', '11620', '5', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:definition:export', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11649', '流程定义导入', '11620', '6', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:definition:import', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11650', '流程定义发布/取消发布', '11620', '7', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:definition:publish', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11651', '流程定义复制', '11620', '8', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:definition:copy', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11652', '流程定义激活/挂起', '11620', '9', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:definition:active', '#', 103, 1, now(), NULL, NULL, ''); + INSERT INTO sys_menu VALUES ('11801', '流程表达式', '11616', 2, 'spel', 'workflow/spel/index', '', 1, 0, 'C', '0', '0', 'workflow:spel:list', 'input', 103, 1, now(), 1, now(), '流程达式定义菜单'); INSERT INTO sys_menu VALUES ('11802', '流程spel表达式定义查询', '11801', 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:query', '#', 103, 1, now(), NULL, NULL, ''); INSERT INTO sys_menu VALUES ('11803', '流程spel表达式定义新增', '11801', 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:add', '#', 103, 1, now(), NULL, NULL, ''); diff --git a/script/sql/ry_workflow.sql b/script/sql/ry_workflow.sql index c911a5bd1..f8b37ecc5 100644 --- a/script/sql/ry_workflow.sql +++ b/script/sql/ry_workflow.sql @@ -263,12 +263,12 @@ insert into sys_menu values ('11618', '我的任务', '0', '7', 'task', '', '', insert into sys_menu values ('11619', '我的待办', '11618', '2', 'taskWaiting', 'workflow/task/taskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, sysdate(), NULL, NULL, ''); insert into sys_menu values ('11632', '我的已办', '11618', '3', 'taskFinish', 'workflow/task/taskFinish', '', '1', '1', 'C', '0', '0', '', 'finish', 103, 1, sysdate(), NULL, NULL, ''); insert into sys_menu values ('11633', '我的抄送', '11618', '4', 'taskCopyList', 'workflow/task/taskCopyList', '', '1', '1', 'C', '0', '0', '', 'my-copy', 103, 1, sysdate(), NULL, NULL, ''); -insert into sys_menu values ('11620', '流程定义', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '', 'process-definition', 103, 1, sysdate(), NULL, NULL, ''); -insert into sys_menu values ('11621', '流程实例', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11620', '流程定义', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', 'workflow:definition:list', 'process-definition', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11621', '流程实例', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', 'workflow:instance:list', 'tree-table', 103, 1, sysdate(), NULL, NULL, ''); insert into sys_menu values ('11622', '流程分类', '11616', '1', 'category', 'workflow/category/index', '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, sysdate(), NULL, NULL, ''); INSERT INTO sys_menu VALUES ('11801', '流程表达式', '11616', '2', 'spel', 'workflow/spel/index', '', 1, 0, 'C', '0', '0', 'workflow:spel:list', 'input', 103, 1, sysdate(), 1, sysdate(), '流程达式定义菜单'); -insert into sys_menu values ('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', '', 'guide', 103, 1, sysdate(), NULL, NULL, ''); -insert into sys_menu values ('11630', '流程监控', '11616', '4', 'monitor', '', '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', 'workflow:instance:currentList', 'guide', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11630', '流程监控', '11616', '4', 'processMonitor', '', '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, sysdate(), NULL, NULL, ''); insert into sys_menu values ('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, sysdate(), NULL, NULL, ''); insert into sys_menu values ('11700', '流程设计', '11616', '5', 'design/index', 'workflow/processDefinition/design', '', 1, 1, 'C', '1', '0', 'workflow:leave:edit', '#', 103, 1, sysdate(), null, null, '/workflow/processDefinition'); insert into sys_menu values ('11701', '请假申请', '11616', '6', 'leaveEdit/index', 'workflow/leave/leaveEdit', '', 1, 1, 'C', '1', '0', 'workflow:leave:edit', '#', 103, 1, sysdate(), null, null, ''); @@ -278,6 +278,26 @@ insert into sys_menu values ('11624', '流程分类新增', '11622', '2', '#', ' insert into sys_menu values ('11625', '流程分类修改', '11622', '3', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:edit', '#', 103, 1,sysdate(), null, null, ''); insert into sys_menu values ('11626', '流程分类删除', '11622', '4', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:remove', '#', 103,1, sysdate(), null, null, ''); insert into sys_menu values ('11627', '流程分类导出', '11622', '5', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:export', '#', 103,1, sysdate(), null, null, ''); + +-- 流程实例管理相关按钮 +insert into sys_menu values ('11653', '流程实例查询', '11621', '1', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:instance:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11654', '流程变量查询', '11621', '2', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:instance:variableQuery', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11655', '流程变量修改', '11621', '3', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:instance:variable', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11656', '流程实例激活/挂起', '11621', '4', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:instance:active', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11657', '流程实例删除', '11621', '5', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:instance:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11658', '流程实例作废', '11621', '6', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:instance:invalid', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11659', '流程实例撤销', '11621', '7', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:instance:cancel', '#', 103, 1, sysdate(), null, null, ''); + +-- 流程定义管理相关按钮 +insert into sys_menu values ('11644', '流程定义查询', '11620', '1', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:definition:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11645', '流程定义新增', '11620', '2', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:definition:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11646', '流程定义修改', '11620', '3', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:definition:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11647', '流程定义删除', '11620', '4', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:definition:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11648', '流程定义导出', '11620', '5', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:definition:export', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11649', '流程定义导入', '11620', '6', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:definition:import', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11650', '流程定义发布/取消发布', '11620', '7', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:definition:publish', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11651', '流程定义复制', '11620', '8', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:definition:copy', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('11652', '流程定义激活/挂起', '11620', '9', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:definition:active', '#', 103, 1, sysdate(), null, null, ''); -- 流程表达式管理相关按钮 INSERT INTO sys_menu VALUES ('11802', '流程达式定义查询', '11801', 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:query', '#', 103, 1, sysdate(), NULL, NULL, ''); INSERT INTO sys_menu VALUES ('11803', '流程达式定义新增', '11801', 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:add', '#', 103, 1, sysdate(), NULL, NULL, ''); diff --git a/script/sql/sqlserver/sqlserver_ry_workflow.sql b/script/sql/sqlserver/sqlserver_ry_workflow.sql index 09a661fbd..ddbf32144 100644 --- a/script/sql/sqlserver/sqlserver_ry_workflow.sql +++ b/script/sql/sqlserver/sqlserver_ry_workflow.sql @@ -1573,13 +1573,13 @@ INSERT sys_menu VALUES (11633, N'我的抄送', 11618, 4, N'taskCopyList', N'wor GO INSERT sys_menu VALUES (11620, N'流程定义', 11616, 3, N'processDefinition', N'workflow/processDefinition/index', N'', 1, 1, N'C', N'0', N'0', N'', N'process-definition', 103, 1, GETDATE(), NULL, NULL, N''); GO -INSERT sys_menu VALUES (11621, N'流程实例', 11630, 1, N'processInstance', N'workflow/processInstance/index', N'', 1, 1, N'C', N'0', N'0', N'', N'tree-table', 103, 1, GETDATE(), NULL, NULL, N''); +INSERT sys_menu VALUES (11621, N'流程实例', 11630, 1, N'processInstance', N'workflow/processInstance/index', N'', 1, 1, N'C', N'0', N'0', N'workflow:instance:list', N'tree-table', 103, 1, GETDATE(), NULL, NULL, N''); GO INSERT sys_menu VALUES (11622, N'流程分类', 11616, 1, N'category', N'workflow/category/index', N'', 1, 0, N'C', N'0', N'0', N'workflow:category:list', N'category', 103, 1, GETDATE(), NULL, NULL, N''); GO -INSERT sys_menu VALUES (11629, N'我发起的', 11618, 1, N'myDocument', N'workflow/task/myDocument', N'', 1, 1, N'C', N'0', N'0', N'', N'guide', 103, 1, GETDATE(), NULL, NULL, N''); +INSERT sys_menu VALUES (11629, N'我发起的', 11618, 1, N'myDocument', N'workflow/task/myDocument', N'', 1, 1, N'C', N'0', N'0', N'workflow:instance:currentList', N'guide', 103, 1, GETDATE(), NULL, NULL, N''); GO -INSERT sys_menu VALUES (11630, N'流程监控', 11616, 4, N'monitor', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'monitor', 103, 1, GETDATE(), NULL, NULL, N''); +INSERT sys_menu VALUES (11630, N'流程监控', 11616, 4, N'processMonitor', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'monitor', 103, 1, GETDATE(), NULL, NULL, N''); GO INSERT sys_menu VALUES (11631, N'待办任务', 11630, 2, N'allTaskWaiting', N'workflow/task/allTaskWaiting', N'', 1, 1, N'C', N'0', N'0', N'', N'waiting', 103, 1, GETDATE(), NULL, NULL, N''); GO @@ -1600,6 +1600,22 @@ GO INSERT sys_menu VALUES (11627, N'流程分类导出', 11622, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:category:export', N'#', 103, 1, GETDATE(), NULL, NULL, N''); GO +-- 流程实例管理相关按钮 +INSERT sys_menu VALUES (11653, N'流程实例查询', 11621, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:instance:query', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11654, N'流程变量查询', 11621, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:instance:variableQuery', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11655, N'流程变量修改', 11621, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:instance:variable', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11656, N'流程实例激活/挂起', 11621, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:instance:active', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11657, N'流程实例删除', 11621, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:instance:remove', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11658, N'流程实例作废', 11621, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:instance:invalid', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11659, N'流程实例撤销', 11621, 7, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:instance:cancel', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO + INSERT sys_menu VALUES (11801, N'流程表达式', N'11616', 2, N'spel', N'workflow/spel/index', N'', 1, 0, N'C', N'0', N'0', N'workflow:spel:list', N'input', 103, 1, GETDATE(), 1, GETDATE(), N'流程达式定义菜单'); GO INSERT sys_menu VALUES (11802, N'流程spel表达式定义查询', N'11801', 1, N'#', N'', NULL, 1, 0, N'F', N'0', N'0', N'workflow:spel:query', N'#', 103, 1, GETDATE(), NULL, NULL, N''); diff --git a/script/sql/update/oracle/update_5.5.3_5.6.0.sql b/script/sql/update/oracle/update_5.5.3_5.6.0.sql new file mode 100644 index 000000000..a40c93938 --- /dev/null +++ b/script/sql/update/oracle/update_5.5.3_5.6.0.sql @@ -0,0 +1,24 @@ +-- 修正已有菜单权限标识 +update sys_menu set perms = 'workflow:definition:list' where menu_id = '11620'; +update sys_menu set perms = 'workflow:instance:list' where menu_id = '11621'; +update sys_menu set perms = 'workflow:instance:currentList' where menu_id = '11629'; + +-- 流程定义管理相关按钮 +INSERT INTO sys_menu VALUES ('11644', '流程定义查询', '11620', '1', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:query', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11645', '流程定义新增', '11620', '2', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:add', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11646', '流程定义修改', '11620', '3', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:edit', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11647', '流程定义删除', '11620', '4', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:remove', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11648', '流程定义导出', '11620', '5', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:export', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11649', '流程定义导入', '11620', '6', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:import', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11650', '流程定义发布/取消发布', '11620', '7', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:publish', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11651', '流程定义复制', '11620', '8', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:copy', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11652', '流程定义激活/挂起', '11620', '9', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:active', '#', 103, 1, SYSDATE, NULL, NULL, ''); + +-- 流程实例管理相关按钮 +INSERT INTO sys_menu VALUES ('11653', '流程实例查询', '11621', '1', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:query', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11654', '流程变量查询', '11621', '2', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:variableQuery', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11655', '流程变量修改', '11621', '3', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:variable', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11656', '流程实例激活/挂起', '11621', '4', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:active', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11657', '流程实例删除', '11621', '5', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:remove', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11658', '流程实例作废', '11621', '6', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:invalid', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11659', '流程实例撤销', '11621', '7', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:cancel', '#', 103, 1, SYSDATE, NULL, NULL, ''); diff --git a/script/sql/update/postgres/update_5.5.3_5.6.0.sql b/script/sql/update/postgres/update_5.5.3_5.6.0.sql new file mode 100644 index 000000000..b9c8c7e9a --- /dev/null +++ b/script/sql/update/postgres/update_5.5.3_5.6.0.sql @@ -0,0 +1,24 @@ +-- 修正已有菜单权限标识 +update sys_menu set perms = 'workflow:definition:list' where menu_id = '11620'; +update sys_menu set perms = 'workflow:instance:list' where menu_id = '11621'; +update sys_menu set perms = 'workflow:instance:currentList' where menu_id = '11629'; + +-- 流程定义管理相关按钮 +INSERT INTO sys_menu VALUES ('11644', '流程定义查询', '11620', '1', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:query', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11645', '流程定义新增', '11620', '2', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:add', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11646', '流程定义修改', '11620', '3', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:edit', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11647', '流程定义删除', '11620', '4', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:remove', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11648', '流程定义导出', '11620', '5', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:export', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11649', '流程定义导入', '11620', '6', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:import', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11650', '流程定义发布/取消发布', '11620', '7', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:publish', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11651', '流程定义复制', '11620', '8', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:copy', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11652', '流程定义激活/挂起', '11620', '9', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:active', '#', 103, 1, now(), NULL, NULL, ''); + +-- 流程实例管理相关按钮 +INSERT INTO sys_menu VALUES ('11653', '流程实例查询', '11621', '1', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:query', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11654', '流程变量查询', '11621', '2', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:variableQuery', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11655', '流程变量修改', '11621', '3', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:variable', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11656', '流程实例激活/挂起', '11621', '4', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:active', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11657', '流程实例删除', '11621', '5', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:remove', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11658', '流程实例作废', '11621', '6', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:invalid', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11659', '流程实例撤销', '11621', '7', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:cancel', '#', 103, 1, now(), NULL, NULL, ''); diff --git a/script/sql/update/sqlserver/update_5.5.3_5.6.0.sql b/script/sql/update/sqlserver/update_5.5.3_5.6.0.sql new file mode 100644 index 000000000..5ac98d6f5 --- /dev/null +++ b/script/sql/update/sqlserver/update_5.5.3_5.6.0.sql @@ -0,0 +1,43 @@ +-- 修正已有菜单权限标识 +update sys_menu set perms = N'workflow:definition:list' where menu_id = 11620; +GO +update sys_menu set perms = N'workflow:instance:list' where menu_id = 11621; +GO +update sys_menu set perms = N'workflow:instance:currentList' where menu_id = 11629; +GO + +-- 流程定义管理相关按钮 +INSERT sys_menu VALUES (11644, N'流程定义查询', N'11620', 1, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:definition:query', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11645, N'流程定义新增', N'11620', 2, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:definition:add', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11646, N'流程定义修改', N'11620', 3, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:definition:edit', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11647, N'流程定义删除', N'11620', 4, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:definition:remove', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11648, N'流程定义导出', N'11620', 5, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:definition:export', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11649, N'流程定义导入', N'11620', 6, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:definition:import', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11650, N'流程定义发布/取消发布', N'11620', 7, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:definition:publish', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11651, N'流程定义复制', N'11620', 8, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:definition:copy', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11652, N'流程定义激活/挂起', N'11620', 9, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:definition:active', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO + +-- 流程实例管理相关按钮 +INSERT sys_menu VALUES (11653, N'流程实例查询', N'11621', 1, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:instance:query', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11654, N'流程变量查询', N'11621', 2, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:instance:variableQuery', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11655, N'流程变量修改', N'11621', 3, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:instance:variable', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11656, N'流程实例激活/挂起', N'11621', 4, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:instance:active', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11657, N'流程实例删除', N'11621', 5, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:instance:remove', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11658, N'流程实例作废', N'11621', 6, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:instance:invalid', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11659, N'流程实例撤销', N'11621', 7, N'#', N'', N'', N'N', N'Y', N'F', N'0', N'0', N'workflow:instance:cancel', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO diff --git a/script/sql/update/update_5.5.3_5.6.0.sql b/script/sql/update/update_5.5.3_5.6.0.sql new file mode 100644 index 000000000..cf3f7dada --- /dev/null +++ b/script/sql/update/update_5.5.3_5.6.0.sql @@ -0,0 +1,24 @@ +-- 修正已有菜单权限标识 +update sys_menu set perms = 'workflow:definition:list' where menu_id = '11620'; +update sys_menu set perms = 'workflow:instance:list' where menu_id = '11621'; +update sys_menu set perms = 'workflow:instance:currentList' where menu_id = '11629'; + +-- 流程定义管理相关按钮 +INSERT INTO sys_menu VALUES ('11644', '流程定义查询', '11620', '1', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:query', '#', 103, 1, sysdate(), null, null, ''); +INSERT INTO sys_menu VALUES ('11645', '流程定义新增', '11620', '2', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:add', '#', 103, 1, sysdate(), null, null, ''); +INSERT INTO sys_menu VALUES ('11646', '流程定义修改', '11620', '3', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:edit', '#', 103, 1, sysdate(), null, null, ''); +INSERT INTO sys_menu VALUES ('11647', '流程定义删除', '11620', '4', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:remove', '#', 103, 1, sysdate(), null, null, ''); +INSERT INTO sys_menu VALUES ('11648', '流程定义导出', '11620', '5', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:export', '#', 103, 1, sysdate(), null, null, ''); +INSERT INTO sys_menu VALUES ('11649', '流程定义导入', '11620', '6', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:import', '#', 103, 1, sysdate(), null, null, ''); +INSERT INTO sys_menu VALUES ('11650', '流程定义发布/取消发布', '11620', '7', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:publish', '#', 103, 1, sysdate(), null, null, ''); +INSERT INTO sys_menu VALUES ('11651', '流程定义复制', '11620', '8', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:copy', '#', 103, 1, sysdate(), null, null, ''); +INSERT INTO sys_menu VALUES ('11652', '流程定义激活/挂起', '11620', '9', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:definition:active', '#', 103, 1, sysdate(), null, null, ''); + +-- 流程实例管理相关按钮 +INSERT INTO sys_menu VALUES ('11653', '流程实例查询', '11621', '1', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:query', '#', 103, 1, sysdate(), null, null, ''); +INSERT INTO sys_menu VALUES ('11654', '流程变量查询', '11621', '2', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:variableQuery', '#', 103, 1, sysdate(), null, null, ''); +INSERT INTO sys_menu VALUES ('11655', '流程变量修改', '11621', '3', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:variable', '#', 103, 1, sysdate(), null, null, ''); +INSERT INTO sys_menu VALUES ('11656', '流程实例激活/挂起', '11621', '4', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:active', '#', 103, 1, sysdate(), null, null, ''); +INSERT INTO sys_menu VALUES ('11657', '流程实例删除', '11621', '5', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:remove', '#', 103, 1, sysdate(), null, null, ''); +INSERT INTO sys_menu VALUES ('11658', '流程实例作废', '11621', '6', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:invalid', '#', 103, 1, sysdate(), null, null, ''); +INSERT INTO sys_menu VALUES ('11659', '流程实例撤销', '11621', '7', '#', '', '', 'N', 'Y', 'F', '0', '0', 'workflow:instance:cancel', '#', 103, 1, sysdate(), null, null, '');