From fc365c426e431a73d116e5d51deaec667f4864de Mon Sep 17 00:00:00 2001
From: zhaowenyu <35589726@qq.com>
Date: Mon, 20 Oct 2025 17:11:48 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev' into dev

---
 ard-work/src/main/java/com/ard/work/component/forest/MyAddressSource.java                    |   10 
 ard-work/src/main/java/com/ard/work/component/websocket/handler/UavAllManager.java           |    6 
 ard-work/src/main/java/com/ard/work/domain/receiver/BoxStreamUrlReceiver.java                |    2 
 ard-work/src/main/java/com/ard/work/service/impl/TyServiceImpl.java                          |   49 +
 ard-route/src/main/java/com/ard/route/service/IArdRouteFolderService.java                    |   63 ++
 ard-work/src/main/java/com/ard/work/domain/receiver/TyHttpCommonReceiver.java                |    2 
 ard-work/src/main/java/com/ard/work/domain/dto/state/UavState.java                           |    6 
 ard-work/src/main/java/com/ard/work/component/netty/TyTcpClientManager.java                  |    2 
 ard-route/src/main/java/com/ard/route/service/IArdRouteFileService.java                      |   62 ++
 ard-work/src/main/resources/mapper/ArdDroneInfoMapper.xml                                    |    2 
 ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteFileController.java             |  111 ++++
 ard-work/src/main/java/com/ard/work/component/websocket/handler/BaseSubscriptionManager.java |    9 
 ard-admin/src/main/java/com/ard/web/controller/work/UavBaseController.java                   |    6 
 ard-admin/src/main/java/com/ard/web/core/config/SwaggerConfig.java                           |  159 +----
 ard-work/src/main/java/com/ard/work/domain/cache/UavStateCache.java                          |   24 
 ard-route/src/main/java/com/ard/route/mapper/ArdRouteFolderMapper.java                       |   62 ++
 ard-route/src/main/resources/mapper/ArdRouteFileMapper.xml                                   |  108 ++++
 ard-work/src/main/java/com/ard/work/domain/dto/signal/SignalInfo.java                        |    2 
 ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteFolderController.java           |  120 +++++
 ard-work/src/main/java/com/ard/work/component/websocket/handler/UavTelemetryManager.java     |    2 
 ard-work/src/main/java/com/ard/work/domain/dto/telemetry/TelemetryData.java                  |    6 
 ard-route/src/main/java/com/ard/route/service/impl/ArdRouteFolderServiceImpl.java            |  131 +++++
 ard-route/src/main/java/com/ard/route/domain/ArdRouteFile.java                               |   45 +
 ard-route/src/main/java/com/ard/route/service/impl/ArdRouteFileServiceImpl.java              |   97 ++++
 ard-admin/src/main/java/com/ard/web/core/config/ApiGroup.java                                |   41 +
 ard-route/src/main/java/com/ard/route/domain/ArdRouteFolder.java                             |   29 +
 ard-work/src/main/java/com/ard/work/domain/cache/UavTelemetryDataCache.java                  |   24 
 ard-work/src/main/java/com/ard/work/domain/cache/UavSignalInfoCache.java                     |   24 
 ard-route/src/main/java/com/ard/route/mapper/ArdRouteFileMapper.java                         |   69 ++
 ard-work/src/main/java/com/ard/work/component/websocket/handler/UavStateManager.java         |    2 
 ard-work/src/main/java/com/ard/work/component/websocket/handler/UavStreamManager.java        |   19 
 ard-work/src/main/java/com/ard/work/component/websocket/handler/TyMessageHandler.java        |    4 
 ard-route/src/main/resources/mapper/ArdRouteFolderMapper.xml                                 |   84 +++
 ard-work/src/main/java/com/ard/work/component/netty/cache/TyTcpServerCache.java              |    2 
 ard-work/src/main/java/com/ard/work/component/websocket/handler/UavControlManager.java       |    7 
 ard-work/src/main/java/com/ard/work/aspect/UavControlAspect.java                             |    2 
 ard-work/src/main/java/com/ard/work/component/netty/handler/ClientHandler.java               |    2 
 ard-work/src/main/java/com/ard/work/component/websocket/handler/UavSignalManager.java        |    2 
 ard-work/src/main/java/com/ard/work/service/ITyService.java                                  |    4 
 39 files changed, 1,193 insertions(+), 208 deletions(-)

diff --git a/ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteFileController.java b/ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteFileController.java
new file mode 100644
index 0000000..3fa81b3
--- /dev/null
+++ b/ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteFileController.java
@@ -0,0 +1,111 @@
+package com.ard.web.controller.route;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+
+import com.ard.common.annotation.Log;
+import com.ard.common.core.controller.BaseController;
+import com.ard.common.core.domain.AjaxResult;
+import com.ard.common.core.page.TableDataInfo;
+import com.ard.common.enums.BusinessType;
+import com.ard.common.utils.poi.ExcelUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.ard.route.domain.ArdRouteFile;
+import com.ard.route.service.IArdRouteFileService;
+
+/**
+ * 文件Controller
+ * 
+ * @author xia
+ * @date 2025-10-18
+ */
+@Api(tags = "文件")
+@RestController
+@RequestMapping("/file")
+public class ArdRouteFileController extends BaseController {
+
+    @Autowired
+    private IArdRouteFileService ardRouteFileService;
+
+    /**
+     * 查询文件列表
+     */
+    @ApiOperation("查询文件列表")
+    @PreAuthorize("@ss.hasPermi('route:file:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(ArdRouteFile ardRouteFile) {
+        startPage();
+        List<ArdRouteFile> list = ardRouteFileService.selectArdRouteFileList(ardRouteFile);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出文件列表
+     */
+    @ApiOperation("导出文件列表")
+    @PreAuthorize("@ss.hasPermi('route:file:export')")
+    @Log(title = "文件", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, ArdRouteFile ardRouteFile) {
+        List<ArdRouteFile> list = ardRouteFileService.selectArdRouteFileList(ardRouteFile);
+        ExcelUtil<ArdRouteFile> util = new ExcelUtil<ArdRouteFile>(ArdRouteFile.class);
+        util.exportExcel(response, list, "文件数据");
+    }
+
+    /**
+     * 获取文件详细信息
+     */
+    @ApiOperation("获取文件详细信息")
+    @PreAuthorize("@ss.hasPermi('route:file:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") String id) {
+        return success(ardRouteFileService.selectArdRouteFileById(id));
+    }
+
+    /**
+     * 新增文件
+     */
+    @ApiOperation("新增文件")
+    @PreAuthorize("@ss.hasPermi('route:file:add')")
+    @Log(title = "文件", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody ArdRouteFile ardRouteFile) {
+        ardRouteFile.setCreateBy(getUsername());
+        return toAjax(ardRouteFileService.insertArdRouteFile(ardRouteFile));
+    }
+
+    /**
+     * 修改文件
+     */
+    @ApiOperation("修改文件")
+    @PreAuthorize("@ss.hasPermi('route:file:edit')")
+    @Log(title = "文件", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody ArdRouteFile ardRouteFile) {
+        ardRouteFile.setUpdateBy(getUsername());
+        return toAjax(ardRouteFileService.updateArdRouteFile(ardRouteFile));
+    }
+
+    /**
+     * 删除文件
+     */
+    @ApiOperation("删除文件")
+    @PreAuthorize("@ss.hasPermi('route:file:remove')")
+    @Log(title = "文件", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable String[] ids) {
+        return toAjax(ardRouteFileService.deleteArdRouteFileByIds(ids));
+    }
+
+}
diff --git a/ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteFolderController.java b/ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteFolderController.java
new file mode 100644
index 0000000..f60b012
--- /dev/null
+++ b/ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteFolderController.java
@@ -0,0 +1,120 @@
+package com.ard.web.controller.route;
+
+import java.util.List;
+import java.util.Map;
+import javax.servlet.http.HttpServletResponse;
+
+import com.ard.common.annotation.Log;
+import com.ard.common.core.controller.BaseController;
+import com.ard.common.core.domain.AjaxResult;
+import com.ard.common.core.page.TableDataInfo;
+import com.ard.common.enums.BusinessType;
+import com.ard.common.utils.poi.ExcelUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.ard.route.domain.ArdRouteFolder;
+import com.ard.route.service.IArdRouteFolderService;
+
+/**
+ * 文件夹Controller
+ * 
+ * @author xia
+ * @date 2025-10-18
+ */
+@Api(tags = "文件夹")
+@RestController
+@RequestMapping("/folder")
+public class ArdRouteFolderController extends BaseController {
+
+    @Autowired
+    private IArdRouteFolderService ardRouteFolderService;
+
+    /**
+     * 查询文件夹列表
+     */
+    @ApiOperation("查询文件夹列表")
+    @PreAuthorize("@ss.hasPermi('route:folder:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(ArdRouteFolder ardRouteFolder) {
+        startPage();
+        List<ArdRouteFolder> list = ardRouteFolderService.selectArdRouteFolderList(ardRouteFolder);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出文件夹列表
+     */
+    @ApiOperation("导出文件夹列表")
+    @PreAuthorize("@ss.hasPermi('route:folder:export')")
+    @Log(title = "文件夹", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, ArdRouteFolder ardRouteFolder) {
+        List<ArdRouteFolder> list = ardRouteFolderService.selectArdRouteFolderList(ardRouteFolder);
+        ExcelUtil<ArdRouteFolder> util = new ExcelUtil<ArdRouteFolder>(ArdRouteFolder.class);
+        util.exportExcel(response, list, "文件夹数据");
+    }
+
+    /**
+     * 获取文件夹详细信息
+     */
+    @ApiOperation("获取文件夹详细信息")
+    @PreAuthorize("@ss.hasPermi('route:folder:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") String id) {
+        return success(ardRouteFolderService.selectArdRouteFolderById(id));
+    }
+
+    /**
+     * 新增文件夹
+     */
+    @ApiOperation("新增文件夹")
+    @PreAuthorize("@ss.hasPermi('route:folder:add')")
+    @Log(title = "文件夹", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody ArdRouteFolder ardRouteFolder) {
+        ardRouteFolder.setCreateBy(getUsername());
+        return toAjax(ardRouteFolderService.insertArdRouteFolder(ardRouteFolder));
+    }
+
+    /**
+     * 修改文件夹
+     */
+    @ApiOperation("修改文件夹")
+    @PreAuthorize("@ss.hasPermi('route:folder:edit')")
+    @Log(title = "文件夹", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody ArdRouteFolder ardRouteFolder) {
+        ardRouteFolder.setUpdateBy(getUsername());
+        return toAjax(ardRouteFolderService.updateArdRouteFolder(ardRouteFolder));
+    }
+
+    /**
+     * 删除文件夹
+     */
+    @ApiOperation("删除文件夹")
+    @PreAuthorize("@ss.hasPermi('route:folder:remove')")
+    @Log(title = "文件夹", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable String[] ids) {
+        try {
+            Map<String, Integer> result = ardRouteFolderService.deleteArdRouteFolderByIds(ids);
+            if (!result.isEmpty()) {
+                return AjaxResult.success("删除成功.文件夹删除" + result.get("folder") + "文件删除" + result.get("file"));
+            } else {
+                return AjaxResult.success("没有删除文件夹信息。");
+            }
+        } catch(Exception e){
+            return AjaxResult.error(e.getMessage());
+        }
+    }
+}
diff --git a/ard-admin/src/main/java/com/ard/web/controller/work/UavBaseController.java b/ard-admin/src/main/java/com/ard/web/controller/work/UavBaseController.java
index 165711a..243651c 100644
--- a/ard-admin/src/main/java/com/ard/web/controller/work/UavBaseController.java
+++ b/ard-admin/src/main/java/com/ard/web/controller/work/UavBaseController.java
@@ -36,7 +36,7 @@
     @Resource
     private ITyService tyService;
 
