mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2025-12-26 07:26:44 +08:00
commit
da4dffcfce
@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||
<deployment type="dockerfile">
|
||||
<settings>
|
||||
<option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.5.1" />
|
||||
<option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.5.2" />
|
||||
<option name="buildOnly" value="true" />
|
||||
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" />
|
||||
</settings>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||
<deployment type="dockerfile">
|
||||
<settings>
|
||||
<option name="imageTag" value="ruoyi/ruoyi-server:5.5.1" />
|
||||
<option name="imageTag" value="ruoyi/ruoyi-server:5.5.2" />
|
||||
<option name="buildOnly" value="true" />
|
||||
<option name="sourceFilePath" value="ruoyi-admin/Dockerfile" />
|
||||
</settings>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="ruoyi-snailjob-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||
<deployment type="dockerfile">
|
||||
<settings>
|
||||
<option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.5.1" />
|
||||
<option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.5.2" />
|
||||
<option name="buildOnly" value="true" />
|
||||
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-snailjob-server/Dockerfile" />
|
||||
</settings>
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
[](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/5.X/LICENSE)
|
||||
[](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
|
||||
<br>
|
||||
[](https://gitee.com/dromara/RuoYi-Vue-Plus)
|
||||
[](https://gitee.com/dromara/RuoYi-Vue-Plus)
|
||||
[]()
|
||||
[]()
|
||||
[]()
|
||||
@ -39,6 +39,7 @@ CCFlow 驰聘低代码-流程-表单 - https://gitee.com/opencc/RuoYi-JFlow <br>
|
||||
Mall4J 高质量Java商城系统 - https://www.mall4j.com/cn/?statId=11 <br>
|
||||
aizuda flowlong 工作流 - https://gitee.com/aizuda/flowlong <br>
|
||||
Ruoyi-Plus-Uniapp - https://ruoyi.plus <br>
|
||||
Topiam IAM/IDaaS身份管理平台 - https://www.topiam.cn/ <br>
|
||||
|
||||
[如何成为赞助商 加群联系作者详谈 每日PV2500-3000 IP1700-2500](https://plus-doc.dromara.org/#/common/add_group)
|
||||
|
||||
|
||||
16
pom.xml
16
pom.xml
@ -13,13 +13,13 @@
|
||||
<description>Dromara RuoYi-Vue-Plus多租户管理系统</description>
|
||||
|
||||
<properties>
|
||||
<revision>5.5.1</revision>
|
||||
<spring-boot.version>3.5.7</spring-boot.version>
|
||||
<revision>5.5.2</revision>
|
||||
<spring-boot.version>3.5.9</spring-boot.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>17</java.version>
|
||||
<mybatis.version>3.5.16</mybatis.version>
|
||||
<springdoc.version>2.8.13</springdoc.version>
|
||||
<springdoc.version>2.8.14</springdoc.version>
|
||||
<therapi-javadoc.version>0.15.0</therapi-javadoc.version>
|
||||
<fastexcel.version>1.3.0</fastexcel.version>
|
||||
<velocity.version>2.3</velocity.version>
|
||||
@ -28,17 +28,17 @@
|
||||
<p6spy.version>3.9.1</p6spy.version>
|
||||
<hutool.version>5.8.40</hutool.version>
|
||||
<spring-boot-admin.version>3.5.5</spring-boot-admin.version>
|
||||
<redisson.version>3.51.0</redisson.version>
|
||||
<redisson.version>3.52.0</redisson.version>
|
||||
<lock4j.version>2.2.7</lock4j.version>
|
||||
<dynamic-ds.version>4.3.1</dynamic-ds.version>
|
||||
<snailjob.version>1.8.0</snailjob.version>
|
||||
<snailjob.version>1.9.0</snailjob.version>
|
||||
<mapstruct-plus.version>1.5.0</mapstruct-plus.version>
|
||||
<mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
|
||||
<lombok.version>1.18.40</lombok.version>
|
||||
<bouncycastle.version>1.80</bouncycastle.version>
|
||||
<justauth.version>1.16.7</justauth.version>
|
||||
<!-- 离线IP地址定位库 -->
|
||||
<ip2region.version>2.7.0</ip2region.version>
|
||||
<ip2region.version>3.3.1</ip2region.version>
|
||||
<!-- OSS 配置 -->
|
||||
<aws.sdk.version>2.28.22</aws.sdk.version>
|
||||
<!-- SMS 配置 -->
|
||||
@ -46,9 +46,9 @@
|
||||
<!-- 限制框架中的fastjson版本 -->
|
||||
<fastjson.version>1.2.83</fastjson.version>
|
||||
<!-- 面向运行时的D-ORM依赖 -->
|
||||
<anyline.version>8.7.2-20250603</anyline.version>
|
||||
<anyline.version>8.7.3-20251210</anyline.version>
|
||||
<!-- 工作流配置 -->
|
||||
<warm-flow.version>1.8.2</warm-flow.version>
|
||||
<warm-flow.version>1.8.4</warm-flow.version>
|
||||
|
||||
<!-- 插件版本 -->
|
||||
<maven-jar-plugin.version>3.4.2</maven-jar-plugin.version>
|
||||
|
||||
@ -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<AuthUser> response = SocialUtils.loginAuth(
|
||||
loginBody.getSource(), loginBody.getSocialCode(),
|
||||
loginBody.getSocialState(), socialProperties);
|
||||
loginBody.getSource(), loginBody.getSocialCode(),
|
||||
loginBody.getSocialState(), socialProperties);
|
||||
AuthUser authUserData = response.getData();
|
||||
// 判断授权响应是否成功
|
||||
if (!response.ok()) {
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<revision>5.5.1</revision>
|
||||
<revision>5.5.2</revision>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
||||
@ -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 {
|
||||
|
||||
/**
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -82,4 +82,10 @@ public interface SystemConstants {
|
||||
*/
|
||||
Long DEFAULT_DEPT_ID = 100L;
|
||||
|
||||
/**
|
||||
* 排除敏感属性字段
|
||||
*/
|
||||
String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -67,7 +67,8 @@ public class CompleteTaskDTO implements Serializable {
|
||||
|
||||
public Map<String, Object> getVariables() {
|
||||
if (variables == null) {
|
||||
return new HashMap<>(16);
|
||||
variables = new HashMap<>(16);
|
||||
return variables;
|
||||
}
|
||||
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
|
||||
return variables;
|
||||
|
||||
@ -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<Dict> getConfigArrayMap(String configKey);
|
||||
|
||||
/**
|
||||
* 根据参数 key 获取指定类型的配置对象
|
||||
*
|
||||
* @param configKey 参数 key
|
||||
* @param clazz 目标对象类型
|
||||
* @param <T> 目标对象泛型
|
||||
* @return 对象实例,如果配置为空或无法解析,返回 null
|
||||
*/
|
||||
<T> T getConfigObject(String configKey, Class<T> clazz);
|
||||
|
||||
/**
|
||||
* 根据参数 key 获取指定类型的配置列表
|
||||
*
|
||||
* @param configKey 参数 key
|
||||
* @param clazz 目标元素类型
|
||||
* @param <T> 元素类型泛型
|
||||
* @return 指定类型列表,如果配置为空或无法解析,返回空列表
|
||||
*/
|
||||
<T> List<T> getConfigArray(String configKey, Class<T> clazz);
|
||||
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@ public interface WorkflowService {
|
||||
* @param businessIds 业务id
|
||||
* @return 结果
|
||||
*/
|
||||
boolean deleteInstance(List<Long> businessIds);
|
||||
boolean deleteInstance(List<String> businessIds);
|
||||
|
||||
/**
|
||||
* 获取当前流程状态
|
||||
|
||||
@ -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 "晚上";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将日期格式化为仿微信的友好时间
|
||||
* <p>
|
||||
* 规则说明:
|
||||
* 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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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地址定位工具类,离线方式
|
||||
* 参考地址:<a href="https://gitee.com/lionsoul/ip2region/tree/master/binding/java">集成 ip2region 实现离线IP地址定位库</a>
|
||||
* IP地址行政区域工具类
|
||||
* 参考地址:<a href="https://gitee.com/lionsoul/ip2region/tree/master/binding/java">ip2region xdb java 查询客户端实现</a>
|
||||
* xdb数据库文件下载:<a href="https://gitee.com/lionsoul/ip2region/tree/master/data">ip2region data</a>
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
/**
|
||||
* 提供者类全限定名
|
||||
* <p>
|
||||
* {@link org.dromara.common.excel.core.ExcelOptionsProvider} 接口实现类 class
|
||||
*/
|
||||
Class<? extends ExcelOptionsProvider> providerClass();
|
||||
}
|
||||
@ -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<CellRangeAddress> 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个单元格合并处理器实例
|
||||
|
||||
@ -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<CellRangeAddress> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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<Object> 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<String> providerOptions = provider.getOptions();
|
||||
if (CollUtil.isNotEmpty(providerOptions)) {
|
||||
options = new ArrayList<>(providerOptions);
|
||||
}
|
||||
}
|
||||
if (ObjectUtil.isNotEmpty(options)) {
|
||||
// 仅当下拉可选项不为空时执行
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
package org.dromara.common.excel.core;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Excel下拉选项数据提供接口
|
||||
*
|
||||
* @author Angus
|
||||
*/
|
||||
public interface ExcelOptionsProvider {
|
||||
|
||||
/**
|
||||
* 获取下拉选项数据
|
||||
*
|
||||
* @return 下拉选项列表
|
||||
*/
|
||||
Set<String> getOptions();
|
||||
|
||||
}
|
||||
@ -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 = "";
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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())
|
||||
|
||||
@ -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
|
||||
* <p>
|
||||
* 调用 {@link IdentifierGenerator#nextId(Object)},返回 String 格式 ID。
|
||||
* </p>
|
||||
*
|
||||
* @return 字符串格式主键 ID
|
||||
*/
|
||||
public static String nextId() {
|
||||
return GENERATOR.nextId(null).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 Long 类型主键 ID
|
||||
* <p>
|
||||
* 自动将生成的数字型主键转换为 Long 类型
|
||||
* </p>
|
||||
*
|
||||
* @return Long 类型主键 ID
|
||||
*/
|
||||
public static Long nextLongId() {
|
||||
return GENERATOR.nextId(null).longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 Number 类型主键 ID
|
||||
* <p>
|
||||
* 推荐在需要保留原始 Number 类型时使用
|
||||
* </p>
|
||||
*
|
||||
* @return Number 类型主键 ID
|
||||
*/
|
||||
public static Number nextNumberId() {
|
||||
return GENERATOR.nextId(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实体生成数字型主键 ID
|
||||
* <p>
|
||||
* 若自定义的 {@link IdentifierGenerator} 根据实体内容生成 ID,则可以使用本方法
|
||||
* </p>
|
||||
*
|
||||
* @param entity 实体对象
|
||||
* @return Number 类型主键 ID
|
||||
*/
|
||||
public static Number nextId(Object entity) {
|
||||
return GENERATOR.nextId(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实体生成字符串主键 ID
|
||||
* <p>
|
||||
* 与 {@link #nextId(Object)} 类似,但返回 String 类型
|
||||
* </p>
|
||||
*
|
||||
* @param entity 实体对象
|
||||
* @return 字符串格式主键 ID
|
||||
*/
|
||||
public static String nextStringId(Object entity) {
|
||||
return GENERATOR.nextId(entity).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 32 位 UUID
|
||||
* <p>
|
||||
* 底层使用 {@link IdWorker#get32UUID()}
|
||||
* </p>
|
||||
*
|
||||
* @return 32 位 UUID 字符串
|
||||
*/
|
||||
public static String nextUUID() {
|
||||
return IdWorker.get32UUID();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实体生成 32 位 UUID
|
||||
* <p>
|
||||
* 默认 {@link IdentifierGenerator#nextUUID(Object)} 实现忽略实体,但保留该方法便于扩展。
|
||||
* </p>
|
||||
*
|
||||
* @param entity 实体对象
|
||||
* @return 32 位 UUID 字符串
|
||||
*/
|
||||
public static String nextUUID(Object entity) {
|
||||
return GENERATOR.nextUUID(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成带指定前缀的字符串主键 ID
|
||||
* <p>
|
||||
* 示例:prefix = "ORD",生成结果形如:{@code ORD20251211000123}
|
||||
* </p>
|
||||
*
|
||||
* @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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<String, String> 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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -43,16 +43,12 @@
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- <!– redis序列化替代方案 比json快无数的跨语言二进制序列化 –>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.apache.fury</groupId>-->
|
||||
<!-- <artifactId>fury-core</artifactId>-->
|
||||
<!-- <version>0.9.0</version>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.slf4j</groupId>-->
|
||||
<!-- <artifactId>slf4j-api</artifactId>-->
|
||||
<!-- </dependency>-->
|
||||
<!-- redis序列化替代方案 比json快无数的跨语言二进制序列化 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.fory</groupId>
|
||||
<artifactId>fory-core</artifactId>
|
||||
<version>0.13.1</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)),
|
||||
|
||||
/**
|
||||
* 清空为""
|
||||
*/
|
||||
|
||||
@ -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 企业名称
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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())
|
||||
|
||||
@ -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<Void> 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<Void> handleSpelException(ExpressionException e, HttpServletRequest request) {
|
||||
log.error("请求地址'{}',SpEL解析异常: {}", request.getRequestURI(), e.getMessage());
|
||||
return R.fail(HttpStatus.HTTP_INTERNAL_ERROR, "SpEL解析失败:" + e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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<String, String[]> parameterMap = request.getParameterMap();
|
||||
if (MapUtil.isNotEmpty(parameterMap)) {
|
||||
String parameters = JsonUtils.toJsonString(parameterMap);
|
||||
Map<String, String[]> 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<String> 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 {
|
||||
|
||||
|
||||
@ -62,6 +62,8 @@ public class TestDemoServiceImpl implements ITestDemoService {
|
||||
private LambdaQueryWrapper<TestDemo> buildQueryWrapper(TestDemoBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<TestDemo> 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,
|
||||
|
||||
@ -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<TestTree> buildQueryWrapper(TestTreeBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<TestTree> 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"));
|
||||
|
||||
@ -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<Void> 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<Void> 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<Object> getCurrentDataSourceNameList(){
|
||||
public R<Object> getCurrentDataSourceNameList() {
|
||||
return R.ok(DataBaseHelper.getDataSourceNameList());
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@ -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<Long> 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<Long> menuIds = new ArrayList<>();
|
||||
for (int i = 0; i < 6; i++) {
|
||||
menuIds.add(identifierGenerator.nextId(null).longValue());
|
||||
menuIds.add(IdGeneratorUtil.nextLongId());
|
||||
}
|
||||
table.setMenuIds(menuIds);
|
||||
// 设置主键列信息
|
||||
|
||||
@ -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<SysOssUploadVo> 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());
|
||||
|
||||
@ -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<AvatarVo> 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) + "格式");
|
||||
|
||||
@ -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<Dict> getConfigArrayMap(String configKey) {
|
||||
String configValue = getConfigValue(configKey);
|
||||
return JsonUtils.parseArrayMap(configValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据参数 key 获取指定类型的配置对象
|
||||
*
|
||||
* @param configKey 参数 key
|
||||
* @param clazz 目标对象类型
|
||||
* @return 对象实例,如果配置为空或无法解析,返回 null
|
||||
*/
|
||||
@Override
|
||||
public <T> T getConfigObject(String configKey, Class<T> clazz) {
|
||||
String configValue = getConfigValue(configKey);
|
||||
return JsonUtils.parseObject(configValue, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据参数 key 获取指定类型的配置列表=
|
||||
*
|
||||
* @param configKey 参数 key
|
||||
* @param clazz 目标元素类型
|
||||
* @return 指定类型列表,如果配置为空或无法解析,返回空列表
|
||||
*/
|
||||
@Override
|
||||
public <T> List<T> getConfigArray(String configKey, Class<T> clazz) {
|
||||
String configValue = getConfigValue(configKey);
|
||||
return JsonUtils.parseArray(configValue, clazz);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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";
|
||||
|
||||
}
|
||||
|
||||
@ -187,6 +187,7 @@ public class FlwDefinitionController extends BaseController {
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/active/{id}")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Log(title = "流程定义", businessType = BusinessType.UPDATE)
|
||||
public R<Boolean> active(@PathVariable Long id, @RequestParam boolean active) {
|
||||
return R.ok(active ? defService.active(id) : defService.unActive(id));
|
||||
}
|
||||
|
||||
@ -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<Void> deleteByBusinessIds(@PathVariable List<Long> 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<Void> deleteByInstanceIds(@PathVariable List<Long> 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<Void> deleteHisByInstanceIds(@PathVariable List<Long> 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<Void> 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<Boolean> 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<Void> updateVariable(@Validated @RequestBody FlowVariableBo bo) {
|
||||
return toAjax(flwInstanceService.updateVariable(bo));
|
||||
}
|
||||
|
||||
@ -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<Void> 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<Void> 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<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
|
||||
return toAjax(flwSpelService.deleteWithValidByIds(List.of(ids), true));
|
||||
|
||||
@ -216,6 +216,7 @@ public class FlwTaskController extends BaseController {
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping("/urgeTask")
|
||||
@Log(title = "任务管理", businessType = BusinessType.INSERT)
|
||||
public R<Void> urgeTask(@RequestBody FlowUrgeTaskBo bo) {
|
||||
return toAjax(flwTaskService.urgeTask(bo));
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -50,6 +50,6 @@ public class FlowInstanceBo implements Serializable {
|
||||
/**
|
||||
* 申请人Ids
|
||||
*/
|
||||
private List<Long> createByIds;
|
||||
private List<String> createByIds;
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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<Long> createByIds;
|
||||
|
||||
/**
|
||||
* 请求参数
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
private Map<String, Object> params = new HashMap<>();
|
||||
|
||||
}
|
||||
|
||||
@ -253,4 +253,8 @@ public class FlowHisTaskVo implements Serializable {
|
||||
this.cooperateTypeName = CooperateType.getValueByKey(cooperateType);
|
||||
}
|
||||
|
||||
public String getCreateTime() {
|
||||
return DateUtils.formatFriendlyTime(createTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ public class FlowInstanceVo {
|
||||
private String variable;
|
||||
|
||||
/**
|
||||
* 流程状态(0待提交 1审批中 2 审批通过 3自动通过 8已完成 9已退回 10失效)
|
||||
* 流程状态
|
||||
*/
|
||||
private String flowStatus;
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* 流程spel达式定义视图对象 flow_spel
|
||||
* 流程spel表达式定义视图对象 flow_spel
|
||||
*
|
||||
* @author Michelle.Chung
|
||||
* @date 2025-07-04
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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<String, Object> params) {
|
||||
public void processTaskHandler(String flowCode, Instance instance, Task nextTask, Map<String, Object> 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);
|
||||
|
||||
@ -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<String, Object> variable = listenerVariable.getVariable();
|
||||
if (CollUtil.isNotEmpty(variable)) {
|
||||
variable = new HashMap<>();
|
||||
}
|
||||
NodeExtVo nodeExt = nodeExtService.parseNodeExt(ext, variable);
|
||||
Set<String> 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<String, Object> 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)) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -75,7 +75,7 @@ public interface IFlwInstanceService {
|
||||
* @param businessIds 业务id
|
||||
* @return 结果
|
||||
*/
|
||||
boolean deleteByBusinessIds(List<Long> businessIds);
|
||||
boolean deleteByBusinessIds(List<String> businessIds);
|
||||
|
||||
/**
|
||||
* 按照实例id删除流程实例
|
||||
|
||||
@ -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<FlowSpelVo> queryPageList(FlowSpelBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询符合条件的流程spel达式定义列表
|
||||
* 查询符合条件的流程spel表达式定义列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 流程spel达式定义列表
|
||||
* @return 流程spel表达式定义列表
|
||||
*/
|
||||
List<FlowSpelVo> 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 是否进行有效性校验
|
||||
|
||||
@ -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)) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 申请人节点编码
|
||||
*
|
||||
|
||||
@ -208,10 +208,6 @@ public class FlwDefinitionServiceImpl implements IFlwDefinitionService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void syncDef(String tenantId) {
|
||||
List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper<FlowDefinition>().eq(FlowDefinition::getTenantId, DEFAULT_TENANT_ID));
|
||||
if (CollUtil.isEmpty(flowDefinitions)) {
|
||||
return;
|
||||
}
|
||||
FlowCategory flowCategory = flwCategoryMapper.selectOne(new LambdaQueryWrapper<FlowCategory>()
|
||||
.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<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper<FlowDefinition>().eq(FlowDefinition::getTenantId, DEFAULT_TENANT_ID));
|
||||
if (CollUtil.isEmpty(flowDefinitions)) {
|
||||
return;
|
||||
}
|
||||
List<Long> defIds = StreamUtils.toList(flowDefinitions, FlowDefinition::getId);
|
||||
List<FlowNode> flowNodes = flowNodeMapper.selectList(new LambdaQueryWrapper<FlowNode>().in(FlowNode::getDefinitionId, defIds));
|
||||
List<FlowSkip> flowSkips = flowSkipMapper.selectList(new LambdaQueryWrapper<FlowSkip>().in(FlowSkip::getDefinitionId, defIds));
|
||||
|
||||
@ -181,8 +181,8 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean deleteByBusinessIds(List<Long> businessIds) {
|
||||
List<FlowInstance> flowInstances = flowInstanceMapper.selectList(new LambdaQueryWrapper<FlowInstance>().in(FlowInstance::getBusinessId, StreamUtils.toList(businessIds, Convert::toStr)));
|
||||
public boolean deleteByBusinessIds(List<String> businessIds) {
|
||||
List<FlowInstance> flowInstances = flowInstanceMapper.selectList(new LambdaQueryWrapper<FlowInstance>().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<FlowTask> 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<FlowTask> 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<String, Object> 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<String, Object> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<FlowSpelVo> 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<FlowSpelVo> 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 是否进行有效性校验
|
||||
|
||||
@ -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<String> messageType = completeTaskBo.getMessageType();
|
||||
String notice = completeTaskBo.getNotice();
|
||||
// 获取抄送人
|
||||
List<FlowCopyBo> flowCopyList = completeTaskBo.getFlowCopyList();
|
||||
// 设置抄送人
|
||||
Map<String, Object> 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<String> messageType = completeTaskBo.getMessageType();
|
||||
String notice = completeTaskBo.getNotice();
|
||||
// 获取抄送人
|
||||
List<FlowCopyBo> flowCopyList = completeTaskBo.getFlowCopyList();
|
||||
// 设置抄送人
|
||||
Map<String, Object> 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<String, Object> 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<String, Object> 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<String> 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<FlowTaskBo> buildQueryWrapper(FlowTaskBo flowTaskBo) {
|
||||
Map<String, Object> params = flowTaskBo.getParams();
|
||||
QueryWrapper<FlowTaskBo> 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<Long> 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<String> 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<String, Object> 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<String> 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<String, Object> 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<Node> nodes = nodeService.previousNodeList(task.getDefinitionId(), nowNodeCode);
|
||||
if (CollUtil.isNotEmpty(nodes)) {
|
||||
return StreamUtils.filter(nodes, e -> NodeType.BETWEEN.getKey().equals(e.getNodeType()));
|
||||
List<HisTask> hisTaskList = hisTaskService.getByInsId(task.getInstanceId());
|
||||
|
||||
Map<String, Node> nodeMap = StreamUtils.toIdentityMap(nodes, Node::getNodeCode);
|
||||
Set<String> added = new HashSet<>();
|
||||
List<Node> 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<FlowTask> flowTasks = this.selectByIdList(taskIdList);
|
||||
// 批量删除现有任务的办理人记录
|
||||
if (CollUtil.isNotEmpty(flowTasks)) {
|
||||
FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTasks, FlowTask::getId));
|
||||
List<User> 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<FlowTask> flowTasks = this.selectByIdList(taskIdList);
|
||||
// 批量删除现有任务的办理人记录
|
||||
if (CollUtil.isNotEmpty(flowTasks)) {
|
||||
FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTasks, FlowTask::getId));
|
||||
List<User> 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<UserDTO> userList = this.currentTaskAllUser(bo.getTaskIdList());
|
||||
if (CollUtil.isEmpty(userList)) {
|
||||
return false;
|
||||
}
|
||||
List<String> 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<UserDTO> userList = this.currentTaskAllUser(bo.getTaskIdList());
|
||||
if (CollUtil.isEmpty(userList)) {
|
||||
return false;
|
||||
}
|
||||
List<String> messageType = bo.getMessageType();
|
||||
String message = bo.getMessage();
|
||||
flwCommonService.sendMessage(messageType, message, "单据审批提醒", userList);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<Long> 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);
|
||||
}
|
||||
|
||||
|
||||
@ -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<Long> businessIds) {
|
||||
public boolean deleteInstance(List<String> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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:
|
||||
# 时区上海
|
||||
|
||||
@ -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/;
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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, '');
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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, '');
|
||||
|
||||
@ -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 '重试完成-日志数量',
|
||||
|
||||
@ -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 '版本',
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
-- 请假测试相关按钮
|
||||
|
||||
@ -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仿钉钉模式)';
|
||||
|
||||
4
script/sql/update/oracle/update_5.5.1-5.5.2.sql
Normal file
4
script/sql/update/oracle/update_5.5.1-5.5.2.sql
Normal file
@ -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;
|
||||
@ -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仿钉钉模式)';
|
||||
|
||||
@ -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 '更新人';
|
||||
|
||||
6
script/sql/update/postgres/update_5.5.1-5.5.2.sql
Normal file
6
script/sql/update/postgres/update_5.5.1-5.5.2.sql
Normal file
@ -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;
|
||||
@ -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';
|
||||
|
||||
22
script/sql/update/sqlserver/update_5.5.1-5.5.2.sql
Normal file
22
script/sql/update/sqlserver/update_5.5.1-5.5.2.sql
Normal file
@ -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
|
||||
@ -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`;
|
||||
|
||||
3
script/sql/update/update_5.5.1-5.5.2.sql
Normal file
3
script/sql/update/update_5.5.1-5.5.2.sql
Normal file
@ -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;
|
||||
Loading…
x
Reference in New Issue
Block a user