Преглед изворни кода

Merge remote-tracking branch 'origin/master'

Lin Qilong пре 5 месеци
родитељ
комит
43fbfc95e5
39 измењених фајлова са 2716 додато и 266 уклоњено
  1. 1 0
      pom.xml
  2. 2 0
      ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
  3. 7 0
      ruoyi-admin/src/main/resources/application-test.yml
  4. 12 0
      ruoyi-admin/src/main/resources/application.yml
  5. 93 0
      ruoyi-admin/src/main/resources/logback.xml
  6. 7 0
      ruoyi-admin/src/test/java/com/ruoyi/JasyptTest.java
  7. 16 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/api/SnailJobApi.java
  8. 98 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/controller/MdAppController.java
  9. 98 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/controller/MdAppFlowController.java
  10. 443 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/controller/web/SnailJobController.java
  11. 166 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/Job.java
  12. 95 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/MdApp.java
  13. 139 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/MdAppFlow.java
  14. 45 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/vo/JobRequestVo.java
  15. 43 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/vo/JobUserResponseVO.java
  16. 41 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/vo/NamespaceResponseVO.java
  17. 19 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/vo/PermissionsResponseVO.java
  18. 61 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/mapper/MdAppFlowMapper.java
  19. 67 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/mapper/MdAppMapper.java
  20. 15 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/mapper/SnailJobMapper.java
  21. 61 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/IMdAppFlowService.java
  22. 61 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/IMdAppService.java
  23. 10 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/SnailJobService.java
  24. 96 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/impl/MdAppFlowServiceImpl.java
  25. 95 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/impl/MdAppServiceImpl.java
  26. 1 1
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/impl/PtServiceServiceImpl.java
  27. 28 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/impl/SnailJobServiceImpl.java
  28. 85 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/snailJob/AuthService.java
  29. 19 0
      ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/snailJob/TestJob.java
  30. 106 0
      ruoyi-api-patform/src/main/resources/mapper/interfaces/MdAppFlowMapper.xml
  31. 81 0
      ruoyi-api-patform/src/main/resources/mapper/interfaces/MdAppMapper.xml
  32. 83 0
      ruoyi-api-patform/src/main/resources/mapper/interfaces/SnailJobMapper.xml
  33. 22 0
      ruoyi-common/pom.xml
  34. 4 0
      ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java
  35. 51 4
      ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java
  36. 9 0
      ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java
  37. 51 0
      ruoyi-ui/src/api/service/timing.js
  38. 5 5
      ruoyi-ui/src/views/register/modelData/index.vue
  39. 380 256
      ruoyi-ui/src/views/service/timing/index.vue

+ 1 - 0
pom.xml

@@ -33,6 +33,7 @@
         <velocity.version>2.3</velocity.version>
         <jwt.version>0.9.1</jwt.version>
         <dom4j.version>2.1.4</dom4j.version>
+        <snail-job.version>1.7.1-jdk8</snail-job.version>
     </properties>
 
     <!-- 依赖声明 -->

+ 2 - 0
ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java

@@ -1,5 +1,6 @@
 package com.ruoyi;
 
+import com.aizuda.snailjob.client.starter.EnableSnailJob;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@@ -10,6 +11,7 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
  * @author ruoyi
  */
 @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
