From 04de920362c9dcc1cc6077b54acba8eeff5090fd Mon Sep 17 00:00:00 2001
From: zhaowenyu <35589726@qq.com>
Date: Thu, 05 Feb 2026 14:09:03 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev' into dev

---
 ard-inspection/src/main/java/com/ard/inspection/service/impl/BigFileUploadServiceImpl.java |  139 ++++++++++++
 ard-admin/src/main/java/com/ard/web/controller/inspection/BigFileUploadController.java     |   60 ++++
 ard-route/src/main/java/com/ard/route/domain/route/ArdRouteMission.java                    |   29 ++
 ard-work/src/main/java/com/ard/work/service/impl/TyServiceImpl.java                        |    3 
 ard-route/src/main/java/com/ard/route/service/impl/ArdRouteInfoServiceImpl.java            |    2 
 ard-route/src/main/java/com/ard/route/service/impl/ArdRouteMissionServiceImpl.java         |   40 +++
 ard-route/src/main/resources/mapper/ArdRouteMissionMapper.xml                              |   71 +++++-
 ard-route/pom.xml                                                                          |    5 
 ard-route/src/main/java/com/ard/route/websocket/handler/MiWebSocketHandler.java            |   39 +++
 ard-route/src/main/java/com/ard/route/websocket/utils/MiWebSocketUtils.java                |  131 +++++++++++
 ard-route/src/main/java/com/ard/route/websocket/interceptor/MiHandshakeInterceptor.java    |   32 ++
 ard-route/src/main/java/com/ard/route/mapper/ArdRouteMissionMapper.java                    |   11 
 ard-route/src/main/java/com/ard/route/service/IArdRouteMissionService.java                 |    9 
 ard-inspection/src/main/java/com/ard/inspection/service/IBigFileUploadService.java         |   42 +++
 ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteMissionController.java        |   11 +
 ard-route/src/main/java/com/ard/route/websocket/config/MiWebSocketConfig.java              |   28 ++
 16 files changed, 626 insertions(+), 26 deletions(-)

diff --git a/ard-admin/src/main/java/com/ard/web/controller/inspection/BigFileUploadController.java b/ard-admin/src/main/java/com/ard/web/controller/inspection/BigFileUploadController.java
index 9732383..d9ad474 100644
--- a/ard-admin/src/main/java/com/ard/web/controller/inspection/BigFileUploadController.java
+++ b/ard-admin/src/main/java/com/ard/web/controller/inspection/BigFileUploadController.java
@@ -1,18 +1,66 @@
 package com.ard.web.controller.inspection;
 
+import com.ard.common.annotation.Log;
 import com.ard.common.core.controller.BaseController;
-import io.lettuce.core.dynamic.annotation.Value;
+import com.ard.common.core.domain.AjaxResult;
+import com.ard.common.enums.BusinessType;
+import com.ard.inspection.service.IBigFileUploadService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import io.swagger.annotations.Api;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 
+import java.util.*;
+
+/**
+ * @author xia
+ */
 @Api(tags = "大文件上传")
 @RestController
 @RequestMapping("/inspection/bigfile")
+@Slf4j
 public class BigFileUploadController extends BaseController {
 
-    /** 若依文件上传根目录(从配置文件读取) */
-    //@Value("${ruoyi.profile}")
-    private String uploadRootDir;
+    @Autowired
+    private IBigFileUploadService bigFileUploadService;
+
+    @Value(value = "${inspection.profile}")
+    private String uploadPath;
+
+    @Value(value = "${inspection.chunk.path}")
+    private String chunkPath;
+
+    /**
+     * 检查分片是否存在
+     */
+    @GetMapping("/chunks/{fileMd5}")
+    public AjaxResult checkChunk(@PathVariable String fileMd5) {
+        Map<String, Object> result = bigFileUploadService.checkChunk(fileMd5,chunkPath);
+        return AjaxResult.success(result);
+    }
+
+    /**
+     * 上传分片
+     */
+    @PostMapping("/chunk")
+    public AjaxResult uploadChunk(@RequestParam("file") MultipartFile file,
+                                  @RequestParam("chunkNumber") Integer chunkNumber,
+                                  @RequestParam("fileMd5") String fileMd5) {
+        Map<String, Object> result = bigFileUploadService.uploadChunk(file, chunkNumber, fileMd5, chunkPath);
+        return AjaxResult.success(result);
+    }
+
+    /**
+     * 合并切片
+     */
+    @Log(title = "合并切片", businessType = BusinessType.IMPORT)
+    @PostMapping("/merge")
+    public AjaxResult mergeChunks(@RequestParam("md5") String md5,
+                                  @RequestParam("fileName") String fileName) {
+        Map<String, Object> result = bigFileUploadService.mergeChunks(md5, fileName, uploadPath);
+        return AjaxResult.success(result);
+    }
 
 }
