zhaowenyu
2025-11-19 e90d0fe42b652c9230c5e544d177dbedb3e57580
Merge remote-tracking branch 'origin/dev' into dev
62 files modified
1 files renamed
1395 ■■■■■ changed files
ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteInfoController.java 51 ●●●●● patch | view | raw | blame | history
ard-route/pom.xml 4 ●●●●● patch | view | raw | blame | history
ard-route/src/main/java/com/ard/route/domain/sixhe/ArdRouteChange.java 4 ●●●●● patch | view | raw | blame | history
ard-route/src/main/java/com/ard/route/service/IArdRouteInfoService.java 46 ●●●●● patch | view | raw | blame | history
ard-route/src/main/java/com/ard/route/service/impl/ArdRouteInfoServiceImpl.java 233 ●●●●● patch | view | raw | blame | history
ard-route/src/main/java/com/ard/route/util/InitializationUtils.java 161 ●●●●● patch | view | raw | blame | history
ard-work/pom.xml 9 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/camera/CameraModeCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/camera/CameraModeReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/camera/CapturePicCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/camera/CapturePicReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/camera/PhotoReturnToggleCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/camera/PicUploadCompletedReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/camera/RecordStartCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/camera/RecordStartReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/camera/RecordStopCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/camera/RecordStopReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/camera/ZoomCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/camera/ZoomToLevelCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/control/AbsAngleControlCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/control/AngleControlCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/control/SpeedControlCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/manual/EmergencyBrakeReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/manual/LandCancelReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/manual/LandForcedReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/manual/LandReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/manual/PointControlReachedReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/manual/ReturnHomeCancelReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/manual/ReturnHomeReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/manual/TakeOffReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/notice/BoxPowerStatusReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/notice/FlyWayEndReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/notice/UavReadyReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/real/SignalInfoCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/real/UavStateCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/real/UavTelemetryDataCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/register/HeartbeatReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/register/RegisterReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/register/UavInitInfoCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/register/UavInitReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/settings/ReturnHeightSettingReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/settings/ReturnPointSettingReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/settings/VideoStreamSettingReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/wayline/WayLineBeginReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/wayline/WayLineEndReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/wayline/WayLinePauseReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/wayline/WayLineResumeReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/component/netty/command/wayline/WayLineUploadReplyCmd.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/domain/dto/state/PointData.java 63 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/domain/dto/wayline/PlanLineData.java 52 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/domain/dto/wayline/PointAction.java 33 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/domain/dto/wayline/WayLineUploadDTO.java 8 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/domain/entity/ArdDroneInfo.java 1 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/domain/entity/ArdFlightTask.java 23 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/domain/entity/ArdMedia.java 16 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/domain/entity/ArdServerInfo.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/domain/entity/UavWayline.java 6 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/mapper/ArdFlightTaskMapper.java 3 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/mapper/ArdMediaMapper.java 8 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceServiceImpl.java 415 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/service/impl/ArdMediaServiceImpl.java 2 ●●●●● patch | view | raw | blame | history
ard-work/src/main/resources/mapper/ArdFlightTaskMapper.xml 21 ●●●●● patch | view | raw | blame | history
ard-work/src/main/resources/mapper/ArdMediaMapper.xml 152 ●●●●● patch | view | raw | blame | history
ard-admin/src/main/java/com/ard/web/controller/route/ArdRouteInfoController.java
@@ -132,10 +132,51 @@
    /**
     * 上传航线到边缘服务器
     */
//    @ApiOperation("上传航线到边缘服务器")
//    @PostMapping
//    public AjaxResult uploadRouteInformation(@RequestBody ArdRouteInfo ArdRouteInfor) {
//        return success(ardRouteInfoService.selectArdRouteInforByName(ArdRouteInfor.getName()));
//    }
    @ApiOperation("上传航线到边缘服务器")
    @PostMapping("/uploadRouteToSixHe/{id}/{boxSn}")
    public AjaxResult uploadRouteToSixHe(@PathVariable("id") String id,
                                         @PathVariable("boxSn") String boxSn) {
        return success(ardRouteInfoService.uploadRouteToSixHe(id,boxSn));
    }
    /**
     * 开始航线
     */
    @ApiOperation("开始航线")
    @PostMapping("/routeBegins/{boxSn}")
    public AjaxResult routeBegins(@PathVariable("boxSn") String boxSn) {
        ardRouteInfoService.routeBegins(boxSn);
        return AjaxResult.success();
    }
    /**
     * 暂停航线
     */
    @ApiOperation("暂停航线")
    @PostMapping("/routeSuspension/{boxSn}")
    public AjaxResult routeSuspension(@PathVariable("boxSn") String boxSn) {
        ardRouteInfoService.routeSuspension(boxSn);
        return AjaxResult.success();
    }
    /**
     * 恢复航线
     */
    @ApiOperation("恢复航线")
    @PostMapping("/routeResumption/{boxSn}")
    public AjaxResult routeResumption(@PathVariable("boxSn") String boxSn) {
        ardRouteInfoService.routeResumption(boxSn);
        return AjaxResult.success();
    }
    /**
     * 结束航线
     */
    @ApiOperation("结束航线")
    @PostMapping("/routeEnd/{boxSn}")
    public AjaxResult routeEnd(@PathVariable("boxSn") String boxSn) {
        ardRouteInfoService.routeEnd(boxSn);
        return AjaxResult.success();
    }
}
ard-route/pom.xml
@@ -55,6 +55,10 @@
            <groupId>com.ard</groupId>
            <artifactId>ard-system</artifactId>
        </dependency>
        <dependency>
            <groupId>com.ard</groupId>
            <artifactId>ard-work</artifactId>
        </dependency>
    </dependencies>
