Jelajahi Sumber

!779 发布 5.5.1 正式版 日常依赖升级bug修复
Merge pull request !779 from 疯狂的狮子Li/dev

疯狂的狮子Li 8 bulan lalu
induk
melakukan
b58085fde1
55 mengubah file dengan 2435 tambahan dan 917 penghapusan
  1. 1 0
      .gitignore
  2. 1 1
      .run/ruoyi-monitor-admin.run.xml
  3. 1 1
      .run/ruoyi-server.run.xml
  4. 1 1
      .run/ruoyi-snailjob-server.run.xml
  5. 1 1
      README.md
  6. 4 4
      pom.xml
  7. 1 1
      ruoyi-common/ruoyi-common-bom/pom.xml
  8. 45 6
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java
  9. 45 0
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowInstanceBizExtDTO.java
  10. 13 0
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java
  11. 0 63
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java
  12. 1 1
      ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelBigNumberConvert.java
  13. 55 0
      ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/utils/JsonUtils.java
  14. 33 0
      ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/validate/JsonPattern.java
  15. 51 0
      ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/validate/JsonPatternValidator.java
  16. 30 0
      ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/validate/JsonType.java
  17. 46 4
      ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java
  18. 9 1
      ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java
  19. 109 0
      ruoyi-common/ruoyi-common-social/src/main/java/me/zhyd/oauth/request/AuthDingTalkV2Request.java
  20. 1 4
      ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java
  21. 57 0
      ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java
  22. 8 2
      ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java
  23. 9 1
      ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java
  24. 21 14
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java
  25. 15 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java
  26. 3 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java
  27. 10 4
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java
  28. 8 3
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java
  29. 16 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java
  30. 2 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java
  31. 56 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java
  32. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
  33. 1 1
      ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/ButtonPermissionEnum.java
  34. 5 3
      ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java
  35. 5 2
      ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwNodeExtService.java
  36. 105 8
      ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwNodeExtServiceImpl.java
  37. 15 8
      ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java
  38. 3 2
      ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java
  39. 2 0
      ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java
  40. 4 4
      script/docker/docker-compose.yml
  41. 41 3
      script/docker/nginx/conf/nginx.conf
  42. 127 73
      script/leave/leave1.json
  43. 185 109
      script/leave/leave2.json
  44. 209 119
      script/leave/leave3.json
  45. 152 88
      script/leave/leave4.json
  46. 209 119
      script/leave/leave5.json
  47. 366 213
      script/leave/leave6.json
  48. 58 38
      script/sql/oracle/oracle_ry_workflow.sql
  49. 26 6
      script/sql/postgres/postgres_ry_workflow.sql
  50. 12 2
      script/sql/ry_workflow.sql
  51. 86 6
      script/sql/sqlserver/sqlserver_ry_workflow.sql
  52. 25 0
      script/sql/update/oracle/update_5.5.0-5.5.1.sql
  53. 25 0
      script/sql/update/postgres/update_5.5.0-5.5.1.sql
  54. 99 0
      script/sql/update/sqlserver/update_5.5.0-5.5.1.sql
  55. 21 0
      script/sql/update/update_5.5.0-5.5.1.sql

+ 1 - 0
.gitignore

@@ -38,6 +38,7 @@ nbdist/
 ######################################################################
 # Others
 *.log
+*.log.gz
 *.xml.versionsBackup
 *.swp
 

+ 1 - 1
.run/ruoyi-monitor-admin.run.xml

@@ -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.0" />
+        <option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.5.1" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" />
       </settings>

+ 1 - 1
.run/ruoyi-server.run.xml

@@ -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.0" />
+        <option name="imageTag" value="ruoyi/ruoyi-server:5.5.1" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-admin/Dockerfile" />
       </settings>

+ 1 - 1
.run/ruoyi-snailjob-server.run.xml

@@ -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.0" />
+        <option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.5.1" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-extend/ruoyi-snailjob-server/Dockerfile" />
       </settings>

+ 1 - 1
README.md

@@ -10,7 +10,7 @@
 [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/5.X/LICENSE)
 [![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
 <br>
-[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.5.0-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
+[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.5.1-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
 [![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.4-blue.svg)]()
 [![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]()
 [![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]()

+ 4 - 4
pom.xml

@@ -13,8 +13,8 @@
     <description>Dromara RuoYi-Vue-Plus多租户管理系统</description>
 
     <properties>
-        <revision>5.5.0</revision>
-        <spring-boot.version>3.5.6</spring-boot.version>
+        <revision>5.5.1</revision>
+        <spring-boot.version>3.5.7</spring-boot.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <java.version>17</java.version>
@@ -27,7 +27,7 @@
         <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.3</spring-boot-admin.version>
+        <spring-boot-admin.version>3.5.5</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>
@@ -48,7 +48,7 @@
         <!-- 面向运行时的D-ORM依赖 -->
         <anyline.version>8.7.2-20250603</anyline.version>
         <!-- 工作流配置 -->
-        <warm-flow.version>1.8.1</warm-flow.version>
+        <warm-flow.version>1.8.2</warm-flow.version>
 
         <!-- 插件版本 -->
         <maven-jar-plugin.version>3.4.2</maven-jar-plugin.version>

+ 1 - 1
ruoyi-common/ruoyi-common-bom/pom.xml

@@ -14,7 +14,7 @@
     </description>
 
     <properties>
-        <revision>5.5.0</revision>
+        <revision>5.5.1</revision>
     </properties>
 
     <dependencyManagement>

+ 45 - 6
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java

@@ -5,15 +5,12 @@ 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.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.*;
 
 /**
  * 线程池配置
@@ -50,7 +47,7 @@ public class ThreadPoolConfig {
             @Override
             protected void afterExecute(Runnable r, Throwable t) {
                 super.afterExecute(r, t);
-                Threads.printException(r, t);
+                printException(r, t);
             }
         };
         this.scheduledExecutorService = scheduledThreadPoolExecutor;
@@ -59,15 +56,57 @@ public class ThreadPoolConfig {
 
     /**
      * 销毁事件
+     * 停止线程池
+     * 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务.
+     * 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数.
+     * 如果仍然超時,則強制退出.
+     * 另对在shutdown时线程本身被调用中断做了处理.
      */
     @PreDestroy
     public void destroy() {
         try {
             log.info("====关闭后台任务任务线程池====");
-            Threads.shutdownAndAwaitTermination(scheduledExecutorService);
+            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();
+                }
+            }
         } 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);
+        }
+    }
+
 }

+ 45 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowInstanceBizExtDTO.java

@@ -0,0 +1,45 @@
+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;
+
+}