diff --git a/ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteMissionController.java b/ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteMissionController.java
index 4a85722..e999013 100644
--- a/ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteMissionController.java
+++ b/ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteMissionController.java
@@ -105,4 +105,15 @@
         return toAjax(ardRouteMissionService.updateArdRouteMissionStatus(id,status));
     }
 
+    /**
+     * 批量修改航线任务已读状态
+     */
+    @ApiOperation("批量修改航线任务已读状态")
+    @Log(title = "航线任务", businessType = BusinessType.UPDATE)
+    @PutMapping("editIsRead/{ids}/{isRead}")
+    public AjaxResult editIsRead(@PathVariable String[] ids,
+                                 @PathVariable String isRead) {
+        return toAjax(ardRouteMissionService.updateIsRead(ids,isRead));
+    }
+
 }
diff --git a/ard-inspection/src/main/java/com/ard/inspection/service/IBigFileUploadService.java b/ard-inspection/src/main/java/com/ard/inspection/service/IBigFileUploadService.java
new file mode 100644
index 0000000..276ed75
--- /dev/null
+++ b/ard-inspection/src/main/java/com/ard/inspection/service/IBigFileUploadService.java
@@ -0,0 +1,42 @@
+package com.ard.inspection.service;
+
+
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.Map;
+
+public interface IBigFileUploadService {
+
+    /**
+     * 检查分片是否存在
+     *
+     * @param fileMd5 fileMd5
+     * @param chunkPath 切片临时目录
+     */
+    public Map<String, Object> checkChunk(String fileMd5, String chunkPath);
+
+    /**
+     * 上传分片
+     *
+     * @param file 文件
+     * @param chunkNumber chunkNumber
+     * @param fileMd5 fileMd5
+     * @param chunkPath 切片临时目录
+     */
+    public Map<String, Object> uploadChunk(MultipartFile file,
+                              Integer chunkNumber,
+                              String fileMd5,
+                              String chunkPath);
+
+    /**
+     * 合并切片
+     *
+     * @param md5 文件MD5
+     * @param fileName 原始文件名
+     * @param uploadPath 上传文件存储路径
+     */
+    public Map<String, Object> mergeChunks(String md5,
+                                           String fileName,
+                                           String uploadPath);
+
+}
diff --git a/ard-inspection/src/main/java/com/ard/inspection/service/impl/BigFileUploadServiceImpl.java b/ard-inspection/src/main/java/com/ard/inspection/service/impl/BigFileUploadServiceImpl.java
new file mode 100644
index 0000000..0daf7a3
--- /dev/null
+++ b/ard-inspection/src/main/java/com/ard/inspection/service/impl/BigFileUploadServiceImpl.java
@@ -0,0 +1,139 @@
+package com.ard.inspection.service.impl;
+
+import com.ard.inspection.service.IBigFileUploadService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author xia
+ */
+@Service
+@Slf4j
+public class BigFileUploadServiceImpl implements IBigFileUploadService {
+
+    @Override
+    public Map<String, Object> checkChunk(String fileMd5,String chunkPath) {
+        Map<String, Object> result = new HashMap<>();
+        try {
+            File chunkFolder = new File(chunkPath + File.separator + fileMd5);
+            if (!chunkFolder.exists()) {
+                result.put("exception", "分片不存在!!!");
+                return result;
+            }
+
+            File[] chunks = chunkFolder.listFiles();
+            if (chunks == null || chunks.length == 0) {
+                result.put("exception", "无分片!!!");
+                return result;
+            }
+
+            List<Integer> uploadedChunks = Arrays.stream(chunks)
+                    .map(file -> Integer.parseInt(file.getName().split("\\.")[0]))
+                    .collect(Collectors.toList());
+            result.put("message", uploadedChunks);
+            return result;
+        } catch (Exception e) {
+            log.error("检查分片失败", e);
+            result.put("exception", "检查分片失败!!!");
+            return result;
+        }
+    }
+
+    @Override
+    public Map<String, Object> uploadChunk(MultipartFile file,
+                              Integer chunkNumber,
+                              String fileMd5,
+                              String chunkPath) {
+        Map<String, Object> result = new HashMap<>();
+        try {
+            // 验证参数
+            if (file.isEmpty()) {
+                result.put("exception", "文件不能为空!!!");
+                return result;
+            }
+
+            // 创建分片目录
+            String chunkDirPath = chunkPath + File.separator + fileMd5;
+            File chunkDir = new File(chunkDirPath);
+            if (!chunkDir.exists()) {
+                chunkDir.mkdirs();
+            }
+
+            // 保存分片
+            String chunkFileName = chunkNumber + ".part";
+            File chunkFile = new File(chunkDir, chunkFileName);
+            file.transferTo(chunkFile);
+
+            result.put("message", "分片上传成功!!!");
+            return result;
+        } catch (IOException e) {
+            log.error("分片上传失败", e);
+            result.put("exception", "分片上传失败!!!");
+            return result;
+        }
+    }
+
+    @Override
+    public Map<String, Object> mergeChunks(String md5,String fileName,String uploadPath) {
+        Map<String, Object> result = new HashMap<>();
+        // 临时目录
+        String chunkDir = uploadPath + File.separator + md5;
+        File dir = new File(chunkDir);
+        if (!dir.exists()) {
+            result.put("exception", "切片目录不存在");
+            return result;
+        }
+        // 获取所有切片文件
+        File[] chunks = dir.listFiles();
+        if (chunks == null || chunks.length == 0) {
+            result.put("exception", "没有切片文件");
+            return result;
+        }
+        // 按照切片索引排序
+        Arrays.sort(chunks, (a, b) -> {
+            int aIndex = Integer.parseInt(a.getName().split("\\.")[0]);
+            int bIndex = Integer.parseInt(b.getName().split("\\.")[0]);
+            return aIndex - bIndex;
+        });
+
+        // 合并后的文件,这里使用原始文件名,为了避免重名,可以加上时间戳或使用UUID
+        // 这里根据业务需求,可以保存到数据库,记录文件路径等信息
+        String ext = fileName.substring(fileName.lastIndexOf("."));
+        String newFileName = UUID.randomUUID().toString().replace("-", "") + ext; // 生成新文件名
+        File mergeFile = new File(uploadPath, newFileName);
+
+        try (RandomAccessFile randomAccessFile = new RandomAccessFile(mergeFile, "rw")) {
+            byte[] buffer = new byte[1024 * 1024]; // 1MB缓冲区
+            for (File chunk : chunks) {
+                try (RandomAccessFile chunkFile = new RandomAccessFile(chunk, "r")) {
+                    int len;
+                    while ((len = chunkFile.read(buffer)) != -1) {
+                        randomAccessFile.write(buffer, 0, len);
+                    }
+                }
+                // 删除切片文件
+                chunk.delete();
+            }
+            // 删除临时目录
+            dir.delete();
+        } catch (IOException e) {
+            log.error("合并文件失败", e);
+            result.put("exception", "合并文件失败");
+            return result;
+        }
+
+        // 这里可以保存文件信息到数据库,例如文件路径、文件名、md5等
+        // fileService.saveFileInfo(...);
+
+        result.put("message", "文件合并成功");
+        return result;
+    }
+
+}
diff --git a/ard-route/pom.xml b/ard-route/pom.xml
index 4bdfa32..fad44dd 100644
--- a/ard-route/pom.xml
+++ b/ard-route/pom.xml
@@ -59,6 +59,11 @@
             <groupId>com.ard</groupId>
             <artifactId>ard-work</artifactId>
         </dependency>
