mirror of
https://github.com/dromara/RuoYi-Vue-Plus.git
synced 2026-01-12 10:16:00 +08:00
Compare commits
24 Commits
f07c20afab
...
v5.5.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b30ffa952f | ||
|
|
fd5d028e95 | ||
|
|
64100cf1ff | ||
|
|
7e7d857ba5 | ||
|
|
d22b2a10df | ||
|
|
957a4d1fcd | ||
|
|
49ef8378fe | ||
|
|
57dd6831d3 | ||
|
|
8aa60abb1f | ||
|
|
7a9f51fc7a | ||
|
|
159e30c982 | ||
|
|
7334d91d6b | ||
|
|
95c01301f6 | ||
|
|
296466fa13 | ||
|
|
3c8d864b5f | ||
|
|
ea50a57602 | ||
|
|
7e14b98676 | ||
|
|
015b406001 | ||
|
|
098d3347a0 | ||
|
|
08d4493994 | ||
|
|
367d739e2d | ||
|
|
d6688a367d | ||
|
|
0b331796e2 | ||
|
|
456620b638 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -38,7 +38,6 @@ nbdist/
|
||||
######################################################################
|
||||
# Others
|
||||
*.log
|
||||
*.log.gz
|
||||
*.xml.versionsBackup
|
||||
*.swp
|
||||
|
||||
|
||||
@@ -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.0" />
|
||||
<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.0" />
|
||||
<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.0" />
|
||||
<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,7 +39,6 @@ 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)
|
||||
|
||||
|
||||
14
pom.xml
14
pom.xml
@@ -13,13 +13,13 @@
|
||||
<description>Dromara RuoYi-Vue-Plus多租户管理系统</description>
|
||||
|
||||
<properties>
|
||||
<revision>5.5.1</revision>
|
||||
<spring-boot.version>3.5.8</spring-boot.version>
|
||||
<revision>5.5.0</revision>
|
||||
<spring-boot.version>3.5.6</spring-boot.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>17</java.version>
|
||||
<mybatis.version>3.5.16</mybatis.version>
|
||||
<springdoc.version>2.8.14</springdoc.version>
|
||||
<springdoc.version>2.8.13</springdoc.version>
|
||||
<therapi-javadoc.version>0.15.0</therapi-javadoc.version>
|
||||
<fastexcel.version>1.3.0</fastexcel.version>
|
||||
<velocity.version>2.3</velocity.version>
|
||||
@@ -27,8 +27,8 @@
|
||||
<mybatis-plus.version>3.5.14</mybatis-plus.version>
|
||||
<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.52.0</redisson.version>
|
||||
<spring-boot-admin.version>3.5.3</spring-boot-admin.version>
|
||||
<redisson.version>3.51.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>
|
||||
@@ -38,7 +38,7 @@
|
||||
<bouncycastle.version>1.80</bouncycastle.version>
|
||||
<justauth.version>1.16.7</justauth.version>
|
||||
<!-- 离线IP地址定位库 -->
|
||||
<ip2region.version>3.3.1</ip2region.version>
|
||||
<ip2region.version>2.7.0</ip2region.version>
|
||||
<!-- OSS 配置 -->
|
||||
<aws.sdk.version>2.28.22</aws.sdk.version>
|
||||
<!-- SMS 配置 -->
|
||||
@@ -48,7 +48,7 @@
|
||||
<!-- 面向运行时的D-ORM依赖 -->
|
||||
<anyline.version>8.7.2-20250603</anyline.version>
|
||||
<!-- 工作流配置 -->
|
||||
<warm-flow.version>1.8.4</warm-flow.version>
|
||||
<warm-flow.version>1.8.1</warm-flow.version>
|
||||
|
||||
<!-- 插件版本 -->
|
||||
<maven-jar-plugin.version>3.4.2</maven-jar-plugin.version>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<revision>5.5.1</revision>
|
||||
<revision>5.5.0</revision>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
||||
@@ -5,12 +5,15 @@ 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.dromara.common.core.utils.Threads;
|
||||
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;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* 线程池配置
|
||||
@@ -47,7 +50,7 @@ public class ThreadPoolConfig {
|
||||
@Override
|
||||
protected void afterExecute(Runnable r, Throwable t) {
|
||||
super.afterExecute(r, t);
|
||||
printException(r, t);
|
||||
Threads.printException(r, t);
|
||||
}
|
||||
};
|
||||
this.scheduledExecutorService = scheduledThreadPoolExecutor;
|
||||
@@ -56,57 +59,15 @@ public class ThreadPoolConfig {
|
||||
|
||||
/**
|
||||
* 销毁事件
|
||||
* 停止线程池
|
||||
* 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务.
|
||||
* 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数.
|
||||
* 如果仍然超時,則強制退出.
|
||||
* 另对在shutdown时线程本身被调用中断做了处理.
|
||||
*/
|
||||
@PreDestroy
|
||||
public void destroy() {
|
||||
try {
|
||||
log.info("====关闭后台任务任务线程池====");
|
||||
ScheduledExecutorService pool = scheduledExecutorService;
|
||||
if (pool != null && !pool.isShutdown()) {
|
||||
pool.shutdown();
|
||||
try {
|
||||
if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
|
||||
pool.shutdownNow();
|
||||
if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
|
||||
log.info("Pool did not terminate");
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
pool.shutdownNow();
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
Threads.shutdownAndAwaitTermination(scheduledExecutorService);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印线程异常信息
|
||||
*/
|
||||
public static void printException(Runnable r, Throwable t) {
|
||||
if (t == null && r instanceof Future<?>) {
|
||||
try {
|
||||
Future<?> future = (Future<?>) r;
|
||||
if (future.isDone()) {
|
||||
future.get();
|
||||
}
|
||||
} catch (CancellationException ce) {
|
||||
t = ce;
|
||||
} catch (ExecutionException ee) {
|
||||
t = ee.getCause();
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
if (t != null) {
|
||||
log.error(t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -82,10 +82,4 @@ public interface SystemConstants {
|
||||
*/
|
||||
Long DEFAULT_DEPT_ID = 100L;
|
||||
|
||||
/**
|
||||
* 排除敏感属性字段
|
||||
*/
|
||||
String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -67,8 +67,7 @@ public class CompleteTaskDTO implements Serializable {
|
||||
|
||||
public Map<String, Object> getVariables() {
|
||||
if (variables == null) {
|
||||
variables = new HashMap<>(16);
|
||||
return variables;
|
||||
return new HashMap<>(16);
|
||||
}
|
||||
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
|
||||
return variables;
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
package org.dromara.common.core.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 流程实例业务扩展对象
|
||||
*
|
||||
* @author may
|
||||
* @date 2025-08-05
|
||||
*/
|
||||
@Data
|
||||
public class FlowInstanceBizExtDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 流程实例ID
|
||||
*/
|
||||
private Long instanceId;
|
||||
|
||||
/**
|
||||
* 业务ID
|
||||
*/
|
||||
private String businessId;
|
||||
|
||||
/**
|
||||
* 业务编码
|
||||
*/
|
||||
private String businessCode;
|
||||
|
||||
/**
|
||||
* 业务标题
|
||||
*/
|
||||
private String businessTitle;
|
||||
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.dromara.common.core.domain.dto;
|
||||
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
@@ -41,11 +40,6 @@ public class StartProcessDTO implements Serializable {
|
||||
*/
|
||||
private Map<String, Object> variables;
|
||||
|
||||
/**
|
||||
* 流程业务扩展信息
|
||||
*/
|
||||
private FlowInstanceBizExtDTO bizExt;
|
||||
|
||||
public Map<String, Object> getVariables() {
|
||||
if (variables == null) {
|
||||
return new HashMap<>(16);
|
||||
@@ -53,11 +47,4 @@ public class StartProcessDTO implements Serializable {
|
||||
variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
|
||||
return variables;
|
||||
}
|
||||
|
||||
public FlowInstanceBizExtDTO getBizExt() {
|
||||
if (ObjectUtil.isNull(bizExt)) {
|
||||
bizExt = new FlowInstanceBizExtDTO();
|
||||
}
|
||||
return bizExt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* 通用 参数配置服务
|
||||
*
|
||||
@@ -21,80 +15,4 @@ 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<String> businessIds);
|
||||
boolean deleteInstance(List<Long> businessIds);
|
||||
|
||||
/**
|
||||
* 获取当前流程状态
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
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();
|
||||
|
||||
// 总长度小于等于前后可见长度 → 全部掩码
|
||||
if (len <= prefixVisible + suffixVisible) {
|
||||
return StrUtil.repeat('*', len);
|
||||
}
|
||||
|
||||
// 可用长度 = 总长度 - 前后可见长度
|
||||
int available = len - prefixVisible - suffixVisible;
|
||||
|
||||
// 中间掩码长度不能超过可用长度
|
||||
int actualMaskLength = Math.min(maskLength, available);
|
||||
|
||||
// 剩余字符尽量显示在中间掩码旁
|
||||
int remaining = available - actualMaskLength;
|
||||
String middleChars = remaining > 0 ? value.substring(prefixVisible, prefixVisible + remaining) : "";
|
||||
String middleMask = StrUtil.repeat('*', actualMaskLength);
|
||||
|
||||
String prefix = value.substring(0, prefixVisible);
|
||||
String suffix = value.substring(len - suffixVisible);
|
||||
|
||||
return prefix + middleChars + middleMask + suffix;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.dromara.common.core.utils;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
|
||||
/**
|
||||
* 线程相关工具类.
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Slf4j
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class Threads {
|
||||
/**
|
||||
* 停止线程池
|
||||
* 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务.
|
||||
* 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数.
|
||||
* 如果仍然超時,則強制退出.
|
||||
* 另对在shutdown时线程本身被调用中断做了处理.
|
||||
*/
|
||||
public static void shutdownAndAwaitTermination(ExecutorService pool) {
|
||||
if (pool != null && !pool.isShutdown()) {
|
||||
pool.shutdown();
|
||||
try {
|
||||
if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
|
||||
pool.shutdownNow();
|
||||
if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
|
||||
log.info("Pool did not terminate");
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
pool.shutdownNow();
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印线程异常信息
|
||||
*/
|
||||
public static void printException(Runnable r, Throwable t) {
|
||||
if (t == null && r instanceof Future<?>) {
|
||||
try {
|
||||
Future<?> future = (Future<?>) r;
|
||||
if (future.isDone()) {
|
||||
future.get();
|
||||
}
|
||||
} catch (CancellationException ce) {
|
||||
t = ce;
|
||||
} catch (ExecutionException ee) {
|
||||
t = ee.getCause();
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
if (t != null) {
|
||||
log.error(t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,24 +20,51 @@ 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
|
||||
boolean isIPv4 = NetUtils.isIPv4(ip);
|
||||
// 判断是否为IPv6
|
||||
boolean isIPv6 = NetUtils.isIPv6(ip);
|
||||
// 如果不是IPv4或IPv6,则返回未知IP
|
||||
if (!isIPv4 && !isIPv6) {
|
||||
return UNKNOWN_IP;
|
||||
if (NetUtils.isIPv4(ip)) {
|
||||
return resolverIPv4Region(ip);
|
||||
}
|
||||
// 判断是否为IPv6
|
||||
if (NetUtils.isIPv6(ip)) {
|
||||
return resolverIPv6Region(ip);
|
||||
}
|
||||
// 如果不是IPv4或IPv6,则返回未知IP
|
||||
return UNKNOWN_IP;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据IPv4地址查询IP归属行政区域
|
||||
* @param ip ipv4地址
|
||||
* @return 归属行政区域
|
||||
*/
|
||||
private static String resolverIPv4Region(String ip){
|
||||
// 内网不查询
|
||||
if ((isIPv4 && NetUtils.isInnerIP(ip)) || (isIPv6 && NetUtils.isInnerIPv6(ip))) {
|
||||
if (NetUtils.isInnerIP(ip)) {
|
||||
return LOCAL_ADDRESS;
|
||||
}
|
||||
// Tips:Ip2Region 提供了精简的IPv6地址库,精简的IPv6地址库并不能完全支持IPv6地址的查询,且准确度上可能会存在问题,如需要准确的IPv6地址查询,建议自行实现
|
||||
return RegionUtils.getRegion(ip);
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,142 +1,50 @@
|
||||
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.service.Config;
|
||||
import org.lionsoul.ip2region.service.Ip2Region;
|
||||
import org.lionsoul.ip2region.xdb.Util;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.time.Duration;
|
||||
import org.lionsoul.ip2region.xdb.Searcher;
|
||||
|
||||
/**
|
||||
* 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>
|
||||
* 根据ip地址定位工具类,离线方式
|
||||
* 参考地址:<a href="https://gitee.com/lionsoul/ip2region/tree/master/binding/java">集成 ip2region 实现离线IP地址定位库</a>
|
||||
*
|
||||
* @author 秋辞未寒
|
||||
* @author lishuyan
|
||||
*/
|
||||
@Slf4j
|
||||
public class RegionUtils {
|
||||
|
||||
// 默认IPv4地址库文件路径
|
||||
// 下载地址:https://gitee.com/lionsoul/ip2region/blob/master/data/ip2region_v4.xdb
|
||||
public static final String DEFAULT_IPV4_XDB_PATH = "ip2region_v4.xdb";
|
||||
// IP地址库文件名称
|
||||
public static final String IP_XDB_FILENAME = "ip2region.xdb";
|
||||
|
||||
// 默认IPv6地址库文件路径
|
||||
// 下载地址:https://gitee.com/lionsoul/ip2region/blob/master/data/ip2region_v6.xdb
|
||||
public static final String DEFAULT_IPV6_XDB_PATH = "ip2region_v6.xdb";
|
||||
private static final Searcher SEARCHER;
|
||||
|
||||
// 未知地址
|
||||
public static final String UNKNOWN_ADDRESS = "未知";
|
||||
|
||||
// Ip2Region服务实例
|
||||
private static Ip2Region ip2Region;
|
||||
|
||||
// 初始化Ip2Region服务实例
|
||||
static {
|
||||
try {
|
||||
// 注意: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地址库数据成功!");
|
||||
// 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地址库数据不存在!");
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException("Ip2RegionHelper初始化失败,原因:{}", e.getMessage());
|
||||
throw new ServiceException("RegionUtils初始化失败,原因:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据IP地址离线获取城市
|
||||
*
|
||||
* @param ipString ip地址字符串
|
||||
*/
|
||||
public static String getRegion(String ipString) {
|
||||
public static String getCityInfo(String ip) {
|
||||
try {
|
||||
String region = ip2Region.search(ipString);
|
||||
if (StringUtils.isBlank(region)) {
|
||||
region = UNKNOWN_ADDRESS;
|
||||
}
|
||||
return region;
|
||||
// 3、执行查询
|
||||
String region = SEARCHER.search(StringUtils.trim(ip));
|
||||
return region.replace("0|", "").replace("|0", "");
|
||||
} catch (Exception e) {
|
||||
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);
|
||||
log.error("IP地址离线获取城市异常 {}", ip);
|
||||
return "未知";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
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();
|
||||
}
|
||||
@@ -28,7 +28,7 @@ public class ExcelBigNumberConvert implements Converter<Long> {
|
||||
|
||||
@Override
|
||||
public CellDataTypeEnum supportExcelTypeKey() {
|
||||
return null;
|
||||
return CellDataTypeEnum.STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -147,12 +147,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,15 @@ package org.dromara.common.excel.core;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.idev.excel.metadata.Head;
|
||||
import cn.idev.excel.write.handler.SheetWriteHandler;
|
||||
import cn.idev.excel.write.handler.WorkbookWriteHandler;
|
||||
import cn.idev.excel.write.handler.context.WorkbookWriteHandlerContext;
|
||||
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.List;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 列值重复合并策略
|
||||
@@ -19,7 +18,7 @@ import java.util.List;
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Slf4j
|
||||
public class CellMergeStrategy extends AbstractMergeStrategy implements SheetWriteHandler {
|
||||
public class CellMergeStrategy extends AbstractMergeStrategy implements WorkbookWriteHandler {
|
||||
|
||||
private final List<CellRangeAddress> cellList;
|
||||
|
||||
@@ -33,28 +32,27 @@ public class CellMergeStrategy extends AbstractMergeStrategy implements SheetWri
|
||||
|
||||
@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 afterSheetCreate(final WriteWorkbookHolder writeWorkbookHolder, final WriteSheetHolder writeSheetHolder) {
|
||||
if (CollUtil.isEmpty(cellList)) {
|
||||
public void afterWorkbookDispose(final WorkbookWriteHandlerContext context) {
|
||||
if (CollUtil.isEmpty(cellList)){
|
||||
return;
|
||||
}
|
||||
// 在 Sheet 创建时提前写入合并区域;后续写入只会影响首格,不会移除合并
|
||||
final Sheet sheet = writeSheetHolder.getSheet();
|
||||
//当前表格写完后,统一写入
|
||||
for (CellRangeAddress item : cellList) {
|
||||
sheet.addMergedRegion(item);
|
||||
context.getWriteContext().writeSheetHolder().getSheet().addMergedRegion(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ 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;
|
||||
@@ -118,15 +117,6 @@ 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)) {
|
||||
// 仅当下拉可选项不为空时执行
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package org.dromara.common.excel.core;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Excel下拉选项数据提供接口
|
||||
*
|
||||
* @author Angus
|
||||
*/
|
||||
public interface ExcelOptionsProvider {
|
||||
|
||||
/**
|
||||
* 获取下拉选项数据
|
||||
*
|
||||
* @return 下拉选项列表
|
||||
*/
|
||||
Set<String> getOptions();
|
||||
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
|
||||
import lombok.AccessLevel;
|
||||
@@ -168,58 +167,4 @@ public class JsonUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断字符串是否为合法 JSON(对象或数组)
|
||||
*
|
||||
* @param str 待校验字符串
|
||||
* @return true = 合法 JSON,false = 非法或空
|
||||
*/
|
||||
public static boolean isJson(String str) {
|
||||
if (StringUtils.isBlank(str)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
OBJECT_MAPPER.readTree(str);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断字符串是否为 JSON 对象({})
|
||||
*
|
||||
* @param str 待校验字符串
|
||||
* @return true = JSON 对象
|
||||
*/
|
||||
public static boolean isJsonObject(String str) {
|
||||
if (StringUtils.isBlank(str)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
JsonNode node = OBJECT_MAPPER.readTree(str);
|
||||
return node.isObject();
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断字符串是否为 JSON 数组([])
|
||||
*
|
||||
* @param str 待校验字符串
|
||||
* @return true = JSON 数组
|
||||
*/
|
||||
public static boolean isJsonArray(String str) {
|
||||
if (StringUtils.isBlank(str)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
JsonNode node = OBJECT_MAPPER.readTree(str);
|
||||
return node.isArray();
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
package org.dromara.common.json.validate;
|
||||
|
||||
import jakarta.validation.Constraint;
|
||||
import jakarta.validation.Payload;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* JSON 格式校验注解
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
@Documented
|
||||
@Target({ElementType.METHOD, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Constraint(validatedBy = JsonPatternValidator.class)
|
||||
public @interface JsonPattern {
|
||||
|
||||
/**
|
||||
* 限制 JSON 类型,默认为 {@link JsonType#ANY},即对象或数组都允许
|
||||
*/
|
||||
JsonType type() default JsonType.ANY;
|
||||
|
||||
/**
|
||||
* 校验失败时的提示消息
|
||||
*/
|
||||
String message() default "不是有效的 JSON 格式";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package org.dromara.common.json.validate;
|
||||
|
||||
import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.json.utils.JsonUtils;
|
||||
|
||||
/**
|
||||
* JSON 格式校验器
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
public class JsonPatternValidator implements ConstraintValidator<JsonPattern, String> {
|
||||
|
||||
/**
|
||||
* 注解中指定的 JSON 类型枚举
|
||||
*/
|
||||
private JsonType jsonType;
|
||||
|
||||
/**
|
||||
* 初始化校验器,从注解中提取 JSON 类型
|
||||
*
|
||||
* @param annotation 注解实例
|
||||
*/
|
||||
@Override
|
||||
public void initialize(JsonPattern annotation) {
|
||||
this.jsonType = annotation.type();
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验字符串是否为合法 JSON
|
||||
*
|
||||
* @param value 待校验字符串
|
||||
* @param context 校验上下文,可用于自定义错误信息
|
||||
* @return true = 合法 JSON 或为空,false = 非法 JSON
|
||||
*/
|
||||
@Override
|
||||
public boolean isValid(String value, ConstraintValidatorContext context) {
|
||||
if (StringUtils.isBlank(value)) {
|
||||
// 交给 @NotBlank 或 @NotNull 控制是否允许为空
|
||||
return true;
|
||||
}
|
||||
// 根据 JSON 类型进行不同的校验
|
||||
return switch (jsonType) {
|
||||
case ANY -> JsonUtils.isJson(value);
|
||||
case OBJECT -> JsonUtils.isJsonObject(value);
|
||||
case ARRAY -> JsonUtils.isJsonArray(value);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package org.dromara.common.json.validate;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* JSON 类型枚举
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum JsonType {
|
||||
|
||||
/**
|
||||
* JSON 对象,例如 {"a":1}
|
||||
*/
|
||||
OBJECT,
|
||||
|
||||
/**
|
||||
* JSON 数组,例如 [1,2,3]
|
||||
*/
|
||||
ARRAY,
|
||||
|
||||
/**
|
||||
* 任意 JSON 类型,对象或数组都可以
|
||||
*/
|
||||
ANY
|
||||
|
||||
}
|
||||
@@ -13,7 +13,6 @@ 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;
|
||||
@@ -40,6 +39,12 @@ import java.util.*;
|
||||
@AutoConfiguration
|
||||
public class LogAspect {
|
||||
|
||||
/**
|
||||
* 排除敏感属性字段
|
||||
*/
|
||||
public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };
|
||||
|
||||
|
||||
/**
|
||||
* 计时 key
|
||||
*/
|
||||
@@ -155,7 +160,7 @@ public class LogAspect {
|
||||
String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
|
||||
operLog.setOperParam(StringUtils.substring(params, 0, 3800));
|
||||
} else {
|
||||
MapUtil.removeAny(paramsMap, SystemConstants.EXCLUDE_PROPERTIES);
|
||||
MapUtil.removeAny(paramsMap, EXCLUDE_PROPERTIES);
|
||||
MapUtil.removeAny(paramsMap, excludeParamNames);
|
||||
operLog.setOperParam(StringUtils.substring(JsonUtils.toJsonString(paramsMap), 0, 3800));
|
||||
}
|
||||
@@ -169,7 +174,7 @@ public class LogAspect {
|
||||
if (ArrayUtil.isEmpty(paramsArray)) {
|
||||
return params.toString();
|
||||
}
|
||||
String[] exclude = ArrayUtil.addAll(excludeParamNames, SystemConstants.EXCLUDE_PROPERTIES);
|
||||
String[] exclude = ArrayUtil.addAll(excludeParamNames, EXCLUDE_PROPERTIES);
|
||||
for (Object o : paramsArray) {
|
||||
if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) {
|
||||
String str = "";
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package org.dromara.common.mybatis.handler;
|
||||
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.hutool.http.HttpStatus;
|
||||
import com.baomidou.dynamic.datasource.exception.CannotFindDataSourceException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.mybatis.spring.MyBatisSystemException;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
@@ -36,54 +35,13 @@ public class MybatisExceptionHandler {
|
||||
@ExceptionHandler(MyBatisSystemException.class)
|
||||
public R<Void> handleCannotFindDataSourceException(MyBatisSystemException e, HttpServletRequest request) {
|
||||
String requestURI = request.getRequestURI();
|
||||
Throwable root = getRootCause(e);
|
||||
if (root instanceof NotLoginException) {
|
||||
log.error("请求地址'{}',认证失败'{}',无法访问系统资源", requestURI, root.getMessage());
|
||||
return R.fail(HttpStatus.HTTP_UNAUTHORIZED, "认证失败,无法访问系统资源");
|
||||
}
|
||||
if (root instanceof CannotFindDataSourceException) {
|
||||
String message = e.getMessage();
|
||||
if (StringUtils.contains(message, "CannotFindDataSourceException")) {
|
||||
log.error("请求地址'{}', 未找到数据源", requestURI);
|
||||
return R.fail(HttpStatus.HTTP_INTERNAL_ERROR, "未找到数据源,请联系管理员确认");
|
||||
}
|
||||
log.error("请求地址'{}', Mybatis系统异常", requestURI, e);
|
||||
return R.fail(HttpStatus.HTTP_INTERNAL_ERROR, e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取异常的根因(递归查找)
|
||||
*
|
||||
* @param e 当前异常
|
||||
* @return 根因异常(最底层的 cause)
|
||||
* <p>
|
||||
* 逻辑说明:
|
||||
* 1. 如果 e 没有 cause,说明 e 本身就是根因,直接返回
|
||||
* 2. 如果 e 的 cause 和自身相同(防止循环引用),也返回 e
|
||||
* 3. 否则递归调用,继续向下寻找最底层的 cause
|
||||
*/
|
||||
public static Throwable getRootCause(Throwable e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause == null || cause == e) {
|
||||
return e;
|
||||
}
|
||||
return getRootCause(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在异常链中查找指定类型的异常
|
||||
*
|
||||
* @param e 当前异常
|
||||
* @param clazz 目标异常类
|
||||
* @return 找到的指定类型异常,如果没有找到返回 null
|
||||
*/
|
||||
public static Throwable findCause(Throwable e, Class<? extends Throwable> clazz) {
|
||||
Throwable t = e;
|
||||
while (t != null && t != t.getCause()) {
|
||||
if (clazz.isInstance(t)) {
|
||||
return t;
|
||||
}
|
||||
t = t.getCause();
|
||||
}
|
||||
return null;
|
||||
return R.fail(HttpStatus.HTTP_INTERNAL_ERROR, message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class DataBaseHelper {
|
||||
String databaseProductName = metaData.getDatabaseProductName();
|
||||
return DataBaseType.find(databaseProductName);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("获取数据库类型失败", e);
|
||||
throw new ServiceException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ public class DataPermissionHelper {
|
||||
/**
|
||||
* 开启忽略数据权限(开启后需手动调用 {@link #disableIgnore()} 关闭)
|
||||
*/
|
||||
private static void enableIgnore() {
|
||||
public static void enableIgnore() {
|
||||
IgnoreStrategy ignoreStrategy = getIgnoreStrategy();
|
||||
if (ObjectUtil.isNull(ignoreStrategy)) {
|
||||
InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().dataPermission(true).build());
|
||||
@@ -126,7 +126,7 @@ public class DataPermissionHelper {
|
||||
/**
|
||||
* 关闭忽略数据权限
|
||||
*/
|
||||
private static void disableIgnore() {
|
||||
public static void disableIgnore() {
|
||||
IgnoreStrategy ignoreStrategy = getIgnoreStrategy();
|
||||
if (ObjectUtil.isNotNull(ignoreStrategy)) {
|
||||
boolean noOtherIgnoreStrategy = !Boolean.TRUE.equals(ignoreStrategy.getDynamicTableName())
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
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,9 +14,7 @@ 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.AsyncResponseTransformer;
|
||||
import software.amazon.awssdk.core.async.BlockingInputStreamAsyncRequestBody;
|
||||
import software.amazon.awssdk.core.async.ResponsePublisher;
|
||||
import software.amazon.awssdk.core.async.*;
|
||||
import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient;
|
||||
import software.amazon.awssdk.regions.Region;
|
||||
import software.amazon.awssdk.services.s3.S3AsyncClient;
|
||||
@@ -35,7 +33,6 @@ 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;
|
||||
|
||||
@@ -97,11 +94,7 @@ public class OssClient {
|
||||
.region(of())
|
||||
.forcePathStyle(isStyle)
|
||||
.httpClient(NettyNioAsyncHttpClient.builder()
|
||||
.connectionTimeout(Duration.ofSeconds(60))
|
||||
.connectionAcquisitionTimeout(Duration.ofSeconds(30))
|
||||
.maxConcurrency(100)
|
||||
.maxPendingConnectionAcquires(1000)
|
||||
.build())
|
||||
.connectionTimeout(Duration.ofSeconds(60)).build())
|
||||
.build();
|
||||
|
||||
//AWS基于 CRT 的 S3 AsyncClient 实例用作 S3 传输管理器的底层客户端
|
||||
@@ -324,13 +317,13 @@ public class OssClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建下载请求的预签名URL
|
||||
* 获取私有URL链接
|
||||
*
|
||||
* @param objectKey 对象KEY
|
||||
* @param expiredTime 链接授权到期时间
|
||||
*/
|
||||
public String createPresignedGetUrl(String objectKey, Duration expiredTime) {
|
||||
// 使用 AWS S3 预签名 URL 的生成器 获取下载对象的预签名 URL
|
||||
public String getPrivateUrl(String objectKey, Duration expiredTime) {
|
||||
// 使用 AWS S3 预签名 URL 的生成器 获取对象的预签名 URL
|
||||
URL url = presigner.presignGetObject(
|
||||
x -> x.signatureDuration(expiredTime)
|
||||
.getObjectRequest(
|
||||
@@ -339,28 +332,7 @@ public class OssClient {
|
||||
.build())
|
||||
.build())
|
||||
.url();
|
||||
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();
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -43,12 +43,16 @@
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- redis序列化替代方案 比json快无数的跨语言二进制序列化 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.fory</groupId>
|
||||
<artifactId>fory-core</artifactId>
|
||||
<version>0.13.1</version>
|
||||
</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>-->
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -53,10 +53,9 @@ public class RedisConfig {
|
||||
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
// 指定序列化输入的类型,类必须是非final修饰的。序列化时将对象全类名一起保存下来
|
||||
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
|
||||
// org.apache.fory.logging.LoggerFactory 包别引入错了
|
||||
// LoggerFactory.useSlf4jLogging(true);
|
||||
// ForyCodec foryCodec = new ForyCodec();
|
||||
// CompositeCodec codec = new CompositeCodec(StringCodec.INSTANCE, foryCodec, foryCodec);
|
||||
// LoggerFactory.useSlf4jLogging(true);
|
||||
// FuryCodec furyCodec = new FuryCodec();
|
||||
// CompositeCodec codec = new CompositeCodec(StringCodec.INSTANCE, furyCodec, furyCodec);
|
||||
TypedJsonJacksonCodec jsonCodec = new TypedJsonJacksonCodec(Object.class, om);
|
||||
// 组合序列化 key 使用 String 内容使用通用 json 格式
|
||||
CompositeCodec codec = new CompositeCodec(StringCodec.INSTANCE, jsonCodec, jsonCodec);
|
||||
|
||||
@@ -7,9 +7,7 @@ import cn.dev33.satoken.interceptor.SaInterceptor;
|
||||
import cn.dev33.satoken.router.SaRouter;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import cn.dev33.satoken.util.SaTokenConsts;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.constant.HttpStatus;
|
||||
@@ -57,8 +55,6 @@ public class SecurityConfig implements WebMvcConfigurer {
|
||||
// 对未排除的路径进行检查
|
||||
.check(() -> {
|
||||
HttpServletRequest request = ServletUtils.getRequest();
|
||||
HttpServletResponse response = ServletUtils.getResponse();
|
||||
response.setContentType(SaTokenConsts.CONTENT_TYPE_APPLICATION_JSON);
|
||||
// 检查是否登录 是否有token
|
||||
StpUtil.checkLogin();
|
||||
|
||||
@@ -98,11 +94,7 @@ public class SecurityConfig implements WebMvcConfigurer {
|
||||
.setAuth(obj -> {
|
||||
SaHttpBasicUtil.check(username + ":" + password);
|
||||
})
|
||||
.setError(e -> {
|
||||
HttpServletResponse response = ServletUtils.getResponse();
|
||||
response.setContentType(SaTokenConsts.CONTENT_TYPE_APPLICATION_JSON);
|
||||
return SaResult.error(e.getMessage()).setCode(HttpStatus.UNAUTHORIZED);
|
||||
});
|
||||
.setError(e -> SaResult.error(e.getMessage()).setCode(HttpStatus.UNAUTHORIZED));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ 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;
|
||||
|
||||
@@ -81,13 +80,6 @@ public enum SensitiveStrategy {
|
||||
*/
|
||||
FIRST_MASK(DesensitizedUtil::firstMask),
|
||||
|
||||
/**
|
||||
* 通用字符串脱敏
|
||||
* 可配置前后可见长度和中间掩码长度
|
||||
* 默认示例:前4位可见,后4位可见,中间固定4个*
|
||||
*/
|
||||
STRING_MASK(s -> DesensitizedUtils.mask(s, 4, 4, 4)),
|
||||
|
||||
/**
|
||||
* 清空为""
|
||||
*/
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.xkcoding.http.support.HttpHeader;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
import me.zhyd.oauth.enums.scope.AuthDingTalkScope;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.AuthScopeUtils;
|
||||
import me.zhyd.oauth.utils.GlobalAuthUtils;
|
||||
import me.zhyd.oauth.utils.HttpUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 新版钉钉二维码登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.16.7
|
||||
*/
|
||||
public class AuthDingTalkV2Request extends AuthDefaultRequest {
|
||||
|
||||
public AuthDingTalkV2Request(AuthConfig config) {
|
||||
super(config, AuthDefaultSource.DINGTALK_V2);
|
||||
}
|
||||
|
||||
public AuthDingTalkV2Request(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthDefaultSource.DINGTALK_V2, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("scope", this.getScopes(",", true, AuthScopeUtils.getDefaultScopes(AuthDingTalkScope.values())))
|
||||
.queryParam("redirect_uri", GlobalAuthUtils.urlEncode(config.getRedirectUri()))
|
||||
.queryParam("prompt", "consent")
|
||||
.queryParam("org_type", config.getDingTalkOrgType())
|
||||
.queryParam("corpId", config.getDingTalkCorpId())
|
||||
.queryParam("exclusiveLogin", config.isDingTalkExclusiveLogin())
|
||||
.queryParam("exclusiveCorpId", config.getDingTalkExclusiveCorpId())
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("grantType", "authorization_code");
|
||||
params.put("clientId", config.getClientId());
|
||||
params.put("clientSecret", config.getClientSecret());
|
||||
params.put("code", authCallback.getCode());
|
||||
String response = new HttpUtils(config.getHttpConfig()).post(this.source.accessToken(), JSONObject.toJSONString(params)).getBody();
|
||||
JSONObject accessTokenObject = JSONObject.parseObject(response);
|
||||
if (!accessTokenObject.containsKey("accessToken")) {
|
||||
throw new AuthException(JSONObject.toJSONString(response), source);
|
||||
}
|
||||
return AuthToken.builder()
|
||||
.accessToken(accessTokenObject.getString("accessToken"))
|
||||
.refreshToken(accessTokenObject.getString("refreshToken"))
|
||||
.expireIn(accessTokenObject.getIntValue("expireIn"))
|
||||
.corpId(accessTokenObject.getString("corpId"))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthUser getUserInfo(AuthToken authToken) {
|
||||
HttpHeader header = new HttpHeader();
|
||||
header.add("x-acs-dingtalk-access-token", authToken.getAccessToken());
|
||||
|
||||
String response = new HttpUtils(config.getHttpConfig()).get(this.source.userInfo(), null, header, false).getBody();
|
||||
JSONObject object = JSONObject.parseObject(response);
|
||||
|
||||
authToken.setOpenId(object.getString("openId"));
|
||||
authToken.setUnionId(object.getString("unionId"));
|
||||
return AuthUser.builder()
|
||||
.rawUserInfo(object)
|
||||
.uuid(object.getString("unionId"))
|
||||
.username(object.getString("nick"))
|
||||
.nickname(object.getString("nick"))
|
||||
.avatar(object.getString("avatarUrl"))
|
||||
.snapshotUser(object.getBooleanValue("visitor"))
|
||||
.token(authToken)
|
||||
.source(source.toString())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回获取accessToken的url
|
||||
*
|
||||
* @param code 授权码
|
||||
* @return 返回获取accessToken的url
|
||||
*/
|
||||
protected String accessTokenUrl(String code) {
|
||||
return UrlBuilder.fromBaseUrl(source.accessToken())
|
||||
.queryParam("code", code)
|
||||
.queryParam("clientId", config.getClientId())
|
||||
.queryParam("clientSecret", config.getClientSecret())
|
||||
.queryParam("grantType", "authorization_code")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -28,14 +28,9 @@ public class SocialLoginConfigProperties {
|
||||
private String redirectUri;
|
||||
|
||||
/**
|
||||
* 是否需要申请unionid,目前只针对qq登录
|
||||
* 是否获取unionId
|
||||
*/
|
||||
private Boolean unionId;
|
||||
|
||||
/**
|
||||
* Microsoft Entra ID(原微软 AAD)中的租户 ID
|
||||
*/
|
||||
private String tenantId;
|
||||
private boolean unionId;
|
||||
|
||||
/**
|
||||
* Coding 企业名称
|
||||
|
||||
@@ -14,6 +14,9 @@ import org.dromara.common.social.gitea.AuthGiteaRequest;
|
||||
import org.dromara.common.social.maxkey.AuthMaxKeyRequest;
|
||||
import org.dromara.common.social.topiam.AuthTopIamRequest;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 认证授权工具类
|
||||
*
|
||||
@@ -40,7 +43,7 @@ public class SocialUtils {
|
||||
AuthConfig.AuthConfigBuilder builder = AuthConfig.builder()
|
||||
.clientId(obj.getClientId())
|
||||
.clientSecret(obj.getClientSecret())
|
||||
.redirectUri(obj.getRedirectUri())
|
||||
.redirectUri(URLEncoder.encode(obj.getRedirectUri(), StandardCharsets.UTF_8))
|
||||
.scopes(obj.getScopes());
|
||||
return switch (source.toLowerCase()) {
|
||||
case "dingtalk" -> new AuthDingTalkV2Request(builder.build(), STATE_CACHE);
|
||||
@@ -57,7 +60,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.tenantId(obj.getTenantId()).build(), STATE_CACHE);
|
||||
case "microsoft" -> new AuthMicrosoftRequest(builder.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);
|
||||
|
||||
@@ -1,21 +1,14 @@
|
||||
package org.dromara.common.sse.core;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.utils.SpringUtils;
|
||||
import org.dromara.common.redis.utils.RedisUtils;
|
||||
import org.dromara.common.sse.dto.SseMessageDto;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@@ -33,12 +26,6 @@ public class SseEmitterManager {
|
||||
|
||||
private final static Map<Long, Map<String, SseEmitter>> USER_TOKEN_EMITTERS = new ConcurrentHashMap<>();
|
||||
|
||||
public SseEmitterManager() {
|
||||
// 定时执行 SSE 心跳检测
|
||||
SpringUtils.getBean(ScheduledExecutorService.class)
|
||||
.scheduleWithFixedDelay(this::sseMonitor, 60L, 60L, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 建立与指定用户的 SSE 连接
|
||||
*
|
||||
@@ -51,12 +38,6 @@ public class SseEmitterManager {
|
||||
// 每个用户可以有多个 SSE 连接,通过 token 进行区分
|
||||
Map<String, SseEmitter> emitters = USER_TOKEN_EMITTERS.computeIfAbsent(userId, k -> new ConcurrentHashMap<>());
|
||||
|
||||
// 关闭已存在的SseEmitter,防止超过最大连接数
|
||||
SseEmitter oldEmitter = emitters.remove(token);
|
||||
if (oldEmitter != null) {
|
||||
oldEmitter.complete();
|
||||
}
|
||||
|
||||
// 创建一个新的 SseEmitter 实例,超时时间设置为一天 避免连接之后直接关闭浏览器导致连接停滞
|
||||
SseEmitter emitter = new SseEmitter(86400000L);
|
||||
|
||||
@@ -116,44 +97,6 @@ public class SseEmitterManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SSE 心跳检测,关闭无效连接
|
||||
*/
|
||||
public void sseMonitor() {
|
||||
final SseEmitter.SseEventBuilder heartbeat = SseEmitter.event().comment("heartbeat");
|
||||
// 记录需要移除的用户ID
|
||||
List<Long> toRemoveUsers = new ArrayList<>();
|
||||
|
||||
USER_TOKEN_EMITTERS.forEach((userId, emitterMap) -> {
|
||||
if (CollUtil.isEmpty(emitterMap)) {
|
||||
toRemoveUsers.add(userId);
|
||||
return;
|
||||
}
|
||||
|
||||
emitterMap.entrySet().removeIf(entry -> {
|
||||
try {
|
||||
entry.getValue().send(heartbeat);
|
||||
return false;
|
||||
} catch (Exception ex) {
|
||||
try {
|
||||
entry.getValue().complete();
|
||||
} catch (Exception ignore) {
|
||||
// 忽略重复关闭异常
|
||||
}
|
||||
return true; // 发送失败 → 移除该连接
|
||||
}
|
||||
});
|
||||
|
||||
// 移除空连接用户
|
||||
if (emitterMap.isEmpty()) {
|
||||
toRemoveUsers.add(userId);
|
||||
}
|
||||
});
|
||||
|
||||
// 循环结束后统一清理空用户,避免并发修改异常
|
||||
toRemoveUsers.forEach(USER_TOKEN_EMITTERS::remove);
|
||||
}
|
||||
|
||||
/**
|
||||
* 订阅SSE消息主题,并提供一个消费者函数来处理接收到的消息
|
||||
*
|
||||
|
||||
@@ -55,7 +55,7 @@ public class TenantHelper {
|
||||
/**
|
||||
* 开启忽略租户(开启后需手动调用 {@link #disableIgnore()} 关闭)
|
||||
*/
|
||||
private static void enableIgnore() {
|
||||
public static void enableIgnore() {
|
||||
IgnoreStrategy ignoreStrategy = getIgnoreStrategy();
|
||||
if (ObjectUtil.isNull(ignoreStrategy)) {
|
||||
InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().tenantLine(true).build());
|
||||
@@ -69,7 +69,7 @@ public class TenantHelper {
|
||||
/**
|
||||
* 关闭忽略租户
|
||||
*/
|
||||
private static void disableIgnore() {
|
||||
public static void disableIgnore() {
|
||||
IgnoreStrategy ignoreStrategy = getIgnoreStrategy();
|
||||
if (ObjectUtil.isNotNull(ignoreStrategy)) {
|
||||
boolean noOtherIgnoreStrategy = !Boolean.TRUE.equals(ignoreStrategy.getDynamicTableName())
|
||||
|
||||
@@ -46,14 +46,8 @@ public class TranslationHandler extends JsonSerializer<Object> implements Contex
|
||||
gen.writeNull();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Object result = trans.translation(value, translation.other());
|
||||
gen.writeObject(result);
|
||||
} catch (Exception e) {
|
||||
log.error("翻译处理异常,type: {}, value: {}", translation.type(), value, e);
|
||||
// 出现异常时输出原始值而不是中断序列化
|
||||
gen.writeObject(value);
|
||||
}
|
||||
Object result = trans.translation(value, translation.other());
|
||||
gen.writeObject(result);
|
||||
} else {
|
||||
gen.writeObject(value);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ 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;
|
||||
@@ -24,7 +23,6 @@ import org.springframework.web.bind.MissingPathVariableException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
|
||||
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
|
||||
import org.springframework.web.servlet.NoHandlerFoundException;
|
||||
|
||||
@@ -44,7 +42,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());
|
||||
@@ -125,7 +123,7 @@ public class GlobalExceptionHandler {
|
||||
*/
|
||||
@ResponseStatus(org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
@ExceptionHandler(IOException.class)
|
||||
public void handleIoException(IOException e, HttpServletRequest request) {
|
||||
public void handleRuntimeException(IOException e, HttpServletRequest request) {
|
||||
String requestURI = request.getRequestURI();
|
||||
if (requestURI.contains("sse")) {
|
||||
// sse 经常性连接中断 例如关闭浏览器 直接屏蔽
|
||||
@@ -134,13 +132,6 @@ public class GlobalExceptionHandler {
|
||||
log.error("请求地址'{}',连接中断", requestURI, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* sse 连接超时异常 不需要处理
|
||||
*/
|
||||
@ExceptionHandler(AsyncRequestTimeoutException.class)
|
||||
public void handleRuntimeException(AsyncRequestTimeoutException e) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截未知的运行时异常
|
||||
*/
|
||||
@@ -211,13 +202,4 @@ 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,17 +2,11 @@ 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;
|
||||
@@ -20,10 +14,8 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.io.BufferedReader;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* web的调用时间统计拦截器
|
||||
@@ -39,25 +31,19 @@ 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) {
|
||||
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();
|
||||
}
|
||||
BufferedReader reader = request.getReader();
|
||||
jsonParam = IoUtil.read(reader);
|
||||
}
|
||||
log.info("[PLUS]开始请求 => URL[{}],参数类型[json],参数:[{}]", url, jsonParam);
|
||||
} else {
|
||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||
if (MapUtil.isNotEmpty(parameterMap)) {
|
||||
Map<String, String[]> map = new LinkedHashMap<>(parameterMap);
|
||||
MapUtil.removeAny(map, SystemConstants.EXCLUDE_PROPERTIES);
|
||||
String parameters = JsonUtils.toJsonString(map);
|
||||
String parameters = JsonUtils.toJsonString(parameterMap);
|
||||
log.info("[PLUS]开始请求 => URL[{}],参数类型[param],参数:[{}]", url, parameters);
|
||||
} else {
|
||||
log.info("[PLUS]开始请求 => URL[{}],无参数", url);
|
||||
@@ -71,30 +57,6 @@ 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 {
|
||||
|
||||
|
||||
@@ -90,12 +90,10 @@ public class GenController extends BaseController {
|
||||
/**
|
||||
* 导入表结构(保存)
|
||||
*
|
||||
* @param tables 表名串
|
||||
* @param dataName 数据源名称
|
||||
* @param tables 表名串
|
||||
*/
|
||||
@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) {
|
||||
@@ -177,7 +175,7 @@ public class GenController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("tool:gen:edit")
|
||||
@Log(title = "代码生成", businessType = BusinessType.UPDATE)
|
||||
@Lock4j(keys = {"#tableId"}, acquireTimeout = 5000)
|
||||
@Lock4j
|
||||
@GetMapping("/synchDb/{tableId}")
|
||||
public R<Void> synchDb(@PathVariable("tableId") Long tableId) {
|
||||
genTableService.synchDb(tableId);
|
||||
@@ -216,7 +214,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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ 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;
|
||||
@@ -27,7 +28,6 @@ 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,6 +60,7 @@ 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_"};
|
||||
|
||||
@@ -321,7 +322,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(IdGeneratorUtil.nextLongId());
|
||||
menuIds.add(identifierGenerator.nextId(null).longValue());
|
||||
}
|
||||
table.setMenuIds(menuIds);
|
||||
// 设置主键列信息
|
||||
@@ -467,7 +468,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(IdGeneratorUtil.nextLongId());
|
||||
menuIds.add(identifierGenerator.nextId(null).longValue());
|
||||
}
|
||||
table.setMenuIds(menuIds);
|
||||
// 设置主键列信息
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
package org.dromara.system.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.system.domain.bo.SysClientBo;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.system.domain.vo.SysClientVo;
|
||||
import org.dromara.system.domain.bo.SysClientBo;
|
||||
import org.dromara.system.service.ISysClientService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 客户端管理
|
||||
@@ -77,9 +76,6 @@ public class SysClientController extends BaseController {
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody SysClientBo bo) {
|
||||
if (!sysClientService.checkClickKeyUnique(bo)) {
|
||||
return R.fail("新增客户端'" + bo.getClientKey() + "'失败,客户端key已存在");
|
||||
}
|
||||
return toAjax(sysClientService.insertByBo(bo));
|
||||
}
|
||||
|
||||
@@ -91,9 +87,6 @@ public class SysClientController extends BaseController {
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysClientBo bo) {
|
||||
if (!sysClientService.checkClickKeyUnique(bo)) {
|
||||
return R.fail("修改客户端'" + bo.getClientKey() + "'失败,客户端key已存在");
|
||||
}
|
||||
return toAjax(sysClientService.updateByBo(bo));
|
||||
}
|
||||
|
||||
|
||||
@@ -2,20 +2,21 @@ package org.dromara.system.controller.system;
|
||||
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
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.*;
|
||||
@@ -69,6 +70,9 @@ 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,7 +2,6 @@ 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;
|
||||
@@ -115,7 +114,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 (ObjectUtil.isNotNull(avatarfile) && !avatarfile.isEmpty()) {
|
||||
if (!avatarfile.isEmpty()) {
|
||||
String extension = FileUtil.extName(avatarfile.getOriginalFilename());
|
||||
if (!StringUtils.equalsAnyIgnoreCase(extension, MimeTypeUtils.IMAGE_EXTENSION)) {
|
||||
return R.fail("文件格式不正确,请上传" + Arrays.toString(MimeTypeUtils.IMAGE_EXTENSION) + "格式");
|
||||
|
||||
@@ -193,19 +193,4 @@ public class SysTenantController extends BaseController {
|
||||
return R.ok("同步租户字典成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步租户参数配置
|
||||
*/
|
||||
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
|
||||
@Log(title = "租户管理", businessType = BusinessType.INSERT)
|
||||
@Lock4j
|
||||
@GetMapping("/syncTenantConfig")
|
||||
public R<Void> syncTenantConfig() {
|
||||
if (!TenantHelper.isEnable()) {
|
||||
return R.fail("当前未开启租户模式");
|
||||
}
|
||||
tenantService.syncTenantConfig();
|
||||
return R.ok("同步租户参数配置成功");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@ import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.constant.RegexConstants;
|
||||
import org.dromara.common.json.validate.JsonPattern;
|
||||
import org.dromara.common.json.validate.JsonType;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.system.domain.SysMenu;
|
||||
|
||||
@@ -63,7 +61,6 @@ public class SysMenuBo extends BaseEntity {
|
||||
/**
|
||||
* 路由参数
|
||||
*/
|
||||
@JsonPattern(type = JsonType.OBJECT, message = "路由参数必须符合JSON格式")
|
||||
private String queryParam;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package org.dromara.system.service;
|
||||
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.system.domain.bo.SysClientBo;
|
||||
import org.dromara.system.domain.SysClient;
|
||||
import org.dromara.system.domain.vo.SysClientVo;
|
||||
import org.dromara.system.domain.bo.SysClientBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -56,11 +57,4 @@ public interface ISysClientService {
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 校验客户端key是否唯一
|
||||
*
|
||||
* @param client 客户端信息
|
||||
* @return 结果
|
||||
*/
|
||||
boolean checkClickKeyUnique(SysClientBo client);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package org.dromara.system.service;
|
||||
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.system.domain.bo.SysTenantBo;
|
||||
import org.dromara.system.domain.vo.SysTenantVo;
|
||||
import org.dromara.system.domain.bo.SysTenantBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -84,9 +84,4 @@ public interface ISysTenantService {
|
||||
* 同步租户字典
|
||||
*/
|
||||
void syncTenantDict();
|
||||
|
||||
/**
|
||||
* 同步租户参数配置
|
||||
*/
|
||||
void syncTenantConfig();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.dromara.system.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
@@ -137,19 +136,4 @@ public class SysClientServiceImpl implements ISysClientService {
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验客户端key是否唯一
|
||||
*
|
||||
* @param client 客户端信息
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public boolean checkClickKeyUnique(SysClientBo client) {
|
||||
boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysClient>()
|
||||
.eq(SysClient::getClientKey, client.getClientKey())
|
||||
.ne(ObjectUtil.isNotNull(client.getId()), SysClient::getId, client.getId()));
|
||||
return !exist;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
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;
|
||||
@@ -15,7 +14,6 @@ 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;
|
||||
@@ -84,7 +82,6 @@ public class SysConfigServiceImpl implements ISysConfigService, ConfigService {
|
||||
|
||||
/**
|
||||
* 获取注册开关
|
||||
*
|
||||
* @param tenantId 租户id
|
||||
* @return true开启,false关闭
|
||||
*/
|
||||
@@ -215,54 +212,4 @@ 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -241,8 +241,6 @@ public class SysMenuServiceImpl implements ISysMenuService {
|
||||
.setWeight(menu.getOrderNum());
|
||||
menuTree.put("menuType", menu.getMenuType());
|
||||
menuTree.put("icon", menu.getIcon());
|
||||
menuTree.put("visible", menu.getVisible());
|
||||
menuTree.put("status", menu.getStatus());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -192,9 +192,6 @@ 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();
|
||||
@@ -219,16 +216,12 @@ 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(length);
|
||||
ext1.setFileSize(file.length());
|
||||
// 保存文件信息
|
||||
return buildResultEntity(originalfileName, suffix, storage.getConfigKey(), uploadResult, ext1);
|
||||
}
|
||||
@@ -277,7 +270,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.createPresignedGetUrl(oss.getFileName(), Duration.ofSeconds(120)));
|
||||
oss.setUrl(storage.getPrivateUrl(oss.getFileName(), Duration.ofSeconds(120)));
|
||||
}
|
||||
return oss;
|
||||
}
|
||||
|
||||
@@ -508,60 +508,4 @@ public class SysTenantServiceImpl implements ISysTenantService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步租户参数配置
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void syncTenantConfig() {
|
||||
// 查询超管 所有参数配置
|
||||
List<SysConfig> configList = TenantHelper.ignore(() -> configMapper.selectList());
|
||||
|
||||
// 所有租户参数配置
|
||||
Map<String, List<SysConfig>> configMap = StreamUtils.groupByKey(configList, TenantEntity::getTenantId);
|
||||
|
||||
// 默认租户字典类型列表
|
||||
List<SysConfig> defaultConfigList = configMap.get(TenantConstants.DEFAULT_TENANT_ID);
|
||||
|
||||
// 获取所有租户编号
|
||||
List<String> tenantIds = baseMapper.selectObjs(
|
||||
new LambdaQueryWrapper<SysTenant>().select(SysTenant::getTenantId)
|
||||
.eq(SysTenant::getStatus, SystemConstants.NORMAL), x -> {
|
||||
return Convert.toStr(x);
|
||||
});
|
||||
// 待入库的字典类型和字典数据
|
||||
List<SysConfig> saveConfigList = new ArrayList<>();
|
||||
// 待同步的租户编号(用于清除对于租户的字典缓存)
|
||||
Set<String> syncTenantIds = new HashSet<>();
|
||||
// 循环所有租户,处理需要同步的数据
|
||||
for (String tenantId : tenantIds) {
|
||||
// 排除默认租户
|
||||
if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
|
||||
continue;
|
||||
}
|
||||
// 根据默认租户的字典类型进行数据同步
|
||||
for (SysConfig config : defaultConfigList) {
|
||||
// 获取当前租户的字典类型列表
|
||||
List<String> typeList = StreamUtils.toList(configMap.get(tenantId), SysConfig::getConfigKey);
|
||||
if (!typeList.contains(config.getConfigKey())) {
|
||||
SysConfig type = BeanUtil.toBean(config, SysConfig.class);
|
||||
type.setConfigId(null);
|
||||
type.setTenantId(tenantId);
|
||||
type.setCreateTime(null);
|
||||
type.setUpdateTime(null);
|
||||
syncTenantIds.add(tenantId);
|
||||
saveConfigList.add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
TenantHelper.ignore(() -> {
|
||||
if (CollUtil.isNotEmpty(saveConfigList)) {
|
||||
configMapper.insertBatch(saveConfigList);
|
||||
}
|
||||
});
|
||||
for (String tenantId : syncTenantIds) {
|
||||
TenantHelper.dynamic(tenantId, () -> CacheUtils.clear(CacheNames.SYS_CONFIG));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
|
||||
w.in(SysUser::getDeptId, ids);
|
||||
}).orderByAsc(SysUser::getUserId);
|
||||
if (StringUtils.isNotBlank(user.getExcludeUserIds())) {
|
||||
wrapper.notIn(SysUser::getUserId, StringUtils.splitTo(user.getExcludeUserIds(), Convert::toLong));
|
||||
wrapper.notIn(SysUser::getUserId, StringUtils.splitList(user.getExcludeUserIds()));
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ public enum ButtonPermissionEnum implements NodeExtEnum {
|
||||
/**
|
||||
* 是否能抄送
|
||||
*/
|
||||
COPY("是否能抄送", "copy", true),
|
||||
COPY("是否能抄送", "copy", false),
|
||||
|
||||
/**
|
||||
* 是否显示退回
|
||||
|
||||
@@ -187,7 +187,6 @@ 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,9 +1,7 @@
|
||||
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;
|
||||
@@ -77,9 +75,8 @@ 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(StreamUtils.toList(businessIds, Convert::toStr)));
|
||||
return toAjax(flwInstanceService.deleteByBusinessIds(businessIds));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,7 +85,6 @@ 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));
|
||||
}
|
||||
@@ -99,7 +95,6 @@ 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));
|
||||
}
|
||||
@@ -111,7 +106,6 @@ 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));
|
||||
}
|
||||
@@ -124,7 +118,6 @@ 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));
|
||||
}
|
||||
@@ -167,7 +160,6 @@ 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,7 +216,6 @@ 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,5 +1,6 @@
|
||||
package org.dromara.workflow.domain.bo;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
|
||||
@@ -50,6 +50,6 @@ public class FlowInstanceBo implements Serializable {
|
||||
/**
|
||||
* 申请人Ids
|
||||
*/
|
||||
private List<String> createByIds;
|
||||
private List<Long> 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,13 +1,10 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* 任务请求对象
|
||||
@@ -45,11 +42,6 @@ public class FlowTaskBo implements Serializable {
|
||||
*/
|
||||
private Long instanceId;
|
||||
|
||||
/**
|
||||
* 流程状态
|
||||
*/
|
||||
private String flowStatus;
|
||||
|
||||
/**
|
||||
* 权限列表
|
||||
*/
|
||||
@@ -60,10 +52,4 @@ public class FlowTaskBo implements Serializable {
|
||||
*/
|
||||
private List<Long> createByIds;
|
||||
|
||||
/**
|
||||
* 请求参数
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
private Map<String, Object> params = new HashMap<>();
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -163,7 +163,7 @@ public class FlowTaskVo implements Serializable {
|
||||
/**
|
||||
* 流程签署比例值 大于0为票签,会签
|
||||
*/
|
||||
private String nodeRatio;
|
||||
private BigDecimal nodeRatio;
|
||||
|
||||
/**
|
||||
* 申请人id
|
||||
|
||||
@@ -7,7 +7,6 @@ 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;
|
||||
|
||||
@@ -56,22 +55,22 @@ public class FlowProcessEventHandler {
|
||||
*
|
||||
* @param flowCode 流程定义编码
|
||||
* @param instance 实例数据
|
||||
* @param nextTask 任务
|
||||
* @param taskId 任务id
|
||||
* @param params 上一个任务的办理参数
|
||||
*/
|
||||
public void processTaskHandler(String flowCode, Instance instance, Task nextTask, Map<String, Object> params) {
|
||||
public void processTaskHandler(String flowCode, Instance instance, Long taskId, Map<String, Object> params) {
|
||||
String tenantId = TenantHelper.getTenantId();
|
||||
log.info("【流程任务事件发布】租户ID: {}, 流程编码: {}, 业务ID: {}, 节点类型: {}, 节点编码: {}, 节点名称: {}, 任务ID: {}",
|
||||
tenantId, flowCode, instance.getBusinessId(), nextTask.getNodeType(), nextTask.getNodeCode(), nextTask.getNodeName(), nextTask.getId());
|
||||
tenantId, flowCode, instance.getBusinessId(), instance.getNodeType(), instance.getNodeCode(), instance.getNodeName(), taskId);
|
||||
ProcessTaskEvent processTaskEvent = new ProcessTaskEvent();
|
||||
processTaskEvent.setTenantId(tenantId);
|
||||
processTaskEvent.setFlowCode(flowCode);
|
||||
processTaskEvent.setInstanceId(instance.getId());
|
||||
processTaskEvent.setBusinessId(instance.getBusinessId());
|
||||
processTaskEvent.setNodeType(nextTask.getNodeType());
|
||||
processTaskEvent.setNodeCode(nextTask.getNodeCode());
|
||||
processTaskEvent.setNodeName(nextTask.getNodeName());
|
||||
processTaskEvent.setTaskId(nextTask.getId());
|
||||
processTaskEvent.setNodeType(instance.getNodeType());
|
||||
processTaskEvent.setNodeCode(instance.getNodeCode());
|
||||
processTaskEvent.setNodeName(instance.getNodeName());
|
||||
processTaskEvent.setTaskId(taskId);
|
||||
processTaskEvent.setStatus(instance.getFlowStatus());
|
||||
processTaskEvent.setParams(params);
|
||||
SpringUtils.context().publishEvent(processTaskEvent);
|
||||
|
||||
@@ -5,7 +5,6 @@ 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,8 +72,8 @@ public class WorkflowGlobalListener implements GlobalListener {
|
||||
public void start(ListenerVariable listenerVariable) {
|
||||
String ext = listenerVariable.getNode().getExt();
|
||||
if (StringUtils.isNotBlank(ext)) {
|
||||
NodeExtVo nodeExt = nodeExtService.parseNodeExt(ext);
|
||||
Map<String, Object> variable = listenerVariable.getVariable();
|
||||
NodeExtVo nodeExt = nodeExtService.parseNodeExt(ext, variable);
|
||||
Set<String> copyList = nodeExt.getCopySettings();
|
||||
if (CollUtil.isNotEmpty(copyList)) {
|
||||
List<FlowCopyBo> list = StreamUtils.toList(copyList, x -> {
|
||||
@@ -105,61 +104,20 @@ 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) {
|
||||
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 (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());
|
||||
}
|
||||
|
||||
// 如果是申请节点,则把启动人添加到办理人
|
||||
if (nodeCode.equals(applyNodeCode) && StringUtils.isNotBlank(instance.getCreateBy())) {
|
||||
if (flowTask.getNodeCode().equals(applyNodeCode)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成监听器,当前任务完成后执行
|
||||
*
|
||||
@@ -186,8 +144,7 @@ public class WorkflowGlobalListener implements GlobalListener {
|
||||
//申请人提交事件
|
||||
Boolean submit = MapUtil.getBool(variable, FlowConstant.SUBMIT);
|
||||
if (submit != null && submit) {
|
||||
String status = determineFlowStatus(instance);
|
||||
flowProcessEventHandler.processHandler(definition.getFlowCode(), instance, status, variable, true);
|
||||
flowProcessEventHandler.processHandler(definition.getFlowCode(), instance, instance.getFlowStatus(), variable, true);
|
||||
} else {
|
||||
// 判断流程状态(发布:撤销,退回,作废,终止,已完成事件)
|
||||
String status = determineFlowStatus(instance);
|
||||
@@ -208,7 +165,7 @@ public class WorkflowGlobalListener implements GlobalListener {
|
||||
//发布任务事件
|
||||
if (CollUtil.isNotEmpty(nextTasks)) {
|
||||
for (Task nextTask : nextTasks) {
|
||||
flowProcessEventHandler.processTaskHandler(definition.getFlowCode(), instance, nextTask, params);
|
||||
flowProcessEventHandler.processTaskHandler(definition.getFlowCode(), instance, nextTask.getId(), params);
|
||||
}
|
||||
}
|
||||
if (ObjectUtil.isNull(flowParams)) {
|
||||
@@ -223,14 +180,12 @@ public class WorkflowGlobalListener implements GlobalListener {
|
||||
}
|
||||
|
||||
if (variable.containsKey(FlowConstant.FLOW_COPY_LIST)) {
|
||||
List<FlowCopyBo> flowCopyList = MapUtil.get(variable, FlowConstant.FLOW_COPY_LIST, new TypeReference<>() {
|
||||
});
|
||||
List<FlowCopyBo> flowCopyList = MapUtil.get(variable, FlowConstant.FLOW_COPY_LIST, new TypeReference<>() {});
|
||||
// 添加抄送人
|
||||
flwTaskService.setCopy(task, flowCopyList);
|
||||
}
|
||||
if (variable.containsKey(FlowConstant.MESSAGE_TYPE)) {
|
||||
List<String> messageType = MapUtil.get(variable, FlowConstant.MESSAGE_TYPE, new TypeReference<>() {
|
||||
});
|
||||
List<String> messageType = MapUtil.get(variable, FlowConstant.MESSAGE_TYPE, new TypeReference<>() {});
|
||||
String notice = MapUtil.getStr(variable, FlowConstant.MESSAGE_NOTICE);
|
||||
flwCommonService.sendMessage(definition.getFlowName(), instance.getId(), messageType, notice);
|
||||
}
|
||||
|
||||
@@ -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<String> businessIds);
|
||||
boolean deleteByBusinessIds(List<Long> businessIds);
|
||||
|
||||
/**
|
||||
* 按照实例id删除流程实例
|
||||
|
||||
@@ -2,8 +2,6 @@ package org.dromara.workflow.service;
|
||||
|
||||
import org.dromara.workflow.domain.vo.NodeExtVo;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程节点扩展属性 服务层
|
||||
*
|
||||
@@ -26,10 +24,9 @@ public interface IFlwNodeExtService {
|
||||
* {"code": "VariablesEnum", "value": "key1=value1,key2=value2"}
|
||||
* ]
|
||||
*
|
||||
* @param ext 扩展属性 JSON 字符串
|
||||
* @param variable 流程变量
|
||||
* @param ext 扩展属性 JSON 字符串
|
||||
* @return NodeExtVo 对象,封装按钮权限列表、抄送对象集合和自定义参数 Map
|
||||
*/
|
||||
NodeExtVo parseNodeExt(String ext, Map<String, Object> variable);
|
||||
NodeExtVo parseNodeExt(String ext);
|
||||
|
||||
}
|
||||
|
||||
@@ -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,9 +206,6 @@ 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,28 +88,23 @@ public class FlwCommonServiceImpl implements IFlwCommonService {
|
||||
if (ObjectUtil.isEmpty(messageTypeEnum)) {
|
||||
continue;
|
||||
}
|
||||
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);
|
||||
switch (messageTypeEnum) {
|
||||
case SYSTEM_MESSAGE -> {
|
||||
SseMessageDto dto = new SseMessageDto();
|
||||
dto.setUserIds(userIds);
|
||||
dto.setMessage(message);
|
||||
SseMessageUtils.publishMessage(dto);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// 记录错误但不抛出,确保主逻辑不受影响
|
||||
log.error("【消息发送失败】类型={},原因={}", messageTypeEnum, ex.getMessage(), ex);
|
||||
case EMAIL_MESSAGE -> MailUtils.sendText(emails, subject, message);
|
||||
case SMS_MESSAGE -> {
|
||||
//todo 短信发送
|
||||
}
|
||||
default -> throw new IllegalStateException("Unexpected value: " + messageTypeEnum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 申请人节点编码
|
||||
*
|
||||
|
||||
@@ -181,8 +181,8 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean deleteByBusinessIds(List<String> businessIds) {
|
||||
List<FlowInstance> flowInstances = flowInstanceMapper.selectList(new LambdaQueryWrapper<FlowInstance>().in(FlowInstance::getBusinessId, businessIds));
|
||||
public boolean deleteByBusinessIds(List<Long> businessIds) {
|
||||
List<FlowInstance> flowInstances = flowInstanceMapper.selectList(new LambdaQueryWrapper<FlowInstance>().in(FlowInstance::getBusinessId, StreamUtils.toList(businessIds, Convert::toStr)));
|
||||
if (CollUtil.isEmpty(flowInstances)) {
|
||||
log.warn("未找到对应的流程实例信息,无法执行删除操作。");
|
||||
return false;
|
||||
@@ -211,17 +211,27 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
|
||||
Function.identity()
|
||||
);
|
||||
|
||||
// 逐一触发删除事件
|
||||
instances.forEach(instance -> {
|
||||
Definition definition = definitionMap.get(instance.getDefinitionId());
|
||||
if (ObjectUtil.isNull(definition)) {
|
||||
log.warn("实例 ID: {} 对应的流程定义信息未找到,跳过删除事件触发。", instance.getId());
|
||||
return;
|
||||
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("删除流程实例失败");
|
||||
}
|
||||
flowProcessEventHandler.processDeleteHandler(definition.getFlowCode(), instance.getBusinessId());
|
||||
});
|
||||
// 删除实例
|
||||
return insService.remove(instanceIds);
|
||||
} catch (Exception e) {
|
||||
log.warn("操作失败!{}", e.getMessage());
|
||||
throw new ServiceException(e.getMessage());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -244,22 +254,27 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
|
||||
Definition::getId,
|
||||
Function.identity()
|
||||
);
|
||||
// 逐一触发删除事件
|
||||
instances.forEach(instance -> {
|
||||
Definition definition = definitionMap.get(instance.getDefinitionId());
|
||||
if (ObjectUtil.isNull(definition)) {
|
||||
log.warn("实例 ID: {} 对应的流程定义信息未找到,跳过删除事件触发。", instance.getId());
|
||||
return;
|
||||
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));
|
||||
}
|
||||
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);
|
||||
} catch (Exception e) {
|
||||
log.warn("操作失败!{}", e.getMessage());
|
||||
throw new ServiceException(e.getMessage());
|
||||
}
|
||||
FlowEngine.taskService().deleteByInsIds(instanceIds);
|
||||
FlowEngine.hisTaskService().deleteByInsIds(instanceIds);
|
||||
FlowEngine.insService().removeByIds(instanceIds);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -271,24 +286,29 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean cancelProcessApply(FlowCancelBo bo) {
|
||||
Instance instance = selectInstByBusinessId(bo.getBusinessId());
|
||||
if (instance == null) {
|
||||
throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE);
|
||||
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());
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -402,14 +422,20 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
|
||||
if (flowInstance == null) {
|
||||
throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE);
|
||||
}
|
||||
Map<String, Object> variableMap = new HashMap<>(Optional.ofNullable(flowInstance.getVariableMap()).orElse(Collections.emptyMap()));
|
||||
if (!variableMap.containsKey(bo.getKey())) {
|
||||
log.error("变量不存在: {}", bo.getKey());
|
||||
return false;
|
||||
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());
|
||||
}
|
||||
variableMap.put(bo.getKey(), bo.getValue());
|
||||
flowInstance.setVariable(FlowEngine.jsonConvert.objToStr(variableMap));
|
||||
return flowInstanceMapper.updateById(flowInstance) > 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,16 +480,21 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean processInvalid(FlowInvalidBo bo) {
|
||||
Instance instance = insService.getById(bo.getId());
|
||||
if (instance != null) {
|
||||
BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus());
|
||||
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());
|
||||
}
|
||||
FlowParams flowParams = FlowParams.build()
|
||||
.message(bo.getComment())
|
||||
.flowStatus(BusinessStatusEnum.INVALID.getStatus())
|
||||
.hisStatus(TaskStatusEnum.INVALID.getStatus())
|
||||
.ignore(true);
|
||||
taskService.terminationByInsId(bo.getId(), flowParams);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,6 @@ import org.dromara.common.core.domain.dto.DictTypeDTO;
|
||||
import org.dromara.common.core.service.DictService;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.json.utils.JsonUtils;
|
||||
import org.dromara.warm.flow.core.FlowEngine;
|
||||
import org.dromara.warm.flow.core.utils.CollUtil;
|
||||
import org.dromara.warm.flow.core.utils.ExpressionUtil;
|
||||
import org.dromara.warm.flow.ui.service.NodeExtService;
|
||||
import org.dromara.warm.flow.ui.vo.NodeExt;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
@@ -48,7 +45,7 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
|
||||
CopySettingEnum.class.getSimpleName(),
|
||||
Map.of(
|
||||
"label", "抄送对象",
|
||||
"type", 5,
|
||||
"type", 2,
|
||||
"must", false,
|
||||
"multiple", false,
|
||||
"desc", "设置该节点的抄送办理人"
|
||||
@@ -59,7 +56,7 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
|
||||
"type", 2,
|
||||
"must", false,
|
||||
"multiple", false,
|
||||
"desc", "节点执行时可设置自定义参数,多个参数以逗号分隔,如:key1=value1,key2=value2"
|
||||
"desc", "节点执行时可以使用的自定义参数"
|
||||
),
|
||||
ButtonPermissionEnum.class.getSimpleName(),
|
||||
Map.of(
|
||||
@@ -140,7 +137,7 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
|
||||
childNode.setCode(simpleName);
|
||||
// label名称
|
||||
childNode.setLabel(Convert.toStr(map.get("label")));
|
||||
// 1:输入框 2:文本域 3:下拉框 4:选择框 5:用户选择器
|
||||
// 1:输入框 2:文本域 3:下拉框 4:选择框
|
||||
childNode.setType(Convert.toInt(map.get("type"), 1));
|
||||
// 是否必填
|
||||
childNode.setMust(Convert.toBool(map.get("must"), false));
|
||||
@@ -173,7 +170,7 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
|
||||
childNode.setCode(dictType);
|
||||
// label名称
|
||||
childNode.setLabel(dictTypeDTO.getDictName());
|
||||
// 1:输入框 2:文本域 3:下拉框 4:选择框 5:用户选择器
|
||||
// 1:输入框 2:文本域 3:下拉框 4:选择框
|
||||
childNode.setType(3);
|
||||
// 是否必填
|
||||
childNode.setMust(false);
|
||||
@@ -200,23 +197,19 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
|
||||
* <p>示例 JSON:
|
||||
* [
|
||||
* {"code": "ButtonPermissionEnum", "value": "back,termination"},
|
||||
* {"code": "CopySettingEnum", "value": "1,3,4,#{@spelRuleComponent.selectDeptLeaderById(#deptId", "#roleId)}"},
|
||||
* {"code": "CopySettingEnum", "value": "1"},
|
||||
* {"code": "VariablesEnum", "value": "key1=value1,key2=value2"}
|
||||
* ]
|
||||
*
|
||||
* @param ext 扩展属性 JSON 字符串
|
||||
* @param variable 流程变量
|
||||
* @param ext 扩展属性 JSON 字符串
|
||||
* @return NodeExtVo 对象,封装按钮权限列表、抄送对象集合和自定义参数 Map
|
||||
*/
|
||||
@Override
|
||||
public NodeExtVo parseNodeExt(String ext, Map<String, Object> variable) {
|
||||
public NodeExtVo parseNodeExt(String ext) {
|
||||
NodeExtVo nodeExtVo = new NodeExtVo();
|
||||
|
||||
// 解析 JSON 为 Dict 列表
|
||||
List<Dict> nodeExtMap = JsonUtils.parseArrayMap(ext);
|
||||
if (ObjectUtil.isEmpty(nodeExtMap)) {
|
||||
return nodeExtVo;
|
||||
}
|
||||
|
||||
for (Dict nodeExt : nodeExtMap) {
|
||||
String code = nodeExt.getStr("code");
|
||||
@@ -241,20 +234,8 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
|
||||
nodeExtVo.setButtonPermissions(buttonList);
|
||||
|
||||
} else if (CopySettingEnum.class.getSimpleName().equals(code)) {
|
||||
List<String> permissions = spelSmartSplit(value).stream()
|
||||
.map(s -> {
|
||||
List<String> result = ExpressionUtil.evalVariable(s, variable);
|
||||
if (CollUtil.isNotEmpty(result)) {
|
||||
return result;
|
||||
}
|
||||
return Collections.singletonList(s);
|
||||
}).filter(Objects::nonNull)
|
||||
.flatMap(List::stream)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
List<String> copySettings = FlowEngine.permissionHandler().convertPermissions(permissions);
|
||||
// 解析抄送对象 ID 集合
|
||||
nodeExtVo.setCopySettings(new HashSet<>(copySettings));
|
||||
nodeExtVo.setCopySettings(StringUtils.str2Set(value, StringUtils.SEPARATOR));
|
||||
|
||||
} else if (VariablesEnum.class.getSimpleName().equals(code)) {
|
||||
// 解析自定义参数
|
||||
@@ -273,82 +254,4 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
|
||||
return nodeExtVo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按逗号分割字符串,但保留 #{...} 表达式和字符串常量中的逗号
|
||||
*/
|
||||
private static List<String> spelSmartSplit(String str) {
|
||||
List<String> result = new ArrayList<>();
|
||||
if (str == null || str.trim().isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
StringBuilder token = new StringBuilder();
|
||||
// #{...} 的嵌套深度
|
||||
int depth = 0;
|
||||
// 是否在字符串常量中(" 或 ')
|
||||
boolean inString = false;
|
||||
// 当前字符串引号类型
|
||||
char stringQuote = 0;
|
||||
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
char c = str.charAt(i);
|
||||
|
||||
// 检测进入 SpEL 表达式 #{...}
|
||||
if (!inString && c == '#' && depth == 0 && checkNext(str, i, '{')) {
|
||||
depth++;
|
||||
token.append("#{");
|
||||
// 跳过 {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 在表达式中遇到 { 或 } 改变嵌套深度
|
||||
if (!inString && depth > 0) {
|
||||
if (c == '{') {
|
||||
depth++;
|
||||
} else if (c == '}') {
|
||||
depth--;
|
||||
}
|
||||
token.append(c);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检测字符串开始/结束
|
||||
if (depth > 0 && (c == '"' || c == '\'')) {
|
||||
if (!inString) {
|
||||
inString = true;
|
||||
stringQuote = c;
|
||||
} else if (stringQuote == c) {
|
||||
inString = false;
|
||||
}
|
||||
token.append(c);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 外层逗号才分割
|
||||
if (c == ',' && depth == 0 && !inString) {
|
||||
String part = token.toString().trim();
|
||||
if (!part.isEmpty()) {
|
||||
result.add(part);
|
||||
}
|
||||
token.setLength(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
token.append(c);
|
||||
}
|
||||
|
||||
// 添加最后一个
|
||||
String part = token.toString().trim();
|
||||
if (!part.isEmpty()) {
|
||||
result.add(part);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean checkNext(String str, int index, char expected) {
|
||||
return index + 1 < str.length() && str.charAt(index + 1) == expected;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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,10 +5,9 @@ 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;
|
||||
@@ -26,12 +25,10 @@ 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;
|
||||
@@ -63,6 +60,7 @@ 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.*;
|
||||
@@ -86,6 +84,7 @@ 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;
|
||||
@@ -102,7 +101,6 @@ 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)) {
|
||||
@@ -139,9 +137,6 @@ 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);
|
||||
@@ -151,7 +146,12 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
.flowCode(startProcessBo.getFlowCode())
|
||||
.variable(startProcessBo.getVariables())
|
||||
.flowStatus(BusinessStatusEnum.DRAFT.getStatus());
|
||||
Instance instance = insService.start(businessId, flowParams);
|
||||
Instance instance;
|
||||
try {
|
||||
instance = insService.start(businessId, flowParams);
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException(e.getMessage());
|
||||
}
|
||||
// 保存流程实例业务信息
|
||||
this.buildFlowInstanceBizExt(instance, bizExt);
|
||||
// 申请人执行流程
|
||||
@@ -197,49 +197,53 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Lock4j(keys = {"#completeTaskBo.taskId"})
|
||||
public boolean completeTask(CompleteTaskBo completeTaskBo) {
|
||||
// 获取任务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);
|
||||
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);
|
||||
|
||||
|
||||
FlowTask flowTask = flowTaskMapper.selectById(taskId);
|
||||
if (ObjectUtil.isNull(flowTask)) {
|
||||
throw new ServiceException("流程任务不存在或任务已审批!");
|
||||
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());
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,12 +305,10 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
List<String> variableUserIds = Arrays.asList(userIds.split(StringUtils.SEPARATOR));
|
||||
hashSet.addAll(popUserIds);
|
||||
hashSet.addAll(variableUserIds);
|
||||
map.put(TaskStatusEnum.PASS.getStatus() + StrUtil.COLON + entry.getKey(), StringUtils.joinComma(hashSet));
|
||||
map.put(TaskStatusEnum.BACK.getStatus() + StrUtil.COLON + entry.getKey(), StringUtils.joinComma(hashSet));
|
||||
map.put(entry.getKey(), StringUtils.joinComma(hashSet));
|
||||
}
|
||||
} else {
|
||||
map.put(TaskStatusEnum.PASS.getStatus() + StrUtil.COLON + entry.getKey(), entry.getValue());
|
||||
map.put(TaskStatusEnum.BACK.getStatus() + StrUtil.COLON + entry.getKey(), entry.getValue());
|
||||
map.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return map;
|
||||
@@ -331,7 +333,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
flowNode.setNodeCode(flowHisTask.getTargetNodeCode());
|
||||
flowNode.setNodeName(flowHisTask.getTargetNodeName());
|
||||
//生成新的任务id
|
||||
long taskId = IdGeneratorUtil.nextLongId();
|
||||
long taskId = identifierGenerator.nextId(null).longValue();
|
||||
task.setId(taskId);
|
||||
task.setNodeName("【抄送】" + task.getNodeName());
|
||||
Date updateTime = new Date(flowHisTask.getUpdateTime().getTime() - 1000);
|
||||
@@ -380,6 +382,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo);
|
||||
queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey());
|
||||
queryWrapper.in("t.approver", LoginHelper.getUserIdStr());
|
||||
queryWrapper.orderByDesc("t.create_time").orderByDesc("t.update_time");
|
||||
Page<FlowHisTaskVo> page = flwTaskMapper.getListFinishTask(pageQuery.build(), queryWrapper);
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
@@ -445,20 +448,16 @@ 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");
|
||||
wrapper.orderByDesc("t.create_time");
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
@@ -470,35 +469,40 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean backProcess(BackProcessBo bo) {
|
||||
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("任务不存在!");
|
||||
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("messageType", messageType);
|
||||
// 消息通知
|
||||
variable.put("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());
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -526,22 +530,8 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
}
|
||||
//获取可驳回的前置节点
|
||||
List<Node> nodes = nodeService.previousNodeList(task.getDefinitionId(), nowNodeCode);
|
||||
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;
|
||||
if (CollUtil.isNotEmpty(nodes)) {
|
||||
return StreamUtils.filter(nodes, e -> NodeType.BETWEEN.getKey().equals(e.getNodeType()));
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
@@ -554,21 +544,26 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean terminationTask(FlowTerminationBo bo) {
|
||||
Long taskId = bo.getTaskId();
|
||||
Task task = taskService.getById(taskId);
|
||||
if (task == null) {
|
||||
throw new ServiceException("任务不存在!");
|
||||
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());
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -604,24 +599,16 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
if (ObjectUtil.isNull(flowNode)) {
|
||||
throw new NullPointerException("当前【" + flowTaskVo.getNodeCode() + "】节点编码不存在");
|
||||
}
|
||||
NodeExtVo nodeExtVo = flwNodeExtService.parseNodeExt(flowNode.getExt(), instance.getVariableMap());
|
||||
NodeExtVo nodeExtVo = flwNodeExtService.parseNodeExt(flowNode.getExt());
|
||||
//设置按钮权限
|
||||
if (CollUtil.isNotEmpty(nodeExtVo.getButtonPermissions())) {
|
||||
flowTaskVo.setButtonList(nodeExtVo.getButtonPermissions());
|
||||
} else {
|
||||
flowTaskVo.setButtonList(new ArrayList<>());
|
||||
}
|
||||
flowTaskVo.setButtonList(nodeExtVo.getButtonPermissions());
|
||||
if (CollUtil.isNotEmpty(nodeExtVo.getCopySettings())) {
|
||||
List<FlowCopyVo> list = StreamUtils.toList(nodeExtVo.getCopySettings(), x -> new FlowCopyVo(Convert.toLong(x)));
|
||||
flowTaskVo.setCopyList(list);
|
||||
} else {
|
||||
flowTaskVo.setCopyList(new ArrayList<>());
|
||||
}
|
||||
if (CollUtil.isNotEmpty(nodeExtVo.getVariables())) {
|
||||
flowTaskVo.setVarList(nodeExtVo.getVariables());
|
||||
} else {
|
||||
flowTaskVo.setVarList(new HashMap<>());
|
||||
}
|
||||
flowTaskVo.setVarList(nodeExtVo.getVariables());
|
||||
flowTaskVo.setNodeRatio(flowNode.getNodeRatio());
|
||||
flowTaskVo.setApplyNode(flowNode.getNodeCode().equals(flwCommonService.applyNodeCode(task.getDefinitionId())));
|
||||
return flowTaskVo;
|
||||
@@ -744,9 +731,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
Long taskId = bo.getTaskId();
|
||||
Task task = taskService.getById(taskId);
|
||||
FlowNode flowNode = getByNodeCode(task.getNodeCode(), task.getDefinitionId());
|
||||
if (ADD_SIGNATURE.equals(taskOperation) || REDUCTION_SIGNATURE.equals(taskOperation)) {
|
||||
if (CooperateType.isOrSign(flowNode.getNodeRatio())) {
|
||||
throw new ServiceException(task.getNodeName() + "不是会签或票签节点!");
|
||||
if ("addSignature".equals(taskOperation) || "reductionSignature".equals(taskOperation)) {
|
||||
if (flowNode.getNodeRatio().compareTo(BigDecimal.ZERO) == 0) {
|
||||
throw new ServiceException(task.getNodeName() + "不是会签节点!");
|
||||
}
|
||||
}
|
||||
// 设置任务状态并执行对应的任务操作
|
||||
@@ -790,18 +777,23 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
if (CollUtil.isEmpty(taskIdList)) {
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw new ServiceException(e.getMessage());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -841,16 +833,21 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
*/
|
||||
@Override
|
||||
public boolean urgeTask(FlowUrgeTaskBo bo) {
|
||||
if (CollUtil.isEmpty(bo.getTaskIdList())) {
|
||||
return false;
|
||||
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());
|
||||
}
|
||||
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,13 +18,11 @@ 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;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.common.constant.FlowConstant;
|
||||
import org.dromara.workflow.domain.TestLeave;
|
||||
import org.dromara.workflow.domain.bo.TestLeaveBo;
|
||||
import org.dromara.workflow.domain.vo.TestLeaveVo;
|
||||
@@ -168,7 +166,7 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean deleteWithValidByIds(List<Long> ids) {
|
||||
workflowService.deleteInstance(StreamUtils.toList(ids, Convert::toStr));
|
||||
workflowService.deleteInstance(ids);
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
|
||||
@@ -195,15 +193,12 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
|
||||
String message = Convert.toStr(params.get("message"));
|
||||
}
|
||||
if (processEvent.getSubmit()) {
|
||||
if (StringUtils.isBlank(testLeave.getApplyCode())) {
|
||||
String businessCode = MapUtil.getStr(params, FlowConstant.BUSINESS_CODE, StrUtil.EMPTY);
|
||||
if(StringUtils.isBlank(testLeave.getApplyCode())){
|
||||
String businessCode = MapUtil.getStr(params, "businessCode",StrUtil.EMPTY);
|
||||
testLeave.setApplyCode(businessCode);
|
||||
}
|
||||
testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus());
|
||||
log.info("申请人提交");
|
||||
}
|
||||
String status = BusinessStatusEnum.findByStatus(processEvent.getStatus());
|
||||
log.info("当前流程状态为{}", status);
|
||||
baseMapper.updateById(testLeave);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@ 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;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.dromara.workflow.common.enums.MessageTypeEnum;
|
||||
import org.dromara.workflow.domain.FlowInstanceBizExt;
|
||||
import org.dromara.workflow.domain.bo.CompleteTaskBo;
|
||||
import org.dromara.workflow.domain.bo.StartProcessBo;
|
||||
import org.dromara.workflow.service.IFlwDefinitionService;
|
||||
@@ -45,7 +45,7 @@ public class WorkflowServiceImpl implements WorkflowService {
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public boolean deleteInstance(List<String> businessIds) {
|
||||
public boolean deleteInstance(List<Long> businessIds) {
|
||||
return flwInstanceService.deleteByBusinessIds(businessIds);
|
||||
}
|
||||
|
||||
@@ -160,19 +160,27 @@ public class WorkflowServiceImpl implements WorkflowService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean startCompleteTask(StartProcessDTO startProcess) {
|
||||
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));
|
||||
try {
|
||||
StartProcessBo processBo = new StartProcessBo();
|
||||
processBo.setBusinessId(startProcess.getBusinessId());
|
||||
processBo.setFlowCode(startProcess.getFlowCode());
|
||||
processBo.setVariables(startProcess.getVariables());
|
||||
processBo.setHandler(startProcess.getHandler());
|
||||
|
||||
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);
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ services:
|
||||
network_mode: "host"
|
||||
|
||||
ruoyi-server1:
|
||||
image: ruoyi/ruoyi-server:5.5.1
|
||||
image: ruoyi/ruoyi-server:5.5.0
|
||||
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.0
|
||||
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.0
|
||||
container_name: ruoyi-monitor-admin
|
||||
environment:
|
||||
# 时区上海
|
||||
@@ -143,7 +143,7 @@ services:
|
||||
network_mode: "host"
|
||||
|
||||
ruoyi-snailjob-server:
|
||||
image: ruoyi/ruoyi-snailjob-server:5.5.1
|
||||
image: ruoyi/ruoyi-snailjob-server:5.5.0
|
||||
container_name: ruoyi-snailjob-server
|
||||
environment:
|
||||
# 时区上海
|
||||
|
||||
@@ -4,30 +4,18 @@ error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
# 可以根据业务并发量适当调高
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
# 高效传输文件
|
||||
sendfile on;
|
||||
# 长连接超时时间
|
||||
keepalive_timeout 65;
|
||||
# 单连接最大请求数,提高长连接复用率
|
||||
keepalive_requests 100000;
|
||||
# 限制body大小
|
||||
client_max_body_size 100m;
|
||||
client_header_buffer_size 32k;
|
||||
client_body_buffer_size 512k;
|
||||
# 开启静态资源压缩
|
||||
gzip_static on;
|
||||
# 连接数限制 (防御类配置) 10m 一般够用了,能存储上万 IP 的计数
|
||||
limit_conn_zone $binary_remote_addr zone=perip:10m;
|
||||
limit_conn_zone $server_name zone=perserver:10m;
|
||||
# 隐藏 nginx 版本号,防止暴露版本信息
|
||||
server_tokens off;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
@@ -62,7 +50,7 @@ http {
|
||||
#ssl_certificate_key /etc/nginx/cert/xxx.local.key; # /etc/nginx/cert/ 为docker映射路径 不允许更改
|
||||
#ssl_session_timeout 5m;
|
||||
#ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
|
||||
#ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1 TLSv1;
|
||||
#ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
#ssl_prefer_server_ciphers on;
|
||||
# https配置参考 end
|
||||
|
||||
@@ -88,29 +76,17 @@ http {
|
||||
}
|
||||
|
||||
location /prod-api/ {
|
||||
# 设置客户端请求头中的 Host 信息(保持原始 Host)
|
||||
proxy_set_header Host $http_host;
|
||||
# 获取客户端真实 IP
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
# 自定义头 REMOTE-HOST,记录客户端 IP
|
||||
proxy_set_header REMOTE-HOST $remote_addr;
|
||||
# 获取完整的客户端 IP 链(经过多级代理时)
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# 设置后端响应超时时间(这里是 24 小时,适合长连接/SSE)
|
||||
proxy_read_timeout 86400s;
|
||||
# SSE (Server-Sent Events) 与 WebSocket 支持参数
|
||||
# sse 与 websocket参数
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
# 禁用代理缓冲,数据直接传给客户端
|
||||
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/;
|
||||
}
|
||||
|
||||
@@ -118,37 +94,23 @@ http {
|
||||
# 解决方案1 将 admin 服务 也配置成 https
|
||||
# 解决方案2 将菜单配置为外链访问 走独立页面 http 访问
|
||||
location /admin/ {
|
||||
# 设置客户端请求头中的 Host 信息(保持原始 Host)
|
||||
proxy_set_header Host $http_host;
|
||||
# 获取客户端真实 IP
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
# 自定义头 REMOTE-HOST,记录客户端 IP
|
||||
proxy_set_header REMOTE-HOST $remote_addr;
|
||||
# 获取完整的客户端 IP 链(经过多级代理时)
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# 禁用代理缓冲,数据直接传给客户端
|
||||
proxy_buffering off;
|
||||
# 禁用代理缓存
|
||||
proxy_cache off;
|
||||
proxy_pass http://monitor-admin/admin/;
|
||||
}
|
||||
|
||||
location /snail-job/ {
|
||||
# 设置客户端请求头中的 Host 信息(保持原始 Host)
|
||||
proxy_set_header Host $http_host;
|
||||
# 获取客户端真实 IP
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
# 自定义头 REMOTE-HOST,记录客户端 IP
|
||||
proxy_set_header REMOTE-HOST $remote_addr;
|
||||
# 获取完整的客户端 IP 链(经过多级代理时)
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
# SSE (Server-Sent Events) 与 WebSocket 支持参数
|
||||
# sse 与 websocket参数
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
# 禁用代理缓冲,直接传输给客户端
|
||||
proxy_buffering off;
|
||||
# 禁用代理缓存
|
||||
proxy_cache off;
|
||||
proxy_pass http://snailjob-server/snail-job/;
|
||||
}
|
||||
|
||||
@@ -1,129 +1,75 @@
|
||||
{
|
||||
"nodeList": [
|
||||
{
|
||||
"nodeType": "0",
|
||||
"nodeCode": "d5ee3ddf-3968-4379-a86f-9ceabde5faac",
|
||||
"nodeName": "开始",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "200,200|200,200",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "d5ee3ddf-3968-4379-a86f-9ceabde5faac",
|
||||
"nextNodeCode": "dd515cdd-59f6-446f-94ca-25ca062afb42",
|
||||
"coordinate": "220,200;310,200"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "dd515cdd-59f6-446f-94ca-25ca062afb42",
|
||||
"nodeName": "申请人",
|
||||
"permissionFlag": "",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,copy\"}]",
|
||||
"coordinate": "360,200|360,200",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "dd515cdd-59f6-446f-94ca-25ca062afb42",
|
||||
"nextNodeCode": "78fa8e5b-e809-44ed-978a-41092409ebcf",
|
||||
"coordinate": "410,200;490,200"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "78fa8e5b-e809-44ed-978a-41092409ebcf",
|
||||
"nodeName": "组长",
|
||||
"permissionFlag": "role:1",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,copy,transfer,trust,file\"}]",
|
||||
"coordinate": "540,200|540,200",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "78fa8e5b-e809-44ed-978a-41092409ebcf",
|
||||
"nextNodeCode": "a8abf15f-b83e-428a-86cc-033555ea9bbe",
|
||||
"coordinate": "590,200;670,200"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "a8abf15f-b83e-428a-86cc-033555ea9bbe",
|
||||
"nodeName": "部门主管",
|
||||
"permissionFlag": "role:3@@role:4",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,copy,transfer,trust,file\"}]",
|
||||
"coordinate": "720,200|720,200",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "a8abf15f-b83e-428a-86cc-033555ea9bbe",
|
||||
"nextNodeCode": "8b82b7d7-8660-455e-b880-d6d22ea3eb6d",
|
||||
"coordinate": "770,200;880,200"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "2",
|
||||
"nodeCode": "8b82b7d7-8660-455e-b880-d6d22ea3eb6d",
|
||||
"nodeName": "结束",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "900,200|900,200",
|
||||
"version": "1",
|
||||
"skipList": []
|
||||
}
|
||||
],
|
||||
"flowCode": "leave1",
|
||||
"flowName": "请假申请-普通",
|
||||
"modelValue": "CLASSICS",
|
||||
"category": "103",
|
||||
"version": "1",
|
||||
"formCustom": "N",
|
||||
"formPath": "/workflow/leaveEdit/index",
|
||||
"listenerType": null,
|
||||
"listenerPath": null
|
||||
"flowCode" : "leave1",
|
||||
"flowName" : "请假申请-普通",
|
||||
"category" : "100",
|
||||
"version" : "1",
|
||||
"formCustom" : "N",
|
||||
"formPath" : "/workflow/leaveEdit/index",
|
||||
"nodeList" : [ {
|
||||
"nodeType" : 0,
|
||||
"nodeCode" : "d5ee3ddf-3968-4379-a86f-9ceabde5faac",
|
||||
"nodeName" : "开始",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "200,200|200,200",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "d5ee3ddf-3968-4379-a86f-9ceabde5faac",
|
||||
"nextNodeCode" : "dd515cdd-59f6-446f-94ca-25ca062afb42",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "220,200;310,200"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "dd515cdd-59f6-446f-94ca-25ca062afb42",
|
||||
"nodeName" : "申请人",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "360,200|360,200",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "dd515cdd-59f6-446f-94ca-25ca062afb42",
|
||||
"nextNodeCode" : "78fa8e5b-e809-44ed-978a-41092409ebcf",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "410,200;490,200"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "78fa8e5b-e809-44ed-978a-41092409ebcf",
|
||||
"nodeName" : "组长",
|
||||
"permissionFlag" : "role:1",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "540,200|540,200",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "78fa8e5b-e809-44ed-978a-41092409ebcf",
|
||||
"nextNodeCode" : "a8abf15f-b83e-428a-86cc-033555ea9bbe",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "590,200;670,200"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "a8abf15f-b83e-428a-86cc-033555ea9bbe",
|
||||
"nodeName" : "部门主管",
|
||||
"permissionFlag" : "role:3@@role:4",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "720,200|720,200",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "a8abf15f-b83e-428a-86cc-033555ea9bbe",
|
||||
"nextNodeCode" : "8b82b7d7-8660-455e-b880-d6d22ea3eb6d",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "770,200;880,200"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 2,
|
||||
"nodeCode" : "8b82b7d7-8660-455e-b880-d6d22ea3eb6d",
|
||||
"nodeName" : "结束",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "900,200|900,200",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]"
|
||||
} ]
|
||||
}
|
||||
|
||||
@@ -1,187 +1,111 @@
|
||||
{
|
||||
"nodeList": [
|
||||
{
|
||||
"nodeType": "0",
|
||||
"nodeCode": "cef3895c-f7d8-4598-8bf3-8ec2ef6ce84a",
|
||||
"nodeName": "开始",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "300,240|300,240",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "cef3895c-f7d8-4598-8bf3-8ec2ef6ce84a",
|
||||
"nextNodeCode": "fdcae93b-b69c-498a-b231-09255e74bcbd",
|
||||
"coordinate": "320,240;390,240"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "fdcae93b-b69c-498a-b231-09255e74bcbd",
|
||||
"nodeName": "申请人",
|
||||
"permissionFlag": "",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]",
|
||||
"coordinate": "440,240|440,240",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "fdcae93b-b69c-498a-b231-09255e74bcbd",
|
||||
"nextNodeCode": "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
|
||||
"coordinate": "490,240;535,240"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "3",
|
||||
"nodeCode": "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "560,240",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": "le@@leaveDays|2",
|
||||
"skipName": null,
|
||||
"nowNodeCode": "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
|
||||
"nextNodeCode": "b3528155-dcb7-4445-bbdf-3d00e3499e86",
|
||||
"coordinate": "560,265;560,320;670,320"
|
||||
},
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": "gt@@leaveDays|2",
|
||||
"skipName": "大于两天",
|
||||
"nowNodeCode": "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
|
||||
"nextNodeCode": "5ed2362b-fc0c-4d52-831f-95208b830605",
|
||||
"coordinate": "560,215;560,160;670,160|560,187"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "b3528155-dcb7-4445-bbdf-3d00e3499e86",
|
||||
"nodeName": "组长",
|
||||
"permissionFlag": "3@@4",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
|
||||
"coordinate": "720,320|720,320",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "b3528155-dcb7-4445-bbdf-3d00e3499e86",
|
||||
"nextNodeCode": "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
|
||||
"coordinate": "770,320;860,320;860,280"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
|
||||
"nodeName": "总经理",
|
||||
"permissionFlag": "role:1",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
|
||||
"coordinate": "860,240|860,240",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
|
||||
"nextNodeCode": "40aa65fd-0712-4d23-b6f7-d0432b920fd1",
|
||||
"coordinate": "910,240;980,240"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "2",
|
||||
"nodeCode": "40aa65fd-0712-4d23-b6f7-d0432b920fd1",
|
||||
"nodeName": "结束",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "1000,240|1000,240",
|
||||
"version": "1",
|
||||
"skipList": []
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "5ed2362b-fc0c-4d52-831f-95208b830605",
|
||||
"nodeName": "部门领导",
|
||||
"permissionFlag": "role:1",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
|
||||
"coordinate": "720,160|720,160",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "5ed2362b-fc0c-4d52-831f-95208b830605",
|
||||
"nextNodeCode": "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
|
||||
"nextNodeType": "1",
|
||||
"coordinate": "770,160;860,160;860,200"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"flowCode": "leave2",
|
||||
"flowName": "请假申请-排他网关",
|
||||
"modelValue": "CLASSICS",
|
||||
"category": "103",
|
||||
"version": "1",
|
||||
"formCustom": "N",
|
||||
"formPath": "/workflow/leaveEdit/index",
|
||||
"listenerType": null,
|
||||
"listenerPath": null
|
||||
"flowCode" : "leave2",
|
||||
"flowName" : "请假申请-排他网关",
|
||||
"category" : "100",
|
||||
"version" : "1",
|
||||
"formCustom" : "N",
|
||||
"formPath" : "/workflow/leaveEdit/index",
|
||||
"nodeList" : [ {
|
||||
"nodeType" : 0,
|
||||
"nodeCode" : "cef3895c-f7d8-4598-8bf3-8ec2ef6ce84a",
|
||||
"nodeName" : "开始",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "300,240|300,240",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "cef3895c-f7d8-4598-8bf3-8ec2ef6ce84a",
|
||||
"nextNodeCode" : "fdcae93b-b69c-498a-b231-09255e74bcbd",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "320,240;390,240"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "fdcae93b-b69c-498a-b231-09255e74bcbd",
|
||||
"nodeName" : "申请人",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "440,240|440,240",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "fdcae93b-b69c-498a-b231-09255e74bcbd",
|
||||
"nextNodeCode" : "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "490,240;535,240"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 3,
|
||||
"nodeCode" : "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "560,240",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
|
||||
"nextNodeCode" : "b3528155-dcb7-4445-bbdf-3d00e3499e86",
|
||||
"skipType" : "PASS",
|
||||
"skipCondition" : "le@@leaveDays|2",
|
||||
"coordinate" : "560,265;560,320;670,320"
|
||||
}, {
|
||||
"nowNodeCode" : "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
|
||||
"nextNodeCode" : "5ed2362b-fc0c-4d52-831f-95208b830605",
|
||||
"skipName" : "大于两天",
|
||||
"skipType" : "PASS",
|
||||
"skipCondition" : "gt@@leaveDays|2",
|
||||
"coordinate" : "560,215;560,160;670,160|560,187"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "b3528155-dcb7-4445-bbdf-3d00e3499e86",
|
||||
"nodeName" : "组长",
|
||||
"permissionFlag" : "3@@4",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "720,320|720,320",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "b3528155-dcb7-4445-bbdf-3d00e3499e86",
|
||||
"nextNodeCode" : "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "770,320;860,320;860,280"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
|
||||
"nodeName" : "总经理",
|
||||
"permissionFlag" : "role:1",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "860,240|860,240",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
|
||||
"nextNodeCode" : "40aa65fd-0712-4d23-b6f7-d0432b920fd1",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "910,240;980,240"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 2,
|
||||
"nodeCode" : "40aa65fd-0712-4d23-b6f7-d0432b920fd1",
|
||||
"nodeName" : "结束",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "1000,240|1000,240",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]"
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "5ed2362b-fc0c-4d52-831f-95208b830605",
|
||||
"nodeName" : "部门领导",
|
||||
"permissionFlag" : "role:1",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "720,160|720,160",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "5ed2362b-fc0c-4d52-831f-95208b830605",
|
||||
"nextNodeCode" : "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "770,160;860,160;860,200"
|
||||
} ]
|
||||
} ]
|
||||
}
|
||||
|
||||
@@ -1,211 +1,121 @@
|
||||
{
|
||||
"nodeList": [
|
||||
{
|
||||
"nodeType": "0",
|
||||
"nodeCode": "a80ecf9f-f465-4ae5-a429-e30ec5d0f957",
|
||||
"nodeName": "开始",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "380,220|380,220",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "a80ecf9f-f465-4ae5-a429-e30ec5d0f957",
|
||||
"nextNodeCode": "b7bbb571-06de-455c-8083-f83c07bf0b99",
|
||||
"coordinate": "400,220;470,220"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "b7bbb571-06de-455c-8083-f83c07bf0b99",
|
||||
"nodeName": "申请人",
|
||||
"permissionFlag": "",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]",
|
||||
"coordinate": "520,220|520,220",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "b7bbb571-06de-455c-8083-f83c07bf0b99",
|
||||
"nextNodeCode": "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
|
||||
"coordinate": "570,220;655,220"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "4",
|
||||
"nodeCode": "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "680,220",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
|
||||
"nextNodeCode": "4b7743cd-940c-431b-926f-e7b614fbf1fe",
|
||||
"coordinate": "680,195;680,140;750,140"
|
||||
},
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
|
||||
"nextNodeCode": "762cb975-37d8-4276-b6db-79a4c3606394",
|
||||
"coordinate": "680,245;680,300;750,300"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "4b7743cd-940c-431b-926f-e7b614fbf1fe",
|
||||
"nodeName": "市场部",
|
||||
"permissionFlag": "role:1",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
|
||||
"coordinate": "800,140|800,140",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "4b7743cd-940c-431b-926f-e7b614fbf1fe",
|
||||
"nextNodeCode": "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
|
||||
"coordinate": "850,140;920,140;920,195"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "4",
|
||||
"nodeCode": "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "920,220",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
|
||||
"nextNodeCode": "23e7429e-2b47-4431-b93e-40db7c431ce6",
|
||||
"coordinate": "945,220;975,220;975,220;960,220;960,220;990,220"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "23e7429e-2b47-4431-b93e-40db7c431ce6",
|
||||
"nodeName": "CEO",
|
||||
"permissionFlag": "1",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
|
||||
"coordinate": "1040,220|1040,220",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "23e7429e-2b47-4431-b93e-40db7c431ce6",
|
||||
"nextNodeCode": "f5ace37f-5a5e-4e64-a6f6-913ab9a71cd1",
|
||||
"coordinate": "1090,220;1140,220"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "2",
|
||||
"nodeCode": "f5ace37f-5a5e-4e64-a6f6-913ab9a71cd1",
|
||||
"nodeName": "结束",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "1160,220|1160,220",
|
||||
"version": "1",
|
||||
"skipList": []
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "762cb975-37d8-4276-b6db-79a4c3606394",
|
||||
"nodeName": "综合部",
|
||||
"permissionFlag": "role:3@@role:4",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
|
||||
"coordinate": "800,300|800,300",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "762cb975-37d8-4276-b6db-79a4c3606394",
|
||||
"nextNodeCode": "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
|
||||
"nextNodeType": "4",
|
||||
"coordinate": "850,300;920,300;920,245"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"flowCode": "leave3",
|
||||
"flowName": "请假申请-并行网关",
|
||||
"modelValue": "CLASSICS",
|
||||
"category": "103",
|
||||
"version": "1",
|
||||
"formCustom": "N",
|
||||
"formPath": "/workflow/leaveEdit/index",
|
||||
"listenerType": null,
|
||||
"listenerPath": null
|
||||
"flowCode" : "leave3",
|
||||
"flowName" : "请假申请-并行网关",
|
||||
"category" : "100",
|
||||
"version" : "1",
|
||||
"formCustom" : "N",
|
||||
"formPath" : "/workflow/leaveEdit/index",
|
||||
"nodeList" : [ {
|
||||
"nodeType" : 0,
|
||||
"nodeCode" : "a80ecf9f-f465-4ae5-a429-e30ec5d0f957",
|
||||
"nodeName" : "开始",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "380,220|380,220",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "a80ecf9f-f465-4ae5-a429-e30ec5d0f957",
|
||||
"nextNodeCode" : "b7bbb571-06de-455c-8083-f83c07bf0b99",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "400,220;470,220"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "b7bbb571-06de-455c-8083-f83c07bf0b99",
|
||||
"nodeName" : "申请人",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "520,220|520,220",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "b7bbb571-06de-455c-8083-f83c07bf0b99",
|
||||
"nextNodeCode" : "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "570,220;655,220"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 4,
|
||||
"nodeCode" : "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "680,220",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
|
||||
"nextNodeCode" : "4b7743cd-940c-431b-926f-e7b614fbf1fe",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "680,195;680,140;750,140"
|
||||
}, {
|
||||
"nowNodeCode" : "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
|
||||
"nextNodeCode" : "762cb975-37d8-4276-b6db-79a4c3606394",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "680,245;680,300;750,300"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "4b7743cd-940c-431b-926f-e7b614fbf1fe",
|
||||
"nodeName" : "市场部",
|
||||
"permissionFlag" : "role:1",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "800,140|800,140",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "4b7743cd-940c-431b-926f-e7b614fbf1fe",
|
||||
"nextNodeCode" : "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "850,140;920,140;920,195"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 4,
|
||||
"nodeCode" : "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "920,220",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
|
||||
"nextNodeCode" : "23e7429e-2b47-4431-b93e-40db7c431ce6",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "945,220;975,220;975,220;960,220;960,220;990,220"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "23e7429e-2b47-4431-b93e-40db7c431ce6",
|
||||
"nodeName" : "CEO",
|
||||
"permissionFlag" : "1",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "1040,220|1040,220",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "23e7429e-2b47-4431-b93e-40db7c431ce6",
|
||||
"nextNodeCode" : "f5ace37f-5a5e-4e64-a6f6-913ab9a71cd1",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "1090,220;1140,220"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 2,
|
||||
"nodeCode" : "f5ace37f-5a5e-4e64-a6f6-913ab9a71cd1",
|
||||
"nodeName" : "结束",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "1160,220|1160,220",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]"
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "762cb975-37d8-4276-b6db-79a4c3606394",
|
||||
"nodeName" : "综合部",
|
||||
"permissionFlag" : "role:3@@role:4",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "800,300|800,300",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "762cb975-37d8-4276-b6db-79a4c3606394",
|
||||
"nextNodeCode" : "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "850,300;920,300;920,245"
|
||||
} ]
|
||||
} ]
|
||||
}
|
||||
|
||||
@@ -1,154 +1,90 @@
|
||||
{
|
||||
"nodeList": [
|
||||
{
|
||||
"nodeType": "0",
|
||||
"nodeCode": "9ce8bf00-f25b-4fc6-91b8-827082fc4876",
|
||||
"nodeName": "开始",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "320,240|320,240",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "9ce8bf00-f25b-4fc6-91b8-827082fc4876",
|
||||
"nextNodeCode": "e90b98ef-35b4-410c-a663-bae8b7624b9f",
|
||||
"coordinate": "340,240;410,240"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "e90b98ef-35b4-410c-a663-bae8b7624b9f",
|
||||
"nodeName": "申请人",
|
||||
"permissionFlag": "",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]",
|
||||
"coordinate": "460,240|460,240",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "e90b98ef-35b4-410c-a663-bae8b7624b9f",
|
||||
"nextNodeCode": "768b5b1a-6726-4d67-8853-4cc70d5b1045",
|
||||
"coordinate": "510,240;590,240"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "768b5b1a-6726-4d67-8853-4cc70d5b1045",
|
||||
"nodeName": "百分之60通过",
|
||||
"permissionFlag": "${userList}",
|
||||
"nodeRatio": "60.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,addSign,subSign\"}]",
|
||||
"coordinate": "640,240|640,240",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "768b5b1a-6726-4d67-8853-4cc70d5b1045",
|
||||
"nextNodeCode": "2f9f2e21-9bcf-42a3-a07c-13037aad22d1",
|
||||
"coordinate": "690,240;770,240"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "2f9f2e21-9bcf-42a3-a07c-13037aad22d1",
|
||||
"nodeName": "全部审批通过",
|
||||
"permissionFlag": "role:1@@role:3",
|
||||
"nodeRatio": "100.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,addSign,subSign\"}]",
|
||||
"coordinate": "820,240|820,240",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "2f9f2e21-9bcf-42a3-a07c-13037aad22d1",
|
||||
"nextNodeCode": "27461e01-3d9f-4530-8fe3-bd5ec7f9571f",
|
||||
"coordinate": "870,240;950,240"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "27461e01-3d9f-4530-8fe3-bd5ec7f9571f",
|
||||
"nodeName": "CEO",
|
||||
"permissionFlag": "1",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
|
||||
"coordinate": "1000,240|1000,240",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "27461e01-3d9f-4530-8fe3-bd5ec7f9571f",
|
||||
"nextNodeCode": "b62b88c3-8d8d-4969-911e-2aaea219e7fc",
|
||||
"coordinate": "1050,240;1080,240;1080,240;1070,240;1070,240;1100,240"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "2",
|
||||
"nodeCode": "b62b88c3-8d8d-4969-911e-2aaea219e7fc",
|
||||
"nodeName": "结束",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "1120,240|1120,240",
|
||||
"version": "1",
|
||||
"skipList": []
|
||||
}
|
||||
],
|
||||
"flowCode": "leave4",
|
||||
"flowName": "请假申请-会签",
|
||||
"modelValue": "CLASSICS",
|
||||
"category": "103",
|
||||
"version": "1",
|
||||
"formCustom": "N",
|
||||
"formPath": "/workflow/leaveEdit/index",
|
||||
"listenerType": null,
|
||||
"listenerPath": null
|
||||
"flowCode" : "leave4",
|
||||
"flowName" : "请假申请-会签",
|
||||
"category" : "100",
|
||||
"version" : "1",
|
||||
"formCustom" : "N",
|
||||
"formPath" : "/workflow/leaveEdit/index",
|
||||
"nodeList" : [ {
|
||||
"nodeType" : 0,
|
||||
"nodeCode" : "9ce8bf00-f25b-4fc6-91b8-827082fc4876",
|
||||
"nodeName" : "开始",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "320,240|320,240",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "9ce8bf00-f25b-4fc6-91b8-827082fc4876",
|
||||
"nextNodeCode" : "e90b98ef-35b4-410c-a663-bae8b7624b9f",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "340,240;410,240"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "e90b98ef-35b4-410c-a663-bae8b7624b9f",
|
||||
"nodeName" : "申请人",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "460,240|460,240",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "e90b98ef-35b4-410c-a663-bae8b7624b9f",
|
||||
"nextNodeCode" : "768b5b1a-6726-4d67-8853-4cc70d5b1045",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "510,240;590,240"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "768b5b1a-6726-4d67-8853-4cc70d5b1045",
|
||||
"nodeName" : "百分之60通过",
|
||||
"permissionFlag" : "${userList}",
|
||||
"nodeRatio" : 60.000,
|
||||
"coordinate" : "640,240|640,240",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "768b5b1a-6726-4d67-8853-4cc70d5b1045",
|
||||
"nextNodeCode" : "2f9f2e21-9bcf-42a3-a07c-13037aad22d1",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "690,240;770,240"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "2f9f2e21-9bcf-42a3-a07c-13037aad22d1",
|
||||
"nodeName" : "全部审批通过",
|
||||
"permissionFlag" : "role:1@@role:3",
|
||||
"nodeRatio" : 100.000,
|
||||
"coordinate" : "820,240|820,240",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "2f9f2e21-9bcf-42a3-a07c-13037aad22d1",
|
||||
"nextNodeCode" : "27461e01-3d9f-4530-8fe3-bd5ec7f9571f",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "870,240;950,240"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "27461e01-3d9f-4530-8fe3-bd5ec7f9571f",
|
||||
"nodeName" : "CEO",
|
||||
"permissionFlag" : "1",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "1000,240|1000,240",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "27461e01-3d9f-4530-8fe3-bd5ec7f9571f",
|
||||
"nextNodeCode" : "b62b88c3-8d8d-4969-911e-2aaea219e7fc",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "1050,240;1080,240;1080,240;1070,240;1070,240;1100,240"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 2,
|
||||
"nodeCode" : "b62b88c3-8d8d-4969-911e-2aaea219e7fc",
|
||||
"nodeName" : "结束",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "1120,240|1120,240",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]"
|
||||
} ]
|
||||
}
|
||||
|
||||
@@ -1,211 +1,121 @@
|
||||
{
|
||||
"nodeList": [
|
||||
{
|
||||
"nodeType": "0",
|
||||
"nodeCode": "ebebaf26-9cb6-497e-8119-4c9fed4c597c",
|
||||
"nodeName": "开始",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "300,220|300,220",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "ebebaf26-9cb6-497e-8119-4c9fed4c597c",
|
||||
"nextNodeCode": "e1b04e96-dc81-4858-a309-2fe945d2f374",
|
||||
"coordinate": "320,220;350,220;350,220;340,220;340,220;370,220"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "e1b04e96-dc81-4858-a309-2fe945d2f374",
|
||||
"nodeName": "申请人",
|
||||
"permissionFlag": "",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]",
|
||||
"coordinate": "420,220|420,220",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "e1b04e96-dc81-4858-a309-2fe945d2f374",
|
||||
"nextNodeCode": "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
|
||||
"coordinate": "470,220;535,220"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "4",
|
||||
"nodeCode": "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "560,220",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
|
||||
"nextNodeCode": "c80f273e-1f17-4bd8-9ad1-04a4a94ea862",
|
||||
"coordinate": "560,245;560,320;650,320"
|
||||
},
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
|
||||
"nextNodeCode": "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4",
|
||||
"coordinate": "560,195;560,120;650,120"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "c80f273e-1f17-4bd8-9ad1-04a4a94ea862",
|
||||
"nodeName": "会签",
|
||||
"permissionFlag": "role:1@@role:3",
|
||||
"nodeRatio": "100.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,addSign,subSign\"}]",
|
||||
"coordinate": "700,320|700,320",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "c80f273e-1f17-4bd8-9ad1-04a4a94ea862",
|
||||
"nextNodeCode": "1a20169e-3d82-4926-a151-e2daad28de1b",
|
||||
"coordinate": "750,320;860,320;860,245"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "4",
|
||||
"nodeCode": "1a20169e-3d82-4926-a151-e2daad28de1b",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "860,220",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "1a20169e-3d82-4926-a151-e2daad28de1b",
|
||||
"nextNodeCode": "7a8f0473-e409-442e-a843-5c2b813d00e9",
|
||||
"coordinate": "885,220;950,220"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "7a8f0473-e409-442e-a843-5c2b813d00e9",
|
||||
"nodeName": "CEO",
|
||||
"permissionFlag": "1",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
|
||||
"coordinate": "1000,220|1000,220",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "7a8f0473-e409-442e-a843-5c2b813d00e9",
|
||||
"nextNodeCode": "03c4d2bc-58b5-4408-a2e4-65afb046f169",
|
||||
"coordinate": "1050,220;1120,220"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "2",
|
||||
"nodeCode": "03c4d2bc-58b5-4408-a2e4-65afb046f169",
|
||||
"nodeName": "结束",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "1140,220|1140,220",
|
||||
"version": "1",
|
||||
"skipList": []
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4",
|
||||
"nodeName": "百分之60票签",
|
||||
"permissionFlag": "${userList}",
|
||||
"nodeRatio": "60.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,addSign,subSign\"}]",
|
||||
"coordinate": "700,120|700,120",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4",
|
||||
"nextNodeCode": "1a20169e-3d82-4926-a151-e2daad28de1b",
|
||||
"nextNodeType": "4",
|
||||
"coordinate": "750,120;860,120;860,195"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"flowCode": "leave5",
|
||||
"flowName": "请假申请-并行会签网关",
|
||||
"modelValue": "CLASSICS",
|
||||
"category": "103",
|
||||
"version": "1",
|
||||
"formCustom": "N",
|
||||
"formPath": "/workflow/leaveEdit/index",
|
||||
"listenerType": null,
|
||||
"listenerPath": null
|
||||
"flowCode" : "leave5",
|
||||
"flowName" : "请假申请-并行会签网关",
|
||||
"category" : "100",
|
||||
"version" : "1",
|
||||
"formCustom" : "N",
|
||||
"formPath" : "/workflow/leaveEdit/index",
|
||||
"nodeList" : [ {
|
||||
"nodeType" : 0,
|
||||
"nodeCode" : "ebebaf26-9cb6-497e-8119-4c9fed4c597c",
|
||||
"nodeName" : "开始",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "300,220|300,220",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "ebebaf26-9cb6-497e-8119-4c9fed4c597c",
|
||||
"nextNodeCode" : "e1b04e96-dc81-4858-a309-2fe945d2f374",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "320,220;350,220;350,220;340,220;340,220;370,220"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "e1b04e96-dc81-4858-a309-2fe945d2f374",
|
||||
"nodeName" : "申请人",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "420,220|420,220",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "e1b04e96-dc81-4858-a309-2fe945d2f374",
|
||||
"nextNodeCode" : "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "470,220;535,220"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 4,
|
||||
"nodeCode" : "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "560,220",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
|
||||
"nextNodeCode" : "c80f273e-1f17-4bd8-9ad1-04a4a94ea862",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "560,245;560,320;650,320"
|
||||
}, {
|
||||
"nowNodeCode" : "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
|
||||
"nextNodeCode" : "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "560,195;560,120;650,120"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "c80f273e-1f17-4bd8-9ad1-04a4a94ea862",
|
||||
"nodeName" : "会签",
|
||||
"permissionFlag" : "role:1@@role:3",
|
||||
"nodeRatio" : 100.000,
|
||||
"coordinate" : "700,320|700,320",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "c80f273e-1f17-4bd8-9ad1-04a4a94ea862",
|
||||
"nextNodeCode" : "1a20169e-3d82-4926-a151-e2daad28de1b",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "750,320;860,320;860,245"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 4,
|
||||
"nodeCode" : "1a20169e-3d82-4926-a151-e2daad28de1b",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "860,220",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "1a20169e-3d82-4926-a151-e2daad28de1b",
|
||||
"nextNodeCode" : "7a8f0473-e409-442e-a843-5c2b813d00e9",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "885,220;950,220"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "7a8f0473-e409-442e-a843-5c2b813d00e9",
|
||||
"nodeName" : "CEO",
|
||||
"permissionFlag" : "1",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "1000,220|1000,220",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "7a8f0473-e409-442e-a843-5c2b813d00e9",
|
||||
"nextNodeCode" : "03c4d2bc-58b5-4408-a2e4-65afb046f169",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "1050,220;1120,220"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 2,
|
||||
"nodeCode" : "03c4d2bc-58b5-4408-a2e4-65afb046f169",
|
||||
"nodeName" : "结束",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "1140,220|1140,220",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]"
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4",
|
||||
"nodeName" : "百分之60票签",
|
||||
"permissionFlag" : "${userList}",
|
||||
"nodeRatio" : 60.000,
|
||||
"coordinate" : "700,120|700,120",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4",
|
||||
"nextNodeCode" : "1a20169e-3d82-4926-a151-e2daad28de1b",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "750,120;860,120;860,195"
|
||||
} ]
|
||||
} ]
|
||||
}
|
||||
|
||||
@@ -1,368 +1,215 @@
|
||||
{
|
||||
"nodeList": [
|
||||
{
|
||||
"nodeType": "0",
|
||||
"nodeCode": "122b89a5-7c6f-40a3-aa09-7a263f902054",
|
||||
"nodeName": "开始",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "240,300|240,300",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "122b89a5-7c6f-40a3-aa09-7a263f902054",
|
||||
"nextNodeCode": "c25a0e86-fdd1-4f03-8e22-14db70389dbd",
|
||||
"coordinate": "260,300;350,300"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "c25a0e86-fdd1-4f03-8e22-14db70389dbd",
|
||||
"nodeName": "申请人",
|
||||
"permissionFlag": "",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]",
|
||||
"coordinate": "400,300|400,300",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "c25a0e86-fdd1-4f03-8e22-14db70389dbd",
|
||||
"nextNodeCode": "07ecda1d-7a0a-47b5-8a91-6186c9473742",
|
||||
"coordinate": "450,300;510,300"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "2bfa3919-78cf-4bc1-b59b-df463a4546f9",
|
||||
"nodeName": "副经理",
|
||||
"permissionFlag": "role:1@@role:3@@role:4",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
|
||||
"coordinate": "860,200|860,200",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "2bfa3919-78cf-4bc1-b59b-df463a4546f9",
|
||||
"nextNodeCode": "394e1cc8-b8b2-4189-9f81-44448e88ac32",
|
||||
"coordinate": "910,200;1000,200;1000,275"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "ec17f60e-94e0-4d96-a3ce-3417e9d32d60",
|
||||
"nodeName": "组长",
|
||||
"permissionFlag": "1",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
|
||||
"coordinate": "860,400|860,400",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "ec17f60e-94e0-4d96-a3ce-3417e9d32d60",
|
||||
"nextNodeCode": "394e1cc8-b8b2-4189-9f81-44448e88ac32",
|
||||
"coordinate": "910,400;1000,400;1000,325"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "07ecda1d-7a0a-47b5-8a91-6186c9473742",
|
||||
"nodeName": "副组长",
|
||||
"permissionFlag": "1",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,transfer,copy,pop\"}]",
|
||||
"coordinate": "560,300|560,300",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "07ecda1d-7a0a-47b5-8a91-6186c9473742",
|
||||
"nextNodeCode": "48117e2c-6328-406b-b102-c4a9d115bb13",
|
||||
"coordinate": "610,300;675,300"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "3",
|
||||
"nodeCode": "48117e2c-6328-406b-b102-c4a9d115bb13",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "700,300",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": "default@@${leaveDays > 2}",
|
||||
"skipName": "大于两天",
|
||||
"nowNodeCode": "48117e2c-6328-406b-b102-c4a9d115bb13",
|
||||
"nextNodeCode": "2bfa3919-78cf-4bc1-b59b-df463a4546f9",
|
||||
"nextNodeType": "1",
|
||||
"coordinate": "700,275;700,200;810,200|700,237"
|
||||
},
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": "spel@@#{@testLeaveServiceImpl.eval(#leaveDays)}",
|
||||
"skipName": null,
|
||||
"nowNodeCode": "48117e2c-6328-406b-b102-c4a9d115bb13",
|
||||
"nextNodeCode": "ec17f60e-94e0-4d96-a3ce-3417e9d32d60",
|
||||
"nextNodeType": "1",
|
||||
"coordinate": "700,325;700,400;810,400"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "3",
|
||||
"nodeCode": "394e1cc8-b8b2-4189-9f81-44448e88ac32",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "1000,300",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "394e1cc8-b8b2-4189-9f81-44448e88ac32",
|
||||
"nextNodeCode": "9c93a195-cff2-4e17-ab0a-a4f264191496",
|
||||
"coordinate": "1025,300;1130,300"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "9c93a195-cff2-4e17-ab0a-a4f264191496",
|
||||
"nodeName": "经理会签",
|
||||
"permissionFlag": "1@@3",
|
||||
"nodeRatio": "100.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,pop,addSign,subSign\"}]",
|
||||
"coordinate": "1180,300|1180,300",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "9c93a195-cff2-4e17-ab0a-a4f264191496",
|
||||
"nextNodeCode": "a1a42056-afd1-4e90-88bc-36cbf5a66992",
|
||||
"coordinate": "1230,300;1315,300"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "4",
|
||||
"nodeCode": "a1a42056-afd1-4e90-88bc-36cbf5a66992",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "1340,300",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "a1a42056-afd1-4e90-88bc-36cbf5a66992",
|
||||
"nextNodeCode": "fcfdd9f6-f526-4c1a-b71d-88afa31aebc5",
|
||||
"coordinate": "1340,325;1340,400;1430,400"
|
||||
},
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "a1a42056-afd1-4e90-88bc-36cbf5a66992",
|
||||
"nextNodeCode": "350dfa0c-a77c-4efa-8527-10efa02d8be4",
|
||||
"coordinate": "1340,275;1340,200;1430,200"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "350dfa0c-a77c-4efa-8527-10efa02d8be4",
|
||||
"nodeName": "总经理",
|
||||
"permissionFlag": "3@@1",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
|
||||
"coordinate": "1480,200|1480,200",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "350dfa0c-a77c-4efa-8527-10efa02d8be4",
|
||||
"nextNodeCode": "c36a46ef-04f9-463f-bad7-4b395c818519",
|
||||
"coordinate": "1530,200;1640,200;1640,275"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "fcfdd9f6-f526-4c1a-b71d-88afa31aebc5",
|
||||
"nodeName": "副总经理",
|
||||
"permissionFlag": "1@@3",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
|
||||
"coordinate": "1480,400|1480,400",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "fcfdd9f6-f526-4c1a-b71d-88afa31aebc5",
|
||||
"nextNodeCode": "c36a46ef-04f9-463f-bad7-4b395c818519",
|
||||
"coordinate": "1530,400;1640,400;1640,325"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "4",
|
||||
"nodeCode": "c36a46ef-04f9-463f-bad7-4b395c818519",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "1640,300",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "c36a46ef-04f9-463f-bad7-4b395c818519",
|
||||
"nextNodeCode": "3fcea762-b53a-4ae1-8365-7bec90444828",
|
||||
"coordinate": "1665,300;1770,300"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "1",
|
||||
"nodeCode": "3fcea762-b53a-4ae1-8365-7bec90444828",
|
||||
"nodeName": "董事",
|
||||
"permissionFlag": "1",
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": "",
|
||||
"listenerPath": "",
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
|
||||
"coordinate": "1820,300|1820,300",
|
||||
"version": "1",
|
||||
"skipList": [
|
||||
{
|
||||
"skipType": "PASS",
|
||||
"skipCondition": null,
|
||||
"skipName": null,
|
||||
"nowNodeCode": "3fcea762-b53a-4ae1-8365-7bec90444828",
|
||||
"nextNodeCode": "9cfbfd3e-6c04-41d6-9fc2-6787a7d2cd31",
|
||||
"coordinate": "1870,300;1960,300"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nodeType": "2",
|
||||
"nodeCode": "9cfbfd3e-6c04-41d6-9fc2-6787a7d2cd31",
|
||||
"nodeName": "结束",
|
||||
"permissionFlag": null,
|
||||
"nodeRatio": "0.000",
|
||||
"anyNodeSkip": null,
|
||||
"listenerType": null,
|
||||
"listenerPath": null,
|
||||
"formCustom": "N",
|
||||
"formPath": null,
|
||||
"ext": "[]",
|
||||
"coordinate": "1980,300|1980,300",
|
||||
"version": "1",
|
||||
"skipList": []
|
||||
}
|
||||
],
|
||||
"flowCode": "leave6",
|
||||
"flowName": "请假申请-排他并行会签",
|
||||
"modelValue": "CLASSICS",
|
||||
"category": "103",
|
||||
"version": "1",
|
||||
"formCustom": "N",
|
||||
"formPath": "/workflow/leaveEdit/index",
|
||||
"listenerType": null,
|
||||
"listenerPath": null
|
||||
"flowCode" : "leave6",
|
||||
"flowName" : "请假申请-排他并行会签",
|
||||
"category" : "100",
|
||||
"version" : "1",
|
||||
"formCustom" : "N",
|
||||
"formPath" : "/workflow/leaveEdit/index",
|
||||
"nodeList" : [ {
|
||||
"nodeType" : 0,
|
||||
"nodeCode" : "122b89a5-7c6f-40a3-aa09-7a263f902054",
|
||||
"nodeName" : "开始",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "240,300|240,300",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "122b89a5-7c6f-40a3-aa09-7a263f902054",
|
||||
"nextNodeCode" : "c25a0e86-fdd1-4f03-8e22-14db70389dbd",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "260,300;350,300"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "c25a0e86-fdd1-4f03-8e22-14db70389dbd",
|
||||
"nodeName" : "申请人",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "400,300|400,300",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "c25a0e86-fdd1-4f03-8e22-14db70389dbd",
|
||||
"nextNodeCode" : "07ecda1d-7a0a-47b5-8a91-6186c9473742",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "450,300;510,300"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "2bfa3919-78cf-4bc1-b59b-df463a4546f9",
|
||||
"nodeName" : "副经理",
|
||||
"permissionFlag" : "role:1@@role:3@@role:4",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "860,200|860,200",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "2bfa3919-78cf-4bc1-b59b-df463a4546f9",
|
||||
"nextNodeCode" : "394e1cc8-b8b2-4189-9f81-44448e88ac32",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "910,200;1000,200;1000,275"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "ec17f60e-94e0-4d96-a3ce-3417e9d32d60",
|
||||
"nodeName" : "组长",
|
||||
"permissionFlag" : "1",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "860,400|860,400",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "ec17f60e-94e0-4d96-a3ce-3417e9d32d60",
|
||||
"nextNodeCode" : "394e1cc8-b8b2-4189-9f81-44448e88ac32",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "910,400;1000,400;1000,325"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "07ecda1d-7a0a-47b5-8a91-6186c9473742",
|
||||
"nodeName" : "副组长",
|
||||
"permissionFlag" : "1",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "560,300|560,300",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,transfer,copy,pop\"}]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "07ecda1d-7a0a-47b5-8a91-6186c9473742",
|
||||
"nextNodeCode" : "48117e2c-6328-406b-b102-c4a9d115bb13",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "610,300;675,300"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 3,
|
||||
"nodeCode" : "48117e2c-6328-406b-b102-c4a9d115bb13",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "700,300",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "48117e2c-6328-406b-b102-c4a9d115bb13",
|
||||
"nextNodeCode" : "2bfa3919-78cf-4bc1-b59b-df463a4546f9",
|
||||
"skipName" : "大于两天",
|
||||
"skipType" : "PASS",
|
||||
"skipCondition" : "default@@${leaveDays > 2}",
|
||||
"coordinate" : "700,275;700,200;810,200|700,237"
|
||||
}, {
|
||||
"nowNodeCode" : "48117e2c-6328-406b-b102-c4a9d115bb13",
|
||||
"nextNodeCode" : "ec17f60e-94e0-4d96-a3ce-3417e9d32d60",
|
||||
"skipType" : "PASS",
|
||||
"skipCondition" : "spel@@#{@testLeaveServiceImpl.eval(#leaveDays)}",
|
||||
"coordinate" : "700,325;700,400;810,400"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 3,
|
||||
"nodeCode" : "394e1cc8-b8b2-4189-9f81-44448e88ac32",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "1000,300",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "394e1cc8-b8b2-4189-9f81-44448e88ac32",
|
||||
"nextNodeCode" : "9c93a195-cff2-4e17-ab0a-a4f264191496",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "1025,300;1130,300"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "9c93a195-cff2-4e17-ab0a-a4f264191496",
|
||||
"nodeName" : "经理会签",
|
||||
"permissionFlag" : "1@@3",
|
||||
"nodeRatio" : 100.000,
|
||||
"coordinate" : "1180,300|1180,300",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,pop,addSign,subSign\"}]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "9c93a195-cff2-4e17-ab0a-a4f264191496",
|
||||
"nextNodeCode" : "a1a42056-afd1-4e90-88bc-36cbf5a66992",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "1230,300;1315,300"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 4,
|
||||
"nodeCode" : "a1a42056-afd1-4e90-88bc-36cbf5a66992",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "1340,300",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "a1a42056-afd1-4e90-88bc-36cbf5a66992",
|
||||
"nextNodeCode" : "fcfdd9f6-f526-4c1a-b71d-88afa31aebc5",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "1340,325;1340,400;1430,400"
|
||||
}, {
|
||||
"nowNodeCode" : "a1a42056-afd1-4e90-88bc-36cbf5a66992",
|
||||
"nextNodeCode" : "350dfa0c-a77c-4efa-8527-10efa02d8be4",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "1340,275;1340,200;1430,200"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "350dfa0c-a77c-4efa-8527-10efa02d8be4",
|
||||
"nodeName" : "总经理",
|
||||
"permissionFlag" : "3@@1",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "1480,200|1480,200",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "350dfa0c-a77c-4efa-8527-10efa02d8be4",
|
||||
"nextNodeCode" : "c36a46ef-04f9-463f-bad7-4b395c818519",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "1530,200;1640,200;1640,275"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "fcfdd9f6-f526-4c1a-b71d-88afa31aebc5",
|
||||
"nodeName" : "副总经理",
|
||||
"permissionFlag" : "1@@3",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "1480,400|1480,400",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "fcfdd9f6-f526-4c1a-b71d-88afa31aebc5",
|
||||
"nextNodeCode" : "c36a46ef-04f9-463f-bad7-4b395c818519",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "1530,400;1640,400;1640,325"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 4,
|
||||
"nodeCode" : "c36a46ef-04f9-463f-bad7-4b395c818519",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "1640,300",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "c36a46ef-04f9-463f-bad7-4b395c818519",
|
||||
"nextNodeCode" : "3fcea762-b53a-4ae1-8365-7bec90444828",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "1665,300;1770,300"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 1,
|
||||
"nodeCode" : "3fcea762-b53a-4ae1-8365-7bec90444828",
|
||||
"nodeName" : "董事",
|
||||
"permissionFlag" : "1",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "1820,300|1820,300",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
|
||||
"skipList" : [ {
|
||||
"nowNodeCode" : "3fcea762-b53a-4ae1-8365-7bec90444828",
|
||||
"nextNodeCode" : "9cfbfd3e-6c04-41d6-9fc2-6787a7d2cd31",
|
||||
"skipType" : "PASS",
|
||||
"coordinate" : "1870,300;1960,300"
|
||||
} ]
|
||||
}, {
|
||||
"nodeType" : 2,
|
||||
"nodeCode" : "9cfbfd3e-6c04-41d6-9fc2-6787a7d2cd31",
|
||||
"nodeName" : "结束",
|
||||
"nodeRatio" : 0.000,
|
||||
"coordinate" : "1980,300|1980,300",
|
||||
"formCustom" : "N",
|
||||
"ext" : "[]"
|
||||
} ]
|
||||
}
|
||||
|
||||
@@ -17,9 +17,7 @@ create table FLOW_DEFINITION
|
||||
LISTENER_PATH VARCHAR2(500),
|
||||
EXT VARCHAR2(500),
|
||||
CREATE_TIME DATE,
|
||||
CREATE_BY VARCHAR2(64) default '',
|
||||
UPDATE_TIME DATE,
|
||||
UPDATE_BY VARCHAR2(64) default '',
|
||||
DEL_FLAG VARCHAR2(1) default '0',
|
||||
TENANT_ID VARCHAR2(40)
|
||||
);
|
||||
@@ -42,9 +40,7 @@ comment on column FLOW_DEFINITION.LISTENER_TYPE is '监听器类型';
|
||||
comment on column FLOW_DEFINITION.LISTENER_PATH is '监听器路径';
|
||||
comment on column FLOW_DEFINITION.EXT is '扩展字段,预留给业务系统使用';
|
||||
comment on column FLOW_DEFINITION.CREATE_TIME is '创建时间';
|
||||
comment on column FLOW_DEFINITION.CREATE_BY is '创建人';
|
||||
comment on column FLOW_DEFINITION.UPDATE_TIME is '更新时间';
|
||||
comment on column FLOW_DEFINITION.UPDATE_BY is '更新人';
|
||||
comment on column FLOW_DEFINITION.DEL_FLAG is '删除标志';
|
||||
comment on column FLOW_DEFINITION.TENANT_ID is '租户id';
|
||||
|
||||
@@ -55,22 +51,22 @@ create table FLOW_NODE
|
||||
DEFINITION_ID NUMBER(20) not null,
|
||||
NODE_CODE VARCHAR2(100) not null,
|
||||
NODE_NAME VARCHAR2(100),
|
||||
PERMISSION_FLAG VARCHAR2(200),
|
||||
NODE_RATIO VARCHAR2(200),
|
||||
NODE_RATIO NUMBER(6, 3),
|
||||
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),
|
||||
CREATE_TIME DATE,
|
||||
CREATE_BY VARCHAR2(64) default '',
|
||||
UPDATE_TIME DATE,
|
||||
UPDATE_BY VARCHAR2(64) default '',
|
||||
EXT CLOB,
|
||||
DEL_FLAG VARCHAR2(1) default '0',
|
||||
TENANT_ID VARCHAR2(40)
|
||||
TENANT_ID VARCHAR2(40),
|
||||
PERMISSION_FLAG VARCHAR2(200)
|
||||
);
|
||||
|
||||
alter table FLOW_NODE
|
||||
@@ -87,13 +83,13 @@ 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 '版本';
|
||||
comment on column FLOW_NODE.CREATE_TIME is '创建时间';
|
||||
comment on column FLOW_NODE.CREATE_BY is '创建人';
|
||||
comment on column FLOW_NODE.UPDATE_TIME is '更新时间';
|
||||
comment on column FLOW_NODE.UPDATE_BY is '更新人';
|
||||
comment on column FLOW_NODE.EXT is '节点扩展属性';
|
||||
comment on column FLOW_NODE.DEL_FLAG is '删除标志';
|
||||
comment on column FLOW_NODE.TENANT_ID is '租户id';
|
||||
@@ -112,9 +108,7 @@ create table FLOW_SKIP
|
||||
SKIP_CONDITION VARCHAR2(200),
|
||||
COORDINATE VARCHAR2(100),
|
||||
CREATE_TIME DATE,
|
||||
CREATE_BY VARCHAR2(64) default '',
|
||||
UPDATE_TIME DATE,
|
||||
UPDATE_BY VARCHAR2(64) default '',
|
||||
DEL_FLAG VARCHAR2(1) default '0',
|
||||
TENANT_ID VARCHAR2(40)
|
||||
);
|
||||
@@ -134,9 +128,7 @@ comment on column FLOW_SKIP.SKIP_TYPE is '跳转类型 (PASS审批通过 REJECT
|
||||
comment on column FLOW_SKIP.SKIP_CONDITION is '跳转条件';
|
||||
comment on column FLOW_SKIP.COORDINATE is '坐标';
|
||||
comment on column FLOW_SKIP.CREATE_TIME is '创建时间';
|
||||
comment on column FLOW_SKIP.CREATE_BY is '创建人';
|
||||
comment on column FLOW_SKIP.UPDATE_TIME is '更新时间';
|
||||
comment on column FLOW_SKIP.UPDATE_BY is '更新人';
|
||||
comment on column FLOW_SKIP.DEL_FLAG is '删除标志';
|
||||
comment on column FLOW_SKIP.TENANT_ID is '租户id';
|
||||
|
||||
@@ -152,10 +144,9 @@ create table FLOW_INSTANCE
|
||||
FLOW_STATUS VARCHAR2(20),
|
||||
ACTIVITY_STATUS NUMBER(1) default 1,
|
||||
DEF_JSON CLOB,
|
||||
CREATE_TIME DATE,
|
||||
CREATE_BY VARCHAR2(64) default '',
|
||||
CREATE_TIME DATE,
|
||||
UPDATE_TIME DATE,
|
||||
UPDATE_BY VARCHAR2(64) default '',
|
||||
EXT VARCHAR2(500),
|
||||
DEL_FLAG VARCHAR2(1) default '0',
|
||||
TENANT_ID VARCHAR2(40)
|
||||
@@ -175,10 +166,9 @@ comment on column FLOW_INSTANCE.VARIABLE is '任务变量';
|
||||
comment on column FLOW_INSTANCE.FLOW_STATUS is '流程状态(0待提交 1审批中 2审批通过 4终止 5作废 6撤销 8已完成 9已退回 10失效 11拿回)';
|
||||
comment on column FLOW_INSTANCE.ACTIVITY_STATUS is '流程激活状态(0挂起 1激活)';
|
||||
comment on column FLOW_INSTANCE.DEF_JSON is '流程定义json';
|
||||
comment on column FLOW_INSTANCE.CREATE_BY is '创建者';
|
||||
comment on column FLOW_INSTANCE.CREATE_TIME is '创建时间';
|
||||
comment on column FLOW_INSTANCE.CREATE_BY is '创建人';
|
||||
comment on column FLOW_INSTANCE.UPDATE_TIME is '更新时间';
|
||||
comment on column FLOW_INSTANCE.UPDATE_BY is '更新人';
|
||||
comment on column FLOW_INSTANCE.EXT is '扩展字段,预留给业务系统使用';
|
||||
comment on column FLOW_INSTANCE.DEL_FLAG is '删除标志';
|
||||
comment on column FLOW_INSTANCE.TENANT_ID is '租户id';
|
||||
@@ -195,9 +185,7 @@ create table FLOW_TASK
|
||||
FORM_CUSTOM VARCHAR2(1) default 'N',
|
||||
FORM_PATH VARCHAR2(100),
|
||||
CREATE_TIME DATE,
|
||||
CREATE_BY VARCHAR2(64) default '',
|
||||
UPDATE_TIME DATE,
|
||||
UPDATE_BY VARCHAR2(64) default '',
|
||||
DEL_FLAG VARCHAR2(1) default '0',
|
||||
TENANT_ID VARCHAR2(40)
|
||||
);
|
||||
@@ -216,9 +204,7 @@ comment on column FLOW_TASK.FLOW_STATUS is '流程状态(0待提交 1审批中
|
||||
comment on column FLOW_TASK.FORM_CUSTOM is '审批表单是否自定义 (Y是 N否)';
|
||||
comment on column FLOW_TASK.FORM_PATH is '审批表单路径';
|
||||
comment on column FLOW_TASK.CREATE_TIME is '创建时间';
|
||||
comment on column FLOW_TASK.CREATE_BY is '创建人';
|
||||
comment on column FLOW_TASK.UPDATE_TIME is '更新时间';
|
||||
comment on column FLOW_TASK.UPDATE_BY is '更新人';
|
||||
comment on column FLOW_TASK.DEL_FLAG is '删除标志';
|
||||
comment on column FLOW_TASK.TENANT_ID is '租户id';
|
||||
|
||||
@@ -285,9 +271,8 @@ create table FLOW_USER
|
||||
PROCESSED_BY VARCHAR2(80),
|
||||
ASSOCIATED NUMBER(20) not null,
|
||||
CREATE_TIME DATE,
|
||||
CREATE_BY VARCHAR2(64) default '',
|
||||
CREATE_BY VARCHAR2(80),
|
||||
UPDATE_TIME DATE,
|
||||
UPDATE_BY VARCHAR2(64) default '',
|
||||
DEL_FLAG VARCHAR2(1) default '0',
|
||||
TENANT_ID VARCHAR2(40)
|
||||
);
|
||||
@@ -301,9 +286,8 @@ comment on column FLOW_USER.TYPE is '人员类型(1待办任务的审批人权
|
||||
comment on column FLOW_USER.PROCESSED_BY is '权限人)';
|
||||
comment on column FLOW_USER.ASSOCIATED is '任务表id';
|
||||
comment on column FLOW_USER.CREATE_TIME is '创建时间';
|
||||
comment on column FLOW_USER.CREATE_BY is '创建人';
|
||||
comment on column FLOW_USER.CREATE_BY is '节点名称';
|
||||
comment on column FLOW_USER.UPDATE_TIME is '更新时间';
|
||||
comment on column FLOW_USER.UPDATE_BY is '更新人';
|
||||
comment on column FLOW_USER.DEL_FLAG is '删除标志';
|
||||
comment on column FLOW_USER.TENANT_ID is '租户id';
|
||||
|
||||
@@ -315,18 +299,18 @@ create index USER_ASSOCIATED_IDX on FLOW_USER (ASSOCIATED);
|
||||
-- ----------------------------
|
||||
CREATE TABLE flow_category
|
||||
(
|
||||
category_id NUMBER(20) NOT NULL,
|
||||
tenant_id VARCHAR2(20) DEFAULT '000000',
|
||||
parent_id NUMBER(20) DEFAULT 0,
|
||||
ancestors VARCHAR2(500) DEFAULT '',
|
||||
category_name VARCHAR2(30) NOT NULL,
|
||||
order_num NUMBER(4) DEFAULT 0,
|
||||
del_flag CHAR(1) DEFAULT '0',
|
||||
create_dept NUMBER(20),
|
||||
create_by NUMBER(20),
|
||||
create_time DATE,
|
||||
update_by NUMBER(20),
|
||||
update_time DATE
|
||||
category_id NUMBER (20) NOT NULL,
|
||||
tenant_id VARCHAR2 (20) DEFAULT '000000',
|
||||
parent_id NUMBER (20) DEFAULT 0,
|
||||
ancestors VARCHAR2 (500) DEFAULT '',
|
||||
category_name VARCHAR2 (30) NOT NULL,
|
||||
order_num NUMBER (4) DEFAULT 0,
|
||||
del_flag CHAR(1) DEFAULT '0',
|
||||
create_dept NUMBER (20),
|
||||
create_by NUMBER (20),
|
||||
create_time DATE,
|
||||
update_by NUMBER (20),
|
||||
update_time DATE
|
||||
);
|
||||
|
||||
alter table flow_category add constraint pk_flow_category primary key (category_id);
|
||||
@@ -360,19 +344,19 @@ INSERT INTO flow_category VALUES (109, '000000', 102, '0,100,102', '离职', 2,
|
||||
-- 流程spel表达式定义表
|
||||
-- ----------------------------
|
||||
CREATE TABLE flow_spel (
|
||||
id NUMBER(20) NOT NULL,
|
||||
component_name VARCHAR2(255),
|
||||
method_name VARCHAR2(255),
|
||||
method_params VARCHAR2(255),
|
||||
view_spel VARCHAR2(255),
|
||||
remark VARCHAR2(255),
|
||||
status CHAR(1) DEFAULT '0',
|
||||
del_flag CHAR(1) DEFAULT '0',
|
||||
create_dept NUMBER(20),
|
||||
create_by NUMBER(20),
|
||||
create_time DATE,
|
||||
update_by NUMBER(20),
|
||||
update_time DATE
|
||||
id NUMBER(20) NOT NULL,
|
||||
component_name VARCHAR2(255),
|
||||
method_name VARCHAR2(255),
|
||||
method_params VARCHAR2(255),
|
||||
view_spel VARCHAR2(255),
|
||||
remark VARCHAR2(255),
|
||||
status CHAR(1) DEFAULT '0',
|
||||
del_flag CHAR(1) DEFAULT '0',
|
||||
create_dept NUMBER(20),
|
||||
create_by NUMBER(20),
|
||||
create_time DATE,
|
||||
update_by NUMBER(20),
|
||||
update_time DATE
|
||||
);
|
||||
|
||||
alter table flow_spel add constraint pk_flow_spel primary key (id);
|
||||
@@ -434,19 +418,19 @@ COMMENT ON COLUMN flow_instance_biz_ext.business_id IS '业务Id';
|
||||
-- ----------------------------
|
||||
CREATE TABLE test_leave
|
||||
(
|
||||
id NUMBER (20) NOT NULL,
|
||||
tenant_id VARCHAR2 (20) DEFAULT '000000',
|
||||
apply_code VARCHAR2 (50) NOT NULL,
|
||||
leave_type VARCHAR2 (255) NOT NULL,
|
||||
id NUMBER (20) NOT NULL,
|
||||
tenant_id VARCHAR2 (20) DEFAULT '000000',
|
||||
apply_code VARCHAR2 (50) NOT NULL,
|
||||
leave_type VARCHAR2 (255) NOT NULL,
|
||||
start_date DATE NOT NULL,
|
||||
end_date DATE NOT NULL,
|
||||
leave_days NUMBER (10) NOT NULL,
|
||||
remark VARCHAR2 (255),
|
||||
status VARCHAR2 (255),
|
||||
leave_days NUMBER (10) NOT NULL,
|
||||
remark VARCHAR2 (255),
|
||||
status VARCHAR2 (255),
|
||||
create_dept NUMBER (20),
|
||||
create_by NUMBER (20),
|
||||
create_by NUMBER (20),
|
||||
create_time DATE,
|
||||
update_by NUMBER (20),
|
||||
update_by NUMBER (20),
|
||||
update_time DATE
|
||||
);
|
||||
|
||||
@@ -489,11 +473,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, '');
|
||||
|
||||
@@ -14,9 +14,7 @@ CREATE TABLE flow_definition
|
||||
listener_path varchar(400) NULL,
|
||||
ext varchar(500) NULL,
|
||||
create_time timestamp NULL,
|
||||
create_by varchar(64) NULL DEFAULT '':: character varying,
|
||||
update_time timestamp NULL,
|
||||
update_by varchar(64) NULL DEFAULT '':: character varying,
|
||||
del_flag bpchar(1) NULL DEFAULT '0':: character varying,
|
||||
tenant_id varchar(40) NULL,
|
||||
CONSTRAINT flow_definition_pkey PRIMARY KEY (id)
|
||||
@@ -37,9 +35,7 @@ COMMENT ON COLUMN flow_definition.listener_type IS '监听器类型';
|
||||
COMMENT ON COLUMN flow_definition.listener_path IS '监听器路径';
|
||||
COMMENT ON COLUMN flow_definition.ext IS '扩展字段,预留给业务系统使用';
|
||||
COMMENT ON COLUMN flow_definition.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN flow_definition.create_by IS '创建人';
|
||||
COMMENT ON COLUMN flow_definition.update_time IS '更新时间';
|
||||
COMMENT ON COLUMN flow_definition.update_by IS '更新人';
|
||||
COMMENT ON COLUMN flow_definition.del_flag IS '删除标志';
|
||||
COMMENT ON COLUMN flow_definition.tenant_id IS '租户id';
|
||||
|
||||
@@ -51,18 +47,18 @@ CREATE TABLE flow_node
|
||||
node_code varchar(100) NOT NULL,
|
||||
node_name varchar(100) NULL,
|
||||
permission_flag varchar(200) NULL,
|
||||
node_ratio varchar(200) NULL,
|
||||
node_ratio numeric(6, 3) 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,
|
||||
create_time timestamp NULL,
|
||||
create_by varchar(64) NULL DEFAULT '':: character varying,
|
||||
update_time timestamp NULL,
|
||||
update_by varchar(64) NULL DEFAULT '':: character varying,
|
||||
create_time timestamp NULL,
|
||||
update_time timestamp NULL,
|
||||
ext text NULL,
|
||||
del_flag bpchar(1) NULL DEFAULT '0':: character varying,
|
||||
tenant_id varchar(40) NULL,
|
||||
@@ -81,13 +77,13 @@ 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 '版本';
|
||||
COMMENT ON COLUMN flow_node.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN flow_node.create_by IS '创建人';
|
||||
COMMENT ON COLUMN flow_node.update_time IS '更新时间';
|
||||
COMMENT ON COLUMN flow_node.update_by IS '更新人';
|
||||
COMMENT ON COLUMN flow_node.ext IS '节点扩展属性';
|
||||
COMMENT ON COLUMN flow_node.del_flag IS '删除标志';
|
||||
COMMENT ON COLUMN flow_node.tenant_id IS '租户id';
|
||||
@@ -106,9 +102,7 @@ CREATE TABLE flow_skip
|
||||
skip_condition varchar(200) NULL,
|
||||
coordinate varchar(100) NULL,
|
||||
create_time timestamp NULL,
|
||||
create_by varchar(64) NULL DEFAULT '':: character varying,
|
||||
update_time timestamp NULL,
|
||||
update_by varchar(64) NULL DEFAULT '':: character varying,
|
||||
del_flag bpchar(1) NULL DEFAULT '0':: character varying,
|
||||
tenant_id varchar(40) NULL,
|
||||
CONSTRAINT flow_skip_pkey PRIMARY KEY (id)
|
||||
@@ -126,9 +120,7 @@ COMMENT ON COLUMN flow_skip.skip_type IS '跳转类型(PASS审批通过 REJECT
|
||||
COMMENT ON COLUMN flow_skip.skip_condition IS '跳转条件';
|
||||
COMMENT ON COLUMN flow_skip.coordinate IS '坐标';
|
||||
COMMENT ON COLUMN flow_skip.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN flow_skip.create_by IS '创建人';
|
||||
COMMENT ON COLUMN flow_skip.update_time IS '更新时间';
|
||||
COMMENT ON COLUMN flow_skip.update_by IS '更新人';
|
||||
COMMENT ON COLUMN flow_skip.del_flag IS '删除标志';
|
||||
COMMENT ON COLUMN flow_skip.tenant_id IS '租户id';
|
||||
|
||||
@@ -144,10 +136,9 @@ CREATE TABLE flow_instance
|
||||
flow_status varchar(20) NOT NULL,
|
||||
activity_status int2 NOT NULL DEFAULT 1,
|
||||
def_json text NULL,
|
||||
create_by varchar(64) NULL DEFAULT '':: character varying,
|
||||
create_time timestamp NULL,
|
||||
create_by varchar(64) NULL DEFAULT '':: character varying,
|
||||
update_time timestamp NULL,
|
||||
update_by varchar(64) NULL DEFAULT '':: character varying,
|
||||
ext varchar(500) NULL,
|
||||
del_flag bpchar(1) NULL DEFAULT '0':: character varying,
|
||||
tenant_id varchar(40) NULL,
|
||||
@@ -165,10 +156,9 @@ COMMENT ON COLUMN flow_instance.variable IS '任务变量';
|
||||
COMMENT ON COLUMN flow_instance.flow_status IS '流程状态(0待提交 1审批中 2审批通过 4终止 5作废 6撤销 8已完成 9已退回 10失效 11拿回)';
|
||||
COMMENT ON COLUMN flow_instance.activity_status IS '流程激活状态(0挂起 1激活)';
|
||||
COMMENT ON COLUMN flow_instance.def_json IS '流程定义json';
|
||||
COMMENT ON COLUMN flow_instance.create_by IS '创建者';
|
||||
COMMENT ON COLUMN flow_instance.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN flow_instance.create_by IS '创建人';
|
||||
COMMENT ON COLUMN flow_instance.update_time IS '更新时间';
|
||||
COMMENT ON COLUMN flow_instance.update_by IS '更新人';
|
||||
COMMENT ON COLUMN flow_instance.ext IS '扩展字段,预留给业务系统使用';
|
||||
COMMENT ON COLUMN flow_instance.del_flag IS '删除标志';
|
||||
COMMENT ON COLUMN flow_instance.tenant_id IS '租户id';
|
||||
@@ -181,13 +171,11 @@ CREATE TABLE flow_task
|
||||
node_code varchar(100) NOT NULL,
|
||||
node_name varchar(100) NULL,
|
||||
node_type int2 NOT NULL,
|
||||
flow_status varchar(20) NOT NULL,
|
||||
flow_status varchar(20) NOT NULL,
|
||||
form_custom bpchar(1) NULL DEFAULT 'N':: character varying,
|
||||
form_path varchar(100) NULL,
|
||||
create_time timestamp NULL,
|
||||
create_by varchar(64) NULL DEFAULT '':: character varying,
|
||||
update_time timestamp NULL,
|
||||
update_by varchar(64) NULL DEFAULT '':: character varying,
|
||||
del_flag bpchar(1) NULL DEFAULT '0':: character varying,
|
||||
tenant_id varchar(40) NULL,
|
||||
CONSTRAINT flow_task_pkey PRIMARY KEY (id)
|
||||
@@ -204,9 +192,7 @@ COMMENT ON COLUMN flow_task.flow_status IS '流程状态(0待提交 1审批中
|
||||
COMMENT ON COLUMN flow_task.form_custom IS '审批表单是否自定义(Y是 N否)';
|
||||
COMMENT ON COLUMN flow_task.form_path IS '审批表单路径';
|
||||
COMMENT ON COLUMN flow_task.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN flow_task.create_by IS '创建人';
|
||||
COMMENT ON COLUMN flow_task.update_time IS '更新时间';
|
||||
COMMENT ON COLUMN flow_task.update_by IS '更新人';
|
||||
COMMENT ON COLUMN flow_task.del_flag IS '删除标志';
|
||||
COMMENT ON COLUMN flow_task.tenant_id IS '租户id';
|
||||
|
||||
@@ -270,9 +256,8 @@ CREATE TABLE flow_user
|
||||
processed_by varchar(80) NULL,
|
||||
associated int8 NOT NULL,
|
||||
create_time timestamp NULL,
|
||||
create_by varchar(64) NULL DEFAULT '':: character varying,
|
||||
create_by varchar(80) NULL,
|
||||
update_time timestamp NULL,
|
||||
update_by varchar(64) NULL DEFAULT '':: character varying,
|
||||
del_flag bpchar(1) NULL DEFAULT '0':: character varying,
|
||||
tenant_id varchar(40) NULL,
|
||||
CONSTRAINT flow_user_pk PRIMARY KEY (id)
|
||||
@@ -288,7 +273,6 @@ COMMENT ON COLUMN flow_user.associated IS '任务表id';
|
||||
COMMENT ON COLUMN flow_user.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN flow_user.create_by IS '创建人';
|
||||
COMMENT ON COLUMN flow_user.update_time IS '更新时间';
|
||||
COMMENT ON COLUMN flow_user.update_by IS '更新人';
|
||||
COMMENT ON COLUMN flow_user.del_flag IS '删除标志';
|
||||
COMMENT ON COLUMN flow_user.tenant_id IS '租户id';
|
||||
|
||||
@@ -467,11 +451,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, '');
|
||||
|
||||
@@ -17,9 +17,7 @@ CREATE TABLE `flow_definition`
|
||||
`listener_path` varchar(400) DEFAULT NULL COMMENT '监听器路径',
|
||||
`ext` varchar(500) DEFAULT NULL COMMENT '业务详情 存业务表对象json字符串',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建人',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新人',
|
||||
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志',
|
||||
`tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
@@ -33,18 +31,18 @@ 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` varchar(200) DEFAULT NULL COMMENT '流程签署比例值',
|
||||
`node_ratio` decimal(6, 3) 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 '版本',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建人',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新人',
|
||||
`ext` text COMMENT '节点扩展属性',
|
||||
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志',
|
||||
`tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id',
|
||||
@@ -64,9 +62,7 @@ CREATE TABLE `flow_skip`
|
||||
`skip_condition` varchar(200) DEFAULT NULL COMMENT '跳转条件',
|
||||
`coordinate` varchar(100) DEFAULT NULL COMMENT '坐标',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建人',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新人',
|
||||
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志',
|
||||
`tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
@@ -84,10 +80,9 @@ CREATE TABLE `flow_instance`
|
||||
`flow_status` varchar(20) NOT NULL COMMENT '流程状态(0待提交 1审批中 2审批通过 4终止 5作废 6撤销 8已完成 9已退回 10失效 11拿回)',
|
||||
`activity_status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '流程激活状态(0挂起 1激活)',
|
||||
`def_json` text COMMENT '流程定义json',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建人',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新人',
|
||||
`ext` varchar(500) DEFAULT NULL COMMENT '扩展字段,预留给业务系统使用',
|
||||
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志',
|
||||
`tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id',
|
||||
@@ -106,9 +101,7 @@ CREATE TABLE `flow_task`
|
||||
`form_custom` char(1) DEFAULT 'N' COMMENT '审批表单是否自定义(Y是 N否)',
|
||||
`form_path` varchar(100) DEFAULT NULL COMMENT '审批表单路径',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建人',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新人',
|
||||
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志',
|
||||
`tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
@@ -125,7 +118,7 @@ CREATE TABLE `flow_his_task`
|
||||
`node_type` tinyint(1) DEFAULT NULL COMMENT '开始节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)',
|
||||
`target_node_code` varchar(200) DEFAULT NULL COMMENT '目标节点编码',
|
||||
`target_node_name` varchar(200) DEFAULT NULL COMMENT '结束节点名称',
|
||||
`approver` varchar(40) DEFAULT NULL COMMENT '审批人',
|
||||
`approver` varchar(40) DEFAULT NULL COMMENT '审批者',
|
||||
`cooperate_type` tinyint(1) NOT NULL DEFAULT '0' COMMENT '协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签)',
|
||||
`collaborator` varchar(500) DEFAULT NULL COMMENT '协作人',
|
||||
`skip_type` varchar(10) NOT NULL COMMENT '流转类型(PASS通过 REJECT退回 NONE无动作)',
|
||||
@@ -152,7 +145,6 @@ CREATE TABLE `flow_user`
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`create_by` varchar(80) DEFAULT NULL COMMENT '创建人',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '创建人',
|
||||
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志',
|
||||
`tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user