+ 13 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java

@@ -1,6 +1,7 @@
 package org.dromara.common.core.domain.dto;
 
 
+import cn.hutool.core.util.ObjectUtil;
 import lombok.Data;
 
 import java.io.Serial;
@@ -40,6 +41,11 @@ 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);
@@ -47,4 +53,11 @@ 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;
+    }
 }

+ 0 - 63
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java

@@ -1,63 +0,0 @@
-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);
-        }
-    }
-}

+ 1 - 1
ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelBigNumberConvert.java

@@ -28,7 +28,7 @@ public class ExcelBigNumberConvert implements Converter<Long> {
 
     @Override
     public CellDataTypeEnum supportExcelTypeKey() {
-        return CellDataTypeEnum.STRING;
+        return null;
     }
 
     @Override

+ 55 - 0
ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/utils/JsonUtils.java

@@ -5,6 +5,7 @@ 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;
@@ -167,4 +168,58 @@ 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;
+        }
+    }
+
 }

+ 33 - 0
ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/validate/JsonPattern.java

@@ -0,0 +1,33 @@
+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 {};
+
+}

+ 51 - 0
ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/validate/JsonPatternValidator.java

@@ -0,0 +1,51 @@
+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);
+        };
+    }
+
+}

+ 30 - 0
ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/validate/JsonType.java

@@ -0,0 +1,30 @@
+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
+
+}

+ 46 - 4
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java

@@ -1,10 +1,11 @@
 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;
@@ -35,13 +36,54 @@ public class MybatisExceptionHandler {
     @ExceptionHandler(MyBatisSystemException.class)
     public R<Void> handleCannotFindDataSourceException(MyBatisSystemException e, HttpServletRequest request) {
         String requestURI = request.getRequestURI();
-        String message = e.getMessage();
-        if (StringUtils.contains(message, "CannotFindDataSourceException")) {
+        Throwable root = getRootCause(e);
+        if (root instanceof NotLoginException) {
+            log.error("请求地址'{}',认证失败'{}',无法访问系统资源", requestURI, root.getMessage());
+            return R.fail(HttpStatus.HTTP_UNAUTHORIZED, "认证失败,无法访问系统资源");
+        }
+        if (root instanceof CannotFindDataSourceException) {
             log.error("请求地址'{}', 未找到数据源", requestURI);
             return R.fail(HttpStatus.HTTP_INTERNAL_ERROR, "未找到数据源,请联系管理员确认");
         }
         log.error("请求地址'{}', Mybatis系统异常", requestURI, e);
-        return R.fail(HttpStatus.HTTP_INTERNAL_ERROR, message);
+        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;
     }
 
 }

+ 9 - 1
ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java

@@ -7,7 +7,9 @@ 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;
@@ -55,6 +57,8 @@ public class SecurityConfig implements WebMvcConfigurer {
                     // 对未排除的路径进行检查
                     .check(() -> {
                         HttpServletRequest request = ServletUtils.getRequest();
+                        HttpServletResponse response = ServletUtils.getResponse();
+                        response.setContentType(SaTokenConsts.CONTENT_TYPE_APPLICATION_JSON);
                         // 检查是否登录 是否有token
                         StpUtil.checkLogin();
 
@@ -94,7 +98,11 @@ public class SecurityConfig implements WebMvcConfigurer {
             .setAuth(obj -> {
                 SaHttpBasicUtil.check(username + ":" + password);
             })
-            .setError(e -> SaResult.error(e.getMessage()).setCode(HttpStatus.UNAUTHORIZED));
+            .setError(e -> {
+                HttpServletResponse response = ServletUtils.getResponse();
+                response.setContentType(SaTokenConsts.CONTENT_TYPE_APPLICATION_JSON);
+                return SaResult.error(e.getMessage()).setCode(HttpStatus.UNAUTHORIZED);
+            });
     }
 
 }

+ 109 - 0
ruoyi-common/ruoyi-common-social/src/main/java/me/zhyd/oauth/request/AuthDingTalkV2Request.java

@@ -0,0 +1,109 @@
+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();
+    }
+}

+ 1 - 4
ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java

@@ -14,9 +14,6 @@ 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;
-
 /**
  * 认证授权工具类
  *
@@ -43,7 +40,7 @@ public class SocialUtils  {
         AuthConfig.AuthConfigBuilder builder = AuthConfig.builder()
             .clientId(obj.getClientId())
             .clientSecret(obj.getClientSecret())
-            .redirectUri(URLEncoder.encode(obj.getRedirectUri(), StandardCharsets.UTF_8))
+            .redirectUri(obj.getRedirectUri())
             .scopes(obj.getScopes());
         return switch (source.toLowerCase()) {
             case "dingtalk" -> new AuthDingTalkV2Request(builder.build(), STATE_CACHE);

+ 57 - 0
ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java

@@ -1,14 +1,21 @@
 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;
 
 /**
@@ -26,6 +33,12 @@ 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 连接
      *
@@ -38,6 +51,12 @@ 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);
 
@@ -97,6 +116,44 @@ 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消息主题,并提供一个消费者函数来处理接收到的消息
      *

+ 8 - 2
ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java

@@ -46,8 +46,14 @@ public class TranslationHandler extends JsonSerializer<Object> implements Contex
                 gen.writeNull();
                 return;
             }
-            Object result = trans.translation(value, translation.other());
-            gen.writeObject(result);
+            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);
+            }
         } else {
             gen.writeObject(value);
         }

+ 9 - 1
ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java

@@ -23,6 +23,7 @@ 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;
 
@@ -123,7 +124,7 @@ public class GlobalExceptionHandler {
      */
     @ResponseStatus(org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR)
     @ExceptionHandler(IOException.class)
-    public void handleRuntimeException(IOException e, HttpServletRequest request) {
+    public void handleIoException(IOException e, HttpServletRequest request) {
         String requestURI = request.getRequestURI();
         if (requestURI.contains("sse")) {
             // sse 经常性连接中断 例如关闭浏览器 直接屏蔽
@@ -132,6 +133,13 @@ public class GlobalExceptionHandler {
         log.error("请求地址'{}',连接中断", requestURI, e);
     }
 
+    /**
+     * sse 连接超时异常 不需要处理
+     */
+    @ExceptionHandler(AsyncRequestTimeoutException.class)
+    public void handleRuntimeException(AsyncRequestTimeoutException e) {
+    }
+
     /**
      * 拦截未知的运行时异常
      */

+ 21 - 14
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java

@@ -1,26 +1,27 @@
 package org.dromara.system.controller.system;
 
-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 jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
 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.log.enums.BusinessType;
 import org.dromara.common.excel.utils.ExcelUtil;
-import org.dromara.system.domain.vo.SysClientVo;
+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.system.domain.vo.SysClientVo;
 import org.dromara.system.service.ISysClientService;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 客户端管理
@@ -76,6 +77,9 @@ 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));
     }
 
@@ -87,6 +91,9 @@ 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));
     }
 