+        <!--websocket依赖-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
+        </dependency>
 
     </dependencies>
 
diff --git a/ard-route/src/main/java/com/ard/route/domain/route/ArdRouteMission.java b/ard-route/src/main/java/com/ard/route/domain/route/ArdRouteMission.java
index 8edb55d..77f6194 100644
--- a/ard-route/src/main/java/com/ard/route/domain/route/ArdRouteMission.java
+++ b/ard-route/src/main/java/com/ard/route/domain/route/ArdRouteMission.java
@@ -33,11 +33,23 @@
      */
     private String executeStatus;
 
-    /** 执行人 */
-    private String executeBy;
+    /** 执行人ID */
+    private Long executeId;
+
+    /** 执行人姓名 */
+    private String executeName;
 
     /** 执行时间 */
     private Date executeTime;
+
+    /** 下发人ID */
+    private Long issuerId;
+
+    /** 下发人姓名 */
+    private String issuerName;
+
+    /** 下发时间 */
+    private Date issuerTime;
 
     /**
      * 任务类型
@@ -46,10 +58,17 @@
      * */
     private String taskType;
 
-    /** 航线任务航点列表 */
-    private List<ArdRoutePoint> missionDetailList;
-
     /** 任务描述 */
     private String taskDescription;
 
+    /**
+     * 是否已读
+     * 0:否
+     * 1:是
+     * */
+    private String isRead;
+
+    /** 航线任务航点列表 */
+    private List<ArdRoutePoint> missionDetailList;
+
 }
