diff --git a/pom.xml b/pom.xml
index 900b61b53..2a218f6f6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -59,6 +59,9 @@
3.11.0
3.1.2
1.3.0
+
+
+ 2.12.1
@@ -339,6 +342,80 @@
${fastjson.version}
+
+ com.yomahub
+ liteflow-spring-boot-starter
+ ${liteflow.version}
+
+
+
+ com.yomahub
+ liteflow-core
+ ${liteflow.version}
+
+
+
+ com.yomahub
+ liteflow-rule-sql
+ ${liteflow.version}
+
+
+
+
+ com.yomahub
+ liteflow-script-groovy
+ ${liteflow.version}
+
+
+
+
+ com.yomahub
+ liteflow-script-graaljs
+ ${liteflow.version}
+
+
+
+
+ com.yomahub
+ liteflow-script-java
+ ${liteflow.version}
+
+
+
+
+ com.yomahub
+ liteflow-script-qlexpress
+ ${liteflow.version}
+
+
+
+
+ com.yomahub
+ liteflow-script-python
+ ${liteflow.version}
+
+
+
+
+ com.yomahub
+ liteflow-script-lua
+ ${liteflow.version}
+
+
+
+
+ com.yomahub
+ liteflow-script-aviator
+ ${liteflow.version}
+
+
+
+
+ com.yomahub
+ liteflow-script-kotlin
+ ${liteflow.version}
+
+
org.dromara
ruoyi-system
@@ -370,6 +447,13 @@
${revision}
+
+
+ org.dromara
+ ruoyi-liteflow
+ ${revision}
+
+
diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml
index 610e9d706..0edfff176 100644
--- a/ruoyi-admin/pom.xml
+++ b/ruoyi-admin/pom.xml
@@ -86,6 +86,12 @@
ruoyi-workflow
+
+
+ org.dromara
+ ruoyi-liteflow
+
+
de.codecentric
spring-boot-admin-starter-client
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index 27de286f0..40ce94ee5 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -285,3 +285,24 @@ flowable:
enabled: false
app:
enabled: false
+
+--- # 规则引擎
+liteflow:
+ # 组件降级
+ fallback-cmp-enable: true
+ # 执行过程中的日志
+ print-execution-log: true
+ # 5000条规则以上的时候,开启可将加载性能能提高4倍
+ fast-load: false
+ # 默认线程池的worker数目
+ parallel-max-workers: 16
+ # 默认线程池的队列长度
+ parallel-queue-limit: 512
+ # 指定自定义的线程池全类名的方式指定异步循环线程池
+ # parallel-loop-executor-class:
+ rule-source-ext-data-map:
+ applicationName: @profiles.active@
+ #以下是轮询机制的配置
+ pollingEnabled: true
+ pollingStartSeconds: 600
+ pollingIntervalSeconds: 600
diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml
index 45493d3e9..b243e2e1e 100644
--- a/ruoyi-common/pom.xml
+++ b/ruoyi-common/pom.xml
@@ -20,6 +20,7 @@
ruoyi-common-log
ruoyi-common-mail
ruoyi-common-mybatis
+ ruoyi-common-liteflow
ruoyi-common-oss
ruoyi-common-ratelimiter
ruoyi-common-redis
diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml
index d546275c9..052b9ee27 100644
--- a/ruoyi-common/ruoyi-common-bom/pom.xml
+++ b/ruoyi-common/ruoyi-common-bom/pom.xml
@@ -47,6 +47,13 @@
${revision}
+
+
+ org.dromara
+ ruoyi-common-liteflow
+ ${revision}
+
+
org.dromara
diff --git a/ruoyi-common/ruoyi-common-liteflow/pom.xml b/ruoyi-common/ruoyi-common-liteflow/pom.xml
new file mode 100644
index 000000000..be04c605a
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-liteflow/pom.xml
@@ -0,0 +1,91 @@
+
+
+
+ org.dromara
+ ruoyi-common
+ ${revision}
+
+ 4.0.0
+
+ ruoyi-common-liteflow
+
+
+ ruoyi-common-liteflow 规则引擎
+
+
+
+
+
+
+ org.dromara
+ ruoyi-common-core
+
+
+
+ com.yomahub
+ liteflow-spring-boot-starter
+
+
+
+ com.yomahub
+ liteflow-core
+
+
+
+ com.yomahub
+ liteflow-rule-sql
+
+
+
+
+ com.yomahub
+ liteflow-script-lua
+
+
+
+
+ com.yomahub
+ liteflow-script-java
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/config/LiteFlowConfig.java b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/config/LiteFlowConfig.java
new file mode 100644
index 000000000..2b46c4c8e
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/config/LiteFlowConfig.java
@@ -0,0 +1,28 @@
+package org.dromara.common.liteflow.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.factory.YmlPropertySourceFactory;
+import org.dromara.common.liteflow.handler.LiteFlowExceptionHandler;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.PropertySource;
+
+/**
+ * LiteFlow 配置
+ *
+ * @author AprilWind
+ */
+@Slf4j
+@AutoConfiguration
+@PropertySource(value = "classpath:common-liteflow.yml", factory = YmlPropertySourceFactory.class)
+public class LiteFlowConfig {
+
+ /**
+ * 异常处理器
+ */
+ @Bean
+ public LiteFlowExceptionHandler liteFlowExceptionHandler() {
+ return new LiteFlowExceptionHandler();
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/constant/LiteFlowConstants.java b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/constant/LiteFlowConstants.java
new file mode 100644
index 000000000..f53fc0622
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/constant/LiteFlowConstants.java
@@ -0,0 +1,20 @@
+package org.dromara.common.liteflow.constant;
+
+/**
+ * Liteflow 常量
+ *
+ * @author AprilWind
+ */
+public interface LiteFlowConstants {
+
+ /**
+ * 激活
+ */
+ Integer LITEFLOW_NORMAL = 1;
+
+ /**
+ * 未激活
+ */
+ Integer LITEFLOW_DISABLE = 0;
+
+}
diff --git a/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/entity/LiteflowFlowBus.java b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/entity/LiteflowFlowBus.java
new file mode 100644
index 000000000..0521f4a36
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/entity/LiteflowFlowBus.java
@@ -0,0 +1,35 @@
+package org.dromara.common.liteflow.entity;
+
+import lombok.Data;
+import org.dromara.common.liteflow.enums.LiteflowType;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 规则引擎事件
+ *
+ * @author AprilWind
+ */
+@Data
+public class LiteflowFlowBus implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 规则引擎事件类型
+ */
+ private LiteflowType liteflowType;
+
+ /**
+ * 事件关联的ID
+ */
+ private String id;
+
+ /**
+ * 事件的内容
+ */
+ private String content;
+
+}
diff --git a/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/enums/LiteflowType.java b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/enums/LiteflowType.java
new file mode 100644
index 000000000..e807ffc93
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/enums/LiteflowType.java
@@ -0,0 +1,36 @@
+package org.dromara.common.liteflow.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 规则引擎事件枚举
+ *
+ * @author AprilWind
+ */
+@Getter
+@AllArgsConstructor
+public enum LiteflowType {
+
+ /**
+ * 重新加载规则
+ */
+ RELOAD_CHAIN("reload_chain"),
+
+ /**
+ * 移除规则
+ */
+ REMOVE_CHAIN("remove_chain"),
+
+ /**
+ * 重新加载脚本
+ */
+ RELOAD_SCRIPT("reload_script"),
+
+ /**
+ * 卸载脚本节点
+ */
+ UNLOAD_SCRIPT("unload_script");
+
+ private final String flowBus;
+}
diff --git a/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/handler/LiteFlowExceptionHandler.java b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/handler/LiteFlowExceptionHandler.java
new file mode 100644
index 000000000..ac1121497
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/handler/LiteFlowExceptionHandler.java
@@ -0,0 +1,30 @@
+package org.dromara.common.liteflow.handler;
+
+import cn.hutool.http.HttpStatus;
+import com.yomahub.liteflow.exception.LiteFlowException;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.R;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+/**
+ * LiteFlow 异常处理器
+ *
+ * @author AprilWind
+ */
+@Slf4j
+@RestControllerAdvice
+public class LiteFlowExceptionHandler {
+
+ /**
+ * 规则引擎内部逻辑发生错误抛出的异常
+ */
+ @ExceptionHandler(LiteFlowException.class)
+ public R handleLockFailureException(LiteFlowException e, HttpServletRequest request) {
+ String requestURI = request.getRequestURI();
+ log.error("处理请求'{}'时发生LiteFlow异常: ", requestURI, e);
+ return R.fail(HttpStatus.HTTP_INTERNAL_ERROR, "系统内部错误,请稍后再试...");
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-liteflow/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-liteflow/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 000000000..f02911399
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-liteflow/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.dromara.common.liteflow.config.LiteFlowConfig
diff --git a/ruoyi-common/ruoyi-common-liteflow/src/main/resources/common-liteflow.yml b/ruoyi-common/ruoyi-common-liteflow/src/main/resources/common-liteflow.yml
new file mode 100644
index 000000000..433ff313b
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-liteflow/src/main/resources/common-liteflow.yml
@@ -0,0 +1,35 @@
+# 规则引擎
+liteflow:
+ # 启动时不解析规则,但是第一次执行相关规则时,只解析对应的规则
+ parse-mode: PARSE_ONE_ON_FIRST_EXEC
+ rule-source-ext-data-map:
+ # 编排规则表
+ chainTableName: liteflow_chain
+ # 应用名称存储字段名
+ chainApplicationNameField: application_name
+ # 规则名称存储的字段名
+ chainNameField: chain_name
+ # EL表达式的字段(只存EL)
+ elDataField: el_str
+ # 决策路由EL字段
+ routeField: route
+ # namespace字段
+ namespaceField: name_space
+ # 是否生效 1为生效,0为不生效
+ chainEnableField: chain_status
+ # 脚本存储表的表名
+ scriptTableName: liteflow_script
+ # 应用名称存储字段名
+ scriptApplicationNameField: application_name
+ # 脚本组件的Id的字段名
+ scriptIdField: script_id
+ # 脚本组件名称的字段名
+ scriptNameField: script_name
+ # 脚本数据的字段名
+ scriptDataField: script_data
+ # 脚本类型的字段名
+ scriptTypeField: script_type
+ # 脚本语言类型(groovy | qlexpress | js | python | lua | aviator | java | kotlin)
+ scriptLanguageField: script_language
+ # 是否生效 1为生效,0为不生效
+ scriptEnableField: script_status
diff --git a/ruoyi-modules/pom.xml b/ruoyi-modules/pom.xml
index daff497a0..5df7b602e 100644
--- a/ruoyi-modules/pom.xml
+++ b/ruoyi-modules/pom.xml
@@ -15,6 +15,7 @@
ruoyi-job
ruoyi-system
ruoyi-workflow
+ ruoyi-liteflow
ruoyi-modules
diff --git a/ruoyi-modules/ruoyi-liteflow/pom.xml b/ruoyi-modules/ruoyi-liteflow/pom.xml
new file mode 100644
index 000000000..d4d911899
--- /dev/null
+++ b/ruoyi-modules/ruoyi-liteflow/pom.xml
@@ -0,0 +1,69 @@
+
+
+
+ org.dromara
+ ruoyi-modules
+ ${revision}
+
+ 4.0.0
+
+ ruoyi-liteflow
+
+
+ liteflow 规则引擎
+
+
+
+
+
+ org.dromara
+ ruoyi-common-doc
+
+
+
+ org.dromara
+ ruoyi-common-mybatis
+
+
+
+ org.dromara
+ ruoyi-common-translation
+
+
+
+ org.dromara
+ ruoyi-common-log
+
+
+
+
+ org.dromara
+ ruoyi-common-excel
+
+
+
+ org.dromara
+ ruoyi-common-tenant
+
+
+
+ org.dromara
+ ruoyi-common-web
+
+
+
+ org.dromara
+ ruoyi-common-idempotent
+
+
+
+
+ org.dromara
+ ruoyi-common-liteflow
+
+
+
+
+
diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/controller/LiteflowChainController.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/controller/LiteflowChainController.java
new file mode 100644
index 000000000..025191cd3
--- /dev/null
+++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/controller/LiteflowChainController.java
@@ -0,0 +1,109 @@
+package org.dromara.liteflow.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+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.excel.utils.ExcelUtil;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.liteflow.domain.bo.LiteflowChainBo;
+import org.dromara.liteflow.domain.vo.LiteflowChainVo;
+import org.dromara.liteflow.service.ILiteflowChainService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 编排规则
+ *
+ * @author AprilWind
+ * @date 2024-06-21
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/liteflow/chain")
+public class LiteflowChainController extends BaseController {
+
+ private final ILiteflowChainService liteflowChainService;
+
+ /**
+ * 查询编排规则列表
+ */
+ @SaCheckPermission("liteflow:chain:list")
+ @GetMapping("/list")
+ public TableDataInfo list(LiteflowChainBo bo, PageQuery pageQuery) {
+ return liteflowChainService.queryPageList(bo, pageQuery);
+ }
+
+ /**
+ * 导出编排规则列表
+ */
+ @SaCheckPermission("liteflow:chain:export")
+ @Log(title = "编排规则", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(LiteflowChainBo bo, HttpServletResponse response) {
+ List list = liteflowChainService.queryList(bo);
+ ExcelUtil.exportExcel(list, "编排规则", LiteflowChainVo.class, response);
+ }
+
+ /**
+ * 获取编排规则详细信息
+ *
+ * @param id 主键
+ */
+ @SaCheckPermission("liteflow:chain:query")
+ @GetMapping("/{id}")
+ public R getInfo(@NotNull(message = "主键不能为空")
+ @PathVariable Long id) {
+ return R.ok(liteflowChainService.queryById(id));
+ }
+
+ /**
+ * 新增编排规则
+ */
+ @SaCheckPermission("liteflow:chain:add")
+ @Log(title = "编排规则", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping()
+ public R add(@Validated(AddGroup.class) @RequestBody LiteflowChainBo bo) {
+ if (!liteflowChainService.checkChainNameUnique(bo)) {
+ return R.fail("新增编排规则'" + bo.getChainName() + "'失败,规则名称已存在");
+ }
+ return toAjax(liteflowChainService.insertByBo(bo));
+ }
+
+ /**
+ * 修改编排规则
+ */
+ @SaCheckPermission("liteflow:chain:edit")
+ @Log(title = "编排规则", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping()
+ public R edit(@Validated(EditGroup.class) @RequestBody LiteflowChainBo bo) {
+ return toAjax(liteflowChainService.updateByBo(bo));
+ }
+
+ /**
+ * 删除编排规则
+ *
+ * @param ids 主键串
+ */
+ @SaCheckPermission("liteflow:chain:remove")
+ @Log(title = "编排规则", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public R remove(@NotEmpty(message = "主键不能为空")
+ @PathVariable Long[] ids) {
+ return toAjax(liteflowChainService.deleteWithValidByIds(List.of(ids), true));
+ }
+}
diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/controller/LiteflowScriptController.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/controller/LiteflowScriptController.java
new file mode 100644
index 000000000..f6349fb62
--- /dev/null
+++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/controller/LiteflowScriptController.java
@@ -0,0 +1,109 @@
+package org.dromara.liteflow.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+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.excel.utils.ExcelUtil;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.liteflow.domain.bo.LiteflowScriptBo;
+import org.dromara.liteflow.domain.vo.LiteflowScriptVo;
+import org.dromara.liteflow.service.ILiteflowScriptService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 脚本
+ *
+ * @author AprilWind
+ * @date 2024-06-21
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/liteflow/script")
+public class LiteflowScriptController extends BaseController {
+
+ private final ILiteflowScriptService liteflowScriptService;
+
+ /**
+ * 查询脚本列表
+ */
+ @SaCheckPermission("liteflow:script:list")
+ @GetMapping("/list")
+ public TableDataInfo list(LiteflowScriptBo bo, PageQuery pageQuery) {
+ return liteflowScriptService.queryPageList(bo, pageQuery);
+ }
+
+ /**
+ * 导出脚本列表
+ */
+ @SaCheckPermission("liteflow:script:export")
+ @Log(title = "脚本", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(LiteflowScriptBo bo, HttpServletResponse response) {
+ List list = liteflowScriptService.queryList(bo);
+ ExcelUtil.exportExcel(list, "脚本", LiteflowScriptVo.class, response);
+ }
+
+ /**
+ * 获取脚本详细信息
+ *
+ * @param id 主键
+ */
+ @SaCheckPermission("liteflow:script:query")
+ @GetMapping("/{id}")
+ public R getInfo(@NotNull(message = "主键不能为空")
+ @PathVariable Long id) {
+ return R.ok(liteflowScriptService.queryById(id));
+ }
+
+ /**
+ * 新增脚本
+ */
+ @SaCheckPermission("liteflow:script:add")
+ @Log(title = "脚本", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping()
+ public R add(@Validated(AddGroup.class) @RequestBody LiteflowScriptBo bo) {
+ if (!liteflowScriptService.checkScriptIdUnique(bo)) {
+ return R.fail("新增脚本'" + bo.getScriptId() + "'失败,脚本ID已存在");
+ }
+ return toAjax(liteflowScriptService.insertByBo(bo));
+ }
+
+ /**
+ * 修改脚本
+ */
+ @SaCheckPermission("liteflow:script:edit")
+ @Log(title = "脚本", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping()
+ public R edit(@Validated(EditGroup.class) @RequestBody LiteflowScriptBo bo) {
+ return toAjax(liteflowScriptService.updateByBo(bo));
+ }
+
+ /**
+ * 删除脚本
+ *
+ * @param ids 主键串
+ */
+ @SaCheckPermission("liteflow:script:remove")
+ @Log(title = "脚本", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public R remove(@NotEmpty(message = "主键不能为空")
+ @PathVariable Long[] ids) {
+ return toAjax(liteflowScriptService.deleteWithValidByIds(List.of(ids), true));
+ }
+}
diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/LiteflowChain.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/LiteflowChain.java
new file mode 100644
index 000000000..e5e985908
--- /dev/null
+++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/LiteflowChain.java
@@ -0,0 +1,74 @@
+package org.dromara.liteflow.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+
+import java.io.Serial;
+
+/**
+ * 编排规则对象 liteflow_chain
+ *
+ * @author AprilWind
+ * @date 2024-06-21
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("liteflow_chain")
+public class LiteflowChain extends BaseEntity {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * id
+ */
+ @TableId(value = "id")
+ private Long id;
+
+ /**
+ * 配置环境
+ */
+ private String applicationName;
+
+ /**
+ * 编排规则ID
+ */
+ private String chainName;
+
+ /**
+ * 状态(0未激活 1激活)
+ */
+ private Integer chainStatus;
+
+ /**
+ * EL表达式
+ */
+ private String elStr;
+
+ /**
+ * namespace(决策路由很多,想要判断某一组决策路由时在chain层面加入namespace参数)
+ */
+ private String nameSpace;
+
+ /**
+ * 决策路由EL
+ */
+ private String route;
+
+ /**
+ * 删除标志(0代表存在 2代表删除)
+ */
+ @TableLogic
+ private String delFlag;
+
+ /**
+ * 备注
+ */
+ private String remark;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/LiteflowScript.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/LiteflowScript.java
new file mode 100644
index 000000000..3c93f5cb4
--- /dev/null
+++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/LiteflowScript.java
@@ -0,0 +1,79 @@
+package org.dromara.liteflow.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+
+import java.io.Serial;
+
+/**
+ * 脚本对象 liteflow_script
+ *
+ * @author AprilWind
+ * @date 2024-06-21
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("liteflow_script")
+public class LiteflowScript extends BaseEntity {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * id
+ */
+ @TableId(value = "id")
+ private Long id;
+
+ /**
+ * 配置环境
+ */
+ private String applicationName;
+
+ /**
+ * 脚本ID
+ */
+ private String scriptId;
+
+ /**
+ * 脚本名称
+ */
+ private String scriptName;
+
+ /**
+ * 脚本语言类型(groovy | qlexpress | js | python | lua | aviator | java | kotlin)
+ */
+ private String scriptLanguage;
+
+ /**
+ * 脚本类型(script普通脚本节点,脚本里无需返回 switch_script选择脚本节点,脚本里需要返回选择的节点Id boolean_script条件脚本节点,脚本里需要返回true/false for_script数量循环节点,脚本里需要返回数值类型,表示循环次数)
+ */
+ private String scriptType;
+
+ /**
+ * 状态(0未激活 1激活)
+ */
+ private Integer scriptStatus;
+
+ /**
+ * 脚本内容
+ */
+ private String scriptData;
+
+ /**
+ * 删除标志(0代表存在 2代表删除)
+ */
+ @TableLogic
+ private String delFlag;
+
+ /**
+ * 备注
+ */
+ private String remark;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/bo/LiteflowChainBo.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/bo/LiteflowChainBo.java
new file mode 100644
index 000000000..5a052771b
--- /dev/null
+++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/bo/LiteflowChainBo.java
@@ -0,0 +1,69 @@
+package org.dromara.liteflow.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.liteflow.domain.LiteflowChain;
+
+/**
+ * 编排规则业务对象 liteflow_chain
+ *
+ * @author AprilWind
+ * @date 2024-06-21
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = LiteflowChain.class, reverseConvertGenerate = false)
+public class LiteflowChainBo extends BaseEntity {
+
+ /**
+ * id
+ */
+ @NotNull(message = "id不能为空", groups = {EditGroup.class})
+ private Long id;
+
+ /**
+ * 配置环境
+ */
+ @NotBlank(message = "配置环境不能为空", groups = {AddGroup.class})
+ private String applicationName;
+
+ /**
+ * 编排规则ID
+ */
+ @NotBlank(message = "编排规则ID不能为空", groups = {AddGroup.class})
+ private String chainName;
+
+ /**
+ * 状态(0未激活 1激活)
+ */
+ private Integer chainStatus;
+
+ /**
+ * EL表达式
+ */
+ @NotBlank(message = "EL表达式不能为空", groups = {AddGroup.class, EditGroup.class})
+ private String elStr;
+
+ /**
+ * namespace(决策路由很多,想要判断某一组决策路由时在chain层面加入namespace参数)
+ */
+ private String nameSpace;
+
+ /**
+ * 决策路由EL
+ */
+ private String route;
+
+ /**
+ * 备注
+ */
+ @NotBlank(message = "备注不能为空", groups = {AddGroup.class, EditGroup.class})
+ private String remark;
+
+}
diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/bo/LiteflowScriptBo.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/bo/LiteflowScriptBo.java
new file mode 100644
index 000000000..fe576f8d0
--- /dev/null
+++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/bo/LiteflowScriptBo.java
@@ -0,0 +1,77 @@
+package org.dromara.liteflow.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.liteflow.domain.LiteflowScript;
+
+/**
+ * 脚本业务对象 liteflow_script
+ *
+ * @author AprilWind
+ * @date 2024-06-21
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = LiteflowScript.class, reverseConvertGenerate = false)
+public class LiteflowScriptBo extends BaseEntity {
+
+ /**
+ * id
+ */
+ @NotNull(message = "id不能为空", groups = {EditGroup.class})
+ private Long id;
+
+ /**
+ * 配置环境
+ */
+ @NotBlank(message = "配置环境不能为空", groups = {AddGroup.class})
+ private String applicationName;
+
+ /**
+ * 脚本ID
+ */
+ @NotBlank(message = "脚本ID不能为空", groups = {AddGroup.class})
+ private String scriptId;
+
+ /**
+ * 脚本名称
+ */
+ @NotBlank(message = "脚本名称不能为空", groups = {AddGroup.class})
+ private String scriptName;
+
+ /**
+ * 脚本语言类型(groovy | qlexpress | js | python | lua | aviator | java | kotlin)
+ */
+ @NotBlank(message = "脚本语言类型不能为空", groups = {AddGroup.class})
+ private String scriptLanguage;
+
+ /**
+ * 脚本类型(script普通脚本节点,脚本里无需返回 switch_script选择脚本节点,脚本里需要返回选择的节点Id boolean_script条件脚本节点,脚本里需要返回true/false for_script数量循环节点,脚本里需要返回数值类型,表示循环次数)
+ */
+ @NotBlank(message = "脚本类型不能为空", groups = {AddGroup.class})
+ private String scriptType;
+
+ /**
+ * 状态(0未激活 1激活)
+ */
+ private Integer scriptStatus;
+
+ /**
+ * 脚本内容
+ */
+ @NotBlank(message = "脚本内容不能为空", groups = {AddGroup.class, EditGroup.class})
+ private String scriptData;
+
+ /**
+ * 备注
+ */
+ @NotBlank(message = "备注不能为空", groups = {AddGroup.class, EditGroup.class})
+ private String remark;
+
+}
diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/vo/LiteflowChainVo.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/vo/LiteflowChainVo.java
new file mode 100644
index 000000000..1de01ca5e
--- /dev/null
+++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/vo/LiteflowChainVo.java
@@ -0,0 +1,78 @@
+package org.dromara.liteflow.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.liteflow.domain.LiteflowChain;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+
+/**
+ * 编排规则视图对象 liteflow_chain
+ *
+ * @author AprilWind
+ * @date 2024-06-21
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = LiteflowChain.class)
+public class LiteflowChainVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * id
+ */
+ @ExcelProperty(value = "id")
+ private Long id;
+
+ /**
+ * 配置环境
+ */
+ @ExcelProperty(value = "配置环境")
+ private String applicationName;
+
+ /**
+ * 编排规则ID
+ */
+ @ExcelProperty(value = "编排规则ID")
+ private String chainName;
+
+ /**
+ * 状态(0未激活 1激活)
+ */
+ @ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(readConverterExp = "0=未激活,1=激活")
+ private Integer chainStatus;
+
+ /**
+ * EL表达式
+ */
+ @ExcelProperty(value = "EL表达式")
+ private String elStr;
+
+ /**
+ * namespace(决策路由很多,想要判断某一组决策路由时在chain层面加入namespace参数)
+ */
+ @ExcelProperty(value = "namespace", converter = ExcelDictConvert.class)
+ private String nameSpace;
+
+ /**
+ * 决策路由EL
+ */
+ @ExcelProperty(value = "决策路由EL")
+ private String route;
+
+ /**
+ * 备注
+ */
+ @ExcelProperty(value = "备注")
+ private String remark;
+
+}
diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/vo/LiteflowScriptVo.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/vo/LiteflowScriptVo.java
new file mode 100644
index 000000000..97cf41254
--- /dev/null
+++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/vo/LiteflowScriptVo.java
@@ -0,0 +1,83 @@
+package org.dromara.liteflow.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.liteflow.domain.LiteflowScript;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 脚本视图对象 liteflow_script
+ *
+ * @author AprilWind
+ * @date 2024-06-21
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = LiteflowScript.class)
+public class LiteflowScriptVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * id
+ */
+ @ExcelProperty(value = "id")
+ private Long id;
+
+ /**
+ * 配置环境
+ */
+ @ExcelProperty(value = "配置环境")
+ private String applicationName;
+
+ /**
+ * 脚本ID
+ */
+ @ExcelProperty(value = "脚本ID")
+ private String scriptId;
+
+ /**
+ * 脚本名称
+ */
+ @ExcelProperty(value = "脚本名称")
+ private String scriptName;
+
+ /**
+ * 脚本语言类型(groovy | qlexpress | js | python | lua | aviator | java | kotlin)
+ */
+ @ExcelProperty(value = "脚本语言类型", converter = ExcelDictConvert.class)
+ private String scriptLanguage;
+
+ /**
+ * 脚本类型(script普通脚本节点,脚本里无需返回 switch_script选择脚本节点,脚本里需要返回选择的节点Id boolean_script条件脚本节点,脚本里需要返回true/false for_script数量循环节点,脚本里需要返回数值类型,表示循环次数)
+ */
+ @ExcelProperty(value = "脚本类型")
+ private String scriptType;
+
+ /**
+ * 状态(0未激活 1激活)
+ */
+ @ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(readConverterExp = "0=未激活,1=激活")
+ private Integer scriptStatus;
+
+ /**
+ * 脚本内容
+ */
+ @ExcelProperty(value = "脚本内容")
+ private String scriptData;
+
+ /**
+ * 备注
+ */
+ @ExcelProperty(value = "备注")
+ private String remark;
+
+}
diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/listener/LiteflowListener.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/listener/LiteflowListener.java
new file mode 100644
index 000000000..df67c6706
--- /dev/null
+++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/listener/LiteflowListener.java
@@ -0,0 +1,79 @@
+package org.dromara.liteflow.listener;
+
+import com.yomahub.liteflow.flow.FlowBus;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.liteflow.entity.LiteflowFlowBus;
+import org.dromara.common.liteflow.enums.LiteflowType;
+import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * 规则引擎 侦听器
+ *
+ * @author AprilWind
+ * @date 2024-06-21
+ */
+@RequiredArgsConstructor
+@Component
+@Slf4j
+public class LiteflowListener {
+
+ /**
+ * 处理规则引擎事件
+ *
+ * @param liteflowFlowBus 包含规则引擎事件信息的对象
+ */
+ @Async
+ @EventListener
+ public void handleLiteflowEvent(LiteflowFlowBus liteflowFlowBus) {
+ // 获取事件的类型
+ LiteflowType flowBusType = liteflowFlowBus.getLiteflowType();
+ // 获取事件关联的ID
+ String id = liteflowFlowBus.getId();
+ // 获取事件的内容
+ String content = liteflowFlowBus.getContent();
+
+ // 根据事件类型执行相应的操作
+ switch (flowBusType) {
+ case RELOAD_CHAIN:
+ // 重新加载链式规则
+ FlowBus.reloadChain(id, content);
+ log.info("重新加载链式规则:{}", id);
+ break;
+ case REMOVE_CHAIN:
+ // 移除链式规则
+ FlowBus.removeChain(id);
+ log.info("移除链式规则:{}", id);
+ break;
+ case RELOAD_SCRIPT:
+ // 重新加载脚本
+ FlowBus.reloadScript(id, content);
+ log.info("重新加载脚本:{}", id);
+ break;
+ case UNLOAD_SCRIPT:
+ // 卸载脚本节点
+ FlowBus.unloadScriptNode(id);
+ log.info("卸载脚本节点:{}", id);
+ break;
+ default:
+ log.error("未知的LiteflowType: {}", flowBusType);
+ }
+ }
+
+ /**
+ * 异步处理规则引擎事件列表
+ * 注意:虽然方法标记了 @Async 注解,但内部的方法调用不会异步执行,需要手动使用 TaskExecutor 实现异步
+ *
+ * @param liteflowFlowBus 包含规则引擎事件信息的对象列表
+ */
+ @Async
+ @EventListener
+ public void handleLiteflowEvent(List liteflowFlowBus) {
+ liteflowFlowBus.forEach(this::handleLiteflowEvent);
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/mapper/LiteflowChainMapper.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/mapper/LiteflowChainMapper.java
new file mode 100644
index 000000000..59c8583e0
--- /dev/null
+++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/mapper/LiteflowChainMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.liteflow.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.liteflow.domain.LiteflowChain;
+import org.dromara.liteflow.domain.vo.LiteflowChainVo;
+
+/**
+ * 编排规则Mapper接口
+ *
+ * @author AprilWind
+ * @date 2024-06-21
+ */
+public interface LiteflowChainMapper extends BaseMapperPlus {
+
+}
diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/mapper/LiteflowScriptMapper.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/mapper/LiteflowScriptMapper.java
new file mode 100644
index 000000000..a4323f277
--- /dev/null
+++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/mapper/LiteflowScriptMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.liteflow.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.liteflow.domain.LiteflowScript;
+import org.dromara.liteflow.domain.vo.LiteflowScriptVo;
+
+/**
+ * 脚本Mapper接口
+ *
+ * @author AprilWind
+ * @date 2024-06-21
+ */
+public interface LiteflowScriptMapper extends BaseMapperPlus {
+
+}
diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/ILiteflowChainService.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/ILiteflowChainService.java
new file mode 100644
index 000000000..d78ead4ec
--- /dev/null
+++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/ILiteflowChainService.java
@@ -0,0 +1,76 @@
+package org.dromara.liteflow.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.liteflow.domain.bo.LiteflowChainBo;
+import org.dromara.liteflow.domain.vo.LiteflowChainVo;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 编排规则Service接口
+ *
+ * @author AprilWind
+ * @date 2024-06-21
+ */
+public interface ILiteflowChainService {
+
+ /**
+ * 查询编排规则
+ *
+ * @param id 主键
+ * @return 编排规则
+ */
+ LiteflowChainVo queryById(Long id);
+
+ /**
+ * 分页查询编排规则列表
+ *
+ * @param bo 查询条件
+ * @param pageQuery 分页参数
+ * @return 编排规则分页列表
+ */
+ TableDataInfo queryPageList(LiteflowChainBo bo, PageQuery pageQuery);
+
+ /**
+ * 查询符合条件的编排规则列表
+ *
+ * @param bo 查询条件
+ * @return 编排规则列表
+ */
+ List queryList(LiteflowChainBo bo);
+
+ /**
+ * 校验编排规则ID是否唯一
+ *
+ * @param chain 规则信息
+ * @return 结果,true表示唯一,false表示不唯一
+ */
+ boolean checkChainNameUnique(LiteflowChainBo chain);
+
+ /**
+ * 新增编排规则
+ *
+ * @param bo 编排规则
+ * @return 是否新增成功
+ */
+ Boolean insertByBo(LiteflowChainBo bo);
+
+ /**
+ * 修改编排规则
+ *
+ * @param bo 编排规则
+ * @return 是否修改成功
+ */
+ Boolean updateByBo(LiteflowChainBo bo);
+
+ /**
+ * 校验并批量删除编排规则信息
+ *
+ * @param ids 待删除的主键集合
+ * @param isValid 是否进行有效性校验
+ * @return 是否删除成功
+ */
+ Boolean deleteWithValidByIds(Collection ids, Boolean isValid);
+}
diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/ILiteflowScriptService.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/ILiteflowScriptService.java
new file mode 100644
index 000000000..6fe4b434e
--- /dev/null
+++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/ILiteflowScriptService.java
@@ -0,0 +1,76 @@
+package org.dromara.liteflow.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.liteflow.domain.bo.LiteflowScriptBo;
+import org.dromara.liteflow.domain.vo.LiteflowScriptVo;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 脚本Service接口
+ *
+ * @author AprilWind
+ * @date 2024-06-21
+ */
+public interface ILiteflowScriptService {
+
+ /**
+ * 查询脚本
+ *
+ * @param id 主键
+ * @return 脚本
+ */
+ LiteflowScriptVo queryById(Long id);
+
+ /**
+ * 分页查询脚本列表
+ *
+ * @param bo 查询条件
+ * @param pageQuery 分页参数
+ * @return 脚本分页列表
+ */
+ TableDataInfo queryPageList(LiteflowScriptBo bo, PageQuery pageQuery);
+
+ /**
+ * 查询符合条件的脚本列表
+ *
+ * @param bo 查询条件
+ * @return 脚本列表
+ */
+ List queryList(LiteflowScriptBo bo);
+
+ /**
+ * 校验脚本ID是否唯一
+ *
+ * @param script 脚本信息
+ * @return 结果,true表示唯一,false表示不唯一
+ */
+ boolean checkScriptIdUnique(LiteflowScriptBo script);
+
+ /**
+ * 新增脚本
+ *
+ * @param bo 脚本
+ * @return 是否新增成功
+ */
+ Boolean insertByBo(LiteflowScriptBo bo);
+
+ /**
+ * 修改脚本
+ *
+ * @param bo 脚本
+ * @return 是否修改成功
+ */
+ Boolean updateByBo(LiteflowScriptBo bo);
+
+ /**
+ * 校验并批量删除脚本信息
+ *
+ * @param ids 待删除的主键集合
+ * @param isValid 是否进行有效性校验
+ * @return 是否删除成功
+ */
+ Boolean deleteWithValidByIds(Collection ids, Boolean isValid);
+}
diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/impl/LiteflowChainServiceImpl.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/impl/LiteflowChainServiceImpl.java
new file mode 100644
index 000000000..54c6cecb3
--- /dev/null
+++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/impl/LiteflowChainServiceImpl.java
@@ -0,0 +1,191 @@
+package org.dromara.liteflow.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.liteflow.entity.LiteflowFlowBus;
+import org.dromara.common.liteflow.enums.LiteflowType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.liteflow.domain.LiteflowChain;
+import org.dromara.liteflow.domain.bo.LiteflowChainBo;
+import org.dromara.liteflow.domain.vo.LiteflowChainVo;
+import org.dromara.liteflow.mapper.LiteflowChainMapper;
+import org.dromara.liteflow.service.ILiteflowChainService;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static org.dromara.common.liteflow.constant.LiteFlowConstants.LITEFLOW_DISABLE;
+import static org.dromara.common.liteflow.constant.LiteFlowConstants.LITEFLOW_NORMAL;
+
+/**
+ * 编排规则Service业务层处理
+ *
+ * @author AprilWind
+ * @date 2024-06-21
+ */
+@RequiredArgsConstructor
+@Service
+public class LiteflowChainServiceImpl implements ILiteflowChainService {
+
+ private final LiteflowChainMapper baseMapper;
+
+ /**
+ * 查询编排规则
+ *
+ * @param id 主键
+ * @return 编排规则
+ */
+ @Override
+ public LiteflowChainVo queryById(Long id) {
+ return baseMapper.selectVoById(id);
+ }
+
+ /**
+ * 分页查询编排规则列表
+ *
+ * @param bo 查询条件
+ * @param pageQuery 分页参数
+ * @return 编排规则分页列表
+ */
+ @Override
+ public TableDataInfo queryPageList(LiteflowChainBo bo, PageQuery pageQuery) {
+ LambdaQueryWrapper lqw = buildQueryWrapper(bo);
+ Page result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ return TableDataInfo.build(result);
+ }
+
+ /**
+ * 查询符合条件的编排规则列表
+ *
+ * @param bo 查询条件
+ * @return 编排规则列表
+ */
+ @Override
+ public List queryList(LiteflowChainBo bo) {
+ LambdaQueryWrapper lqw = buildQueryWrapper(bo);
+ return baseMapper.selectVoList(lqw);
+ }
+
+ private LambdaQueryWrapper buildQueryWrapper(LiteflowChainBo bo) {
+ Map params = bo.getParams();
+ LambdaQueryWrapper lqw = Wrappers.lambdaQuery();
+ lqw.eq(StringUtils.isNotBlank(bo.getApplicationName()), LiteflowChain::getApplicationName, bo.getApplicationName());
+ lqw.eq(StringUtils.isNotBlank(bo.getChainName()), LiteflowChain::getChainName, bo.getChainName());
+ lqw.eq(bo.getChainStatus() != null, LiteflowChain::getChainStatus, bo.getChainStatus());
+ lqw.eq(StringUtils.isNotBlank(bo.getNameSpace()), LiteflowChain::getNameSpace, bo.getNameSpace());
+ lqw.like(StringUtils.isNotBlank(bo.getRemark()), LiteflowChain::getRemark, bo.getRemark());
+ return lqw;
+ }
+
+ /**
+ * 校验编排规则ID是否唯一
+ *
+ * @param chain 规则信息
+ * @return 结果,true表示唯一,false表示不唯一
+ */
+ @Override
+ public boolean checkChainNameUnique(LiteflowChainBo chain) {
+ boolean exist = baseMapper.exists(new LambdaQueryWrapper()
+ .eq(LiteflowChain::getApplicationName, chain.getApplicationName())
+ .eq(LiteflowChain::getChainName, chain.getChainName())
+ .ne(ObjectUtil.isNotNull(chain.getId()), LiteflowChain::getId, chain.getId()));
+ return !exist;
+ }
+
+ /**
+ * 新增编排规则
+ *
+ * @param bo 编排规则
+ * @return 是否新增成功
+ */
+ @Override
+ public Boolean insertByBo(LiteflowChainBo bo) {
+ LiteflowChain add = MapstructUtils.convert(bo, LiteflowChain.class);
+ validEntityBeforeSave(add);
+ boolean flag = baseMapper.insert(add) > 0;
+ if (flag) {
+ bo.setId(add.getId());
+ }
+ return flag;
+ }
+
+ /**
+ * 修改编排规则
+ *
+ * @param bo 编排规则
+ * @return 是否修改成功
+ */
+ @Override
+ public Boolean updateByBo(LiteflowChainBo bo) {
+ LiteflowChain update = MapstructUtils.convert(bo, LiteflowChain.class);
+ validEntityBeforeSave(update);
+ LiteflowChainVo vo = baseMapper.selectVoById(bo.getId());
+ if (LITEFLOW_NORMAL.equals(vo.getChainStatus())) {
+ LiteflowFlowBus bus = new LiteflowFlowBus();
+ bus.setId(vo.getChainName());
+ if (LITEFLOW_DISABLE.equals(update.getChainStatus())) {
+ bus.setLiteflowType(LiteflowType.REMOVE_CHAIN);
+ } else {
+ bus.setLiteflowType(LiteflowType.RELOAD_CHAIN);
+ bus.setContent(update.getElStr());
+ }
+ SpringUtils.context().publishEvent(bus);
+ }
+ return baseMapper.updateById(update) > 0;
+ }
+
+ /**
+ * 保存前的数据校验
+ */
+ private void validEntityBeforeSave(LiteflowChain entity) {
+ // 校验EL表达式
+ if (!LiteFlowChainELBuilder.validate(entity.getElStr())) {
+ throw new ServiceException("EL表达式校验失败!");
+ }
+ // 如果路由不为空,校验路由
+ if (StringUtils.isNotBlank(entity.getRoute()) && !LiteFlowChainELBuilder.validate(entity.getRoute())) {
+ throw new ServiceException("决策路由EL校验失败!");
+ }
+ }
+
+ /**
+ * 校验并批量删除编排规则信息
+ *
+ * @param ids 待删除的主键集合
+ * @param isValid 是否进行有效性校验
+ * @return 是否删除成功
+ */
+ @Override
+ public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) {
+ List liteflowChainVos = baseMapper.selectVoList(
+ new LambdaQueryWrapper().in(LiteflowChain::getId, ids));
+ if (isValid) {
+ if (CollUtil.isEmpty(liteflowChainVos)) {
+ return true;
+ }
+ }
+ List liteflowFlowBus = liteflowChainVos.stream()
+ .map(x -> {
+ LiteflowFlowBus flowBus = new LiteflowFlowBus();
+ flowBus.setLiteflowType(LiteflowType.REMOVE_CHAIN);
+ flowBus.setId(x.getChainName());
+ return flowBus;
+ }).collect(Collectors.toList());
+ // 发布规则引擎事件
+ SpringUtils.context().publishEvent(liteflowFlowBus);
+ return baseMapper.deleteByIds(ids) > 0;
+ }
+}
diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/impl/LiteflowScriptServiceImpl.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/impl/LiteflowScriptServiceImpl.java
new file mode 100644
index 000000000..ba6e113f6
--- /dev/null
+++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/impl/LiteflowScriptServiceImpl.java
@@ -0,0 +1,198 @@
+package org.dromara.liteflow.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.yomahub.liteflow.enums.ScriptTypeEnum;
+import com.yomahub.liteflow.script.validator.ScriptValidator;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.liteflow.entity.LiteflowFlowBus;
+import org.dromara.common.liteflow.enums.LiteflowType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.liteflow.domain.LiteflowScript;
+import org.dromara.liteflow.domain.bo.LiteflowScriptBo;
+import org.dromara.liteflow.domain.vo.LiteflowScriptVo;
+import org.dromara.liteflow.mapper.LiteflowScriptMapper;
+import org.dromara.liteflow.service.ILiteflowScriptService;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static org.dromara.common.liteflow.constant.LiteFlowConstants.LITEFLOW_DISABLE;
+import static org.dromara.common.liteflow.constant.LiteFlowConstants.LITEFLOW_NORMAL;
+
+/**
+ * 脚本Service业务层处理
+ *
+ * @author AprilWind
+ * @date 2024-06-21
+ */
+@RequiredArgsConstructor
+@Service
+public class LiteflowScriptServiceImpl implements ILiteflowScriptService {
+
+ private final LiteflowScriptMapper baseMapper;
+
+ /**
+ * 查询脚本
+ *
+ * @param id 主键
+ * @return 脚本
+ */
+ @Override
+ public LiteflowScriptVo queryById(Long id) {
+ return baseMapper.selectVoById(id);
+ }
+
+ /**
+ * 分页查询脚本列表
+ *
+ * @param bo 查询条件
+ * @param pageQuery 分页参数
+ * @return 脚本分页列表
+ */
+ @Override
+ public TableDataInfo queryPageList(LiteflowScriptBo bo, PageQuery pageQuery) {
+ LambdaQueryWrapper lqw = buildQueryWrapper(bo);
+ Page result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ return TableDataInfo.build(result);
+ }
+
+ /**
+ * 查询符合条件的脚本列表
+ *
+ * @param bo 查询条件
+ * @return 脚本列表
+ */
+ @Override
+ public List queryList(LiteflowScriptBo bo) {
+ LambdaQueryWrapper lqw = buildQueryWrapper(bo);
+ return baseMapper.selectVoList(lqw);
+ }
+
+ private LambdaQueryWrapper buildQueryWrapper(LiteflowScriptBo bo) {
+ Map params = bo.getParams();
+ LambdaQueryWrapper lqw = Wrappers.lambdaQuery();
+ lqw.eq(StringUtils.isNotBlank(bo.getApplicationName()), LiteflowScript::getApplicationName, bo.getApplicationName());
+ lqw.eq(StringUtils.isNotBlank(bo.getScriptId()), LiteflowScript::getScriptId, bo.getScriptId());
+ lqw.eq(StringUtils.isNotBlank(bo.getScriptName()), LiteflowScript::getScriptName, bo.getScriptName());
+ lqw.eq(StringUtils.isNotBlank(bo.getScriptLanguage()), LiteflowScript::getScriptLanguage, bo.getScriptLanguage());
+ lqw.eq(StringUtils.isNotBlank(bo.getScriptType()), LiteflowScript::getScriptType, bo.getScriptType());
+ lqw.eq(bo.getScriptStatus() != null, LiteflowScript::getScriptStatus, bo.getScriptStatus());
+ lqw.like(StringUtils.isNotBlank(bo.getRemark()), LiteflowScript::getRemark, bo.getRemark());
+ return lqw;
+ }
+
+ /**
+ * 校验脚本ID是否唯一
+ *
+ * @param script 脚本信息
+ * @return 结果,true表示唯一,false表示不唯一
+ */
+ @Override
+ public boolean checkScriptIdUnique(LiteflowScriptBo script) {
+ boolean exist = baseMapper.exists(new LambdaQueryWrapper()
+ .eq(LiteflowScript::getApplicationName, script.getApplicationName())
+ .eq(LiteflowScript::getScriptId, script.getScriptId())
+ .ne(ObjectUtil.isNotNull(script.getId()), LiteflowScript::getId, script.getId()));
+ return !exist;
+ }
+
+ /**
+ * 新增脚本
+ *
+ * @param bo 脚本
+ * @return 是否新增成功
+ */
+ @Override
+ public Boolean insertByBo(LiteflowScriptBo bo) {
+ LiteflowScript add = MapstructUtils.convert(bo, LiteflowScript.class);
+ validEntityBeforeSave(add);
+ boolean flag = baseMapper.insert(add) > 0;
+ if (flag) {
+ bo.setId(add.getId());
+ }
+ return flag;
+ }
+
+ /**
+ * 修改脚本
+ *
+ * @param bo 脚本
+ * @return 是否修改成功
+ */
+ @Override
+ public Boolean updateByBo(LiteflowScriptBo bo) {
+ LiteflowScript update = MapstructUtils.convert(bo, LiteflowScript.class);
+ validEntityBeforeSave(update);
+ LiteflowScriptVo vo = baseMapper.selectVoById(update.getId());
+
+ if (LITEFLOW_NORMAL.equals(vo.getScriptStatus())) {
+ LiteflowFlowBus bus = new LiteflowFlowBus();
+ bus.setId(vo.getScriptId());
+ if (LITEFLOW_DISABLE.equals(update.getScriptStatus())) {
+ bus.setLiteflowType(LiteflowType.UNLOAD_SCRIPT);
+ } else {
+ bus.setLiteflowType(LiteflowType.RELOAD_SCRIPT);
+ bus.setContent(update.getScriptData());
+ }
+ SpringUtils.context().publishEvent(bus);
+ }
+ return baseMapper.updateById(update) > 0;
+ }
+
+ /**
+ * 保存前的数据校验
+ */
+ private void validEntityBeforeSave(LiteflowScript entity) {
+ // 检查脚本语言是否合法
+ if (!ScriptTypeEnum.checkScriptType(entity.getScriptLanguage())) {
+ throw new ServiceException("脚本语言不合法!");
+ }
+
+ ScriptTypeEnum enumByDisplayName = ScriptTypeEnum.getEnumByDisplayName(entity.getScriptLanguage());
+ // 验证脚本数据是否符合规范
+ if (!ScriptValidator.validate(entity.getScriptData(), enumByDisplayName)) {
+ // 具体错误请查看日志,暂不支持返回错误详细异常信息
+ throw new ServiceException("脚本内容不规范!");
+ }
+ }
+
+ /**
+ * 校验并批量删除脚本信息
+ *
+ * @param ids 待删除的主键集合
+ * @param isValid 是否进行有效性校验
+ * @return 是否删除成功
+ */
+ @Override
+ public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) {
+ List liteflowScriptVos = baseMapper.selectVoList(
+ new LambdaQueryWrapper().in(LiteflowScript::getId, ids));
+ if (isValid) {
+ if (CollUtil.isEmpty(liteflowScriptVos)) {
+ return true;
+ }
+ }
+ List liteflowFlowBus = liteflowScriptVos.stream()
+ .map(x -> {
+ LiteflowFlowBus flowBus = new LiteflowFlowBus();
+ flowBus.setLiteflowType(LiteflowType.UNLOAD_SCRIPT);
+ flowBus.setId(x.getScriptId());
+ return flowBus;
+ }).collect(Collectors.toList());
+ // 发布规则引擎事件
+ SpringUtils.context().publishEvent(liteflowFlowBus);
+ return baseMapper.deleteByIds(ids) > 0;
+ }
+}
diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/resources/mapper/liteflow/LiteflowChainMapper.xml b/ruoyi-modules/ruoyi-liteflow/src/main/resources/mapper/liteflow/LiteflowChainMapper.xml
new file mode 100644
index 000000000..f1fb6e316
--- /dev/null
+++ b/ruoyi-modules/ruoyi-liteflow/src/main/resources/mapper/liteflow/LiteflowChainMapper.xml
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/resources/mapper/liteflow/LiteflowScriptMapper.xml b/ruoyi-modules/ruoyi-liteflow/src/main/resources/mapper/liteflow/LiteflowScriptMapper.xml
new file mode 100644
index 000000000..181918848
--- /dev/null
+++ b/ruoyi-modules/ruoyi-liteflow/src/main/resources/mapper/liteflow/LiteflowScriptMapper.xml
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/script/sql/liteflow.sql b/script/sql/liteflow.sql
new file mode 100644
index 000000000..b1a3d6cd9
--- /dev/null
+++ b/script/sql/liteflow.sql
@@ -0,0 +1,38 @@
+CREATE TABLE liteflow_chain
+(
+ `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
+ `application_name` varchar(32) NOT NULL COMMENT '配置环境',
+ `chain_name` varchar(32) NOT NULL COMMENT '编排规则ID',
+ `chain_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '状态(0未激活 1激活)',
+ `el_str` text NOT NULL COMMENT 'EL表达式',
+ `name_space` varchar(32) DEFAULT NULL COMMENT 'namespace(决策路由很多,想要判断某一组决策路由时在chain层面加入namespace参数)',
+ `route` text COMMENT '决策路由EL',
+ `del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
+ `create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
+ `create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `remark` varchar(500) DEFAULT NULL COMMENT '备注',
+ PRIMARY KEY (`id`)
+) engine = innodb comment = '编排规则表';
+
+CREATE TABLE liteflow_script
+(
+ `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
+ `application_name` varchar(32) NOT NULL COMMENT '配置环境',
+ `script_id` varchar(32) NOT NULL COMMENT '脚本ID',
+ `script_name` varchar(64) NOT NULL COMMENT '脚本名称',
+ `script_language` varchar(32) NOT NULL COMMENT '脚本语言类型(groovy | qlexpress | js | python | lua | aviator | java | kotlin)',
+ `script_type` varchar(16) NOT NULL COMMENT '脚本类型(script普通脚本节点,脚本里无需返回 switch_script选择脚本节点,脚本里需要返回选择的节点Id boolean_script条件脚本节点,脚本里需要返回true/false for_script数量循环节点,脚本里需要返回数值类型,表示循环次数)',
+ `script_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '状态(0未激活 1激活)',
+ `script_data` text NOT NULL COMMENT '脚本内容',
+ `del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
+ `create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
+ `create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `remark` varchar(500) DEFAULT NULL COMMENT '备注',
+ PRIMARY KEY (`id`)
+) engine = innodb comment = '脚本表';