+ 15 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java

@@ -193,4 +193,19 @@ 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("同步租户参数配置成功");
+    }
+
 }

+ 3 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java

@@ -9,6 +9,8 @@ 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;
 
@@ -61,6 +63,7 @@ public class SysMenuBo extends BaseEntity {
     /**
      * 路由参数
      */
+    @JsonPattern(type = JsonType.OBJECT, message = "路由参数必须符合JSON格式")
     private String queryParam;
 
     /**

+ 10 - 4
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java

@@ -1,10 +1,9 @@
 package org.dromara.system.service;
 
-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 org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysClientBo;
+import org.dromara.system.domain.vo.SysClientVo;
 
 import java.util.Collection;
 import java.util.List;
@@ -57,4 +56,11 @@ public interface ISysClientService {
      */
     Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
 
+    /**
+     * 校验客户端key是否唯一
+     *
+     * @param client 客户端信息
+     * @return 结果
+     */
+    boolean checkClickKeyUnique(SysClientBo client);
 }

+ 8 - 3
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java

@@ -1,9 +1,9 @@
 package org.dromara.system.service;
 
-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 org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysTenantBo;
+import org.dromara.system.domain.vo.SysTenantVo;
 
 import java.util.Collection;
 import java.util.List;
@@ -84,4 +84,9 @@ public interface ISysTenantService {
      * 同步租户字典
      */
     void syncTenantDict();
+
+    /**
+     * 同步租户参数配置
+     */
+    void syncTenantConfig();
 }

+ 16 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java

@@ -1,6 +1,7 @@
 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;
@@ -136,4 +137,19 @@ 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;
+    }
+
 }

+ 2 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java

@@ -241,6 +241,8 @@ 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());
         });
     }
 

+ 56 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java

@@ -508,4 +508,60 @@ 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));
+        }
+    }
+
 }

+ 1 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java

@@ -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.splitList(user.getExcludeUserIds()));
+            wrapper.notIn(SysUser::getUserId, StringUtils.splitTo(user.getExcludeUserIds(), Convert::toLong));
         }
         return wrapper;
     }

+ 1 - 1
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/ButtonPermissionEnum.java

@@ -30,7 +30,7 @@ public enum ButtonPermissionEnum implements NodeExtEnum {
     /**
      * 是否能抄送
      */
-    COPY("是否能抄送", "copy", false),
+    COPY("是否能抄送", "copy", true),
 
     /**
      * 是否显示退回

+ 5 - 3
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java

@@ -72,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 -> {
@@ -180,12 +180,14 @@ 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 - 2
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwNodeExtService.java

@@ -2,6 +2,8 @@ package org.dromara.workflow.service;
 
 import org.dromara.workflow.domain.vo.NodeExtVo;
 
+import java.util.Map;
+
 /**
  * 流程节点扩展属性 服务层
  *
@@ -24,9 +26,10 @@ public interface IFlwNodeExtService {
      * {"code": "VariablesEnum", "value": "key1=value1,key2=value2"}
      * ]
      *
-     * @param ext 扩展属性 JSON 字符串
+     * @param ext      扩展属性 JSON 字符串
+     * @param variable 流程变量
      * @return NodeExtVo 对象,封装按钮权限列表、抄送对象集合和自定义参数 Map
      */
-    NodeExtVo parseNodeExt(String ext);
+    NodeExtVo parseNodeExt(String ext, Map<String, Object> variable);
 
 }

+ 105 - 8
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwNodeExtServiceImpl.java