diff --git a/ard-route/src/main/java/com/ard/route/mapper/ArdRouteMissionMapper.java b/ard-route/src/main/java/com/ard/route/mapper/ArdRouteMissionMapper.java
index 9d02438..2d55ae3 100644
--- a/ard-route/src/main/java/com/ard/route/mapper/ArdRouteMissionMapper.java
+++ b/ard-route/src/main/java/com/ard/route/mapper/ArdRouteMissionMapper.java
@@ -68,6 +68,15 @@
      * @param executeStatus 状态类型
      * @return 结果
      */
-    public int updateArdRouteMissionStatus(@Param("id")String id, @Param("executeStatus")String executeStatus);
+    public int updateArdRouteMissionStatus(@Param("id")String id,@Param("executeStatus")String executeStatus);
+
+    /**
+     * 批量修改航线任务已读状态
+     *
+     * @param ids 主键集合
+     * @param isRead 已读状态
+     * @return 结果
+     */
+    public int updateIsRead(@Param("id")String[] ids,@Param("isRead")String isRead);
 
 }
diff --git a/ard-route/src/main/java/com/ard/route/service/IArdRouteMissionService.java b/ard-route/src/main/java/com/ard/route/service/IArdRouteMissionService.java
index b41bdcb..e2e55d4 100644
--- a/ard-route/src/main/java/com/ard/route/service/IArdRouteMissionService.java
+++ b/ard-route/src/main/java/com/ard/route/service/IArdRouteMissionService.java
@@ -69,4 +69,13 @@
      */
     public int updateArdRouteMissionStatus(String id,String status);
 
+    /**
+     * 批量修改航线任务已读状态
+     *
+     * @param ids 主键集合
+     * @param isRead 已读状态
+     * @return 结果
+     */
+    public int updateIsRead(String[] ids,String isRead);
+
 }
