diff --git a/.run/ruoyi-monitor-admin.run.xml b/.run/ruoyi-monitor-admin.run.xml index 7257917a3..751f46f7f 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 7528b365d..2adc33a19 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 b3242df48..442c2748b 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 c66f0d14c..457f0a0b5 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/5.X/LICENSE) [![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
-[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.5.1-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus) +[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.5.2-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus) [![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.4-blue.svg)]() [![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]() [![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]() @@ -39,6 +39,7 @@ CCFlow 驰聘低代码-流程-表单 - https://gitee.com/opencc/RuoYi-JFlow
Mall4J 高质量Java商城系统 - https://www.mall4j.com/cn/?statId=11
aizuda flowlong 工作流 - https://gitee.com/aizuda/flowlong
Ruoyi-Plus-Uniapp - https://ruoyi.plus
+Topiam IAM/IDaaS身份管理平台 - https://www.topiam.cn/
[如何成为赞助商 加群联系作者详谈 每日PV2500-3000 IP1700-2500](https://plus-doc.dromara.org/#/common/add_group) diff --git a/pom.xml b/pom.xml index b6baf1b12..0c175fda9 100644 --- a/pom.xml +++ b/pom.xml @@ -13,13 +13,13 @@ Dromara RuoYi-Vue-Plus多租户管理系统 - 5.5.1 - 3.5.7 + 5.5.2 + 3.5.9 UTF-8 UTF-8 17 3.5.16 - 2.8.13 + 2.8.14 0.15.0 1.3.0 2.3 @@ -28,17 +28,17 @@ 3.9.1 5.8.40 3.5.5 - 3.51.0 + 3.52.0 2.2.7 4.3.1 - 1.8.0 + 1.9.0 1.5.0 0.2.0 1.18.40 1.80 1.16.7 - 2.7.0 + 3.3.1 2.28.22 @@ -46,9 +46,9 @@ 1.2.83 - 8.7.2-20250603 + 8.7.3-20251210 - 1.8.2 + 1.8.4 3.4.2 diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java index 89b9ab63c..c448a60d3 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java @@ -48,6 +48,7 @@ import org.springframework.web.bind.annotation.*; import java.net.URL; import java.nio.charset.StandardCharsets; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -106,7 +107,7 @@ public class AuthController { Long userId = LoginHelper.getUserId(); scheduledExecutorService.schedule(() -> { SseMessageDto dto = new SseMessageDto(); - dto.setMessage("欢迎登录RuoYi-Vue-Plus后台管理系统"); + dto.setMessage(DateUtils.getTodayHour(new Date()) + "好,欢迎登录 RuoYi-Vue-Plus 后台管理系统"); dto.setUserIds(List.of(userId)); SseMessageUtils.publishMessage(dto); }, 5, TimeUnit.SECONDS); @@ -147,8 +148,8 @@ public class AuthController { StpUtil.checkLogin(); // 获取第三方登录信息 AuthResponse response = SocialUtils.loginAuth( - loginBody.getSource(), loginBody.getSocialCode(), - loginBody.getSocialState(), socialProperties); + loginBody.getSource(), loginBody.getSocialCode(), + loginBody.getSocialState(), socialProperties); AuthUser authUserData = response.getData(); // 判断授权响应是否成功 if (!response.ok()) { diff --git a/ruoyi-admin/src/main/resources/ip2region.xdb b/ruoyi-admin/src/main/resources/ip2region_v4.xdb similarity index 100% rename from ruoyi-admin/src/main/resources/ip2region.xdb rename to ruoyi-admin/src/main/resources/ip2region_v4.xdb diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml index f1407814b..3324cbe5f 100644 --- a/ruoyi-common/ruoyi-common-bom/pom.xml +++ b/ruoyi-common/ruoyi-common-bom/pom.xml @@ -14,7 +14,7 @@ - 5.5.1 + 5.5.2 diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java index 18d3614ae..1cc3bd683 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java @@ -3,10 +3,8 @@ package org.dromara.common.core.config; import jakarta.annotation.PreDestroy; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.concurrent.BasicThreadFactory; -import org.dromara.common.core.config.properties.ThreadPoolProperties; import org.dromara.common.core.utils.SpringUtils; import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.core.task.VirtualThreadTaskExecutor; @@ -19,7 +17,6 @@ import java.util.concurrent.*; **/ @Slf4j @AutoConfiguration -@EnableConfigurationProperties(ThreadPoolProperties.class) public class ThreadPoolConfig { /** diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/properties/ThreadPoolProperties.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/properties/ThreadPoolProperties.java deleted file mode 100644 index 820564f50..000000000 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/properties/ThreadPoolProperties.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.dromara.common.core.config.properties; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; - -/** - * 线程池 配置属性 - * - * @author Lion Li - */ -@Data -@ConfigurationProperties(prefix = "thread-pool") -public class ThreadPoolProperties { - - /** - * 是否开启线程池 - */ - private boolean enabled; - - /** - * 队列最大长度 - */ - private int queueCapacity; - - /** - * 线程池维护线程所允许的空闲时间 - */ - private int keepAliveSeconds; - -} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/SystemConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/SystemConstants.java index 4bd858f4c..e38d9fd2d 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/SystemConstants.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/SystemConstants.java @@ -82,4 +82,10 @@ public interface SystemConstants { */ Long DEFAULT_DEPT_ID = 100L; + /** + * 排除敏感属性字段 + */ + String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" }; + + } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java index e011874a2..21a561e61 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java @@ -67,7 +67,8 @@ public class CompleteTaskDTO 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/service/ConfigService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/ConfigService.java index 7328c690d..9ae52c789 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/ConfigService.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/ConfigService.java @@ -1,5 +1,11 @@ package org.dromara.common.core.service; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Dict; + +import java.math.BigDecimal; +import java.util.List; + /** * 通用 参数配置服务 * @@ -15,4 +21,80 @@ public interface ConfigService { */ String getConfigValue(String configKey); + /** + * 根据参数 key 获取布尔值 + * + * @param configKey 参数 key + * @return Boolean 值 + */ + default Boolean getConfigBool(String configKey) { + return Convert.toBool(getConfigValue(configKey)); + } + + /** + * 根据参数 key 获取整数值 + * + * @param configKey 参数 key + * @return Integer 值 + */ + default Integer getConfigInt(String configKey) { + return Convert.toInt(getConfigValue(configKey)); + } + + /** + * 根据参数 key 获取长整型值 + * + * @param configKey 参数 key + * @return Long 值 + */ + default Long getConfigLong(String configKey) { + return Convert.toLong(getConfigValue(configKey)); + } + + /** + * 根据参数 key 获取 BigDecimal 值 + * + * @param configKey 参数 key + * @return BigDecimal 值 + */ + default BigDecimal getConfigDecimal(String configKey) { + return Convert.toBigDecimal(getConfigValue(configKey)); + } + + /** + * 根据参数 key 获取 Map 类型的配置 + * + * @param configKey 参数 key + * @return Dict 对象,如果配置为空或无法解析,返回空 Dict + */ + Dict getConfigMap(String configKey); + + /** + * 根据参数 key 获取 Map 类型的配置列表 + * + * @param configKey 参数 key + * @return Dict 列表,如果配置为空或无法解析,返回空列表 + */ + List getConfigArrayMap(String configKey); + + /** + * 根据参数 key 获取指定类型的配置对象 + * + * @param configKey 参数 key + * @param clazz 目标对象类型 + * @param 目标对象泛型 + * @return 对象实例,如果配置为空或无法解析,返回 null + */ + T getConfigObject(String configKey, Class clazz); + + /** + * 根据参数 key 获取指定类型的配置列表 + * + * @param configKey 参数 key + * @param clazz 目标元素类型 + * @param 元素类型泛型 + * @return 指定类型列表,如果配置为空或无法解析,返回空列表 + */ + List getConfigArray(String configKey, Class clazz); + } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java index 706d357e7..8efeb76ef 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java @@ -20,7 +20,7 @@ public interface WorkflowService { * @param businessIds 业务id * @return 结果 */ - boolean deleteInstance(List businessIds); + boolean deleteInstance(List businessIds); /** * 获取当前流程状态 diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java index b4d146242..6c450853c 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java @@ -1,5 +1,7 @@ package org.dromara.common.core.utils; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; import org.apache.commons.lang3.time.DateFormatUtils; import org.dromara.common.core.enums.FormatsType; import org.dromara.common.core.exception.ServiceException; @@ -297,4 +299,80 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils { } } + /** + * 根据指定日期时间获取时间段(凌晨 / 上午 / 中午 / 下午 / 晚上) + * + * @param date 日期时间 + * @return 时间段描述 + */ + public static String getTodayHour(Date date) { + int hour = DateUtil.hour(date, true); + if (hour <= 6) { + return "凌晨"; + } else if (hour < 12) { + return "上午"; + } else if (hour == 12) { + return "中午"; + } else if (hour <= 18) { + return "下午"; + } else { + return "晚上"; + } + } + + /** + * 将日期格式化为仿微信的友好时间 + *

+ * 规则说明: + * 1. 未来时间:yyyy-MM-dd HH:mm + * 2. 今天: + * - 1 分钟内:刚刚 + * - 1 小时内:X 分钟前 + * - 超过 1 小时:凌晨/上午/中午/下午/晚上 HH:mm + * 3. 昨天:昨天 HH:mm + * 4. 本周:周X HH:mm + * 5. 今年内:MM-dd HH:mm + * 6. 非今年:yyyy-MM-dd HH:mm + * + * @param date 日期时间 + * @return 格式化后的时间描述 + */ + public static String formatFriendlyTime(Date date) { + if (date == null) { + return ""; + } + Date now = DateUtil.date(); + + // 未来时间或非今年 + if (date.after(now) || DateUtil.year(date) != DateUtil.year(now)) { + return parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM, date); + } + + // 今天 + if (DateUtil.isSameDay(date, now)) { + long minutes = DateUtil.between(date, now, DateUnit.MINUTE); + if (minutes < 1) { + return "刚刚"; + } + if (minutes < 60) { + return minutes + "分钟前"; + } + return getTodayHour(date) + " " + DateUtil.format(date, "HH:mm"); + } + + // 昨天 + if (DateUtil.isSameDay(date, DateUtil.yesterday())) { + return "昨天 " + DateUtil.format(date, "HH:mm"); + } + + // 本周 + if (DateUtil.isSameWeek(date, now, true)) { + return DateUtil.dayOfWeekEnum(date).toChinese("周") + + " " + DateUtil.format(date, "HH:mm"); + } + + // 今年内其它时间 + return DateUtil.format(date, "MM-dd HH:mm"); + } + } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DesensitizedUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DesensitizedUtils.java new file mode 100644 index 000000000..8a2ffcf97 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DesensitizedUtils.java @@ -0,0 +1,87 @@ +package org.dromara.common.core.utils; + +import cn.hutool.core.util.DesensitizedUtil; +import cn.hutool.core.util.StrUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +/** + * 脱敏工具类 + * + * @author AprilWind + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class DesensitizedUtils extends DesensitizedUtil { + + /** + * 灵活脱敏方法 + * + * @param value 原始字符串 + * @param prefixVisible 前面可见长度 + * @param suffixVisible 后面可见长度 + * @param maskLength 中间掩码长度(固定显示多少 *,如果总长度不足则自动缩减) + * @return 脱敏后字符串 + */ + public static String mask(String value, int prefixVisible, int suffixVisible, int maskLength) { + if (StrUtil.isBlank(value)) { + return value; + } + + int len = value.length(); + int prefixMaskLimit = prefixVisible + maskLength; + int fullLimit = prefixMaskLimit + suffixVisible; + + // 规则 1:长度 <= 中间掩码长度 → 全掩码 + if (len <= maskLength) { + return StrUtil.repeat('*', len); + } + String mask = StrUtil.repeat('*', maskLength); + + // 规则 2:长度 <= 前缀 + 中间掩码 + if (len <= prefixMaskLimit) { + return value.substring(0, len - maskLength) + mask; + } + + String prefix = value.substring(0, prefixVisible); + + // 规则 3:长度 <= 前缀 + 中间掩码 + 后缀 + if (len <= fullLimit) { + int suffixLen = len - prefixMaskLimit; + return prefix + mask + value.substring(len - suffixLen); + } + + // 规则 4:标准形态 + return prefix + mask + value.substring(len - suffixVisible); + } + + /** + * 高安全级别脱敏方法(Token / 私钥) + * + * @param value 原始字符串 + * @param prefixVisible 前面可见长度(推荐0~4) + * @param suffixVisible 后面可见长度(推荐0~4) + * @return 脱敏后字符串 + */ + public static String maskHighSecurity(String value, int prefixVisible, int suffixVisible) { + if (StrUtil.isBlank(value)) { + return value; + } + int len = value.length(); + + // 规则1:长度 <= 前缀可见长度 → 全部掩码 + if (len <= prefixVisible) { + return StrUtil.repeat('*', len); + } + + // 规则2:长度 <= 前缀 + 后缀可见长度 → 优先掩码后面 + if (len <= prefixVisible + suffixVisible) { + return value.substring(0, len - prefixVisible) + StrUtil.repeat('*', prefixVisible); + } + + // 规则3:标准形态 → 前后可见,中间全部掩码 + return value.substring(0, prefixVisible) + + StrUtil.repeat('*', len - prefixVisible - suffixVisible) + + value.substring(len - suffixVisible); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java index 2fe3bd7b6..fe36d9cc0 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java @@ -20,51 +20,24 @@ public class AddressUtils { public static final String UNKNOWN_IP = "XX XX"; // 内网地址 public static final String LOCAL_ADDRESS = "内网IP"; - // 未知地址 - public static final String UNKNOWN_ADDRESS = "未知"; public static String getRealAddressByIP(String ip) { // 处理空串并过滤HTML标签 ip = HtmlUtil.cleanHtmlTag(StringUtils.blankToDefault(ip,"")); // 判断是否为IPv4 - if (NetUtils.isIPv4(ip)) { - return resolverIPv4Region(ip); - } + boolean isIPv4 = NetUtils.isIPv4(ip); // 判断是否为IPv6 - if (NetUtils.isIPv6(ip)) { - return resolverIPv6Region(ip); - } + boolean isIPv6 = NetUtils.isIPv6(ip); // 如果不是IPv4或IPv6,则返回未知IP - return UNKNOWN_IP; - } - - /** - * 根据IPv4地址查询IP归属行政区域 - * @param ip ipv4地址 - * @return 归属行政区域 - */ - private static String resolverIPv4Region(String ip){ + if (!isIPv4 && !isIPv6) { + return UNKNOWN_IP; + } // 内网不查询 - if (NetUtils.isInnerIP(ip)) { + if ((isIPv4 && NetUtils.isInnerIP(ip)) || (isIPv6 && NetUtils.isInnerIPv6(ip))) { return LOCAL_ADDRESS; } - return RegionUtils.getCityInfo(ip); - } - - /** - * 根据IPv6地址查询IP归属行政区域 - * @param ip ipv6地址 - * @return 归属行政区域 - */ - private static String resolverIPv6Region(String ip){ - // 内网不查询 - if (NetUtils.isInnerIPv6(ip)) { - return LOCAL_ADDRESS; - } - log.warn("ip2region不支持IPV6地址解析:{}", ip); - // 不支持IPv6,不再进行没有必要的IP地址信息的解析,直接返回 - // 如有需要,可自行实现IPv6地址信息解析逻辑,并在这里返回 - return UNKNOWN_ADDRESS; + // Tips:Ip2Region 提供了精简的IPv6地址库,精简的IPv6地址库并不能完全支持IPv6地址的查询,且准确度上可能会存在问题,如需要准确的IPv6地址查询,建议自行实现 + return RegionUtils.getRegion(ip); } } 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 c9e867899..bab520838 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 @@ -1,50 +1,142 @@ package org.dromara.common.core.utils.ip; -import cn.hutool.core.io.resource.NoResourceException; import cn.hutool.core.io.resource.ResourceUtil; import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.utils.StringUtils; -import org.lionsoul.ip2region.xdb.Searcher; +import org.lionsoul.ip2region.service.Config; +import org.lionsoul.ip2region.service.Ip2Region; +import org.lionsoul.ip2region.xdb.Util; + +import java.io.InputStream; +import java.time.Duration; /** - * 根据ip地址定位工具类,离线方式 - * 参考地址:集成 ip2region 实现离线IP地址定位库 + * IP地址行政区域工具类 + * 参考地址:ip2region xdb java 查询客户端实现 + * xdb数据库文件下载:ip2region data * - * @author lishuyan + * @author 秋辞未寒 */ @Slf4j public class RegionUtils { - // IP地址库文件名称 - public static final String IP_XDB_FILENAME = "ip2region.xdb"; + // 默认IPv4地址库文件路径 + // 下载地址:https://gitee.com/lionsoul/ip2region/blob/master/data/ip2region_v4.xdb + public static final String DEFAULT_IPV4_XDB_PATH = "ip2region_v4.xdb"; - private static final Searcher SEARCHER; + // 默认IPv6地址库文件路径 + // 下载地址:https://gitee.com/lionsoul/ip2region/blob/master/data/ip2region_v6.xdb + public static final String DEFAULT_IPV6_XDB_PATH = "ip2region_v6.xdb"; + // 未知地址 + public static final String UNKNOWN_ADDRESS = "未知"; + + // Ip2Region服务实例 + private static Ip2Region ip2Region; + + // 初始化Ip2Region服务实例 static { try { - // 1、将 ip2region 数据库文件 xdb 从 ClassPath 加载到内存。 - // 2、基于加载到内存的 xdb 数据创建一个 Searcher 查询对象。 - SEARCHER = Searcher.newWithBuffer(ResourceUtil.readBytes(IP_XDB_FILENAME)); - log.info("RegionUtils初始化成功,加载IP地址库数据成功!"); - } catch (NoResourceException e) { - throw new ServiceException("RegionUtils初始化失败,原因:IP地址库数据不存在!"); + // 注意:Ip2Region 的xdb文件加载策略 CachePolicy 有三种,分别是:BufferCache(全量读取xdb到内存中)、VIndexCache(默认策略,按需读取并缓存)、NoCache(实时读取) + // 本项目工具使用的 CachePolicy 为 BufferCache,BufferCache会加载整个xdb文件到内存中,setXdbInputStream 仅支持 BufferCache 策略。 + // 因为加载整个xdb文件会耗费非常大的内存,如果你不希望加载整个xdb到内存中,更推荐使用 VIndexCache 或 NoCache(即实时读取文件)策略和 setXdbPath/setXdbFile 加载方法(需要注意的一点,setXdbPath 和 setXdbFile 不支持读取ClassPath(即源码和resource目录)中的文件)。 + // 一般而言,更建议把xdb数据库放到一个指定的文件目录中(即不打包进jar包中),然后使用 NoCache + 配合SearcherPool的并发池读取数据,更方便随时更新xdb数据库 + + // IPv4配置 + Config v4Config = Config.custom() + .setCachePolicy(Config.BufferCache) + .setXdbInputStream(ResourceUtil.getStream(DEFAULT_IPV4_XDB_PATH)) + .asV4(); + + // IPv6配置 + Config v6Config = null; + InputStream v6XdbInputStream = ResourceUtil.getStreamSafe(DEFAULT_IPV6_XDB_PATH); + if (v6XdbInputStream == null) { + log.warn("未加载 IPv6 地址库:未在类路径下找到文件 {}。当前仅启用 IPv4 查询。如需启用 IPv6,请将 ip2region_v6.xdb 放置到 resources 目录", DEFAULT_IPV6_XDB_PATH); + } else { + v6Config = Config.custom() + .setCachePolicy(Config.BufferCache) + .setXdbInputStream(v6XdbInputStream) + .asV6(); + } + + // 初始化Ip2Region实例 + RegionUtils.ip2Region = Ip2Region.create(v4Config, v6Config); + log.debug("IP工具初始化成功,加载IP地址库数据成功!"); } catch (Exception e) { - throw new ServiceException("RegionUtils初始化失败,原因:" + e.getMessage()); + throw new ServiceException("RegionUtils初始化失败,原因:{}", e.getMessage()); } } /** * 根据IP地址离线获取城市 + * + * @param ipString ip地址字符串 */ - public static String getCityInfo(String ip) { + public static String getRegion(String ipString) { try { - // 3、执行查询 - String region = SEARCHER.search(StringUtils.trim(ip)); - return region.replace("0|", "").replace("|0", ""); + String region = ip2Region.search(ipString); + if (StringUtils.isBlank(region)) { + region = UNKNOWN_ADDRESS; + } + return region; } catch (Exception e) { - log.error("IP地址离线获取城市异常 {}", ip); - return "未知"; + log.error("IP地址离线获取城市异常 {}", ipString); + return UNKNOWN_ADDRESS; + } + + } + + /** + * 根据IP地址离线获取城市 + * + * @param ipBytes ip地址字节数组 + */ + public static String getRegion(byte[] ipBytes) { + try { + String region = ip2Region.search(ipBytes); + if (StringUtils.isBlank(region)) { + region = UNKNOWN_ADDRESS; + } + return region; + } catch (Exception e) { + log.error("IP地址离线获取城市异常 {}", Util.ipToString(ipBytes)); + return UNKNOWN_ADDRESS; + } + } + + /** + * 关闭Ip2Region服务 + */ + public static void close() { + if (ip2Region == null) { + return; + } + try { + ip2Region.close(10000); + } catch (Exception e) { + log.error("Ip2Region服务关闭异常", e); + } + } + + /** + * 关闭Ip2Region服务 + * + * @param timeout 关闭超时时间 + */ + public static void close(final Duration timeout) { + if (ip2Region == null) { + return; + } + if (timeout == null) { + close(); + return; + } + try { + ip2Region.close(timeout.toMillis()); + } catch (Exception e) { + log.error("Ip2Region服务关闭异常", e); } } diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelDynamicOptions.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelDynamicOptions.java new file mode 100644 index 000000000..c26bd68ff --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelDynamicOptions.java @@ -0,0 +1,23 @@ +package org.dromara.common.excel.annotation; + +import org.dromara.common.excel.core.ExcelOptionsProvider; + +import java.lang.annotation.*; + +/** + * Excel动态下拉选项注解 + * + * @author Angus + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ExcelDynamicOptions { + + /** + * 提供者类全限定名 + *

+ * {@link org.dromara.common.excel.core.ExcelOptionsProvider} 接口实现类 class + */ + Class providerClass(); +} 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 204a88e25..6a1a3a72d 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 @@ -29,7 +29,10 @@ public class CellMergeHandler { // 行合并开始下标 this.rowIndex = hasTitle ? 1 : 0; } - + private CellMergeHandler(final boolean hasTitle, final int rowIndex) { + this.hasTitle = hasTitle; + this.rowIndex = hasTitle ? rowIndex : 0; + } @SneakyThrows public List handle(List rows) { // 如果入参为空集合则返回空集 @@ -103,6 +106,10 @@ public class CellMergeHandler { } if (isAddResult && i > current) { + //如果是同一行,则跳过合并 + if (current + rowIndex == lastRow) { + continue; + } result.add(new CellRangeAddress(current + rowIndex, lastRow, colNum, colNum)); } } @@ -147,12 +154,12 @@ public class CellMergeHandler { private boolean isMerge(Object currentRow, Object preRow, CellMerge cellMerge) { final String[] mergeBy = cellMerge.mergeBy(); if (StrUtil.isAllNotBlank(mergeBy)) { - //比对当前行和上一行的各个属性值一一比对 如果全为真 则为真 + // 比对当前行和上一行的各个属性值一一比对 如果全为真 则为真 for (String fieldName : mergeBy) { final Object valCurrent = ReflectUtil.getFieldValue(currentRow, fieldName); final Object valPre = ReflectUtil.getFieldValue(preRow, fieldName); if (!Objects.equals(valPre, valCurrent)) { - //依赖字段如有任一不等值,则标记为不可合并 + // 依赖字段如有任一不等值,则标记为不可合并 return false; } } @@ -177,6 +184,16 @@ public class CellMergeHandler { return new FieldColumnIndex(colIndex, cellMerge); } } + /** + * 创建一个单元格合并处理器实例 + * + * @param hasTitle 是否合并标题 + * @param rowIndex 行索引 + * @return 单元格合并处理器 + */ + public static CellMergeHandler of(final boolean hasTitle, final int rowIndex) { + return new CellMergeHandler(hasTitle, rowIndex); + } /** * 创建一个单元格合并处理器实例 diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java index 34bf4a42f..64d8c7779 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java @@ -2,15 +2,16 @@ package org.dromara.common.excel.core; import cn.hutool.core.collection.CollUtil; import cn.idev.excel.metadata.Head; -import cn.idev.excel.write.handler.WorkbookWriteHandler; -import cn.idev.excel.write.handler.context.WorkbookWriteHandlerContext; +import cn.idev.excel.write.handler.SheetWriteHandler; import cn.idev.excel.write.merge.AbstractMergeStrategy; +import cn.idev.excel.write.metadata.holder.WriteSheetHolder; +import cn.idev.excel.write.metadata.holder.WriteWorkbookHolder; import lombok.extern.slf4j.Slf4j; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.util.CellRangeAddress; -import java.util.*; +import java.util.List; /** * 列值重复合并策略 @@ -18,7 +19,7 @@ import java.util.*; * @author Lion Li */ @Slf4j -public class CellMergeStrategy extends AbstractMergeStrategy implements WorkbookWriteHandler { +public class CellMergeStrategy extends AbstractMergeStrategy implements SheetWriteHandler { private final List cellList; @@ -30,29 +31,34 @@ public class CellMergeStrategy extends AbstractMergeStrategy implements Workbook this.cellList = CellMergeHandler.of(hasTitle).handle(list); } + public CellMergeStrategy(List list, boolean hasTitle, int rowIndex) { + this.cellList = CellMergeHandler.of(hasTitle, rowIndex).handle(list); + } + @Override protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { - if (CollUtil.isEmpty(cellList)){ + if (CollUtil.isEmpty(cellList)) { return; } - //单元格写入了,遍历合并区域,如果该Cell在区域内,但非首行,则清空 + // 单元格写入了,遍历合并区域,如果该Cell在区域内,但非首行,则清空 final int rowIndex = cell.getRowIndex(); for (CellRangeAddress cellAddresses : cellList) { final int firstRow = cellAddresses.getFirstRow(); - if (cellAddresses.isInRange(cell) && rowIndex != firstRow){ + if (cellAddresses.isInRange(cell) && rowIndex != firstRow) { cell.setBlank(); } } } @Override - public void afterWorkbookDispose(final WorkbookWriteHandlerContext context) { - if (CollUtil.isEmpty(cellList)){ + public void afterSheetCreate(final WriteWorkbookHolder writeWorkbookHolder, final WriteSheetHolder writeSheetHolder) { + if (CollUtil.isEmpty(cellList)) { return; } - //当前表格写完后,统一写入 + // 在 Sheet 创建时提前写入合并区域;后续写入只会影响首格,不会移除合并 + final Sheet sheet = writeSheetHolder.getSheet(); for (CellRangeAddress item : cellList) { - context.getWriteContext().writeSheetHolder().getSheet().addMergedRegion(item); + sheet.addMergedRegion(item); } } diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java index 139728390..05c79c410 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java @@ -23,6 +23,7 @@ import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.StreamUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.annotation.ExcelDynamicOptions; import org.dromara.common.excel.annotation.ExcelEnumFormat; import java.lang.reflect.Field; @@ -117,6 +118,15 @@ public class ExcelDownHandler implements SheetWriteHandler { ExcelEnumFormat format = field.getDeclaredAnnotation(ExcelEnumFormat.class); List values = EnumUtil.getFieldValues(format.enumClass(), format.textField()); options = StreamUtils.toList(values, Convert::toStr); + } else if (field.isAnnotationPresent(ExcelDynamicOptions.class)) { + // 处理动态下拉选项 + ExcelDynamicOptions dynamicOptions = field.getDeclaredAnnotation(ExcelDynamicOptions.class); + // 获取提供者实例 + ExcelOptionsProvider provider = SpringUtils.getBean(dynamicOptions.providerClass()); + Set providerOptions = provider.getOptions(); + if (CollUtil.isNotEmpty(providerOptions)) { + options = new ArrayList<>(providerOptions); + } } if (ObjectUtil.isNotEmpty(options)) { // 仅当下拉可选项不为空时执行 diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelOptionsProvider.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelOptionsProvider.java new file mode 100644 index 000000000..85f939ae7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelOptionsProvider.java @@ -0,0 +1,19 @@ +package org.dromara.common.excel.core; + +import java.util.Set; + +/** + * Excel下拉选项数据提供接口 + * + * @author Angus + */ +public interface ExcelOptionsProvider { + + /** + * 获取下拉选项数据 + * + * @return 下拉选项列表 + */ + Set getOptions(); + +} diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java index d68be2251..2c22811ae 100644 --- a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java +++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java @@ -13,6 +13,7 @@ import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; +import org.dromara.common.core.constant.SystemConstants; import org.dromara.common.core.domain.model.LoginUser; import org.dromara.common.core.utils.ServletUtils; import org.dromara.common.core.utils.SpringUtils; @@ -39,12 +40,6 @@ import java.util.*; @AutoConfiguration public class LogAspect { - /** - * 排除敏感属性字段 - */ - public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" }; - - /** * 计时 key */ @@ -160,7 +155,7 @@ public class LogAspect { String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames); operLog.setOperParam(StringUtils.substring(params, 0, 3800)); } else { - MapUtil.removeAny(paramsMap, EXCLUDE_PROPERTIES); + MapUtil.removeAny(paramsMap, SystemConstants.EXCLUDE_PROPERTIES); MapUtil.removeAny(paramsMap, excludeParamNames); operLog.setOperParam(StringUtils.substring(JsonUtils.toJsonString(paramsMap), 0, 3800)); } @@ -174,7 +169,7 @@ public class LogAspect { if (ArrayUtil.isEmpty(paramsArray)) { return params.toString(); } - String[] exclude = ArrayUtil.addAll(excludeParamNames, EXCLUDE_PROPERTIES); + String[] exclude = ArrayUtil.addAll(excludeParamNames, SystemConstants.EXCLUDE_PROPERTIES); for (Object o : paramsArray) { if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) { String str = ""; diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java index 487ffd375..84a8a5c2a 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java @@ -42,7 +42,7 @@ public class DataBaseHelper { String databaseProductName = metaData.getDatabaseProductName(); return DataBaseType.find(databaseProductName); } catch (SQLException e) { - throw new ServiceException(e.getMessage()); + throw new RuntimeException("获取数据库类型失败", e); } } 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 f03d74e83..8963648c0 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 @@ -112,7 +112,7 @@ public class DataPermissionHelper { /** * 开启忽略数据权限(开启后需手动调用 {@link #disableIgnore()} 关闭) */ - public static void enableIgnore() { + private static void enableIgnore() { IgnoreStrategy ignoreStrategy = getIgnoreStrategy(); if (ObjectUtil.isNull(ignoreStrategy)) { InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().dataPermission(true).build()); @@ -126,7 +126,7 @@ public class DataPermissionHelper { /** * 关闭忽略数据权限 */ - public static void disableIgnore() { + private static void disableIgnore() { IgnoreStrategy ignoreStrategy = getIgnoreStrategy(); if (ObjectUtil.isNotNull(ignoreStrategy)) { boolean noOtherIgnoreStrategy = !Boolean.TRUE.equals(ignoreStrategy.getDynamicTableName()) diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/utils/IdGeneratorUtil.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/utils/IdGeneratorUtil.java new file mode 100644 index 000000000..33b3f1c56 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/utils/IdGeneratorUtil.java @@ -0,0 +1,129 @@ +package org.dromara.common.mybatis.utils; + +import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.utils.SpringUtils; + +/** + * ID 生成工具类 + * + * @author AprilWind + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class IdGeneratorUtil { + + private static final IdentifierGenerator GENERATOR = SpringUtils.getBean(IdentifierGenerator.class); + + /** + * 生成字符串类型主键 ID + *

+ * 调用 {@link IdentifierGenerator#nextId(Object)},返回 String 格式 ID。 + *

+ * + * @return 字符串格式主键 ID + */ + public static String nextId() { + return GENERATOR.nextId(null).toString(); + } + + /** + * 生成 Long 类型主键 ID + *

+ * 自动将生成的数字型主键转换为 Long 类型 + *

+ * + * @return Long 类型主键 ID + */ + public static Long nextLongId() { + return GENERATOR.nextId(null).longValue(); + } + + /** + * 生成 Number 类型主键 ID + *

+ * 推荐在需要保留原始 Number 类型时使用 + *

+ * + * @return Number 类型主键 ID + */ + public static Number nextNumberId() { + return GENERATOR.nextId(null); + } + + /** + * 根据实体生成数字型主键 ID + *

+ * 若自定义的 {@link IdentifierGenerator} 根据实体内容生成 ID,则可以使用本方法 + *

+ * + * @param entity 实体对象 + * @return Number 类型主键 ID + */ + public static Number nextId(Object entity) { + return GENERATOR.nextId(entity); + } + + /** + * 根据实体生成字符串主键 ID + *

+ * 与 {@link #nextId(Object)} 类似,但返回 String 类型 + *

+ * + * @param entity 实体对象 + * @return 字符串格式主键 ID + */ + public static String nextStringId(Object entity) { + return GENERATOR.nextId(entity).toString(); + } + + /** + * 生成 32 位 UUID + *

+ * 底层使用 {@link IdWorker#get32UUID()} + *

+ * + * @return 32 位 UUID 字符串 + */ + public static String nextUUID() { + return IdWorker.get32UUID(); + } + + /** + * 根据实体生成 32 位 UUID + *

+ * 默认 {@link IdentifierGenerator#nextUUID(Object)} 实现忽略实体,但保留该方法便于扩展。 + *

+ * + * @param entity 实体对象 + * @return 32 位 UUID 字符串 + */ + public static String nextUUID(Object entity) { + return GENERATOR.nextUUID(entity); + } + + /** + * 生成带指定前缀的字符串主键 ID + *

+ * 示例:prefix = "ORD",生成结果形如:{@code ORD20251211000123} + *

+ * + * @param prefix 自定义前缀 + * @return 带前缀的字符串主键 ID + */ + public static String nextIdWithPrefix(String prefix) { + return prefix + nextId(); + } + + /** + * 生成带前缀的 UUID + * + * @param prefix 前缀 + * @return prefix + UUID + */ + public static String nextUUIDWithPrefix(String prefix) { + return prefix + nextUUID(); + } + +} diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java index b9a90dc75..089d1926b 100644 --- a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java @@ -14,7 +14,9 @@ import org.dromara.common.oss.exception.OssException; import org.dromara.common.oss.properties.OssProperties; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; -import software.amazon.awssdk.core.async.*; +import software.amazon.awssdk.core.async.AsyncResponseTransformer; +import software.amazon.awssdk.core.async.BlockingInputStreamAsyncRequestBody; +import software.amazon.awssdk.core.async.ResponsePublisher; import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3AsyncClient; @@ -33,6 +35,7 @@ import java.nio.channels.WritableByteChannel; import java.nio.file.Files; import java.nio.file.Path; import java.time.Duration; +import java.util.Map; import java.util.Optional; import java.util.function.Consumer; @@ -94,7 +97,11 @@ public class OssClient { .region(of()) .forcePathStyle(isStyle) .httpClient(NettyNioAsyncHttpClient.builder() - .connectionTimeout(Duration.ofSeconds(60)).build()) + .connectionTimeout(Duration.ofSeconds(60)) + .connectionAcquisitionTimeout(Duration.ofSeconds(30)) + .maxConcurrency(100) + .maxPendingConnectionAcquires(1000) + .build()) .build(); //AWS基于 CRT 的 S3 AsyncClient 实例用作 S3 传输管理器的底层客户端 @@ -317,13 +324,13 @@ public class OssClient { } /** - * 获取私有URL链接 + * 创建下载请求的预签名URL * * @param objectKey 对象KEY * @param expiredTime 链接授权到期时间 */ - public String getPrivateUrl(String objectKey, Duration expiredTime) { - // 使用 AWS S3 预签名 URL 的生成器 获取对象的预签名 URL + public String createPresignedGetUrl(String objectKey, Duration expiredTime) { + // 使用 AWS S3 预签名 URL 的生成器 获取下载对象的预签名 URL URL url = presigner.presignGetObject( x -> x.signatureDuration(expiredTime) .getObjectRequest( @@ -332,7 +339,28 @@ public class OssClient { .build()) .build()) .url(); - return url.toString(); + return url.toExternalForm(); + } + + /** + * 创建上传请求的预签名URL + * + * @param objectKey 对象KEY + * @param expiredTime 链接授权到期时间 + * @param metadata 元数据 + */ + public String createPresignedPutUrl(String objectKey, Duration expiredTime, Map metadata) { + // 使用 AWS S3 预签名 URL 的生成器 获取上传文件对象的预签名 URL + URL url = presigner.presignPutObject( + x -> x.signatureDuration(expiredTime) + .putObjectRequest( + y -> y.bucket(properties.getBucketName()) + .key(objectKey) + .metadata(metadata) + .build()) + .build()) + .url(); + return url.toExternalForm(); } /** diff --git a/ruoyi-common/ruoyi-common-redis/pom.xml b/ruoyi-common/ruoyi-common-redis/pom.xml index d7d99cacc..576be5e14 100644 --- a/ruoyi-common/ruoyi-common-redis/pom.xml +++ b/ruoyi-common/ruoyi-common-redis/pom.xml @@ -43,16 +43,12 @@ jackson-datatype-jsr310 - - - - - - - - - - + + + org.apache.fory + fory-core + 0.13.1 + diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java index 7ba94751a..4c39196e8 100644 --- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java @@ -53,9 +53,10 @@ public class RedisConfig { om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // 指定序列化输入的类型,类必须是非final修饰的。序列化时将对象全类名一起保存下来 om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); -// LoggerFactory.useSlf4jLogging(true); -// FuryCodec furyCodec = new FuryCodec(); -// CompositeCodec codec = new CompositeCodec(StringCodec.INSTANCE, furyCodec, furyCodec); + // org.apache.fory.logging.LoggerFactory 包别引入错了 + // LoggerFactory.useSlf4jLogging(true); + // ForyCodec foryCodec = new ForyCodec(); + // CompositeCodec codec = new CompositeCodec(StringCodec.INSTANCE, foryCodec, foryCodec); TypedJsonJacksonCodec jsonCodec = new TypedJsonJacksonCodec(Object.class, om); // 组合序列化 key 使用 String 内容使用通用 json 格式 CompositeCodec codec = new CompositeCodec(StringCodec.INSTANCE, jsonCodec, jsonCodec); diff --git a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java index 087132ea3..30de412a8 100644 --- a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java +++ b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java @@ -3,6 +3,7 @@ package org.dromara.common.sensitive.core; import cn.hutool.core.convert.Convert; import cn.hutool.core.util.DesensitizedUtil; import lombok.AllArgsConstructor; +import org.dromara.common.core.utils.DesensitizedUtils; import java.util.function.Function; @@ -80,6 +81,18 @@ public enum SensitiveStrategy { */ FIRST_MASK(DesensitizedUtil::firstMask), + /** + * 通用字符串脱敏 + * 可配置前后可见长度和中间掩码长度 + * 默认示例:前4位可见,后4位可见,中间固定4个* + */ + STRING_MASK(s -> DesensitizedUtils.mask(s, 4, 4, 4)), + + /** + * 高安全级别脱敏(Token / 私钥):前2位可见,后2位可见,中间全部掩码 + */ + MASK_HIGH_SECURITY(s -> DesensitizedUtils.maskHighSecurity(s, 2, 2)), + /** * 清空为"" */ diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java index 5f49d9c27..667be4d2f 100644 --- a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java +++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java @@ -28,9 +28,14 @@ public class SocialLoginConfigProperties { private String redirectUri; /** - * 是否获取unionId + * 是否需要申请unionid,目前只针对qq登录 */ - private boolean unionId; + private Boolean unionId; + + /** + * Microsoft Entra ID(原微软 AAD)中的租户 ID + */ + private String tenantId; /** * Coding 企业名称 diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java index 3f7924d9b..df21aa8df 100644 --- a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java +++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java @@ -57,7 +57,7 @@ public class SocialUtils { case "taobao" -> new AuthTaobaoRequest(builder.build(), STATE_CACHE); case "douyin" -> new AuthDouyinRequest(builder.build(), STATE_CACHE); case "linkedin" -> new AuthLinkedinRequest(builder.build(), STATE_CACHE); - case "microsoft" -> new AuthMicrosoftRequest(builder.build(), STATE_CACHE); + case "microsoft" -> new AuthMicrosoftRequest(builder.tenantId(obj.getTenantId()).build(), STATE_CACHE); case "renren" -> new AuthRenrenRequest(builder.build(), STATE_CACHE); case "stack_overflow" -> new AuthStackOverflowRequest(builder.stackOverflowKey(obj.getStackOverflowKey()).build(), STATE_CACHE); case "huawei" -> new AuthHuaweiV3Request(builder.build(), STATE_CACHE); diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java index 4b6981a10..98f03f3ad 100644 --- a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java @@ -55,7 +55,7 @@ public class TenantHelper { /** * 开启忽略租户(开启后需手动调用 {@link #disableIgnore()} 关闭) */ - public static void enableIgnore() { + private static void enableIgnore() { IgnoreStrategy ignoreStrategy = getIgnoreStrategy(); if (ObjectUtil.isNull(ignoreStrategy)) { InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().tenantLine(true).build()); @@ -69,7 +69,7 @@ public class TenantHelper { /** * 关闭忽略租户 */ - public static void disableIgnore() { + private static void disableIgnore() { IgnoreStrategy ignoreStrategy = getIgnoreStrategy(); if (ObjectUtil.isNotNull(ignoreStrategy)) { boolean noOtherIgnoreStrategy = !Boolean.TRUE.equals(ignoreStrategy.getDynamicTableName()) diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java index 3d1aac22a..d519b9d55 100644 --- a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java @@ -15,6 +15,7 @@ import org.dromara.common.core.exception.base.BaseException; import org.dromara.common.core.utils.StreamUtils; import org.dromara.common.json.utils.JsonUtils; import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.expression.ExpressionException; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.validation.BindException; import org.springframework.web.HttpRequestMethodNotSupportedException; @@ -43,7 +44,7 @@ public class GlobalExceptionHandler { */ @ExceptionHandler(HttpRequestMethodNotSupportedException.class) public R handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, - HttpServletRequest request) { + HttpServletRequest request) { String requestURI = request.getRequestURI(); log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod()); return R.fail(HttpStatus.HTTP_BAD_METHOD, e.getMessage()); @@ -210,4 +211,13 @@ public class GlobalExceptionHandler { return R.fail(HttpStatus.HTTP_BAD_REQUEST, "请求参数格式错误:" + e.getMostSpecificCause().getMessage()); } + /** + * SpEL 表达式相关异常 + */ + @ExceptionHandler(ExpressionException.class) + public R handleSpelException(ExpressionException e, HttpServletRequest request) { + log.error("请求地址'{}',SpEL解析异常: {}", request.getRequestURI(), e.getMessage()); + return R.fail(HttpStatus.HTTP_INTERNAL_ERROR, "SpEL解析失败:" + e.getMessage()); + } + } diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java index f25601572..b56cec1f5 100644 --- a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java @@ -2,11 +2,17 @@ package org.dromara.common.web.interceptor; import cn.hutool.core.io.IoUtil; import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.time.StopWatch; +import org.dromara.common.core.constant.SystemConstants; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.json.utils.JsonUtils; import org.dromara.common.web.filter.RepeatedlyRequestWrapper; @@ -14,8 +20,10 @@ import org.springframework.http.MediaType; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; -import java.io.BufferedReader; +import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.Set; /** * web的调用时间统计拦截器 @@ -31,19 +39,25 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String url = request.getMethod() + " " + request.getRequestURI(); - // 打印请求参数 if (isJsonRequest(request)) { String jsonParam = ""; if (request instanceof RepeatedlyRequestWrapper) { - BufferedReader reader = request.getReader(); - jsonParam = IoUtil.read(reader); + jsonParam = IoUtil.read(request.getReader()); + if (StringUtils.isNotBlank(jsonParam)) { + ObjectMapper objectMapper = JsonUtils.getObjectMapper(); + JsonNode rootNode = objectMapper.readTree(jsonParam); + removeSensitiveFields(rootNode, SystemConstants.EXCLUDE_PROPERTIES); + jsonParam = rootNode.toString(); + } } log.info("[PLUS]开始请求 => URL[{}],参数类型[json],参数:[{}]", url, jsonParam); } else { Map parameterMap = request.getParameterMap(); if (MapUtil.isNotEmpty(parameterMap)) { - String parameters = JsonUtils.toJsonString(parameterMap); + Map map = new LinkedHashMap<>(parameterMap); + MapUtil.removeAny(map, SystemConstants.EXCLUDE_PROPERTIES); + String parameters = JsonUtils.toJsonString(map); log.info("[PLUS]开始请求 => URL[{}],参数类型[param],参数:[{}]", url, parameters); } else { log.info("[PLUS]开始请求 => URL[{}],无参数", url); @@ -57,6 +71,30 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor { return true; } + private void removeSensitiveFields(JsonNode node, String[] excludeProperties) { + if (node == null) { + return; + } + if (node.isObject()) { + ObjectNode objectNode = (ObjectNode) node; + // 收集要删除的字段名(避免 ConcurrentModification) + Set fieldsToRemove = new HashSet<>(); + objectNode.fieldNames().forEachRemaining(fieldName -> { + if (ArrayUtil.contains(excludeProperties, fieldName)) { + fieldsToRemove.add(fieldName); + } + }); + fieldsToRemove.forEach(objectNode::remove); + // 递归处理子节点 + objectNode.elements().forEachRemaining(child -> removeSensitiveFields(child, excludeProperties)); + } else if (node.isArray()) { + ArrayNode arrayNode = (ArrayNode) node; + for (JsonNode child : arrayNode) { + removeSensitiveFields(child, excludeProperties); + } + } + } + @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java index ced141ef6..415e440e0 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java @@ -62,6 +62,8 @@ public class TestDemoServiceImpl implements ITestDemoService { private LambdaQueryWrapper buildQueryWrapper(TestDemoBo bo) { Map params = bo.getParams(); LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(bo.getDeptId() != null, TestDemo::getDeptId, bo.getDeptId()); + lqw.eq(bo.getUserId() != null, TestDemo::getUserId, bo.getUserId()); lqw.like(StringUtils.isNotBlank(bo.getTestKey()), TestDemo::getTestKey, bo.getTestKey()); lqw.eq(StringUtils.isNotBlank(bo.getValue()), TestDemo::getValue, bo.getValue()); lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestTreeServiceImpl.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestTreeServiceImpl.java index e4e548b65..836a0909b 100644 --- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestTreeServiceImpl.java +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestTreeServiceImpl.java @@ -2,6 +2,7 @@ package org.dromara.demo.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.demo.domain.TestTree; @@ -9,7 +10,6 @@ import org.dromara.demo.domain.bo.TestTreeBo; import org.dromara.demo.domain.vo.TestTreeVo; import org.dromara.demo.mapper.TestTreeMapper; import org.dromara.demo.service.ITestTreeService; -import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import java.util.Collection; @@ -44,6 +44,8 @@ public class TestTreeServiceImpl implements ITestTreeService { private LambdaQueryWrapper buildQueryWrapper(TestTreeBo bo) { Map params = bo.getParams(); LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(bo.getDeptId() != null, TestTree::getDeptId, bo.getDeptId()); + lqw.eq(bo.getUserId() != null, TestTree::getUserId, bo.getUserId()); lqw.like(StringUtils.isNotBlank(bo.getTreeName()), TestTree::getTreeName, bo.getTreeName()); lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, TestTree::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime")); diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/controller/GenController.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/controller/GenController.java index 99626a208..802c43ca6 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/controller/GenController.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/controller/GenController.java @@ -90,10 +90,12 @@ public class GenController extends BaseController { /** * 导入表结构(保存) * - * @param tables 表名串 + * @param tables 表名串 + * @param dataName 数据源名称 */ @SaCheckPermission("tool:gen:import") @Log(title = "代码生成", businessType = BusinessType.IMPORT) + @Lock4j(keys = {"#dataName"}, acquireTimeout = 10000) @RepeatSubmit() @PostMapping("/importTable") public R importTableSave(String tables, String dataName) { @@ -175,7 +177,7 @@ public class GenController extends BaseController { */ @SaCheckPermission("tool:gen:edit") @Log(title = "代码生成", businessType = BusinessType.UPDATE) - @Lock4j + @Lock4j(keys = {"#tableId"}, acquireTimeout = 5000) @GetMapping("/synchDb/{tableId}") public R synchDb(@PathVariable("tableId") Long tableId) { genTableService.synchDb(tableId); @@ -214,7 +216,7 @@ public class GenController extends BaseController { */ @SaCheckPermission("tool:gen:list") @GetMapping(value = "/getDataNames") - public R getCurrentDataSourceNameList(){ + public R getCurrentDataSourceNameList() { return R.ok(DataBaseHelper.getDataSourceNameList()); } } diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java index 6b2e429ed..63fd1f5b7 100644 --- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java @@ -4,13 +4,12 @@ import com.baomidou.mybatisplus.annotation.FieldStrategy; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import org.dromara.common.core.utils.StringUtils; -import org.dromara.common.mybatis.core.domain.BaseEntity; +import jakarta.validation.constraints.NotBlank; import lombok.Data; import lombok.EqualsAndHashCode; import org.apache.ibatis.type.JdbcType; - -import jakarta.validation.constraints.NotBlank; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.domain.BaseEntity; /** * 代码生成业务字段表 gen_table_column @@ -115,6 +114,7 @@ public class GenTableColumn extends BaseEntity { /** * 字典类型 */ + @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR) private String dictType; /** 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 c4c79b0ba..3e7bdf7bb 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 @@ -8,7 +8,6 @@ import com.baomidou.dynamic.datasource.annotation.DS; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.RequiredArgsConstructor; @@ -28,6 +27,7 @@ import org.dromara.common.core.utils.file.FileUtils; import org.dromara.common.json.utils.JsonUtils; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.utils.IdGeneratorUtil; import org.dromara.generator.constant.GenConstants; import org.dromara.generator.domain.GenTable; import org.dromara.generator.domain.GenTableColumn; @@ -60,7 +60,6 @@ public class GenTableServiceImpl implements IGenTableService { private final GenTableMapper baseMapper; private final GenTableColumnMapper genTableColumnMapper; - private final IdentifierGenerator identifierGenerator; private static final String[] TABLE_IGNORE = new String[]{"sj_", "flow_", "gen_"}; @@ -322,7 +321,7 @@ public class GenTableServiceImpl implements IGenTableService { GenTable table = baseMapper.selectGenTableById(tableId); List menuIds = new ArrayList<>(); for (int i = 0; i < 6; i++) { - menuIds.add(identifierGenerator.nextId(null).longValue()); + menuIds.add(IdGeneratorUtil.nextLongId()); } table.setMenuIds(menuIds); // 设置主键列信息 @@ -468,7 +467,7 @@ public class GenTableServiceImpl implements IGenTableService { GenTable table = baseMapper.selectGenTableById(tableId); List menuIds = new ArrayList<>(); for (int i = 0; i < 6; i++) { - menuIds.add(identifierGenerator.nextId(null).longValue()); + menuIds.add(IdGeneratorUtil.nextLongId()); } table.setMenuIds(menuIds); // 设置主键列信息 diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java index 81200c115..35c1a8996 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java @@ -2,21 +2,20 @@ package org.dromara.system.controller.system; import cn.dev33.satoken.annotation.SaCheckPermission; -import cn.hutool.core.util.ObjectUtil; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import lombok.RequiredArgsConstructor; import org.dromara.common.core.domain.R; import org.dromara.common.core.validate.QueryGroup; -import org.dromara.common.web.core.BaseController; import org.dromara.common.log.annotation.Log; import org.dromara.common.log.enums.BusinessType; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; import org.dromara.system.domain.bo.SysOssBo; import org.dromara.system.domain.vo.SysOssUploadVo; import org.dromara.system.domain.vo.SysOssVo; import org.dromara.system.service.ISysOssService; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.constraints.NotEmpty; -import lombok.RequiredArgsConstructor; import org.springframework.http.MediaType; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -70,9 +69,6 @@ public class SysOssController extends BaseController { @Log(title = "OSS对象存储", businessType = BusinessType.INSERT) @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public R upload(@RequestPart("file") MultipartFile file) { - if (ObjectUtil.isNull(file)) { - return R.fail("上传文件不能为空"); - } SysOssVo oss = ossService.upload(file); SysOssUploadVo uploadVo = new SysOssUploadVo(); uploadVo.setUrl(oss.getUrl()); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java index 9621cb239..2edab3eb9 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java @@ -2,6 +2,7 @@ package org.dromara.system.controller.system; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.crypto.digest.BCrypt; import lombok.RequiredArgsConstructor; import org.dromara.common.core.domain.R; @@ -114,7 +115,7 @@ public class SysProfileController extends BaseController { @Log(title = "用户头像", businessType = BusinessType.UPDATE) @PostMapping(value = "/avatar", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public R avatar(@RequestPart("avatarfile") MultipartFile avatarfile) { - if (!avatarfile.isEmpty()) { + if (ObjectUtil.isNotNull(avatarfile) && !avatarfile.isEmpty()) { String extension = FileUtil.extName(avatarfile.getOriginalFilename()); if (!StringUtils.equalsAnyIgnoreCase(extension, MimeTypeUtils.IMAGE_EXTENSION)) { return R.fail("文件格式不正确,请上传" + Arrays.toString(MimeTypeUtils.IMAGE_EXTENSION) + "格式"); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java index d96fa1246..6b0b2a27e 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java @@ -1,6 +1,7 @@ package org.dromara.system.service.impl; import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Dict; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; @@ -14,6 +15,7 @@ import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.ObjectUtils; import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.redis.utils.CacheUtils; @@ -82,6 +84,7 @@ public class SysConfigServiceImpl implements ISysConfigService, ConfigService { /** * 获取注册开关 + * * @param tenantId 租户id * @return true开启,false关闭 */ @@ -212,4 +215,54 @@ public class SysConfigServiceImpl implements ISysConfigService, ConfigService { return SpringUtils.getAopProxy(this).selectConfigByKey(configKey); } + /** + * 根据参数 key 获取 Map 类型的配置 + * + * @param configKey 参数 key + * @return Dict 对象,如果配置为空或无法解析,返回空 Dict + */ + @Override + public Dict getConfigMap(String configKey) { + String configValue = getConfigValue(configKey); + return JsonUtils.parseMap(configValue); + } + + /** + * 根据参数 key 获取 Map 类型的配置列表 + * + * @param configKey 参数 key + * @return Dict 列表,如果配置为空或无法解析,返回空列表 + */ + @Override + public List getConfigArrayMap(String configKey) { + String configValue = getConfigValue(configKey); + return JsonUtils.parseArrayMap(configValue); + } + + /** + * 根据参数 key 获取指定类型的配置对象 + * + * @param configKey 参数 key + * @param clazz 目标对象类型 + * @return 对象实例,如果配置为空或无法解析,返回 null + */ + @Override + public T getConfigObject(String configKey, Class clazz) { + String configValue = getConfigValue(configKey); + return JsonUtils.parseObject(configValue, clazz); + } + + /** + * 根据参数 key 获取指定类型的配置列表= + * + * @param configKey 参数 key + * @param clazz 目标元素类型 + * @return 指定类型列表,如果配置为空或无法解析,返回空列表 + */ + @Override + public List getConfigArray(String configKey, Class clazz) { + String configValue = getConfigValue(configKey); + return JsonUtils.parseArray(configValue, clazz); + } + } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java index 33341a91d..d920ddbde 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java @@ -192,6 +192,9 @@ public class SysOssServiceImpl implements ISysOssService, OssService { */ @Override public SysOssVo upload(MultipartFile file) { + if (ObjectUtil.isNull(file) || file.isEmpty()) { + throw new ServiceException("上传文件不能为空"); + } String originalfileName = file.getOriginalFilename(); String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length()); OssClient storage = OssFactory.instance(); @@ -216,12 +219,16 @@ public class SysOssServiceImpl implements ISysOssService, OssService { */ @Override public SysOssVo upload(File file) { + if (ObjectUtil.isNull(file) || !file.isFile() || file.length() <= 0) { + throw new ServiceException("上传文件不能为空"); + } String originalfileName = file.getName(); String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length()); OssClient storage = OssFactory.instance(); + long length = file.length(); UploadResult uploadResult = storage.uploadSuffix(file, suffix); SysOssExt ext1 = new SysOssExt(); - ext1.setFileSize(file.length()); + ext1.setFileSize(length); // 保存文件信息 return buildResultEntity(originalfileName, suffix, storage.getConfigKey(), uploadResult, ext1); } @@ -270,7 +277,7 @@ public class SysOssServiceImpl implements ISysOssService, OssService { OssClient storage = OssFactory.instance(oss.getService()); // 仅修改桶类型为 private 的URL,临时URL时长为120s if (AccessPolicyType.PRIVATE == storage.getAccessPolicy()) { - oss.setUrl(storage.getPrivateUrl(oss.getFileName(), Duration.ofSeconds(120))); + oss.setUrl(storage.createPresignedGetUrl(oss.getFileName(), Duration.ofSeconds(120))); } return oss; } 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 cacb2a257..88372f0b7 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 @@ -92,4 +92,20 @@ public interface FlowConstant { * 业务编码 */ String BUSINESS_CODE = "businessCode"; + + /** + * 忽略-办理权限校验(true:忽略,false:不忽略) + */ + String VAR_IGNORE = "ignore"; + + /** + * 忽略-委派处理(true:忽略,false:不忽略) + */ + String VAR_IGNORE_DEPUTE = "ignoreDepute"; + + /** + * 忽略-会签票签处理(true:忽略,false:不忽略) + */ + String VAR_IGNORE_COOPERATE = "ignoreCooperate"; + } 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 10d9de838..54e412ae0 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 @@ -187,6 +187,7 @@ public class FlwDefinitionController extends BaseController { @RepeatSubmit() @PutMapping("/active/{id}") @Transactional(rollbackFor = Exception.class) + @Log(title = "流程定义", businessType = BusinessType.UPDATE) 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 c798dc5c2..a8a5fc604 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,7 +1,9 @@ package org.dromara.workflow.controller; +import cn.hutool.core.convert.Convert; import lombok.RequiredArgsConstructor; import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StreamUtils; import org.dromara.common.idempotent.annotation.RepeatSubmit; import org.dromara.common.log.annotation.Log; import org.dromara.common.log.enums.BusinessType; @@ -75,8 +77,9 @@ public class FlwInstanceController extends BaseController { * @param businessIds 业务id */ @DeleteMapping("/deleteByBusinessIds/{businessIds}") + @Log(title = "流程实例管理", businessType = BusinessType.DELETE) public R deleteByBusinessIds(@PathVariable List businessIds) { - return toAjax(flwInstanceService.deleteByBusinessIds(businessIds)); + return toAjax(flwInstanceService.deleteByBusinessIds(StreamUtils.toList(businessIds, Convert::toStr))); } /** @@ -85,6 +88,7 @@ public class FlwInstanceController extends BaseController { * @param instanceIds 实例id */ @DeleteMapping("/deleteByInstanceIds/{instanceIds}") + @Log(title = "流程实例管理", businessType = BusinessType.DELETE) public R deleteByInstanceIds(@PathVariable List instanceIds) { return toAjax(flwInstanceService.deleteByInstanceIds(instanceIds)); } @@ -95,6 +99,7 @@ public class FlwInstanceController extends BaseController { * @param instanceIds 实例id */ @DeleteMapping("/deleteHisByInstanceIds/{instanceIds}") + @Log(title = "流程实例管理", businessType = BusinessType.DELETE) public R deleteHisByInstanceIds(@PathVariable List instanceIds) { return toAjax(flwInstanceService.deleteHisByInstanceIds(instanceIds)); } @@ -106,6 +111,7 @@ public class FlwInstanceController extends BaseController { */ @RepeatSubmit() @PutMapping("/cancelProcessApply") + @Log(title = "流程实例管理", businessType = BusinessType.UPDATE) public R cancelProcessApply(@RequestBody FlowCancelBo bo) { return toAjax(flwInstanceService.cancelProcessApply(bo)); } @@ -118,6 +124,7 @@ public class FlwInstanceController extends BaseController { */ @RepeatSubmit() @PutMapping("/active/{id}") + @Log(title = "流程实例管理", businessType = BusinessType.UPDATE) public R active(@PathVariable Long id, @RequestParam boolean active) { return R.ok(active ? insService.active(id) : insService.unActive(id)); } @@ -160,6 +167,7 @@ public class FlwInstanceController extends BaseController { */ @RepeatSubmit() @PutMapping("/updateVariable") + @Log(title = "流程实例管理", businessType = BusinessType.UPDATE) public R updateVariable(@Validated @RequestBody FlowVariableBo bo) { return toAjax(flwInstanceService.updateVariable(bo)); } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwSpelController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwSpelController.java index 212b6592a..7d3932e7c 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwSpelController.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwSpelController.java @@ -23,7 +23,7 @@ import org.springframework.web.bind.annotation.*; import java.util.List; /** - * 流程spel达式定义 + * 流程spel表达式定义 * * @author Michelle.Chung * @date 2025-07-04 @@ -38,7 +38,7 @@ public class FlwSpelController extends BaseController { private final IFlwSpelService flwSpelService; /** - * 查询流程spel达式定义列表 + * 查询流程spel表达式定义列表 */ @SaCheckPermission("workflow:spel:list") @GetMapping("/list") @@ -47,7 +47,7 @@ public class FlwSpelController extends BaseController { } /** - * 获取流程spel达式定义详细信息 + * 获取流程spel表达式定义详细信息 * * @param id 主键 */ @@ -58,10 +58,10 @@ public class FlwSpelController extends BaseController { } /** - * 新增流程spel达式定义 + * 新增流程spel表达式定义 */ @SaCheckPermission("workflow:spel:add") - @Log(title = "流程spel达式定义", businessType = BusinessType.INSERT) + @Log(title = "流程spel表达式定义", businessType = BusinessType.INSERT) @RepeatSubmit() @PostMapping() public R add(@Validated(AddGroup.class) @RequestBody FlowSpelBo bo) { @@ -69,10 +69,10 @@ public class FlwSpelController extends BaseController { } /** - * 修改流程spel达式定义 + * 修改流程spel表达式定义 */ @SaCheckPermission("workflow:spel:edit") - @Log(title = "流程spel达式定义", businessType = BusinessType.UPDATE) + @Log(title = "流程spel表达式定义", businessType = BusinessType.UPDATE) @RepeatSubmit() @PutMapping() public R edit(@Validated(EditGroup.class) @RequestBody FlowSpelBo bo) { @@ -80,12 +80,12 @@ public class FlwSpelController extends BaseController { } /** - * 删除流程spel达式定义 + * 删除流程spel表达式定义 * * @param ids 主键串 */ @SaCheckPermission("workflow:spel:remove") - @Log(title = "流程spel达式定义", businessType = BusinessType.DELETE) + @Log(title = "流程spel表达式定义", businessType = BusinessType.DELETE) @DeleteMapping("/{ids}") public R remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) { return toAjax(flwSpelService.deleteWithValidByIds(List.of(ids), true)); diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java index 4370ff82b..f372fbb0f 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java @@ -216,6 +216,7 @@ public class FlwTaskController extends BaseController { * @return 结果 */ @PostMapping("/urgeTask") + @Log(title = "任务管理", businessType = BusinessType.INSERT) public R urgeTask(@RequestBody FlowUrgeTaskBo bo) { return toAjax(flwTaskService.urgeTask(bo)); } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowSpel.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowSpel.java index be74ccb90..89a7ae9fb 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowSpel.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowSpel.java @@ -10,7 +10,7 @@ import org.dromara.common.mybatis.core.domain.BaseEntity; import java.io.Serial; /** - * 流程spel达式定义对象 flow_spel + * 流程spel表达式定义对象 flow_spel * * @author Michelle.Chung * @date 2025-07-04 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 654bf0800..a67a1f78e 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 @@ -1,6 +1,5 @@ package org.dromara.workflow.domain.bo; -import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; import org.dromara.common.core.validate.AddGroup; diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInstanceBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInstanceBo.java index fb1fe611b..bb1621f91 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInstanceBo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInstanceBo.java @@ -50,6 +50,6 @@ public class FlowInstanceBo implements Serializable { /** * 申请人Ids */ - private List createByIds; + private List createByIds; } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowSpelBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowSpelBo.java index ebad8eafb..da78935c6 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowSpelBo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowSpelBo.java @@ -10,7 +10,7 @@ import jakarta.validation.constraints.*; import org.dromara.workflow.domain.FlowSpel; /** - * 流程spel达式定义业务对象 flow_spel + * 流程spel表达式定义业务对象 flow_spel * * @author Michelle.Chung * @date 2025-07-04 diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTaskBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTaskBo.java index 64dd08255..75405647f 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTaskBo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTaskBo.java @@ -1,10 +1,13 @@ package org.dromara.workflow.domain.bo; +import com.fasterxml.jackson.annotation.JsonInclude; import lombok.Data; import java.io.Serial; import java.io.Serializable; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * 任务请求对象 @@ -42,6 +45,11 @@ public class FlowTaskBo implements Serializable { */ private Long instanceId; + /** + * 流程状态 + */ + private String flowStatus; + /** * 权限列表 */ @@ -52,4 +60,10 @@ public class FlowTaskBo implements Serializable { */ private List createByIds; + /** + * 请求参数 + */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + private Map params = new HashMap<>(); + } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowHisTaskVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowHisTaskVo.java index ee0fd6330..a9f6a60f4 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowHisTaskVo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowHisTaskVo.java @@ -253,4 +253,8 @@ public class FlowHisTaskVo implements Serializable { this.cooperateTypeName = CooperateType.getValueByKey(cooperateType); } + public String getCreateTime() { + return DateUtils.formatFriendlyTime(createTime); + } + } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowInstanceVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowInstanceVo.java index fce6725ff..b03f73b13 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowInstanceVo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowInstanceVo.java @@ -78,7 +78,7 @@ public class FlowInstanceVo { private String variable; /** - * 流程状态(0待提交 1审批中 2 审批通过 3自动通过 8已完成 9已退回 10失效) + * 流程状态 */ private String flowStatus; diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowSpelVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowSpelVo.java index 24f1437e8..76ead83d9 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowSpelVo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowSpelVo.java @@ -14,7 +14,7 @@ import java.util.Date; /** - * 流程spel达式定义视图对象 flow_spel + * 流程spel表达式定义视图对象 flow_spel * * @author Michelle.Chung * @date 2025-07-04 diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowTaskVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowTaskVo.java index 25a7d85b1..ffe804912 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowTaskVo.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowTaskVo.java @@ -1,6 +1,7 @@ package org.dromara.workflow.domain.vo; import lombok.Data; +import org.dromara.common.core.utils.DateUtils; import org.dromara.common.translation.annotation.Translation; import org.dromara.common.translation.constant.TransConstant; import org.dromara.warm.flow.core.entity.User; @@ -8,7 +9,6 @@ import org.dromara.workflow.common.constant.FlowConstant; import java.io.Serial; import java.io.Serializable; -import java.math.BigDecimal; import java.util.Date; import java.util.List; import java.util.Map; @@ -163,7 +163,7 @@ public class FlowTaskVo implements Serializable { /** * 流程签署比例值 大于0为票签,会签 */ - private BigDecimal nodeRatio; + private String nodeRatio; /** * 申请人id @@ -212,4 +212,8 @@ public class FlowTaskVo implements Serializable { private String businessTitle; //业务扩展信息结束 + public String getCreateTime() { + return DateUtils.formatFriendlyTime(createTime); + } + } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowProcessEventHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowProcessEventHandler.java index 91b608c97..1965f67e8 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowProcessEventHandler.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowProcessEventHandler.java @@ -7,6 +7,7 @@ import org.dromara.common.core.domain.event.ProcessEvent; import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.warm.flow.core.entity.Instance; +import org.dromara.warm.flow.core.entity.Task; import org.dromara.workflow.common.ConditionalOnEnable; import org.springframework.stereotype.Component; @@ -55,22 +56,22 @@ public class FlowProcessEventHandler { * * @param flowCode 流程定义编码 * @param instance 实例数据 - * @param taskId 任务id + * @param nextTask 任务 * @param params 上一个任务的办理参数 */ - public void processTaskHandler(String flowCode, Instance instance, Long taskId, Map params) { + public void processTaskHandler(String flowCode, Instance instance, Task nextTask, Map params) { String tenantId = TenantHelper.getTenantId(); log.info("【流程任务事件发布】租户ID: {}, 流程编码: {}, 业务ID: {}, 节点类型: {}, 节点编码: {}, 节点名称: {}, 任务ID: {}", - tenantId, flowCode, instance.getBusinessId(), instance.getNodeType(), instance.getNodeCode(), instance.getNodeName(), taskId); + tenantId, flowCode, instance.getBusinessId(), nextTask.getNodeType(), nextTask.getNodeCode(), nextTask.getNodeName(), nextTask.getId()); ProcessTaskEvent processTaskEvent = new ProcessTaskEvent(); processTaskEvent.setTenantId(tenantId); processTaskEvent.setFlowCode(flowCode); processTaskEvent.setInstanceId(instance.getId()); processTaskEvent.setBusinessId(instance.getBusinessId()); - processTaskEvent.setNodeType(instance.getNodeType()); - processTaskEvent.setNodeCode(instance.getNodeCode()); - processTaskEvent.setNodeName(instance.getNodeName()); - processTaskEvent.setTaskId(taskId); + processTaskEvent.setNodeType(nextTask.getNodeType()); + processTaskEvent.setNodeCode(nextTask.getNodeCode()); + processTaskEvent.setNodeName(nextTask.getNodeName()); + processTaskEvent.setTaskId(nextTask.getId()); processTaskEvent.setStatus(instance.getFlowStatus()); processTaskEvent.setParams(params); SpringUtils.context().publishEvent(processTaskEvent); 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 d158e2623..fca24d0d5 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 @@ -5,6 +5,7 @@ import cn.hutool.core.convert.Convert; import cn.hutool.core.lang.TypeReference; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.enums.BusinessStatusEnum; @@ -73,6 +74,9 @@ public class WorkflowGlobalListener implements GlobalListener { String ext = listenerVariable.getNode().getExt(); if (StringUtils.isNotBlank(ext)) { Map variable = listenerVariable.getVariable(); + if (CollUtil.isNotEmpty(variable)) { + variable = new HashMap<>(); + } NodeExtVo nodeExt = nodeExtService.parseNodeExt(ext, variable); Set copyList = nodeExt.getCopySettings(); if (CollUtil.isNotEmpty(copyList)) { @@ -104,20 +108,61 @@ public class WorkflowGlobalListener implements GlobalListener { Definition definition = listenerVariable.getDefinition(); Instance instance = listenerVariable.getInstance(); String applyNodeCode = flwCommonService.applyNodeCode(definition.getId()); + String hisStatus = flowParams != null ? flowParams.getHisStatus() : null; + for (Task flowTask : nextTasks) { - // 如果办理或者退回并行存在需要指定办理人,则直接覆盖办理人 - if (variable.containsKey(flowTask.getNodeCode()) && TaskStatusEnum.isPassOrBack(flowParams.getHisStatus())) { - String userIds = variable.get(flowTask.getNodeCode()).toString(); - flowTask.setPermissionList(List.of(userIds.split(StringUtils.SEPARATOR))); - variable.remove(flowTask.getNodeCode()); + String nodeCode = flowTask.getNodeCode(); + + // 处理办理或退回时指定办理人的情况 + if (TaskStatusEnum.PASS.getStatus().equals(hisStatus)) { + processTaskPermission(variable, flowTask, hisStatus); + } else if (TaskStatusEnum.BACK.getStatus().equals(hisStatus)) { + processTaskPermission(variable, flowTask, hisStatus); } + // 如果是申请节点,则把启动人添加到办理人 - if (flowTask.getNodeCode().equals(applyNodeCode)) { + if (nodeCode.equals(applyNodeCode) && StringUtils.isNotBlank(instance.getCreateBy())) { flowTask.setPermissionList(List.of(instance.getCreateBy())); } } } + /** + * 处理任务权限设置 + * + * @param variable 变量集合 + * @param flowTask 流程任务 + * @param taskStatus 任务状态 + */ + private void processTaskPermission(Map variable, Task flowTask, String taskStatus) { + String nodeKey = taskStatus + StrUtil.COLON + flowTask.getNodeCode(); + + // 检查是否存在状态相关的变量 + if (!variable.containsKey(nodeKey)) { + return; + } + + // 获取用户ID字符串 + Object userIdsObj = variable.get(nodeKey); + if (userIdsObj == null) { + return; + } + + String userIds = userIdsObj.toString(); + if (StringUtils.isBlank(userIds)) { + return; + } + + // 分割用户ID并设置权限列表 + String[] userIdArray = userIds.split(StringUtils.SEPARATOR); + if (userIdArray.length > 0) { + flowTask.setPermissionList(List.of(userIdArray)); + // 移除已处理的状态变量 + variable.remove(nodeKey); + FlowEngine.insService().removeVariables(flowTask.getInstanceId(),nodeKey); + } + } + /** * 完成监听器,当前任务完成后执行 * @@ -144,7 +189,8 @@ public class WorkflowGlobalListener implements GlobalListener { //申请人提交事件 Boolean submit = MapUtil.getBool(variable, FlowConstant.SUBMIT); if (submit != null && submit) { - flowProcessEventHandler.processHandler(definition.getFlowCode(), instance, instance.getFlowStatus(), variable, true); + String status = determineFlowStatus(instance); + flowProcessEventHandler.processHandler(definition.getFlowCode(), instance, status, variable, true); } else { // 判断流程状态(发布:撤销,退回,作废,终止,已完成事件) String status = determineFlowStatus(instance); @@ -165,7 +211,7 @@ public class WorkflowGlobalListener implements GlobalListener { //发布任务事件 if (CollUtil.isNotEmpty(nextTasks)) { for (Task nextTask : nextTasks) { - flowProcessEventHandler.processTaskHandler(definition.getFlowCode(), instance, nextTask.getId(), params); + flowProcessEventHandler.processTaskHandler(definition.getFlowCode(), instance, nextTask, params); } } if (ObjectUtil.isNull(flowParams)) { diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwSpelMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwSpelMapper.java index d3204958f..12dff9f77 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwSpelMapper.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwSpelMapper.java @@ -5,7 +5,7 @@ import org.dromara.workflow.domain.vo.FlowSpelVo; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; /** - * 流程spel达式定义Mapper接口 + * 流程spel表达式定义Mapper接口 * * @author Michelle.Chung * @date 2025-07-04 diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java index 54ffe977e..814b89d0f 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java @@ -75,7 +75,7 @@ public interface IFlwInstanceService { * @param businessIds 业务id * @return 结果 */ - boolean deleteByBusinessIds(List businessIds); + boolean deleteByBusinessIds(List businessIds); /** * 按照实例id删除流程实例 diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwSpelService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwSpelService.java index 02781682a..7c4453433 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwSpelService.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwSpelService.java @@ -12,7 +12,7 @@ import java.util.List; import java.util.Map; /** - * 流程spel达式定义Service接口 + * 流程spel表达式定义Service接口 * * @author Michelle.Chung * @date 2025-07-04 @@ -20,48 +20,48 @@ import java.util.Map; public interface IFlwSpelService { /** - * 查询流程spel达式定义 + * 查询流程spel表达式定义 * * @param id 主键 - * @return 流程spel达式定义 + * @return 流程spel表达式定义 */ FlowSpelVo queryById(Long id); /** - * 分页查询流程spel达式定义列表 + * 分页查询流程spel表达式定义列表 * * @param bo 查询条件 * @param pageQuery 分页参数 - * @return 流程spel达式定义分页列表 + * @return 流程spel表达式定义分页列表 */ TableDataInfo queryPageList(FlowSpelBo bo, PageQuery pageQuery); /** - * 查询符合条件的流程spel达式定义列表 + * 查询符合条件的流程spel表达式定义列表 * * @param bo 查询条件 - * @return 流程spel达式定义列表 + * @return 流程spel表达式定义列表 */ List queryList(FlowSpelBo bo); /** - * 新增流程spel达式定义 + * 新增流程spel表达式定义 * - * @param bo 流程spel达式定义 + * @param bo 流程spel表达式定义 * @return 是否新增成功 */ Boolean insertByBo(FlowSpelBo bo); /** - * 修改流程spel达式定义 + * 修改流程spel表达式定义 * - * @param bo 流程spel达式定义 + * @param bo 流程spel表达式定义 * @return 是否修改成功 */ Boolean updateByBo(FlowSpelBo bo); /** - * 校验并批量删除流程spel达式定义信息 + * 校验并批量删除流程spel表达式定义信息 * * @param ids 待删除的主键集合 * @param isValid 是否进行有效性校验 diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java index 1e2f6c268..3515ebb03 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java @@ -206,6 +206,9 @@ public class FlwCategoryServiceImpl implements IFlwCategoryService, CategoryServ if (ObjectUtil.isNull(oldCategory)) { throw new ServiceException("流程分类不存在,无法修改"); } + if (oldCategory.getParentId() == 0L && category.getParentId() != 0L) { + throw new ServiceException("不允许修改顶级分类的父级节点"); + } if (!oldCategory.getParentId().equals(category.getParentId())) { FlowCategory newParentCategory = baseMapper.selectById(category.getParentId()); if (ObjectUtil.isNotNull(newParentCategory)) { 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 8f8d61eb0..8d4708b8e 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 @@ -88,23 +88,28 @@ public class FlwCommonServiceImpl implements IFlwCommonService { if (ObjectUtil.isEmpty(messageTypeEnum)) { continue; } - switch (messageTypeEnum) { - case SYSTEM_MESSAGE -> { - SseMessageDto dto = new SseMessageDto(); - dto.setUserIds(userIds); - dto.setMessage(message); - SseMessageUtils.publishMessage(dto); + try { + switch (messageTypeEnum) { + case SYSTEM_MESSAGE -> { + SseMessageDto dto = new SseMessageDto(); + dto.setUserIds(userIds); + dto.setMessage(message); + SseMessageUtils.publishMessage(dto); + } + case EMAIL_MESSAGE -> MailUtils.sendText(emails, subject, message); + case SMS_MESSAGE -> { + // TODO: 补充短信发送逻辑 + log.info("【短信发送 - TODO】用户数量={} 内容={}", userList.size(), message); + } + default -> log.warn("【消息发送】未处理的消息类型:{}", messageTypeEnum); } - case EMAIL_MESSAGE -> MailUtils.sendText(emails, subject, message); - case SMS_MESSAGE -> { - //todo 短信发送 - } - default -> throw new IllegalStateException("Unexpected value: " + messageTypeEnum); + } catch (Exception ex) { + // 记录错误但不抛出,确保主逻辑不受影响 + log.error("【消息发送失败】类型={},原因={}", messageTypeEnum, ex.getMessage(), ex); } } } - /** * 申请人节点编码 * diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java index b89a369cf..1cc61fee4 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java @@ -208,10 +208,6 @@ public class FlwDefinitionServiceImpl implements IFlwDefinitionService { @Override @Transactional(rollbackFor = Exception.class) public void syncDef(String tenantId) { - List flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper().eq(FlowDefinition::getTenantId, DEFAULT_TENANT_ID)); - if (CollUtil.isEmpty(flowDefinitions)) { - return; - } FlowCategory flowCategory = flwCategoryMapper.selectOne(new LambdaQueryWrapper() .eq(FlowCategory::getTenantId, DEFAULT_TENANT_ID) .eq(FlowCategory::getCategoryId, FlowConstant.FLOW_CATEGORY_ID)); @@ -223,6 +219,11 @@ public class FlwDefinitionServiceImpl implements IFlwDefinitionService { flowCategory.setUpdateBy(null); flowCategory.setUpdateTime(null); flwCategoryMapper.insert(flowCategory); + + List flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper().eq(FlowDefinition::getTenantId, DEFAULT_TENANT_ID)); + if (CollUtil.isEmpty(flowDefinitions)) { + return; + } List defIds = StreamUtils.toList(flowDefinitions, FlowDefinition::getId); List flowNodes = flowNodeMapper.selectList(new LambdaQueryWrapper().in(FlowNode::getDefinitionId, defIds)); List flowSkips = flowSkipMapper.selectList(new LambdaQueryWrapper().in(FlowSkip::getDefinitionId, defIds)); 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 be6dfaf1a..4de669da7 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 @@ -181,8 +181,8 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService { */ @Override @Transactional(rollbackFor = Exception.class) - public boolean deleteByBusinessIds(List businessIds) { - List flowInstances = flowInstanceMapper.selectList(new LambdaQueryWrapper().in(FlowInstance::getBusinessId, StreamUtils.toList(businessIds, Convert::toStr))); + public boolean deleteByBusinessIds(List businessIds) { + List flowInstances = flowInstanceMapper.selectList(new LambdaQueryWrapper().in(FlowInstance::getBusinessId, businessIds)); if (CollUtil.isEmpty(flowInstances)) { log.warn("未找到对应的流程实例信息,无法执行删除操作。"); return false; @@ -211,27 +211,17 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService { Function.identity() ); - try { - // 逐一触发删除事件 - 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()); - }); - // 删除实例 - boolean remove = insService.remove(instanceIds); - if (!remove) { - log.warn("删除流程实例失败!"); - throw new ServiceException("删除流程实例失败"); + // 逐一触发删除事件 + instances.forEach(instance -> { + Definition definition = definitionMap.get(instance.getDefinitionId()); + if (ObjectUtil.isNull(definition)) { + log.warn("实例 ID: {} 对应的流程定义信息未找到,跳过删除事件触发。", instance.getId()); + return; } - } catch (Exception e) { - log.warn("操作失败!{}", e.getMessage()); - throw new ServiceException(e.getMessage()); - } - return true; + flowProcessEventHandler.processDeleteHandler(definition.getFlowCode(), instance.getBusinessId()); + }); + // 删除实例 + return insService.remove(instanceIds); } /** @@ -254,27 +244,22 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService { Definition::getId, Function.identity() ); - try { - // 逐一触发删除事件 - 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()); - }); - List flowTaskList = flwTaskService.selectByInstIds(instanceIds); - if (CollUtil.isNotEmpty(flowTaskList)) { - FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTaskList, FlowTask::getId)); + // 逐一触发删除事件 + instances.forEach(instance -> { + Definition definition = definitionMap.get(instance.getDefinitionId()); + if (ObjectUtil.isNull(definition)) { + log.warn("实例 ID: {} 对应的流程定义信息未找到,跳过删除事件触发。", instance.getId()); + return; } - FlowEngine.taskService().deleteByInsIds(instanceIds); - FlowEngine.hisTaskService().deleteByInsIds(instanceIds); - FlowEngine.insService().removeByIds(instanceIds); - } catch (Exception e) { - log.warn("操作失败!{}", e.getMessage()); - throw new ServiceException(e.getMessage()); + flowProcessEventHandler.processDeleteHandler(definition.getFlowCode(), instance.getBusinessId()); + }); + List flowTaskList = flwTaskService.selectByInstIds(instanceIds); + if (CollUtil.isNotEmpty(flowTaskList)) { + FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTaskList, FlowTask::getId)); } + FlowEngine.taskService().deleteByInsIds(instanceIds); + FlowEngine.hisTaskService().deleteByInsIds(instanceIds); + FlowEngine.insService().removeByIds(instanceIds); return true; } @@ -286,29 +271,24 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService { @Override @Transactional(rollbackFor = Exception.class) public boolean cancelProcessApply(FlowCancelBo bo) { - try { - Instance instance = selectInstByBusinessId(bo.getBusinessId()); - if (instance == null) { - throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE); - } - Definition definition = defService.getById(instance.getDefinitionId()); - if (definition == null) { - throw new ServiceException(ExceptionCons.NOT_FOUNT_DEF); - } - String message = bo.getMessage(); - String userIdStr = LoginHelper.getUserIdStr(); - BusinessStatusEnum.checkCancelStatus(instance.getFlowStatus()); - FlowParams flowParams = FlowParams.build() - .message(message) - .flowStatus(BusinessStatusEnum.CANCEL.getStatus()) - .hisStatus(BusinessStatusEnum.CANCEL.getStatus()) - .handler(userIdStr) - .ignore(true); - taskService.revoke(instance.getId(), flowParams); - } catch (Exception e) { - log.error("撤销失败: {}", e.getMessage(), e); - throw new ServiceException(e.getMessage()); + Instance instance = selectInstByBusinessId(bo.getBusinessId()); + if (instance == null) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE); } + Definition definition = defService.getById(instance.getDefinitionId()); + if (definition == null) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_DEF); + } + String message = bo.getMessage(); + String userIdStr = LoginHelper.getUserIdStr(); + BusinessStatusEnum.checkCancelStatus(instance.getFlowStatus()); + FlowParams flowParams = FlowParams.build() + .message(message) + .flowStatus(BusinessStatusEnum.CANCEL.getStatus()) + .hisStatus(BusinessStatusEnum.CANCEL.getStatus()) + .handler(userIdStr) + .ignore(true); + taskService.revoke(instance.getId(), flowParams); return true; } @@ -422,20 +402,14 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService { if (flowInstance == null) { throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE); } - try { - Map variableMap = new HashMap<>(Optional.ofNullable(flowInstance.getVariableMap()).orElse(Collections.emptyMap())); - if (!variableMap.containsKey(bo.getKey())) { - log.error("变量不存在: {}", bo.getKey()); - return false; - } - variableMap.put(bo.getKey(), bo.getValue()); - flowInstance.setVariable(FlowEngine.jsonConvert.objToStr(variableMap)); - flowInstanceMapper.updateById(flowInstance); - } catch (Exception e) { - log.error("设置流程变量失败: {}", e.getMessage(), e); - throw new ServiceException(e.getMessage()); + Map variableMap = new HashMap<>(Optional.ofNullable(flowInstance.getVariableMap()).orElse(Collections.emptyMap())); + if (!variableMap.containsKey(bo.getKey())) { + log.error("变量不存在: {}", bo.getKey()); + return false; } - return true; + variableMap.put(bo.getKey(), bo.getValue()); + flowInstance.setVariable(FlowEngine.jsonConvert.objToStr(variableMap)); + return flowInstanceMapper.updateById(flowInstance) > 0; } /** @@ -480,21 +454,16 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService { @Override @Transactional(rollbackFor = Exception.class) public boolean processInvalid(FlowInvalidBo bo) { - try { - Instance instance = insService.getById(bo.getId()); - if (instance != null) { - BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus()); - } - FlowParams flowParams = FlowParams.build() - .message(bo.getComment()) - .flowStatus(BusinessStatusEnum.INVALID.getStatus()) - .hisStatus(TaskStatusEnum.INVALID.getStatus()) - .ignore(true); - taskService.terminationByInsId(bo.getId(), flowParams); - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); + Instance instance = insService.getById(bo.getId()); + if (instance != null) { + BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus()); } + FlowParams flowParams = FlowParams.build() + .message(bo.getComment()) + .flowStatus(BusinessStatusEnum.INVALID.getStatus()) + .hisStatus(TaskStatusEnum.INVALID.getStatus()) + .ignore(true); + taskService.terminationByInsId(bo.getId(), flowParams); + return true; } } 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 e06b31448..3790cdfd4 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 @@ -28,7 +28,7 @@ import java.util.List; import java.util.Map; /** - * 流程spel达式定义Service业务层处理 + * 流程spel表达式定义Service业务层处理 * * @author Michelle.Chung * @date 2025-07-04 @@ -42,10 +42,10 @@ public class FlwSpelServiceImpl implements IFlwSpelService { private final FlwSpelMapper baseMapper; /** - * 查询流程spel达式定义 + * 查询流程spel表达式定义 * * @param id 主键 - * @return 流程spel达式定义 + * @return 流程spel表达式定义 */ @Override public FlowSpelVo queryById(Long id){ @@ -53,11 +53,11 @@ public class FlwSpelServiceImpl implements IFlwSpelService { } /** - * 分页查询流程spel达式定义列表 + * 分页查询流程spel表达式定义列表 * * @param bo 查询条件 * @param pageQuery 分页参数 - * @return 流程spel达式定义分页列表 + * @return 流程spel表达式定义分页列表 */ @Override public TableDataInfo queryPageList(FlowSpelBo bo, PageQuery pageQuery) { @@ -67,10 +67,10 @@ public class FlwSpelServiceImpl implements IFlwSpelService { } /** - * 查询符合条件的流程spel达式定义列表 + * 查询符合条件的流程spel表达式定义列表 * * @param bo 查询条件 - * @return 流程spel达式定义列表 + * @return 流程spel表达式定义列表 */ @Override public List queryList(FlowSpelBo bo) { @@ -92,9 +92,9 @@ public class FlwSpelServiceImpl implements IFlwSpelService { } /** - * 新增流程spel达式定义 + * 新增流程spel表达式定义 * - * @param bo 流程spel达式定义 + * @param bo 流程spel表达式定义 * @return 是否新增成功 */ @Override @@ -109,9 +109,9 @@ public class FlwSpelServiceImpl implements IFlwSpelService { } /** - * 修改流程spel达式定义 + * 修改流程spel表达式定义 * - * @param bo 流程spel达式定义 + * @param bo 流程spel表达式定义 * @return 是否修改成功 */ @Override @@ -129,7 +129,7 @@ public class FlwSpelServiceImpl implements IFlwSpelService { } /** - * 校验并批量删除流程spel达式定义信息 + * 校验并批量删除流程spel表达式定义信息 * * @param ids 待删除的主键集合 * @param isValid 是否进行有效性校验 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 6703ebdc1..0a8bdc72d 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 @@ -5,9 +5,10 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.lang.Dict; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.lock.annotation.Lock4j; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.RequiredArgsConstructor; @@ -25,10 +26,12 @@ import org.dromara.common.core.validate.EditGroup; import org.dromara.common.json.utils.JsonUtils; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.utils.IdGeneratorUtil; import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.warm.flow.core.FlowEngine; import org.dromara.warm.flow.core.dto.FlowParams; import org.dromara.warm.flow.core.entity.*; +import org.dromara.warm.flow.core.enums.CooperateType; import org.dromara.warm.flow.core.enums.NodeType; import org.dromara.warm.flow.core.enums.SkipType; import org.dromara.warm.flow.core.enums.UserType; @@ -60,7 +63,6 @@ import org.dromara.workflow.service.IFlwTaskService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.math.BigDecimal; import java.util.*; import static org.dromara.workflow.common.constant.FlowConstant.*; @@ -84,7 +86,6 @@ public class FlwTaskServiceImpl implements IFlwTaskService { private final FlowInstanceMapper flowInstanceMapper; private final FlowTaskMapper flowTaskMapper; private final FlowHisTaskMapper flowHisTaskMapper; - private final IdentifierGenerator identifierGenerator; private final UserService userService; private final FlwTaskMapper flwTaskMapper; private final FlwCategoryMapper flwCategoryMapper; @@ -101,6 +102,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService { */ @Override @Transactional(rollbackFor = Exception.class) + @Lock4j(keys = {"#startProcessBo.flowCode + #startProcessBo.businessId"}) public StartProcessReturnDTO startWorkFlow(StartProcessBo startProcessBo) { String businessId = startProcessBo.getBusinessId(); if (StringUtils.isBlank(businessId)) { @@ -137,6 +139,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService { // 将流程定义内的扩展参数设置到变量中 Definition definition = FlowEngine.defService().getPublishByFlowCode(startProcessBo.getFlowCode()); + if (ObjectUtil.isNull(definition)) { + 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); @@ -146,12 +151,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService { .flowCode(startProcessBo.getFlowCode()) .variable(startProcessBo.getVariables()) .flowStatus(BusinessStatusEnum.DRAFT.getStatus()); - Instance instance; - try { - instance = insService.start(businessId, flowParams); - } catch (Exception e) { - throw new ServiceException(e.getMessage()); - } + Instance instance = insService.start(businessId, flowParams); // 保存流程实例业务信息 this.buildFlowInstanceBizExt(instance, bizExt); // 申请人执行流程 @@ -197,53 +197,52 @@ public class FlwTaskServiceImpl implements IFlwTaskService { */ @Override @Transactional(rollbackFor = Exception.class) + @Lock4j(keys = {"#completeTaskBo.taskId"}) public boolean completeTask(CompleteTaskBo completeTaskBo) { - try { - // 获取任务ID并查询对应的流程任务和实例信息 - Long taskId = completeTaskBo.getTaskId(); - List messageType = completeTaskBo.getMessageType(); - String notice = completeTaskBo.getNotice(); - // 获取抄送人 - List flowCopyList = completeTaskBo.getFlowCopyList(); - // 设置抄送人 - Map variables = completeTaskBo.getVariables(); - variables.put(FlowConstant.FLOW_COPY_LIST, flowCopyList); - // 消息类型 - variables.put(FlowConstant.MESSAGE_TYPE, messageType); - // 消息通知 - variables.put(FlowConstant.MESSAGE_NOTICE, notice); + // 获取任务ID并查询对应的流程任务和实例信息 + Long taskId = completeTaskBo.getTaskId(); + List messageType = completeTaskBo.getMessageType(); + String notice = completeTaskBo.getNotice(); + // 获取抄送人 + List flowCopyList = completeTaskBo.getFlowCopyList(); + // 设置抄送人 + Map variables = completeTaskBo.getVariables(); + variables.put(FlowConstant.FLOW_COPY_LIST, flowCopyList); + // 消息类型 + variables.put(FlowConstant.MESSAGE_TYPE, messageType); + // 消息通知 + variables.put(FlowConstant.MESSAGE_NOTICE, notice); - FlowTask flowTask = flowTaskMapper.selectById(taskId); - if (ObjectUtil.isNull(flowTask)) { - throw new ServiceException("流程任务不存在或任务已审批!"); - } - Instance ins = insService.getById(flowTask.getInstanceId()); - // 检查流程状态是否为草稿、已撤销或已退回状态,若是则执行流程提交监听 - if (BusinessStatusEnum.isDraftOrCancelOrBack(ins.getFlowStatus())) { - variables.put(FlowConstant.SUBMIT, true); - } - // 设置弹窗处理人 - Map assigneeMap = setPopAssigneeMap(completeTaskBo.getAssigneeMap(), ins.getVariableMap()); - if (CollUtil.isNotEmpty(assigneeMap)) { - variables.putAll(assigneeMap); - } - // 构建流程参数,包括变量、跳转类型、消息、处理人、权限等信息 - FlowParams flowParams = FlowParams.build() - .handler(completeTaskBo.getHandler()) - .variable(variables) - .skipType(SkipType.PASS.getKey()) - .message(completeTaskBo.getMessage()) - .flowStatus(BusinessStatusEnum.WAITING.getStatus()) - .hisStatus(TaskStatusEnum.PASS.getStatus()) - .hisTaskExt(completeTaskBo.getFileId()); - Boolean autoPass = Convert.toBool(variables.getOrDefault(AUTO_PASS, false)); - skipTask(taskId, flowParams, flowTask.getInstanceId(), autoPass); - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); + FlowTask flowTask = flowTaskMapper.selectById(taskId); + if (ObjectUtil.isNull(flowTask)) { + throw new ServiceException("流程任务不存在或任务已审批!"); } + Instance ins = insService.getById(flowTask.getInstanceId()); + // 检查流程状态是否为草稿、已撤销或已退回状态,若是则执行流程提交监听 + if (BusinessStatusEnum.isDraftOrCancelOrBack(ins.getFlowStatus())) { + variables.put(FlowConstant.SUBMIT, true); + } + // 设置弹窗处理人 + Map assigneeMap = setPopAssigneeMap(completeTaskBo.getAssigneeMap(), ins.getVariableMap()); + if (CollUtil.isNotEmpty(assigneeMap)) { + variables.putAll(assigneeMap); + } + // 构建流程参数,包括变量、跳转类型、消息、处理人、权限等信息 + FlowParams flowParams = FlowParams.build() + .handler(completeTaskBo.getHandler()) + .variable(variables) + .ignore(Convert.toBool(variables.getOrDefault(VAR_IGNORE, false))) + .ignoreDepute(Convert.toBool(variables.getOrDefault(VAR_IGNORE_DEPUTE, false))) + .ignoreCooperate(Convert.toBool(variables.getOrDefault(VAR_IGNORE_COOPERATE, false))) + .skipType(SkipType.PASS.getKey()) + .message(completeTaskBo.getMessage()) + .flowStatus(BusinessStatusEnum.WAITING.getStatus()) + .hisStatus(TaskStatusEnum.PASS.getStatus()) + .hisTaskExt(completeTaskBo.getFileId()); + Boolean autoPass = Convert.toBool(variables.getOrDefault(AUTO_PASS, false)); + skipTask(taskId, flowParams, flowTask.getInstanceId(), autoPass); + return true; } /** @@ -305,10 +304,12 @@ public class FlwTaskServiceImpl implements IFlwTaskService { List variableUserIds = Arrays.asList(userIds.split(StringUtils.SEPARATOR)); hashSet.addAll(popUserIds); hashSet.addAll(variableUserIds); - map.put(entry.getKey(), StringUtils.joinComma(hashSet)); + map.put(TaskStatusEnum.PASS.getStatus() + StrUtil.COLON + entry.getKey(), StringUtils.joinComma(hashSet)); + map.put(TaskStatusEnum.BACK.getStatus() + StrUtil.COLON + entry.getKey(), StringUtils.joinComma(hashSet)); } } else { - map.put(entry.getKey(), entry.getValue()); + map.put(TaskStatusEnum.PASS.getStatus() + StrUtil.COLON + entry.getKey(), entry.getValue()); + map.put(TaskStatusEnum.BACK.getStatus() + StrUtil.COLON + entry.getKey(), entry.getValue()); } } return map; @@ -333,7 +334,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService { flowNode.setNodeCode(flowHisTask.getTargetNodeCode()); flowNode.setNodeName(flowHisTask.getTargetNodeName()); //生成新的任务id - long taskId = identifierGenerator.nextId(null).longValue(); + long taskId = IdGeneratorUtil.nextLongId(); task.setId(taskId); task.setNodeName("【抄送】" + task.getNodeName()); Date updateTime = new Date(flowHisTask.getUpdateTime().getTime() - 1000); @@ -447,15 +448,19 @@ public class FlwTaskServiceImpl implements IFlwTaskService { } private QueryWrapper buildQueryWrapper(FlowTaskBo flowTaskBo) { + Map params = flowTaskBo.getParams(); QueryWrapper wrapper = Wrappers.query(); wrapper.like(StringUtils.isNotBlank(flowTaskBo.getNodeName()), "t.node_name", flowTaskBo.getNodeName()); wrapper.like(StringUtils.isNotBlank(flowTaskBo.getFlowName()), "t.flow_name", flowTaskBo.getFlowName()); wrapper.like(StringUtils.isNotBlank(flowTaskBo.getFlowCode()), "t.flow_code", flowTaskBo.getFlowCode()); + wrapper.like(StringUtils.isNotBlank(flowTaskBo.getFlowStatus()), "t.flow_status", flowTaskBo.getFlowStatus()); wrapper.in(CollUtil.isNotEmpty(flowTaskBo.getCreateByIds()), "t.create_by", flowTaskBo.getCreateByIds()); if (StringUtils.isNotBlank(flowTaskBo.getCategory())) { List categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowTaskBo.getCategory())); wrapper.in("t.category", StreamUtils.toList(categoryIds, Convert::toStr)); } + wrapper.between(params.get("beginTime") != null && params.get("endTime") != null, + "t.create_time", params.get("beginTime"), params.get("endTime")); wrapper.orderByDesc("t.create_time").orderByDesc("t.update_time"); return wrapper; } @@ -468,40 +473,35 @@ public class FlwTaskServiceImpl implements IFlwTaskService { @Override @Transactional(rollbackFor = Exception.class) public boolean backProcess(BackProcessBo bo) { - try { - Long taskId = bo.getTaskId(); - String notice = bo.getNotice(); - List messageType = bo.getMessageType(); - String message = bo.getMessage(); - FlowTask task = flowTaskMapper.selectById(taskId); - if (ObjectUtil.isNull(task)) { - throw new ServiceException("任务不存在!"); - } - Instance inst = insService.getById(task.getInstanceId()); - 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(FlowConstant.MESSAGE_NOTICE, notice); - - FlowParams flowParams = FlowParams.build() - .nodeCode(bo.getNodeCode()) - .variable(variable) - .message(message) - .skipType(SkipType.REJECT.getKey()) - .flowStatus(applyNodeCode.equals(bo.getNodeCode()) ? TaskStatusEnum.BACK.getStatus() : TaskStatusEnum.WAITING.getStatus()) - .hisStatus(TaskStatusEnum.BACK.getStatus()) - .hisTaskExt(bo.getFileId()); - taskService.skip(task.getId(), flowParams); - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); + Long taskId = bo.getTaskId(); + String notice = bo.getNotice(); + List messageType = bo.getMessageType(); + String message = bo.getMessage(); + FlowTask task = flowTaskMapper.selectById(taskId); + if (ObjectUtil.isNull(task)) { + throw new ServiceException("任务不存在!"); } + Instance inst = insService.getById(task.getInstanceId()); + 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(FlowConstant.MESSAGE_NOTICE, notice); + + FlowParams flowParams = FlowParams.build() + .nodeCode(bo.getNodeCode()) + .variable(variable) + .message(message) + .skipType(SkipType.REJECT.getKey()) + .flowStatus(applyNodeCode.equals(bo.getNodeCode()) ? TaskStatusEnum.BACK.getStatus() : TaskStatusEnum.WAITING.getStatus()) + .hisStatus(TaskStatusEnum.BACK.getStatus()) + .hisTaskExt(bo.getFileId()); + taskService.skip(task.getId(), flowParams); + return true; } /** @@ -529,8 +529,22 @@ public class FlwTaskServiceImpl implements IFlwTaskService { } //获取可驳回的前置节点 List nodes = nodeService.previousNodeList(task.getDefinitionId(), nowNodeCode); - if (CollUtil.isNotEmpty(nodes)) { - return StreamUtils.filter(nodes, e -> NodeType.BETWEEN.getKey().equals(e.getNodeType())); + List hisTaskList = hisTaskService.getByInsId(task.getInstanceId()); + + Map nodeMap = StreamUtils.toIdentityMap(nodes, Node::getNodeCode); + Set added = new HashSet<>(); + List backNodeList = new ArrayList<>(); + for (HisTask hisTask : hisTaskList) { + Node nodeValue = nodeMap.get(hisTask.getNodeCode()); + if (nodeValue != null + && NodeType.BETWEEN.getKey().equals(nodeValue.getNodeType()) + && added.add(nodeValue.getNodeCode())) { + backNodeList.add(nodeValue); + } + } + if (CollUtil.isNotEmpty(backNodeList)) { + Collections.reverse(backNodeList); + return backNodeList; } return nodes; } @@ -543,26 +557,21 @@ public class FlwTaskServiceImpl implements IFlwTaskService { @Override @Transactional(rollbackFor = Exception.class) public boolean terminationTask(FlowTerminationBo bo) { - try { - Long taskId = bo.getTaskId(); - Task task = taskService.getById(taskId); - if (task == null) { - throw new ServiceException("任务不存在!"); - } - Instance instance = insService.getById(task.getInstanceId()); - if (ObjectUtil.isNotNull(instance)) { - BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus()); - } - FlowParams flowParams = FlowParams.build() - .message(bo.getComment()) - .flowStatus(BusinessStatusEnum.TERMINATION.getStatus()) - .hisStatus(TaskStatusEnum.TERMINATION.getStatus()); - taskService.termination(taskId, flowParams); - return true; - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); + Long taskId = bo.getTaskId(); + Task task = taskService.getById(taskId); + if (task == null) { + throw new ServiceException("任务不存在!"); } + Instance instance = insService.getById(task.getInstanceId()); + if (ObjectUtil.isNotNull(instance)) { + BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus()); + } + FlowParams flowParams = FlowParams.build() + .message(bo.getComment()) + .flowStatus(BusinessStatusEnum.TERMINATION.getStatus()) + .hisStatus(TaskStatusEnum.TERMINATION.getStatus()); + taskService.termination(taskId, flowParams); + return true; } /** @@ -739,8 +748,8 @@ public class FlwTaskServiceImpl implements IFlwTaskService { Task task = taskService.getById(taskId); FlowNode flowNode = getByNodeCode(task.getNodeCode(), task.getDefinitionId()); if (ADD_SIGNATURE.equals(taskOperation) || REDUCTION_SIGNATURE.equals(taskOperation)) { - if (flowNode.getNodeRatio().compareTo(BigDecimal.ZERO) == 0) { - throw new ServiceException(task.getNodeName() + "不是会签节点!"); + if (CooperateType.isOrSign(flowNode.getNodeRatio())) { + throw new ServiceException(task.getNodeName() + "不是会签或票签节点!"); } } // 设置任务状态并执行对应的任务操作 @@ -784,23 +793,18 @@ public class FlwTaskServiceImpl implements IFlwTaskService { if (CollUtil.isEmpty(taskIdList)) { return false; } - try { - List flowTasks = this.selectByIdList(taskIdList); - // 批量删除现有任务的办理人记录 - if (CollUtil.isNotEmpty(flowTasks)) { - FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTasks, FlowTask::getId)); - List userList = StreamUtils.toList(flowTasks, flowTask -> - new FlowUser() - .setType(TaskAssigneeType.APPROVER.getCode()) - .setProcessedBy(userId) - .setAssociated(flowTask.getId())); - if (CollUtil.isNotEmpty(userList)) { - FlowEngine.userService().saveBatch(userList); - } + List flowTasks = this.selectByIdList(taskIdList); + // 批量删除现有任务的办理人记录 + if (CollUtil.isNotEmpty(flowTasks)) { + FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTasks, FlowTask::getId)); + List userList = StreamUtils.toList(flowTasks, flowTask -> + new FlowUser() + .setType(TaskAssigneeType.APPROVER.getCode()) + .setProcessedBy(userId) + .setAssociated(flowTask.getId())); + if (CollUtil.isNotEmpty(userList)) { + FlowEngine.userService().saveBatch(userList); } - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); } return true; } @@ -840,21 +844,16 @@ public class FlwTaskServiceImpl implements IFlwTaskService { */ @Override public boolean urgeTask(FlowUrgeTaskBo bo) { - try { - if (CollUtil.isEmpty(bo.getTaskIdList())) { - return false; - } - List userList = this.currentTaskAllUser(bo.getTaskIdList()); - if (CollUtil.isEmpty(userList)) { - return false; - } - List messageType = bo.getMessageType(); - String message = bo.getMessage(); - flwCommonService.sendMessage(messageType, message, "单据审批提醒", userList); - } catch (Exception e) { - log.error(e.getMessage(), e); - throw new ServiceException(e.getMessage()); + if (CollUtil.isEmpty(bo.getTaskIdList())) { + return false; } + List userList = this.currentTaskAllUser(bo.getTaskIdList()); + if (CollUtil.isEmpty(userList)) { + return false; + } + List messageType = bo.getMessageType(); + String message = bo.getMessage(); + flwCommonService.sendMessage(messageType, message, "单据审批提醒", userList); return true; } } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java index ae11d18e9..ec0be3ce4 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java @@ -18,6 +18,7 @@ import org.dromara.common.core.enums.BusinessStatusEnum; import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.service.WorkflowService; import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StreamUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mybatis.core.domain.BaseEntity; import org.dromara.common.mybatis.core.page.PageQuery; @@ -167,7 +168,7 @@ public class TestLeaveServiceImpl implements ITestLeaveService { @Override @Transactional(rollbackFor = Exception.class) public Boolean deleteWithValidByIds(List ids) { - workflowService.deleteInstance(ids); + workflowService.deleteInstance(StreamUtils.toList(ids, Convert::toStr)); return baseMapper.deleteByIds(ids) > 0; } @@ -199,7 +200,10 @@ public class TestLeaveServiceImpl implements ITestLeaveService { testLeave.setApplyCode(businessCode); } testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus()); + log.info("申请人提交"); } + String status = BusinessStatusEnum.findByStatus(processEvent.getStatus()); + log.info("当前流程状态为{}", status); baseMapper.updateById(testLeave); } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java index 8f8314060..8d6b8d211 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java @@ -6,7 +6,6 @@ import lombok.RequiredArgsConstructor; import org.dromara.common.core.domain.dto.CompleteTaskDTO; import org.dromara.common.core.domain.dto.StartProcessDTO; import org.dromara.common.core.domain.dto.StartProcessReturnDTO; -import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.service.WorkflowService; import org.dromara.common.core.utils.StringUtils; import org.dromara.warm.flow.orm.entity.FlowInstance; @@ -46,7 +45,7 @@ public class WorkflowServiceImpl implements WorkflowService { * @return 结果 */ @Override - public boolean deleteInstance(List businessIds) { + public boolean deleteInstance(List businessIds) { return flwInstanceService.deleteByBusinessIds(businessIds); } @@ -161,28 +160,19 @@ public class WorkflowServiceImpl implements WorkflowService { @Override @Transactional(rollbackFor = Exception.class) public boolean startCompleteTask(StartProcessDTO startProcess) { - try { - StartProcessBo processBo = new StartProcessBo(); - processBo.setBusinessId(startProcess.getBusinessId()); - processBo.setFlowCode(startProcess.getFlowCode()); - processBo.setVariables(startProcess.getVariables()); - processBo.setHandler(startProcess.getHandler()); - processBo.setBizExt(BeanUtil.toBean(startProcess.getBizExt(), FlowInstanceBizExt.class)); + StartProcessBo processBo = new StartProcessBo(); + processBo.setBusinessId(startProcess.getBusinessId()); + processBo.setFlowCode(startProcess.getFlowCode()); + processBo.setVariables(startProcess.getVariables()); + processBo.setHandler(startProcess.getHandler()); + processBo.setBizExt(BeanUtil.toBean(startProcess.getBizExt(), FlowInstanceBizExt.class)); - StartProcessReturnDTO result = flwTaskService.startWorkFlow(processBo); - CompleteTaskBo taskBo = new CompleteTaskBo(); - taskBo.setTaskId(result.getTaskId()); - taskBo.setMessageType(Collections.singletonList(MessageTypeEnum.SYSTEM_MESSAGE.getCode())); - taskBo.setVariables(startProcess.getVariables()); - taskBo.setHandler(startProcess.getHandler()); - - boolean flag = flwTaskService.completeTask(taskBo); - if (!flag) { - throw new ServiceException("流程发起异常"); - } - return true; - } catch (Exception e) { - throw new ServiceException(e.getMessage()); - } + StartProcessReturnDTO result = flwTaskService.startWorkFlow(processBo); + CompleteTaskBo taskBo = new CompleteTaskBo(); + taskBo.setTaskId(result.getTaskId()); + taskBo.setMessageType(Collections.singletonList(MessageTypeEnum.SYSTEM_MESSAGE.getCode())); + taskBo.setVariables(startProcess.getVariables()); + taskBo.setHandler(startProcess.getHandler()); + return flwTaskService.completeTask(taskBo); } } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml index c19992847..ead3d0759 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml @@ -27,7 +27,10 @@ d.flow_code, d.form_custom, d.category, - COALESCE(t.form_path, d.form_path) as form_path, + COALESCE( + NULLIF(TRIM(t.form_path), ''), + NULLIF(TRIM(d.form_path), '') + ) AS form_path, d.version, uu.processed_by, uu.type, diff --git a/script/docker/docker-compose.yml b/script/docker/docker-compose.yml index fd5f476a1..462650bd5 100644 --- a/script/docker/docker-compose.yml +++ b/script/docker/docker-compose.yml @@ -99,7 +99,7 @@ services: network_mode: "host" ruoyi-server1: - image: ruoyi/ruoyi-server:5.5.1 + image: ruoyi/ruoyi-server:5.5.2 container_name: ruoyi-server1 environment: # 时区上海 @@ -115,7 +115,7 @@ services: network_mode: "host" ruoyi-server2: - image: ruoyi/ruoyi-server:5.5.1 + image: ruoyi/ruoyi-server:5.5.2 container_name: ruoyi-server2 environment: # 时区上海 @@ -131,7 +131,7 @@ services: network_mode: "host" ruoyi-monitor-admin: - image: ruoyi/ruoyi-monitor-admin:5.5.1 + image: ruoyi/ruoyi-monitor-admin:5.5.2 container_name: ruoyi-monitor-admin environment: # 时区上海 @@ -143,7 +143,7 @@ services: network_mode: "host" ruoyi-snailjob-server: - image: ruoyi/ruoyi-snailjob-server:5.5.1 + image: ruoyi/ruoyi-snailjob-server:5.5.2 container_name: ruoyi-snailjob-server environment: # 时区上海 diff --git a/script/docker/nginx/conf/nginx.conf b/script/docker/nginx/conf/nginx.conf index 3cab30025..0a5cb7b43 100644 --- a/script/docker/nginx/conf/nginx.conf +++ b/script/docker/nginx/conf/nginx.conf @@ -106,11 +106,6 @@ http { proxy_buffering off; # 禁用代理缓存 proxy_cache off; - # 按 IP 限制连接数(防 CC 攻击) 小型站:10~20 就够 中型站:50~100 - limit_conn perip 20; - - # 按 Server 限制总并发连接数 根据服务器的最大并发处理能力来定 太小会限制合法用户访问,太大会占满服务器资源 - limit_conn perserver 500; proxy_pass http://server/; } diff --git a/script/sql/oracle/oracle_ry_job.sql b/script/sql/oracle/oracle_ry_job.sql index 84d31ec02..2a7f11f9a 100644 --- a/script/sql/oracle/oracle_ry_job.sql +++ b/script/sql/oracle/oracle_ry_job.sql @@ -738,7 +738,7 @@ CREATE TABLE sj_retry_summary id number GENERATED ALWAYS AS IDENTITY, namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, group_name varchar2(64) DEFAULT '' NULL, - scene_name varchar2(50) DEFAULT '' NULL, + scene_name varchar2(64) DEFAULT '' NULL, trigger_at date DEFAULT CURRENT_TIMESTAMP NOT NULL, running_num number DEFAULT 0 NOT NULL, finish_num number DEFAULT 0 NOT NULL, diff --git a/script/sql/oracle/oracle_ry_workflow.sql b/script/sql/oracle/oracle_ry_workflow.sql index 3130f325c..7f5ab22fa 100644 --- a/script/sql/oracle/oracle_ry_workflow.sql +++ b/script/sql/oracle/oracle_ry_workflow.sql @@ -55,13 +55,12 @@ create table FLOW_NODE DEFINITION_ID NUMBER(20) not null, NODE_CODE VARCHAR2(100) not null, NODE_NAME VARCHAR2(100), - NODE_RATIO NUMBER(6, 3), + PERMISSION_FLAG VARCHAR2(200), + NODE_RATIO VARCHAR2(200), COORDINATE VARCHAR2(100), ANY_NODE_SKIP VARCHAR2(100), LISTENER_TYPE VARCHAR2(100), LISTENER_PATH VARCHAR2(500), - HANDLER_TYPE VARCHAR2(100), - HANDLER_PATH VARCHAR2(400), FORM_CUSTOM VARCHAR2(1) default 'N', FORM_PATH VARCHAR2(100), VERSION VARCHAR2(20), @@ -71,8 +70,7 @@ create table FLOW_NODE UPDATE_BY VARCHAR2(64) default '', EXT CLOB, DEL_FLAG VARCHAR2(1) default '0', - TENANT_ID VARCHAR2(40), - PERMISSION_FLAG VARCHAR2(200) + TENANT_ID VARCHAR2(40) ); alter table FLOW_NODE @@ -89,8 +87,6 @@ comment on column FLOW_NODE.COORDINATE is '坐标'; comment on column FLOW_NODE.ANY_NODE_SKIP is '任意结点跳转'; comment on column FLOW_NODE.LISTENER_TYPE is '监听器类型'; comment on column FLOW_NODE.LISTENER_PATH is '监听器路径'; -comment on column FLOW_NODE.HANDLER_TYPE is '处理器类型'; -comment on column FLOW_NODE.HANDLER_PATH is '处理器路径'; comment on column FLOW_NODE.FORM_CUSTOM is '审批表单是否自定义 (Y是 N否)'; comment on column FLOW_NODE.FORM_PATH is '审批表单路径'; comment on column FLOW_NODE.VERSION is '版本'; @@ -493,11 +489,11 @@ INSERT INTO sys_menu VALUES ('11626', '流程分类删除', '11622', '4', '#', ' 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 ('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, ''); -INSERT INTO sys_menu VALUES ('11804', '流程spel达式定义修改', '11801', 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:edit', '#', 103, 1, SYSDATE, NULL, NULL, ''); -INSERT INTO sys_menu VALUES ('11805', '流程spel达式定义删除', '11801', 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:remove', '#', 103, 1, SYSDATE, NULL, NULL, ''); -INSERT INTO sys_menu VALUES ('11806', '流程spel达式定义导出', '11801', 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:export', '#', 103, 1, SYSDATE, NULL, NULL, ''); +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, ''); +INSERT INTO sys_menu VALUES ('11804', '流程spel表达式定义修改', '11801', 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:edit', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11805', '流程spel表达式定义删除', '11801', 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:remove', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11806', '流程spel表达式定义导出', '11801', 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:export', '#', 103, 1, SYSDATE, NULL, NULL, ''); INSERT INTO sys_menu VALUES ('11638', '请假申请', '5', '1', 'leave', 'workflow/leave/index', '', '1', '0', 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, SYSDATE, NULL, NULL, '请假申请菜单'); INSERT INTO sys_menu VALUES ('11639', '请假申请查询', '11638', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, SYSDATE, NULL, NULL, ''); diff --git a/script/sql/postgres/postgres_ry_job.sql b/script/sql/postgres/postgres_ry_job.sql index 8cd32a850..9980c3b43 100644 --- a/script/sql/postgres/postgres_ry_job.sql +++ b/script/sql/postgres/postgres_ry_job.sql @@ -684,7 +684,7 @@ CREATE TABLE sj_retry_summary id bigserial PRIMARY KEY, namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', group_name varchar(64) NOT NULL DEFAULT '', - scene_name varchar(50) NOT NULL DEFAULT '', + scene_name varchar(64) NOT NULL DEFAULT '', trigger_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, running_num int NOT NULL DEFAULT 0, finish_num int NOT NULL DEFAULT 0, diff --git a/script/sql/postgres/postgres_ry_workflow.sql b/script/sql/postgres/postgres_ry_workflow.sql index 370f526eb..d6f30dfd2 100644 --- a/script/sql/postgres/postgres_ry_workflow.sql +++ b/script/sql/postgres/postgres_ry_workflow.sql @@ -51,13 +51,11 @@ CREATE TABLE flow_node node_code varchar(100) NOT NULL, node_name varchar(100) NULL, permission_flag varchar(200) NULL, - node_ratio numeric(6, 3) NULL, + node_ratio varchar(200) NULL, coordinate varchar(100) NULL, any_node_skip varchar(100) NULL, listener_type varchar(100) NULL, listener_path varchar(400) NULL, - handler_type varchar(100) NULL, - handler_path varchar(400) NULL, form_custom bpchar(1) NULL DEFAULT 'N':: character varying, form_path varchar(100) NULL, "version" varchar(20) NOT NULL, @@ -83,8 +81,6 @@ COMMENT ON COLUMN flow_node.coordinate IS '坐标'; COMMENT ON COLUMN flow_node.any_node_skip IS '任意结点跳转'; COMMENT ON COLUMN flow_node.listener_type IS '监听器类型'; COMMENT ON COLUMN flow_node.listener_path IS '监听器路径'; -COMMENT ON COLUMN flow_node.handler_type IS '处理器类型'; -COMMENT ON COLUMN flow_node.handler_path IS '处理器路径'; COMMENT ON COLUMN flow_node.form_custom IS '审批表单是否自定义(Y是 N否)'; COMMENT ON COLUMN flow_node.form_path IS '审批表单路径'; COMMENT ON COLUMN flow_node."version" IS '版本'; @@ -471,11 +467,11 @@ INSERT INTO sys_menu VALUES ('11626', '流程分类删除', '11622', '4', '#', ' 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 ('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, ''); -INSERT INTO sys_menu VALUES ('11804', '流程spel达式定义修改', '11801', 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:edit', '#', 103, 1, now(), NULL, NULL, ''); -INSERT INTO sys_menu VALUES ('11805', '流程spel达式定义删除', '11801', 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:remove', '#', 103, 1, now(), NULL, NULL, ''); -INSERT INTO sys_menu VALUES ('11806', '流程spel达式定义导出', '11801', 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:export', '#', 103, 1, now(), NULL, NULL, ''); +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, ''); +INSERT INTO sys_menu VALUES ('11804', '流程spel表达式定义修改', '11801', 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:edit', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11805', '流程spel表达式定义删除', '11801', 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:remove', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11806', '流程spel表达式定义导出', '11801', 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:export', '#', 103, 1, now(), NULL, NULL, ''); INSERT INTO sys_menu VALUES ('11638', '请假申请', '5', '1', 'leave', 'workflow/leave/index', '', '1', '0', 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, now(), NULL, NULL, '请假申请菜单'); INSERT INTO sys_menu VALUES ('11639', '请假申请查询', '11638', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, now(), NULL, NULL, ''); diff --git a/script/sql/ry_job.sql b/script/sql/ry_job.sql index 1e75571d1..dd8124cf5 100644 --- a/script/sql/ry_job.sql +++ b/script/sql/ry_job.sql @@ -423,7 +423,7 @@ CREATE TABLE `sj_retry_summary` `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', `namespace_id` VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', `group_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '组名称', - `scene_name` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '场景名称', + `scene_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '场景名称', `trigger_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '统计时间', `running_num` int NOT NULL DEFAULT 0 COMMENT '重试中-日志数量', `finish_num` int NOT NULL DEFAULT 0 COMMENT '重试完成-日志数量', diff --git a/script/sql/ry_workflow.sql b/script/sql/ry_workflow.sql index f79a1667f..c911a5bd1 100644 --- a/script/sql/ry_workflow.sql +++ b/script/sql/ry_workflow.sql @@ -33,13 +33,11 @@ CREATE TABLE `flow_node` `node_code` varchar(100) NOT NULL COMMENT '流程节点编码', `node_name` varchar(100) DEFAULT NULL COMMENT '流程节点名称', `permission_flag` varchar(200) DEFAULT NULL COMMENT '权限标识(权限类型:权限标识,可以多个,用@@隔开)', - `node_ratio` decimal(6, 3) DEFAULT NULL COMMENT '流程签署比例值', + `node_ratio` varchar(200) DEFAULT NULL COMMENT '流程签署比例值', `coordinate` varchar(100) DEFAULT NULL COMMENT '坐标', `any_node_skip` varchar(100) DEFAULT NULL COMMENT '任意结点跳转', `listener_type` varchar(100) DEFAULT NULL COMMENT '监听器类型', `listener_path` varchar(400) DEFAULT NULL COMMENT '监听器路径', - `handler_type` varchar(100) DEFAULT NULL COMMENT '处理器类型', - `handler_path` varchar(400) DEFAULT NULL COMMENT '处理器路径', `form_custom` char(1) DEFAULT 'N' COMMENT '审批表单是否自定义(Y是 N否)', `form_path` varchar(100) DEFAULT NULL COMMENT '审批表单路径', `version` varchar(20) NOT NULL COMMENT '版本', diff --git a/script/sql/sqlserver/sqlserver_ry_job.sql b/script/sql/sqlserver/sqlserver_ry_job.sql index 48451d039..ceb8c459b 100644 --- a/script/sql/sqlserver/sqlserver_ry_job.sql +++ b/script/sql/sqlserver/sqlserver_ry_job.sql @@ -2248,7 +2248,7 @@ CREATE TABLE sj_retry_summary id bigint NOT NULL PRIMARY KEY IDENTITY, namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', group_name nvarchar(64) NOT NULL DEFAULT '', - scene_name nvarchar(50) NOT NULL DEFAULT '', + scene_name nvarchar(64) NOT NULL DEFAULT '', trigger_at datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, running_num int NOT NULL DEFAULT 0, finish_num int NOT NULL DEFAULT 0, diff --git a/script/sql/sqlserver/sqlserver_ry_workflow.sql b/script/sql/sqlserver/sqlserver_ry_workflow.sql index f187e3879..09a661fbd 100644 --- a/script/sql/sqlserver/sqlserver_ry_workflow.sql +++ b/script/sql/sqlserver/sqlserver_ry_workflow.sql @@ -174,13 +174,11 @@ CREATE TABLE flow_node ( node_code nvarchar(100) NOT NULL, node_name nvarchar(100) NULL, permission_flag nvarchar(200) NULL, - node_ratio decimal(6,3) NULL, + node_ratio nvarchar(200) NULL, coordinate nvarchar(100) NULL, any_node_skip nvarchar(100) NULL, listener_type nvarchar(100) NULL, listener_path nvarchar(400) NULL, - handler_type nvarchar(100) NULL, - handler_path nvarchar(400) NULL, form_custom nchar(1) DEFAULT('N') NULL, form_path nvarchar(100) NULL, version nvarchar(20) NOT NULL, @@ -275,20 +273,6 @@ EXEC sp_addextendedproperty 'COLUMN', N'listener_path' GO -EXEC sp_addextendedproperty -'MS_Description', N'处理器类型', -'SCHEMA', N'dbo', -'TABLE', N'flow_node', -'COLUMN', N'handler_type' -GO - -EXEC sp_addextendedproperty -'MS_Description', N'处理器路径', -'SCHEMA', N'dbo', -'TABLE', N'flow_node', -'COLUMN', N'handler_path' -GO - EXEC sp_addextendedproperty 'MS_Description', N'审批表单是否自定义(Y是 N否)', 'SCHEMA', N'dbo', @@ -1261,7 +1245,7 @@ EXEC sp_addextendedproperty 'COLUMN', N'component_name' GO --- method_name 字段注释 +EXEC sp_addextendedproperty 'MS_Description', N'方法名', 'SCHEMA', N'dbo', 'TABLE', N'flow_spel', @@ -1618,15 +1602,15 @@ 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''); +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''); GO -INSERT sys_menu VALUES (11803, N'流程spel达式定义新增', N'11801', 2, N'#', N'', NULL, 1, 0, N'F', N'0', N'0', N'workflow:spel:add', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +INSERT sys_menu VALUES (11803, N'流程spel表达式定义新增', N'11801', 2, N'#', N'', NULL, 1, 0, N'F', N'0', N'0', N'workflow:spel:add', N'#', 103, 1, GETDATE(), NULL, NULL, N''); GO -INSERT sys_menu VALUES (11804, N'流程spel达式定义修改', N'11801', 3, N'#', N'', NULL, 1, 0, N'F', N'0', N'0', N'workflow:spel:edit', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +INSERT sys_menu VALUES (11804, N'流程spel表达式定义修改', N'11801', 3, N'#', N'', NULL, 1, 0, N'F', N'0', N'0', N'workflow:spel:edit', N'#', 103, 1, GETDATE(), NULL, NULL, N''); GO -INSERT sys_menu VALUES (11805, N'流程spel达式定义删除', N'11801', 4, N'#', N'', NULL, 1, 0, N'F', N'0', N'0', N'workflow:spel:remove', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +INSERT sys_menu VALUES (11805, N'流程spel表达式定义删除', N'11801', 4, N'#', N'', NULL, 1, 0, N'F', N'0', N'0', N'workflow:spel:remove', N'#', 103, 1, GETDATE(), NULL, NULL, N''); GO -INSERT sys_menu VALUES (11806, N'流程spel达式定义导出', N'11801', 5, N'#', N'', NULL, 1, 0, N'F', N'0', N'0', N'workflow:spel:export', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +INSERT sys_menu VALUES (11806, N'流程spel表达式定义导出', N'11801', 5, N'#', N'', NULL, 1, 0, N'F', N'0', N'0', N'workflow:spel:export', N'#', 103, 1, GETDATE(), NULL, NULL, N''); GO -- 请假测试相关按钮 diff --git a/script/sql/update/oracle/update_5.4.1-5.5.0.sql b/script/sql/update/oracle/update_5.4.1-5.5.0.sql index c4fe2a2f7..455501ffe 100644 --- a/script/sql/update/oracle/update_5.4.1-5.5.0.sql +++ b/script/sql/update/oracle/update_5.4.1-5.5.0.sql @@ -38,11 +38,11 @@ INSERT INTO flow_spel VALUES (1, 'spelRuleComponent', 'selectDeptLeaderById', 'i INSERT INTO flow_spel VALUES (2, NULL, NULL, 'initiator', '${initiator}', '流程发起人', '0', '0', 103, 1, SYSDATE, 1, SYSDATE); 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, ''); -INSERT INTO sys_menu VALUES ('11804', '流程spel达式定义修改', '11801', 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:edit', '#', 103, 1, SYSDATE, NULL, NULL, ''); -INSERT INTO sys_menu VALUES ('11805', '流程spel达式定义删除', '11801', 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:remove', '#', 103, 1, SYSDATE, NULL, NULL, ''); -INSERT INTO sys_menu VALUES ('11806', '流程spel达式定义导出', '11801', 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:export', '#', 103, 1, SYSDATE, NULL, NULL, ''); +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, ''); +INSERT INTO sys_menu VALUES ('11804', '流程spel表达式定义修改', '11801', 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:edit', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11805', '流程spel表达式定义删除', '11801', 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:remove', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11806', '流程spel表达式定义导出', '11801', 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:export', '#', 103, 1, SYSDATE, NULL, NULL, ''); ALTER TABLE flow_definition ADD model_value VARCHAR2(40) DEFAULT 'CLASSICS' NOT NULL; COMMENT ON COLUMN flow_definition.model_value IS '设计器模式(CLASSICS经典模式 MIMIC仿钉钉模式)'; diff --git a/script/sql/update/oracle/update_5.5.1-5.5.2.sql b/script/sql/update/oracle/update_5.5.1-5.5.2.sql new file mode 100644 index 000000000..17600d6b9 --- /dev/null +++ b/script/sql/update/oracle/update_5.5.1-5.5.2.sql @@ -0,0 +1,4 @@ +ALTER TABLE flow_node MODIFY (node_ratio VARCHAR2(200) DEFAULT NULL NULL); +COMMENT ON COLUMN flow_node.node_ratio IS '流程签署比例值'; +ALTER TABLE flow_node DROP COLUMN handler_type; +ALTER TABLE flow_node DROP COLUMN handler_path; diff --git a/script/sql/update/postgres/update_5.4.1-5.5.0.sql b/script/sql/update/postgres/update_5.4.1-5.5.0.sql index 46e960509..0bc80b4f6 100644 --- a/script/sql/update/postgres/update_5.4.1-5.5.0.sql +++ b/script/sql/update/postgres/update_5.4.1-5.5.0.sql @@ -37,11 +37,11 @@ INSERT INTO flow_spel VALUES (1, 'spelRuleComponent', 'selectDeptLeaderById', 'i INSERT INTO flow_spel VALUES (2, NULL, NULL, 'initiator', '${initiator}', '流程发起人', '0', '0', 103, 1, now(), 1, now()); 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, ''); -INSERT INTO sys_menu VALUES ('11804', '流程spel达式定义修改', '11801', 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:edit', '#', 103, 1, now(), NULL, NULL, ''); -INSERT INTO sys_menu VALUES ('11805', '流程spel达式定义删除', '11801', 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:remove', '#', 103, 1, now(), NULL, NULL, ''); -INSERT INTO sys_menu VALUES ('11806', '流程spel达式定义导出', '11801', 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:export', '#', 103, 1, now(), NULL, NULL, ''); +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, ''); +INSERT INTO sys_menu VALUES ('11804', '流程spel表达式定义修改', '11801', 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:edit', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11805', '流程spel表达式定义删除', '11801', 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:remove', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11806', '流程spel表达式定义导出', '11801', 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:export', '#', 103, 1, now(), NULL, NULL, ''); ALTER TABLE flow_definition ADD COLUMN model_value VARCHAR(40) NOT NULL DEFAULT 'CLASSICS'; COMMENT ON COLUMN flow_definition.model_value IS '设计器模式(CLASSICS经典模式 MIMIC仿钉钉模式)'; diff --git a/script/sql/update/postgres/update_5.5.0-5.5.1.sql b/script/sql/update/postgres/update_5.5.0-5.5.1.sql index 8fa28c007..f1449f0f6 100644 --- a/script/sql/update/postgres/update_5.5.0-5.5.1.sql +++ b/script/sql/update/postgres/update_5.5.0-5.5.1.sql @@ -1,25 +1,25 @@ -ALTER TABLE flow_definition ADD create_by VARCHAR2(64) DEFAULT '' NOT NULL; -ALTER TABLE flow_definition ADD update_by VARCHAR2(64) DEFAULT '' NOT NULL; +ALTER TABLE flow_definition ADD create_by VARCHAR(64) DEFAULT '' NOT NULL; +ALTER TABLE flow_definition ADD update_by VARCHAR(64) DEFAULT '' NOT NULL; COMMENT ON COLUMN flow_definition.create_by IS '创建人'; COMMENT ON COLUMN flow_definition.update_by IS '更新人'; -ALTER TABLE flow_node ADD create_by VARCHAR2(64) DEFAULT '' NOT NULL; -ALTER TABLE flow_node ADD update_by VARCHAR2(64) DEFAULT '' NOT NULL; +ALTER TABLE flow_node ADD create_by VARCHAR(64) DEFAULT '' NOT NULL; +ALTER TABLE flow_node ADD update_by VARCHAR(64) DEFAULT '' NOT NULL; COMMENT ON COLUMN flow_node.create_by IS '创建人'; COMMENT ON COLUMN flow_node.update_by IS '更新人'; -ALTER TABLE flow_skip ADD create_by VARCHAR2(64) DEFAULT '' NOT NULL; -ALTER TABLE flow_skip ADD update_by VARCHAR2(64) DEFAULT '' NOT NULL; +ALTER TABLE flow_skip ADD create_by VARCHAR(64) DEFAULT '' NOT NULL; +ALTER TABLE flow_skip ADD update_by VARCHAR(64) DEFAULT '' NOT NULL; COMMENT ON COLUMN flow_skip.create_by IS '创建人'; COMMENT ON COLUMN flow_skip.update_by IS '更新人'; -ALTER TABLE flow_instance ADD update_by VARCHAR2(64) DEFAULT '' NOT NULL; +ALTER TABLE flow_instance ADD update_by VARCHAR(64) DEFAULT '' NOT NULL; COMMENT ON COLUMN flow_instance.update_by IS '更新人'; -ALTER TABLE flow_task ADD create_by VARCHAR2(64) DEFAULT '' NOT NULL; -ALTER TABLE flow_task ADD update_by VARCHAR2(64) DEFAULT '' NOT NULL; +ALTER TABLE flow_task ADD create_by VARCHAR(64) DEFAULT '' NOT NULL; +ALTER TABLE flow_task ADD update_by VARCHAR(64) DEFAULT '' NOT NULL; COMMENT ON COLUMN flow_task.create_by IS '创建人'; COMMENT ON COLUMN flow_task.update_by IS '更新人'; -ALTER TABLE flow_user ADD update_by VARCHAR2(64) DEFAULT '' NOT NULL; +ALTER TABLE flow_user ADD update_by VARCHAR(64) DEFAULT '' NOT NULL; COMMENT ON COLUMN flow_user.update_by IS '更新人'; diff --git a/script/sql/update/postgres/update_5.5.1-5.5.2.sql b/script/sql/update/postgres/update_5.5.1-5.5.2.sql new file mode 100644 index 000000000..bf2d69f84 --- /dev/null +++ b/script/sql/update/postgres/update_5.5.1-5.5.2.sql @@ -0,0 +1,6 @@ +ALTER TABLE flow_node + ALTER COLUMN node_ratio TYPE VARCHAR(200), + ALTER COLUMN node_ratio DROP NOT NULL; +COMMENT ON COLUMN flow_node.node_ratio IS '流程签署比例值'; +ALTER TABLE flow_node DROP COLUMN handler_type; +ALTER TABLE flow_node DROP COLUMN handler_path; diff --git a/script/sql/update/sqlserver/update_5.4.1-5.5.0.sql b/script/sql/update/sqlserver/update_5.4.1-5.5.0.sql index c2cc1b5b3..ce6b6ddf5 100644 --- a/script/sql/update/sqlserver/update_5.4.1-5.5.0.sql +++ b/script/sql/update/sqlserver/update_5.4.1-5.5.0.sql @@ -123,15 +123,15 @@ 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''); +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''); GO -INSERT sys_menu VALUES (11803, N'流程spel达式定义新增', N'11801', 2, N'#', N'', NULL, 1, 0, N'F', N'0', N'0', N'workflow:spel:add', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +INSERT sys_menu VALUES (11803, N'流程spel表达式定义新增', N'11801', 2, N'#', N'', NULL, 1, 0, N'F', N'0', N'0', N'workflow:spel:add', N'#', 103, 1, GETDATE(), NULL, NULL, N''); GO -INSERT sys_menu VALUES (11804, N'流程spel达式定义修改', N'11801', 3, N'#', N'', NULL, 1, 0, N'F', N'0', N'0', N'workflow:spel:edit', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +INSERT sys_menu VALUES (11804, N'流程spel表达式定义修改', N'11801', 3, N'#', N'', NULL, 1, 0, N'F', N'0', N'0', N'workflow:spel:edit', N'#', 103, 1, GETDATE(), NULL, NULL, N''); GO -INSERT sys_menu VALUES (11805, N'流程spel达式定义删除', N'11801', 4, N'#', N'', NULL, 1, 0, N'F', N'0', N'0', N'workflow:spel:remove', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +INSERT sys_menu VALUES (11805, N'流程spel表达式定义删除', N'11801', 4, N'#', N'', NULL, 1, 0, N'F', N'0', N'0', N'workflow:spel:remove', N'#', 103, 1, GETDATE(), NULL, NULL, N''); GO -INSERT sys_menu VALUES (11806, N'流程spel达式定义导出', N'11801', 5, N'#', N'', NULL, 1, 0, N'F', N'0', N'0', N'workflow:spel:export', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +INSERT sys_menu VALUES (11806, N'流程spel表达式定义导出', N'11801', 5, N'#', N'', NULL, 1, 0, N'F', N'0', N'0', N'workflow:spel:export', N'#', 103, 1, GETDATE(), NULL, NULL, N''); GO ALTER TABLE flow_definition ADD model_value VARCHAR(40) NOT NULL CONSTRAINT DF_flow_definition_model_value DEFAULT 'CLASSICS'; diff --git a/script/sql/update/sqlserver/update_5.5.1-5.5.2.sql b/script/sql/update/sqlserver/update_5.5.1-5.5.2.sql new file mode 100644 index 000000000..716abb597 --- /dev/null +++ b/script/sql/update/sqlserver/update_5.5.1-5.5.2.sql @@ -0,0 +1,22 @@ +ALTER TABLE flow_node ALTER COLUMN node_ratio nvarchar(200) NULL; +GO +IF ((SELECT COUNT(*) FROM ::fn_listextendedproperty('MS_Description', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'collaborator')) > 0) + EXEC sp_updateextendedproperty +'MS_Description', N'流程签署比例值', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'node_ratio' +ELSE + EXEC sp_addextendedproperty +'MS_Description', N'流程签署比例值', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'node_ratio' +GO +ALTER TABLE flow_node DROP COLUMN handler_type; +GO +ALTER TABLE flow_node DROP COLUMN handler_path; +GO diff --git a/script/sql/update/update_5.4.1-5.5.0.sql b/script/sql/update/update_5.4.1-5.5.0.sql index 980d098a9..a0d29fe6c 100644 --- a/script/sql/update/update_5.4.1-5.5.0.sql +++ b/script/sql/update/update_5.4.1-5.5.0.sql @@ -22,11 +22,11 @@ INSERT INTO flow_spel VALUES (1, 'spelRuleComponent', 'selectDeptLeaderById', 'i INSERT INTO flow_spel VALUES (2, NULL, NULL, 'initiator', '${initiator}', '流程发起人', '0', '0', 103, 1, sysdate(), 1, sysdate()); 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, ''); -INSERT INTO sys_menu VALUES ('11804', '流程spel达式定义修改', '11801', 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:edit', '#', 103, 1, sysdate(), NULL, NULL, ''); -INSERT INTO sys_menu VALUES ('11805', '流程spel达式定义删除', '11801', 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:remove', '#', 103, 1, sysdate(), NULL, NULL, ''); -INSERT INTO sys_menu VALUES ('11806', '流程spel达式定义导出', '11801', 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:export', '#', 103, 1, sysdate(), NULL, NULL, ''); +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, ''); +INSERT INTO sys_menu VALUES ('11804', '流程spel表达式定义修改', '11801', 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:edit', '#', 103, 1, sysdate(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11805', '流程spel表达式定义删除', '11801', 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:remove', '#', 103, 1, sysdate(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11806', '流程spel表达式定义导出', '11801', 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'workflow:spel:export', '#', 103, 1, sysdate(), NULL, NULL, ''); ALTER TABLE `flow_definition` ADD COLUMN `model_value` varchar(40) NOT NULL DEFAULT 'CLASSICS' COMMENT '设计器模式(CLASSICS经典模式 MIMIC仿钉钉模式)' AFTER `flow_name`; diff --git a/script/sql/update/update_5.5.1-5.5.2.sql b/script/sql/update/update_5.5.1-5.5.2.sql new file mode 100644 index 000000000..d1e4cef20 --- /dev/null +++ b/script/sql/update/update_5.5.1-5.5.2.sql @@ -0,0 +1,3 @@ +ALTER TABLE flow_node MODIFY COLUMN node_ratio varchar(200) NULL COMMENT '流程签署比例值'; +ALTER TABLE flow_node DROP COLUMN handler_type; +ALTER TABLE flow_node DROP COLUMN handler_path;