@@ -9,6 +9,9 @@ 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;
@@ -45,7 +48,7 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
             CopySettingEnum.class.getSimpleName(),
             Map.of(
                 "label", "抄送对象",
-                "type", 2,
+                "type", 5,
                 "must", false,
                 "multiple", false,
                 "desc", "设置该节点的抄送办理人"
@@ -56,7 +59,7 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
                 "type", 2,
                 "must", false,
                 "multiple", false,
-                "desc", "节点执行时可以使用的自定义参数"
+                "desc", "节点执行时可设置自定义参数,多个参数以逗号分隔,如:key1=value1,key2=value2"
             ),
             ButtonPermissionEnum.class.getSimpleName(),
             Map.of(
@@ -137,7 +140,7 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
         childNode.setCode(simpleName);
         // label名称
         childNode.setLabel(Convert.toStr(map.get("label")));
-        // 1:输入框 2:文本域 3:下拉框 4:选择框
+        // 1:输入框 2:文本域 3:下拉框 4:选择框 5:用户选择器
         childNode.setType(Convert.toInt(map.get("type"), 1));
         // 是否必填
         childNode.setMust(Convert.toBool(map.get("must"), false));
@@ -170,7 +173,7 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
         childNode.setCode(dictType);
         // label名称
         childNode.setLabel(dictTypeDTO.getDictName());
-        // 1:输入框 2:文本域 3:下拉框 4:选择框
+        // 1:输入框 2:文本域 3:下拉框 4:选择框 5:用户选择器
         childNode.setType(3);
         // 是否必填
         childNode.setMust(false);
@@ -197,19 +200,23 @@ public class FlwNodeExtServiceImpl implements NodeExtService, IFlwNodeExtService
      * <p>示例 JSON:
      * [
      * {"code": "ButtonPermissionEnum", "value": "back,termination"},
-     * {"code": "CopySettingEnum", "value": "1"},
+     * {"code": "CopySettingEnum", "value": "1,3,4,#{@spelRuleComponent.selectDeptLeaderById(#deptId", "#roleId)}"},
      * {"code": "VariablesEnum", "value": "key1=value1,key2=value2"}
      * ]
      *
-     * @param ext 扩展属性 JSON 字符串
+     * @param ext      扩展属性 JSON 字符串
+     * @param variable 流程变量
      * @return NodeExtVo 对象,封装按钮权限列表、抄送对象集合和自定义参数 Map
      */
     @Override
-    public NodeExtVo parseNodeExt(String ext) {
+    public NodeExtVo parseNodeExt(String ext, Map<String, Object> variable) {
         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");
@@ -234,8 +241,20 @@ 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(StringUtils.str2Set(value, StringUtils.SEPARATOR));
+                nodeExtVo.setCopySettings(new HashSet<>(copySettings));
 
             } else if (VariablesEnum.class.getSimpleName().equals(code)) {
                 // 解析自定义参数
@@ -254,4 +273,82 @@ 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;
+    }
+
 }

+ 15 - 8
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java

@@ -382,7 +382,6 @@ 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);
     }
@@ -457,7 +456,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
             List<Long> categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowTaskBo.getCategory()));
             wrapper.in("t.category", StreamUtils.toList(categoryIds, Convert::toStr));
         }
-        wrapper.orderByDesc("t.create_time");
+        wrapper.orderByDesc("t.create_time").orderByDesc("t.update_time");
         return wrapper;
     }
 
@@ -485,9 +484,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
 
             Map<String, Object> variable = new HashMap<>();
             // 消息类型
-            variable.put("messageType", messageType);
+            variable.put(FlowConstant.MESSAGE_TYPE, messageType);
             // 消息通知
-            variable.put("notice", notice);
+            variable.put(FlowConstant.MESSAGE_NOTICE, notice);
 
             FlowParams flowParams = FlowParams.build()
                 .nodeCode(bo.getNodeCode())
@@ -599,16 +598,24 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
         if (ObjectUtil.isNull(flowNode)) {
             throw new NullPointerException("当前【" + flowTaskVo.getNodeCode() + "】节点编码不存在");
         }
-        NodeExtVo nodeExtVo = flwNodeExtService.parseNodeExt(flowNode.getExt());
+        NodeExtVo nodeExtVo = flwNodeExtService.parseNodeExt(flowNode.getExt(), instance.getVariableMap());
         //设置按钮权限
-        flowTaskVo.setButtonList(nodeExtVo.getButtonPermissions());
+        if (CollUtil.isNotEmpty(nodeExtVo.getButtonPermissions())) {
+            flowTaskVo.setButtonList(nodeExtVo.getButtonPermissions());
+        } else {
+            flowTaskVo.setButtonList(new ArrayList<>());
+        }
         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<>());
         }
-        flowTaskVo.setVarList(nodeExtVo.getVariables());
+        if (CollUtil.isNotEmpty(nodeExtVo.getVariables())) {
+            flowTaskVo.setVarList(nodeExtVo.getVariables());
+        } else {
+            flowTaskVo.setVarList(new HashMap<>());
+        }
         flowTaskVo.setNodeRatio(flowNode.getNodeRatio());
         flowTaskVo.setApplyNode(flowNode.getNodeCode().equals(flwCommonService.applyNodeCode(task.getDefinitionId())));
         return flowTaskVo;
@@ -731,7 +738,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
         Long taskId = bo.getTaskId();
         Task task = taskService.getById(taskId);
         FlowNode flowNode = getByNodeCode(task.getNodeCode(), task.getDefinitionId());
-        if ("addSignature".equals(taskOperation) || "reductionSignature".equals(taskOperation)) {
+        if (ADD_SIGNATURE.equals(taskOperation) || REDUCTION_SIGNATURE.equals(taskOperation)) {
             if (flowNode.getNodeRatio().compareTo(BigDecimal.ZERO) == 0) {
                 throw new ServiceException(task.getNodeName() + "不是会签节点!");
             }

+ 3 - 2
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java

@@ -23,6 +23,7 @@ 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;
@@ -193,8 +194,8 @@ 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, "businessCode",StrUtil.EMPTY);
+            if (StringUtils.isBlank(testLeave.getApplyCode())) {
+                String businessCode = MapUtil.getStr(params, FlowConstant.BUSINESS_CODE, StrUtil.EMPTY);
                 testLeave.setApplyCode(businessCode);
             }
             testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus());

+ 2 - 0
ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java