diff --git a/ard-route/src/main/java/com/ard/route/service/impl/ArdRouteInfoServiceImpl.java b/ard-route/src/main/java/com/ard/route/service/impl/ArdRouteInfoServiceImpl.java
index 136018d..f6859f7 100644
--- a/ard-route/src/main/java/com/ard/route/service/impl/ArdRouteInfoServiceImpl.java
+++ b/ard-route/src/main/java/com/ard/route/service/impl/ArdRouteInfoServiceImpl.java
@@ -198,7 +198,7 @@
         if ("0".equals(mission.getExecuteStatus())) {
             mission.setRouteId(ardRouteInfo.getId());
             mission.setExecuteStatus("1");
-            mission.setExecuteBy(SecurityUtils.getUsername());
+            mission.setExecuteName(SecurityUtils.getUsername());
             mission.setExecuteTime(DateUtils.getNowDate());
             mission.setUpdateTime(DateUtils.getNowDate());
             ardRouteMissionMapper.updateArdRouteMission(mission);
diff --git a/ard-route/src/main/java/com/ard/route/service/impl/ArdRouteMissionServiceImpl.java b/ard-route/src/main/java/com/ard/route/service/impl/ArdRouteMissionServiceImpl.java
index f3e54d2..e23626c 100644
--- a/ard-route/src/main/java/com/ard/route/service/impl/ArdRouteMissionServiceImpl.java
+++ b/ard-route/src/main/java/com/ard/route/service/impl/ArdRouteMissionServiceImpl.java
@@ -1,18 +1,23 @@
 package com.ard.route.service.impl;
 
 import java.util.List;
+
+import com.alibaba.fastjson2.JSON;
+import com.ard.common.core.domain.entity.SysUser;
 import com.ard.common.utils.DateUtils;
 import com.ard.common.utils.SecurityUtils;
 import com.ard.common.utils.uuid.IdUtils;
 import com.ard.route.domain.route.ArdRouteMission;
 import com.ard.route.domain.route.ArdRoutePoint;
 import com.ard.route.mapper.ArdRoutePointMapper;
+import com.ard.route.websocket.utils.MiWebSocketUtils;
+import com.ard.system.mapper.SysUserMapper;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.ard.route.mapper.ArdRouteMissionMapper;
 import com.ard.route.service.IArdRouteMissionService;
 
-import static com.ard.common.utils.SecurityUtils.getUsername;
 
 /**
  * 航线任务Service业务层处理
@@ -21,6 +26,7 @@
  * @date 2026-01-20
  */
 @Service
+@Slf4j
 public class ArdRouteMissionServiceImpl implements IArdRouteMissionService {
 
     @Autowired
@@ -28,6 +34,9 @@
 
     @Autowired
     private ArdRoutePointMapper ardRoutePointMapper;
+
+    @Autowired
+    private SysUserMapper sysUserMapper;
 
     /**
      * 查询航线任务
@@ -71,8 +80,16 @@
     public int insertArdRouteMission(ArdRouteMission ardRouteMission) {
         ardRouteMission.setId(IdUtils.simpleUUID());
         ardRouteMission.setExecuteStatus("0");
+        ardRouteMission.setIsRead("0");
         ardRouteMission.setCreateTime(DateUtils.getNowDate());
+        ardRouteMission.setIssuerName(getUserName(ardRouteMission.getIssuerId()));
         dataProcessingRoutePoint(ardRouteMission.getMissionDetailList(),ardRouteMission.getId());
+        try {
+            log.debug("给用户{}定时推送,航线任务信息", ardRouteMission.getIssuerName());
+            MiWebSocketUtils.sendMessage(ardRouteMission.getIssuerId(),JSON.toJSONString(ardRouteMission));
+        } catch (Exception e) {
+            log.error("Error sending message to session {}", ardRouteMission.getIssuerName(), e);
+        }
         return ardRouteMissionMapper.insertArdRouteMission(ardRouteMission);
     }
 
@@ -85,11 +102,18 @@
     @Override
     public int updateArdRouteMission(ArdRouteMission ardRouteMission) {
         ardRouteMission.setUpdateTime(DateUtils.getNowDate());
+        ardRouteMission.setIssuerName(getUserName(ardRouteMission.getIssuerId()));
         // 删除航线任务航点
         ardRoutePointMapper.deleteArdRoutePointByMissionId(ardRouteMission.getId());
         // 重新插入航线任务航点
         dataProcessingRoutePoint(ardRouteMission.getMissionDetailList(),ardRouteMission.getId());
         return ardRouteMissionMapper.updateArdRouteMission(ardRouteMission);
+    }
+
+    // 获取用户名称
+    private String getUserName(Long userId) {
+        SysUser sysUser = sysUserMapper.selectUserById(userId);
+        return sysUser.getUserName();
     }
 
     /**
@@ -139,10 +163,22 @@
         ArdRouteMission ardRouteMission = new ArdRouteMission();
         ardRouteMission.setId(id);
         ardRouteMission.setExecuteStatus(status);
-        ardRouteMission.setExecuteBy(SecurityUtils.getUsername());
+        ardRouteMission.setExecuteName(SecurityUtils.getUsername());
         ardRouteMission.setExecuteTime(DateUtils.getNowDate());
         ardRouteMission.setUpdateTime(DateUtils.getNowDate());
         return ardRouteMissionMapper.updateArdRouteMission(ardRouteMission);
     }
 
+    /**
+     * 批量修改航线任务已读状态
+     *
+     * @param ids 主键集合
+     * @param isRead 已读状态
+     * @return 结果
+     */
+    @Override
+    public int updateIsRead(String[] ids, String isRead) {
+        return ardRouteMissionMapper.updateIsRead(ids,isRead);
+    }
+
 }
diff --git a/ard-route/src/main/java/com/ard/route/websocket/config/MiWebSocketConfig.java b/ard-route/src/main/java/com/ard/route/websocket/config/MiWebSocketConfig.java
new file mode 100644
index 0000000..d207936
--- /dev/null
+++ b/ard-route/src/main/java/com/ard/route/websocket/config/MiWebSocketConfig.java
@@ -0,0 +1,28 @@
+package com.ard.route.websocket.config;
+
+import com.ard.route.websocket.handler.MiWebSocketHandler;
+import com.ard.route.websocket.interceptor.MiHandshakeInterceptor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.socket.config.annotation.EnableWebSocket;
+import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
+import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
+
+import javax.annotation.Resource;
+
+@Configuration
+@EnableWebSocket
+public class MiWebSocketConfig implements WebSocketConfigurer {
+
+    @Resource
+    private MiWebSocketHandler miWebSocketHandler;
+
+    @Override
+    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
+        //添加myWebSocketHandler消息处理对象以及websocket连接地址
+        registry.addHandler(miWebSocketHandler, "/ws/mission/**")
+                //设置允许跨域访问
+                .setAllowedOrigins("*")
+                //添加拦截器可实现用户链接前进行权限校验等操作
+                .addInterceptors(new MiHandshakeInterceptor());
+    }
+}
diff --git a/ard-route/src/main/java/com/ard/route/websocket/handler/MiWebSocketHandler.java b/ard-route/src/main/java/com/ard/route/websocket/handler/MiWebSocketHandler.java
new file mode 100644
index 0000000..9228529
--- /dev/null
+++ b/ard-route/src/main/java/com/ard/route/websocket/handler/MiWebSocketHandler.java
@@ -0,0 +1,39 @@
+package com.ard.route.websocket.handler;
+
+import com.ard.route.websocket.utils.MiWebSocketUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.web.socket.CloseStatus;
+import org.springframework.web.socket.TextMessage;
+import org.springframework.web.socket.WebSocketSession;
+import org.springframework.web.socket.handler.TextWebSocketHandler;
+
+@Component
+@Slf4j
+public class MiWebSocketHandler extends TextWebSocketHandler {
+
+    @Override
+    public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
+        // 处理接收到的消息
+        String payload = message.getPayload();
+        log.info("【mi_websocket】Received message: " + payload);
+        log.info("【mi_websocket】size: " + MiWebSocketUtils.ONLINE_USER_SESSIONS.size());
+    }
+
+    @Override
+    public void afterConnectionEstablished(WebSocketSession session) {
+        log.info("【mi_websocket】Connected: " + session.getId());
+        String userId = (String) session.getAttributes().get("userId");
+        MiWebSocketUtils.ONLINE_USER_SESSIONS.put(userId, session);
+        log.info("【mi_websocket】size: " + MiWebSocketUtils.ONLINE_USER_SESSIONS.size());
+    }
+
+    @Override
+    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
+        log.info("【mi_websocket】Disconnected: " + session.getId());
+        String userId = (String) session.getAttributes().get("userId");
+        MiWebSocketUtils.ONLINE_USER_SESSIONS.remove(userId);
+        log.info("【mi_websocket】size: " + MiWebSocketUtils.ONLINE_USER_SESSIONS.size());
+    }
+
+}
diff --git a/ard-route/src/main/java/com/ard/route/websocket/interceptor/MiHandshakeInterceptor.java b/ard-route/src/main/java/com/ard/route/websocket/interceptor/MiHandshakeInterceptor.java
new file mode 100644
index 0000000..9d29610
--- /dev/null
+++ b/ard-route/src/main/java/com/ard/route/websocket/interceptor/MiHandshakeInterceptor.java
@@ -0,0 +1,32 @@
+package com.ard.route.websocket.interceptor;
+
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.web.socket.WebSocketHandler;
+
+import java.util.Map;
+
+public class MiHandshakeInterceptor implements org.springframework.web.socket.server.HandshakeInterceptor {
+    @Override
+    public boolean beforeHandshake(ServerHttpRequest request,
+                                   ServerHttpResponse response,
+                                   WebSocketHandler wsHandler,
+                                   Map<String, Object> attributes) throws Exception {
+        //从路径中获取userId
+        String path = request.getURI().getPath();
+        String[] segments = path.split("/");
+        if (segments.length > 2) {
+            String userId = segments[segments.length - 1];
+            attributes.put("userId", userId);
+        }
+        return true;
+    }
+
+    @Override
+    public void afterHandshake(ServerHttpRequest request,
+                               ServerHttpResponse response,
+                               WebSocketHandler wsHandler,
+                               Exception exception) {
+
+    }
+}
diff --git a/ard-route/src/main/java/com/ard/route/websocket/utils/MiWebSocketUtils.java b/ard-route/src/main/java/com/ard/route/websocket/utils/MiWebSocketUtils.java
new file mode 100644
index 0000000..eae6628
--- /dev/null
+++ b/ard-route/src/main/java/com/ard/route/websocket/utils/MiWebSocketUtils.java
@@ -0,0 +1,131 @@
+package com.ard.route.websocket.utils;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.ard.work.component.websocket.WebSocketSessionManager;
+import com.ard.work.component.websocket.utils.WebSocketUtil;
+import com.ard.work.domain.message.BaseMessage;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.socket.TextMessage;
+import org.springframework.web.socket.WebSocketSession;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+@Slf4j
+public class MiWebSocketUtils {
+
+    // 用于存储所有打开的WebSocket会话
+    public static final ConcurrentMap<String, WebSocketSession> ONLINE_USER_SESSIONS = new ConcurrentHashMap<>();
+
+    /**
+     * @param session 用户 session
+     * @param message 发送内容
+     */
+    public static void sendMessage(WebSocketSession session, String message) {
+        if (session == null) {
+            return;
+        }
+        final InetSocketAddress remoteAddress = session.getRemoteAddress();
+        if (remoteAddress == null) {
+            return;
+        }
+        synchronized (session) {
+            try {
+                log.debug("发送消息:" + message);
+                session.sendMessage(new TextMessage(String.join(", ", message)));
+            } catch (IOException e) {
+                log.error("sendMessage IOException ", e);
+            }
+        }
+    }
+
+    public static void sendMessage(Long userId, String message) {
+        WebSocketSession session = WebSocketSessionManager.getSession(userId);
+        sendMessage(session, message);
+    }
+
+    /**
+     * @param session 用户 session
+     * @param message 发送内容
+     */
+    public static void sendMessage(WebSocketSession session, Map message) {
+        if (session == null) {
+            return;
+        }
+        final InetSocketAddress remoteAddress = session.getRemoteAddress();
+        if (remoteAddress == null) {
+            return;
+        }
+        synchronized (session) {
+            try {
+                session.sendMessage(new TextMessage(JSONObject.toJSONString(message)));
+            } catch (IOException e) {
+                log.error("sendMessage IOException ", e);
+            }
+        }
+    }
+
+    public static void sendMessage(WebSocketSession session, List message) {
+        if (session == null) {
+            return;
+        }
+        final InetSocketAddress remoteAddress = session.getRemoteAddress();
+        if (remoteAddress == null) {
+            return;
+        }
+        synchronized (session) {
+            try {
+                session.sendMessage(new TextMessage(JSONObject.toJSONString(message)));
+            } catch (IOException e) {
+                log.error("sendMessage IOException ", e);
+            }
+        }
+    }
+
+    /**
+     * 推送消息到其他客户端
+     *
+     * @param message
+     */
+    public static void sendMessageAll(String message) {
+        ONLINE_USER_SESSIONS.forEach((sessionId, session) -> sendMessage(session, message));
+    }
+
+    /**
+     * 推送消息到其他客户端
+     *
+     * @param message
+     */
+    public static void sendMessageAll(Map message) {
+        JSONObject jsonObject = new JSONObject(message);
+        ONLINE_USER_SESSIONS.forEach((sessionId, session) -> sendMessage(session, jsonObject.toString()));
+    }
+
+    /**
+     * 推送消息到其他客户端
+     *
+     * @param message
+     */
+    public static void sendMessageAll(List message) {
+        ONLINE_USER_SESSIONS.forEach((sessionId, session) -> sendMessage(session, JSON.toJSONString(message)));
+    }
+
+    // 发送消息到所有 WebSocket 客户端
+    public static <T> void sendToAll(BaseMessage<T> baseMessage) {
+        WebSocketUtil.sendMessageAll(baseMessage);  // 你已有的 WebSocket 发送逻辑
+    }
+
+    // 根据消息类型和内容创建消息并发送
+    public static <T> void sendMessage(String type, T payload) {
+        BaseMessage<T> baseMessage = BaseMessage.<T>builder()
+                .type(type)
+                .payload(payload)
+                .build();
+        sendToAll(baseMessage);
+    }
+}
diff --git a/ard-route/src/main/resources/mapper/ArdRouteMissionMapper.xml b/ard-route/src/main/resources/mapper/ArdRouteMissionMapper.xml
index 895f203..b3c6aef 100644
--- a/ard-route/src/main/resources/mapper/ArdRouteMissionMapper.xml
+++ b/ard-route/src/main/resources/mapper/ArdRouteMissionMapper.xml
@@ -13,10 +13,15 @@
         <result property="createTime"    column="create_time"    />
         <result property="updateBy"    column="update_by"    />
         <result property="updateTime"    column="update_time"    />