-    @ApiOperation("获取六合token信息")
+    @ApiOperation("获取边缘服务器token信息")
     @ApiOperationSupport(order = 1)
     @GetMapping("/getToken/{serverId}")
     public AjaxResult getToken(@PathVariable("serverId") String serverId) {
@@ -72,7 +72,7 @@
 
     @ApiOperation("获取直播地址")
     @ApiOperationSupport(order = 6)
-    @GetMapping("/getBoxList/{boxSn}")
+    @GetMapping("/getBoxLiveUrl/{boxSn}")
     public AjaxResult getBoxLiveUrl(@PathVariable("boxSn") String boxSn) {
         BoxStreamUrlReceiver boxLiveUrl = tyService.getBoxLiveUrl(boxSn);
         return AjaxResult.success(boxLiveUrl);
@@ -86,7 +86,7 @@
         return AjaxResult.success(state);
     }
 
-    @ApiOperation("根据[服务器id]获取六合盒子列表")
+    @ApiOperation("根据[服务器id]获取边缘服务器盒子列表")
     @ApiOperationSupport(order = 8)
     @GetMapping("/getBoxSnToList/{id}")
     public TableDataInfo getBoxSnToList(@PathVariable("id") String id) {
diff --git a/ard-admin/src/main/java/com/ard/web/core/config/ApiGroup.java b/ard-admin/src/main/java/com/ard/web/core/config/ApiGroup.java
new file mode 100644
index 0000000..4882b1a
--- /dev/null
+++ b/ard-admin/src/main/java/com/ard/web/core/config/ApiGroup.java
@@ -0,0 +1,41 @@
+package com.ard.web.core.config;
+
+/**
+ * API分组配置枚举
+ */
+public enum ApiGroup {
+
+    SYSTEM("系统接口", "com.ard.web.controller.system", "系统接口"),
+    DRONE("无人机接口", "com.ard.web.controller.work", "无人机管理接口"),
+    SAMPLE("机场接口", "com.ard.web.controller.sample", "机场管理接口"),
+    MEDIA_MTX("流媒体接口", "com.ard.web.controller.vtdu", "流媒体管理接口"),
+    DEVICE("设备接口", "com.ard.web.controller.device", "设备管理接口"),
+    DATA("数据接口", "com.ard.web.controller.data", "数据管理接口"),
+    STORAGE("存储接口", "com.ard.web.controller.storage", "存储管理接口"),
+    ROUTE("航线接口", "com.ard.web.controller.route", "航线管理接口");
+
+    // 分组名
+    private final String groupName;
+    // 包路径
+    private final String packagePath;
+    // API文档标题
+    private final String title;
+
+    ApiGroup(String groupName, String packagePath, String title) {
+        this.groupName = groupName;
+        this.packagePath = packagePath;
+        this.title = title;
+    }
+
+    public String getGroupName() {
+        return groupName;
+    }
+
+    public String getPackagePath() {
+        return packagePath;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+}
diff --git a/ard-admin/src/main/java/com/ard/web/core/config/SwaggerConfig.java b/ard-admin/src/main/java/com/ard/web/core/config/SwaggerConfig.java
index 71ef983..8ff77a1 100644
--- a/ard-admin/src/main/java/com/ard/web/core/config/SwaggerConfig.java
+++ b/ard-admin/src/main/java/com/ard/web/core/config/SwaggerConfig.java
@@ -27,151 +27,73 @@
  * @author ruoyi
  */
 @Configuration
-public class SwaggerConfig
-{
+public class SwaggerConfig {
+
     /** 系统基础配置 */
     @Autowired
     private UavConfig uavConfig;
 
-    /**
-     * 创建API
-     */
+    private Docket createApiDocket(ApiGroup apiGroup) {
+        return new Docket(DocumentationType.SWAGGER_2)
+                .enable(true)
+                .groupName(apiGroup.getGroupName())
+                .apiInfo(apiInfo(apiGroup.getTitle()))
+                .select()
+                .apis(requestHandler ->
+                        requestHandler.declaringClass().getPackage().getName()
+                                .startsWith(apiGroup.getPackagePath()) &&
+                                requestHandler.isAnnotatedWith(io.swagger.annotations.ApiOperation.class)
+                )
+                .paths(PathSelectors.any())
+                .build()
+                .securitySchemes(securitySchemes())
+                .securityContexts(securityContexts());
+    }
+
     @Bean
     public Docket systemApi() {
-        return new Docket(DocumentationType.SWAGGER_2)
-                .enable(true)
-                .groupName("系统接口")   // 分组名
-                .apiInfo(apiInfo("系统接口"))
-                .select()
-                // 扫描指定包下,但只扫描加了 @ApiOperation 注解的方法
-                .apis(requestHandler ->
-                        requestHandler.declaringClass().getPackage().getName().startsWith("com.ard.web.controller.system") &&
-                                requestHandler.isAnnotatedWith(io.swagger.annotations.ApiOperation.class)
-                )
-                .paths(PathSelectors.any())
-                .build()
-                /* 设置安全模式,swagger可以设置访问token */
-                .securitySchemes(securitySchemes())
-                .securityContexts(securityContexts());
+        return createApiDocket(ApiGroup.SYSTEM);
     }
+
     @Bean
     public Docket droneApi() {
-        return new Docket(DocumentationType.SWAGGER_2)
-                .enable(true)
-                .groupName("无人机接口")   // 分组名
-                .apiInfo(apiInfo("无人机管理接口"))
-                .select()
-                // 扫描指定包下,但只扫描加了 @ApiOperation 注解的方法
-                .apis(requestHandler ->
-                        requestHandler.declaringClass().getPackage().getName().startsWith("com.ard.web.controller.work") &&
-                                requestHandler.isAnnotatedWith(io.swagger.annotations.ApiOperation.class)
-                )
-                .paths(PathSelectors.any())
-                .build()
-                /* 设置安全模式,swagger可以设置访问token */
-                .securitySchemes(securitySchemes())
-                .securityContexts(securityContexts());
+        return createApiDocket(ApiGroup.DRONE);
     }
+
     @Bean
     public Docket sampleApi() {
-        return new Docket(DocumentationType.SWAGGER_2)
-                .enable(true)
-                .groupName("机场接口")   // 分组名
-                .apiInfo(apiInfo("机场管理接口"))
-                .select()
-                // 扫描指定包下,但只扫描加了 @ApiOperation 注解的方法
-                .apis(requestHandler ->
-                        requestHandler.declaringClass().getPackage().getName().startsWith("com.ard.web.controller" +
-                                ".sample") &&
-                                requestHandler.isAnnotatedWith(io.swagger.annotations.ApiOperation.class)
-                )
-                .paths(PathSelectors.any())
-                .build()
-                /* 设置安全模式,swagger可以设置访问token */
-                .securitySchemes(securitySchemes())
-                .securityContexts(securityContexts());
+        return createApiDocket(ApiGroup.SAMPLE);
     }
+
     @Bean
     public Docket mediaMTXApi() {
-        return new Docket(DocumentationType.SWAGGER_2)
-                .enable(true)
-                .groupName("流媒体接口")   // 分组名
-                .apiInfo(apiInfo("流媒体管理接口"))
-                .select()
-                // 扫描指定包下,但只扫描加了 @ApiOperation 注解的方法
-                .apis(requestHandler ->
-                        requestHandler.declaringClass().getPackage().getName().startsWith("com.ard.web.controller" +
-                                ".vtdu") &&
-                                requestHandler.isAnnotatedWith(io.swagger.annotations.ApiOperation.class)
-                )
-                .paths(PathSelectors.any())
-                .build()
-                /* 设置安全模式,swagger可以设置访问token */
-                .securitySchemes(securitySchemes())
-                .securityContexts(securityContexts());
+        return createApiDocket(ApiGroup.MEDIA_MTX);
     }
+
     @Bean
     public Docket deviceApi() {
-        return new Docket(DocumentationType.SWAGGER_2)
-                .enable(true)
-                .groupName("设备接口")   // 分组名
-                .apiInfo(apiInfo("设备管理接口"))
-                .select()
-                // 扫描指定包下,但只扫描加了 @ApiOperation 注解的方法
-                .apis(requestHandler ->
-                        requestHandler.declaringClass().getPackage().getName().startsWith("com.ard.web.controller" +
-                                ".device") &&
-                                requestHandler.isAnnotatedWith(io.swagger.annotations.ApiOperation.class)
-                )
-                .paths(PathSelectors.any())
-                .build()
-                /* 设置安全模式,swagger可以设置访问token */
-                .securitySchemes(securitySchemes())
-                .securityContexts(securityContexts());
+        return createApiDocket(ApiGroup.DEVICE);
     }
+
     @Bean
     public Docket dataApi() {
-        return new Docket(DocumentationType.SWAGGER_2)
-                .enable(true)
-                .groupName("数据接口")   // 分组名
-                .apiInfo(apiInfo("数据管理接口"))
-                .select()
-                // 扫描指定包下,但只扫描加了 @ApiOperation 注解的方法
-                .apis(requestHandler ->
-                        requestHandler.declaringClass().getPackage().getName().startsWith("com.ard.web.controller" +
-                                ".data") &&
-                                requestHandler.isAnnotatedWith(io.swagger.annotations.ApiOperation.class)
-                )
-                .paths(PathSelectors.any())
-                .build()
-                /* 设置安全模式,swagger可以设置访问token */
-                .securitySchemes(securitySchemes())
-                .securityContexts(securityContexts());
+        return createApiDocket(ApiGroup.DATA);
     }
+
     @Bean
     public Docket storageApi() {
-        return new Docket(DocumentationType.SWAGGER_2)
-                .enable(true)
-                .groupName("存储接口")   // 分组名
-                .apiInfo(apiInfo("存储管理接口"))
-                .select()
-                // 扫描指定包下,但只扫描加了 @ApiOperation 注解的方法
-                .apis(requestHandler ->
-                        requestHandler.declaringClass().getPackage().getName().startsWith("com.ard.web.controller" +
-                                ".storage") &&
-                                requestHandler.isAnnotatedWith(io.swagger.annotations.ApiOperation.class)
-                )
-                .paths(PathSelectors.any())
-                .build()
-                /* 设置安全模式,swagger可以设置访问token */
-                .securitySchemes(securitySchemes())
-                .securityContexts(securityContexts());
+        return createApiDocket(ApiGroup.STORAGE);
     }
+
+    @Bean
+    public Docket routeApi() {
+        return createApiDocket(ApiGroup.ROUTE);
+    }
+
     /**
      * 安全模式,这里指定token通过Authorization头请求头传递
      */
-    private List<SecurityScheme> securitySchemes()
-    {
+    private List<SecurityScheme> securitySchemes() {
         List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
         apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue()));
         return apiKeyList;
@@ -207,8 +129,7 @@
     /**
      * 添加摘要信息
      */
-    private ApiInfo apiInfo()
-    {
+    private ApiInfo apiInfo() {
         // 用ApiInfoBuilder进行定制
         return new ApiInfoBuilder()
                 // 设置标题
diff --git a/ard-route/src/main/java/com/ard/route/domain/ArdRouteFile.java b/ard-route/src/main/java/com/ard/route/domain/ArdRouteFile.java
new file mode 100644
index 0000000..7c86914
--- /dev/null
+++ b/ard-route/src/main/java/com/ard/route/domain/ArdRouteFile.java
@@ -0,0 +1,45 @@
+package com.ard.route.domain;
+
+import java.util.Date;
+import java.util.List;
+
+import com.ard.common.annotation.Excel;
+import com.ard.common.core.domain.BaseEntity;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+/**
+ * 文件对象 ard_route_file
+ * 
+ * @author xia
+ * @date 2025-10-18
+ */
+@Data
+public class ArdRouteFile extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    /** ID */
+    private String id;
+
+    /** 文件名称 */
+    @Excel(name = "文件名称")
+    private String name;
+
+    /** 所属文件夹ID */
+    @Excel(name = "所属文件夹ID")
+    private String folderId;
+
+    /** 文件类型 */
+    @Excel(name = "文件类型")
+    private String fileType;
+
+    /** 文件大小(字节) */
+    @Excel(name = "文件大小(字节)")
+    private Long fileSize;
+
+    /** 文件存储路径 */
+    @Excel(name = "文件存储路径")
+    private String filePath;
+
+}
diff --git a/ard-route/src/main/java/com/ard/route/domain/ArdRouteFolder.java b/ard-route/src/main/java/com/ard/route/domain/ArdRouteFolder.java
new file mode 100644
index 0000000..f3757d7
--- /dev/null
+++ b/ard-route/src/main/java/com/ard/route/domain/ArdRouteFolder.java
@@ -0,0 +1,29 @@
+package com.ard.route.domain;
+
+import java.util.List;
+
+import com.ard.common.annotation.Excel;
+import com.ard.common.core.domain.BaseEntity;
+import lombok.Data;
+
+/**
+ * 文件夹对象 ard_route_folder
+ * 
+ * @author xia
+ * @date 2025-10-18
+ */
+@Data
+public class ArdRouteFolder extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    /** ID */
+    private String id;
+
+    /** 文件夹名称 */
+    @Excel(name = "文件夹名称")
+    private String fileName;
+
+    private List<ArdRouteFile> ardRouteFileLs;
+
+}
diff --git a/ard-route/src/main/java/com/ard/route/mapper/ArdRouteFileMapper.java b/ard-route/src/main/java/com/ard/route/mapper/ArdRouteFileMapper.java
new file mode 100644
index 0000000..bc965b2
--- /dev/null
+++ b/ard-route/src/main/java/com/ard/route/mapper/ArdRouteFileMapper.java
@@ -0,0 +1,69 @@
+package com.ard.route.mapper;
+
+import java.util.List;
+import com.ard.route.domain.ArdRouteFile;
+
+/**
+ * 文件Mapper接口
+ * 
+ * @author xia
+ * @date 2025-10-18
+ */
+public interface ArdRouteFileMapper {
+
+    /**
+     * 查询文件
+     * 
+     * @param id 文件主键
+     * @return 文件
+     */
+    public ArdRouteFile selectArdRouteFileById(String id);
+
+    /**
+     * 查询文件列表
+     * 
+     * @param ardRouteFile 文件
+     * @return 文件集合
+     */
+    public List<ArdRouteFile> selectArdRouteFileList(ArdRouteFile ardRouteFile);
+
+    /**
+     * 新增文件
+     * 
+     * @param ardRouteFile 文件
+     * @return 结果
+     */
+    public int insertArdRouteFile(ArdRouteFile ardRouteFile);
+
+    /**
+     * 修改文件
+     * 
+     * @param ardRouteFile 文件
+     * @return 结果
+     */
+    public int updateArdRouteFile(ArdRouteFile ardRouteFile);
+
+    /**
+     * 删除文件
+     * 
+     * @param id 文件主键
+     * @return 结果
+     */
+    public int deleteArdRouteFileById(String id);
+
+    /**
+     * 批量删除文件
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteArdRouteFileByIds(String[] ids);
+
+    /**
+     * 根据所属文件夹ID,删除文件
+     *
+     * @param folderId 所属文件夹ID
+     * @return 结果
+     */
+    public int deleteArdRouteFileByFolderId(String folderId);
+}
diff --git a/ard-route/src/main/java/com/ard/route/mapper/ArdRouteFolderMapper.java b/ard-route/src/main/java/com/ard/route/mapper/ArdRouteFolderMapper.java
new file mode 100644
index 0000000..c4df0f7
--- /dev/null
+++ b/ard-route/src/main/java/com/ard/route/mapper/ArdRouteFolderMapper.java
@@ -0,0 +1,62 @@
+package com.ard.route.mapper;
+
+import java.util.List;
+import com.ard.route.domain.ArdRouteFolder;
+
+/**
+ * 文件夹Mapper接口
+ * 
+ * @author xia
+ * @date 2025-10-18
+ */
+public interface ArdRouteFolderMapper {
+
+    /**
+     * 查询文件夹
+     * 
+     * @param id 文件夹主键
+     * @return 文件夹
+     */
+    public ArdRouteFolder selectArdRouteFolderById(String id);
+
+    /**
+     * 查询文件夹列表
+     * 
+     * @param ardRouteFolder 文件夹
+     * @return 文件夹集合
+     */
+    public List<ArdRouteFolder> selectArdRouteFolderList(ArdRouteFolder ardRouteFolder);
+
+    /**
+     * 新增文件夹
+     * 
+     * @param ardRouteFolder 文件夹
+     * @return 结果
+     */
+    public int insertArdRouteFolder(ArdRouteFolder ardRouteFolder);
+
+    /**
+     * 修改文件夹
+     * 
+     * @param ardRouteFolder 文件夹
+     * @return 结果
+     */
+    public int updateArdRouteFolder(ArdRouteFolder ardRouteFolder);
+
+    /**
+     * 删除文件夹
+     * 
+     * @param id 文件夹主键
+     * @return 结果
+     */
+    public int deleteArdRouteFolderById(String id);
+
+    /**
+     * 批量删除文件夹
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteArdRouteFolderByIds(String[] ids);
+
+}
diff --git a/ard-route/src/main/java/com/ard/route/service/IArdRouteFileService.java b/ard-route/src/main/java/com/ard/route/service/IArdRouteFileService.java
new file mode 100644
index 0000000..ce3185b
--- /dev/null
+++ b/ard-route/src/main/java/com/ard/route/service/IArdRouteFileService.java
@@ -0,0 +1,62 @@
+package com.ard.route.service;
+
+import java.util.List;
+import com.ard.route.domain.ArdRouteFile;
+
+/**
+ * 文件Service接口
+ * 
+ * @author xia
+ * @date 2025-10-18
+ */
+public interface IArdRouteFileService {
+
+    /**
+     * 查询文件
+     * 
+     * @param id 文件主键
+     * @return 文件
+     */
+    public ArdRouteFile selectArdRouteFileById(String id);
+
+    /**
+     * 查询文件列表
+     * 
+     * @param ardRouteFile 文件
+     * @return 文件集合
+     */
+    public List<ArdRouteFile> selectArdRouteFileList(ArdRouteFile ardRouteFile);
+
+    /**
+     * 新增文件
+     * 
+     * @param ardRouteFile 文件
+     * @return 结果
+     */
+    public int insertArdRouteFile(ArdRouteFile ardRouteFile);
+
+    /**
+     * 修改文件
+     * 
+     * @param ardRouteFile 文件
+     * @return 结果
+     */
+    public int updateArdRouteFile(ArdRouteFile ardRouteFile);
+
+    /**
+     * 批量删除文件
+     * 
+     * @param ids 需要删除的文件主键集合
+     * @return 结果
+     */
+    public int deleteArdRouteFileByIds(String[] ids);
+
+    /**
+     * 删除文件信息
+     * 
+     * @param id 文件主键
+     * @return 结果
+     */
+    public int deleteArdRouteFileById(String id);
+
+}
diff --git a/ard-route/src/main/java/com/ard/route/service/IArdRouteFolderService.java b/ard-route/src/main/java/com/ard/route/service/IArdRouteFolderService.java
new file mode 100644
index 0000000..652673b
--- /dev/null
+++ b/ard-route/src/main/java/com/ard/route/service/IArdRouteFolderService.java
@@ -0,0 +1,63 @@
+package com.ard.route.service;
+
+import java.util.List;
+import java.util.Map;
+
+import com.ard.route.domain.ArdRouteFolder;
+
+/**
+ * 文件夹Service接口
+ * 
+ * @author xia
+ * @date 2025-10-18
+ */
+public interface IArdRouteFolderService {
+
+    /**
+     * 查询文件夹
+     * 
+     * @param id 文件夹主键
+     * @return 文件夹
+     */
+    public ArdRouteFolder selectArdRouteFolderById(String id);
+
+    /**
+     * 查询文件夹列表
+     * 
+     * @param ardRouteFolder 文件夹
+     * @return 文件夹集合
+     */
+    public List<ArdRouteFolder> selectArdRouteFolderList(ArdRouteFolder ardRouteFolder);
+
+    /**
+     * 新增文件夹
+     * 
+     * @param ardRouteFolder 文件夹
+     * @return 结果
+     */
+    public int insertArdRouteFolder(ArdRouteFolder ardRouteFolder);
+
+    /**
+     * 修改文件夹
+     * 
+     * @param ardRouteFolder 文件夹
+     * @return 结果
+     */
+    public int updateArdRouteFolder(ArdRouteFolder ardRouteFolder);
+
+    /**
+     * 批量删除文件夹
+     * 
+     * @param ids 需要删除的文件夹主键集合
+     * @return 结果
+     */
+    public Map<String, Integer> deleteArdRouteFolderByIds(String[] ids);
+
+    /**
+     * 删除文件夹信息
+     * 
+     * @param id 文件夹主键
+     * @return 结果
+     */
+    public int deleteArdRouteFolderById(String id);
+}
diff --git a/ard-route/src/main/java/com/ard/route/service/impl/ArdRouteFileServiceImpl.java b/ard-route/src/main/java/com/ard/route/service/impl/ArdRouteFileServiceImpl.java
new file mode 100644
index 0000000..175ba15
--- /dev/null
+++ b/ard-route/src/main/java/com/ard/route/service/impl/ArdRouteFileServiceImpl.java
@@ -0,0 +1,97 @@
+package com.ard.route.service.impl;
+
+import java.util.List;
+import java.util.UUID;
+
+import com.ard.common.annotation.DataScope;
+import com.ard.common.utils.DateUtils;
+import com.ard.common.utils.SecurityUtils;
+import com.ard.common.utils.uuid.IdUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ard.route.mapper.ArdRouteFileMapper;
+import com.ard.route.domain.ArdRouteFile;
+import com.ard.route.service.IArdRouteFileService;
+
+/**
+ * 文件Service业务层处理
+ * 
+ * @author xia
+ * @date 2025-10-18
+ */
+@Service
+public class ArdRouteFileServiceImpl implements IArdRouteFileService {
+
+    @Autowired
+    private ArdRouteFileMapper ardRouteFileMapper;
+
+    /**
+     * 查询文件
+     * 
+     * @param id 文件主键
+     * @return 文件
+     */
+    @Override
+    public ArdRouteFile selectArdRouteFileById(String id) {
+        return ardRouteFileMapper.selectArdRouteFileById(id);
+    }
+
+    /**
+     * 查询文件列表
+     * 
+     * @param ardRouteFile 文件
+     * @return 文件
+     */
+    @Override
+    @DataScope(deptAlias = "d", userAlias = "u")
+    public List<ArdRouteFile> selectArdRouteFileList(ArdRouteFile ardRouteFile) {
+        return ardRouteFileMapper.selectArdRouteFileList(ardRouteFile);
+    }
+
+    /**
+     * 新增文件
+     * 
+     * @param ardRouteFile 文件
+     * @return 结果
+     */
+    @Override
+    public int insertArdRouteFile(ArdRouteFile ardRouteFile) {
+        ardRouteFile.setId(IdUtils.simpleUUID());
+        ardRouteFile.setCreateTime(DateUtils.getNowDate());
+        return ardRouteFileMapper.insertArdRouteFile(ardRouteFile);
+    }
+
+    /**
+     * 修改文件
+     * 
+     * @param ardRouteFile 文件
+     * @return 结果
+     */
+    @Override
+    public int updateArdRouteFile(ArdRouteFile ardRouteFile) {
+        ardRouteFile.setUpdateTime(DateUtils.getNowDate());
+        return ardRouteFileMapper.updateArdRouteFile(ardRouteFile);
+    }
+
+    /**
+     * 批量删除文件
+     * 
+     * @param ids 需要删除的文件主键
+     * @return 结果
+     */
+    @Override
+    public int deleteArdRouteFileByIds(String[] ids) {
+        return ardRouteFileMapper.deleteArdRouteFileByIds(ids);
+    }
+
+    /**
+     * 删除文件信息
+     * 
+     * @param id 文件主键
+     * @return 结果
+     */
+    @Override
+    public int deleteArdRouteFileById(String id) {
+        return ardRouteFileMapper.deleteArdRouteFileById(id);
+    }
+}
diff --git a/ard-route/src/main/java/com/ard/route/service/impl/ArdRouteFolderServiceImpl.java b/ard-route/src/main/java/com/ard/route/service/impl/ArdRouteFolderServiceImpl.java
new file mode 100644
index 0000000..2b0a1b3
--- /dev/null
+++ b/ard-route/src/main/java/com/ard/route/service/impl/ArdRouteFolderServiceImpl.java
@@ -0,0 +1,131 @@
+package com.ard.route.service.impl;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.ard.common.annotation.DataScope;
+import com.ard.common.utils.DateUtils;
+import com.ard.common.utils.SecurityUtils;
+import com.ard.common.utils.uuid.IdUtils;
+import com.ard.route.domain.ArdRouteFile;
+import com.ard.route.mapper.ArdRouteFileMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ard.route.mapper.ArdRouteFolderMapper;
+import com.ard.route.domain.ArdRouteFolder;
+import com.ard.route.service.IArdRouteFolderService;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * 文件夹Service业务层处理
+ * 
+ * @author xia
+ * @date 2025-10-18
+ */
+@Service
+public class ArdRouteFolderServiceImpl implements IArdRouteFolderService {
+
+    @Autowired
+    private ArdRouteFolderMapper ardRouteFolderMapper;
+
+    @Autowired
+    private ArdRouteFileMapper ardRouteFileMapper;
+
+    /**
+     * 查询文件夹
+     * 
+     * @param id 文件夹主键
+     * @return 文件夹
+     */
+    @Override
+    public ArdRouteFolder selectArdRouteFolderById(String id) {
+        ArdRouteFolder ardRouteFolder = ardRouteFolderMapper.selectArdRouteFolderById(id);
+        ardRouteFolder.setArdRouteFileLs(getArdRouteFiles(id));
+        return ardRouteFolder;
+    }
+
+    /**
+     * 查询文件夹列表
+     * 
+     * @param ardRouteFolder 文件夹
+     * @return 文件夹
+     */
+    @Override
+    @DataScope(deptAlias = "d", userAlias = "u")
+    public List<ArdRouteFolder> selectArdRouteFolderList(ArdRouteFolder ardRouteFolder) {
+        List<ArdRouteFolder> list = ardRouteFolderMapper.selectArdRouteFolderList(ardRouteFolder);
+        for (ArdRouteFolder routeFolder : list) {
+            routeFolder.setArdRouteFileLs(getArdRouteFiles(routeFolder.getId()));
+        }
+        return list;
+    }
+
+    /**
+     * 查询文件列表
+     */
+    private List<ArdRouteFile> getArdRouteFiles(String folderId) {
+        ArdRouteFile ardRouteFile = new ArdRouteFile();
+        ardRouteFile.setFolderId(folderId);
+        return ardRouteFileMapper.selectArdRouteFileList(ardRouteFile);
+    }
+
+    /**
+     * 新增文件夹
+     * 
+     * @param ardRouteFolder 文件夹
+     * @return 结果
+     */
+    @Override
+    public int insertArdRouteFolder(ArdRouteFolder ardRouteFolder) {
+        ardRouteFolder.setId(IdUtils.simpleUUID());
+        ardRouteFolder.setCreateTime(DateUtils.getNowDate());
+        return ardRouteFolderMapper.insertArdRouteFolder(ardRouteFolder);
+    }
+
+    /**
+     * 修改文件夹
+     * 
+     * @param ardRouteFolder 文件夹
+     * @return 结果
+     */
+    @Override
+    public int updateArdRouteFolder(ArdRouteFolder ardRouteFolder) {
+        ardRouteFolder.setUpdateTime(DateUtils.getNowDate());
+        return ardRouteFolderMapper.updateArdRouteFolder(ardRouteFolder);
+    }
+
+    /**
+     * 批量删除文件夹
+     * 
+     * @param ids 需要删除的文件夹主键
+     * @return 结果
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Map<String, Integer> deleteArdRouteFolderByIds(String[] ids) {
+        Map<String, Integer> result = new HashMap<>();
+        int fileAdd = 0;
+        // 删除文件夹的同时也删除文件夹下的所有文件
+        for (String folderId : ids) {
+            ardRouteFileMapper.deleteArdRouteFileByFolderId(folderId);
+            fileAdd ++;
+        }
+        result.put("file", fileAdd);
+        int folderCount = ardRouteFolderMapper.deleteArdRouteFolderByIds(ids);
+        result.put("folder", folderCount);
+        return result;
+    }
+
+    /**
+     * 删除文件夹信息
+     * 
+     * @param id 文件夹主键
+     * @return 结果
+     */
+    @Override
+    public int deleteArdRouteFolderById(String id) {
+        return ardRouteFolderMapper.deleteArdRouteFolderById(id);
+    }
+
+}
diff --git a/ard-route/src/main/resources/mapper/ArdRouteFileMapper.xml b/ard-route/src/main/resources/mapper/ArdRouteFileMapper.xml
new file mode 100644
index 0000000..1a64382
--- /dev/null
+++ b/ard-route/src/main/resources/mapper/ArdRouteFileMapper.xml
@@ -0,0 +1,108 @@
+<?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.ard.route.mapper.ArdRouteFileMapper">
+    
+    <resultMap type="ArdRouteFile" id="ArdRouteFileResult">
+        <result property="id"    column="id"    />
+        <result property="name"    column="name"    />
+        <result property="folderId"    column="folder_id"    />
+        <result property="fileType"    column="file_type"    />
+        <result property="fileSize"    column="file_size"    />
+        <result property="filePath"    column="file_path"    />
+        <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="selectArdRouteFileVo">
+        select id,
+               name,
+               folder_id,
+               file_type,
+               file_size,
+               file_path,
+               create_by,
+               create_time,
+               update_by,
+               update_time
+        from ard_route_file
+    </sql>
+
+    <select id="selectArdRouteFileList" parameterType="ArdRouteFile" resultMap="ArdRouteFileResult">
+        <include refid="selectArdRouteFileVo"/>
+        <where>  
+            <if test="name != null  and name != ''"> and name like concat('%', #{name}, '%')</if>
+            <if test="folderId != null  and folderId != ''"> and folder_id = #{folderId}</if>
+            <if test="fileType != null  and fileType != ''"> and file_type = #{fileType}</if>
+            <if test="fileSize != null "> and file_size = #{fileSize}</if>
+            <if test="filePath != null  and filePath != ''"> and file_path = #{filePath}</if>
+        </where>
+    </select>
+    
+    <select id="selectArdRouteFileById" parameterType="String" resultMap="ArdRouteFileResult">
+        <include refid="selectArdRouteFileVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertArdRouteFile" parameterType="ArdRouteFile">
+        insert into ard_route_file
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="id != null">id,</if>
+            <if test="name != null">name,</if>
+            <if test="folderId != null">folder_id,</if>
+            <if test="fileType != null">file_type,</if>
+            <if test="fileSize != null">file_size,</if>
+            <if test="filePath != null">file_path,</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="id != null">#{id},</if>
+            <if test="name != null">#{name},</if>
+            <if test="folderId != null">#{folderId},</if>
+            <if test="fileType != null">#{fileType},</if>
+            <if test="fileSize != null">#{fileSize},</if>
+            <if test="filePath != null">#{filePath},</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="updateArdRouteFile" parameterType="ArdRouteFile">
+        update ard_route_file
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="name != null">name = #{name},</if>
+            <if test="folderId != null">folder_id = #{folderId},</if>
+            <if test="fileType != null">file_type = #{fileType},</if>
+            <if test="fileSize != null">file_size = #{fileSize},</if>
+            <if test="filePath != null">file_path = #{filePath},</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 id = #{id}
+    </update>
+
+    <delete id="deleteArdRouteFileById" parameterType="String">
+        delete from ard_route_file where id = #{id}
+    </delete>
+
+    <delete id="deleteArdRouteFileByFolderId" parameterType="String">
+        delete from ard_route_file where folder_id = #{folderId}
+    </delete>
+
+    <delete id="deleteArdRouteFileByIds" parameterType="String">
+        delete from ard_route_file where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>
\ No newline at end of file
diff --git a/ard-route/src/main/resources/mapper/ArdRouteFolderMapper.xml b/ard-route/src/main/resources/mapper/ArdRouteFolderMapper.xml
new file mode 100644
index 0000000..29385ce
--- /dev/null
+++ b/ard-route/src/main/resources/mapper/ArdRouteFolderMapper.xml
@@ -0,0 +1,84 @@
+<?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.ard.route.mapper.ArdRouteFolderMapper">
+    
+    <resultMap type="ArdRouteFolder" id="ArdRouteFolderResult">
+        <result property="id"    column="id"    />
+        <result property="fileName"    column="file_name"    />
+        <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>
+
+    <select id="selectArdRouteFile" resultType="com.ard.route.domain.ArdRouteFile">
+        select * from ard_route_file where id = #{folderId}
+    </select>
+
+    <sql id="selectArdRouteFolderVo">
+        select id,
+               file_name,
+               create_by,
+               create_time,
+               update_by,
+               update_time
+        from ard_route_folder
+    </sql>
+
+    <select id="selectArdRouteFolderList" parameterType="ArdRouteFolder" resultMap="ArdRouteFolderResult">
+        <include refid="selectArdRouteFolderVo"/>
+        <where>  
+            <if test="fileName != null  and fileName != ''"> and file_name like concat('%', #{fileName}, '%')</if>
+        </where>
+    </select>
+    
+    <select id="selectArdRouteFolderById" parameterType="String" resultMap="ArdRouteFolderResult">
+        <include refid="selectArdRouteFolderVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertArdRouteFolder" parameterType="ArdRouteFolder">
+        insert into ard_route_folder
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="id != null">id,</if>
+            <if test="fileName != null">file_name,</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="id != null">#{id},</if>
+            <if test="fileName != null">#{fileName},</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="updateArdRouteFolder" parameterType="ArdRouteFolder">
+        update ard_route_folder
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="fileName != null">file_name = #{fileName},</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 id = #{id}
+    </update>
+
+    <delete id="deleteArdRouteFolderById" parameterType="String">
+        delete from ard_route_folder where id = #{id}
+    </delete>
+
+    <delete id="deleteArdRouteFolderByIds" parameterType="String">
+        delete from ard_route_folder where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>
\ No newline at end of file
diff --git a/ard-work/src/main/java/com/ard/work/aspect/UavControlAspect.java b/ard-work/src/main/java/com/ard/work/aspect/UavControlAspect.java
index 5cd5cd4..f796aa1 100644
--- a/ard-work/src/main/java/com/ard/work/aspect/UavControlAspect.java
+++ b/ard-work/src/main/java/com/ard/work/aspect/UavControlAspect.java
@@ -70,7 +70,7 @@
         for (Object arg : args) {
             String boxSn = getBoxSn(arg);  // 调用之前实现的 getBoxSn 方法
             if (boxSn != null) {
-                TelemetryData uavTelemetryData = UavTelemetryDataCache.getUavTelemetryData(boxSn);
+                TelemetryData uavTelemetryData = UavTelemetryDataCache.get(boxSn);
                 if (uavTelemetryData == null) {
                     throw new ControlException("遥测数据异常,无法执行!");
                 }
diff --git a/ard-work/src/main/java/com/ard/work/component/forest/MyAddressSource.java b/ard-work/src/main/java/com/ard/work/component/forest/MyAddressSource.java
index 079e96c..7a49d70 100644
--- a/ard-work/src/main/java/com/ard/work/component/forest/MyAddressSource.java
+++ b/ard-work/src/main/java/com/ard/work/component/forest/MyAddressSource.java
@@ -5,10 +5,12 @@
 import com.dtflys.forest.callback.AddressSource;
 import com.dtflys.forest.http.ForestAddress;
 import com.dtflys.forest.http.ForestRequest;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
 
+@Slf4j
 @Component
 public class MyAddressSource implements AddressSource {
 
@@ -17,7 +19,15 @@
     @Override
     public ForestAddress getAddress(ForestRequest request) {
         String serverKey = request.varAsString("serverId");
+        if(serverKey == null){
+            log.warn("请求属性serverId为空");
+            return null;
+        }
         ArdServerInfo serverInfo = ardServerService.selectArdServerInfoById(serverKey);
+        if(serverInfo == null){
+            log.warn("边缘服务器不存在");
+            return null;
+        }
         // 返回 Forest 地址对象
         return new ForestAddress(serverInfo.getHost(), serverInfo.getHttpPort());
     }
diff --git a/ard-work/src/main/java/com/ard/work/component/netty/TyTcpClientManager.java b/ard-work/src/main/java/com/ard/work/component/netty/TyTcpClientManager.java
index 2060ae7..547b22f 100644
--- a/ard-work/src/main/java/com/ard/work/component/netty/TyTcpClientManager.java
+++ b/ard-work/src/main/java/com/ard/work/component/netty/TyTcpClientManager.java
@@ -143,7 +143,7 @@
     }
 
     /**
-     * 定时向所有已连接的六合服务器发送心跳
+     * 定时向所有已连接的边缘服务器服务器发送心跳
      */
     @Scheduled(fixedRate = 5000) // 每5秒执行一次
     public void sendHeartBeat() {
diff --git a/ard-work/src/main/java/com/ard/work/component/netty/cache/TyTcpServerCache.java b/ard-work/src/main/java/com/ard/work/component/netty/cache/TyTcpServerCache.java
index aec481d..356fd12 100644
--- a/ard-work/src/main/java/com/ard/work/component/netty/cache/TyTcpServerCache.java
+++ b/ard-work/src/main/java/com/ard/work/component/netty/cache/TyTcpServerCache.java
@@ -9,7 +9,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
- * 六合tcp服务器缓存
+ * 边缘服务器tcp服务器缓存
  *
  * @author liusuyi
  * @date 2024年11月01日13:53
diff --git a/ard-work/src/main/java/com/ard/work/component/netty/handler/ClientHandler.java b/ard-work/src/main/java/com/ard/work/component/netty/handler/ClientHandler.java
index afc3752..55da307 100644
--- a/ard-work/src/main/java/com/ard/work/component/netty/handler/ClientHandler.java
+++ b/ard-work/src/main/java/com/ard/work/component/netty/handler/ClientHandler.java
@@ -86,7 +86,7 @@
         InetSocketAddress remoteAddress = (InetSocketAddress) channel.remoteAddress();
         String host = remoteAddress.getHostString();
         int port = remoteAddress.getPort();
-        log.error("与六合服务{}:{}连接断开!", host, port);
+        log.error("与边缘服务器服务{}:{}连接断开!", host, port);
         TyTcpServerCache.putTcpServerCache(serverId, false);
         super.channelInactive(ctx);
     }
diff --git a/ard-work/src/main/java/com/ard/work/component/websocket/handler/BaseSubscriptionManager.java b/ard-work/src/main/java/com/ard/work/component/websocket/handler/BaseSubscriptionManager.java
index 1a74d58..9482d18 100644
--- a/ard-work/src/main/java/com/ard/work/component/websocket/handler/BaseSubscriptionManager.java
+++ b/ard-work/src/main/java/com/ard/work/component/websocket/handler/BaseSubscriptionManager.java
@@ -23,10 +23,10 @@
     /**
      * 订阅指定设备的数据
      */
-    public void subscribe(String boxSn, Long userId,Integer period) {
+    public void subscribe(String boxSn, Long userId, Integer period) {
         subscriptions.computeIfAbsent(boxSn, k -> new HashSet<>()).add(userId);
         if (subscriptions.get(boxSn).size() == 1) {
-            startPushTask(boxSn,period);
+            startPushTask(boxSn, period);
         }
     }
 
@@ -46,7 +46,7 @@
     /**
      * 启动推送任务
      */
-    private void startPushTask(String boxSn,Integer period) {
+    private void startPushTask(String boxSn, Integer period) {
         // 如果已经存在任务,则不再创建
         if (pushTasks.containsKey(boxSn)) {
             return;
@@ -79,7 +79,6 @@
     }
 
 
-
     /**
      * 向订阅者发送数据
      */
@@ -90,7 +89,7 @@
         if (userIds != null) {
             for (Long userId : userIds) {
                 try {
-                    log.warn("给用户{}定时推送",userId);
+                    log.debug("给用户{}定时推送", userId);
                     WebSocketUtil.sendMessage(userId, JSON.toJSONString(baseMessage));
                 } catch (Exception e) {
                     log.error("Error sending message to session {}", userId, e);
diff --git a/ard-work/src/main/java/com/ard/work/component/websocket/handler/TyMessageHandler.java b/ard-work/src/main/java/com/ard/work/component/websocket/handler/TyMessageHandler.java
index ca41681..b7e380a 100644
--- a/ard-work/src/main/java/com/ard/work/component/websocket/handler/TyMessageHandler.java
+++ b/ard-work/src/main/java/com/ard/work/component/websocket/handler/TyMessageHandler.java
@@ -192,8 +192,8 @@
     }
 
     /**
-     * 处理无人机控制
-     * 根据接收到的消息内容,决定无人机控制信息的订阅或退订
+     * 处理无人机控制者
+     * 根据接收到的消息内容,决定无人机控制者信息的订阅或退订
      *
      * @param payload 消息负载,包含控制信息
      * @param userId  用户ID,用于标识用户
diff --git a/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavAllManager.java b/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavAllManager.java
index 1e74284..1e1e469 100644
--- a/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavAllManager.java
+++ b/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavAllManager.java
@@ -22,15 +22,15 @@
     @Override
     protected Map<String,Object> getData(String boxSn) {
         Map<String,Object> map=new HashMap<>();
-        UavState uavState = UavStateCache.getUavState(boxSn);
+        UavState uavState = UavStateCache.get(boxSn);
         if (uavState != null) {
             uavState.calculateFieldAngle();// 计算当前无人机的FieldAngle
         }
         map.put("boxSn", uavState.getBoxSn());
         map.put("state", uavState);
-        TelemetryData uavTelemetryData = UavTelemetryDataCache.getUavTelemetryData(boxSn);
+        TelemetryData uavTelemetryData = UavTelemetryDataCache.get(boxSn);
         map.put("telemetry", uavTelemetryData);
-        SignalInfo uavSignalInfo = UavSignalInfoCache.getUavSignalInfo(boxSn);
+        SignalInfo uavSignalInfo = UavSignalInfoCache.get(boxSn);
         map.put("signal", uavSignalInfo);
         // 获取当前控制飞行的用户ID
         Long flyUserId = uavControlService.getCurrentController(boxSn, "fly");
diff --git a/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavControlManager.java b/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavControlManager.java
index 863171a..4e56d46 100644
--- a/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavControlManager.java
+++ b/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavControlManager.java
@@ -12,7 +12,7 @@
 import java.util.Map;
 
 @Service
-public class UavControlManager  extends BaseSubscriptionManager<Map<String, Long>> {
+public class UavControlManager  extends BaseSubscriptionManager<Map<String, Object>> {
 
     @Resource
     private UavControlService uavControlService;
@@ -60,13 +60,14 @@
      * @return 返回一个映射,包含无人机(fly)和载荷(payload)的当前控制者用户ID
      */
     @Override
-    protected Map<String, Long> getData(String boxSn) {
+    protected Map<String, Object> getData(String boxSn) {
         // 获取当前控制飞行的用户ID
         Long flyUserId = uavControlService.getCurrentController(boxSn, "fly");
         // 获取当前控制载荷的用户ID
         Long payloadUserId = uavControlService.getCurrentController(boxSn, "payload");
         // 创建一个映射,用于存储飞行和载荷的当前控制者用户ID
-        Map<String, Long> map=new HashMap<>();
+        Map<String, Object> map=new HashMap<>();
+        map.put("boxSn", boxSn);
         // 将飞行当前控制者用户ID添加到映射中
         map.put("flyController", flyUserId);
         // 将载荷当前控制者用户ID添加到映射中
diff --git a/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavSignalManager.java b/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavSignalManager.java
index ab54db4..e860d9d 100644
--- a/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavSignalManager.java
+++ b/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavSignalManager.java
@@ -10,7 +10,7 @@
 
     @Override
     protected SignalInfo getData(String boxSn) {
-        return UavSignalInfoCache.getUavSignalInfo(boxSn);
+        return UavSignalInfoCache.get(boxSn);
     }
 
     @Override
diff --git a/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavStateManager.java b/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavStateManager.java
index b5aff26..e7d4e48 100644
--- a/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavStateManager.java
+++ b/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavStateManager.java
@@ -10,7 +10,7 @@
 
     @Override
     protected UavState getData(String boxSn) {
-        UavState uavState = UavStateCache.getUavState(boxSn);
+        UavState uavState = UavStateCache.get(boxSn);
         if (uavState != null) {
             uavState.calculateFieldAngle();// 计算当前无人机的FieldAngle
         }
diff --git a/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavStreamManager.java b/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavStreamManager.java
index e24af6f..f0b0362 100644
--- a/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavStreamManager.java
+++ b/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavStreamManager.java
@@ -42,14 +42,15 @@
     public void subscribe(String boxSn, Long userId) {
 
         STREAM_USER_MAP.computeIfAbsent(boxSn, k -> ConcurrentHashMap.newKeySet()).add(userId);
-        String webrtcUrl = getWebrtcUrl(boxSn);
+        BoxStreamUrlReceiver streamReceiver = getWebrtcUrl(boxSn);
+        String webrtcUrl = streamReceiver.getRtc();
         if (Objects.equals(webrtcUrl, "")) {
             log.warn("{}{}{}", STREAM_LOG_PREFIX, STREAM_NOT_FOUND_MSG, boxSn);
             BaseMessage<String> baseMessage = new BaseMessage<>("stream", STREAM_NOT_FOUND_MSG + boxSn);
             sendMessageToUser(userId, JSON.toJSONString(baseMessage));
         }
         BOX_STREAM_PULL_MAP.put(boxSn, webrtcUrl);
-        BaseMessage<String> baseMessage = new BaseMessage<>("stream", webrtcUrl);
+        BaseMessage<BoxStreamUrlReceiver> baseMessage = new BaseMessage<>("stream", streamReceiver);
         sendMessageToUser(userId, JSON.toJSONString(baseMessage));
     }
 
@@ -117,15 +118,9 @@
      * @param boxSn 盒子编号
      * @return String webrtcUrl
      */
-    private String getWebrtcUrl(String boxSn) {
-        try {
-            BoxStreamUrlReceiver boxLiveUrl = tyService.getBoxLiveUrl(boxSn);
-            if (boxLiveUrl != null) {
-                return boxLiveUrl.getRtc();
-            }
-        } catch (Exception e) {
-            log.error("获取媒体地址异常:{}", e.getMessage());
-        }
-        return "";
+    private BoxStreamUrlReceiver getWebrtcUrl(String boxSn) {
+        BoxStreamUrlReceiver boxLiveUrl = tyService.getBoxLiveUrl(boxSn);
+        boxLiveUrl.setBoxSn(boxSn);
+        return boxLiveUrl;
     }
 }
\ No newline at end of file
diff --git a/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavTelemetryManager.java b/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavTelemetryManager.java
index f7a23e7..e83625d 100644
--- a/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavTelemetryManager.java
+++ b/ard-work/src/main/java/com/ard/work/component/websocket/handler/UavTelemetryManager.java
@@ -10,7 +10,7 @@
 
     @Override
     protected TelemetryData getData(String boxSn) {
-        return UavTelemetryDataCache.getUavTelemetryData(boxSn);
+        return UavTelemetryDataCache.get(boxSn);
     }
 
     @Override
diff --git a/ard-work/src/main/java/com/ard/work/domain/cache/UavSignalInfoCache.java b/ard-work/src/main/java/com/ard/work/domain/cache/UavSignalInfoCache.java
index 2e25c41..02b761e 100644
--- a/ard-work/src/main/java/com/ard/work/domain/cache/UavSignalInfoCache.java
+++ b/ard-work/src/main/java/com/ard/work/domain/cache/UavSignalInfoCache.java
@@ -1,6 +1,7 @@
 package com.ard.work.domain.cache;
 
 import com.ard.work.domain.dto.signal.SignalInfo;
+import com.ard.work.domain.dto.telemetry.TelemetryData;
 
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -13,20 +14,29 @@
 public class UavSignalInfoCache {
 
     // 使用 ConcurrentHashMap 来缓存无人机信道质量数据,key 是 boxSn(无人机序列号)
-    private static final ConcurrentHashMap<String, SignalInfo> uavSignalInfoCache = new ConcurrentHashMap<>();
+    private static final ConcurrentHashMap<String, SignalInfo> cache = new ConcurrentHashMap<>();
 
     // 存储无人机信道质量数据到缓存
-    public static void putUavSignalInfoCache(SignalInfo signalInfo) {
-        uavSignalInfoCache.put(signalInfo.getBoxSn(), signalInfo);
+    public static void put(SignalInfo signalInfo) {
+        cache.put(signalInfo.getBoxSn(), signalInfo);
     }
 
     // 从缓存中获取信道质量数据
-    public static SignalInfo getUavSignalInfo(String boxSn) {
-        return uavSignalInfoCache.get(boxSn);
+    public static SignalInfo get(String boxSn) {
+        return cache.get(boxSn);
     }
 
     // 删除缓存中的信道质量数据
-    public static void removeUavSignalInfo(String boxSn) {
-        uavSignalInfoCache.remove(boxSn);
+    public static void remove(String boxSn) {
+        cache.remove(boxSn);
+    }
+
+    // 定时任务使用:判断状遥测数据是否变化,但不更新缓存
+    public static boolean hasChanged(String boxSn, SignalInfo signalInfo) {
+        SignalInfo oldSignalInfo= cache.get(boxSn);
+        if (oldSignalInfo == null) {
+            return true; // 没有缓存,算作变化
+        }
+        return !oldSignalInfo.equals(signalInfo); // true = 有变化
     }
 }
diff --git a/ard-work/src/main/java/com/ard/work/domain/cache/UavStateCache.java b/ard-work/src/main/java/com/ard/work/domain/cache/UavStateCache.java
index ddd31c3..70349c4 100644
--- a/ard-work/src/main/java/com/ard/work/domain/cache/UavStateCache.java
+++ b/ard-work/src/main/java/com/ard/work/domain/cache/UavStateCache.java
@@ -1,6 +1,7 @@
 package com.ard.work.domain.cache;
 
 import com.ard.work.domain.dto.state.UavState;
+
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
@@ -12,20 +13,27 @@
 public class UavStateCache {
 
     // 使用 ConcurrentHashMap 来缓存无人机状态数据,key 是 boxSn(无人机序列号)
-    private static final ConcurrentHashMap<String, UavState> uavStateCache = new ConcurrentHashMap<>();
+    private static final ConcurrentHashMap<String, UavState> cache = new ConcurrentHashMap<>();
 
     // 存储无人机状态数据到缓存
-    public static void putUavState(UavState uavState) {
-        uavStateCache.put(uavState.getBoxSn(), uavState);
-    }
+    public static void put(UavState uavState) {cache.put(uavState.getBoxSn(), uavState);}
 
     // 从缓存中获取无人机状态数据
-    public static UavState getUavState(String boxSn) {
-        return uavStateCache.get(boxSn);
+    public static UavState get(String boxSn) {
+        return cache.get(boxSn);
     }
 
     // 删除缓存中的无人机状态数据
-    public static void removeUavState(String boxSn) {
-        uavStateCache.remove(boxSn);
+    public static void remove(String boxSn) {
+        cache.remove(boxSn);
+    }
+
+    // 定时任务使用:判断状态是否变化,但不更新缓存
+    public static boolean hasChanged(String boxSn, UavState newState) {
+        UavState oldState = cache.get(boxSn);
+        if (oldState == null) {
+            return true; // 没有缓存,算作变化
+        }
+        return !oldState.equals(newState); // true = 有变化
     }
 }
diff --git a/ard-work/src/main/java/com/ard/work/domain/cache/UavTelemetryDataCache.java b/ard-work/src/main/java/com/ard/work/domain/cache/UavTelemetryDataCache.java
index 65cb4ba..abb7da0 100644
--- a/ard-work/src/main/java/com/ard/work/domain/cache/UavTelemetryDataCache.java
+++ b/ard-work/src/main/java/com/ard/work/domain/cache/UavTelemetryDataCache.java
@@ -1,5 +1,6 @@
 package com.ard.work.domain.cache;
 
+import com.ard.work.domain.dto.state.UavState;
 import com.ard.work.domain.dto.telemetry.TelemetryData;
 
 import java.util.concurrent.ConcurrentHashMap;
@@ -13,20 +14,29 @@
 public class UavTelemetryDataCache {
 
     // 使用 ConcurrentHashMap 来缓存无人机遥测数据,key 是 boxSn(无人机序列号)
-    private static final ConcurrentHashMap<String, TelemetryData> uavTelemetryDataCache = new ConcurrentHashMap<>();
+    private static final ConcurrentHashMap<String, TelemetryData> cache = new ConcurrentHashMap<>();
 
     // 存储无人机遥测数据到缓存
-    public static void putUavTelemetryData(TelemetryData telemetryData) {
-        uavTelemetryDataCache.put(telemetryData.getBoxSn(), telemetryData);
+    public static void put(TelemetryData telemetryData) {
+        cache.put(telemetryData.getBoxSn(), telemetryData);
     }
 
     // 从缓存中获取无人机遥测数据
-    public static TelemetryData getUavTelemetryData(String boxSn) {
-        return uavTelemetryDataCache.get(boxSn);
+    public static TelemetryData get(String boxSn) {
+        return cache.get(boxSn);
     }
 
     // 删除缓存中的无人机遥测数据
-    public static void removeUavTelemetryData(String boxSn) {
-        uavTelemetryDataCache.remove(boxSn);
+    public static void remove(String boxSn) {
+        cache.remove(boxSn);
+    }
+
+    // 定时任务使用:判断状遥测数据是否变化,但不更新缓存
+    public static boolean hasChanged(String boxSn, TelemetryData telemetryData) {
+        TelemetryData oldTelemetryData= cache.get(boxSn);
+        if (oldTelemetryData == null) {
+            return true; // 没有缓存,算作变化
+        }
+        return !oldTelemetryData.equals(telemetryData); // true = 有变化
     }
 }
diff --git a/ard-work/src/main/java/com/ard/work/domain/dto/signal/SignalInfo.java b/ard-work/src/main/java/com/ard/work/domain/dto/signal/SignalInfo.java
index 8ee8ce2..d591b92 100644
--- a/ard-work/src/main/java/com/ard/work/domain/dto/signal/SignalInfo.java
+++ b/ard-work/src/main/java/com/ard/work/domain/dto/signal/SignalInfo.java
@@ -2,8 +2,10 @@
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.Data;
+import lombok.EqualsAndHashCode;
 
 @Data
+@EqualsAndHashCode
 public class SignalInfo {
     private String mode;               // 入网模式: NR5G-SA, NR5G-NSA,LTE
     private String mcc;                // NR5G-SA, NR5G-NSA, LTE
diff --git a/ard-work/src/main/java/com/ard/work/domain/dto/state/UavState.java b/ard-work/src/main/java/com/ard/work/domain/dto/state/UavState.java
index 893f4bc..679f147 100644
--- a/ard-work/src/main/java/com/ard/work/domain/dto/state/UavState.java
+++ b/ard-work/src/main/java/com/ard/work/domain/dto/state/UavState.java
@@ -1,10 +1,7 @@
 package com.ard.work.domain.dto.state;
 
 import com.ard.work.util.CameraUtil;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
+import lombok.*;
 
 import java.util.List;
 
@@ -12,6 +9,7 @@
 @Builder
 @AllArgsConstructor
 @NoArgsConstructor
+@EqualsAndHashCode
 public class UavState {
 
     private FlightControllerState flightControllerState;  // 飞控状态
diff --git a/ard-work/src/main/java/com/ard/work/domain/dto/telemetry/TelemetryData.java b/ard-work/src/main/java/com/ard/work/domain/dto/telemetry/TelemetryData.java
index 5e0aa8d..8111ec1 100644
--- a/ard-work/src/main/java/com/ard/work/domain/dto/telemetry/TelemetryData.java
+++ b/ard-work/src/main/java/com/ard/work/domain/dto/telemetry/TelemetryData.java
@@ -1,14 +1,12 @@
 package com.ard.work.domain.dto.telemetry;
 
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
+import lombok.*;
 
 @Data
 @Builder
 @AllArgsConstructor
 @NoArgsConstructor
+@EqualsAndHashCode
 public class TelemetryData {
 
     private double lng;              // 经度
diff --git a/ard-work/src/main/java/com/ard/work/domain/receiver/BoxStreamUrlReceiver.java b/ard-work/src/main/java/com/ard/work/domain/receiver/BoxStreamUrlReceiver.java
index 58dd24d..b70b9d6 100644
--- a/ard-work/src/main/java/com/ard/work/domain/receiver/BoxStreamUrlReceiver.java
+++ b/ard-work/src/main/java/com/ard/work/domain/receiver/BoxStreamUrlReceiver.java
@@ -8,6 +8,8 @@
 @JsonIgnoreProperties(ignoreUnknown = true)
 public class BoxStreamUrlReceiver {
 
+    private String boxSn;
+
     @JsonProperty("rtsp")
     private String rtsp;
 
diff --git a/ard-work/src/main/java/com/ard/work/domain/receiver/TyHttpCommonReceiver.java b/ard-work/src/main/java/com/ard/work/domain/receiver/TyHttpCommonReceiver.java
index 5b88d4a..f170641 100644
--- a/ard-work/src/main/java/com/ard/work/domain/receiver/TyHttpCommonReceiver.java
+++ b/ard-work/src/main/java/com/ard/work/domain/receiver/TyHttpCommonReceiver.java
@@ -8,7 +8,7 @@
 @JsonIgnoreProperties(ignoreUnknown = true)
 public class TyHttpCommonReceiver<T> {
     /**
-     * 六合http请求返回信息
+     * 边缘服务器http请求返回信息
      */
     @JsonProperty("state")
     private Integer state;
diff --git a/ard-work/src/main/java/com/ard/work/service/ITyService.java b/ard-work/src/main/java/com/ard/work/service/ITyService.java
index 5828e4e..52f1c75 100644
--- a/ard-work/src/main/java/com/ard/work/service/ITyService.java
+++ b/ard-work/src/main/java/com/ard/work/service/ITyService.java
@@ -31,7 +31,7 @@
 public interface ITyService {
 
     /**
-     * 获取六合token信息
+     * 获取边缘服务器token信息
      * @return
      */
     AccessTokenReceiver getAccessToken(String ServerId);
@@ -288,7 +288,7 @@
     void processReplyMessage(String key, BaseCmd tyMessage);
 
     /**
-     * 根据[服务器id]获取六合盒子列表
+     * 根据[服务器id]获取边缘服务器盒子列表
      */
     List<BoxInfoReceiver> getBoxSnToList(String id);
 
diff --git a/ard-work/src/main/java/com/ard/work/service/impl/TyServiceImpl.java b/ard-work/src/main/java/com/ard/work/service/impl/TyServiceImpl.java
index 6f849c0..130b9c9 100644
--- a/ard-work/src/main/java/com/ard/work/service/impl/TyServiceImpl.java
+++ b/ard-work/src/main/java/com/ard/work/service/impl/TyServiceImpl.java
@@ -52,6 +52,7 @@
 import com.ard.work.service.ITyService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
+
 import javax.annotation.Resource;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -74,7 +75,7 @@
     private TyClient tyClient;
 
     /**
-     * 获取六合token信息
+     * 获取边缘服务器token信息
      *
      * @return AccessTokenReceiver
      */
@@ -93,6 +94,7 @@
         List<ArdServerInfo> ardServerInfos = ardServerService.selectArdServerInfoList(new ArdServerInfo());
         return getBoxList(ardServerInfos);
     }
+
     /**
      * 获取指定服务器云盒列表
      *
@@ -101,8 +103,9 @@
     @Override
     public List<BoxInfoReceiver> getBoxList(String serverId) {
         TyHttpCommonReceiver<List<BoxInfoReceiver>> boxList = tyClient.getBoxList(serverId);
-        return boxList.getContent();
+        return boxList == null ? null : boxList.getContent();
     }
+
     /**
      * 获取直播地址
      *
@@ -111,8 +114,13 @@
     @Override
     public BoxStreamUrlReceiver getBoxLiveUrl(String boxSn) {
         ArdDroneInfo ardDroneInfo = ardDroneService.selectArdDroneByboxSn(boxSn);
-        TyHttpCommonReceiver<BoxStreamUrlReceiver> boxLiveUrl = tyClient.getBoxLiveUrl(ardDroneInfo.getServerId(),boxSn);
-        return boxLiveUrl.getContent();
+        if (ardDroneInfo == null) {
+            log.warn("未找到对应的飞行器信息,boxSn:{}", boxSn);
+            return null;
+        }
+        TyHttpCommonReceiver<BoxStreamUrlReceiver> boxLiveUrl = tyClient.getBoxLiveUrl(ardDroneInfo.getServerId(),
+                boxSn);
+        return boxLiveUrl == null ? null : boxLiveUrl.getContent();
     }
 
     /**
@@ -125,7 +133,7 @@
         ArdDroneInfo ardDroneInfo = ardDroneService.selectArdDroneByboxSn(boxHistoryDTO.getBoxSn());
         TyHttpCommonReceiver<List<BoxHistoryReceiver>> boxHistory = tyClient.getBoxHistory(ardDroneInfo.getServerId(),
                 boxHistoryDTO);
-        return boxHistory.getContent();
+        return boxHistory == null ? null : boxHistory.getContent();
     }
 
     /**
@@ -136,8 +144,9 @@
     @Override
     public List<BoxPhotosReceiver> getBoxPhotos(BoxPhotosDTO boxPhotosDTO) {
         ArdDroneInfo ardDroneInfo = ardDroneService.selectArdDroneByboxSn(boxPhotosDTO.getBoxSn());
-        TyHttpCommonReceiver<List<BoxPhotosReceiver>> boxPhotos = tyClient.getBoxPhotos(ardDroneInfo.getServerId(),boxPhotosDTO);
-        return boxPhotos.getContent();
+        TyHttpCommonReceiver<List<BoxPhotosReceiver>> boxPhotos = tyClient.getBoxPhotos(ardDroneInfo.getServerId(),
+                boxPhotosDTO);
+        return boxPhotos == null ? null : boxPhotos.getContent();
     }
 
     /**
@@ -146,7 +155,7 @@
     @Override
     public Boolean updateBoxSettings(BoxSettingsDTO boxSettingsDTO) {
         ArdDroneInfo ardDroneInfo = ardDroneService.selectArdDroneByboxSn(boxSettingsDTO.getBoxSn());
-        TyHttpCommonReceiver<?> result = tyClient.updateBoxSettings(ardDroneInfo.getServerId(),boxSettingsDTO);
+        TyHttpCommonReceiver<?> result = tyClient.updateBoxSettings(ardDroneInfo.getServerId(), boxSettingsDTO);
         return result.getState() == 1;
     }
 
@@ -184,7 +193,7 @@
     }
 
     /**
-     * 注册六合平台
+     * 注册边缘服务器平台
      */
     @Override
     public Boolean registerMessage(String serverId) {
@@ -193,7 +202,7 @@
             RegisterCmd registerMessage = new RegisterCmd(tyToken.getCompanyId(), tyToken.getAccessToken().getBytes());
             this.sendMessage(serverId, registerMessage);
         } catch (Exception e) {
-            log.error("注册六合平台失败:{}", e.getMessage());
+            log.error("注册边缘服务器平台失败:{}", e.getMessage());
         }
         return true;
     }
@@ -472,7 +481,7 @@
      */
     @Override
     public UavState getUavState(String boxSn) {
-        return UavStateCache.getUavState(boxSn);
+        return UavStateCache.get(boxSn);
     }
 
     /**
@@ -480,7 +489,7 @@
      */
     @Override
     public TelemetryData getUavTelemetryData(String boxSn) {
-        return UavTelemetryDataCache.getUavTelemetryData(boxSn);
+        return UavTelemetryDataCache.get(boxSn);
     }
 
     /**
@@ -488,7 +497,7 @@
      */
     @Override
     public SignalInfo getSignalInfo(String boxSn) {
-        return UavSignalInfoCache.getUavSignalInfo(boxSn);
+        return UavSignalInfoCache.get(boxSn);
     }
 
     /**
@@ -651,7 +660,7 @@
     }
 
     /**
-     * 处理六合服务器返回的消息
+     * 处理边缘服务器返回的消息
      */
     @Override
     public void processReplyMessage(String key, BaseCmd tyCommand) {
@@ -669,8 +678,8 @@
                 break;
             case 0x02:
                 // 处理注册消息
-                 HeartbeatReplyCmd heartbeatReplyCmd = (HeartbeatReplyCmd) tyCommand;
-                 logPrint("心跳消息", heartbeatReplyCmd.getTimestamp());
+                HeartbeatReplyCmd heartbeatReplyCmd = (HeartbeatReplyCmd) tyCommand;
+                logPrint("心跳消息", heartbeatReplyCmd.getTimestamp());
                 break;
             case 0x03:
                 // 处理订阅消息
@@ -691,14 +700,14 @@
             case (byte) 0xA8:
                 // 处理无人机状态消息
                 UavStateCmd uavStateCmd = (UavStateCmd) tyCommand;
-                UavStateCache.putUavState(uavStateCmd.getUavState());
+                UavStateCache.put(uavStateCmd.getUavState());
                 //logPrint("无人机状态", uavStateCmd.getUavState().getBoxSn());
                 // WebSocketUtil.sendMessageAll(uavStateCmd.getUavState());
                 break;
             case (byte) 0xA9:
                 // 处理无人机遥测消息
                 UavTelemetryDataCmd uavTelemetryDataCmd = (UavTelemetryDataCmd) tyCommand;
-                UavTelemetryDataCache.putUavTelemetryData(uavTelemetryDataCmd.getTelemetryData());
+                UavTelemetryDataCache.put(uavTelemetryDataCmd.getTelemetryData());
                 //logPrint("无人机遥测", uavTelemetryDataCmd.getTelemetryData().getBoxSn());
                 //WebSocketUtil.sendMessageAll(uavTelemetryDataCmd.getTelemetryData());
                 break;
@@ -706,7 +715,7 @@
             case (byte) 0x0C:
                 // 处理无人机信道质量数据
                 SignalInfoCmd signalInfoCmd = (SignalInfoCmd) tyCommand;
-                UavSignalInfoCache.putUavSignalInfoCache(signalInfoCmd.getSignalInfo());
+                UavSignalInfoCache.put(signalInfoCmd.getSignalInfo());
                 //logPrint("无人机信道质量", signalInfoCmd.getSignalInfo().getBoxSn());
                 break;
             case (byte) 0xD1:
@@ -835,7 +844,7 @@
     }
 
     /**
-     * 根据[服务器id]获取六合盒子列表
+     * 根据[服务器id]获取边缘服务器盒子列表
      */
     @Override
     public List<BoxInfoReceiver> getBoxSnToList(String id) {
diff --git a/ard-work/src/main/resources/mapper/ArdDroneInfoMapper.xml b/ard-work/src/main/resources/mapper/ArdDroneInfoMapper.xml
index dafd26d..fdcc976 100644
--- a/ard-work/src/main/resources/mapper/ArdDroneInfoMapper.xml
+++ b/ard-work/src/main/resources/mapper/ArdDroneInfoMapper.xml
@@ -10,7 +10,7 @@
         <result property="boxName"    column="box_name"    />
         <result property="boxVersion"    column="box_version"    />
         <result property="startTime"    column="start_time"    />
-        <result property="onLine"    column="onLine"    />
+        <result property="onLine"    column="on_line"    />
         <result property="videoServer"    column="video_server"    />
         <result property="videoPort"    column="video_port"    />
         <result property="lastTaskId"    column="last_task_id"    />

--
Gitblit v1.9.3