zhaowenyu
2026-03-07 d7fef91a4cbb702988dc820bcde82c166253ceec
Merge remote-tracking branch 'origin/dev' into dev
10 files added
17 files modified
1131 ■■■■■ changed files
ard-admin/src/main/java/com/ard/web/controller/inspection/ArdInspectionGroupController.java 12 ●●●●● patch | view | raw | blame | history
ard-admin/src/main/java/com/ard/web/controller/inspection/ArdPointCloudController.java 113 ●●●●● patch | view | raw | blame | history
ard-admin/src/main/java/com/ard/web/controller/inspection/BigFileUploadController.java 48 ●●●●● patch | view | raw | blame | history
ard-admin/src/main/resources/application.yml 13 ●●●●● patch | view | raw | blame | history
ard-framework/src/main/java/com/ard/framework/config/SecurityConfig.java 2 ●●●●● patch | view | raw | blame | history
ard-inspection/pom.xml 6 ●●●●● patch | view | raw | blame | history
ard-inspection/src/main/java/com/ard/inspection/domain/ArdInspectionGroup.java 25 ●●●●● patch | view | raw | blame | history
ard-inspection/src/main/java/com/ard/inspection/domain/ArdPointCloud.java 62 ●●●●● patch | view | raw | blame | history
ard-inspection/src/main/java/com/ard/inspection/domain/UploadFileEntity.java 19 ●●●●● patch | view | raw | blame | history
ard-inspection/src/main/java/com/ard/inspection/mapper/ArdInspectionGroupMapper.java 12 ●●●●● patch | view | raw | blame | history
ard-inspection/src/main/java/com/ard/inspection/mapper/ArdPointCloudMapper.java 64 ●●●●● patch | view | raw | blame | history
ard-inspection/src/main/java/com/ard/inspection/service/IArdPointCloudService.java 64 ●●●●● patch | view | raw | blame | history
ard-inspection/src/main/java/com/ard/inspection/service/IBigFileUploadService.java 21 ●●●●● patch | view | raw | blame | history
ard-inspection/src/main/java/com/ard/inspection/service/impl/ArdInspectionGroupServiceImpl.java 16 ●●●●● patch | view | raw | blame | history
ard-inspection/src/main/java/com/ard/inspection/service/impl/ArdPointCloudServiceImpl.java 116 ●●●●● patch | view | raw | blame | history
ard-inspection/src/main/java/com/ard/inspection/service/impl/BigFileUploadServiceImpl.java 134 ●●●●● patch | view | raw | blame | history
ard-inspection/src/main/java/com/ard/inspection/service/impl/StaticResourceConfig.java 17 ●●●●● patch | view | raw | blame | history
ard-inspection/src/main/java/com/ard/inspection/utils/ZipFileUtils.java 135 ●●●●● patch | view | raw | blame | history
ard-inspection/src/main/resources/mapper/ArdInspectionGroupMapper.xml 51 ●●●●● patch | view | raw | blame | history
ard-inspection/src/main/resources/mapper/ArdPointCloudMapper.xml 133 ●●●●● patch | view | raw | blame | history
ard-route/src/main/java/com/ard/route/domain/djuav/RoutePointReq.java 16 ●●●●● patch | view | raw | blame | history
ard-route/src/main/java/com/ard/route/domain/djuav/TargetPosObj.java 29 ●●●●● patch | view | raw | blame | history
ard-route/src/main/java/com/ard/route/domain/djuav/WaypointTurnReq.java 1 ●●●●● patch | view | raw | blame | history
ard-route/src/main/java/com/ard/route/domain/route/ArdRouteInfo.java 9 ●●●●● patch | view | raw | blame | history
ard-route/src/main/java/com/ard/route/util/InitializationUtils.java 2 ●●●●● patch | view | raw | blame | history
ard-route/src/main/java/com/ard/route/util/ToolUtils.java 4 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/websocket/handler/TyMessageHandler.java 7 ●●●●● patch | view | raw | blame | history
ard-admin/src/main/java/com/ard/web/controller/inspection/ArdInspectionGroupController.java
@@ -39,7 +39,7 @@
     * 查询精细化巡检分组列表
     */
    @ApiOperation("查询精细化巡检分组列表")
    @PreAuthorize("@ss.hasPermi('inspection:group:list')")
    //@PreAuthorize("@ss.hasPermi('inspection:group:list')")
    @GetMapping("/list")
    public AjaxResult list(ArdInspectionGroup ardInspectionGroup) {
        List<ArdInspectionGroup> list = ardInspectionGroupService.selectArdInspectionGroupList(ardInspectionGroup);
@@ -50,7 +50,7 @@
     * 获取精细化巡检分组详细信息
     */
    @ApiOperation("获取精细化巡检分组详细信息")
    @PreAuthorize("@ss.hasPermi('inspection:group:query')")
    //@PreAuthorize("@ss.hasPermi('inspection:group:query')")
    @GetMapping(value = "/{groupId}")
    public AjaxResult getInfo(@PathVariable("groupId") Long groupId) {
        //ardInspectionGroupService.checkInspectionGroupDataScope(groupId);
@@ -61,7 +61,7 @@
     * 新增精细化巡检分组
     */
    @ApiOperation("新增精细化巡检分组")
    @PreAuthorize("@ss.hasPermi('inspection:group:add')")
    //@PreAuthorize("@ss.hasPermi('inspection:group:add')")
    @Log(title = "精细化巡检分组", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody ArdInspectionGroup ardInspectionGroup) {
@@ -76,7 +76,7 @@
     * 修改精细化巡检分组
     */
    @ApiOperation("修改精细化巡检分组")
    @PreAuthorize("@ss.hasPermi('inspection:group:edit')")
    //@PreAuthorize("@ss.hasPermi('inspection:group:edit')")
    @Log(title = "精细化巡检分组", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody ArdInspectionGroup ardInspectionGroup) {
@@ -95,7 +95,7 @@
     * 删除精细化巡检分组
     */
    @ApiOperation("删除精细化巡检分组")
    @PreAuthorize("@ss.hasPermi('inspection:group:remove')")
    //@PreAuthorize("@ss.hasPermi('inspection:group:remove')")
    @Log(title = "精细化巡检分组", businessType = BusinessType.DELETE)
    @DeleteMapping("/{groupId}")
    public AjaxResult remove(@PathVariable Long groupId) {
@@ -113,7 +113,7 @@
     * 获取巡检分组树列表
     */
    @ApiOperation("获取巡检分组树列表")
    @PreAuthorize("@ss.hasPermi('inspection:group:groupTree')")
    //@PreAuthorize("@ss.hasPermi('inspection:group:groupTree')")
    @GetMapping("/groupTree")
    public AjaxResult deptTree(ArdInspectionGroup ardInspectionGroup) {
        return success(ardInspectionGroupService.selectGroupTreeList(ardInspectionGroup));
ard-admin/src/main/java/com/ard/web/controller/inspection/ArdPointCloudController.java
New file
@@ -0,0 +1,113 @@
package com.ard.web.controller.inspection;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ard.inspection.domain.ArdPointCloud;
import com.ard.inspection.service.IArdPointCloudService;
/**
 * 点云文件Controller
 *
 * @author xia
 * @date 2026-03-03
 */
@Api(tags = "点云文件信息")
@RestController
@RequestMapping("/inspection/cloud")
@Slf4j
public class ArdPointCloudController extends BaseController {
    @Autowired
    private IArdPointCloudService ardPointCloudService;
    /**
     * 查询点云文件列表
     */
    @ApiOperation("查询点云文件列表")
    //@PreAuthorize("@ss.hasPermi('inspection:cloud:list')")
    @GetMapping("/list")
    public TableDataInfo list(ArdPointCloud ardPointCloud) {
        startPage();
        List<ArdPointCloud> list = ardPointCloudService.selectArdPointCloudList(ardPointCloud);
        return getDataTable(list);
    }
    /**
     * 导出点云文件列表
     */
    @ApiOperation("导出点云文件列表")
    //@PreAuthorize("@ss.hasPermi('inspection:cloud:export')")
    @Log(title = "点云文件", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, ArdPointCloud ardPointCloud) {
        List<ArdPointCloud> list = ardPointCloudService.selectArdPointCloudList(ardPointCloud);
        ExcelUtil<ArdPointCloud> util = new ExcelUtil<ArdPointCloud>(ArdPointCloud.class);
        util.exportExcel(response, list, "点云文件数据");
    }
    /**
     * 获取点云文件详细信息
     */
    @ApiOperation("获取点云文件详细信息")
    //@PreAuthorize("@ss.hasPermi('inspection:cloud:query')")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") String id) {
        return success(ardPointCloudService.selectArdPointCloudById(id));
    }
    /**
     * 新增点云文件
     */
    @ApiOperation("新增点云文件")
    //@PreAuthorize("@ss.hasPermi('inspection:cloud:add')")
    @Log(title = "点云文件", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody ArdPointCloud ardPointCloud) {
        ardPointCloud.setCreateBy(getUsername());
        return toAjax(ardPointCloudService.insertArdPointCloud(ardPointCloud));
    }
    /**
     * 修改点云文件
     */
    @ApiOperation("修改点云文件")
    //@PreAuthorize("@ss.hasPermi('inspection:cloud:edit')")
    @Log(title = "点云文件", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody ArdPointCloud ardPointCloud) {
        ardPointCloud.setUpdateBy(getUsername());
        return toAjax(ardPointCloudService.updateArdPointCloud(ardPointCloud));
    }
    /**
     * 删除点云文件
     */
    @ApiOperation("删除点云文件")
    //@PreAuthorize("@ss.hasPermi('inspection:cloud:remove')")
    @Log(title = "点云文件", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable String[] ids) {
        return toAjax(ardPointCloudService.deleteArdPointCloudByIds(ids));
    }
}
ard-admin/src/main/java/com/ard/web/controller/inspection/BigFileUploadController.java
@@ -4,7 +4,10 @@
import com.ard.common.core.controller.BaseController;
import com.ard.common.core.domain.AjaxResult;
import com.ard.common.enums.BusinessType;
import com.ard.inspection.domain.UploadFileEntity;
import com.ard.inspection.service.IBigFileUploadService;
import com.ard.inspection.utils.ZipFileUtils;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import io.swagger.annotations.Api;
@@ -12,7 +15,10 @@
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.*;
import java.io.File;
import java.io.IOException;
/**
 * @author xia
@@ -26,16 +32,20 @@
    @Autowired
    private IBigFileUploadService bigFileUploadService;
    //@Value(value = "${inspection.profile}")
    @Value(value = "${inspection.profile}")
    private String uploadPath;
    //@Value(value = "${inspection.chunk.path}")
    @Value(value = "${inspection.chunk.path}")
    private String chunkPath;
    @Value(value = "${inspection.chunk.zipPath}")
    private String zipPath;
    /**
     * 检查分片是否存在
     */
    @GetMapping("/chunks/{fileMd5}")
    @ApiOperation("检查分片是否存在")
    @GetMapping("/bigfile/{fileMd5}")
    public AjaxResult checkChunk(@PathVariable String fileMd5) {
        Map<String, Object> result = bigFileUploadService.checkChunk(fileMd5,chunkPath);
        return AjaxResult.success(result);
@@ -44,23 +54,43 @@
    /**
     * 上传分片
     */
    @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);
    @ApiOperation("上传分片")
    @PostMapping("/bigfile/chunk")
    public AjaxResult uploadChunk(@RequestBody UploadFileEntity uploadFileEntity,
                                  @RequestParam("file") MultipartFile file) {
//    public AjaxResult uploadChunk(@RequestParam("file") MultipartFile file,
//                                  @RequestParam("chunkNumber") Integer chunkNumber,
//                                  @RequestParam("fileMd5") String fileMd5) {
        Map<String, Object> result = bigFileUploadService.uploadChunk(file,uploadFileEntity,chunkPath);
        return AjaxResult.success(result);
    }
    /**
     * 合并切片
     */
    @ApiOperation("合并分片")
    @Log(title = "合并切片", businessType = BusinessType.IMPORT)
    @PostMapping("/merge")
    @PostMapping("/bigfile/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);
    }
    /**
     * 大文件上传并解压接口
     * @param file 上传的ZIP文件
     * @param overwrite 是否覆盖已存在文件(默认false)
     * @return 上传结果
     */
    @ApiOperation("大文件上传并解压接口")
    @Log(title = "大文件上传解压", businessType = BusinessType.INSERT)
    @PostMapping("/upload/bigFileUnzip")
    public AjaxResult uploadBigZipFile(
            @RequestPart("file") MultipartFile file) {
            //@RequestParam(value = "overwrite", defaultValue = "false") boolean overwrite) {
        boolean overwrite = false;
        return bigFileUploadService.uploadBigZipFile(file,overwrite,uploadPath,chunkPath,zipPath);
    }
}
ard-admin/src/main/resources/application.yml
@@ -118,9 +118,9 @@
  servlet:
    multipart:
      # 单个文件大小
      max-file-size: 10MB
      max-file-size: 3GB
      # 设置总上传的文件大小
      max-request-size: 20MB
      max-request-size: 3GB
  # 服务模块
  devtools:
    restart:
@@ -160,7 +160,12 @@
          management-url: http://127.0.0.1:8080/actuator
          service-url: http://127.0.0.1:8080/
  # 激活配置文件
  profiles:
    active: @spring.profiles.active@
    active: @spring.profiles.active@
inspection:
  profile: /home/inspection/uploadPath  # 上传文件存储路径
  chunk:
    path: /home/inspection/uploadPath/chunks  # 切片临时目录
    zipPath: /home/inspection/uploadPath/zip  # 压缩文件临时目录
ard-framework/src/main/java/com/ard/framework/config/SecurityConfig.java
@@ -111,7 +111,7 @@
            .authorizeHttpRequests((requests) -> {
                permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
                // 对于登录login 注册register 验证码captchaImage 允许匿名访问
                requests.antMatchers("/login", "/register", "/captchaImage", "/ws/**","/actuator/**","/instances","/minioTransfer/**").permitAll()
                requests.antMatchers("/login", "/register", "/captchaImage", "/ws/**","/actuator/**","/instances","/minioTransfer/**","/inspection/**").permitAll()
                    // 静态资源,可匿名访问
                    .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
                    .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
ard-inspection/pom.xml
@@ -32,7 +32,11 @@
            <artifactId>hutool-all</artifactId>
            <version>5.8.20</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.20</version>
        </dependency>
    </dependencies>
ard-inspection/src/main/java/com/ard/inspection/domain/ArdInspectionGroup.java
@@ -1,6 +1,9 @@
package com.ard.inspection.domain;
import com.ard.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.util.ArrayList;
@@ -30,6 +33,9 @@
    /** 显示顺序 */
    private Integer orderNum;
    /** 删除标志(0代表存在 2代表删除) */
    private String delFlag;
    /** 父部门名称 */
    private String parentName;
@@ -95,4 +101,23 @@
        this.children = children;
    }
    public String getDelFlag() {
        return delFlag;
    }
    public void setDelFlag(String delFlag) {
        this.delFlag = delFlag;
    }
    @Override
    public String toString() {
        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
            .append("groupId", getGroupId())
            .append("groupParentId", getGroupParentId())
            .append("ancestors", getAncestors())
            .append("groupName", getGroupName())
            .append("orderNum", getOrderNum())
            .append("delFlag", getDelFlag())
            .toString();
    }
}
ard-inspection/src/main/java/com/ard/inspection/domain/ArdPointCloud.java
New file
@@ -0,0 +1,62 @@
package com.ard.inspection.domain;
import com.ard.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 点云文件
 * @author xia
 */
@EqualsAndHashCode(callSuper = true)
@Data
public class ArdPointCloud extends BaseEntity {
    /**
     * ID
     */
    private String id;
    /**
     * 点云名称
     */
    private String cloudName;
    /**
     * 文件名称
     */
    private String fileName;
    /**
     * 文件夹名称
     */
    private String folderName;
    /**
     * 文件大小
     */
    private String fileSize;
    /**
     * 关联状态
     * 0:未关联
     * 1:已关联
     */
    private String associatedState;
    /**
     * 航线ID
     */
    private String routeId;
    /**
     * 分组ID
     */
    private String groupId;
    /**
     * 文件路径
     */
    private String filePath;
}
ard-inspection/src/main/java/com/ard/inspection/domain/UploadFileEntity.java
New file
@@ -0,0 +1,19 @@
package com.ard.inspection.domain;
import lombok.Data;
/**
 * @author xia
 */
@Data
public class UploadFileEntity {
    private Integer chunkNumber;
    private String fileMd5;
    private String cloudName;
    private String groupId;
}
ard-inspection/src/main/java/com/ard/inspection/mapper/ArdInspectionGroupMapper.java
@@ -69,8 +69,10 @@
     * @param groupParentId 分组父部门ID
     * @return 结果
     */
    public ArdInspectionGroup checkInspectionGroupNameUnique(@Param("groupName") String groupName,
    public ArdInspectionGroup checkInspectionGroupNameUniqueA(@Param("groupName") String groupName,
                                                             @Param("groupParentId") Long groupParentId);
    public ArdInspectionGroup checkInspectionGroupNameUniqueB(@Param("groupName") String groupName);
    /**
     * 根据ID查询所有子分组
@@ -103,4 +105,12 @@
     * @return 结果 true 存在 false 不存在
     */
    public int checkInspectionGroupExistUser(Long groupId);
    /**
     * 查询groupId最大值
     *
     * @return 结果 true 存在 false 不存在
     */
    public int selectMaxGroupId();
}
ard-inspection/src/main/java/com/ard/inspection/mapper/ArdPointCloudMapper.java
New file
@@ -0,0 +1,64 @@
package com.ard.inspection.mapper;
import java.util.List;
import com.ard.inspection.domain.ArdPointCloud;
/**
 * 点云文件Mapper接口
 *
 * @author xia
 * @date 2026-03-03
 */
public interface ArdPointCloudMapper {
    /**
     * 查询点云文件
     *
     * @param id 点云文件主键
     * @return 点云文件
     */
    public ArdPointCloud selectArdPointCloudById(String id);
    /**
     * 查询点云文件列表
     *
     * @param ardPointCloud 点云文件
     * @return 点云文件集合
     */
    public List<ArdPointCloud> selectArdPointCloudList(ArdPointCloud ardPointCloud);
    /**
     * 新增点云文件
     *
     * @param ardPointCloud 点云文件
     * @return 结果
     */
    public int insertArdPointCloud(ArdPointCloud ardPointCloud);
    /**
     * 修改点云文件
     *
     * @param ardPointCloud 点云文件
     * @return 结果
     */
    public int updateArdPointCloud(ArdPointCloud ardPointCloud);
    /**
     * 删除点云文件
     *
     * @param id 点云文件主键
     * @return 结果
     */
    public int deleteArdPointCloudById(String id);
    /**
     * 批量删除点云文件
     *
     * @param ids 需要删除的数据主键集合
     * @return 结果
     */
    public int deleteArdPointCloudByIds(String[] ids);
    public ArdPointCloud selectArdPointCloudByFileName(String fileName);
}
ard-inspection/src/main/java/com/ard/inspection/service/IArdPointCloudService.java
New file
@@ -0,0 +1,64 @@
package com.ard.inspection.service;
import java.util.List;
import com.ard.inspection.domain.ArdPointCloud;
/**
 * 点云文件Service接口
 *
 * @author xia
 * @date 2026-03-03
 */
public interface IArdPointCloudService {
    /**
     * 查询点云文件
     *
     * @param id 点云文件主键
     * @return 点云文件
     */
    public ArdPointCloud selectArdPointCloudById(String id);
    /**
     * 查询点云文件列表
     *
     * @param ardPointCloud 点云文件
     * @return 点云文件集合
     */
    public List<ArdPointCloud> selectArdPointCloudList(ArdPointCloud ardPointCloud);
    /**
     * 新增点云文件
     *
     * @param ardPointCloud 点云文件
     * @return 结果
     */
    public int insertArdPointCloud(ArdPointCloud ardPointCloud);
    /**
     * 修改点云文件
     *
     * @param ardPointCloud 点云文件
     * @return 结果
     */
    public int updateArdPointCloud(ArdPointCloud ardPointCloud);
    /**
     * 批量删除点云文件
     *
     * @param ids 需要删除的点云文件主键集合
     * @return 结果
     */
    public int deleteArdPointCloudByIds(String[] ids);
    /**
     * 删除点云文件信息
     *
     * @param id 点云文件主键
     * @return 结果
     */
    public int deleteArdPointCloudById(String id);
    public ArdPointCloud selectArdPointCloudByFileName(String filename);
}
ard-inspection/src/main/java/com/ard/inspection/service/IBigFileUploadService.java
@@ -1,6 +1,8 @@
package com.ard.inspection.service;
import com.ard.common.core.domain.AjaxResult;
import com.ard.inspection.domain.UploadFileEntity;
import org.springframework.web.multipart.MultipartFile;
import java.util.Map;
@@ -28,6 +30,10 @@
                              String fileMd5,
                              String chunkPath);
    public Map<String, Object> uploadChunk(MultipartFile file,
                                           UploadFileEntity uploadFileEntity,
                                           String chunkPath);
    /**
     * 合并切片
     *
@@ -39,4 +45,19 @@
                                           String fileName,
                                           String uploadPath);
    /**
     * 大文件上传并解压接口
     * @param file 上传的ZIP文件
     * @param overwrite 是否覆盖已存在文件(默认false)
     * @param uploadPath 上传文件存储路径
     * @param chunkPath 临时切片存储路径
     * @param zipPath 解压文件存储路径
     * @return 上传结果
     */
    public AjaxResult uploadBigZipFile(MultipartFile file,
                                       boolean overwrite,
                                       String uploadPath,
                                       String chunkPath,
                                       String zipPath);
}
ard-inspection/src/main/java/com/ard/inspection/service/impl/ArdInspectionGroupServiceImpl.java
@@ -61,9 +61,16 @@
     */
    @Override
    public int insertArdInspectionGroup(ArdInspectionGroup ardInspectionGroup) {
        ArdInspectionGroup inspectionGroup = ardInspectionGroupMapper.selectArdInspectionGroupByGroupId(ardInspectionGroup.getGroupParentId());
        ardInspectionGroup.setAncestors(inspectionGroup.getAncestors() + "," + ardInspectionGroup.getGroupParentId());
        if (ardInspectionGroup.getGroupParentId() == null){
            ardInspectionGroup.setGroupId((long) (ardInspectionGroupMapper.selectMaxGroupId() + 100));
            ardInspectionGroup.setGroupParentId(0L);
            ardInspectionGroup.setAncestors("0");
        }else {
            ArdInspectionGroup inspectionGroup = ardInspectionGroupMapper.selectArdInspectionGroupByGroupId(ardInspectionGroup.getGroupParentId());
            ardInspectionGroup.setAncestors(inspectionGroup.getAncestors() + "," + ardInspectionGroup.getGroupParentId());
        }
        ardInspectionGroup.setCreateTime(DateUtils.getNowDate());
        ardInspectionGroup.setDelFlag("0");
        return ardInspectionGroupMapper.insertArdInspectionGroup(ardInspectionGroup);
    }
@@ -124,8 +131,9 @@
    @Override
    public boolean checkInspectionGroupNameUnique(ArdInspectionGroup ardInspectionGroup) {
        Long groupId = StringUtils.isNull(ardInspectionGroup.getGroupId()) ? -1L : ardInspectionGroup.getGroupId();
        ArdInspectionGroup info = ardInspectionGroupMapper.checkInspectionGroupNameUnique(ardInspectionGroup.getGroupName(),ardInspectionGroup.getGroupParentId());
        if (StringUtils.isNotNull(info) && info.getGroupId().longValue() != groupId.longValue())
        ArdInspectionGroup infoA = ardInspectionGroupMapper.checkInspectionGroupNameUniqueA(ardInspectionGroup.getGroupName(),ardInspectionGroup.getGroupParentId());
        ArdInspectionGroup infoB = ardInspectionGroupMapper.checkInspectionGroupNameUniqueB(ardInspectionGroup.getGroupName());
        if (StringUtils.isNotNull(infoB) && infoB.getGroupId().longValue() != groupId.longValue())
        {
            return UserConstants.NOT_UNIQUE;
        }
ard-inspection/src/main/java/com/ard/inspection/service/impl/ArdPointCloudServiceImpl.java
New file
@@ -0,0 +1,116 @@
package com.ard.inspection.service.impl;
import java.util.List;
import com.ard.common.utils.DateUtils;
import com.ard.common.utils.uuid.IdUtils;
import com.ard.inspection.utils.ZipFileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ard.inspection.mapper.ArdPointCloudMapper;
import com.ard.inspection.domain.ArdPointCloud;
import com.ard.inspection.service.IArdPointCloudService;
import javax.annotation.Resource;
/**
 * 点云文件Service业务层处理
 *
 * @author xia
 * @date 2026-03-03
 */
@Service
public class ArdPointCloudServiceImpl implements IArdPointCloudService {
    @Autowired
    private ArdPointCloudMapper ardPointCloudMapper;
    @Resource
    private ZipFileUtils zipFileUtils;
    /**
     * 查询点云文件
     *
     * @param id 点云文件主键
     * @return 点云文件
     */
    @Override
    public ArdPointCloud selectArdPointCloudById(String id) {
        return ardPointCloudMapper.selectArdPointCloudById(id);
    }
    /**
     * 查询点云文件列表
     *
     * @param ardPointCloud 点云文件
     * @return 点云文件
     */
    @Override
    public List<ArdPointCloud> selectArdPointCloudList(ArdPointCloud ardPointCloud) {
        return ardPointCloudMapper.selectArdPointCloudList(ardPointCloud);
    }
    /**
     * 新增点云文件
     *
     * @param ardPointCloud 点云文件
     * @return 结果
     */
    @Override
    public int insertArdPointCloud(ArdPointCloud ardPointCloud) {
        ardPointCloud.setId(IdUtils.simpleUUID());
        ardPointCloud.setCreateTime(DateUtils.getNowDate());
        ardPointCloud.setAssociatedState("0");
        return ardPointCloudMapper.insertArdPointCloud(ardPointCloud);
    }
    /**
     * 修改点云文件
     *
     * @param ardPointCloud 点云文件
     * @return 结果
     */
    @Override
    public int updateArdPointCloud(ArdPointCloud ardPointCloud) {
        ardPointCloud.setUpdateTime(DateUtils.getNowDate());
        return ardPointCloudMapper.updateArdPointCloud(ardPointCloud);
    }
    /**
     * 批量删除点云文件
     *
     * @param ids 需要删除的点云文件主键
     * @return 结果
     */
    @Override
    public int deleteArdPointCloudByIds(String[] ids) {
        // 删除点云文件
        String folderPath = "/home/inspection/uploadPath/zip/";
        int count = 0;
        for (String id : ids) {
            ArdPointCloud ardPointCloud = ardPointCloudMapper.selectArdPointCloudById(id);
            if (zipFileUtils.deleteZipFile(folderPath + ardPointCloud.getFolderName())){
                ardPointCloudMapper.deleteArdPointCloudById(id);
                count++;
            }
        }
        return count;
    }
    /**
     * 删除点云文件信息
     *
     * @param id 点云文件主键
     * @return 结果
     */
    @Override
    public int deleteArdPointCloudById(String id) {
        return ardPointCloudMapper.deleteArdPointCloudById(id);
    }
    @Override
    public ArdPointCloud selectArdPointCloudByFileName(String filename) {
        return ardPointCloudMapper.selectArdPointCloudByFileName(filename);
    }
}
ard-inspection/src/main/java/com/ard/inspection/service/impl/BigFileUploadServiceImpl.java
@@ -1,15 +1,25 @@
package com.ard.inspection.service.impl;
import com.ard.common.core.domain.AjaxResult;
import com.ard.common.utils.uuid.IdUtils;
import com.ard.inspection.domain.ArdPointCloud;
import com.ard.inspection.domain.UploadFileEntity;
import com.ard.inspection.service.IArdPointCloudService;
import com.ard.inspection.service.IBigFileUploadService;
import com.ard.inspection.utils.ZipFileUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.*;
import java.util.stream.Collectors;
import static com.ard.inspection.utils.ZipFileUtils.formatFileSize;
/**
 * @author xia
@@ -17,6 +27,14 @@
@Service
@Slf4j
public class BigFileUploadServiceImpl implements IBigFileUploadService {
    public static final String CLOUD_FILE_PATH = "http://192.168.1.3:6100";
    @Autowired
    private IArdPointCloudService ardPointCloudService;
    @Resource
    private ZipFileUtils zipFileUtils;
    @Override
    public Map<String, Object> checkChunk(String fileMd5,String chunkPath) {
@@ -81,6 +99,37 @@
    }
    @Override
    public Map<String, Object> uploadChunk(MultipartFile file,UploadFileEntity uploadFileEntity,String chunkPath) {
        Map<String, Object> result = new HashMap<>();
        try {
            // 验证参数
            if (file.isEmpty()) {
                result.put("exception", "文件不能为空!!!");
                return result;
            }
            // 创建分片目录
            String chunkDirPath = chunkPath + File.separator + uploadFileEntity.getFileMd5();
            File chunkDir = new File(chunkDirPath);
            if (!chunkDir.exists()) {
                chunkDir.mkdirs();
            }
            // 保存分片
            String chunkFileName = uploadFileEntity.getChunkNumber() + ".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<>();
        // 临时目录
@@ -131,9 +180,94 @@
        // 这里可以保存文件信息到数据库,例如文件路径、文件名、md5等
        // fileService.saveFileInfo(...);
//        ArdPointCloud ardPointCloud = new ArdPointCloud();
//        ardPointCloud.setFileName(newFileName);
//        ardPointCloud.setFileSize(mergeFile.length());
//        ardPointCloud.setAssociatedState("0");
//        ardPointCloudService.insertArdPointCloud(ardPointCloud);
        result.put("message", "文件合并成功");
        return result;
    }
    /**
     * 大文件上传并解压接口
     * @param file 上传的ZIP文件
     * @param overwrite 是否覆盖已存在文件(默认false)
     * @param uploadPath 上传文件存储路径
     * @param chunkPath 临时切片存储路径
     * @param zipPath 解压文件存储路径
     * @return 上传结果
     */
    @Override
    public AjaxResult uploadBigZipFile(MultipartFile file, boolean overwrite,
                                       String uploadPath,
                                       String chunkPath,
                                       String zipPath) {
        // 1. 校验文件是否为空
        if (file.isEmpty()) {
            return AjaxResult.error("上传文件不能为空");
        }
        // 2. 校验文件格式
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || !originalFilename.endsWith(".zip")) {
            return AjaxResult.error("仅支持ZIP格式文件上传");
        }
        // 2.1 校验文件名是否重复
        if (!overwrite) {
            if (ardPointCloudService.selectArdPointCloudByFileName(originalFilename) != null) {
                return AjaxResult.error("文件已存在");
            }
        }
        // 3. 创建临时目录
        File tempDir = new File(uploadPath);
        if (!tempDir.exists()) {
            boolean mkdirs = tempDir.mkdirs();
            if (!mkdirs) {
                return AjaxResult.error("创建临时上传目录失败");
            }
        }
        // 4. 保存上传的ZIP文件到临时目录(避免重名)
        String tempFileName = UUID.randomUUID() + ".zip";
        File tempFile = new File(chunkPath + File.separator + tempFileName);
        try {
            file.transferTo(tempFile);
            log.info("临时文件保存成功:{},文件大小:{}MB", tempFile.getAbsolutePath(),
                    file.getSize() / 1024 / 1024);
        } catch (IOException e) {
            log.error("保存临时文件失败", e);
            return AjaxResult.error("文件上传失败:" + e.getMessage());
        }
        // 5. 解压文件
        try {
            zipFileUtils.unzip(tempFile.getAbsolutePath(), overwrite);
            // 6. 删除临时文件(可选,若需要保留压缩包可注释)
            boolean delete = tempFile.delete();
            if (delete) {
                log.info("临时文件已删除:{}", tempFile.getAbsolutePath());
            }
            ArdPointCloud ardPointCloud = new ArdPointCloud();
            ardPointCloud.setFileName(originalFilename);
            ardPointCloud.setFileSize(formatFileSize(file.getSize()));
            int dotIndex = originalFilename.lastIndexOf('.');
            String folderName = (dotIndex > 0) ? originalFilename.substring(0, dotIndex) : originalFilename;
            ardPointCloud.setFolderName(folderName);
            String zipP = CLOUD_FILE_PATH + zipPath + "/" + folderName + "/tileset.json";
            ardPointCloud.setFilePath(zipP);
            return AjaxResult.success("文件上传并解压成功", ardPointCloud);
        } catch (IOException e) {
            log.error("解压文件失败", e);
            // 失败时删除临时文件
            if (tempFile.exists()) {
                tempFile.delete();
            }
            return AjaxResult.error("文件解压失败:" + e.getMessage());
        }
    }
}
ard-inspection/src/main/java/com/ard/inspection/service/impl/StaticResourceConfig.java
New file
@@ -0,0 +1,17 @@
package com.ard.inspection.service.impl;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class StaticResourceConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 将 /inspection/** 映射到本地 /home/inspection/uploadPath/zip/ 目录
        registry.addResourceHandler("/inspection/**")
                .addResourceLocations("file:/home/inspection/uploadPath/zip/");
    }
}
ard-inspection/src/main/java/com/ard/inspection/utils/ZipFileUtils.java
New file
@@ -0,0 +1,135 @@
package com.ard.inspection.utils;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Comparator;
import java.util.Enumeration;
/**
 * ZIP文件解压工具类
 */
@Component
public class ZipFileUtils {
    private static final Logger log = LoggerFactory.getLogger(ZipFileUtils.class);
    @Value(value = "${inspection.chunk.zipPath}")
    private String zipPath;
    /**
     * 解压ZIP文件到指定目录
     * @param zipFilePath 压缩包路径
     * @param overwrite 是否覆盖已存在文件
     * @throws IOException 解压异常
     */
    public void unzip(String zipFilePath, boolean overwrite) throws IOException {
        // 校验压缩包是否存在
        File zipFile = new File(zipFilePath);
        if (!zipFile.exists()) {
            throw new FileNotFoundException("压缩包不存在:" + zipFilePath);
        }
        // 创建目标目录
        Path targetDir = Paths.get(zipPath);
        if (!Files.exists(targetDir)) {
            Files.createDirectories(targetDir);
        }
        // 使用Apache Commons Compress处理大ZIP文件
        try (ZipFile zf = new ZipFile(zipFile)) {
            Enumeration<ZipArchiveEntry> entries = zf.getEntries();
            while (entries.hasMoreElements()) {
                ZipArchiveEntry entry = entries.nextElement();
                String entryName = entry.getName();
                // 拼接解压后的文件路径
                Path entryPath = targetDir.resolve(entryName);
                // 跳过已存在且不覆盖的文件
                if (Files.exists(entryPath) && !overwrite) {
                    log.warn("文件已存在,跳过解压:{}", entryPath);
                    continue;
                }
                // 如果是目录,创建目录
                if (entry.isDirectory()) {
                    if (!Files.exists(entryPath)) {
                        Files.createDirectories(entryPath);
                    }
                    continue;
                }
                // 创建父目录(防止文件在子目录下)
                Path parentDir = entryPath.getParent();
                if (!Files.exists(parentDir)) {
                    Files.createDirectories(parentDir);
                }
                // 流式复制文件(避免内存溢出)
                try (InputStream in = zf.getInputStream(entry);
                     OutputStream out = Files.newOutputStream(entryPath)) {
                    byte[] buffer = new byte[8192]; // 8K缓冲区
                    int len;
                    while ((len = in.read(buffer)) != -1) {
                        out.write(buffer, 0, len);
                    }
                    log.info("解压文件完成:{}", entryPath);
                }
            }
        } catch (Exception e) {
            log.error("解压文件失败:{}", zipFilePath, e);
            throw new IOException("解压失败:" + e.getMessage(), e);
        }
    }
    /**
     * 解压ZIP文件到指定目录
     * @param pathStr 删除文件夹路径
     */
    public boolean deleteZipFile(String pathStr) {
        if (pathStr == null || pathStr.isEmpty()) {
            return false;
        }
        Path path = Paths.get(pathStr);
        if (!Files.exists(path)) {
            // 路径不存在,视为删除成功
            return true;
        }
        try {
            // 遍历并反向排序,确保先删除子文件/子目录,再删除父目录
            Files.walk(path)
                    .sorted(Comparator.reverseOrder())
                    .forEach(p -> {
                        try {
                            Files.deleteIfExists(p);
                        } catch (IOException e) {
                            throw new RuntimeException("删除失败: " + p, e);
                        }
                    });
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 根据文件大小格式化
     * @param size 文件大小
     */
    public static String formatFileSize(long size) {
        if (size <= 0) return "0 B";
        final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};
        int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
        return String.format("%.2f %s", size / Math.pow(1024, digitGroups), units[digitGroups]);
    }
}
ard-inspection/src/main/resources/mapper/ArdInspectionGroupMapper.xml
@@ -5,16 +5,17 @@
<mapper namespace="com.ard.inspection.mapper.ArdInspectionGroupMapper">
    
    <resultMap type="ArdInspectionGroup" id="ArdInspectionGroupResult">
        <result property="groupId"    column="group_id"    />
        <result property="groupId"          column="group_id"           />
        <result property="groupParentId"    column="group_parent_id"    />
        <result property="ancestors"    column="ancestors"    />
        <result property="groupName"    column="group_name"    />
        <result property="orderNum"    column="order_num"    />
        <result property="createBy"    column="create_by"    />
        <result property="createTime"    column="create_time"    />
        <result property="updateBy"    column="update_by"    />
        <result property="updateTime"    column="update_time"    />
        <result property="parentName" column="parent_name" />
        <result property="ancestors"        column="ancestors"          />
        <result property="groupName"        column="group_name"         />
        <result property="orderNum"         column="order_num"          />
        <result property="createBy"         column="create_by"          />
        <result property="createTime"       column="create_time"        />
        <result property="updateBy"         column="update_by"          />
        <result property="updateTime"       column="update_time"        />
        <result property="delFlag"          column="del_flag"           />
        <result property="parentName"       column="parent_name"        />
    </resultMap>
    <sql id="selectArdInspectionGroupVo">
@@ -26,13 +27,15 @@
               create_by,
               create_time,
               update_by,
               update_time
               update_time,
               del_flag
        from ard_inspection_group
    </sql>
    <select id="selectArdInspectionGroupList" parameterType="ArdInspectionGroup" resultMap="ArdInspectionGroupResult">
        <include refid="selectArdInspectionGroupVo"/>
        <where>
            del_flag = '0'
            <if test="groupId != null ">
                and group_id = #{groupId}
            </if>
@@ -107,21 +110,27 @@
        where group_id = #{groupId}
    </update>
    <delete id="deleteArdInspectionGroupByGroupId" parameterType="Long">
        delete from ard_inspection_group where group_id = #{groupId}
    </delete>
    <update id="deleteArdInspectionGroupByGroupId" parameterType="Long">
        update ard_inspection_group set del_flag = '2' where group_id = #{groupId}
    </update>
    <delete id="deleteArdInspectionGroupByGroupIds" parameterType="String">
        delete from ard_inspection_group where group_id in
    <update id="deleteArdInspectionGroupByGroupIds" parameterType="String">
        update ard_inspection_group set del_flag = '2' where group_id in
        <foreach item="groupId" collection="array" open="(" separator="," close=")">
            #{groupId}
        </foreach>
    </delete>
    </update>
    <select id="checkInspectionGroupNameUnique" resultMap="ArdInspectionGroupResult">
    <select id="checkInspectionGroupNameUniqueA" resultMap="ArdInspectionGroupResult">
        <include refid="selectArdInspectionGroupVo"/>
        where group_name=#{groupName}
        and group_parent_id = #{groupParentId} limit 1
    </select>
    <select id="checkInspectionGroupNameUniqueB" resultMap="ArdInspectionGroupResult">
        <include refid="selectArdInspectionGroupVo"/>
        where del_flag = '0'
        and group_name=#{groupName} limit 1
    </select>
    <select id="selectChildrenInspectionGroupById" parameterType="Long" resultMap="ArdInspectionGroupResult">
@@ -143,11 +152,17 @@
    <select id="hasChildByInspectionGroupId" parameterType="Long" resultType="int">
        select count(1) from ard_inspection_group
        where group_parent_id = #{groupId} limit 1
        where del_flag = '0' and group_parent_id = #{groupId} limit 1
    </select>
    <select id="checkInspectionGroupExistUser" parameterType="Long" resultType="int">
        select count(1) from sys_user where group_id = #{groupId} and del_flag = '0'
    </select>
    <select id="selectMaxGroupId" resultType="int">
        SELECT group_id FROM ard_inspection_group
        WHERE group_parent_id = 0 AND ancestors = 0
        ORDER BY group_id DESC LIMIT 1
    </select>
</mapper>
ard-inspection/src/main/resources/mapper/ArdPointCloudMapper.xml
New file
@@ -0,0 +1,133 @@
<?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.inspection.mapper.ArdPointCloudMapper">
    <resultMap type="ArdPointCloud" id="ArdPointCloudResult">
        <result property="id"    column="id"    />
        <result property="cloudName"    column="cloud_name"    />
        <result property="fileName"    column="file_name"    />
        <result property="folderName"    column="folder_name"    />
        <result property="fileSize"    column="file_size"    />
        <result property="associatedState"    column="associated_state"    />
        <result property="routeId"    column="route_id"    />
        <result property="groupId"    column="group_id"    />
        <result property="createBy"    column="create_by"    />
        <result property="createTime"    column="create_time"    />
        <result property="updateBy"    column="update_by"    />
        <result property="updateTime"    column="update_time"    />
        <result property="filePath"    column="file_path"    />
    </resultMap>
    <sql id="selectArdPointCloudVo">
        select id,
               cloud_name,
               file_name,
               folder_name,
               file_size,
               associated_state,
               route_id,
               group_id,
               create_by,
               create_time,
               update_by,
               update_time,
               file_path
        from ard_point_cloud
    </sql>
    <select id="selectArdPointCloudList" parameterType="ArdPointCloud" resultMap="ArdPointCloudResult">
        <include refid="selectArdPointCloudVo"/>
        <where>
            <if test="cloudName != null  and cloudName != ''"> and cloud_name like concat('%', #{cloudName}, '%')</if>
            <if test="fileName != null  and fileName != ''"> and file_name like concat('%', #{fileName}, '%')</if>
            <if test="fileSize != null "> and file_size = #{fileSize}</if>
            <if test="associatedState != null  and associatedState != ''"> and associated_state = #{associatedState}</if>
            <if test="routeId != null  and routeId != ''"> and route_id = #{routeId}</if>
            <if test="groupId != null  and groupId != ''"> and group_id = #{groupId}</if>
            <if test="createBy != null  and createBy != ''"> and create_by = #{createBy}</if>
            <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
                and date_format(create_time,'%Y%m%d') &gt;= date_format(#{params.beginTime},'%Y%m%d')
            </if>
            <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
                and date_format(create_time,'%Y%m%d') &lt;= date_format(#{params.endTime},'%Y%m%d')
            </if>
        </where>
    </select>
    <select id="selectArdPointCloudById" parameterType="String" resultMap="ArdPointCloudResult">
        <include refid="selectArdPointCloudVo"/>
        where id = #{id}
    </select>
    <insert id="insertArdPointCloud" parameterType="ArdPointCloud">
        insert into ard_point_cloud
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="id != null">id,</if>
            <if test="cloudName != null">cloud_name,</if>
            <if test="fileName != null">file_name,</if>
            <if test="folderName != null">folder_name,</if>
            <if test="fileSize != null">file_size,</if>
            <if test="associatedState != null">associated_state,</if>
            <if test="routeId != null">route_id,</if>
            <if test="groupId != null">group_id,</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>
            <if test="filePath != null">file_path,</if>
         </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="id != null">#{id},</if>
            <if test="cloudName != null">#{cloudName},</if>
            <if test="fileName != null">#{fileName},</if>
            <if test="folderName != null">#{folderName},</if>
            <if test="fileSize != null">#{fileSize},</if>
            <if test="associatedState != null">#{associatedState},</if>
            <if test="routeId != null">#{routeId},</if>
            <if test="groupId != null">#{groupId},</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>
            <if test="filePath != null">#{filePath},</if>
         </trim>
    </insert>
    <update id="updateArdPointCloud" parameterType="ArdPointCloud">
        update ard_point_cloud
        <trim prefix="SET" suffixOverrides=",">
            <if test="cloudName != null">cloud_name = #{cloudName},</if>
            <if test="fileName != null">file_name = #{fileName},</if>
            <if test="folderName != null">folder_name = #{folderName},</if>
            <if test="fileSize != null">file_size = #{fileSize},</if>
            <if test="associatedState != null">associated_state = #{associatedState},</if>
            <if test="routeId != null">route_id = #{routeId},</if>
            <if test="groupId != null">group_id = #{groupId},</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>
            <if test="filePath != null">file_path = #{filePath},</if>
        </trim>
        where id = #{id}
    </update>
    <delete id="deleteArdPointCloudById" parameterType="String">
        delete from ard_point_cloud where id = #{id}
    </delete>
    <delete id="deleteArdPointCloudByIds" parameterType="String">
        delete from ard_point_cloud where id in
        <foreach item="id" collection="array" open="(" separator="," close=")">
            #{id}
        </foreach>
    </delete>
    <select id="selectArdPointCloudByFileName" parameterType="String" resultMap="ArdPointCloudResult">
        <include refid="selectArdPointCloudVo"/>
        where file_name = #{fileName}
    </select>
</mapper>
ard-route/src/main/java/com/ard/route/domain/djuav/RoutePointReq.java
@@ -7,6 +7,7 @@
/**
 * 航点列表实体类
 * @author xia
 */
@Data
public class RoutePointReq implements Serializable {
@@ -56,4 +57,19 @@
     */
    private List<ActionGroupReq> actionGroupList;
    /**
     * 目标点
     */
    private TargetPosObj targetPosObj;
    /**
     * 当前航线距离
     */
    private Double distance;
    /**
     * 当前航线速度
     */
    private Integer nowGlobalFlightSpeed;
}
ard-route/src/main/java/com/ard/route/domain/djuav/TargetPosObj.java
New file
@@ -0,0 +1,29 @@
package com.ard.route.domain.djuav;
import lombok.Data;
import java.io.Serializable;
/**
 * 目标点
 * @author xia
 */
@Data
public class TargetPosObj implements Serializable {
    /**
     * 经度
     */
    private Double longitude;
    /**
     * 纬度
     */
    private Double latitude;
    /**
     * 高度
     */
    private Double height;
}
ard-route/src/main/java/com/ard/route/domain/djuav/WaypointTurnReq.java
@@ -26,5 +26,4 @@
     */
    private Integer useStraightLine;
}
ard-route/src/main/java/com/ard/route/domain/route/ArdRouteInfo.java
@@ -5,6 +5,8 @@
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
 * 航线(kmz)对象 ard_route_info
 * 
@@ -13,9 +15,7 @@
 */
@EqualsAndHashCode(callSuper = true)
@Data
public class ArdRouteInfo extends BaseEntity {
    private static final long serialVersionUID = 1L;
public class ArdRouteInfo extends BaseEntity implements Serializable{
    /** ID */
    private String id;
@@ -78,4 +78,7 @@
    /** 航线任务ID */
    private String missionId;
    /** 点云数据 */
    //private List<>
}
ard-route/src/main/java/com/ard/route/util/InitializationUtils.java
@@ -31,7 +31,7 @@
    public UavRouteReq initialization(UavRouteReq uavRouteReq){
        uavRouteReq.setTemplateType("waypoint");
        // 起始点默认航线第一个点
        if (uavRouteReq.getTakeOffRefPoint().isEmpty()){
        if (uavRouteReq.getTakeOffRefPoint() == null){
            uavRouteReq.setTakeOffRefPoint(
                    uavRouteReq.getRoutePointList().get(0).getLatitude() + "," +
                            uavRouteReq.getRoutePointList().get(0).getLongitude() + "," + "0");
ard-route/src/main/java/com/ard/route/util/ToolUtils.java
@@ -1,7 +1,6 @@
package com.ard.route.util;
import com.ard.route.domain.djuav.UavRouteReq;
import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@@ -86,6 +85,9 @@
    // 对象序列化为字节数组
    public static byte[] serialize(Object obj) throws IOException {
        if (obj == null) {
            return null;
        }
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            oos.writeObject(obj);
ard-work/src/main/java/com/ard/work/component/websocket/handler/TyMessageHandler.java
@@ -317,7 +317,7 @@
        Long userId = Long.parseLong(userIdStr);
        lastDisconnectTime.remove(userId); // 清除断开标记
        WebSocketSessionManager.addSession(userId, session);
        log.info("【ws】【{}】Connected,size: {}",userId, WebSocketSessionManager.getOnlineUserCount());
        log.info("【ws】【{}】Connected,size: {}", userId, WebSocketSessionManager.getOnlineUserCount());
    }
    @Override
@@ -329,7 +329,7 @@
        }
        Long userId = Long.parseLong(userIdStr);
        WebSocketSessionManager.removeSession(userId);
        log.info("【ws】【{}】Disconnected,size: {}",userId, WebSocketSessionManager.getOnlineUserCount());
        log.info("【ws】【{}】Disconnected,size: {}", userId, WebSocketSessionManager.getOnlineUserCount());
        long version = System.currentTimeMillis();
        lastDisconnectTime.put(userId, version);
        // 释放该用户所有 UAV 控制权
@@ -352,7 +352,8 @@
                uavSignalManager.removeSubscribe(userId);
                uavControlManager.removeSubscribe(userId);
                LoginUser loginUser = tokenService.getLoginUserByUserId(userId);
                if (loginUser != null) {
                // 只移除本平台用户token,挂接用户token不移除
                if (loginUser != null && "0".equals(loginUser.getUser().getPlatform())) {
                    tokenService.delLoginUser(loginUser.getToken(), userId);
                    log.info("【cmd】用户 [{}] 超时未重连,已删除 token", userId);
                }