-        <result property="executeBy"    column="execute_by"    />
+        <result property="executeId"    column="execute_id"    />
+        <result property="executeName"    column="execute_name"    />
         <result property="executeTime"    column="execute_time"    />
+        <result property="issuerId"    column="issuer_id"    />
+        <result property="issuerName"    column="issuer_name"    />
+        <result property="issuerTime"    column="issuer_time"    />
         <result property="taskType"    column="task_type"    />
         <result property="taskDescription"    column="task_description"    />
+        <result property="isRead"    column="is_read"    />
     </resultMap>
 
     <sql id="selectArdRouteMissionVo">
@@ -28,22 +33,32 @@
                create_time,
                update_by,
                update_time,
-               execute_by,
+               execute_id,
+               execute_name,
                execute_time,
                task_type,
-               task_description
+               task_description,
+               is_read,
+               issuer_id,
+               issuer_name,
+               issuer_time
         from ard_route_mission
     </sql>
 
     <select id="selectArdRouteMissionList" parameterType="ArdRouteMission" resultMap="ArdRouteMissionResult">
         <include refid="selectArdRouteMissionVo"/>
         <where>  
-            <if test="routeId != null  and routeId != ''"> and route_id = #{routeId}</if>
-            <if test="missionName != null  and missionName != ''"> and mission_name like concat('%', #{missionName}, '%')</if>
-            <if test="executeStatus != null  and executeStatus != ''"> and execute_status = #{executeStatus}</if>
-            <if test="executeBy != null  and executeBy != ''"> and execute_by = #{executeBy}</if>
+            <if test="routeId != null and routeId != ''"> and route_id = #{routeId}</if>
+            <if test="missionName != null and missionName != ''"> and mission_name like concat('%', #{missionName}, '%')</if>
+            <if test="executeStatus != null and executeStatus != ''"> and execute_status = #{executeStatus}</if>
+            <if test="executeId != null and executeId != ''"> and execute_id = #{executeId}</if>
+            <if test="executeName != null and executeName != ''"> and execute_name like concat('%', #{executeName}, '%')</if>
             <if test="executeTime != null "> and execute_time = #{executeTime}</if>
-            <if test="taskType != null  and taskType != ''"> and task_type = #{taskType}</if>
+            <if test="issuerId != null and issuerId != ''"> and issuer_id = #{issuerId}</if>
+            <if test="issuerName != null and issuerName != ''"> and issuer_name like concat('%', #{issuerName}, '%')</if>
+            <if test="issuerTime != null "> and issuer_time = #{issuerTime}</if>
+            <if test="taskType != null and taskType != ''"> and task_type = #{taskType}</if>
+            <if test="isRead != null and isRead != ''"> and is_read = #{isRead}</if>
         </where>
         order by create_time DESC
     </select>
@@ -65,10 +80,15 @@
             <if test="createTime != null">create_time,</if>
             <if test="updateBy != null">update_by,</if>
             <if test="updateTime != null">update_time,</if>
-            <if test="executeBy != null">execute_by,</if>
+            <if test="executeId != null">execute_id,</if>
+            <if test="executeName != null">execute_name,</if>
             <if test="executeTime != null">execute_time,</if>
+            <if test="issuerId != null">issuer_id,</if>
+            <if test="issuerName != null">issuer_name,</if>
+            <if test="issuerTime != null">issuer_time,</if>
             <if test="taskType != null">task_type,</if>
             <if test="taskDescription != null">task_description,</if>
+            <if test="isRead != null">is_read,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="id != null">#{id},</if>
@@ -79,10 +99,15 @@
             <if test="createTime != null">#{createTime},</if>
             <if test="updateBy != null">#{updateBy},</if>
             <if test="updateTime != null">#{updateTime},</if>
-            <if test="executeBy != null">#{executeBy},</if>
+            <if test="executeId != null">#{executeId},</if>
+            <if test="executeName != null">#{executeName},</if>
             <if test="executeTime != null">#{executeTime},</if>
+            <if test="issuerId != null">#{issuerId},</if>
+            <if test="issuerName != null">#{issuerName},</if>
+            <if test="issuerTime != null">#{issuerTime},</if>
             <if test="taskType != null">#{taskType},</if>
             <if test="taskDescription != null">#{taskDescription},</if>
+            <if test="isRead != null">#{isRead},</if>
          </trim>
     </insert>
 
@@ -96,10 +121,15 @@
             <if test="createTime != null">create_time = #{createTime},</if>
             <if test="updateBy != null">update_by = #{updateBy},</if>
             <if test="updateTime != null">update_time = #{updateTime},</if>
-            <if test="executeBy != null">execute_by = #{executeBy},</if>
+            <if test="executeId != null">execute_id = #{executeId},</if>
+            <if test="executeName != null">execute_name = #{executeName},</if>
             <if test="executeTime != null">execute_time = #{executeTime},</if>
+            <if test="issuerId != null">issuer_id = #{issuerId},</if>
+            <if test="issuerName != null">issuer_name = #{issuerName},</if>
+            <if test="issuerTime != null">issuer_time = #{issuerTime},</if>
             <if test="taskType != null">task_type = #{taskType},</if>
             <if test="taskDescription != null">task_description = #{taskDescription},</if>
+            <if test="isRead != null">is_read = #{isRead},</if>
         </trim>
         where id = #{id}
     </update>
@@ -123,4 +153,23 @@
         where id = #{id}
     </update>
 
+    <update id="updateArdRouteMissionStatus">
+        update ard_route_mission
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="executeStatus != null">execute_status = #{executeStatus},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <update id="updateIsRead">
+        update ard_route_mission
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="isRead != null">is_read = #{isRead},</if>
+        </trim>
+        where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </update>
+
 </mapper>
\ No newline at end of file
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 ed5d4bb..f03d7c3 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
@@ -637,6 +637,9 @@
     /**
      * 环绕飞行控制
      */
+//    @CheckControlRight(UavControlType.FLY)
+//    @CheckTakeoffAltitude
+//    @CheckNoFlyZone
     @Override
     public Boolean FlyRoundControl(FlyRoundControlDTO flyRoundControlDTO) {
         String boxSn = flyRoundControlDTO.getBoxSn();

--
Gitblit v1.9.3