@@ -12,6 +12,7 @@ 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;
@@ -166,6 +167,7 @@ public class WorkflowServiceImpl implements WorkflowService {
             processBo.setFlowCode(startProcess.getFlowCode());
             processBo.setVariables(startProcess.getVariables());
             processBo.setHandler(startProcess.getHandler());
+            processBo.setBizExt(BeanUtil.toBean(startProcess.getBizExt(), FlowInstanceBizExt.class));
 
             StartProcessReturnDTO result = flwTaskService.startWorkFlow(processBo);
             CompleteTaskBo taskBo = new CompleteTaskBo();

+ 4 - 4
script/docker/docker-compose.yml

@@ -99,7 +99,7 @@ services:
     network_mode: "host"
 
   ruoyi-server1:
-    image: ruoyi/ruoyi-server:5.5.0
+    image: ruoyi/ruoyi-server:5.5.1
     container_name: ruoyi-server1
     environment:
       # 时区上海
@@ -115,7 +115,7 @@ services:
     network_mode: "host"
 
   ruoyi-server2:
-    image: ruoyi/ruoyi-server:5.5.0
+    image: ruoyi/ruoyi-server:5.5.1
     container_name: ruoyi-server2
     environment:
       # 时区上海
@@ -131,7 +131,7 @@ services:
     network_mode: "host"
 
   ruoyi-monitor-admin:
-    image: ruoyi/ruoyi-monitor-admin:5.5.0
+    image: ruoyi/ruoyi-monitor-admin:5.5.1
     container_name: ruoyi-monitor-admin
     environment:
       # 时区上海
@@ -143,7 +143,7 @@ services:
     network_mode: "host"
 
   ruoyi-snailjob-server:
-    image: ruoyi/ruoyi-snailjob-server:5.5.0
+    image: ruoyi/ruoyi-snailjob-server:5.5.1
     container_name: ruoyi-snailjob-server
     environment:
       # 时区上海

+ 41 - 3
script/docker/nginx/conf/nginx.conf

@@ -4,18 +4,30 @@ 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" '
@@ -50,7 +62,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 TLSv1.1 TLSv1.2;
+        #ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1 TLSv1;
         #ssl_prefer_server_ciphers on;
         # https配置参考 end
 
@@ -76,17 +88,29 @@ 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 与 websocket参数
+            # SSE (Server-Sent Events) 与 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/;
         }
 
@@ -94,23 +118,37 @@ 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 与 websocket参数
+            # SSE (Server-Sent Events) 与 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/;
         }

+ 127 - 73
script/leave/leave1.json

@@ -1,75 +1,129 @@
 {
-  "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" : "[]"
-  } ]
+  "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
 }

+ 185 - 109
script/leave/leave2.json

@@ -1,111 +1,187 @@
 {
-  "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"
-    } ]
-  } ]
+  "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
 }

+ 209 - 119
script/leave/leave3.json

@@ -1,121 +1,211 @@
 {
-  "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"
-    } ]
-  } ]
+  "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
 }

+ 152 - 88
script/leave/leave4.json

@@ -1,90 +1,154 @@
 {
-  "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" : "[]"
-  } ]
+  "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
 }

+ 209 - 119
script/leave/leave5.json

@@ -1,121 +1,211 @@
 {
-  "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"
-    } ]
-  } ]
+  "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
 }

+ 366 - 213
script/leave/leave6.json

@@ -1,215 +1,368 @@
 {
-  "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" : "[]"
-  } ]
+  "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
 }

+ 58 - 38
script/sql/oracle/oracle_ry_workflow.sql

@@ -17,7 +17,9 @@ 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)
 );
@@ -40,7 +42,9 @@ 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';
 
@@ -62,7 +66,9 @@ create table FLOW_NODE
     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),
@@ -89,7 +95,9 @@ 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';
@@ -108,7 +116,9 @@ 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)
 );
@@ -128,7 +138,9 @@ 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,9 +156,10 @@ create table FLOW_INSTANCE
     FLOW_STATUS     VARCHAR2(20),
     ACTIVITY_STATUS NUMBER(1)    default 1,
     DEF_JSON        CLOB,
-    CREATE_BY       VARCHAR2(64) default '',
     CREATE_TIME     DATE,
+    CREATE_BY       VARCHAR2(64) default '',
     UPDATE_TIME     DATE,
+    UPDATE_BY       VARCHAR2(64) default '',
     EXT             VARCHAR2(500),
     DEL_FLAG        VARCHAR2(1)  default '0',
     TENANT_ID       VARCHAR2(40)
@@ -166,9 +179,10 @@ 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';
@@ -185,7 +199,9 @@ 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)
 );
@@ -204,7 +220,9 @@ 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';
 
@@ -271,8 +289,9 @@ create table FLOW_USER
     PROCESSED_BY VARCHAR2(80),
     ASSOCIATED   NUMBER(20)  not null,
     CREATE_TIME  DATE,
-    CREATE_BY    VARCHAR2(80),
+    CREATE_BY    VARCHAR2(64) default '',
     UPDATE_TIME  DATE,
+    UPDATE_BY    VARCHAR2(64) default '',
     DEL_FLAG     VARCHAR2(1) default '0',
     TENANT_ID    VARCHAR2(40)
 );
@@ -286,8 +305,9 @@ 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';
 
@@ -299,18 +319,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);
@@ -344,19 +364,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);
@@ -418,19 +438,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
 );
 

+ 26 - 6
script/sql/postgres/postgres_ry_workflow.sql

@@ -14,7 +14,9 @@ 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)
@@ -35,7 +37,9 @@ 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';
 
@@ -57,8 +61,10 @@ CREATE TABLE flow_node
     form_custom     bpchar(1)     NULL DEFAULT 'N':: character varying,
     form_path       varchar(100)  NULL,
     "version"       varchar(20)   NOT NULL,