ard-route/src/main/java/com/ard/route/domain/sixhe/ArdRouteChange.java
@@ -26,4 +26,8 @@
    private List<ArdRoutePoints> points;
    private Integer securityHeight;
    private Integer templateId;
}
ard-route/src/main/java/com/ard/route/service/IArdRouteInfoService.java
@@ -4,6 +4,8 @@
import com.ard.oss.model.MinioUploadResult;
import com.ard.route.domain.dto.ArdNoflyDto;
import com.ard.route.domain.route.ArdRouteInfo;
import com.ard.route.domain.sixhe.ArdRouteChange;
import com.ard.work.domain.dto.wayline.WayLineUploadDTO;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@@ -92,9 +94,51 @@
    /**
     * 判断行点是否在禁飞区
     *
     * ardNoflyDto
     * @param ardNoflyDto 禁飞区DTO实体类
     * @return 结果
     */
    public Boolean selectRouteInfomationNoFly(ArdNoflyDto ardNoflyDto);
    /**
     * 上传航线到边缘服务器
     *
     * @param id ID
     * @param boxSn 云盒SN编号
     * @return 结果
     */
    public Boolean uploadRouteToSixHe(String id, String boxSn);
    /**
     * 开始航线
     *
     * @param boxSn 云盒SN编号
     * @return 结果
     */
    public Boolean routeBegins(String boxSn);
    /**
     * 暂停航线
     *
     * @param boxSn 云盒SN编号
     * @return 结果
     */
    public Boolean routeSuspension(String boxSn);
    /**
     * 恢复航线
     *
     * @param boxSn 云盒SN编号
     * @return 结果
     */
    public Boolean routeResumption(String boxSn);
    /**
     * 结束航线
     *
     * @param boxSn 云盒SN编号
     * @return 结果
     */
    public Boolean routeEnd(String boxSn);
}
ard-route/src/main/java/com/ard/route/service/impl/ArdRouteInfoServiceImpl.java
@@ -1,6 +1,7 @@
package com.ard.route.service.impl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.ard.common.exception.ControlException;
@@ -13,13 +14,20 @@
import com.ard.data.noflyzone.utils.NoFlyZoneUtils;
import com.ard.oss.model.MinioUploadResult;
import com.ard.oss.service.impl.OssServiceContext;
import com.ard.route.domain.djuav.ActionGroupReq;
import com.ard.route.domain.djuav.PointActionReq;
import com.ard.route.domain.djuav.RoutePointReq;
import com.ard.route.domain.djuav.UavRouteReq;
import com.ard.route.domain.dto.ArdNoflyDto;
import com.ard.route.domain.route.ArdRouteInfo;
import com.ard.route.domain.sixhe.ArdRouteChange;
import com.ard.route.domain.vo.KmzResultVo;
import com.ard.route.mapper.ArdRouteInfoMapper;
import com.ard.route.service.IArdRouteInfoService;
import com.ard.route.service.UavRouteService;
import com.ard.work.domain.dto.state.PointData;
import com.ard.work.domain.dto.wayline.*;
import com.ard.work.service.ITyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@@ -48,6 +56,9 @@
    @Resource
    private IArdNoFlyZoneService ardNoFlyZoneService;
    @Resource
    private ITyService tyService;
    /**
     * 查询航线(kmz)
@@ -227,6 +238,228 @@
    }
    /**
     * 上传航线到边缘服务器
     *
     * ardNoflyDto
     * @return 结果
     */
    @Override
    public Boolean uploadRouteToSixHe(String id,String boxSn) {
        // 1.获取航线信息
        // 1.1通过航线数据,转换。
        ArdRouteInfo route = ardRouteInfoMapper.selectArdRouteInfoById(id);
        try {
            route.setUavRouteReq((UavRouteReq) deserialize(route.getRouteData()));
        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        // 2.将航线信息转换成对应实体类
        WayLineUploadDTO wayLineUploadDTO = buildWayLineUploadDTO(route);
        // 3.调用接口
        tyService.wayLineUpload(wayLineUploadDTO);
        return true;
    }
    /**
     * 开始航线
     *
     * @param boxSn 云盒SN编号
     * @return 结果
     */
    @Override
    public Boolean routeBegins(String boxSn) {
        WayLineBeginDTO wayLineBeginDTO = new WayLineBeginDTO(boxSn);
        tyService.wayLineBegin(wayLineBeginDTO);
        return true;
    }
    /**
     * 暂停航线
     *
     * @param boxSn 云盒SN编号
     * @return 结果
     */
    @Override
    public Boolean routeSuspension(String boxSn) {
        WayLinePauseDTO wayLinePauseDTO = new WayLinePauseDTO(boxSn);
        tyService.wayLinePause(wayLinePauseDTO);
        return true;
    }
    /**
     * 恢复航线
     *
     * @param boxSn 云盒SN编号
     * @return 结果
     */
    @Override
    public Boolean routeResumption(String boxSn) {
        WayLineResumeDTO wayLineResumeDTO = new WayLineResumeDTO(boxSn);
        tyService.wayLineResume(wayLineResumeDTO);
        return true;
    }
    /**
     * 结束航线
     *
     * @param boxSn 云盒SN编号
     * @return 结果
     */
    @Override
    public Boolean routeEnd(String boxSn) {
        WayLineEndDTO wayLineEndDTO = new WayLineEndDTO(boxSn);
        tyService.wayLineEnd(wayLineEndDTO);
        return true;
    }
    /**
     * ArdRouteInfo实体转换,WayLineUploadDTO
     */
    private WayLineUploadDTO buildWayLineUploadDTO(ArdRouteInfo ardRouteInfo){
        WayLineUploadDTO wayLineUploadDTO = new WayLineUploadDTO();
        String finishAction = ardRouteInfo.getUavRouteReq().getFinishAction(); //1
        Double autoFlightSpeed = ardRouteInfo.getUavRouteReq().getAutoFlightSpeed(); //15
        Double globalTransitionalSpeed = ardRouteInfo.getUavRouteReq().getGlobalTransitionalSpeed(); //8
        String exitOnRcLostAction = ardRouteInfo.getUavRouteReq().getExitOnRcLostAction();  //0
        PlanLineData planLineData = new PlanLineData();
        if (finishAction != null){
            planLineData.setLoseAction(0);
        }
        if (autoFlightSpeed != null){
            planLineData.setAutoSpeed(8);
        }
        if (globalTransitionalSpeed != null){
            planLineData.setMaxSpeed(15);
        }
        if (exitOnRcLostAction != null){
            planLineData.setFinishedAction(1);
        }
        planLineData.setHomeHeight(50);
        planLineData.setInterests(new ArrayList<>());
        planLineData.setIsSaveEnergyMode(0);
        planLineData.setPoints(buildPointDataList(ardRouteInfo.getUavRouteReq()));
        wayLineUploadDTO.setWayLineData(planLineData);
        return wayLineUploadDTO;
    }
    private List<PointData> buildPointDataList(UavRouteReq uavRouteReq){
        List<PointData> pointDataList = new ArrayList<>();
        for (RoutePointReq routePointReq : uavRouteReq.getRoutePointList()) {
            PointData pointData = new PointData();
            Integer routePointIndex = routePointReq.getRoutePointIndex();
            if (routePointIndex != null){
                pointData.setGroupIndex(routePointIndex);
            }
            Double height = routePointReq.getHeight();
            if (height != null){
                pointData.setHeight(height.floatValue());
            }
            Double longitude = routePointReq.getLatitude();
            if (longitude != null){
                pointData.setLng(longitude.floatValue());
            }
            Double latitude = routePointReq.getLongitude();
            if (latitude != null){
                pointData.setLat(latitude.floatValue());
            }
            Double speed = routePointReq.getSpeed();
            if (speed != null){
                pointData.setSpeed(speed.floatValue());
            }
            pointData.setDampingDistance(0);
            pointData.setFlightPathMode(1);
            pointData.setHeading(0);
            pointData.setHeadingMode(0);
            pointData.setInterestIndex(-1);
            pointData.setSafeGohomeFlag(0);
            pointData.setActions(buildPointActionList(routePointReq.getActionGroupList()));
            pointDataList.add(pointData);
        }
        return pointDataList;
    }
    private List<PointAction> buildPointActionList(List<ActionGroupReq> actionGroupList){
        List<PointAction> pointActionList = new ArrayList<>();
        for (ActionGroupReq actionGroupReq : actionGroupList) {
            for (PointActionReq action : actionGroupReq.getActions()) {
                PointAction pointAction = typeProcessing(action);
                pointActionList.add(pointAction);
            }
        }
        return pointActionList;
    }
    private PointAction typeProcessing(PointActionReq pointActionReq){
        PointAction pointAction = new PointAction();
        if (pointActionReq.getZoom() != null){
            pointAction.setType(1);
            pointAction.setParam(pointActionReq.getZoom().floatValue());
            pointAction.setSpeakInfo("");
            pointAction.setWaitTime(2);
        }
        if (pointActionReq.getTakePhotoType() != null){
            pointAction.setType(2);
            pointAction.setParam(1);
            pointAction.setSpeakInfo("");
            pointAction.setWaitTime(2);
        }
        if (pointActionReq.getStartRecord() != null){
            pointAction.setType(3);
            pointAction.setParam(1);
            pointAction.setSpeakInfo("");
            pointAction.setWaitTime(2);
        }
        if (pointActionReq.getStopRecord() != null){
            pointAction.setType(4);
            pointAction.setParam(1);
            pointAction.setSpeakInfo("");
            pointAction.setWaitTime(2);
        }
        if (pointActionReq.getAircraftHeading() != null){
            pointAction.setType(5);
            pointAction.setParam(pointActionReq.getAircraftHeading().floatValue());
            pointAction.setSpeakInfo("");
            pointAction.setWaitTime(2);
        }
        if (pointActionReq.getGimbalPitchRotateAngle() != null){
            pointAction.setType(6);
            pointAction.setParam(pointActionReq.getGimbalPitchRotateAngle().floatValue());
            pointAction.setSpeakInfo("");
            pointAction.setWaitTime(2);
        }
        if (pointActionReq.getGimbalYawRotateAngle() != null){
            pointAction.setType(7);
            pointAction.setParam(pointActionReq.getGimbalYawRotateAngle().floatValue());
            pointAction.setSpeakInfo("");
            pointAction.setWaitTime(2);
        }
        if (pointActionReq.getHoverTime() != null){
            pointAction.setType(9);
            pointAction.setParam(pointActionReq.getHoverTime().floatValue());
            pointAction.setSpeakInfo("");
            pointAction.setWaitTime(2);
        }
        return pointAction;
    }
    /**
     * 数据新增航线信息
     */
    private void insertRouteInfomation(ArdRouteInfo ardRouteInfo){
ard-route/src/main/java/com/ard/route/util/InitializationUtils.java
@@ -80,40 +80,137 @@
        ardRouteChange.setIsSaveEnergyMode(0);
        ardRouteChange.setLoseAction(0);
        ardRouteChange.setMaxSpeed(15);
        ardRouteChange.setSecurityHeight(50);
        ardRouteChange.setTemplateId(0);
        List<ArdRoutePoints> points = new ArrayList<>();
        ArdRoutePoints ardRoutePoints0 = new ArdRoutePoints();
        ardRoutePoints0.setDampingDistance(0);
        ardRoutePoints0.setFlightPathMode(1);
        ardRoutePoints0.setGroupIndex(0);
        ardRoutePoints0.setHeading(0);
        ardRoutePoints0.setHeadingMode(0);
        ardRoutePoints0.setHeight(50);
        ardRoutePoints0.setInterestIndex(0);
        ardRoutePoints0.setLat(31.11339916);
        ardRoutePoints0.setLon(103.75851462);
        ardRoutePoints0.setSafeGohomeFlag(0);
        ardRoutePoints0.setSpeed(8);
        List<ArdRouteActions> actions = new ArrayList<>();
        ArdRouteActions ardRouteActions0 = new ArdRouteActions();
        ardRouteActions0.setParam(10);
        ardRouteActions0.setSpeakInfo("");
        ardRouteActions0.setType(1);
        ardRouteActions0.setWaitTime(2);
        ArdRouteActions ardRouteActions1 = new ArdRouteActions();
        ardRouteActions1.setParam(10);
        ardRouteActions1.setSpeakInfo("");
        ardRouteActions1.setType(1);
        ardRouteActions1.setWaitTime(2);
        ArdRouteActions ardRouteActions2 = new ArdRouteActions();
        ardRouteActions2.setParam(10);
        ardRouteActions2.setSpeakInfo("");
        ardRouteActions2.setType(1);
        ardRouteActions2.setWaitTime(2);
        actions.add(ardRouteActions0);
        actions.add(ardRouteActions1);
        actions.add(ardRouteActions2);
        points.add(ardRoutePoints0);
        //-----------------------------------------------------
        ArdRoutePoints ardRoutePoints00 = new ArdRoutePoints();
        ardRoutePoints00.setDampingDistance(0);
        ardRoutePoints00.setFlightPathMode(1);
        ardRoutePoints00.setGroupIndex(0);
        ardRoutePoints00.setHeading(0);
        ardRoutePoints00.setHeadingMode(0);
        ardRoutePoints00.setHeight(50);
        ardRoutePoints00.setInterestIndex(-1);
        ardRoutePoints00.setLat(31.11339916);
        ardRoutePoints00.setLon(103.75851462);
        ardRoutePoints00.setSafeGohomeFlag(0);
        ardRoutePoints00.setSpeed(8);
        List<ArdRouteActions> actions00 = new ArrayList<>();
        ArdRouteActions ardRouteActions00 = new ArdRouteActions();
        ardRouteActions00.setParam(10);
        ardRouteActions00.setSpeakInfo("");
        ardRouteActions00.setType(1);
        ardRouteActions00.setWaitTime(2);
        ArdRouteActions ardRouteActions01 = new ArdRouteActions();
        ardRouteActions01.setParam(10);
        ardRouteActions01.setSpeakInfo("");
        ardRouteActions01.setType(1);
        ardRouteActions01.setWaitTime(2);
        ArdRouteActions ardRouteActions02 = new ArdRouteActions();
        ardRouteActions02.setParam(10);
        ardRouteActions02.setSpeakInfo("");
        ardRouteActions02.setType(1);
        ardRouteActions02.setWaitTime(2);
        actions00.add(ardRouteActions00);
        actions00.add(ardRouteActions01);
        actions00.add(ardRouteActions02);
        ardRoutePoints00.setActions(actions00);
        //-----------------------------------------------------
        ArdRoutePoints ardRoutePoints10 = new ArdRoutePoints();
        ardRoutePoints10.setDampingDistance(0);
        ardRoutePoints10.setFlightPathMode(1);
        ardRoutePoints10.setGroupIndex(0);
        ardRoutePoints10.setHeading(0);
        ardRoutePoints10.setHeadingMode(0);
        ardRoutePoints10.setHeight(50);
        ardRoutePoints10.setInterestIndex(-1);
        ardRoutePoints10.setLat(31.11339916);
        ardRoutePoints10.setLon(103.75746538);
        ardRoutePoints10.setSafeGohomeFlag(0);
        ardRoutePoints10.setSpeed(8);
        List<ArdRouteActions> actions10 = new ArrayList<>();
        ArdRouteActions ardRouteActions10 = new ArdRouteActions();
        ardRouteActions10.setParam(20);
        ardRouteActions10.setSpeakInfo("");
        ardRouteActions10.setType(9);
        ardRouteActions10.setWaitTime(2);
        ArdRouteActions ardRouteActions11 = new ArdRouteActions();
        ardRouteActions11.setParam(40);
        ardRouteActions11.setSpeakInfo("");
        ardRouteActions11.setType(6);
        ardRouteActions11.setWaitTime(2);
        ArdRouteActions ardRouteActions12 = new ArdRouteActions();
        ardRouteActions12.setParam(40);
        ardRouteActions12.setSpeakInfo("");
        ardRouteActions12.setType(7);
        ardRouteActions12.setWaitTime(2);
        ArdRouteActions ardRouteActions13 = new ArdRouteActions();
        ardRouteActions13.setParam(40);
        ardRouteActions13.setSpeakInfo("");
        ardRouteActions13.setType(8);
        ardRouteActions13.setWaitTime(2);
        actions10.add(ardRouteActions10);
        actions10.add(ardRouteActions11);
        actions10.add(ardRouteActions12);
        ardRoutePoints10.setActions(actions10);
        //-----------------------------------------------------
        ArdRoutePoints ardRoutePoints20 = new ArdRoutePoints();
        ardRoutePoints20.setDampingDistance(0);
        ardRoutePoints20.setFlightPathMode(1);
        ardRoutePoints20.setGroupIndex(0);
        ardRoutePoints20.setHeading(0);
        ardRoutePoints20.setHeadingMode(0);
        ardRoutePoints20.setHeight(50);
        ardRoutePoints20.setInterestIndex(-1);
        ardRoutePoints20.setLat(31.11250084);
        ardRoutePoints20.setLon(103.75746538);
        ardRoutePoints20.setSafeGohomeFlag(0);
        ardRoutePoints20.setSpeed(8);
        List<ArdRouteActions> actions20 = new ArrayList<>();
        ArdRouteActions ardRouteActions20 = new ArdRouteActions();
        ardRouteActions20.setParam(15);
        ardRouteActions20.setSpeakInfo("");
        ardRouteActions20.setType(9);
        ardRouteActions20.setWaitTime(2);
        ArdRouteActions ardRouteActions21 = new ArdRouteActions();
        ardRouteActions21.setParam(3);
        ardRouteActions21.setSpeakInfo("");
        ardRouteActions21.setType(10);
        ardRouteActions21.setWaitTime(2);
        actions20.add(ardRouteActions20);
        actions20.add(ardRouteActions21);
        ardRoutePoints20.setActions(actions20);
        //-----------------------------------------------------
        ArdRoutePoints ardRoutePoints30 = new ArdRoutePoints();
        ardRoutePoints30.setDampingDistance(0);
        ardRoutePoints30.setFlightPathMode(1);
        ardRoutePoints30.setGroupIndex(0);
        ardRoutePoints30.setHeading(0);
        ardRoutePoints30.setHeadingMode(0);
        ardRoutePoints30.setHeight(60);
        ardRoutePoints30.setInterestIndex(-1);
        ardRoutePoints30.setLat(31.11250084);
        ardRoutePoints30.setLon(103.75851462);
        ardRoutePoints30.setSafeGohomeFlag(0);
        ardRoutePoints30.setSpeed(8);
        List<ArdRouteActions> actions30 = new ArrayList<>();
        ArdRouteActions ardRouteActions30 = new ArdRouteActions();
        ardRouteActions30.setParam(1);
        ardRouteActions30.setSpeakInfo("");
        ardRouteActions30.setType(2);
        ardRouteActions30.setWaitTime(2);
        actions30.add(ardRouteActions30);
        ardRoutePoints30.setActions(actions30);
        points.add(ardRoutePoints00);
        points.add(ardRoutePoints10);
        points.add(ardRoutePoints20);
        points.add(ardRoutePoints30);
        ardRouteChange.setPoints(points);
    }
ard-work/pom.xml
@@ -113,6 +113,15 @@
            <groupId>com.ard</groupId>
            <artifactId>ard-oss</artifactId>
        </dependency>
        <!-- JavaCV 核心(非常小) -->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv</artifactId>
            <version>1.5.8</version>
        </dependency>
    </dependencies>
    <repositories>
        <repository>
ard-work/src/main/java/com/ard/work/component/netty/command/camera/CameraModeCmd.java
@@ -4,6 +4,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 设置相机模式指令
@@ -11,6 +12,7 @@
 * @author liusuyi
 * @date 2024年10月25日14:44
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class CameraModeCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
ard-work/src/main/java/com/ard/work/component/netty/command/camera/CameraModeReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 设置相机模式回复指令
@@ -10,6 +11,7 @@
 * @author liusuyi
 * @date 2024年10月25日14:44
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class CameraModeReplyCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
ard-work/src/main/java/com/ard/work/component/netty/command/camera/CapturePicCmd.java
@@ -4,6 +4,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 抓拍指令
@@ -11,6 +12,7 @@
 * @author liusuyi
 * @date 2024年10月25日14:44
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class CapturePicCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
ard-work/src/main/java/com/ard/work/component/netty/command/camera/CapturePicReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 抓拍回复指令
@@ -10,6 +11,7 @@
 * @author liusuyi
 * @date 2024年10月25日14:44
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class CapturePicReplyCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
ard-work/src/main/java/com/ard/work/component/netty/command/camera/PhotoReturnToggleCmd.java
@@ -4,6 +4,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 打开或关闭照片回传指令
@@ -11,6 +12,7 @@
 * @author liusuyi
 * @date 2024年10月25日14:44
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class PhotoReturnToggleCmd extends BaseCmd {
    private final byte encryptFlag = 0x00;      // 加密标志
ard-work/src/main/java/com/ard/work/component/netty/command/camera/PicUploadCompletedReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.nio.charset.StandardCharsets;
@@ -12,6 +13,7 @@
 * @author liusuyi
 * @date 2024年10月26日11:54
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class PicUploadCompletedReplyCmd extends BaseCmd {
    private final byte encryptFlag = 0x00;  // 加密标志
ard-work/src/main/java/com/ard/work/component/netty/command/camera/RecordStartCmd.java
@@ -4,6 +4,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 开始录像指令
@@ -12,6 +13,7 @@
 * @date 2024年10月25日14:44
 **/
@Data
@EqualsAndHashCode(callSuper = false)
public class RecordStartCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
    private final byte actionCode=0x24;    // 动作编号
ard-work/src/main/java/com/ard/work/component/netty/command/camera/RecordStartReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 开始录像回复指令
@@ -10,6 +11,7 @@
 * @author liusuyi
 * @date 2024年10月25日14:44
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class RecordStartReplyCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
ard-work/src/main/java/com/ard/work/component/netty/command/camera/RecordStopCmd.java
@@ -4,6 +4,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 停止录像指令
@@ -11,6 +12,7 @@
 * @author liusuyi
 * @date 2024年10月25日14:44
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class RecordStopCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
ard-work/src/main/java/com/ard/work/component/netty/command/camera/RecordStopReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 停止录像回复指令
@@ -10,6 +11,7 @@
 * @author liusuyi
 * @date 2024年10月25日14:44
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class RecordStopReplyCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
ard-work/src/main/java/com/ard/work/component/netty/command/camera/ZoomCmd.java
@@ -4,6 +4,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 变倍指令
@@ -12,6 +13,7 @@
 * @date 2024年10月25日14:44
 **/
@Data
@EqualsAndHashCode(callSuper = false)
public class ZoomCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
    private final byte actionCode;  // 动作编号
ard-work/src/main/java/com/ard/work/component/netty/command/camera/ZoomToLevelCmd.java
@@ -4,6 +4,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 变倍到指定倍数指令
@@ -11,6 +12,7 @@
 * @author liusuyi
 * @date 2024年10月25日14:44
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class ZoomToLevelCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
ard-work/src/main/java/com/ard/work/component/netty/command/control/AbsAngleControlCmd.java
@@ -4,6 +4,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 云台绝对值控制(基于角度)命令
@@ -13,6 +14,7 @@
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class AbsAngleControlCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
    private final byte actionCode = 0x09;  // 动作编号
ard-work/src/main/java/com/ard/work/component/netty/command/control/AngleControlCmd.java
@@ -4,6 +4,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 云台转动(基于角度)命令
@@ -13,6 +14,7 @@
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class AngleControlCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
    private final byte actionCode; // 动作编号
ard-work/src/main/java/com/ard/work/component/netty/command/control/SpeedControlCmd.java
@@ -4,6 +4,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 云台绝对值控制(基于角度)命令
@@ -12,6 +13,7 @@
 * @date 2024/10/22 16:36
 */
@EqualsAndHashCode(callSuper = true)
@Data
public class SpeedControlCmd extends BaseCmd {
    private final byte encryptFlag = 0x00;          // 加密标志
ard-work/src/main/java/com/ard/work/component/netty/command/manual/EmergencyBrakeReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 紧急制动回复指令
@@ -10,6 +11,7 @@
 * @author liusuyi
 * @date 2024年10月30日16:20
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class EmergencyBrakeReplyCmd extends BaseCmd {
ard-work/src/main/java/com/ard/work/component/netty/command/manual/LandCancelReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 取消降落回复指令
@@ -11,6 +12,7 @@
 * @date 2024年10月26日15:43
 **/
@Data
@EqualsAndHashCode(callSuper = false)
public class LandCancelReplyCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
ard-work/src/main/java/com/ard/work/component/netty/command/manual/LandForcedReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 强制降落回复指令
@@ -10,6 +11,7 @@
 * @author liusuyi
 * @date 2024年10月26日15:43
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class LandForcedReplyCmd extends BaseCmd {
ard-work/src/main/java/com/ard/work/component/netty/command/manual/LandReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 降落回复指令
@@ -10,6 +11,7 @@
 * @author liusuyi
 * @date 2024年10月26日15:43
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class LandReplyCmd extends BaseCmd {
ard-work/src/main/java/com/ard/work/component/netty/command/manual/PointControlReachedReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 到达指点飞行位置回复指令
@@ -10,6 +11,7 @@
 * @author liusuyi
 * @date 2024年10月26日15:43
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class PointControlReachedReplyCmd extends BaseCmd {
ard-work/src/main/java/com/ard/work/component/netty/command/manual/ReturnHomeCancelReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 取消返航回复指令
@@ -11,6 +12,7 @@
 * @date 2024年10月26日15:43
 **/
@Data
@EqualsAndHashCode(callSuper = false)
public class ReturnHomeCancelReplyCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
ard-work/src/main/java/com/ard/work/component/netty/command/manual/ReturnHomeReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 返航回复指令
@@ -10,6 +11,7 @@
 * @author liusuyi
 * @date 2024年10月26日15:43
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class ReturnHomeReplyCmd extends BaseCmd {
ard-work/src/main/java/com/ard/work/component/netty/command/manual/TakeOffReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 起飞回复指令
@@ -10,6 +11,7 @@
 * @author liusuyi
 * @date 2024年10月26日15:43
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class TakeOffReplyCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
ard-work/src/main/java/com/ard/work/component/netty/command/notice/BoxPowerStatusReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 云盒开关机通知回复指令
@@ -11,6 +12,7 @@
 * @date 2024年10月26日11:54
 **/
@Data
@EqualsAndHashCode(callSuper = false)
public class BoxPowerStatusReplyCmd extends BaseCmd {
    private final byte status; // 时间戳
ard-work/src/main/java/com/ard/work/component/netty/command/notice/FlyWayEndReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 航线结束通知回复指令
@@ -11,6 +12,7 @@
 * @date 2024年10月26日11:54
 **/
@Data
@EqualsAndHashCode(callSuper = false)
public class FlyWayEndReplyCmd extends BaseCmd {
    private final byte encryptFlag = 0x00;  // 加密标志
    private final byte actionCode = 0x2E;   // 动作编号
ard-work/src/main/java/com/ard/work/component/netty/command/notice/UavReadyReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 无人机准备完成通知回复指令
@@ -11,6 +12,7 @@
 * @date 2024年10月26日11:54
 **/
@Data
@EqualsAndHashCode(callSuper = false)
public class UavReadyReplyCmd extends BaseCmd {
    private final byte encryptFlag = 0x00;  // 加密标志
    private final byte actionCode = 0x3D;   // 动作编号
ard-work/src/main/java/com/ard/work/component/netty/command/real/SignalInfoCmd.java
@@ -4,7 +4,9 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class SignalInfoCmd extends BaseCmd {
    private int delayTime;
ard-work/src/main/java/com/ard/work/component/netty/command/real/UavStateCmd.java
@@ -4,7 +4,9 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class UavStateCmd extends BaseCmd {
    private UavState uavState;  // ProtoBuf 数据类
ard-work/src/main/java/com/ard/work/component/netty/command/real/UavTelemetryDataCmd.java
@@ -4,6 +4,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * UavDataCommand
@@ -12,6 +13,7 @@
 * @date 2024年10月23日9:33
 **/
@Data
@EqualsAndHashCode(callSuper = false)
public class UavTelemetryDataCmd extends BaseCmd {
    private TelemetryData telemetryData;
    // 构造函数
ard-work/src/main/java/com/ard/work/component/netty/command/register/HeartbeatReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
@@ -12,6 +13,7 @@
 * @date 2024/10/22 16:36
 */
@Data
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor
public class HeartbeatReplyCmd extends BaseCmd {
ard-work/src/main/java/com/ard/work/component/netty/command/register/RegisterReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 注册命令
@@ -10,6 +11,7 @@
 * @author 刘苏义
 * @date 2024/10/22 16:36
 */
@EqualsAndHashCode(callSuper = true)
@Data
public class RegisterReplyCmd extends BaseCmd {
    private byte success;
ard-work/src/main/java/com/ard/work/component/netty/command/register/UavInitInfoCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 无人机初始化回复命令
@@ -12,6 +13,7 @@
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class UavInitInfoCmd extends BaseCmd {
    private final byte encryptFlag; // 加密标志
ard-work/src/main/java/com/ard/work/component/netty/command/register/UavInitReplyCmd.java
@@ -4,6 +4,7 @@
import com.ard.work.component.netty.protobuf.TelemetryDataPB;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 *  无人机就绪通知命令
@@ -11,6 +12,7 @@
 * @author 刘苏义
 * @date 2024/10/24 17:18
 */
@EqualsAndHashCode(callSuper = true)
@Data
public class UavInitReplyCmd extends BaseCmd {
ard-work/src/main/java/com/ard/work/component/netty/command/settings/ReturnHeightSettingReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 修改返航高度回复指令
@@ -11,6 +12,7 @@
 * @date 2024年10月30日16:20
 **/
@Data
@EqualsAndHashCode(callSuper = false)
public class ReturnHeightSettingReplyCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
ard-work/src/main/java/com/ard/work/component/netty/command/settings/ReturnPointSettingReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 修改返航高度回复指令
@@ -10,6 +11,7 @@
 * @author liusuyi
 * @date 2024年10月30日16:20
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class ReturnPointSettingReplyCmd extends BaseCmd {
ard-work/src/main/java/com/ard/work/component/netty/command/settings/VideoStreamSettingReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 设置视频码流回复指令
@@ -10,6 +11,7 @@
 * @author liusuyi
 * @date 2024年10月30日16:20
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class VideoStreamSettingReplyCmd extends BaseCmd {
ard-work/src/main/java/com/ard/work/component/netty/command/wayline/WayLineBeginReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 开始航线回复指令
@@ -10,6 +11,7 @@
 * @author liusuyi
 * @date 2024年10月30日16:20
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class WayLineBeginReplyCmd extends BaseCmd {
ard-work/src/main/java/com/ard/work/component/netty/command/wayline/WayLineEndReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 结束航线回复指令
@@ -11,6 +12,7 @@
 * @date 2024年10月30日16:20
 **/
@Data
@EqualsAndHashCode(callSuper = false)
public class WayLineEndReplyCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
ard-work/src/main/java/com/ard/work/component/netty/command/wayline/WayLinePauseReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 暂停航线回复指令
@@ -10,6 +11,7 @@
 * @author liusuyi
 * @date 2024年10月30日16:20
 **/
@EqualsAndHashCode(callSuper = true)
@Data
public class WayLinePauseReplyCmd extends BaseCmd {
ard-work/src/main/java/com/ard/work/component/netty/command/wayline/WayLineResumeReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 恢复航线回复指令
@@ -11,6 +12,7 @@
 * @date 2024年10月30日16:20
 **/
@Data
@EqualsAndHashCode(callSuper = false)
public class WayLineResumeReplyCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
ard-work/src/main/java/com/ard/work/component/netty/command/wayline/WayLineUploadReplyCmd.java
@@ -3,6 +3,7 @@
import com.ard.work.component.netty.command.BaseCmd;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 上传航线回复指令
@@ -11,6 +12,7 @@
 * @date 2024年10月30日16:20
 **/
@Data
@EqualsAndHashCode(callSuper = false)
public class WayLineUploadReplyCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
ard-work/src/main/java/com/ard/work/domain/dto/state/PointData.java
@@ -8,17 +8,56 @@
// 假设 PointData 类定义如下
@Data
public class PointData {
    private double lat; // 纬度
    private double lng; // 经度
    private float height; // 高度(单位:米,范围0~遥控器限高)
    private float speed; // 速度(单位:米/秒,范围0~15),默认8
    private List<PointAction> actions; // 动作数组
    private int flightPathMode; // 航线飞行模式:1=直线飞行,2=协调转弯,3=曲线飞行(停),4=曲线飞行(不停)
    private float dampingDistance; // 转弯半径(仅协调转弯模式下有效),取值范围1~655.35单位:米
    private int safeGohomeFlag; // 是否为安全返航点 0=不是,1=是
    private int headingMode; // 偏航模式 0=自动,1=锁定,2=遥控器控制,3=云台依照航点方向旋转,4=朝向兴趣点,5=飞机和云台的偏航同时旋转
    private float heading; // 航点偏航 -180~180
    private int interestIndex; // 兴趣点下标,默认-1
    private int groupIndex; // 组下标
    /** 纬度 */
    private double lat;
    /** 经度 */
    private double lng;
    /** 高度(单位:米,范围0~遥控器限高) */
    private float height;
    /** 速度(单位:米/秒,范围0~15),默认8 */
    private float speed;
    /** 动作数组 */
    private List<PointAction> actions;
    /** 航线飞行模式:
     * 1=直线飞行,
     * 2=协调转弯,
     * 3=曲线飞行(停),
     * 4=曲线飞行(不停)
     */
    private int flightPathMode;
    /** 转弯半径(仅协调转弯模式下有效),取值范围1~655.35单位:米 */
    private float dampingDistance;
    /** 是否为安全返航点
     * 0=不是,
     * 1=是
     */
    private int safeGohomeFlag;
    /** 偏航模式
     * 0=自动,
     * 1=锁定,
     * 2=遥控器控制,
     * 3=云台依照航点方向旋转,
     * 4=朝向兴趣点,
     * 5=飞机和云台的偏航同时旋转
     */
    private int headingMode;
    /** 航点偏航 -180~180 */
    private float heading;
    /** 兴趣点下标,默认-1 */
    private int interestIndex;
    /** 组下标 */
    private int groupIndex;
}
ard-work/src/main/java/com/ard/work/domain/dto/wayline/PlanLineData.java
@@ -18,17 +18,43 @@
@AllArgsConstructor
@NoArgsConstructor
public class PlanLineData {
    private int finishedAction;     // 结束航线后动作(必填)
    private float maxSpeed;         // 最大飞行速度(单位:米/秒)
    private float autoSpeed;        // 自动飞行速度(单位:米/秒)
    private List<PointData> points; // 坐标点数组(必填)
    private int loseAction;         // 网络失联后动作(必填)
    private int homeHeight;         // 返航高度(必填)
    private int isSaveEnergyMode;   // 是否开启节能模式
    private HangarPoint takePoint;  // 起飞点机库信息
    private HangarPoint landPoint;  // 降落点机库信息
    private List<PointData> interests;      // 兴趣点数组
    private NormalModel normalModel;        // 普通建模
    private SurroundModel surroundModel;    // 环绕建模
    private PointData takeOffPoint;         // 起飞点
    /**  结束航线后动作(必填) */
    private int finishedAction;
    /**  最大飞行速度(单位:米/秒) */
    private float maxSpeed;
    /**  自动飞行速度(单位:米/秒) */
    private float autoSpeed;
    /**  坐标点数组(必填) */
    private List<PointData> points;
    /**  网络失联后动作(必填) */
    private int loseAction;
    /**  返航高度(必填) */
    private int homeHeight;
    /**  是否开启节能模式 */
    private int isSaveEnergyMode;
    /**  起飞点机库信息 */
    private HangarPoint takePoint;
    /**  降落点机库信息 */
    private HangarPoint landPoint;
    /**  兴趣点数组 */
    private List<PointData> interests;
    /**  普通建模 */
    private NormalModel normalModel;
    /**  环绕建模 */
    private SurroundModel surroundModel;
    /**  起飞点 */
    private PointData takeOffPoint;
}
ard-work/src/main/java/com/ard/work/domain/dto/wayline/PointAction.java
@@ -15,8 +15,33 @@
@AllArgsConstructor
@NoArgsConstructor
public class PointAction {
    private int type; // 类型:1-变焦 2-拍照 3-录像 4-停录 5-控制飞机机头偏航 6-控制云台俯仰 7-控制云台偏航 8-控制云台横滚 9-悬停 10-等距间隔拍照 11-等时间隔拍照 12-结束间隔拍照 13-单条喊话 14-开始循环喊话 15-结束循环喊话 16-对焦
    private float param; // 参数,根据类型不同含义不同
    private int waitTime; // 动作触发后等待时长(单位:秒)
    private String speakInfo; // 喊话内容[type=13和type=14时生效]
    /** 类型:
     * 1-变焦
     * 2-拍照
     * 3-录像
     * 4-停录
     * 5-控制飞机机头偏航
     * 6-控制云台俯仰
     * 7-控制云台偏航
     * 8-控制云台横滚
     * 9-悬停
     * 10-等距间隔拍照
     * 11-等时间隔拍照
     * 12-结束间隔拍照
     * 13-单条喊话
     * 14-开始循环喊话
     * 15-结束循环喊话
     * 16-对焦
     */
    private int type;
    /** 参数,根据类型不同含义不同 */
    private float param;
    /** 动作触发后等待时长(单位:秒) */
    private int waitTime;
    /** 喊话内容[type=13和type=14时生效] */
    private String speakInfo;
}
ard-work/src/main/java/com/ard/work/domain/dto/wayline/WayLineUploadDTO.java
@@ -16,6 +16,14 @@
@AllArgsConstructor
@NoArgsConstructor
public class WayLineUploadDTO {
    /**
     * 云盒SN编号
     */
    private String boxSn;
    /**
     * 航线数据
     */
    private PlanLineData wayLineData;
}
ard-work/src/main/java/com/ard/work/domain/entity/ArdDroneInfo.java
@@ -19,6 +19,7 @@
@Builder
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class ArdDroneInfo extends BaseEntity {
    private static final long serialVersionUID = 1L;
ard-work/src/main/java/com/ard/work/domain/entity/ArdFlightTask.java
@@ -1,12 +1,16 @@
package com.ard.work.domain.entity;
import com.ard.common.core.domain.BaseEntity;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.*;
import java.util.Date;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ArdFlightTask extends BaseEntity {
    private Integer taskId;             // 任务ID
@@ -16,8 +20,21 @@
    private Integer photoCount;         // 图片数量
    private Integer videoCount;         // 录像数量
    private String videoPath;           // 视频路径
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date startTime;             // 任务开始时间
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date endTime;               // 任务结束时间
    private Long duration;              // 持续时长(单位:秒)
    private String serverId;            // 服务器ID
    private List<ArdMedia> mediaList;   // 媒体文件列表
    // 计算持续时长,单位:秒
    public Long getDuration() {
        if (startTime != null && endTime != null) {
            // 计算时间差(毫秒)
            long durationMillis = endTime.getTime() - startTime.getTime();
            // 将毫秒转换为秒
            return durationMillis / 1000;
        }
        return null;
    }
}
ard-work/src/main/java/com/ard/work/domain/entity/ArdMedia.java
@@ -1,9 +1,16 @@
package com.ard.work.domain.entity;
import com.ard.common.core.domain.BaseEntity;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.*;
import java.util.Date;
@EqualsAndHashCode(callSuper = true)
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ArdMedia extends BaseEntity {
    private String id;                 // 媒体ID
@@ -13,4 +20,11 @@
    private String fileMd5;            // 文件MD5值
    private String mediaUrl;           // 地址
    private String sourceUrl;          // 源地址
    private Long   photoId;            // 图片ID
    private Double longitude;          // 经度
    private Double latitude;           // 纬度
    private Double height;             // 高度
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date captureTime;          // 抓拍时间
    private String thumbnailUrl;       // 视频缩略图URL
}
ard-work/src/main/java/com/ard/work/domain/entity/ArdServerInfo.java
@@ -5,6 +5,7 @@
import com.ard.common.core.domain.BaseEntity;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 服务器管理对象 ard_server
@@ -12,6 +13,7 @@
 * @author xia
 * @date 2025-10-10
 */
@EqualsAndHashCode(callSuper = true)
@Data
public class ArdServerInfo extends BaseEntity {
ard-work/src/main/java/com/ard/work/domain/entity/UavWayline.java
@@ -1,9 +1,6 @@
package com.ard.work.domain.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.*;
import com.ard.common.annotation.Excel;
import com.ard.common.core.domain.BaseEntity;
@@ -13,6 +10,7 @@
 * @author ard
 * @date 2025-06-27
 */
@EqualsAndHashCode(callSuper = true)
@Data
@Builder
@AllArgsConstructor
ard-work/src/main/java/com/ard/work/mapper/ArdFlightTaskMapper.java
@@ -10,6 +10,9 @@
    // 插入飞行任务
    int insertArdFlightTask(ArdFlightTask task);
    // 插入飞行任务
    int updateArdFlightTask(ArdFlightTask task);
    // 根据任务ID获取飞行任务
    ArdFlightTask getArdFlightTaskById(@Param("taskId") Integer taskId);
ard-work/src/main/java/com/ard/work/mapper/ArdMediaMapper.java
@@ -2,6 +2,8 @@
import com.ard.work.domain.entity.ArdMedia;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -14,7 +16,10 @@
     * @return 媒体数据集合
     */
    List<ArdMedia> selectArdMedia(ArdMedia ardMedia);  // 动态查询
    List<ArdMedia> selectArdMediaByTaskId(Integer taskId);  // 根据任务ID查询
    List<ArdMedia> selectArdMediaByTaskIdAndType(@Param("taskId") Integer taskId, @Param("mediaType") Integer mediaType);  //
    /**
     * 插入媒体数据记录
@@ -26,7 +31,10 @@
    void insertArdMediaList(List<ArdMedia> ardMediaList);  // 插入批量记录
    void updateArdMedia(ArdMedia ardMedia);  // 更新记录
    void deleteArdMediaById(Integer id);  // 根据ID删除记录
    void deleteArdMediaByIds(List<Integer> mediaIds);  // 批量删除记录
    void deleteArdMediaByTaskId(Integer taskId);  // 批量删除记录
}
ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceServiceImpl.java
@@ -1,10 +1,8 @@
package com.ard.work.service.impl;
import com.ard.common.utils.DateUtils;
import com.ard.common.utils.StringUtils;
import com.ard.common.utils.file.MimeTypeUtils;
import com.ard.common.utils.uuid.IdUtils;
import com.ard.oss.service.IOssService;
import com.ard.oss.service.impl.OssServiceContext;
import com.ard.work.component.forest.TyClient;
import com.ard.work.domain.dto.BoxHistoryDTO;
@@ -18,23 +16,29 @@
import com.ard.work.mapper.ArdMediaMapper;
import com.ard.work.service.IArdFlightTaskService;
import com.ard.work.service.IArdServerInfoService;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.net.ssl.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
@Slf4j
@Service
public class ArdFlightTaskServiceServiceImpl implements IArdFlightTaskService {
@@ -48,16 +52,23 @@
    private TyClient tyClient;
    @Resource
    private OssServiceContext ossServiceContext;
    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;  // 使用线程池执行异步任务
    /**
     * 查询飞行架次列表
     *
     * @param ardFlightTask 飞行架次
     * @return 飞行架次集合
     */
    @Override
    public List<ArdFlightTask> selectArdFlightTask(ArdFlightTask ardFlightTask) {
        return ardFlightTaskMapper.selectArdFlightTask(ardFlightTask);
    }
    // 同步所有服务的飞行历史
    /**
     * 同步所有服务的飞行历史
     */
    @Scheduled(fixedDelay = 10000)
    public void syncAllFlightHistory() {
        List<String> serverIds = ardServerInfoService.getServerIdsList();
@@ -75,12 +86,12 @@
        return maxStartTime != null ? maxStartTime : new Date(0);  // 如果没有数据,返回 Unix 纪元时间作为起点
    }
    // 调用接口获取飞行历史数据
    // 根据上次同步时间同步飞行历史
    public void syncFlightHistory(String serverId, Date lastSyncTime) {
    public void syncFlightHistory(String serverId, Date startTime) {
        // 创建查询条件 BoxHistoryDTO,并设置 startTime 作为过滤条件
        BoxHistoryDTO boxHistoryDTO = new BoxHistoryDTO();
        boxHistoryDTO.setStartTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, lastSyncTime));  // 传递 lastSyncTime 参数
        BoxHistoryDTO boxHistoryDTO = BoxHistoryDTO.builder()
                .startTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, startTime))
                .build();
        // 获取飞行历史
        List<BoxHistoryReceiver> historyList = getBoxHistory(serverId, boxHistoryDTO);
@@ -93,118 +104,257 @@
        }
    }
    // 将数据同步到本地数据库
    private void syncToLocalDatabase(String serverId, BoxHistoryReceiver boxHistoryReceiver) {
        // 检查是否已经存在相同任务ID的记录
        ArdFlightTask ardFlightTask = ardFlightTaskMapper.getArdFlightTaskById(boxHistoryReceiver.getTaskId());
        if (ardFlightTask == null) {
            // 如果不存在,则插入新记录
            log.debug("insert task {}", boxHistoryReceiver.getTaskId());
            // 创建FlightTask实体对象并填充数据
            ArdFlightTask flightTask = ArdFlightTask.builder()
                    .taskId(boxHistoryReceiver.getTaskId())
                    .boxSn(boxHistoryReceiver.getBoxSn())
                    .boxName(boxHistoryReceiver.getBoxName())
                    .taskName(boxHistoryReceiver.getTaskName())
                    .photoCount(Integer.parseInt(boxHistoryReceiver.getPhotoCount()))
                    .videoCount((boxHistoryReceiver.getVideoPathList() != null) ?
                            boxHistoryReceiver.getVideoPathList().size() : 0)
                    .videoPath(boxHistoryReceiver.getVideoPath())
                    .serverId(serverId)
                    .startTime(DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, boxHistoryReceiver.getStartTime()))
                    .endTime(DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, boxHistoryReceiver.getEndTime()))
                    .build();
            flightTask.setCreateTime(DateUtils.getNowDate());
            // 插入新记录
            int rows = ardFlightTaskMapper.insertArdFlightTask(flightTask);
            if (rows > 0) {
                // 删除旧的媒体记录,防止重复插入
                ardMediaMapper.deleteArdMediaByTaskId(flightTask.getTaskId());
                // 插入视频
                insertVideoToDatabase(flightTask, boxHistoryReceiver.getVideoPathList());
                // 插入图片
                insertPhotoToDatabase(flightTask, serverId, boxHistoryReceiver.getBoxSn());
            }
        } else {
            // 如果存在,则更新记录
            log.debug("Updating task {}", boxHistoryReceiver.getTaskId());
            // 增量更新
            updateVideoToDatabase(ardFlightTask, boxHistoryReceiver.getVideoPathList());
            // 增量更新图片
            updatePhotoToDatabase(ardFlightTask, serverId, boxHistoryReceiver.getBoxSn());
        }
    }
    // 调用接口获取飞行历史数据
    private List<BoxHistoryReceiver> getBoxHistory(String serverId, BoxHistoryDTO boxHistoryDTO) {
        TyHttpCommonReceiver<List<BoxHistoryReceiver>> boxHistory = tyClient.getBoxHistory(serverId, boxHistoryDTO);
        return boxHistory.getContent();
    }
    // 将数据同步到本地数据库
    private void syncToLocalDatabase(String serverId, BoxHistoryReceiver boxHistoryReceiver) {
        // 创建FlightTask实体对象并填充数据
        ArdFlightTask flightTask = new ArdFlightTask();
        flightTask.setTaskId(boxHistoryReceiver.getTaskId());
        flightTask.setBoxSn(boxHistoryReceiver.getBoxSn());
        flightTask.setBoxName(boxHistoryReceiver.getBoxName());
        flightTask.setTaskName(boxHistoryReceiver.getTaskName());
    //调用接口获取架次图片
    private List<BoxPhotosReceiver> getBoxPhotos(String serverId, BoxPhotosDTO boxPhotosDTO) {
        TyHttpCommonReceiver<List<BoxPhotosReceiver>> boxPhotos = tyClient.getBoxPhotos(serverId, boxPhotosDTO);
        return boxPhotos.getContent();
    }
        Integer photoCount = Integer.parseInt(boxHistoryReceiver.getPhotoCount());
        flightTask.setPhotoCount(photoCount);
        Integer videoCount = (boxHistoryReceiver.getVideoPathList() != null) ?
                boxHistoryReceiver.getVideoPathList().size() : 0;
        flightTask.setVideoCount(videoCount);
    // 插入视频记录
    private void insertVideoToDatabase(ArdFlightTask flightTask, List<String> videoPathList) {
        if (videoPathList != null && !videoPathList.isEmpty()) {
            for (String videoPath : videoPathList) {
                ArdMedia ardMedia = ArdMedia.builder()
                        .id(IdUtils.simpleUUID())
                        .taskId(flightTask.getTaskId())
                        .mediaType(1) // 1表示视频
                        .sourceUrl(videoPath)
                        .fileSize(getFileSizeByUrl(videoPath))
                        .build();
                CompletableFuture.supplyAsync(() -> {
                    try {
                        // 上传视频
                        String videoUrl = uploadFileToOss(flightTask.getBoxSn(), videoPath, "record",
                                MimeTypeUtils.VIDEO_MP4);
                        ardMedia.setMediaUrl(videoUrl);
                        // 生成缩略图 InputStream
                        ByteArrayInputStream thumbnailStream = generateThumbnailInputStream(videoPath, 2, 200);
                        if (thumbnailStream != null) {
                            String thumbnailUrl = ossServiceContext.upload("record",
                                    flightTask.getBoxSn() + "/" + IdUtils.fastSimpleUUID() + ".jpg",
                                    thumbnailStream,
                                    MimeTypeUtils.IMAGE_JPEG);
                            ardMedia.setThumbnailUrl(thumbnailUrl);
                        }
        flightTask.setVideoPath(boxHistoryReceiver.getVideoPath());
        flightTask.setServerId(serverId);
                        ardMedia.setCreateTime(new Date());
                        return ardMedia;
        Date startTime = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, boxHistoryReceiver.getStartTime());
        flightTask.setStartTime(startTime);
                    } catch (Exception e) {
                        e.printStackTrace();
                        return null;
                    }
                }, threadPoolTaskExecutor).thenAccept(am -> {
                    if (am != null) {
                        ardMediaMapper.insertArdMedia(am);
                    }
                });
        Date endTime = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, boxHistoryReceiver.getEndTime());
        flightTask.setEndTime(endTime);
        flightTask.setCreateTime(DateUtils.getNowDate());
        // 检查是否已经存在相同任务ID的记录
        ArdFlightTask ardFlightTaskById = ardFlightTaskMapper.getArdFlightTaskById(flightTask.getTaskId());
        if (ardFlightTaskById != null) {
            return;
        }
        System.out.println("Syncing task " + boxHistoryReceiver.getTaskId());
        // 插入新记录
        int rows = ardFlightTaskMapper.insertArdFlightTask(flightTask);
        if (rows > 0) {
            // 删除旧的媒体记录,防止重复插入
            ardMediaMapper.deleteArdMediaByTaskId(flightTask.getTaskId());
            // 插入视频
            syncVideoToDatabase(flightTask, boxHistoryReceiver.getVideoPathList());
            // 插入图片
            syncPhotoToDatabase(flightTask, serverId, boxHistoryReceiver.getBoxSn());
            }
        }
    }
    // 插入视频记录
    private void syncVideoToDatabase(ArdFlightTask flightTask, List<String> videoPathList) {
        if (videoPathList != null && !videoPathList.isEmpty()) {
            for (String videoPath : videoPathList) {
    private void updateVideoToDatabase(ArdFlightTask flightTask, List<String> videoPathList) {
        if (videoPathList == null) {
            return;
        }
        Integer count = flightTask.getVideoCount();//获取本地库视频数量
        int size = videoPathList.size();//获取接口返回的视频数量
        if (count != null && size > count) {
            log.info("录像数量不一致,需要更新数据库");
            // 需要插入新的视频
            List<ArdMedia> existingVideos = ardMediaMapper.selectArdMediaByTaskIdAndType(flightTask.getTaskId(), 1);
            // 提取现有的视频路径
            List<String> existingVideoPaths = existingVideos.stream()
                    .map(ArdMedia::getSourceUrl) // 获取每个视频的 URL
                    .collect(Collectors.toList());
                ArdMedia ardMedia = new ArdMedia();
                ardMedia.setId(IdUtils.simpleUUID());
                ardMedia.setTaskId(flightTask.getTaskId());
                ardMedia.setMediaType(1); // 1表示视频
                ardMedia.setSourceUrl(videoPath);
                // 异步上传文件到OSS,并在上传完成后插入数据库
                CompletableFuture.supplyAsync(() -> uploadFileToOss(flightTask.getBoxSn(), videoPath, "record",
                                MimeTypeUtils.VIDEO_MP4), threadPoolTaskExecutor)
                        .thenAccept(url -> {
                            ardMedia.setMediaUrl(url);  // 获取上传后的文件 URL
            // 从接口返回的视频路径中找出新的视频
            List<String> newVideos = videoPathList.stream()
                    .filter(videoPath -> !existingVideoPaths.contains(videoPath)) // 过滤出新的视频
                    .collect(Collectors.toList());
            if (!newVideos.isEmpty()) {
                // 插入新的视频记录
                for (String videoPath : newVideos) {
                    ArdMedia ardMedia = ArdMedia.builder()
                            .id(IdUtils.simpleUUID())
                            .taskId(flightTask.getTaskId())
                            .mediaType(1) // 1表示视频
                            .fileSize(getFileSizeByUrl(videoPath))
                            .sourceUrl(videoPath)
                            .build();
                    CompletableFuture.supplyAsync(() -> {
                        try {
                            // 上传视频
                            String videoUrl = uploadFileToOss(flightTask.getBoxSn(), videoPath, "record",
                                    MimeTypeUtils.VIDEO_MP4);
                            ardMedia.setMediaUrl(videoUrl);
                            // 生成缩略图 InputStream
                            ByteArrayInputStream thumbnailStream = generateThumbnailInputStream(videoPath, 2, 200);
                            if (thumbnailStream != null) {
                                String thumbnailUrl = ossServiceContext.upload("record",
                                        flightTask.getBoxSn() + "/" + IdUtils.fastSimpleUUID() + ".jpg",
                                        thumbnailStream,
                                        MimeTypeUtils.IMAGE_JPEG);
                                ardMedia.setThumbnailUrl(thumbnailUrl);
                            }
                            ardMedia.setCreateTime(new Date());
                            ardMediaMapper.insertArdMedia(ardMedia);  // 插入数据库
                        });
                            return ardMedia;
                        } catch (Exception e) {
                            e.printStackTrace();
                            return null;
                        }
                    }, threadPoolTaskExecutor).thenAccept(am -> {
                        if (am != null) {
                            ardMediaMapper.insertArdMedia(am);
                        }
                    });
                }
                // 更新任务的视频数量
                flightTask.setVideoCount(flightTask.getVideoCount() + newVideos.size());
                ardFlightTaskMapper.updateArdFlightTask(flightTask);
            }
        }
    }
    // 插入图片记录
    private void syncPhotoToDatabase(ArdFlightTask flightTask, String serverId, String boxSn) {
    private void insertPhotoToDatabase(ArdFlightTask flightTask, String serverId, String boxSn) {
        // 查询图片
        BoxPhotosDTO boxPhotosDTO = new BoxPhotosDTO();
        boxPhotosDTO.setTaskId(flightTask.getTaskId());
        boxPhotosDTO.setBoxSn(boxSn);
        boxPhotosDTO.setPageIndex(1);
        boxPhotosDTO.setPageSize(1000);
        boxPhotosDTO.setPageSize(500);
        List<BoxPhotosReceiver> photoList = getBoxPhotos(serverId, boxPhotosDTO);
        if (photoList != null && !photoList.isEmpty()) {
            addPhotos(flightTask, photoList);
        }
    }
    private void updatePhotoToDatabase(ArdFlightTask flightTask, String serverId, String boxSn) {
        int count = flightTask.getPhotoCount(); //获取本地库图片数量
        // 查询图片
        BoxPhotosDTO boxPhotosDTO = BoxPhotosDTO.builder()
                .taskId(flightTask.getTaskId())
                .boxSn(boxSn)
                .pageIndex(1)
                .pageSize(500)
                .build();
        TyHttpCommonReceiver<List<BoxPhotosReceiver>> boxPhotos = tyClient.getBoxPhotos(serverId, boxPhotosDTO);
        List<BoxPhotosReceiver> photoList = boxPhotos.getContent();
        int size = photoList.size();
        if (photoList != null && !photoList.isEmpty()) {
            for (BoxPhotosReceiver photo : photoList) {
                ArdMedia ardMedia = new ArdMedia();
                ardMedia.setId(IdUtils.simpleUUID());
                ardMedia.setTaskId(flightTask.getTaskId());
                ardMedia.setMediaType(0); // 0表示图片
                ardMedia.setFileSize(photo.getFileSize());
                ardMedia.setFileMd5(photo.getFileMd5());
                ardMedia.setSourceUrl(photo.getImgUrl());
                // 异步上传文件到OSS,并在上传完成后插入数据库
                CompletableFuture.supplyAsync(() -> uploadFileToOss(flightTask.getBoxSn(), photo.getImgUrl(), "pic",
                                MimeTypeUtils.IMAGE_JPG), threadPoolTaskExecutor)
                        .thenAccept(url -> {
                            ardMedia.setMediaUrl(url);  // 获取上传后的文件 URL
                            ardMedia.setCreateTime(new Date());
                            ardMediaMapper.insertArdMedia(ardMedia);  // 插入数据库
                        });
        if (size > count) {
            log.info("图片数量不一致,需要更新数据库");
            // 获取本地数据库中已存在的图片记录(类型为 0 表示图片)
            List<ArdMedia> existingPhotos = ardMediaMapper.selectArdMediaByTaskIdAndType(flightTask.getTaskId(), 0);
            // 需要插入新的视频
            // 提取现有的图片路径(根据 imgUrl 来判断是否重复)
            List<String> existingPhotoUrls = existingPhotos.stream()
                    .map(ArdMedia::getSourceUrl) // 提取 ArdMedia 中的图片 URL
                    .collect(Collectors.toList());
            // 筛选出 photoList 中没有出现在 existingPhotos 中的新图片
            List<BoxPhotosReceiver> newPhotos = photoList.stream()
                    .filter(photo -> !existingPhotoUrls.contains(photo.getImgUrl())) // 过滤出新图片
                    .collect(Collectors.toList());
            if (!newPhotos.isEmpty()) {
                // 插入新的视频记录
                addPhotos(flightTask, newPhotos);
                // 更新任务的视频数量
                flightTask.setPhotoCount(flightTask.getPhotoCount() + newPhotos.size());
                ardFlightTaskMapper.updateArdFlightTask(flightTask);
            }
        }
    }
    private void addPhotos(ArdFlightTask flightTask, List<BoxPhotosReceiver> photoList) {
        for (BoxPhotosReceiver photo : photoList) {
            ArdMedia ardMedia = ArdMedia.builder()
                    .id(IdUtils.simpleUUID())
                    .taskId(flightTask.getTaskId())
                    .mediaType(0) // 0表示图片
                    .fileSize(photo.getFileSize())
                    .fileMd5(photo.getFileMd5())
                    .sourceUrl(photo.getImgUrl())
                    .photoId(photo.getPhotoId())
                    .longitude(photo.getLng())
                    .latitude(photo.getLat())
                    .height(photo.getHeight())
                    .captureTime(DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, photo.getTimeStamp()))
                    .build();
            // 异步上传文件到OSS,并在上传完成后插入数据库
            CompletableFuture.supplyAsync(() -> uploadFileToOss(flightTask.getBoxSn(), photo.getImgUrl(), "pic",
                            MimeTypeUtils.IMAGE_JPG), threadPoolTaskExecutor)
                    .thenAccept(url -> {
                        ardMedia.setMediaUrl(url);  // 获取上传后的文件 URL
                        ardMedia.setCreateTime(new Date());
                        ardMediaMapper.insertArdMedia(ardMedia);  // 插入数据库
                    });
        }
    }
    // 通用的上传方法,支持视频和图片等文件上传
    public String uploadFileToOss(String boxSn, String fileUrl, String bucket, String contentType) {
    private String uploadFileToOss(String boxSn, String fileUrl, String bucket, String contentType) {
        InputStream fileInputStream = null;
        String fileOssUrl = "";
        try {
@@ -233,12 +383,7 @@
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
            // 创建所有主机名都信任的HostnameVerifier
            HostnameVerifier allHostsValid = new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };
            HostnameVerifier allHostsValid = (hostname, session) -> true;
            HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
            // 现在可以正常访问
@@ -270,4 +415,82 @@
        return fileOssUrl; // 返回上传后的文件OSS URL
    }
    // 获取文件大小
    private long getFileSizeByUrl(String fileUrl) {
        try {
            URL url = new URL(fileUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("HEAD");
            conn.connect();
            return conn.getContentLengthLong(); // 返回字节大小
        } catch (Exception e) {
            return -1;
        }
    }
    // 生成视频缩略图
    public ByteArrayInputStream generateThumbnailInputStream(String videoFile,
                                                             int skipFrames,
                                                             int targetWidth) throws Exception {
        long start = System.currentTimeMillis();
        FFmpegFrameGrabber grabber = null;
        try {
            grabber = new FFmpegFrameGrabber(videoFile);
            grabber.start();
            int totalFrames = grabber.getLengthInFrames();
            System.out.println("视频总帧数: " + totalFrames);
            System.out.println("视频时长: " + grabber.getLengthInTime() / 1000000 + "秒");
            Frame frame = null;
            int currentFrame = 0;
            // 读取指定帧数后的第一帧有效图像
            while (currentFrame < totalFrames) {
                frame = grabber.grabImage();
                if (frame == null) {
                    break;
                }
                if (currentFrame > skipFrames && frame.image != null) {
                    break;
                }
                currentFrame++;
            }
            if (frame == null || frame.image == null) {
                throw new Exception("无法获取有效视频帧");
            }
            // 转换 Frame 为 BufferedImage
            Java2DFrameConverter converter = new Java2DFrameConverter();
            BufferedImage image = converter.getBufferedImage(frame);
            // 按目标宽度等比缩放
            int targetHeight = (int) ((double) targetWidth / image.getWidth() * image.getHeight());
            BufferedImage scaledImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_3BYTE_BGR);
            scaledImage.getGraphics().drawImage(image, 0, 0, targetWidth, targetHeight, null);
            // 转成 ByteArrayInputStream
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(scaledImage, "jpg", baos);
            long cost = System.currentTimeMillis() - start;
            System.out.println("处理耗时: " + cost + "ms");
            return new ByteArrayInputStream(baos.toByteArray());
        } finally {
            if (grabber != null) {
                try {
                    grabber.stop();
                    grabber.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
ard-work/src/main/java/com/ard/work/service/impl/ArdMediaServiceImpl.java
File was renamed from ard-work/src/main/java/com/ard/work/service/impl/IArdMediaServiceImpl.java
@@ -14,7 +14,7 @@
 * Date: 2025年11月18日13:17
 **/
@Service
public class IArdMediaServiceImpl implements IArdMediaService {
public class ArdMediaServiceImpl implements IArdMediaService {
    @Resource
    private ArdMediaMapper ardMediaMapper;
ard-work/src/main/resources/mapper/ArdFlightTaskMapper.xml
@@ -93,9 +93,28 @@
        </trim>
    </insert>
    <update id="updateArdFlightTask" parameterType="com.ard.work.domain.entity.ArdFlightTask">
        update ard_flight_task
        <set>
            <if test="taskId != null">task_id = #{taskId},</if>
            <if test="boxSn != null">box_sn = #{boxSn},</if>
            <if test="boxName != null">box_name = #{boxName},</if>
            <if test="taskName != null">task_name = #{taskName},</if>
            <if test="videoCount != null">video_count = #{videoCount},</if>
            <if test="photoCount != null">photo_count = #{photoCount},</if>
            <if test="videoPath != null">video_path = #{videoPath},</if>
            <if test="startTime != null">start_time = #{startTime},</if>
            <if test="endTime != null">end_time = #{endTime},</if>
            <if test="serverId != null">server_id = #{serverId},</if>
            <if test="updateBy != null">update_by = #{updateBy},</if>
            <if test="updateTime != null">update_time = #{updateTime},</if>
            <if test="remark != null">remark = #{remark},</if>
        </set>
        where task_id = #{taskId}
    </update>
    <!-- 根据任务ID获取飞行任务 -->
    <select id="getArdFlightTaskById" resultType="ArdFlightTask">
    <select id="getArdFlightTaskById" resultMap="ArdFlightTaskResult">
        SELECT *
        FROM ard_flight_task
        WHERE task_id = #{taskId}
ard-work/src/main/resources/mapper/ArdMediaMapper.xml
@@ -11,41 +11,80 @@
        <result property="fileMd5" column="file_md5"/>
        <result property="mediaUrl" column="media_url"/>
        <result property="sourceUrl" column="source_url"/>
        <result property="photoId" column="photo_id"/>
        <result property="longitude" column="longitude"/>
        <result property="latitude" column="latitude"/>
        <result property="height" column="height"/>
        <result property="thumbnailUrl" column="thumbnail_url"/>
        <result property="captureTime" column="capture_time"/>
        <result property="createTime" column="create_time"/>
    </resultMap>
    <!-- 查询媒体列表:根据条件动态生成SQL -->
    <select id="selectArdMedia" resultMap="ArdMediaResult">
        SELECT id, task_id, media_type, file_size, file_md5, media_url, source_url,create_time
        SELECT
        id, task_id, media_type, file_size, file_md5, media_url, source_url,thumbnail_url,
        photo_id, longitude, latitude, height, capture_time, create_time
        FROM ard_media
        <where>
            <!-- 动态查询条件:任务ID -->
            <if test="taskId != null">AND task_id = #{taskId}</if>
            <!-- 动态查询条件:媒体类型 -->
            <if test="mediaType != null">AND media_type = #{mediaType}</if>
            <!-- 动态查询条件:文件大小 -->
            <if test="fileSize != null">AND file_size = #{fileSize}</if>
            <!-- 动态查询条件:文件MD5 -->
            <if test="fileMd5 != null">AND file_md5 = #{fileMd5}</if>
            <!-- 动态查询条件:媒体URL -->
            <if test="mediaUrl != null">AND media_url = #{mediaUrl}</if>
            <!-- 动态查询条件:时间戳 -->
            <if test="sourceUrl != null">AND source_url = #{sourceUrl}</if>
            <if test="thumbnailUrl != null">AND thumbnail_url = #{thumbnailUrl}</if>
            <if test="photoId != null">AND photo_id = #{photoId}</if>
            <if test="longitude != null">AND longitude = #{longitude}</if>
            <if test="latitude != null">AND latitude = #{latitude}</if>
            <if test="height != null">AND height = #{height}</if>
            <if test="captureTime != null">AND capture_time = #{captureTime}</if>
            <if test="createTime != null">AND create_time = #{createTime}</if>
        </where>
        ORDER BY create_time DESC
    </select>
    <!-- 根据任务ID查询媒体 -->
    <select id="selectArdMediaByTaskId" resultMap="ArdMediaResult">
        SELECT id, task_id, media_type, file_size, file_md5, media_url, create_time
        SELECT id,
               task_id,
               media_type,
               file_size,
               file_md5,
               media_url,
               source_url,
               thumbnail_url,
               photo_id,
               longitude,
               latitude,
               height,
               capture_time,
               create_time
        FROM ard_media
        WHERE task_id = #{taskId}
    </select>
    <!-- 根据任务ID和媒体类型查询媒体 -->
    <select id="selectArdMediaByTaskIdAndType" resultMap="ArdMediaResult">
        SELECT id,
               task_id,
               media_type,
               file_size,
               file_md5,
               media_url,
               source_url,
               thumbnail_url,
               photo_id,
               longitude,
               latitude,
               height,
               capture_time,
               create_time
        FROM ard_media
        WHERE task_id = #{taskId}
          and media_type = #{mediaType}
    </select>
    <!-- 插入媒体记录 -->
    <insert id="insertArdMedia" parameterType="com.ard.work.domain.entity.ArdMedia">
        INSERT INTO ard_media
@@ -57,8 +96,15 @@
            <if test="fileMd5 != null">file_md5,</if>
            <if test="mediaUrl != null">media_url,</if>
            <if test="sourceUrl != null">source_url,</if>
            <if test="thumbnailUrl != null">thumbnail_url,</if>
            <if test="photoId != null">photo_id,</if>
            <if test="longitude != null">longitude,</if>
            <if test="latitude != null">latitude,</if>
            <if test="height != null">height,</if>
            <if test="captureTime != null">capture_time,</if>
            <if test="createTime != null">create_time,</if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="id != null">#{id},</if>
            <if test="taskId != null">#{taskId},</if>
@@ -67,43 +113,51 @@
            <if test="fileMd5 != null">#{fileMd5},</if>
            <if test="mediaUrl != null">#{mediaUrl},</if>
            <if test="sourceUrl != null">#{sourceUrl},</if>
            <if test="thumbnailUrl != null">#{thumbnailUrl},</if>
            <if test="photoId != null">#{photoId},</if>
            <if test="longitude != null">#{longitude},</if>
            <if test="latitude != null">#{latitude},</if>
            <if test="height != null">#{height},</if>
            <if test="captureTime != null">#{captureTime},</if>
            <if test="createTime != null">#{createTime},</if>
        </trim>
    </insert>
    <!-- 批量插入媒体记录 -->
    <insert id="insertArdMediaList" parameterType="java.util.List">
        INSERT INTO ard_media
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="list != null and !list.isEmpty()">
                <foreach item="item" collection="list" separator=",">
                    <trim prefix="(" suffix=")" suffixOverrides=",">
                        <if test="item.taskId != null">task_id,</if>
                        <if test="item.mediaType != null">media_type,</if>
                        <if test="item.fileSize != null">file_size,</if>
                        <if test="item.fileMd5 != null">file_md5,</if>
                        <if test="item.mediaUrl != null">media_url,</if>
                        <if test="item.sourceUrl != null">source_url,</if>
                        <if test="item.createTime != null">create_time,</if>
                    </trim>
                </foreach>
            </if>
        </trim>
        <trim prefix="values " suffix=")" suffixOverrides=",">
            <foreach item="item" collection="list" separator=",">
                <trim prefix="(" suffix=")" suffixOverrides=",">
                    <if test="item.taskId != null">#{item.taskId},</if>
                    <if test="item.mediaType != null">#{item.mediaType},</if>
                    <if test="item.fileSize != null">#{item.fileSize},</if>
                    <if test="item.fileMd5 != null">#{item.fileMd5},</if>
                    <if test="item.mediaUrl != null">#{item.mediaUrl},</if>
                    <if test="item.sourceUrl != null">#{item.sourceUrl},</if>
                    <if test="item.createTime != null">#{item.createTime},</if>
                </trim>
            </foreach>
        </trim>
        INSERT INTO ard_media(
        task_id,
        media_type,
        file_size,
        file_md5,
        media_url,
        source_url,
        thumbnail_url,
        photo_id,
        longitude,
        latitude,
        height,
        capture_time,
        create_time
        )
        VALUES
        <foreach collection="list" item="item" separator=",">
            (
            #{item.taskId},
            #{item.mediaType},
            #{item.fileSize},
            #{item.fileMd5},
            #{item.mediaUrl},
            #{item.sourceUrl},
            #{item.thumbnailUrl},
            #{item.photoId},
            #{item.longitude},
            #{item.latitude},
            #{item.height},
            #{item.captureTime},
            #{item.createTime}
            )
        </foreach>
    </insert>
@@ -122,7 +176,9 @@
    <!-- 删除媒体记录 -->
    <delete id="deleteArdMediaById" parameterType="Integer">
        DELETE FROM ard_media WHERE id = #{id}
        DELETE
        FROM ard_media
        WHERE id = #{id}
    </delete>
    <!-- 批量删除媒体记录 -->
@@ -134,7 +190,9 @@
    </delete>
    <delete id="deleteArdMediaByTaskId" parameterType="java.lang.Integer">
        DELETE FROM ard_media WHERE task_id = #{taskId}
        DELETE
        FROM ard_media
        WHERE task_id = #{taskId}
    </delete>
</mapper>