+@EnableSnailJob
 public class RuoYiApplication
 {
     public static void main(String[] args)

+ 7 - 0
ruoyi-admin/src/main/resources/application-test.yml

@@ -18,6 +18,13 @@ spring:
         url: jdbc:mysql://39.98.38.2:13306/sh_model?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
         username: shmodel
         password: shmodel#$0526
+      job:
+        # 从数据源开关/默认关闭
+        enabled: true
+        #url: jdbc:mysql://192.168.0.146:3306/sh_project?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+        url: jdbc:mysql://39.98.38.2:13306/snail_job?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+        username: shmodel
+        password: shmodel#$0526
       # 初始连接数
       initialSize: 5
       # 最小连接池数量

+ 12 - 0
ruoyi-admin/src/main/resources/application.yml

@@ -131,3 +131,15 @@ sys:
     upload:
       path: D:/tmp/map/
 
+snail-job:
+  login:
+    url: http://localhost:8080/snail-job
+    username: admin
+    password: 21232f297a57a5a743894a0e4a801fc3
+    timeout: 60
+  server:
+    port: 17888
+    host: 127.0.0.1
+  namespace: M18Z4tm7bKJmswwcLMlGgzLUEn5I2_A8
+  group: test_sh_group
+  token: SJ_bM5DeeFSAV6ltYwqqCKoA7v5HuwGH5Hr

+ 93 - 0
ruoyi-admin/src/main/resources/logback.xml

@@ -1,5 +1,93 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <configuration>
+
+
+
+    <!-- job配置↓↓↓↓↓↓↓↓↓↓↓↓↓ -->
+
+    <property name="log.base" value="snail-job-demo" />
+
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{256} - %msg%n
+            </Pattern>
+        </encoder>
+    </appender>
+
+    <appender name="fileInfo"
+              class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>./data/log/${log.base}/info/info.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <FileNamePattern>./data/log/${log.base}/info/info.%d{yyyy-MM-dd}.log</FileNamePattern>
+            <MaxHistory>30</MaxHistory>
+        </rollingPolicy>
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{256} - %msg%n</pattern>
+        </layout>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>INFO</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name="fileWarn" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>./data/log/${log.base}/warn/warn.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <FileNamePattern>./data/log/${log.base}/warn/warn.%d{yyyy-MM-dd}.log
+            </FileNamePattern>
+            <MaxHistory>30</MaxHistory>
+        </rollingPolicy>
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{256} - %msg%n</pattern>
+        </layout>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>WARN</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name="fileError" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>./data/log/${log.base}/error/error.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <FileNamePattern>./data/log/${log.base}/error/error.%d{yyyy-MM-dd}.log
+            </FileNamePattern>
+            <MaxHistory>30</MaxHistory>
+        </rollingPolicy>
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{256} - %msg%n</pattern>
+        </layout>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>ERROR</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name ="asyncInfo" class= "ch.qos.logback.classic.AsyncAppender">
+        <discardingThreshold >100</discardingThreshold>
+        <queueSize>1024</queueSize>
+        <appender-ref ref ="fileInfo"/>
+    </appender>
+
+    <appender name ="asyncWarn" class= "ch.qos.logback.classic.AsyncAppender">
+        <discardingThreshold >100</discardingThreshold>
+        <queueSize>1024</queueSize>
+        <appender-ref ref ="fileWarn"/>
+    </appender>
+
+    <appender name ="asyncError" class= "ch.qos.logback.classic.AsyncAppender">
+        <discardingThreshold >100</discardingThreshold>
+        <queueSize>1024</queueSize>
+        <appender-ref ref ="fileError"/>
+    </appender>
+
+    <!-- Snail appender -->
+    <appender name="snailLogAppender" class="com.aizuda.snailjob.client.common.appender.SnailLogbackAppender">
+    </appender>
+
+    <!-- job配置↑↑↑↑↑↑↑↑↑↑↑↑↑ -->
     <!-- 日志存放路径 -->
 	<property name="log.path" value="/tmp/sh-models/logs" />
     <!-- 日志输出格式 -->
@@ -84,6 +172,11 @@
     <root level="info">
         <appender-ref ref="file_info" />
         <appender-ref ref="file_error" />
+        <appender-ref ref="stdout" />
+        <appender-ref ref="asyncInfo" />
+        <appender-ref ref="asyncWarn" />
+        <appender-ref ref="asyncError" />
+        <appender-ref ref="snailLogAppender" />
     </root>
 	
 	<!--系统用户操作日志-->

+ 7 - 0
ruoyi-admin/src/test/java/com/ruoyi/JasyptTest.java

@@ -1,7 +1,11 @@
 package com.ruoyi;
 
+import com.aizuda.snailjob.client.job.core.handler.query.RequestQueryHandler;
+import com.aizuda.snailjob.model.response.JobApiResponse;
 import com.ruoyi.RuoYiApplication;
 import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.interfaces.api.SnailJobApi;
+import com.ruoyi.interfaces.snailJob.AuthService;
 import org.jasypt.encryption.StringEncryptor;
 import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
@@ -21,6 +25,9 @@ public class JasyptTest {
 
     @Test
     public void encryptPwd() {
+        RequestQueryHandler jobDetail = SnailJobApi.getJobDetail(1l);
+        JobApiResponse execute = jobDetail.execute();
+        System.out.println(execute.toString());
     }
 
 }

+ 16 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/api/SnailJobApi.java

@@ -0,0 +1,16 @@
+package com.ruoyi.interfaces.api;
+
+import com.aizuda.snailjob.client.job.core.handler.query.RequestQueryHandler;
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import org.springframework.beans.factory.annotation.Value;
+
+import javax.naming.ldap.PagedResultsControl;
+
+public class SnailJobApi {
+
+
+    public static RequestQueryHandler getJobDetail(Long jobId) {
+        return new RequestQueryHandler(jobId);
+    }
+}

+ 98 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/controller/MdAppController.java

@@ -0,0 +1,98 @@
+package com.ruoyi.interfaces.controller;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.interfaces.domain.MdApp;
+import com.ruoyi.interfaces.service.IMdAppService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 模型应用Controller
+ * 
+ * @author 朱得糠
+ * @date 2025-08-19
+ */
+@RestController
+@RequestMapping("/md/app")
+public class MdAppController extends BaseController
+{
+    @Autowired
+    private IMdAppService mdAppService;
+
+    /**
+     * 查询模型应用列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(MdApp mdApp)
+    {
+        startPage();
+        List<MdApp> list = mdAppService.selectMdAppList(mdApp);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出模型应用列表
+     */
+    @Log(title = "模型应用", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, MdApp mdApp)
+    {
+        List<MdApp> list = mdAppService.selectMdAppList(mdApp);
+        ExcelUtil<MdApp> util = new ExcelUtil<MdApp>(MdApp.class);
+        util.exportExcel(response, list, "模型应用数据");
+    }
+
+    /**
+     * 获取模型应用详细信息
+     */
+    @GetMapping(value = "/{appId}")
+    public AjaxResult getInfo(@PathVariable("appId") Long appId)
+    {
+        return success(mdAppService.selectMdAppByAppId(appId));
+    }
+
+    /**
+     * 新增模型应用
+     */
+    @Log(title = "模型应用", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody MdApp mdApp)
+    {
+        return toAjax(mdAppService.insertMdApp(mdApp));
+    }
+
+    /**
+     * 修改模型应用
+     */
+    @Log(title = "模型应用", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody MdApp mdApp)
+    {
+        return toAjax(mdAppService.updateMdApp(mdApp));
+    }
+
+    /**
+     * 删除模型应用
+     */
+    @Log(title = "模型应用", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{appIds}")
+    public AjaxResult remove(@PathVariable Long[] appIds)
+    {
+        return toAjax(mdAppService.deleteMdAppByAppIds(appIds));
+    }
+}

+ 98 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/controller/MdAppFlowController.java

@@ -0,0 +1,98 @@
+package com.ruoyi.interfaces.controller;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.interfaces.domain.MdAppFlow;
+import com.ruoyi.interfaces.service.IMdAppFlowService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 模型应用流程Controller
+ * 
+ * @author 朱得糠
+ * @date 2025-08-19
+ */
+@RestController
+@RequestMapping("/app/flow")
+public class MdAppFlowController extends BaseController
+{
+    @Autowired
+    private IMdAppFlowService mdAppFlowService;
+
+    /**
+     * 查询模型应用流程列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(MdAppFlow mdAppFlow)
+    {
+        startPage();
+        List<MdAppFlow> list = mdAppFlowService.selectMdAppFlowList(mdAppFlow);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出模型应用流程列表
+     */
+    @Log(title = "模型应用流程", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, MdAppFlow mdAppFlow)
+    {
+        List<MdAppFlow> list = mdAppFlowService.selectMdAppFlowList(mdAppFlow);
+        ExcelUtil<MdAppFlow> util = new ExcelUtil<MdAppFlow>(MdAppFlow.class);
+        util.exportExcel(response, list, "模型应用流程数据");
+    }
+
+    /**
+     * 获取模型应用流程详细信息
+     */
+    @GetMapping(value = "/{flowId}")
+    public AjaxResult getInfo(@PathVariable("flowId") Long flowId)
+    {
+        return success(mdAppFlowService.selectMdAppFlowByFlowId(flowId));
+    }
+
+    /**
+     * 新增模型应用流程
+     */
+    @Log(title = "模型应用流程", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody MdAppFlow mdAppFlow)
+    {
+        return toAjax(mdAppFlowService.insertMdAppFlow(mdAppFlow));
+    }
+
+    /**
+     * 修改模型应用流程
+     */
+    @Log(title = "模型应用流程", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody MdAppFlow mdAppFlow)
+    {
+        return toAjax(mdAppFlowService.updateMdAppFlow(mdAppFlow));
+    }
+
+    /**
+     * 删除模型应用流程
+     */
+    @Log(title = "模型应用流程", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{flowIds}")
+    public AjaxResult remove(@PathVariable Long[] flowIds)
+    {
+        return toAjax(mdAppFlowService.deleteMdAppFlowByFlowIds(flowIds));
+    }
+}

+ 443 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/controller/web/SnailJobController.java

@@ -0,0 +1,443 @@
+package com.ruoyi.interfaces.controller.web;
+
+import com.aizuda.snailjob.client.job.core.enums.AllocationAlgorithmEnum;
+import com.aizuda.snailjob.client.job.core.enums.TriggerTypeEnum;
+import com.aizuda.snailjob.client.job.core.handler.add.BroadcastAddHandler;
+import com.aizuda.snailjob.client.job.core.handler.add.ClusterAddHandler;
+import com.aizuda.snailjob.client.job.core.handler.query.RequestQueryHandler;
+import com.aizuda.snailjob.client.job.core.handler.update.BroadcastUpdateHandler;
+import com.aizuda.snailjob.client.job.core.handler.update.ClusterUpdateHandler;
+import com.aizuda.snailjob.client.job.core.openapi.SnailJobOpenApi;
+import com.aizuda.snailjob.common.core.enums.JobBlockStrategyEnum;
+import com.aizuda.snailjob.common.core.enums.StatusEnum;
+import com.aizuda.snailjob.model.request.base.JobRequest;
+import com.aizuda.snailjob.model.response.JobApiResponse;
+import com.aizuda.snailjob.model.response.JobBatchApiResponse;
+import com.aizuda.snailjob.model.response.WorkflowDetailApiResponse;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.interfaces.api.SnailJobApi;
+import com.ruoyi.interfaces.domain.Job;
+import com.ruoyi.interfaces.domain.vo.JobRequestVo;
+import com.ruoyi.interfaces.service.SnailJobService;
+import com.ruoyi.interfaces.service.impl.SnailJobServiceImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+
+@RestController
+@RequestMapping("/snail/job")
+public class SnailJobController extends BaseController {
+
+    @Autowired
+    private SnailJobService snailJobService;
+
+
+    @GetMapping("/jobList")
+    public TableDataInfo jobList(Job jobRequestVo) {
+        startPage();
+        List<Job> list = snailJobService.selectJobList(jobRequestVo);
+        return getDataTable(list);
+    }
+
+    /**
+     * 根据任务id获取job任务详情
+     *
+     * @return
+     */
+    @GetMapping("/getJobDetail")
+    public AjaxResult getJobDetail(Long jobId) {
+        return success(SnailJobOpenApi.getJobDetail(jobId).execute());
+    }
+
+    /**
+     * @return
+     */
+    @GetMapping("/getJobBatchDetail")
+    public AjaxResult getJobBatchDetail(Long jobId) {
+        return success(SnailJobOpenApi.getJobBatchDetail(jobId).execute());
+    }
+
+    /**
+     * @return
+     */
+    @GetMapping("/getWorkflowBatchDetail")
+    public AjaxResult getWorkflowBatchDetail(Long jobId) {
+        return success(SnailJobOpenApi.getWorkflowBatchDetail(jobId).execute());
+    }
+
+
+    /**
+     * 更新定时任务状态
+     *
+     * @param jobId  定时任务ID
+     * @param status
+     */
+    @GetMapping("/updateJobStatus")
+    public AjaxResult updateJobStatus(Long jobId, Long status) {
+        return success(SnailJobOpenApi
+                .updateJobStatus(jobId)
+                .setStatus(StatusEnum.YES.getStatus().equals(status.intValue()) ? StatusEnum.YES : StatusEnum.NO)
+                .execute());
+    }
+
+    /**
+     * 更新工作流任务状态
+     *
+     * @param workFlowId 工作流ID
+     * @param status
+     */
+    @GetMapping("/updateWorkFlowStatus")
+    public AjaxResult updateWorkFlowStatus(Long workFlowId, Long status) {
+        return success(SnailJobOpenApi
+                .updateWorkFlowStatus(workFlowId)
+                .setStatus(StatusEnum.YES.getStatus().equals(status.intValue()) ? StatusEnum.YES : StatusEnum.NO)
+                .execute());
+    }
+
+    /**
+     * 手动调度任务
+     *
+     * @param jobId 任务Id
+     */
+    @GetMapping("/triggerJob")
+    public AjaxResult triggerJob(Long jobId, Integer taskType) {
+        switch (taskType) {
+            case 1:
+                return success(SnailJobOpenApi.triggerClusterJob(jobId).execute());
+            case 2:
+                return success(SnailJobOpenApi.triggerBroadcastJob(jobId).execute());
+            case 3:
+                return success(SnailJobOpenApi.triggerShardingJob(jobId).execute());
+            case 4:
+                return success(SnailJobOpenApi.triggerMapJob(jobId).execute());
+            case 5:
+                return success(SnailJobOpenApi.triggerMapReduceJob(jobId).execute());
+            case 6:
+                return success(SnailJobOpenApi.triggerWorkFlow(jobId).execute());
+        }
+        return success(false);
+    }
+
+    @DeleteMapping("job")
+    public AjaxResult deleteJob(@RequestParam Set<Long> jobIds) {
+        return success(SnailJobOpenApi.deleteJob(jobIds).execute());
+    }
+
+    /**
+     * 删除工作流任务
+     *
+     * @param workflowIds 工作流任务ID
+     */
+    @DeleteMapping("workflow")
+    public AjaxResult deleteWorkflow(Set<Long> workflowIds) {
+        return success(SnailJobOpenApi.deleteWorkflow(workflowIds).execute());
+    }
+
+    /**
+     * 新增任务
+     *
+     * @param jobRequest
+     * @return
+     */
+    @PostMapping()
+    public AjaxResult saveJob(@RequestBody JobRequestVo jobRequest) {
+        switch (jobRequest.getTaskType()) {
+            case 1:
+                return success(addClusterJob(jobRequest));
+            case 2:
+                return success(addBroadcastJob(jobRequest));
+            case 3:
+                return success(addShardingJob(jobRequest));
+            case 4:
+                return success(addMapJob(jobRequest));
+            case 5:
+                return success(addMapReduceJob(jobRequest));
+        }
+        return success(0L);
+    }
+
+
+    /**
+     * 更新任务
+     *
+     * @param jobRequest
+     * @return
+     */
+    @PutMapping()
+    public AjaxResult updateJob(@RequestBody JobRequestVo jobRequest) {
+        switch (jobRequest.getTaskType()) {
+            case 1:
+                return success(updateClusterJob(jobRequest));
+            case 2:
+                return success(updateBroadcastJob(jobRequest));
+            case 3:
+                return success(updateShardingJob(jobRequest));
+            case 4:
+                return success(updateMapJob(jobRequest));
+            case 5:
+                return success(updateMapReduceJob(jobRequest));
+        }
+        return success(false);
+    }
+
+    /**
+     * 新增集群模式的任务
+     *
+     * @param jobRequest
+     * @return 任务id
+     */
+    public Long addClusterJob(JobRequestVo jobRequest) {
+        ClusterAddHandler clusterAddHandler = SnailJobOpenApi.addClusterJob()
+                //.setRouteKey(AllocationAlgorithmEnum.RANDOM)
+                .setRouteKey(getAllocationAlgorithmEnum(jobRequest.getRouteKey()))
+                .setJobName(jobRequest.getJobName())//
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .setJobStatus(StatusEnum.of(jobRequest.getJobStatus()))  //状态不能为空
+                .setRetryInterval(jobRequest.getRetryInterval());
+
+        HashMap<String, Object> argsMap = jobRequest.getArgsStrMap();
+        if (StringUtils.isNotEmpty(argsMap)) {
+            argsMap.forEach(clusterAddHandler::addArgsStr);
+        }
+        return clusterAddHandler.execute();
+    }
+
+    /**
+     * 修改集群模式的任务
+     */
+    public Boolean updateClusterJob(JobRequestVo jobRequest) {
+        ClusterUpdateHandler clusterUpdateHandler = SnailJobOpenApi.updateClusterJob(jobRequest.getId())
+                .setRouteKey(getAllocationAlgorithmEnum(jobRequest.getRouteKey()))
+                .setJobName(jobRequest.getJobName())//
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .setRetryInterval(jobRequest.getRetryInterval());
+
+        HashMap<String, Object> argsMap = jobRequest.getArgsStrMap();
+        if (StringUtils.isNotEmpty(argsMap)) {
+            argsMap.forEach(clusterUpdateHandler::addArgsStr);
+        }
+
+        return clusterUpdateHandler.execute();
+
+    }
+
+
+    /**
+     * 新增广播模式的任务
+     *
+     * @param jobRequest
+     * @return
+     */
+    public Long addBroadcastJob(JobRequestVo jobRequest) {
+        BroadcastAddHandler broadcastAddHandler = SnailJobOpenApi.addBroadcastJob()
+                .setJobName(jobRequest.getJobName())
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .setJobStatus(StatusEnum.of(jobRequest.getJobStatus()))  //状态不能为空
+                .setRetryInterval(jobRequest.getRetryInterval());
+        HashMap<String, Object> argsMap = jobRequest.getArgsStrMap();
+        if (StringUtils.isNotEmpty(argsMap)) {
+            argsMap.forEach(broadcastAddHandler::addArgsStr);
+        }
+        return broadcastAddHandler.execute();
+    }
+
+
+    /**
+     * 修改广播任务
+     */
+    public Boolean updateBroadcastJob(JobRequestVo jobRequest) {
+        BroadcastUpdateHandler broadcastUpdateHandler = SnailJobOpenApi.updateBroadcastJob(jobRequest.getId())
+                .setJobName(jobRequest.getJobName())
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .setRetryInterval(jobRequest.getRetryInterval());
+        HashMap<String, Object> argsMap = jobRequest.getArgsStrMap();
+        if (StringUtils.isNotEmpty(argsMap)) {
+            argsMap.forEach(broadcastUpdateHandler::addArgsStr);
+        }
+        return broadcastUpdateHandler.execute();
+    }
+
+    /**
+     * 新增Sharding模式的任务
+     *
+     * @param jobRequest 任务名称
+     * @return 任务id
+     */
+    public Long addShardingJob(JobRequestVo jobRequest) {
+        return SnailJobOpenApi.addShardingJob()
+                .setJobName(jobRequest.getJobName())
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .addShardingArgs(jobRequest.getShardingArgs())
+                .setParallelNum(jobRequest.getParallelNum())
+                .setJobStatus(StatusEnum.of(jobRequest.getJobStatus()))  //状态不能为空
+                .setRetryInterval(jobRequest.getRetryInterval())
+                .execute();
+    }
+
+    /**
+     * 修改Sharding模式的任务
+     *
+     * @param jobRequest 任务名称
+     * @return 任务id
+     */
+    public Boolean updateShardingJob(JobRequestVo jobRequest) {
+        return SnailJobOpenApi.updateShardingJob(jobRequest.getId())
+                .setJobName(jobRequest.getJobName())
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .addShardingArgs(jobRequest.getShardingArgs())
+                .setParallelNum(jobRequest.getParallelNum())
+                .setRetryInterval(jobRequest.getRetryInterval())
+                .execute();
+    }
+
+    /**
+     * 新增Map模式的任务
+     *
+     * @param jobRequest 任务名称
+     * @return 任务id
+     */
+    public Long addMapJob(JobRequestVo jobRequest) {
+        return SnailJobOpenApi.addMapJob()
+                .setJobName(jobRequest.getJobName())
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .setParallelNum(jobRequest.getParallelNum())
+                .setRetryInterval(jobRequest.getRetryInterval())
+                .setJobStatus(StatusEnum.of(jobRequest.getJobStatus()))  //状态不能为空
+                .execute();
+    }
+
+    /**
+     * 修改Map模式的任务
+     *
+     * @param jobRequest
+     * @return
+     */
+    public Boolean updateMapJob(JobRequestVo jobRequest) {
+        return SnailJobOpenApi.updateMapJob(jobRequest.getId())
+                .setJobName(jobRequest.getJobName())
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .setParallelNum(jobRequest.getParallelNum())
+                .setRetryInterval(jobRequest.getRetryInterval())
+                .execute();
+    }
+
+    /**
+     * 新增MapReduce模式的任务
+     *
+     * @param jobRequest
+     * @return 任务id
+     */
+    public Long addMapReduceJob(JobRequestVo jobRequest) {
+        return SnailJobOpenApi.addMapReduceJob()
+                .setJobName(jobRequest.getJobName())
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .setParallelNum(jobRequest.getParallelNum())
+                .setShardNum(jobRequest.getShardNum())
+                .setRetryInterval(jobRequest.getRetryInterval())
+                .execute();
+    }
+
+    /**
+     * 修改MapReduce模式的任务
+     *
+     * @param jobRequest
+     * @return 任务id
+     */
+    public Boolean updateMapReduceJob(JobRequestVo jobRequest) {
+        return SnailJobOpenApi.updateMapReduceJob(jobRequest.getId())
+                .setJobName(jobRequest.getJobName())
+                .setExecutorInfo(jobRequest.getExecutorInfo())
+                .setExecutorTimeout(jobRequest.getExecutorTimeout())
+                .setDescription(jobRequest.getDescription())
+                .setBlockStrategy(JobBlockStrategyEnum.valueOf(jobRequest.getBlockStrategy()))
+                .setMaxRetryTimes(jobRequest.getMaxRetryTimes())
+                .setTriggerType(getTriggerTypeEnum(jobRequest.getTriggerType()))
+                .setTriggerInterval(jobRequest.getTriggerInterval())
+                .setParallelNum(jobRequest.getParallelNum())
+                .setShardNum(jobRequest.getShardNum())
+                .setRetryInterval(jobRequest.getRetryInterval())
+                .execute();
+
+    }
+
+
+    public AllocationAlgorithmEnum getAllocationAlgorithmEnum(Integer type) {
+        for (AllocationAlgorithmEnum algorithm : AllocationAlgorithmEnum.values()) {
+            if (type.equals(algorithm.getType())) {
+                return algorithm;
+            }
+        }
+        return null;
+    }
+
+    public TriggerTypeEnum getTriggerTypeEnum(Integer type) {
+        for (TriggerTypeEnum triggerTypeEnum : TriggerTypeEnum.values()) {
+            if (type.equals(triggerTypeEnum.getType())) {
+                return triggerTypeEnum;
+            }
+        }
+        return null;
+    }
+
+
+}

+ 166 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/Job.java

@@ -0,0 +1,166 @@
+package com.ruoyi.interfaces.domain;
+
+import com.aizuda.snailjob.common.core.enums.ExecutorTypeEnum;
+import com.aizuda.snailjob.common.core.enums.JobTaskTypeEnum;
+import com.aizuda.snailjob.common.core.enums.StatusEnum;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.apache.ibatis.type.JdbcType;
+
+/**
+ * 任务信息
+ *
+ * @author opensnail
+ * @since 2023-09-24
+ */
+@Data
+public class Job  {
+
+    /**
+     * 主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 命名空间id
+     */
+    private String namespaceId;
+
+    /**
+     * 组名称
+     */
+    private String groupName;
+
+    /**
+     * 名称
+     */
+    @TableField(updateStrategy =  FieldStrategy.NOT_EMPTY)
+    private String jobName;
+
+    /**
+     * 执行方法参数
+     */
+    @TableField(updateStrategy =  FieldStrategy.NOT_EMPTY)
+    private String argsStr;
+
+    /**
+     * 参数类型 text/json
+     */
+    @TableField(updateStrategy =  FieldStrategy.NOT_EMPTY)
+    private Integer argsType;
+
+    /**
+     * 扩展字段
+     */
+    @TableField(updateStrategy =  FieldStrategy.NOT_EMPTY)
+    private String extAttrs;
+
+    /**
+     * 下次触发时间
+     */
+    private Long nextTriggerAt;
+
+    /**
+     * 重试状态 0、关闭、1、开启
+     * {@link StatusEnum}
+     */
+    private Integer jobStatus;
+
+    /**
+     * 执行器路由策略
+     */
+    private Integer routeKey;
+
+    /**
+     * 执行器类型 1、Java
+     * {@link ExecutorTypeEnum}
+     */
+    private Integer executorType;
+
+    /**
+     * 执行器信息
+     */
+    private String executorInfo;
+
+    /**
+     * 触发类型 1.CRON 表达式 2. 固定时间
+     */
+    private Integer triggerType;
+
+    /**
+     * 间隔时长
+     */
+    @TableField(updateStrategy =  FieldStrategy.NOT_EMPTY)
+    private String triggerInterval;
+
+    /**
+     * 阻塞策略 1、丢弃 2、覆盖 3、并行
+     */
+    private Integer blockStrategy;
+
+    /**
+     * 任务执行超时时间,单位秒
+     */
+    private Integer executorTimeout;
+
+    /**
+     * 最大重试次数
+     */
+    private Integer maxRetryTimes;
+
+    /**
+     * 重试间隔(s)
+     */
+    private Integer retryInterval;
+
+    /**
+     * 任务类型
+     * {@link JobTaskTypeEnum}
+     */
+    private Integer taskType;
+
+    /**
+     * 并行数
+     */
+    private Integer parallelNum;
+
+    /**
+     * bucket
+     */
+    private Integer bucketIndex;
+
+    /**
+     * 是否是常驻任务
+     */
+    private Integer resident;
+
+    /**
+     * 描述
+     */
+    private String description;
+
+    /**
+     * 逻辑删除 1、删除
+     */
+    private Integer deleted;
+
+    /**
+     * 通知告警场景配置id列表
+     */
+    private String notifyIds;
+
+    /**
+     * 负责人id
+     */
+    private Long ownerId;
+
+    /**
+     * 标签
+     * json格式,如:{"key1":"value1","key2":"value2"}
+     */
+    @TableField(updateStrategy =  FieldStrategy.NOT_EMPTY)
+    private String labels;
+
+}

+ 95 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/MdApp.java

@@ -0,0 +1,95 @@
+package com.ruoyi.interfaces.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 模型应用对象 md_app
+ * 
+ * @author 朱得糠
+ * @date 2025-08-19
+ */
+public class MdApp extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 应用标识 */
+    private Long appId;
+
+    /** 模型应用名称 */
+    @Excel(name = "模型应用名称")
+    private String appTitle;
+
+    /** 模型应用介绍 */
+    @Excel(name = "模型应用介绍")
+    private String appNote;
+
+    /** 模型应用图标 */
+    @Excel(name = "模型应用图标")
+    private String appIcon;
+
+    /** 模型应用排序 */
+    @Excel(name = "模型应用排序")
+    private Long appOrd;
+
+    public void setAppId(Long appId) 
+    {
+        this.appId = appId;
+    }
+
+    public Long getAppId() 
+    {
+        return appId;
+    }
+    public void setAppTitle(String appTitle) 
+    {
+        this.appTitle = appTitle;
+    }
+
+    public String getAppTitle() 
+    {
+        return appTitle;
+    }
+    public void setAppNote(String appNote) 
+    {
+        this.appNote = appNote;
+    }
+
+    public String getAppNote() 
+    {
+        return appNote;
+    }
+    public void setAppIcon(String appIcon) 
+    {
+        this.appIcon = appIcon;
+    }
+
+    public String getAppIcon() 
+    {
+        return appIcon;
+    }
+    public void setAppOrd(Long appOrd) 
+    {
+        this.appOrd = appOrd;
+    }
+
+    public Long getAppOrd() 
+    {
+        return appOrd;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("appId", getAppId())
+            .append("appTitle", getAppTitle())
+            .append("appNote", getAppNote())
+            .append("appIcon", getAppIcon())
+            .append("appOrd", getAppOrd())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .toString();
+    }
+}

+ 139 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/MdAppFlow.java

@@ -0,0 +1,139 @@
+package com.ruoyi.interfaces.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 模型应用流程对象 md_app_flow
+ * 
+ * @author 朱得糠
+ * @date 2025-08-19
+ */
+public class MdAppFlow extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 流程图ID */
+    private Long flowId;
+
+    /** 模型ID */
+    @Excel(name = "模型ID")
+    private String appId;
+
+    /** 流程图名称 */
+    @Excel(name = "流程图名称")
+    private String flowName;
+
+    /** 流程图 */
+    @Excel(name = "流程图")
+    private String flowGraph;
+
+    /** 流程类型 */
+    @Excel(name = "流程类型")
+    private String flowType;
+
+    /** 流程图描述 */
+    @Excel(name = "流程图描述")
+    private String flowNote;
+
+    /** 流程图状态 */
+    @Excel(name = "流程图状态")
+    private Integer flowStatus;
+
+    /** 流程排序 */
+    @Excel(name = "流程排序")
+    private Integer flowSort;
+
+    public void setFlowId(Long flowId) 
+    {
+        this.flowId = flowId;
+    }
+
+    public Long getFlowId() 
+    {
+        return flowId;
+    }
+    public void setAppId(String appId) 
+    {
+        this.appId = appId;
+    }
+
+    public String getAppId() 
+    {
+        return appId;
+    }
+    public void setFlowName(String flowName) 
+    {
+        this.flowName = flowName;
+    }
+
+    public String getFlowName() 
+    {
+        return flowName;
+    }
+    public void setFlowGraph(String flowGraph) 
+    {
+        this.flowGraph = flowGraph;
+    }
+
+    public String getFlowGraph() 
+    {
+        return flowGraph;
+    }
+    public void setFlowType(String flowType) 
+    {
+        this.flowType = flowType;
+    }
+
+    public String getFlowType() 
+    {
+        return flowType;
+    }
+    public void setFlowNote(String flowNote) 
+    {
+        this.flowNote = flowNote;
+    }
+
+    public String getFlowNote() 
+    {
+        return flowNote;
+    }
+    public void setFlowStatus(Integer flowStatus) 
+    {
+        this.flowStatus = flowStatus;
+    }
+
+    public Integer getFlowStatus() 
+    {
+        return flowStatus;
+    }
+    public void setFlowSort(Integer flowSort) 
+    {
+        this.flowSort = flowSort;
+    }
+
+    public Integer getFlowSort() 
+    {
+        return flowSort;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("flowId", getFlowId())
+            .append("appId", getAppId())
+            .append("flowName", getFlowName())
+            .append("flowGraph", getFlowGraph())
+            .append("flowType", getFlowType())
+            .append("flowNote", getFlowNote())
+            .append("flowStatus", getFlowStatus())
+            .append("flowSort", getFlowSort())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .toString();
+    }
+}

+ 45 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/vo/JobRequestVo.java

@@ -0,0 +1,45 @@
+package com.ruoyi.interfaces.domain.vo;
+
+import com.aizuda.snailjob.model.request.base.JobRequest;
+import com.ruoyi.common.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.util.HashMap;
+
+public class JobRequestVo extends JobRequest {
+    private HashMap<String,Object> argsStrMap;
+    private String[] shardingArgs;
+
+    private Integer shardNum;
+
+    public Integer getShardNum() {
+        return shardNum;
+    }
+
+    public void setShardNum(Integer shardNum) {
+        this.shardNum = shardNum;
+    }
+
+    public String[] getShardingArgs() {
+        return shardingArgs;
+    }
+
+    public void setShardingArgs(String[] shardingArgs) {
+        this.shardingArgs = shardingArgs;
+    }
+
+    public HashMap<String, Object> getArgsStrMap() {
+        return argsStrMap;
+    }
+
+    public void setArgsStrMap(HashMap<String, Object> argsStrMap) {
+        this.argsStrMap = argsStrMap;
+    }
+
+    public JobRequestVo(HashMap<String, Object> argsStrMap) {
+        this.argsStrMap = argsStrMap;
+    }
+
+    public JobRequestVo() {
+    }
+}

+ 43 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/vo/JobUserResponseVO.java

@@ -0,0 +1,43 @@
+package com.ruoyi.interfaces.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author opensnail
+ * @date 2022-03-05
+ * @since 2.0
+ */
+@Data
+public class JobUserResponseVO {
+
+    private Long id;
+
+    private String username;
+
+    private Integer role;
+
+    private List<String> groupNameList;
+
+    private List<NamespaceResponseVO> namespaceIds;
+
+    private List<PermissionsResponseVO> permissions;
+
+    private String token;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createDt;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateDt;
+
+    private String mode;
+
+
+
+
+}

+ 41 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/vo/NamespaceResponseVO.java

@@ -0,0 +1,41 @@
+package com.ruoyi.interfaces.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+
+/**
+ * @author: xiaowoniu
+ * @date : 2023-11-21 15:39
+ * @since : 2.5.0
+ */
+@Data
+public class NamespaceResponseVO {
+
+    private Long id;
+
+    /**
+     * 名称
+     */
+    private String name;
+
+    /**
+     * 唯一id
+     */
+    private String uniqueId;
+
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createDt;
+
+    /**
+     * 修改时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateDt;
+
+}

+ 19 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/domain/vo/PermissionsResponseVO.java

@@ -0,0 +1,19 @@
+package com.ruoyi.interfaces.domain.vo;
+
+import lombok.Data;
+
+import java.util.Set;
+
+/**
+ * @author: xiaowoniu
+ * @date : 2023-11-23 14:01
+ * @since : 2.5.0
+ */
+@Data
+public class PermissionsResponseVO {
+
+    private String groupName;
+    private String namespaceId;
+    private String namespaceName;
+    private Set<String> groupNames;
+}

+ 61 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/mapper/MdAppFlowMapper.java

@@ -0,0 +1,61 @@
+package com.ruoyi.interfaces.mapper;
+
+import java.util.List;
+import com.ruoyi.interfaces.domain.MdAppFlow;
+
+/**
+ * 模型应用流程Mapper接口
+ * 
+ * @author 朱得糠
+ * @date 2025-08-19
+ */
+public interface MdAppFlowMapper 
+{
+    /**
+     * 查询模型应用流程
+     * 
+     * @param flowId 模型应用流程主键
+     * @return 模型应用流程
+     */
+    public MdAppFlow selectMdAppFlowByFlowId(Long flowId);
+
+    /**
+     * 查询模型应用流程列表
+     * 
+     * @param mdAppFlow 模型应用流程
+     * @return 模型应用流程集合
+     */
+    public List<MdAppFlow> selectMdAppFlowList(MdAppFlow mdAppFlow);
+
+    /**
+     * 新增模型应用流程
+     * 
+     * @param mdAppFlow 模型应用流程
+     * @return 结果
+     */
+    public int insertMdAppFlow(MdAppFlow mdAppFlow);
+
+    /**
+     * 修改模型应用流程
+     * 
+     * @param mdAppFlow 模型应用流程
+     * @return 结果
+     */
+    public int updateMdAppFlow(MdAppFlow mdAppFlow);
+
+    /**
+     * 删除模型应用流程
+     * 
+     * @param flowId 模型应用流程主键
+     * @return 结果
+     */
+    public int deleteMdAppFlowByFlowId(Long flowId);
+
+    /**
+     * 批量删除模型应用流程
+     * 
+     * @param flowIds 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteMdAppFlowByFlowIds(Long[] flowIds);
+}

+ 67 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/mapper/MdAppMapper.java

@@ -0,0 +1,67 @@
+package com.ruoyi.interfaces.mapper;
+
+import java.util.List;
+
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.interfaces.domain.MdApp;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 模型应用Mapper接口
+ * 
+ * @author 朱得糠
+ * @date 2025-08-19
+ */
+@Mapper
+@DataSource(DataSourceType.SLAVE)
+public interface MdAppMapper 
+{
+    /**
+     * 查询模型应用
+     * 
+     * @param appId 模型应用主键
+     * @return 模型应用
+     */
+    public MdApp selectMdAppByAppId(Long appId);
+
+    /**
+     * 查询模型应用列表
+     * 
+     * @param mdApp 模型应用
+     * @return 模型应用集合
+     */
+    public List<MdApp> selectMdAppList(MdApp mdApp);
+
+    /**
+     * 新增模型应用
+     * 
+     * @param mdApp 模型应用
+     * @return 结果
+     */
+    public int insertMdApp(MdApp mdApp);
+
+    /**
+     * 修改模型应用
+     * 
+     * @param mdApp 模型应用
+     * @return 结果
+     */
+    public int updateMdApp(MdApp mdApp);
+
+    /**
+     * 删除模型应用
+     * 
+     * @param appId 模型应用主键
+     * @return 结果
+     */
+    public int deleteMdAppByAppId(Long appId);
+
+    /**
+     * 批量删除模型应用
+     * 
+     * @param appIds 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteMdAppByAppIds(Long[] appIds);
+}

+ 15 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/mapper/SnailJobMapper.java

@@ -0,0 +1,15 @@
+package com.ruoyi.interfaces.mapper;
+
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.interfaces.domain.Job;
+import com.ruoyi.interfaces.domain.vo.JobRequestVo;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+@DataSource(DataSourceType.JOB)
+public interface SnailJobMapper {
+    List<Job> selectJobList(Job jobRequestVo);
+}

+ 61 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/IMdAppFlowService.java

@@ -0,0 +1,61 @@
+package com.ruoyi.interfaces.service;
+
+import java.util.List;
+import com.ruoyi.interfaces.domain.MdAppFlow;
+
+/**
+ * 模型应用流程Service接口
+ * 
+ * @author 朱得糠
+ * @date 2025-08-19
+ */
+public interface IMdAppFlowService 
+{
+    /**
+     * 查询模型应用流程
+     * 
+     * @param flowId 模型应用流程主键
+     * @return 模型应用流程
+     */
+    public MdAppFlow selectMdAppFlowByFlowId(Long flowId);
+
+    /**
+     * 查询模型应用流程列表
+     * 
+     * @param mdAppFlow 模型应用流程
+     * @return 模型应用流程集合
+     */
+    public List<MdAppFlow> selectMdAppFlowList(MdAppFlow mdAppFlow);
+
+    /**
+     * 新增模型应用流程
+     * 
+     * @param mdAppFlow 模型应用流程
+     * @return 结果
+     */
+    public int insertMdAppFlow(MdAppFlow mdAppFlow);
+
+    /**
+     * 修改模型应用流程
+     * 
+     * @param mdAppFlow 模型应用流程
+     * @return 结果
+     */
+    public int updateMdAppFlow(MdAppFlow mdAppFlow);
+
+    /**
+     * 批量删除模型应用流程
+     * 
+     * @param flowIds 需要删除的模型应用流程主键集合
+     * @return 结果
+     */
+    public int deleteMdAppFlowByFlowIds(Long[] flowIds);
+
+    /**
+     * 删除模型应用流程信息
+     * 
+     * @param flowId 模型应用流程主键
+     * @return 结果
+     */
+    public int deleteMdAppFlowByFlowId(Long flowId);
+}

+ 61 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/IMdAppService.java

@@ -0,0 +1,61 @@
+package com.ruoyi.interfaces.service;
+
+import java.util.List;
+import com.ruoyi.interfaces.domain.MdApp;
+
+/**
+ * 模型应用Service接口
+ * 
+ * @author 朱得糠
+ * @date 2025-08-19
+ */
+public interface IMdAppService 
+{
+    /**
+     * 查询模型应用
+     * 
+     * @param appId 模型应用主键
+     * @return 模型应用
+     */
+    public MdApp selectMdAppByAppId(Long appId);
+
+    /**
+     * 查询模型应用列表
+     * 
+     * @param mdApp 模型应用
+     * @return 模型应用集合
+     */
+    public List<MdApp> selectMdAppList(MdApp mdApp);
+
+    /**
+     * 新增模型应用
+     * 
+     * @param mdApp 模型应用
+     * @return 结果
+     */
+    public int insertMdApp(MdApp mdApp);
+
+    /**
+     * 修改模型应用
+     * 
+     * @param mdApp 模型应用
+     * @return 结果
+     */
+    public int updateMdApp(MdApp mdApp);
+
+    /**
+     * 批量删除模型应用
+     * 
+     * @param appIds 需要删除的模型应用主键集合
+     * @return 结果
+     */
+    public int deleteMdAppByAppIds(Long[] appIds);
+
+    /**
+     * 删除模型应用信息
+     * 
+     * @param appId 模型应用主键
+     * @return 结果
+     */
+    public int deleteMdAppByAppId(Long appId);
+}

+ 10 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/SnailJobService.java

@@ -0,0 +1,10 @@
+package com.ruoyi.interfaces.service;
+
+import com.ruoyi.interfaces.domain.Job;
+import com.ruoyi.interfaces.domain.vo.JobRequestVo;
+
+import java.util.List;
+
+public interface SnailJobService {
+    List<Job> selectJobList(Job jobRequestVo);
+}

+ 96 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/impl/MdAppFlowServiceImpl.java

@@ -0,0 +1,96 @@
+package com.ruoyi.interfaces.service.impl;
+
+import java.util.List;
+import com.ruoyi.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.interfaces.mapper.MdAppFlowMapper;
+import com.ruoyi.interfaces.domain.MdAppFlow;
+import com.ruoyi.interfaces.service.IMdAppFlowService;
+
+/**
+ * 模型应用流程Service业务层处理
+ * 
+ * @author 朱得糠
+ * @date 2025-08-19
+ */
+@Service
+public class MdAppFlowServiceImpl implements IMdAppFlowService 
+{
+    @Autowired
+    private MdAppFlowMapper mdAppFlowMapper;
+
+    /**
+     * 查询模型应用流程
+     * 
+     * @param flowId 模型应用流程主键
+     * @return 模型应用流程
+     */
+    @Override
+    public MdAppFlow selectMdAppFlowByFlowId(Long flowId)
+    {
+        return mdAppFlowMapper.selectMdAppFlowByFlowId(flowId);
+    }
+
+    /**
+     * 查询模型应用流程列表
+     * 
+     * @param mdAppFlow 模型应用流程
+     * @return 模型应用流程
+     */
+    @Override
+    public List<MdAppFlow> selectMdAppFlowList(MdAppFlow mdAppFlow)
+    {
+        return mdAppFlowMapper.selectMdAppFlowList(mdAppFlow);
+    }
+
+    /**
+     * 新增模型应用流程
+     * 
+     * @param mdAppFlow 模型应用流程
+     * @return 结果
+     */
+    @Override
+    public int insertMdAppFlow(MdAppFlow mdAppFlow)
+    {
+        mdAppFlow.setCreateTime(DateUtils.getNowDate());
+        return mdAppFlowMapper.insertMdAppFlow(mdAppFlow);
+    }
+
+    /**
+     * 修改模型应用流程
+     * 
+     * @param mdAppFlow 模型应用流程
+     * @return 结果
+     */
+    @Override
+    public int updateMdAppFlow(MdAppFlow mdAppFlow)
+    {
+        mdAppFlow.setUpdateTime(DateUtils.getNowDate());
+        return mdAppFlowMapper.updateMdAppFlow(mdAppFlow);
+    }
+
+    /**
+     * 批量删除模型应用流程
+     * 
+     * @param flowIds 需要删除的模型应用流程主键
+     * @return 结果
+     */
+    @Override
+    public int deleteMdAppFlowByFlowIds(Long[] flowIds)
+    {
+        return mdAppFlowMapper.deleteMdAppFlowByFlowIds(flowIds);
+    }
+
+    /**
+     * 删除模型应用流程信息
+     * 
+     * @param flowId 模型应用流程主键
+     * @return 结果
+     */
+    @Override
+    public int deleteMdAppFlowByFlowId(Long flowId)
+    {
+        return mdAppFlowMapper.deleteMdAppFlowByFlowId(flowId);
+    }
+}

+ 95 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/impl/MdAppServiceImpl.java

@@ -0,0 +1,95 @@
+package com.ruoyi.interfaces.service.impl;
+
+import java.util.List;
+import com.ruoyi.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.interfaces.mapper.MdAppMapper;
+import com.ruoyi.interfaces.domain.MdApp;
+import com.ruoyi.interfaces.service.IMdAppService;
+
+/**
+ * 模型应用Service业务层处理
+ * 
+ * @author 朱得糠
+ * @date 2025-08-19
+ */
+@Service
+public class MdAppServiceImpl implements IMdAppService 
+{
+    @Autowired
+    private MdAppMapper mdAppMapper;
+
+    /**
+     * 查询模型应用
+     * 
+     * @param appId 模型应用主键
+     * @return 模型应用
+     */
+    @Override
+    public MdApp selectMdAppByAppId(Long appId)
+    {
+        return mdAppMapper.selectMdAppByAppId(appId);
+    }
+
+    /**
+     * 查询模型应用列表
+     * 
+     * @param mdApp 模型应用
+     * @return 模型应用
+     */
+    @Override
+    public List<MdApp> selectMdAppList(MdApp mdApp)
+    {
+        return mdAppMapper.selectMdAppList(mdApp);
+    }
+
+    /**
+     * 新增模型应用
+     * 
+     * @param mdApp 模型应用
+     * @return 结果
+     */
+    @Override
+    public int insertMdApp(MdApp mdApp)
+    {
+        mdApp.setCreateTime(DateUtils.getNowDate());
+        return mdAppMapper.insertMdApp(mdApp);
+    }
+
+    /**
+     * 修改模型应用
+     * 
+     * @param mdApp 模型应用
+     * @return 结果
+     */
+    @Override
+    public int updateMdApp(MdApp mdApp)
+    {
+        return mdAppMapper.updateMdApp(mdApp);
+    }
+
+    /**
+     * 批量删除模型应用
+     * 
+     * @param appIds 需要删除的模型应用主键
+     * @return 结果
+     */
+    @Override
+    public int deleteMdAppByAppIds(Long[] appIds)
+    {
+        return mdAppMapper.deleteMdAppByAppIds(appIds);
+    }
+
+    /**
+     * 删除模型应用信息
+     * 
+     * @param appId 模型应用主键
+     * @return 结果
+     */
+    @Override
+    public int deleteMdAppByAppId(Long appId)
+    {
+        return mdAppMapper.deleteMdAppByAppId(appId);
+    }
+}

+ 1 - 1
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/impl/PtServiceServiceImpl.java

@@ -170,7 +170,7 @@ public class PtServiceServiceImpl extends ServiceImpl<PtServiceMapper, PtService
             case "POST":
             return HttpUtils.sendPost(ptService.getUrl(),paramString);
             case "GET":
-                return HttpUtils.sendGet(ptService.getUrl(),paramString, Constants.UTF8,map);
+                return HttpUtils.sendGet(ptService.getUrl(),paramString,map);
         }
         return null;
     }

+ 28 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/impl/SnailJobServiceImpl.java

@@ -0,0 +1,28 @@
+package com.ruoyi.interfaces.service.impl;
+
+import com.ruoyi.interfaces.domain.Job;
+import com.ruoyi.interfaces.domain.vo.JobRequestVo;
+import com.ruoyi.interfaces.mapper.SnailJobMapper;
+import com.ruoyi.interfaces.service.SnailJobService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class SnailJobServiceImpl implements SnailJobService {
+
+    @Value("${snail-job.group}")
+    private String groupName;
+
+
+    @Autowired
+    private SnailJobMapper snailJobMapper;
+
+    @Override
+    public List<Job> selectJobList(Job jobRequestVo) {
+        jobRequestVo.setGroupName(groupName);
+        return snailJobMapper.selectJobList(jobRequestVo);
+    }
+}

+ 85 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/snailJob/AuthService.java

@@ -0,0 +1,85 @@
+package com.ruoyi.interfaces.snailJob;
+
+import com.google.gson.Gson;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.utils.JsonUtils;
+import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.http.HttpUtils;
+import com.ruoyi.interfaces.domain.vo.JobUserResponseVO;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.*;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import javax.json.JsonObject;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+@Component
+public class AuthService {
+    @Value("${snail-job.login.url}")
+    private  String url;
+    @Value("${snail-job.login.username}")
+    private String username;
+    @Value("${snail-job.login.password}")
+    private String password;
+    @Value("${snail-job.login.timeout}")
+    private Integer timeout;
+
+    public static final String AUTHENTICATION = "SNAIL-JOB-AUTH";
+    public static final String NAMESPACE_ID = "SNAIL-JOB-NAMESPACE-ID";
+    @Autowired
+    private RedisCache redisCache;
+
+    private static final String JOB_USER_KEY = "JOB_USER_KEY";
+
+    public JobUserResponseVO authenticate() {
+
+        String bodyPar = "{\n" +
+                "  \"username\": \"" + username + "\",\n" +
+                "  \"password\": \"" + password + "\"\n" +
+                "}";
+        String token = "";
+        JobUserResponseVO response = new JobUserResponseVO();
+        try {
+            token = HttpUtils.sendBodyPostTest(url+"/auth/login", bodyPar, null);
+            System.out.println(token);
+            String data = new JSONObject(token).getString("data");
+            System.out.println(data);
+            Gson gson = new Gson();
+            response = gson.fromJson(data, JobUserResponseVO.class);
+            redisCache.setCacheObject(JOB_USER_KEY, response, timeout, TimeUnit.MINUTES);
+        } catch (IOException | JSONException e) {
+            throw new RuntimeException(e);
+        }
+        return response;
+    }
+
+    public JobUserResponseVO getJobUserResponse() {
+        JobUserResponseVO jobUser = redisCache.getCacheObject(JOB_USER_KEY);
+        if (StringUtils.isNull(jobUser)) {
+            return authenticate();
+        }
+        return jobUser;
+    }
+
+    public String getUrl(){
+        return url;
+    }
+    public HashMap<String, String> getHeaders(){
+        HashMap<String, String> map = new HashMap<>();
+        HttpServletRequest request = ServletUtils.getRequest();
+        map.put(AUTHENTICATION,request.getHeader(AUTHENTICATION));
+        map.put(NAMESPACE_ID,ServletUtils.getRequest().getHeader(NAMESPACE_ID));
+        return map;
+    }
+}

+ 19 - 0
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/snailJob/TestJob.java

@@ -0,0 +1,19 @@
+package com.ruoyi.interfaces.snailJob;
+
+import com.aizuda.snailjob.client.job.core.annotation.JobExecutor;
+import com.aizuda.snailjob.client.job.core.dto.JobArgs;
+import com.aizuda.snailjob.common.log.SnailJobLog;
+import com.aizuda.snailjob.model.dto.ExecuteResult;
+import org.springframework.stereotype.Component;
+
+@Component
+public class TestJob {
+    @JobExecutor(name = "testJob")
+    public ExecuteResult job(JobArgs jobArgs) {
+        SnailJobLog.REMOTE.info("=======调用成功========");
+        SnailJobLog.REMOTE.info("=======调用成功========");
+        SnailJobLog.REMOTE.info("=======调用成功========");
+        SnailJobLog.REMOTE.info("=======调用成功========");
+        return ExecuteResult.success("成功");
+    }
+}

+ 106 - 0
ruoyi-api-patform/src/main/resources/mapper/interfaces/MdAppFlowMapper.xml

@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.interfaces.mapper.MdAppFlowMapper">
+
+    <resultMap type="com.ruoyi.interfaces.domain.MdAppFlow" id="MdAppFlowResult">
+        <result property="flowId"    column="FLOW_ID"    />
+        <result property="appId"    column="APP_ID"    />
+        <result property="flowName"    column="FLOW_NAME"    />
+        <result property="flowGraph"    column="FLOW_GRAPH"    />
+        <result property="flowType"    column="FLOW_TYPE"    />
+        <result property="flowNote"    column="FLOW_NOTE"    />
+        <result property="flowStatus"    column="FLOW_STATUS"    />
+        <result property="flowSort"    column="FLOW_SORT"    />
+        <result property="createBy"    column="CREATE_BY"    />
+        <result property="createTime"    column="CREATE_TIME"    />
+        <result property="updateBy"    column="UPDATE_BY"    />
+        <result property="updateTime"    column="UPDATE_TIME"    />
+    </resultMap>
+
+    <sql id="selectMdAppFlowVo">
+        select FLOW_ID, APP_ID, FLOW_NAME, FLOW_GRAPH, FLOW_TYPE, FLOW_NOTE, FLOW_STATUS, FLOW_SORT, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME from md_app_flow
+    </sql>
+
+    <select id="selectMdAppFlowList" parameterType="com.ruoyi.interfaces.domain.MdAppFlow" resultMap="MdAppFlowResult">
+        <include refid="selectMdAppFlowVo"/>
+        <where>
+            <if test="appId != null  and appId != ''"> and APP_ID = #{appId}</if>
+            <if test="flowName != null  and flowName != ''"> and FLOW_NAME like concat('%', #{flowName}, '%')</if>
+            <if test="flowGraph != null  and flowGraph != ''"> and FLOW_GRAPH = #{flowGraph}</if>
+            <if test="flowType != null  and flowType != ''"> and FLOW_TYPE = #{flowType}</if>
+            <if test="flowNote != null  and flowNote != ''"> and FLOW_NOTE = #{flowNote}</if>
+            <if test="flowStatus != null "> and FLOW_STATUS = #{flowStatus}</if>
+            <if test="flowSort != null "> and FLOW_SORT = #{flowSort}</if>
+            <if test="createBy != null  and createBy != ''"> and CREATE_BY = #{createBy}</if>
+            <if test="createTime != null "> and CREATE_TIME = #{createTime}</if>
+            <if test="updateBy != null  and updateBy != ''"> and UPDATE_BY = #{updateBy}</if>
+            <if test="updateTime != null "> and UPDATE_TIME = #{updateTime}</if>
+        </where>
+    </select>
+
+    <select id="selectMdAppFlowByFlowId" parameterType="Long" resultMap="MdAppFlowResult">
+        <include refid="selectMdAppFlowVo"/>
+        where FLOW_ID = #{flowId}
+    </select>
+
+    <insert id="insertMdAppFlow" parameterType="com.ruoyi.interfaces.domain.MdAppFlow" useGeneratedKeys="true" keyProperty="flowId">
+        insert into md_app_flow
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="appId != null and appId != ''">APP_ID,</if>
+            <if test="flowName != null and flowName != ''">FLOW_NAME,</if>
+            <if test="flowGraph != null">FLOW_GRAPH,</if>
+            <if test="flowType != null">FLOW_TYPE,</if>
+            <if test="flowNote != null">FLOW_NOTE,</if>
+            <if test="flowStatus != null">FLOW_STATUS,</if>
+            <if test="flowSort != null">FLOW_SORT,</if>
+            <if test="createBy != null">CREATE_BY,</if>
+            <if test="createTime != null">CREATE_TIME,</if>
+            <if test="updateBy != null">UPDATE_BY,</if>
+            <if test="updateTime != null">UPDATE_TIME,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="appId != null and appId != ''">#{appId},</if>
+            <if test="flowName != null and flowName != ''">#{flowName},</if>
+            <if test="flowGraph != null">#{flowGraph},</if>
+            <if test="flowType != null">#{flowType},</if>
+            <if test="flowNote != null">#{flowNote},</if>
+            <if test="flowStatus != null">#{flowStatus},</if>
+            <if test="flowSort != null">#{flowSort},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+        </trim>
+    </insert>
+
+    <update id="updateMdAppFlow" parameterType="com.ruoyi.interfaces.domain.MdAppFlow">
+        update md_app_flow
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="appId != null and appId != ''">APP_ID = #{appId},</if>
+            <if test="flowName != null and flowName != ''">FLOW_NAME = #{flowName},</if>
+            <if test="flowGraph != null">FLOW_GRAPH = #{flowGraph},</if>
+            <if test="flowType != null">FLOW_TYPE = #{flowType},</if>
+            <if test="flowNote != null">FLOW_NOTE = #{flowNote},</if>
+            <if test="flowStatus != null">FLOW_STATUS = #{flowStatus},</if>
+            <if test="flowSort != null">FLOW_SORT = #{flowSort},</if>
+            <if test="createBy != null">CREATE_BY = #{createBy},</if>
+            <if test="createTime != null">CREATE_TIME = #{createTime},</if>
+            <if test="updateBy != null">UPDATE_BY = #{updateBy},</if>
+            <if test="updateTime != null">UPDATE_TIME = #{updateTime},</if>
+        </trim>
+        where FLOW_ID = #{flowId}
+    </update>
+
+    <delete id="deleteMdAppFlowByFlowId" parameterType="Long">
+        delete from md_app_flow where FLOW_ID = #{flowId}
+    </delete>
+
+    <delete id="deleteMdAppFlowByFlowIds" parameterType="String">
+        delete from md_app_flow where FLOW_ID in
+        <foreach item="flowId" collection="array" open="(" separator="," close=")">
+            #{flowId}
+        </foreach>
+    </delete>
+</mapper>

+ 81 - 0
ruoyi-api-patform/src/main/resources/mapper/interfaces/MdAppMapper.xml

@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.interfaces.mapper.MdAppMapper">
+
+    <resultMap type="com.ruoyi.interfaces.domain.MdApp" id="MdAppResult">
+        <result property="appId"    column="APP_ID"    />
+        <result property="appTitle"    column="APP_TITLE"    />
+        <result property="appNote"    column="APP_NOTE"    />
+        <result property="appIcon"    column="APP_ICON"    />
+        <result property="appOrd"    column="APP_ORD"    />
+        <result property="createBy"    column="CREATE_BY"    />
+        <result property="createTime"    column="CREATE_TIME"    />
+    </resultMap>
+
+    <sql id="selectMdAppVo">
+        select APP_ID, APP_TITLE, APP_NOTE, APP_ICON, APP_ORD, CREATE_BY, CREATE_TIME from md_app
+    </sql>
+
+    <select id="selectMdAppList" parameterType="com.ruoyi.interfaces.domain.MdApp" resultMap="MdAppResult">
+        <include refid="selectMdAppVo"/>
+        <where>
+            <if test="appTitle != null  and appTitle != ''"> and APP_TITLE like concat('%', #{appTitle}, '%')</if>
+            <if test="appNote != null  and appNote != ''"> and APP_NOTE = #{appNote}</if>
+            <if test="appIcon != null  and appIcon != ''"> and APP_ICON = #{appIcon}</if>
+            <if test="appOrd != null "> and APP_ORD = #{appOrd}</if>
+            <if test="createBy != null  and createBy != ''"> and CREATE_BY = #{createBy}</if>
+            <if test="createTime != null "> and CREATE_TIME = #{createTime}</if>
+        </where>
+    </select>
+
+    <select id="selectMdAppByAppId" parameterType="Long" resultMap="MdAppResult">
+        <include refid="selectMdAppVo"/>
+        where APP_ID = #{appId}
+    </select>
+
+    <insert id="insertMdApp" parameterType="com.ruoyi.interfaces.domain.MdApp" useGeneratedKeys="true" keyProperty="appId">
+        insert into md_app
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="appTitle != null and appTitle != ''">APP_TITLE,</if>
+            <if test="appNote != null and appNote != ''">APP_NOTE,</if>
+            <if test="appIcon != null">APP_ICON,</if>
+            <if test="appOrd != null">APP_ORD,</if>
+            <if test="createBy != null">CREATE_BY,</if>
+            <if test="createTime != null">CREATE_TIME,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="appTitle != null and appTitle != ''">#{appTitle},</if>
+            <if test="appNote != null and appNote != ''">#{appNote},</if>
+            <if test="appIcon != null">#{appIcon},</if>
+            <if test="appOrd != null">#{appOrd},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+        </trim>
+    </insert>
+
+    <update id="updateMdApp" parameterType="com.ruoyi.interfaces.domain.MdApp">
+        update md_app
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="appTitle != null and appTitle != ''">APP_TITLE = #{appTitle},</if>
+            <if test="appNote != null and appNote != ''">APP_NOTE = #{appNote},</if>
+            <if test="appIcon != null">APP_ICON = #{appIcon},</if>
+            <if test="appOrd != null">APP_ORD = #{appOrd},</if>
+            <if test="createBy != null">CREATE_BY = #{createBy},</if>
+            <if test="createTime != null">CREATE_TIME = #{createTime},</if>
+        </trim>
+        where APP_ID = #{appId}
+    </update>
+
+    <delete id="deleteMdAppByAppId" parameterType="Long">
+        delete from md_app where APP_ID = #{appId}
+    </delete>
+
+    <delete id="deleteMdAppByAppIds" parameterType="String">
+        delete from md_app where APP_ID in
+        <foreach item="appId" collection="array" open="(" separator="," close=")">
+            #{appId}
+        </foreach>
+    </delete>
+</mapper>

+ 83 - 0
ruoyi-api-patform/src/main/resources/mapper/interfaces/SnailJobMapper.xml

@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.interfaces.mapper.SnailJobMapper">
+
+    <resultMap type="com.ruoyi.interfaces.domain.Job" id="JobResult">
+    <result property="id"    column="id"    />
+    <result property="namespaceId"    column="namespace_id"    />
+    <result property="groupName"    column="group_name"    />
+    <result property="jobName"    column="job_name"    />
+    <result property="argsStr"    column="args_str"    />
+    <result property="argsType"    column="args_type"    />
+    <result property="nextTriggerAt"    column="next_trigger_at"    />
+    <result property="jobStatus"    column="job_status"    />
+    <result property="taskType"    column="task_type"    />
+    <result property="routeKey"    column="route_key"    />
+    <result property="executorType"    column="executor_type"    />
+    <result property="executorInfo"    column="executor_info"    />
+    <result property="triggerType"    column="trigger_type"    />
+    <result property="triggerInterval"    column="trigger_interval"    />
+    <result property="blockStrategy"    column="block_strategy"    />
+    <result property="executorTimeout"    column="executor_timeout"    />
+    <result property="maxRetryTimes"    column="max_retry_times"    />
+    <result property="parallelNum"    column="parallel_num"    />
+    <result property="retryInterval"    column="retry_interval"    />
+    <result property="bucketIndex"    column="bucket_index"    />
+    <result property="resident"    column="resident"    />
+    <result property="notifyIds"    column="notify_ids"    />
+    <result property="ownerId"    column="owner_id"    />
+    <result property="labels"    column="labels"    />
+    <result property="description"    column="description"    />
+    <result property="extAttrs"    column="ext_attrs"    />
+    <result property="deleted"    column="deleted"    />
+    </resultMap>
+    <sql id="selectJobVo">
+        select id,
+            namespace_id,
+            group_name,
+            job_name,
+            args_str,
+            args_type,
+            next_trigger_at,
+            job_status,
+            task_type,
+            route_key,
+            executor_type,
+            executor_info,
+            trigger_type,
+            trigger_interval,
+            block_strategy,
+            executor_timeout,
+            max_retry_times,
+            parallel_num,
+            retry_interval,
+            bucket_index,
+            resident,
+            notify_ids,
+            owner_id,
+            labels,
+            description,
+            ext_attrs,
+            deleted
+        from sj_job
+    </sql>
+    <select id="selectJobList" resultType="com.ruoyi.interfaces.domain.Job">
+        <include refid="selectJobVo"></include>
+        <where>
+            <if test="namespaceId != null  and namespaceId != ''">and namespace_id = #{namespaceId}</if>
+            <if test="groupName != null  and groupName != ''">and group_name = #{groupName}</if>
+            <if test="jobName != null  and jobName != ''">and job_name = #{jobName}</if>
+            <if test="argsStr != null  and argsStr != ''">and args_str = #{argsStr}</if>
+            <if test="argsType != null  ">and args_type = #{argsType}</if>
+            <if test="nextTriggerAt != null  ">and next_trigger_at = #{nextTriggerAt}</if>
+            <if test="jobStatus != null  ">and job_status = #{jobStatus}</if>
+            <if test="taskType != null ">and task_type = #{taskType}</if>
+            <if test="routeKey != null ">and route_key = #{routeKey}</if>
+            <if test="executorType != null ">and executor_type = #{executorType}</if>
+            <if test="executorInfo != null ">and executor_info = #{executorInfo}</if>
+        </where>
+        order by id
+    </select>
+</mapper>

+ 22 - 0
ruoyi-common/pom.xml

@@ -163,6 +163,28 @@
             <artifactId>lombok</artifactId>
         </dependency>
 
+        <!-- snail-job 客户端依赖 -->
+        <dependency>
+            <groupId>com.aizuda</groupId>
+            <artifactId>snail-job-client-starter</artifactId>
+            <version>${snail-job.version}</version>
+        </dependency>
+
+        <!-- snail-job 重试相关依赖 -->
+        <dependency>
+            <groupId>com.aizuda</groupId>
+            <artifactId>snail-job-client-retry-core</artifactId>
+            <version>${snail-job.version}</version>
+        </dependency>
+
+        <!-- snail-job 客户端核心依赖 -->
+        <dependency>
+            <groupId>com.aizuda</groupId>
+            <artifactId>snail-job-client-job-core</artifactId>
+            <version>${snail-job.version}</version>
+        </dependency>
+
+
 
         <dependency>
             <groupId>dev.tinyflow</groupId>

+ 4 - 0
ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java

@@ -16,6 +16,10 @@ public enum DataSourceType
      * 从库
      */
     SLAVE,
+    /**
+     * snail_job
+     */
+    JOB,
     /**
      * me数据库
      * */

+ 51 - 4
ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java

@@ -8,8 +8,7 @@ import java.net.URLConnection;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
 import java.security.cert.X509Certificate;
-import java.util.Base64;
-import java.util.HashMap;
+import java.util.*;
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
@@ -18,12 +17,15 @@ import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
 
 import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.utils.URLEncodedUtils;
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.mime.MultipartEntityBuilder;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
 import org.apache.http.util.EntityUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -74,6 +76,15 @@ public class HttpUtils {
         return sendGet(url, param, Constants.UTF8);
     }
 
+    public static String sendGet(String url, Object param) {
+        return sendGet(url, toQueryString(param));
+    }
+
+    public static String sendGet(String url, Object param,HashMap<String, String> headers) {
+
+        return sendGet(url, toQueryString(param),headers);
+    }
+
     /**
      * 向指定 URL 发送GET方法的请求
      *
@@ -117,10 +128,30 @@ public class HttpUtils {
                 log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
             }
         }
+
         return result.toString();
     }
 
-    public static String sendGet(String url, String param, String contentType, HashMap<String, String> headers) {
+    public static String sendGet(String url, String param, HashMap<String, String> headers) {
+        System.out.println("=======================");
+        System.out.println("=======================");
+        System.out.println("=======================");
+        System.out.println("=======================");
+        System.out.println(url);
+        System.out.println(param);
+        param = param.substring(0,1);
+        System.out.println(param);
+        for (String s : headers.keySet()) {
+            System.out.println(s+":"+headers.get(s));
+        }
+
+        System.out.println("=======================");
+        System.out.println("=======================");
+        System.out.println("=======================");
+        System.out.println("=======================");
+
+
+
         StringBuilder result = new StringBuilder();
         BufferedReader in = null;
         try {
@@ -137,7 +168,7 @@ public class HttpUtils {
             }
 
             connection.connect();
-            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
+            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), Constants.UTF8));
             String line;
             while ((line = in.readLine()) != null) {
                 result.append(line);
@@ -548,5 +579,21 @@ public class HttpUtils {
             throw new IOException("SSL configuration failed", e);
         }
     }*/
+    public static String toQueryString(Object obj) {
+        List<NameValuePair> params = new ArrayList<>();
 
+        // 遍历实体类字段(简化版,实际需处理复杂类型)
+        for (java.lang.reflect.Field field : obj.getClass().getDeclaredFields()) {
+            field.setAccessible(true);
+            try {
+                Object value = field.get(obj);
+                if (value != null) {
+                    params.add(new BasicNameValuePair(field.getName(), value.toString()));
+                }
+            } catch (IllegalAccessException ignored) {
+            }
+        }
+
+        return URLEncodedUtils.format(params, StandardCharsets.UTF_8);
+    }
 }

+ 9 - 0
ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java

@@ -48,6 +48,14 @@ public class DruidConfig
         DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
         return druidProperties.dataSource(dataSource);
     }
+    @Bean
+    @ConfigurationProperties("spring.datasource.druid.job")
+    @ConditionalOnProperty(prefix = "spring.datasource.druid.job", name = "enabled", havingValue = "true")
+    public DataSource jobDataSource(DruidProperties druidProperties)
+    {
+        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
+        return druidProperties.dataSource(dataSource);
+    }
 
     @Bean
     @ConfigurationProperties("spring.datasource.druid.me")
@@ -65,6 +73,7 @@ public class DruidConfig
         Map<Object, Object> targetDataSources = new HashMap<>();
         targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
         setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");
+        setDataSource(targetDataSources, DataSourceType.JOB.name(), "jobDataSource");
         setDataSource(targetDataSources, DataSourceType.ME.name(), "meDataSource");
         return new DynamicDataSource(masterDataSource, targetDataSources);
     }

+ 51 - 0
ruoyi-ui/src/api/service/timing.js

@@ -0,0 +1,51 @@
+import request from "@/utils/request";
+
+export function snailList(query) {
+  return request({
+    url: '/snail/job/jobList',
+    method: 'get',
+    params: query
+  })
+}
+export function addSnail(data) {
+  return request({
+    url: "/snail/job",
+    method: 'post',
+    data:data
+  });
+}
+export function snailDe(query) {
+  return request({
+    url: '/snail/job/getJobDetail',
+    method: 'get',
+    params: query
+  })
+}
+export function snailEdit(data) {
+  return request({
+    url: '/snail/job',
+    method: 'put',
+    data: data
+  })
+}
+export function delSnamil(id) {
+  return request({
+    url: '/snail/job/job',
+    method: 'delete',
+    params: id
+  })
+}
+export function snailSta(query) {
+  return request({
+    url: '/snail/job/updateJobStatus',
+    method: 'get',
+    params: query
+  })
+}
+export function snailTri(query) {
+  return request({
+    url: '/snail/job/triggerJob',
+    method: 'get',
+    params: query
+  })
+}

+ 5 - 5
ruoyi-ui/src/views/register/modelData/index.vue

@@ -41,11 +41,11 @@ const data =  ref([
         value:'dataSource',
         id:'1'
     },
-    {
-        label:'元数据',
-        value:'metaData',
-        id:'2'
-    },
+    // {
+    //     label:'元数据',
+    //     value:'metaData',
+    //     id:'2'
+    // },
     {
         label:'数据集(编辑)',
         value:'dataUn',

+ 380 - 256
ruoyi-ui/src/views/service/timing/index.vue

@@ -5,63 +5,40 @@
             <div>
                 组名称
             </div>
-            <el-select
-            v-model="serzu"
-            class="noBorSel"
-            placeholder=""
-            style="width: 10%;margin-left: 1%;"
-            >
-                <el-option
-                v-for="item in optionsShuLei"
-                :key="item.value"
-                :label="item.label"
-                :value="item.value"
-                />
-            </el-select>
+            <el-input size="mini" v-model="groupName" style="width: 10%;margin-left: 1%;" placeholder="" />
             <div style="margin-left: 2%;">
                 任务名称
             </div>
-            <el-input size="mini" v-model="formTree.itemNo" style="width: 10%;margin-left: 1%;" placeholder="" />
+            <el-input size="mini" v-model="jobName" style="width: 10%;margin-left: 1%;" placeholder="" />
             <div style="margin-left: 2%;">
                 执行器名称
             </div>
-            <el-input size="mini" v-model="formTree.itemNo" style="width: 10%;margin-left: 1%;" placeholder="" />
+            <el-input size="mini" v-model="executorInfo" style="width: 10%;margin-left: 1%;" placeholder="" />
             <div style="margin-left: 2%;">
                 状态
             </div>
             <el-select
-            v-model="serzu"
+            v-model="jobStatus"
             class="noBorSel"
             placeholder=""
             style="width: 10%;margin-left: 1%;"
             >
-                <el-option
-                v-for="item in optionsShuLei"
-                :key="item.value"
-                :label="item.label"
-                :value="item.value"
-                />
+                <el-option label="启用" :value="0" />
+                <el-option label="禁用" :value="1" />
             </el-select>
-            <div style="margin-left: 2%;">
-                负责人
-            </div>
-            <el-input size="mini" v-model="formTree.itemNo" style="width: 10%;margin-left: 1%;" placeholder="" />
-            <el-button type="" @click="showAdd" size="mini" style="margin-left:auto;" :icon="RefreshRight">重置 </el-button>
-            <el-button type="primary" @click="showAdd" size="mini" style="margin-left:1%;" :icon="Search">搜索 </el-button>
+            <!-- <el-button type="" @click="" size="mini" style="margin-left:auto;" :icon="RefreshRight">重置 </el-button> -->
+            <el-button type="primary" @click="getTable" size="mini" style="margin-left:auto;" :icon="Search">搜索 </el-button>
         </div>
-        <el-divider/>
-        <div style="width: 98%;margin-left: 1%;">
+        <!-- <el-divider/> -->
+        <div style="width: 99%;margin-left: 1%;margin-top: 1%;">
             <div style="display: flex;justify-content: space-between;width: 100%;align-items: center;">
                 <div style="font-weight: bold;">
                     定时任务列表
                 </div>
                 <div style="display: flex;width: 50%;">
                     <el-button plain type="primary" @click="showAdd" size="mini" style="margin-left:auto;" :icon="Plus">新增 </el-button>
-                    <el-button plain type="primary"  size="mini" style="margin-left:1%;" :icon="Upload">导入</el-button>
-                    <el-button plain type="primary"  size="mini" style="margin-left:1%;" :icon="Download">导出</el-button>
-                    <el-button type="danger" plain size="mini" style="margin-left:1%;" :icon="Delete">批量删除</el-button>
-                    <el-button plain type=""  size="mini" style="margin-left:1%;" :icon="RefreshRight">刷新</el-button>
-                    <el-dropdown trigger="click" v-model="dropdownVisible" @visible-change="handleVisibleChange" style="margin-left:1%;">
+                    <el-button type="danger" @click="delAll" plain size="mini" style="margin-left:1%;" :icon="Delete">删除</el-button>
+                    <!-- <el-dropdown trigger="click" v-model="dropdownVisible" @visible-change="handleVisibleChange" style="margin-left:1%;">
                         <el-button type="primary" plain size="mini" style="margin-left:1%;" :icon="Setting">列设置</el-button>
                         <template #dropdown>
                             <el-dropdown-menu style="width: 150px;">
@@ -106,7 +83,7 @@
                                 </el-dropdown-item>
                             </el-dropdown-menu>
                         </template>
-                    </el-dropdown>
+                    </el-dropdown> -->
                 </div>
             </div>
         </div>
@@ -115,6 +92,7 @@
         style="width: 100%;margin-left: 0%;margin-top:1%;"
         :cell-style="{ paddingTop:'3px',paddingBottom:'3px' }"
         :header-cell-style="{height: heightAll*0.01+'px',}"
+        @selection-change="handleSelectionChange" 
         :row-style="{ fontSize: '16px',textAlign:'center'}"
         border 
         :height="tableheight">
@@ -128,45 +106,45 @@
         <el-table-column prop="groupName" label="组名称" width="160" v-if="showTablepane.zm"/>
         <el-table-column prop="executorInfo" label="执行器名称" width="160" v-if="showTablepane.zx"/>
         <el-table-column prop="ownerName" label="负责人" width="160" v-if="showTablepane.fz"/>
-        <el-table-column prop="labels" label="标签" width="140" v-if="showTablepane.bq">
-            <template #default="scope">
-                <el-tag>测试</el-tag>
-                <div v-for="item in scope.row.labels">
-                  <el-tag></el-tag>
-                </div>
-            </template>
-        </el-table-column>
-        <el-table-column prop="nextTriggerAt" label="触发时间" width="140" v-if="showTablepane.cf">
+        <el-table-column prop="nextTriggerAt" label="触发时间" width="180" v-if="showTablepane.cf">
         </el-table-column>
         <el-table-column prop="jobStatus" label="状态" width="170" v-if="showTablepane.zt">
             <template #default="scope">
-                <el-switch v-model="scope.row.jobStatus"/>
+                <el-switch @change="changejobStatus(scope.row)" v-model="scope.row.jobStatus"/>
             </template>
         </el-table-column>
-        <el-table-column prop="itemNotes" label="任务类型" width="170" v-if="showTablepane.rwl">
+        <el-table-column prop="taskType" label="任务类型" width="170" v-if="showTablepane.rwl">
             <template #default="scope">
-                <el-tag>测试</el-tag>
+                <el-tag v-if="scope.row.taskType==1" type="success">集群</el-tag>
+                <el-tag v-if="scope.row.taskType==2" type="info">广播</el-tag>
+                <el-tag v-if="scope.row.taskType==3" type="warning">Sharding</el-tag>
+                <el-tag v-if="scope.row.taskType==4" type="danger">Map</el-tag>
+                <el-tag v-if="scope.row.taskType==5">MapReduce</el-tag>
             </template>
         </el-table-column>
-        <el-table-column prop="itemNotes" label="触发类型" width="170" v-if="showTablepane.cfl">
+        <el-table-column prop="triggerType" label="触发类型" width="170" v-if="showTablepane.cfl">
             <template #default="scope">
-                <el-tag>测试</el-tag>
+                <el-tag v-if="scope.row.triggerType==2">固定时间</el-tag>
+                <el-tag v-if="scope.row.triggerType==3">CRON 表达式</el-tag>
+                <el-tag v-if="scope.row.triggerType==99">工作流</el-tag>
             </template>
         </el-table-column>
-        <el-table-column prop="itemNotes" label="间隔时长" width="170" v-if="showTablepane.jg"/>
-        <el-table-column prop="itemNotes" label="阻塞策略" width="170" v-if="showTablepane.zs">
+        <el-table-column prop="retryInterval" label="间隔时长" width="170" v-if="showTablepane.jg"/>
+        <el-table-column prop="blockStrategy" label="阻塞策略" width="170" v-if="showTablepane.zs">
             <template #default="scope">
-                <el-tag>测试</el-tag>
+                <el-tag v-if="scope.row.blockStrategy==1">丢弃</el-tag>
+                <el-tag v-if="scope.row.blockStrategy==2">覆盖</el-tag>
+                <el-tag v-if="scope.row.blockStrategy==3">并行</el-tag>
             </template>
         </el-table-column>
-        <el-table-column prop="itemNotes" label="超时时间(秒)" width="170" v-if="showTablepane.cs"/>
-        <el-table-column prop="itemNotes" label="更新时间" width="170" v-if="showTablepane.gx"/>
+        <el-table-column prop="executorTimeout" label="超时时间(秒)" width="170" v-if="showTablepane.cs"/>
+        <el-table-column prop="updateDt" label="更新时间" width="170" v-if="showTablepane.gx"/>
         <el-table-column prop="address" label="操作" width="222" fixed="right">
             <template #default="scope">
                 <div style="display: flex;justify-content: space-between;width: 100%;">
                     <el-button type="primary" @click="showEdit(scope.row)" size="mini" text style="margin-left: 1%;">编辑</el-button>
-                    <el-button @click="showDe(scope.row)" type="primary" text size="mini" style="margin-left: 1%;">执行</el-button>
-                    <el-button @click="delRow(scope.row)" type="danger" text size="mini" style="margin-left: 1%;">更多</el-button>
+                    <el-button @click="snaliTrigger(scope.row)" type="primary" text size="mini" style="margin-left: 1%;">执行</el-button>
+                    <el-button @click="delRow(scope.row)" type="danger" text size="mini" style="margin-left: 1%;">删除</el-button>
                 </div>
             </template>
         </el-table-column>
@@ -197,7 +175,7 @@
                 <el-col :span="8">
                 <el-form-item label="组名称:" prop="groupName" style="">
                     <div style="display: flex;width: 100%;justify-content: space-between;">
-                        <el-input  v-model="formJi.groupName" style="width: 100%;"/>
+                        <el-input :disabled="!isAddTa" v-model="formJi.groupName" style="width: 100%;"/>
                     </div>
                 </el-form-item>
                 </el-col>
@@ -211,7 +189,7 @@
         </el-row>
         <el-row :gutter="48">
             <el-col :span="15">
-            <el-form-item label="标签:" prop="" style="">
+            <!-- <el-form-item label="标签:" prop="" style="">
                  <div 
                     v-if="parTag.length==0"
                     @click='addTag'
@@ -238,15 +216,15 @@
                         <el-icon @click="addTag" style="margin-left: 3%;color: #337ecc;cursor: pointer;"><Plus /></el-icon>
                     </div>
                 </div>
-            </el-form-item>
+            </el-form-item> -->
             </el-col>
         </el-row>
         <el-row :gutter="48">
             <el-col :span="8">
-                <el-form-item label="状态:">
-                    <el-radio-group v-model="formJi.jobStatus" class="custom-radio-group" style="width: 100%;margin-top: -1%;">
-                        <el-radio :label=0 size="large">启用</el-radio>
-                        <el-radio :label=1 size="large">禁用</el-radio>
+                <el-form-item label="状态:" prop="jobStatus">
+                    <el-radio-group :disabled="!isAddTa" v-model="formJi.jobStatus" class="custom-radio-group" style="width: 100%;margin-top: -1%;">
+                        <el-radio :label=1 size="large">启用</el-radio>
+                        <el-radio :label=0 size="large">禁用</el-radio>
                     </el-radio-group>
                 </el-form-item>
             </el-col>
@@ -254,7 +232,7 @@
         </el-row>
         <el-row :gutter="48">
             <el-col :span="8">
-                <el-form-item label="任务类型:">
+                <el-form-item label="任务类型:" prop="taskType">
                     <el-select
                     v-model="formJi.taskType"
                     class="noBorSel"
@@ -271,106 +249,82 @@
                 </el-form-item>
             </el-col>
         </el-row>
-        <el-form-item label="执行器名称:">
-            <div style="display: flex;width: 50%;align-items: center;">
-                <el-radio-group @change="showCode" v-model="formJi.executorInfo" class="custom-radio-group" style="width: 100%;margin-top: -0.5%;">
-                    <el-radio label="自定义执行器" size="large">自定义执行器</el-radio>
-                    <el-radio label="内置执行器" size="large">内置执行器</el-radio>
-                </el-radio-group>
-                <el-select
-                v-if="formJi.executorInfo=='内置执行器'"
-                v-model="serzu"
-                class="noBorSel"
-                placeholder=""
-                style="width: 70%;margin-left: 1%;"
-                >
-                    <el-option
-                    v-for="item in optionsShuLei"
-                    :key="item.value"
-                    :label="item.label"
-                    :value="item.value"
-                    />
-                </el-select>
-                <el-input v-if="formJi.executorInfo=='自定义执行器'" v-model="formZu.dcNote" style="width: 75%;" placeholder="请输入自定义执行器名称"/>
+        <el-form-item label="执行器名称:" prop="executorInfo">
+            <div style="display: flex;width: 100%;align-items: center;">
+                <el-input  v-model="formJi.executorInfo" style="width: 75%;" placeholder=""/>
             </div>
         </el-form-item>
-        <div v-if="formJi.executorInfo=='自定义执行器'" style="margin-top: 4%;">
+        <div style="margin-top: 0%;">
             <el-form-item label="方法参数:" >
-                <el-input v-model="formZu.dcNote" style="width: 75%;" placeholder="" type="textarea" :row="2" resize="none"/>
+                <el-input v-model="formJi.argsStr" style="width: 75%;" placeholder="" type="textarea" :row="2" resize="none"/>
             </el-form-item>
             <el-row :gutter="48">
                 <el-col :span="8">
-                    <el-form-item label="路由策略:">
+                    <el-form-item label="路由策略:" prop="routeKey">
                         <el-select
-                        v-model="serzu"
+                        v-model="formJi.routeKey"
                         class="noBorSel"
                         placeholder=""
                         style="width: 100%;margin-left: 0%;"
                         >
-                            <el-option
-                            v-for="item in optionsShuLei"
-                            :key="item.value"
-                            :label="item.label"
-                            :value="item.value"
-                            />
+                          <el-option label="Hash" :value="1" />
+                          <el-option label="随机" :value="2" />
+                          <el-option label="LRU" :value="3" />
+                          <el-option label="轮询" :value="4" />
+                          <el-option label="匹配第一个" :value="5" />
+                          <el-option label="匹配最后一个" :value="6" />
                         </el-select>
                     </el-form-item>
                 </el-col>
                 <el-col :span="8">
-                    <el-form-item label="阻塞策略:">
+                    <el-form-item label="阻塞策略:" prop="blockStrategy">
                         <el-select
-                        v-model="serzu"
+                        v-model="formJi.blockStrategy"
                         class="noBorSel"
                         placeholder=""
                         style="width: 100%;margin-left: 0%;"
                         >
-                            <el-option
-                            v-for="item in optionsShuLei"
-                            :key="item.value"
-                            :label="item.label"
-                            :value="item.value"
-                            />
+                          <el-option label="丢弃" :value="1" />
+                          <el-option label="覆盖" :value="2" />
+                          <el-option label="并行" :value="3" />
                         </el-select>
                     </el-form-item>
                 </el-col>
             </el-row>
             <el-row :gutter="48">
                 <el-col :span="8">
-                    <el-form-item label="触发类型:">
+                    <el-form-item label="触发类型:" prop="triggerType">
                         <el-select
-                        v-model="serzu"
+                        v-model="formJi.triggerType"
                         class="noBorSel"
                         placeholder=""
                         style="width: 100%;margin-left: 0%;"
                         >
-                            <el-option
-                            v-for="item in optionsShuLei"
-                            :key="item.value"
-                            :label="item.label"
-                            :value="item.value"
-                            />
+                          <el-option label="固定时间" :value="2" />
+                          <el-option label="CRON 表达式" :value="3" />
+                          <el-option label="工作流" :value="99" />
                         </el-select>
                     </el-form-item>
                 </el-col>
                 <el-col :span="8">
-                    <el-form-item label="间隔时长:">
+                    <el-form-item label="间隔时长:" prop="triggerInterval">
                          <el-input-number
-                            v-model="num"
+                            v-model="formJi.triggerInterval"
                             style="width: 100%;"
                             class="mx-4"
                             :min="1"
                             :max="10"
                             controls-position="right"
-                            @change="handleChange"
+                            @CHANGE="handleChange"
                         />
                     </el-form-item>
                 </el-col>
             </el-row>
             <el-row :gutter="48">
                 <el-col :span="8">
-                    <el-form-item label="超时时间(秒):">
+                    <el-form-item label="超时时间(秒):" prop="executorTimeout">
                         <el-input-number
-                            v-model="num"
+                            v-model="formJi.executorTimeout"
                             style="width: 100%;"
                             class="mx-4"
                             :min="1"
@@ -381,9 +335,9 @@
                     </el-form-item>
                 </el-col>
                 <el-col :span="8">
-                    <el-form-item label="最大重试次数:">
+                    <el-form-item label="最大重试次数:" prop="maxRetryTimes">
                          <el-input-number
-                            v-model="num"
+                            v-model="formJi.maxRetryTimes"
                             style="width: 100%;"
                             class="mx-4"
                             :min="1"
@@ -396,9 +350,9 @@
             </el-row>
             <el-row :gutter="48">
                 <el-col :span="8">
-                    <el-form-item label="重试间隔:">
+                    <el-form-item label="重试间隔:" prop="retryInterval">
                         <el-input-number
-                            v-model="num"
+                            v-model="formJi.retryInterval"
                             style="width: 100%;"
                             class="mx-4"
                             :min="1"
@@ -408,29 +362,12 @@
                         />
                     </el-form-item>
                 </el-col>
-                <el-col :span="8">
-                    <el-form-item label="告警通知:">
-                         <el-select
-                        v-model="serzu"
-                        class="noBorSel"
-                        placeholder=""
-                        style="width: 100%;margin-left: 0%;"
-                        >
-                            <el-option
-                            v-for="item in optionsShuLei"
-                            :key="item.value"
-                            :label="item.label"
-                            :value="item.value"
-                            />
-                        </el-select>
-                    </el-form-item>
-                </el-col>
             </el-row>
             <el-form-item label="描述:" >
-                <el-input v-model="formZu.dcNote" style="width: 75%;" placeholder="" type="textarea" :row="2" resize="none"/>
+                <el-input v-model="formJi.description" style="width: 75%;" placeholder="" type="textarea" :row="2" resize="none"/>
             </el-form-item>
         </div>
-        <div v-if="formJi.executorInfo=='内置执行器'" style="margin-top: 4%;">
+        <!-- <div v-if="formJi.executorInfoTy=='内置执行器'" style="margin-top: 4%;">
             <el-form-item label="请求参数:" >
                 <el-input
                 style="width: 75%"
@@ -488,7 +425,7 @@
             </el-form-item>
             <el-form-item label="接口超时时间">
                 <el-input-number
-                    v-model="num"
+                    v-model="formJi.retryInterval"
                     style="width: 75%;"
                     class="mx-4"
                     :min="1"
@@ -554,7 +491,7 @@
                 <el-col :span="8">
                     <el-form-item label="间隔时长:">
                          <el-input-number
-                            v-model="num"
+                            v-model="formJi.retryInterval"
                             style="width: 100%;"
                             class="mx-4"
                             :min="1"
@@ -569,7 +506,7 @@
                 <el-col :span="8">
                     <el-form-item label="超时时间(秒):">
                         <el-input-number
-                            v-model="num"
+                            v-model="formJi.retryInterval"
                             style="width: 100%;"
                             class="mx-4"
                             :min="1"
@@ -582,7 +519,7 @@
                 <el-col :span="8">
                     <el-form-item label="最大重试次数:">
                          <el-input-number
-                            v-model="num"
+                            v-model="formJi.retryInterval"
                             style="width: 100%;"
                             class="mx-4"
                             :min="1"
@@ -597,7 +534,7 @@
                 <el-col :span="8">
                     <el-form-item label="重试间隔:">
                         <el-input-number
-                            v-model="num"
+                            v-model="formJi.retryInterval"
                             style="width: 100%;"
                             class="mx-4"
                             :min="1"
@@ -628,7 +565,7 @@
             <el-form-item label="描述:" >
                 <el-input v-model="formZu.dcNote" style="width: 75%;" placeholder="" type="textarea" :row="2" resize="none"/>
             </el-form-item>
-        </div>
+        </div> -->
         </el-form>
     <template #footer>
       <span class="dialog-footer">
@@ -642,30 +579,139 @@
       </span>
     </template>
   </el-dialog>
-  <el-dialog @close="clearFromTree" :title="titleTree" v-model="dialogVisibleTree" title="" width="30%" destroy-on-close :key="tableKey">
-    <el-form style="margin-left: 5%;margin-top: 2%;"  :model="formTree" class="demo-form-inline" ref="formRefTree" :rules="rulesTree">
-      <el-form-item label="名称:" prop="itemName" style="margin-left: -2%;">
-        <el-input v-model="formTree.itemName" style="width: 75%;" placeholder=""/>
-      </el-form-item>
-      <el-form-item label="父节点id:" prop="catePid" style="margin-left: -2%;">
-        <el-input v-model="formTree.catePid" style="width: 75%;" placeholder=""  resize="none"/>
-      </el-form-item>
-      <el-form-item label="排序:" prop="itemNo" style="margin-left: -2%;">
-        <el-input v-model="formTree.itemNo" style="width: 75%;" placeholder=""  resize="none"/>
-      </el-form-item>
-      <el-form-item label="备注:" prop="itemNotes" style=" ">
-        <el-input v-model="formTree.itemNotes" style="width: 75%;" placeholder=""  resize="none"/>
-      </el-form-item>
-    </el-form>
+  <el-dialog @close="clearFromTree"  v-model="dialogVisibleTree" title="" width="55%" destroy-on-close :key="tableKey">
+    <el-descriptions
+    class="margin-top"
+    :title="titleDe"
+    style="padding-top: 2%;"
+    :column="3"
+    :size="size"
+    border
+  >
+    <el-descriptions-item>
+      <template #label>
+        <div class="cell-item">
+          任务名称
+        </div>
+      </template>
+      {{formJi.jobName}}
+    </el-descriptions-item>
+    <el-descriptions-item>
+      <template #label>
+        <div class="cell-item">
+          组名称
+        </div>
+      </template>
+      {{formJi.groupName}}
+    </el-descriptions-item>
+    <el-descriptions-item>
+      <template #label>
+        <div class="cell-item">
+          负责人
+        </div>
+      </template>
+      {{formJi.ownerName}}
+    </el-descriptions-item>
+    <el-descriptions-item>
+      <template #label>
+        <div class="cell-item">
+          状态
+        </div>
+      </template>
+      <el-tag size="small">{{formJi.jobStatus}}</el-tag>
+    </el-descriptions-item>
+    <el-descriptions-item>
+      <template #label>
+        <div class="cell-item">
+          任务类型
+        </div>
+      </template>
+      {{formJi.taskType}}
+    </el-descriptions-item>
+    <el-descriptions-item>
+      <template #label>
+        <div class="cell-item">
+          执行器名称
+        </div>
+      </template>
+      {{formJi.executorInfo}} 
+    </el-descriptions-item>
+    <el-descriptions-item>
+      <template #label>
+        <div class="cell-item">
+          方法参数
+        </div>
+      </template>
+      {{formJi.argsStr}}
+    </el-descriptions-item>
+    <el-descriptions-item>
+      <template #label>
+        <div class="cell-item">
+          路由策略
+        </div>
+      </template>
+      {{formJi.routeKey}}
+    </el-descriptions-item>
+    <el-descriptions-item>
+      <template #label>
+        <div class="cell-item">
+          阻塞策略
+        </div>
+      </template>
+      {{formJi.blockStrategy}}
+    </el-descriptions-item>
+    <el-descriptions-item>
+      <template #label>
+        <div class="cell-item">
+          触发类型
+        </div>
+      </template>
+      {{formJi.triggerType}}
+    </el-descriptions-item>
+    <el-descriptions-item>
+      <template #label>
+        <div class="cell-item">
+          间隔时长
+        </div>
+      </template>
+      {{formJi.triggerInterval}}
+    </el-descriptions-item>
+    <el-descriptions-item>
+      <template #label>
+        <div class="cell-item">
+          超时时间(秒)
+        </div>
+      </template>
+      {{formJi.executorTimeout}}
+    </el-descriptions-item>
+    <el-descriptions-item>
+      <template #label>
+        <div class="cell-item">
+          最大重试次数
+        </div>
+      </template>
+      {{formJi.maxRetryTimes}}
+    </el-descriptions-item>
+    <el-descriptions-item>
+      <template #label>
+        <div class="cell-item">
+          重试间隔
+        </div>
+      </template>
+      {{formJi.retryInterval}}
+    </el-descriptions-item>
+    <el-descriptions-item>
+      <template #label>
+        <div class="cell-item">
+          描述:
+        </div>
+      </template>
+      {{formJi.description}}
+    </el-descriptions-item>
+  </el-descriptions>
     <template #footer>
       <span class="dialog-footer">
-        <el-button size="mini" @click="dialogVisible = false">取消</el-button>
-        <el-button v-if="isAdd" type="primary" @click="addTree" size="mini">
-          提交
-        </el-button>
-        <el-button v-if="!isAdd" type="primary" @click="saveEditTree" size="mini">
-          提交
-        </el-button>
+        <el-button size="mini" type="primary" @click="dialogVisibleTree = false">确定</el-button>
       </span>
     </template>
   </el-dialog>
@@ -674,8 +720,12 @@
 import { Search,RefreshRight,Plus,Download,Upload,Delete,Setting,Minus} from '@element-plus/icons-vue'
 import { reactive } from 'vue'
 import Codemirror from 'codemirror-editor-vue3';
-import { addDataCate,getCateTree,getCateDe,editCate,delCate,addDataItem,getItem,getItemDe,editItem,delItem} from "@/api/service/cate";
+import { snailList,addSnail,snailDe,snailEdit,delSnamil,snailSta,snailTri } from "@/api/service/timing";
 import { ref, onMounted, onUnmounted, nextTick } from 'vue';
+const groupName= ref('')
+const jobName= ref('')
+const jobStatus= ref('')
+const executorInfo= ref('')
 const { proxy } = getCurrentInstance();
 const data =  ref([])
 const title =  ref([])
@@ -691,6 +741,7 @@ const dialogVisibleTree = ref(false)
 const isAdd = ref(false)
 const isAddTa = ref(false)
 const treeId = ref('');
+const titleDe = ref('')
 const parTag = ref([])
 const optionsTaskType = ref([
   {
@@ -741,11 +792,12 @@ const showTablepane = ref({
     gx:true,
 })
 const formJi = ref({
-  name:'',
-  version:'',
-  enname:'',
-  devlang:'',
-  intro:'',
+  jobName:'',
+  groupName:'',
+  jobStatus:'',
+  taskType:'',
+  executorInfo:'',
+  executorInfoTy:'',
   type:'',
   mdContact:'',
   mdUnit:'',
@@ -767,10 +819,21 @@ const formJi = ref({
   mdInNote:'',
   mdOutNote:''
 });
+const selectedRows = ref([])
 const activeTabKey = ref(0)
 const rulesJi = reactive({
-  name: [{ required: true, message: '必填', trigger: 'blur' }],
-  enname: [{ required: true, message: '必填', trigger: 'blur' }],
+  jobName: [{ required: true, message: '必填', trigger: 'blur' }],
+  groupName: [{ required: true, message: '必填', trigger: 'blur' }],
+  taskType: [{ required: true, message: '必填', trigger: 'blur' }],
+  jobStatus: [{ required: true, message: '必填', trigger: 'blur' }],
+  executorInfo: [{ required: true, message: '必填', trigger: 'blur' }],
+  routeKey: [{ required: true, message: '可选', trigger: 'blur' }],
+  blockStrategy: [{ required: true, message: '必填', trigger: 'blur' }],
+  triggerInterval: [{ required: true, message: '必填', trigger: 'blur' }],
+  executorTimeout: [{ required: true, message: '必填', trigger: 'blur' }],
+  maxRetryTimes: [{ required: true, message: '必填', trigger: 'blur' }],
+  retryInterval: [{ required: true, message: '必填', trigger: 'blur' }],
+  triggerType: [{ required: true, message: '必填', trigger: 'blur' }],
 });
 const formRefJi = ref();
 const formZu = ref({
@@ -807,10 +870,100 @@ const formRefTree = ref();
 
 const dropdownVisible = ref(false);
 
+const handleSelectionChange = (selection) => {
+  selectedRows.value = selection;
+};
+function snaliTrigger(row){
+  var par = {
+    jobId:row.id,
+    taskType:row.taskType
+  }
+  snailTri(par).then(res=>{
+    if(res.code===200){
+      proxy.$modal.msgSuccess(res.msg);
+    }
+  })
+}
 function showCode(){
-    nextTick(() => {
-        cmRef.value?.refresh(); // 关键调用
-    });
+  Object.keys(rulesJi).forEach(key => {
+      delete rulesJi[key];
+  });
+    if(formJi.value.executorInfoTy==='自定义执行器'){
+      Object.assign(rulesJi, {
+        jobName: [{ required: true, message: '必填', trigger: 'blur' }],
+        groupName: [{ required: true, message: '必填', trigger: 'blur' }],
+        taskType: [{ required: true, message: '必填', trigger: 'blur' }],
+        jobStatus: [{ required: true, message: '必填', trigger: 'blur' }],
+        executorInfo: [{ required: true, message: '必填', trigger: 'blur' }],
+        routeKey: [{ required: true, message: '可选', trigger: 'blur' }],
+        blockStrategy: [{ required: true, message: '必填', trigger: 'blur' }],
+        triggerInterval: [{ required: true, message: '必填', trigger: 'blur' }],
+        executorTimeout: [{ required: true, message: '必填', trigger: 'blur' }],
+        maxRetryTimes: [{ required: true, message: '必填', trigger: 'blur' }],
+        retryInterval: [{ required: true, message: '必填', trigger: 'blur' }],
+        triggerType: [{ required: true, message: '必填', trigger: 'blur' }],
+      });
+    }
+    if(formJi.value.executorInfoTy==='内置执行器'){
+      Object.assign(rulesJi, {
+        jobName: [{ required: true, message: '必填', trigger: 'blur' }],
+        groupName: [{ required: true, message: '必填', trigger: 'blur' }],
+        taskType: [{ required: true, message: '必填', trigger: 'blur' }],
+        jobStatus: [{ required: true, message: '必填', trigger: 'blur' }],
+        executorInfo: [{ required: true, message: '必填', trigger: 'blur' }],
+        routeKey: [{ required: true, message: '可选', trigger: 'blur' }],
+        blockStrategy: [{ required: true, message: '必填', trigger: 'blur' }],
+        triggerInterval: [{ required: true, message: '必填', trigger: 'blur' }],
+        executorTimeout: [{ required: true, message: '必填', trigger: 'blur' }],
+        maxRetryTimes: [{ required: true, message: '必填', trigger: 'blur' }],
+        retryInterval: [{ required: true, message: '必填', trigger: 'blur' }],
+        triggerType: [{ required: true, message: '必填', trigger: 'blur' }],
+      });
+    }
+}
+function delAll(){
+  var parDel = ''
+  selectedRows.value.forEach(item=>{
+    parDel = parDel + item.id + ','
+  })
+  parDel = parDel.slice(0, -1)
+  proxy.$modal.confirm('是否确认删除?').then(function () {
+    var par = {
+      jobIds:parDel
+    }
+    return delSnamil(par);
+  }).then(() => {
+    getTable();
+    proxy.$modal.msgSuccess("删除成功");
+  }).catch(() => {});
+}
+function showDe(row){
+  dialogVisibleTree.value = true
+  var par = {
+    jobId:row.id
+  }
+  snailDe(par).then(res=>{
+    formJi.value = res.data
+    if(formJi.value.jobStatus===0){
+      formJi.value.jobStatus = '启用'
+    }
+    if(formJi.value.jobStatus===1){
+      formJi.value.jobStatus = '关闭'
+    }
+  })
+}
+async function changejobStatus(row){
+  var par = {
+    jobId:row.id,
+    status:row.jobStatus===true?1:0
+  }
+  await snailSta(par).then(res=>{
+    formJi.value = res
+    if(res.code===200){
+      proxy.$modal.msgSuccess("修改成功");
+    }
+  })
+
 }
 const handleCheckboxClick = () => {
   // 1. 执行 checkbox 的切换逻辑(v-model 自动处理)
@@ -824,25 +977,35 @@ function delTag(index){
     parTag.value.splice(index,1)
 }
 function clearForm(){
-  formZu.value = {
-    itemName:'',
-    itemTp:'',
-    itemEn:'',
-    itemTp:'',
-    itemDataTp:'',
-    itemDefaultVal:'',
-    itemUnit:'',
-    itemNotes:'',
+  formJi.value = {
+    
   }
 }
+function formatTimestamp(ms) {
+  const date = new Date(ms);
+  const year = date.getFullYear();
+  const month = String(date.getMonth() + 1).padStart(2, '0'); // 补零
+  const day = String(date.getDate()).padStart(2, '0'); // 补零
+  return `${year}年${month}月${day}日`;
+}
 function getTable(){
   var par = {
-    pageNum:currentPage.value,
-    pageSize:15,
-    cateId:''
+    groupName:groupName.value,
+    executorInfo:executorInfo.value,
+    jobName:jobName.value,
+    jobStatus:jobStatus.value
   }
-  getItem(par).then(res=>{
+  snailList(par).then(res=>{
     tableData.value = res.rows
+    tableData.value.forEach(item=>{
+      if(item.jobStatus===0){
+        item.jobStatus = false
+      }
+      if(item.jobStatus===1){
+        item.jobStatus = true
+      }
+      item.nextTriggerAt = formatTimestamp(item.nextTriggerAt)
+    })
     total.value = res.total
   })
 }
@@ -855,15 +1018,13 @@ function showEdit(row){
   isAddTa.value = false
   title.value = '编辑'
   dialogVisible.value = true
-  getItemDe(row.dataId).then(res=>{
-    formZu.value = res.data
+  var par = {
+    jobId:row.id
+  }
+  snailDe(par).then(res=>{
+    formJi.value = res.data
   })
 }
-function showAddTree(){
-  isAdd.value = true
-  titleTree.value = '新增节点'
-  dialogVisibleTree.value = true
-}
 function clearFromTree(){
   formTree.value = {
     itemName:'',
@@ -872,24 +1033,27 @@ function clearFromTree(){
     itemNotes:''
   }
 }
-function getTree(){
-  getCateTree().then(res=>{
-    data.value = res.data
-  })
-}
 function addTa(){
-  formRefZu.value.validate(async (valid) => {
-    await addDataItem(formZu.value).then(res=>{
-      if(res.code===200){
-        proxy.$modal.msgSuccess("新增成功");
-        getTable()
-        dialogVisible.value = false
+  formRefJi.value.validate(async (valid) => {
+    if(valid){
+      if(formJi.value.argsStr){
+        formJi.value.argsStr = JSON.parse(formJi.value.argsStr)
       }
-    })
+      await addSnail(formJi.value).then(res=>{
+        if(res.code===200){
+          proxy.$modal.msgSuccess("新增成功");
+          getTable()
+          dialogVisible.value = false
+        }
+      })
+    }
   });
 }
 function saveEditTa(){
-  editItem(formZu.value).then(res=>{
+  if(formJi.value.argsStr){
+    formJi.value.argsStr = JSON.parse(formJi.value.argsStr)
+  }
+  snailEdit(formJi.value).then(res=>{
     if(res.code===200){
       proxy.$modal.msgSuccess("修改成功");
       dialogVisible.value = false
@@ -899,56 +1063,16 @@ function saveEditTa(){
 }
 function delRow(row) {
   proxy.$modal.confirm('是否确认删除?').then(function () {
-    return delItem(row.dataId);
-  }).then(() => {
-    getTable();
-    proxy.$modal.msgSuccess("删除成功");
-  }).catch(() => {});
-};
-async function addTree(){
-  formRefTree.value.validate(async (valid) => {
-    await addDataCate(formTree.value).then(res=>{
-      if(res.code===200){
-        proxy.$modal.msgSuccess("新增成功");
-        getTree()
-        dialogVisibleTree.value = false
-      }
-    })
-  });
-}
-function saveEditTree(){
-  editCate(formTree.value).then(res=>{
-    if(res.code===200){
-      proxy.$modal.msgSuccess("修改成功");
-      dialogVisibleTree.value = false
-      getTree()
+    var par = {
+      jobIds:row.id
     }
-  })
-}
-function handleNodeClick(node, data){
-  treeId.value = data.id
-  getTable()
-}
-function delTree(node, data) {
-  proxy.$modal.confirm('是否确认删除?').then(function () {
-    return delCate(data.id);
+    return delSnamil(par);
   }).then(() => {
-    getTree();
+    getTable();
     proxy.$modal.msgSuccess("删除成功");
   }).catch(() => {});
 };
-function editTree(node, data){
-  console.log(data)
-  titleTree.value = '编辑'
-  isAdd.value = false
-  dialogVisibleTree.value = true
-  getCateDe(data.id).then(res=>{
-    formTree.value = res.data
-  })
-  console.log(node, data)
-}
 onMounted(() => {
-  getTree()
   getTable()
 });