-    create_time     timestamp     NULL,
-    update_time     timestamp     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,
     ext             text         NULL,
     del_flag        bpchar(1)     NULL DEFAULT '0':: character varying,
     tenant_id       varchar(40)   NULL,
@@ -83,7 +89,9 @@ 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';
@@ -102,7 +110,9 @@ 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)
@@ -120,7 +130,9 @@ 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';
 
@@ -136,9 +148,10 @@ 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,
@@ -156,9 +169,10 @@ 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';
@@ -171,11 +185,13 @@ 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)
@@ -192,7 +208,9 @@ 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';
 
@@ -256,8 +274,9 @@ CREATE TABLE flow_user
     processed_by varchar(80) NULL,
     associated   int8        NOT NULL,
     create_time  timestamp   NULL,
-    create_by    varchar(80) 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_user_pk PRIMARY KEY (id)
@@ -273,6 +292,7 @@ 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';
 

+ 12 - 2
script/sql/ry_workflow.sql

@@ -17,7 +17,9 @@ 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
@@ -42,7 +44,9 @@ CREATE TABLE `flow_node`
     `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',
@@ -62,7 +66,9 @@ 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
@@ -80,9 +86,10 @@ 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',
@@ -101,7 +108,9 @@ 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
@@ -118,7 +127,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无动作)',
@@ -145,6 +154,7 @@ 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,

+ 86 - 6
script/sql/sqlserver/sqlserver_ry_workflow.sql

@@ -16,7 +16,9 @@ CREATE TABLE flow_definition (
     listener_path nvarchar(400) NULL,
     ext nvarchar(500) NULL,
     create_time datetime2(7)  NULL,
+    create_by nvarchar(64) NULL,
     update_time datetime2(7)  NULL,
+    update_by nvarchar(64) NULL,
     del_flag nchar(1) DEFAULT('0') NULL,
     tenant_id nvarchar(40) NULL,
     CONSTRAINT PK__flow_def__3213E83FEE39AE33 PRIMARY KEY CLUSTERED (id)
@@ -124,6 +126,13 @@ EXEC sp_addextendedproperty
 'COLUMN', N'create_time'
 GO
 
+EXEC sp_addextendedproperty
+'MS_Description', N'创建人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'create_by'
+GO
+
 EXEC sp_addextendedproperty
 'MS_Description', N'更新时间',
 'SCHEMA', N'dbo',
@@ -131,6 +140,13 @@ EXEC sp_addextendedproperty
 'COLUMN', N'update_time'
 GO
 
+EXEC sp_addextendedproperty
+'MS_Description', N'更新人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'update_by'
+GO
+
 EXEC sp_addextendedproperty
 'MS_Description', N'删除标志',
 'SCHEMA', N'dbo',
@@ -169,7 +185,9 @@ CREATE TABLE flow_node (
     form_path nvarchar(100) NULL,
     version nvarchar(20) NOT NULL,
     create_time datetime2(7)  NULL,
+    create_by nvarchar(64) NULL,
     update_time datetime2(7)  NULL,
+    update_by nvarchar(64) NULL,
     ext nvarchar(max) NULL,
     del_flag nchar(1) DEFAULT('0') NULL,
     tenant_id nvarchar(40) NULL,
@@ -299,6 +317,13 @@ EXEC sp_addextendedproperty
 'COLUMN', N'create_time'
 GO
 
+EXEC sp_addextendedproperty
+'MS_Description', N'创建人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'create_by'
+GO
+
 EXEC sp_addextendedproperty
 'MS_Description', N'更新时间',
 'SCHEMA', N'dbo',
@@ -306,6 +331,13 @@ EXEC sp_addextendedproperty
 'COLUMN', N'update_time'
 GO
 
+EXEC sp_addextendedproperty
+'MS_Description', N'更新人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'update_by'
+GO
+
 EXEC sp_addextendedproperty
 'MS_Description', N'节点扩展属性',
 'SCHEMA', N'dbo',
@@ -346,7 +378,9 @@ CREATE TABLE flow_skip (
     skip_condition nvarchar(200) NULL,
     coordinate nvarchar(100) NULL,
     create_time datetime2(7)  NULL,
+    create_by nvarchar(64) NULL,
     update_time datetime2(7)  NULL,
+    update_by nvarchar(64) NULL,
     del_flag nchar(1) DEFAULT('0') NULL,
     tenant_id nvarchar(40) NULL,
     CONSTRAINT PK__flow_ski__3213E83F073FEE6E PRIMARY KEY CLUSTERED (id)
@@ -433,6 +467,13 @@ EXEC sp_addextendedproperty
 'COLUMN', N'create_time'
 GO
 
+EXEC sp_addextendedproperty
+'MS_Description', N'创建人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip',
+'COLUMN', N'create_by'
+GO
+
 EXEC sp_addextendedproperty
 'MS_Description', N'更新时间',
 'SCHEMA', N'dbo',
@@ -440,6 +481,13 @@ EXEC sp_addextendedproperty
 'COLUMN', N'update_time'
 GO
 
+EXEC sp_addextendedproperty
+'MS_Description', N'更新人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip',
+'COLUMN', N'update_by'
+GO
+
 EXEC sp_addextendedproperty
 'MS_Description', N'删除标志',
 'SCHEMA', N'dbo',
@@ -471,9 +519,10 @@ CREATE TABLE flow_instance (
     flow_status nvarchar(20) NOT NULL,
     activity_status tinyint DEFAULT('1') NULL,
     def_json nvarchar(max) NULL,
-    create_by nvarchar(64) NULL,
     create_time datetime2(7)  NULL,
+    create_by nvarchar(64) NULL,
     update_time datetime2(7)  NULL,
+    update_by nvarchar(64) NULL,
     ext nvarchar(500) NULL,
     del_flag nchar(1) DEFAULT('0') NULL,
     tenant_id nvarchar(40) NULL,
@@ -556,17 +605,17 @@ EXEC sp_addextendedproperty
 GO
 
 EXEC sp_addextendedproperty
-'MS_Description', N'创建',
+'MS_Description', N'创建时间',
 'SCHEMA', N'dbo',
 'TABLE', N'flow_instance',
-'COLUMN', N'create_by'
+'COLUMN', N'create_time'
 GO
 
 EXEC sp_addextendedproperty
-'MS_Description', N'创建时间',
+'MS_Description', N'创建',
 'SCHEMA', N'dbo',
 'TABLE', N'flow_instance',
-'COLUMN', N'create_time'
+'COLUMN', N'create_by'
 GO
 
 EXEC sp_addextendedproperty
@@ -576,6 +625,13 @@ EXEC sp_addextendedproperty
 'COLUMN', N'update_time'
 GO
 
+EXEC sp_addextendedproperty
+'MS_Description', N'更新人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance',
+'COLUMN', N'update_by'
+GO
+
 EXEC sp_addextendedproperty
 'MS_Description', N'扩展字段,预留给业务系统使用',
 'SCHEMA', N'dbo',
@@ -614,7 +670,9 @@ CREATE TABLE flow_task (
     form_custom nchar(1) DEFAULT('N') NULL,
     form_path nvarchar(100) NULL,
     create_time datetime2(7)  NULL,
+    create_by nvarchar(64) NULL,
     update_time datetime2(7)  NULL,
+    update_by nvarchar(64) NULL,
     del_flag nchar(1) DEFAULT('0') NULL,
     tenant_id nvarchar(40) NULL,
     CONSTRAINT PK__flow_tas__3213E83F5AE1F1BA PRIMARY KEY CLUSTERED (id)
@@ -694,6 +752,13 @@ EXEC sp_addextendedproperty
 'COLUMN', N'create_time'
 GO
 
+EXEC sp_addextendedproperty
+'MS_Description', N'创建人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_task',
+'COLUMN', N'create_by'
+GO
+
 EXEC sp_addextendedproperty
 'MS_Description', N'更新时间',
 'SCHEMA', N'dbo',
@@ -701,6 +766,13 @@ EXEC sp_addextendedproperty
 'COLUMN', N'update_time'
 GO
 
+EXEC sp_addextendedproperty
+'MS_Description', N'更新人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_task',
+'COLUMN', N'update_by'
+GO
+
 EXEC sp_addextendedproperty
 'MS_Description', N'删除标志',
 'SCHEMA', N'dbo',
@@ -925,8 +997,9 @@ CREATE TABLE flow_user (
     processed_by nvarchar(80) NULL,
     associated bigint NOT NULL,
     create_time datetime2(7)  NULL,
-    create_by nvarchar(80) NULL,
+    create_by nvarchar(64) NULL,
     update_time datetime2(7)  NULL,
+    update_by nvarchar(64) NULL,
     del_flag nchar(1) DEFAULT('0') NULL,
     tenant_id nvarchar(40) NULL,
     CONSTRAINT PK__flow_use__3213E83FFA38CA8B PRIMARY KEY CLUSTERED (id)
@@ -990,6 +1063,13 @@ EXEC sp_addextendedproperty
 'COLUMN', N'update_time'
 GO
 
+EXEC sp_addextendedproperty
+'MS_Description', N'更新人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_user',
+'COLUMN', N'update_by'
+GO
+
 EXEC sp_addextendedproperty
 'MS_Description', N'删除标志',
 'SCHEMA', N'dbo',

+ 25 - 0
script/sql/update/oracle/update_5.5.0-5.5.1.sql

@@ -0,0 +1,25 @@
+ALTER TABLE flow_definition ADD create_by VARCHAR2(64) DEFAULT '' NOT NULL;
+ALTER TABLE flow_definition ADD update_by VARCHAR2(64) DEFAULT '' NOT NULL;
+COMMENT ON COLUMN flow_definition.create_by IS '创建人';
+COMMENT ON COLUMN flow_definition.update_by IS '更新人';
+
+ALTER TABLE flow_node ADD create_by VARCHAR2(64) DEFAULT '' NOT NULL;
+ALTER TABLE flow_node ADD update_by VARCHAR2(64) DEFAULT '' NOT NULL;
+COMMENT ON COLUMN flow_node.create_by IS '创建人';
+COMMENT ON COLUMN flow_node.update_by IS '更新人';
+
+ALTER TABLE flow_skip ADD create_by VARCHAR2(64) DEFAULT '' NOT NULL;
+ALTER TABLE flow_skip ADD update_by VARCHAR2(64) DEFAULT '' NOT NULL;
+COMMENT ON COLUMN flow_skip.create_by IS '创建人';
+COMMENT ON COLUMN flow_skip.update_by IS '更新人';
+
+ALTER TABLE flow_instance ADD update_by VARCHAR2(64) DEFAULT '' NOT NULL;
+COMMENT ON COLUMN flow_instance.update_by IS '更新人';
+
+ALTER TABLE flow_task ADD create_by VARCHAR2(64) DEFAULT '' NOT NULL;
+ALTER TABLE flow_task ADD update_by VARCHAR2(64) DEFAULT '' NOT NULL;
+COMMENT ON COLUMN flow_task.create_by IS '创建人';
+COMMENT ON COLUMN flow_task.update_by IS '更新人';
+
+ALTER TABLE flow_user ADD update_by VARCHAR2(64) DEFAULT '' NOT NULL;
+COMMENT ON COLUMN flow_user.update_by IS '更新人';

+ 25 - 0
script/sql/update/postgres/update_5.5.0-5.5.1.sql

@@ -0,0 +1,25 @@
+ALTER TABLE flow_definition ADD create_by VARCHAR2(64) DEFAULT '' NOT NULL;
+ALTER TABLE flow_definition ADD update_by VARCHAR2(64) DEFAULT '' NOT NULL;
+COMMENT ON COLUMN flow_definition.create_by IS '创建人';
+COMMENT ON COLUMN flow_definition.update_by IS '更新人';
+
+ALTER TABLE flow_node ADD create_by VARCHAR2(64) DEFAULT '' NOT NULL;
+ALTER TABLE flow_node ADD update_by VARCHAR2(64) DEFAULT '' NOT NULL;
+COMMENT ON COLUMN flow_node.create_by IS '创建人';
+COMMENT ON COLUMN flow_node.update_by IS '更新人';
+
+ALTER TABLE flow_skip ADD create_by VARCHAR2(64) DEFAULT '' NOT NULL;
+ALTER TABLE flow_skip ADD update_by VARCHAR2(64) DEFAULT '' NOT NULL;
+COMMENT ON COLUMN flow_skip.create_by IS '创建人';
+COMMENT ON COLUMN flow_skip.update_by IS '更新人';
+
+ALTER TABLE flow_instance ADD update_by VARCHAR2(64) DEFAULT '' NOT NULL;
+COMMENT ON COLUMN flow_instance.update_by IS '更新人';
+
+ALTER TABLE flow_task ADD create_by VARCHAR2(64) DEFAULT '' NOT NULL;
+ALTER TABLE flow_task ADD update_by VARCHAR2(64) DEFAULT '' NOT NULL;
+COMMENT ON COLUMN flow_task.create_by IS '创建人';
+COMMENT ON COLUMN flow_task.update_by IS '更新人';
+
+ALTER TABLE flow_user ADD update_by VARCHAR2(64) DEFAULT '' NOT NULL;
+COMMENT ON COLUMN flow_user.update_by IS '更新人';

+ 99 - 0
script/sql/update/sqlserver/update_5.5.0-5.5.1.sql

@@ -0,0 +1,99 @@
+ALTER TABLE flow_definition ADD create_by nvarchar(64) NOT NULL CONSTRAINT DF_flow_definition_create_by DEFAULT '';
+GO
+
+ALTER TABLE flow_definition ADD update_by nvarchar(64) NOT NULL CONSTRAINT DF_flow_definition_update_by DEFAULT '';
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'创建人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'create_by'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'更新人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_definition',
+'COLUMN', N'update_by'
+GO
+
+ALTER TABLE flow_node ADD create_by nvarchar(64) NOT NULL CONSTRAINT DF_flow_node_create_by DEFAULT '';
+GO
+
+ALTER TABLE flow_node ADD update_by nvarchar(64) NOT NULL CONSTRAINT DF_flow_node_update_by DEFAULT '';
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'创建人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'create_by'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'更新人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_node',
+'COLUMN', N'update_by'
+GO
+
+ALTER TABLE flow_skip ADD create_by nvarchar(64) NOT NULL CONSTRAINT DF_flow_skip_create_by DEFAULT '';
+GO
+
+ALTER TABLE flow_skip ADD update_by nvarchar(64) NOT NULL CONSTRAINT DF_flow_skip_update_by DEFAULT '';
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'创建人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip',
+'COLUMN', N'create_by'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'更新人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_skip',
+'COLUMN', N'update_by'
+GO
+
+ALTER TABLE flow_instance ADD update_by nvarchar(64) NOT NULL CONSTRAINT DF_flow_instance_update_by DEFAULT '';
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'更新人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_instance',
+'COLUMN', N'update_by'
+GO
+
+ALTER TABLE flow_task ADD create_by nvarchar(64) NOT NULL CONSTRAINT DF_flow_task_create_by DEFAULT '';
+GO
+
+ALTER TABLE flow_task ADD update_by nvarchar(64) NOT NULL CONSTRAINT DF_flow_task_update_by DEFAULT '';
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'创建人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_task',
+'COLUMN', N'create_by'
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'更新人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_task',
+'COLUMN', N'update_by'
+GO
+
+ALTER TABLE flow_user ADD update_by nvarchar(64) NOT NULL CONSTRAINT DF_flow_user_update_by DEFAULT '';
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'更新人',
+'SCHEMA', N'dbo',
+'TABLE', N'flow_user',
+'COLUMN', N'update_by'
+GO

+ 21 - 0
script/sql/update/update_5.5.0-5.5.1.sql

@@ -0,0 +1,21 @@
+ALTER TABLE `flow_definition`
+    ADD COLUMN `create_by` varchar(64) NULL DEFAULT NULL COMMENT '创建人' AFTER `create_time`,
+    ADD COLUMN `update_by` varchar(64) NULL DEFAULT NULL COMMENT '更新人' AFTER `update_time`;
+
+ALTER TABLE `flow_node`
+    ADD COLUMN `create_by` varchar(64) NULL DEFAULT NULL COMMENT '创建人' AFTER `create_time`,
+    ADD COLUMN `update_by` varchar(64) NULL DEFAULT NULL COMMENT '更新人' AFTER `update_time`;
+
+ALTER TABLE `flow_skip`
+    ADD COLUMN `create_by` varchar(64) NULL DEFAULT NULL COMMENT '创建人' AFTER `create_time`,
+    ADD COLUMN `update_by` varchar(64) NULL DEFAULT NULL COMMENT '更新人' AFTER `update_time`;
+
+ALTER TABLE `flow_instance`
+    ADD COLUMN `update_by` varchar(64) NULL DEFAULT NULL COMMENT '更新人' AFTER `update_time`;
+
+ALTER TABLE `flow_task`
+    ADD COLUMN `create_by` varchar(64) NULL DEFAULT NULL COMMENT '创建人' AFTER `create_time`,
+    ADD COLUMN `update_by` varchar(64) NULL DEFAULT NULL COMMENT '更新人' AFTER `update_time`;
+
+ALTER TABLE `flow_user`
+    ADD COLUMN `update_by` varchar(64) NULL DEFAULT NULL COMMENT '更新人' AFTER `update_time`;