From 4e8a1c02b45f72f6377603778e8c8746ed82f374 Mon Sep 17 00:00:00 2001
From: zhaowenyu <35589726@qq.com>
Date: Tue, 06 Jan 2026 10:04:33 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev' into dev
---
ard-admin/src/main/java/com/ard/web/controller/data/ArdNoFlyZoneController.java | 7
ard-system/src/main/resources/mapper/data/ArdModelMapper.xml | 5
ard-system/src/main/resources/mapper/data/ArdMapMapper.xml | 5
ard-admin/src/main/java/com/ard/web/controller/work/UavBaseController.java | 30
ard-system/src/main/java/com/ard/data/model/mapper/ArdModelMapper.java | 10
ard-route/src/main/java/com/ard/route/util/RouteFileUtils.java | 6
ard-work/src/main/java/com/ard/work/mapper/ArdMediaPicMapper.java | 60 +
ard-device/src/main/java/com/ard/device/camera/service/impl/ArdCameraServiceImpl.java | 86 -
ard-work/src/main/java/com/ard/work/service/impl/ArdServerInfoServiceImpl.java | 24
ard-admin/src/main/java/com/ard/web/controller/work/ArdServerInfoController.java | 12
ard-admin/src/main/java/com/ard/web/controller/data/ArdModelController.java | 7
ard-admin/src/main/java/com/ard/web/controller/data/ArdTileController.java | 7
ard-framework/src/main/java/com/ard/framework/config/ThreadPoolConfig.java | 28
ard-system/src/main/java/com/ard/data/map/service/impl/ArdMapServiceImpl.java | 21
ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskPartServiceImpl.java | 14
ard-device/src/main/java/com/ard/device/camera/domain/ArdCamera.java | 2
ard-system/src/main/resources/mapper/data/ArdNoFlyZoneMapper.xml | 5
ard-work/src/main/java/com/ard/work/domain/entity/ArdMediaPic.java | 28
ard-system/src/main/java/com/ard/data/map/mapper/ArdMapMapper.java | 10
ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceImpl.java | 473 --------
ard-work/src/main/java/com/ard/work/mapper/ArdMediaVideoMapper.java | 59 +
ard-sample/src/main/java/com/ard/sample/manage/service/impl/LiveStreamServiceImpl.java | 1
ard-work/src/main/resources/mapper/ArdMediaPicMapper.xml | 115 ++
ard-admin/src/main/java/com/ard/web/controller/data/ArdMapController.java | 7
ard-work/src/main/java/com/ard/work/service/IArdMediaService.java | 20
ard-work/src/main/java/com/ard/work/service/IArdServerInfoService.java | 2
ard-device/src/main/java/com/ard/device/channel/service/impl/ArdChannelServiceImpl.java | 107 --
ard-system/src/main/java/com/ard/data/tile/service/IArdTileService.java | 9
ard-device/src/main/java/com/ard/device/component/sdk/hik/service/impl/HikVisionSDK.java | 40
ard-device/src/main/java/com/ard/device/component/sdk/service/CameraSDK.java | 6
ard-work/src/main/java/com/ard/work/service/impl/TyServiceImpl.java | 5
ard-admin/src/main/java/com/ard/web/controller/work/ArdFlightTaskController.java | 78 +
ard-system/src/main/java/com/ard/data/model/service/impl/ArdModelServiceImpl.java | 21
ard-system/src/main/java/com/ard/data/model/service/IArdModelService.java | 9
ard-work/src/main/java/com/ard/work/domain/entity/ArdMediaVideo.java | 30
ard-system/src/main/java/com/ard/data/map/service/IArdMapService.java | 9
ard-work/src/main/java/com/ard/work/service/IArdDroneInfoService.java | 2
ard-system/src/main/java/com/ard/data/tile/mapper/ArdTileMapper.java | 10
ard-quartz/src/main/java/com/ard/quartz/task/MediaTask.java | 353 +++++++
ard-system/src/main/java/com/ard/data/noflyzone/service/impl/ArdNoFlyZoneServiceImpl.java | 55
ard-quartz/pom.xml | 8
ard-system/src/main/java/com/ard/data/noflyzone/mapper/ArdNoFlyZoneMapper.java | 9
ard-device/src/main/java/com/ard/device/component/sdk/service/CameraSDKService.java | 36
ard-route/src/main/java/com/ard/route/service/impl/ArdRouteInfoServiceImpl.java | 39
ard-system/src/main/java/com/ard/data/noflyzone/service/IArdNoFlyZoneService.java | 8
ard-system/src/main/resources/mapper/data/ArdTileMapper.xml | 5
ard-work/src/main/java/com/ard/work/service/impl/ArdMediaServiceImpl.java | 275 +++++
ard-quartz/src/main/java/com/ard/quartz/task/DeviceTask.java | 258 +++++
/dev/null | 202 ----
ard-work/src/main/resources/mapper/ArdFlightTaskMapper.xml | 2
ard-vtdu/src/main/java/com/ard/vtdu/service/impl/ArdVtduServiceImpl.java | 8
ard-work/src/main/java/com/ard/work/service/impl/ArdDroneInfoServiceImpl.java | 78
ard-work/src/main/resources/mapper/ArdMediaVideoMapper.xml | 108 ++
ard-device/src/main/java/com/ard/device/component/sdk/dh/service/impl/DaHuaSDK.java | 39
ard-system/src/main/java/com/ard/data/tile/service/impl/ArdTileServiceImpl.java | 21
ard-admin/src/main/java/com/ard/web/controller/work/ArdDroneInfoController.java | 8
ard-device/src/main/java/com/ard/device/component/sdk/common/GlobalVariable.java | 3
ard-work/src/main/java/com/ard/work/service/ITyService.java | 2
58 files changed, 1,788 insertions(+), 1,099 deletions(-)
diff --git a/ard-admin/src/main/java/com/ard/web/controller/data/ArdMapController.java b/ard-admin/src/main/java/com/ard/web/controller/data/ArdMapController.java
index 5a97336..537ac14 100644
--- a/ard-admin/src/main/java/com/ard/web/controller/data/ArdMapController.java
+++ b/ard-admin/src/main/java/com/ard/web/controller/data/ArdMapController.java
@@ -3,6 +3,7 @@
import java.util.List;
import javax.servlet.http.HttpServletResponse;
+import com.ard.common.constant.DeviceConstants;
import com.ard.data.map.domain.ArdMap;
import com.ard.data.map.service.IArdMapService;
import io.swagger.annotations.Api;
@@ -81,6 +82,9 @@
@Log(title = "地图管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody ArdMap ardMap) {
+ if (DeviceConstants.NOT_UNIQUE.equals(ardMapService.checkArdMapNameUnique(ardMap))) {
+ return error("新增地图'" + ardMap.getMapName() + "'失败,已存在");
+ }
return toAjax(ardMapService.insertArdMap(ardMap));
}
@@ -92,6 +96,9 @@
@Log(title = "地图管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody ArdMap ardMap) {
+ if (DeviceConstants.NOT_UNIQUE.equals(ardMapService.checkArdMapNameUnique(ardMap))) {
+ return error("修改地图'" + ardMap.getMapName() + "'失败,已存在");
+ }
return toAjax(ardMapService.updateArdMap(ardMap));
}
diff --git a/ard-admin/src/main/java/com/ard/web/controller/data/ArdModelController.java b/ard-admin/src/main/java/com/ard/web/controller/data/ArdModelController.java
index d9e6612..3db3520 100644
--- a/ard-admin/src/main/java/com/ard/web/controller/data/ArdModelController.java
+++ b/ard-admin/src/main/java/com/ard/web/controller/data/ArdModelController.java
@@ -3,6 +3,7 @@
import java.util.List;
import javax.servlet.http.HttpServletResponse;
+import com.ard.common.constant.DeviceConstants;
import com.ard.data.model.domain.ArdModel;
import com.ard.data.model.service.IArdModelService;
import io.swagger.annotations.Api;
@@ -81,6 +82,9 @@
@Log(title = "模型管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody ArdModel ardModel) {
+ if (DeviceConstants.NOT_UNIQUE.equals(ardModelService.checkArdModelNameUnique(ardModel))) {
+ return error("新增模型'" + ardModel.getModelName() + "'失败,已存在");
+ }
return toAjax(ardModelService.insertArdModel(ardModel));
}
@@ -92,6 +96,9 @@
@Log(title = "模型管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody ArdModel ardModel) {
+ if (DeviceConstants.NOT_UNIQUE.equals(ardModelService.checkArdModelNameUnique(ardModel))) {
+ return error("修改模型'" + ardModel.getModelName() + "'失败,已存在");
+ }
return toAjax(ardModelService.updateArdModel(ardModel));
}
diff --git a/ard-admin/src/main/java/com/ard/web/controller/data/ArdNoFlyZoneController.java b/ard-admin/src/main/java/com/ard/web/controller/data/ArdNoFlyZoneController.java
index b1aa9a4..8e8b4ae 100644
--- a/ard-admin/src/main/java/com/ard/web/controller/data/ArdNoFlyZoneController.java
+++ b/ard-admin/src/main/java/com/ard/web/controller/data/ArdNoFlyZoneController.java
@@ -1,6 +1,7 @@
package com.ard.web.controller.data;
import com.alibaba.fastjson2.JSON;
+import com.ard.common.constant.DeviceConstants;
import com.ard.common.utils.uuid.IdUtils;
import com.ard.data.noflyzone.domain.FeatureCollection;
import io.swagger.annotations.Api;
@@ -82,6 +83,9 @@
@PostMapping
public AjaxResult add(@RequestBody ArdNoFlyZone ardNoFlyZone)
{
+ if (DeviceConstants.NOT_UNIQUE.equals(ardNoFlyZoneService.checkArdNoFlyZoneNameUnique(ardNoFlyZone))) {
+ return error("新增禁飞区'" + ardNoFlyZone.getName() + "'失败,已存在");
+ }
return toAjax(ardNoFlyZoneService.insertArdNoFlyZone(ardNoFlyZone));
}
@@ -94,6 +98,9 @@
@PutMapping
public AjaxResult edit(@RequestBody ArdNoFlyZone ardNoFlyZone)
{
+ if (DeviceConstants.NOT_UNIQUE.equals(ardNoFlyZoneService.checkArdNoFlyZoneNameUnique(ardNoFlyZone))) {
+ return error("修改禁飞区'" + ardNoFlyZone.getName() + "'失败,已存在");
+ }
return toAjax(ardNoFlyZoneService.updateArdNoFlyZone(ardNoFlyZone));
}
diff --git a/ard-admin/src/main/java/com/ard/web/controller/data/ArdTileController.java b/ard-admin/src/main/java/com/ard/web/controller/data/ArdTileController.java
index dc69330..4f57755 100644
--- a/ard-admin/src/main/java/com/ard/web/controller/data/ArdTileController.java
+++ b/ard-admin/src/main/java/com/ard/web/controller/data/ArdTileController.java
@@ -3,6 +3,7 @@
import java.util.List;
import javax.servlet.http.HttpServletResponse;
+import com.ard.common.constant.DeviceConstants;
import com.ard.data.tile.domain.ArdTile;
import com.ard.data.tile.service.IArdTileService;
import io.swagger.annotations.Api;
@@ -81,6 +82,9 @@
@Log(title = "tile管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody ArdTile ardTile) {
+ if (DeviceConstants.NOT_UNIQUE.equals(ardTileService.checkArdTileNameUnique(ardTile))) {
+ return error("新增tile'" + ardTile.getTilesName() + "'失败,已存在");
+ }
return toAjax(ardTileService.insertArdTile(ardTile));
}
@@ -92,6 +96,9 @@
@Log(title = "tile管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody ArdTile ardTile) {
+ if (DeviceConstants.NOT_UNIQUE.equals(ardTileService.checkArdTileNameUnique(ardTile))) {
+ return error("修改tile'" + ardTile.getTilesName() + "'失败,已存在");
+ }
return toAjax(ardTileService.updateArdTile(ardTile));
}
diff --git a/ard-admin/src/main/java/com/ard/web/controller/work/ArdDroneInfoController.java b/ard-admin/src/main/java/com/ard/web/controller/work/ArdDroneInfoController.java
index 51e538a..b2bf7a3 100644
--- a/ard-admin/src/main/java/com/ard/web/controller/work/ArdDroneInfoController.java
+++ b/ard-admin/src/main/java/com/ard/web/controller/work/ArdDroneInfoController.java
@@ -112,10 +112,12 @@
@ApiOperation("批量新增无人机盒子")
@PreAuthorize("@ss.hasPermi('work:drone:insertArdDroneLs')")
@Log(title = "无人机管理", businessType = BusinessType.DELETE)
- @PostMapping("insertArdDroneLs/{boxSn}/{deptId}")
- public AjaxResult insertArdDroneLs(@PathVariable String[] boxSn, @PathVariable Long deptId) {
+ @PostMapping("insertArdDroneLs/{boxSn}/{deptId}/{serverId}")
+ public AjaxResult insertArdDroneLs(@PathVariable String[] boxSn,
+ @PathVariable Long deptId,
+ @PathVariable String serverId) {
try {
- int result = ardDroneInfoService.insertArdDroneLs(boxSn, deptId);
+ int result = ardDroneInfoService.insertArdDroneLs(boxSn,deptId,serverId);
if (result > 0) {
return AjaxResult.success("成功新增 " + result + " 个无人机盒子");
} else {
diff --git a/ard-admin/src/main/java/com/ard/web/controller/work/ArdFlightTaskController.java b/ard-admin/src/main/java/com/ard/web/controller/work/ArdFlightTaskController.java
new file mode 100644
index 0000000..008e125
--- /dev/null
+++ b/ard-admin/src/main/java/com/ard/web/controller/work/ArdFlightTaskController.java
@@ -0,0 +1,78 @@
+package com.ard.web.controller.work;
+
+import com.ard.common.core.controller.BaseController;
+import com.ard.common.core.page.TableDataInfo;
+import com.ard.work.domain.dto.*;
+import com.ard.work.domain.entity.ArdFlightTask;
+import com.ard.work.domain.entity.ArdFlightTaskPart;
+import com.ard.work.domain.entity.ArdMediaPic;
+import com.ard.work.domain.entity.ArdMediaVideo;
+import com.ard.work.service.IArdFlightTaskPartService;
+import com.ard.work.service.IArdFlightTaskService;
+import com.ard.work.service.IArdMediaService;
+import com.ard.work.service.ITyService;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import com.github.xiaoymin.knife4j.annotations.ApiSort;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 飞行架次管理接口
+ * ArdFlightController
+ *
+ * @author liusuyi
+ * @date 2024年10月21日13:52
+ **/
+@Api(tags = "飞行架次管理接口")
+@ApiSort(value = 2)
+@RequestMapping("/uav/base")
+@RestController
+public class ArdFlightTaskController extends BaseController {
+
+ @Resource
+ private IArdFlightTaskService ardFlightTaskService;
+ @Resource
+ private IArdFlightTaskPartService ardFlightTaskPartService;
+ @Resource
+ private IArdMediaService ardMediaService;
+
+
+ @ApiOperation("获取飞行架次")
+ @ApiOperationSupport(order = 1)
+ @GetMapping("/getFlightTask")
+ public TableDataInfo getFlightTask(ArdFlightTask ardFlightTask) {
+ startPage();
+ List<ArdFlightTask> list = ardFlightTaskService.selectArdFlightTask(ardFlightTask);
+ return getDataTable(list);
+ }
+
+ @ApiOperation("获取架次飞行轨迹")
+ @ApiOperationSupport(order = 2)
+ @GetMapping("/getCompleteFlightData")
+ public TableDataInfo getCompleteFlightData(ArdFlightTaskPart ardFlightTaskPart) {
+ List<UavFlightStateDTO> completeFlightData = ardFlightTaskPartService.getCompleteFlightData(ardFlightTaskPart);
+ return getDataTable(completeFlightData);
+ }
+
+ @ApiOperation("获取架次图片数据")
+ @ApiOperationSupport(order = 3)
+ @GetMapping("/getMediaPicList")
+ public TableDataInfo getMediaPicList(ArdMediaPic ardMedia) {
+ startPage();
+ List<ArdMediaPic> list = ardMediaService.selectArdMediaPicList(ardMedia);
+ return getDataTable(list);
+ }
+
+ @ApiOperation("获取架次录像数据")
+ @ApiOperationSupport(order = 4)
+ @GetMapping("/getMediaVideoList")
+ public TableDataInfo getMediaVideoList(ArdMediaVideo ardMedia) {
+ startPage();
+ List<ArdMediaVideo> list = ardMediaService.selectArdMediaVideoList(ardMedia);
+ return getDataTable(list);
+ }
+}
\ No newline at end of file
diff --git a/ard-admin/src/main/java/com/ard/web/controller/work/ArdServerInfoController.java b/ard-admin/src/main/java/com/ard/web/controller/work/ArdServerInfoController.java
index 7c14a8d..8a531ba 100644
--- a/ard-admin/src/main/java/com/ard/web/controller/work/ArdServerInfoController.java
+++ b/ard-admin/src/main/java/com/ard/web/controller/work/ArdServerInfoController.java
@@ -51,18 +51,6 @@
}
/**
- * 查询服务器管理列表
- */
- @ApiOperation("查询服务器管理列表")
- @PreAuthorize("@ss.hasPermi('work:server:listNo')")
- @GetMapping("/listNo")
- public TableDataInfo listNo(ArdServerInfo ardServerInfo) {
- startPage();
- List<ArdServerInfo> list = ardServerInfoService.selectArdServerInfoListNo(ardServerInfo);
- return getDataTable(list);
- }
-
- /**
* 导出服务器管理列表
*/
@ApiOperation("导出服务器管理列表")
diff --git a/ard-admin/src/main/java/com/ard/web/controller/work/UavBaseController.java b/ard-admin/src/main/java/com/ard/web/controller/work/UavBaseController.java
index bc41a9c..0904ee9 100644
--- a/ard-admin/src/main/java/com/ard/web/controller/work/UavBaseController.java
+++ b/ard-admin/src/main/java/com/ard/web/controller/work/UavBaseController.java
@@ -5,9 +5,7 @@
import com.ard.common.core.page.TableDataInfo;
import com.ard.work.domain.dto.*;
import com.ard.work.domain.dto.telemetry.TelemetryData;
-import com.ard.work.domain.entity.ArdFlightTask;
-import com.ard.work.domain.entity.ArdFlightTaskPart;
-import com.ard.work.domain.entity.ArdMedia;
+import com.ard.work.domain.entity.*;
import com.ard.work.domain.receiver.*;
import com.ard.work.service.IArdFlightTaskPartService;
import com.ard.work.service.IArdFlightTaskService;
@@ -70,32 +68,6 @@
public AjaxResult getBoxHistory(@RequestBody BoxHistoryDTO boxHistoryDTO) {
List<BoxHistoryReceiver> boxHistory = tyService.getBoxHistory(boxHistoryDTO);
return AjaxResult.success(boxHistory);
- }
-
- @ApiOperation("获取飞行架次")
- @ApiOperationSupport(order = 4)
- @GetMapping("/getFlightTask")
- public TableDataInfo getFlightTask(ArdFlightTask ardFlightTask) {
- startPage();
- List<ArdFlightTask> list = ardFlightTaskService.selectArdFlightTask(ardFlightTask);
- return getDataTable(list);
- }
-
- @ApiOperation("获取架次飞行轨迹")
- @ApiOperationSupport(order = 4)
- @GetMapping("/getCompleteFlightData")
- public TableDataInfo getCompleteFlightData(ArdFlightTaskPart ardFlightTaskPart) {
- List<UavFlightStateDTO> completeFlightData = ardFlightTaskPartService.getCompleteFlightData(ardFlightTaskPart);
- return getDataTable(completeFlightData);
- }
-
- @ApiOperation("获取媒体数据")
- @ApiOperationSupport(order = 4)
- @GetMapping("/getMediaList")
- public TableDataInfo getMediaList(ArdMedia ardMedia) {
- startPage();
- List<ArdMedia> list = ardMediaService.selectArdMediaList(ardMedia);
- return getDataTable(list);
}
@ApiOperation("获取任务照片")
diff --git a/ard-device/src/main/java/com/ard/device/camera/domain/ArdCamera.java b/ard-device/src/main/java/com/ard/device/camera/domain/ArdCamera.java
index 135810d..b7c379c 100644
--- a/ard-device/src/main/java/com/ard/device/camera/domain/ArdCamera.java
+++ b/ard-device/src/main/java/com/ard/device/camera/domain/ArdCamera.java
@@ -4,6 +4,7 @@
import com.ard.common.core.domain.BaseEntity;
import com.ard.device.channel.domain.ArdChannel;
import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@@ -17,6 +18,7 @@
@Data
@AllArgsConstructor
@NoArgsConstructor
+@Builder
public class ArdCamera extends BaseEntity {
private static final long serialVersionUID = 1L;
diff --git a/ard-device/src/main/java/com/ard/device/camera/service/impl/ArdCameraServiceImpl.java b/ard-device/src/main/java/com/ard/device/camera/service/impl/ArdCameraServiceImpl.java
index b8f40d8..e55b8cc 100644
--- a/ard-device/src/main/java/com/ard/device/camera/service/impl/ArdCameraServiceImpl.java
+++ b/ard-device/src/main/java/com/ard/device/camera/service/impl/ArdCameraServiceImpl.java
@@ -163,7 +163,7 @@
ardCamera.setUpdateBy(SecurityUtils.getUsername());
int res = ardCameraMapper.updateArdCamera(ardCamera);
if (res > 0) {
- cameraSDKService.logout(ardCamera.getId());//sdk注销
+ cameraSDKService.logout(ardCamera);//sdk注销
cameraSDKService.login(ardCamera);//sdk登录获取通道信息
}
return res;
@@ -186,7 +186,7 @@
//删除当前相机的所有通道
ardChannelService.deleteArdChannelByDeviceId(id);
//sdk注销
- cameraSDKService.logout(id);
+ cameraSDKService.logout(camera);
}
}
return ardCameraMapper.deleteArdCameraByIds(ids);
@@ -207,7 +207,7 @@
//删除当前相机的所有通道
ardChannelService.deleteArdChannelByDeviceId(id);
//sdk注销
- cameraSDKService.logout(id);
+ cameraSDKService.logout(ArdCamera.builder().id(id).build());
}
return i;
}
@@ -373,84 +373,4 @@
redisService.setCacheObject(getCacheKey(camera.getId()), camera);
}
- /**
- * 同步设备通道与本地通道库信息
- *
- * @author 刘苏义
- * @date 2024/8/22 14:37
- */
- @Scheduled(cron = "0/10 * * * * ?")
- public void syncChannel() {
- try {
- log.debug("定时执行同步通道任务");
- List<ArdCamera> ardCameraList = this.selectArdCameraList(new ArdCamera());
- if (!ardCameraList.isEmpty()) {
- ardCameraList
- .forEach(ardCamera -> {
- //SDK获取实际通道
- List<ArdChannel> ardChannelListSDK = cameraSDKService.getChannels(ardCamera);
- //数据库获取通道
- ArdChannel ardChannel = new ArdChannel();
- ardChannel.setDeviceId(ardCamera.getId());
- List<ArdChannel> ardChannelListDb = ardChannelService.selectArdChannelList(ardChannel);
- //同步通道
- asyncChannel(ardChannelListDb, ardChannelListSDK);
- });
- }
- } catch (Exception ex) {
- log.error("定时执行同步通道任务异常:{}", ex.getMessage());
- }
- }
-
- /**
- * 定时执行登录失败相机重新登录
- *
- * @author 刘苏义
- * @date 2024/8/22 14:37
- */
- @Scheduled(cron = "0/30 * * * * ?")
- public void failedReconnect() {
- try {
- log.debug("定时执行失败相机重连任务");
- List<Object> ardCameras = redisService.getListKey(CacheConstants.CAMERA_LIST_KEY);
- ardCameras.stream()
- .map(object -> (ArdCamera) object) // 将Object转换为ArdCameras
- .filter(camera -> !GlobalVariable.loginMap.containsKey(camera.getId()))
- .forEach(camera -> cameraSDKService.login(camera));
- } catch (Exception ex) {
- log.error("定时执行失败相机重连任务异常:{}", ex.getMessage());
- }
- }
-
- /**
- * 同步相机在线状态
- * 刘苏义
- * 2023/10/8 14:54:41
- */
- @Scheduled(cron = "0/10 * * * * ?")
- public void cameraState() {
- try {
- log.debug("定时执行同步相机在线状态任务");
- //调用查询方法
- List<ArdCamera> ardCameraList = selectArdCameraList(new ArdCamera());
- ardCameraList
- .forEach(camera -> {
- CameraCmd cmd = new CameraCmd();
- cmd.setCameraId(camera.getId());
- boolean onLineNew = cameraSDKService.isOnLine(cmd);
- boolean onLineOld = "1".equals(camera.getState());
- if (onLineNew != onLineOld) {
- if (onLineNew) {
- camera.setState("1");
- } else {
- camera.setState("0");
- }
- camera.setUpdateTime(DateUtils.getNowDate());
- ardCameraMapper.updateArdCamera(camera);
- }
- });
- } catch (Exception ex) {
- log.error("同步相机在线状态异常:{}", ex.getMessage());
- }
- }
}
\ No newline at end of file
diff --git a/ard-device/src/main/java/com/ard/device/channel/service/impl/ArdChannelServiceImpl.java b/ard-device/src/main/java/com/ard/device/channel/service/impl/ArdChannelServiceImpl.java
index 2c9f997..6c00d76 100644
--- a/ard-device/src/main/java/com/ard/device/channel/service/impl/ArdChannelServiceImpl.java
+++ b/ard-device/src/main/java/com/ard/device/channel/service/impl/ArdChannelServiceImpl.java
@@ -1,6 +1,8 @@
package com.ard.device.channel.service.impl;
+import com.ard.common.constant.CacheConstants;
import com.ard.common.constant.UserConstants;
+import com.ard.common.core.redis.RedisCache;
import com.ard.common.utils.uuid.IdUtils;
import com.ard.device.camera.domain.ArdCamera;
import com.ard.device.camera.service.IArdCameraService;
@@ -11,6 +13,7 @@
import com.ard.vtdu.domain.ArdVtdu;
import com.ard.vtdu.service.IArdVtduService;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@@ -27,14 +30,9 @@
@Slf4j
@Service
public class ArdChannelServiceImpl implements IArdChannelService {
- @Resource
- private IArdCameraService ardCameraService;
+
@Resource
private ArdChannelMapper ardChannelMapper;
- @Resource
- private IArdVtduService ardVtduService;
- @Resource
- private MediamtxConfig mediamtxConfig;
/**
* 查询通道管理
@@ -138,102 +136,5 @@
return UserConstants.NOT_UNIQUE;
}
return UserConstants.UNIQUE;
- }
-
-
- @Scheduled(cron = "0/5 * * * * ?")
- public void syncVtdu() {
- log.debug("定时同步Vtdu任务");
- List<ArdChannel> channels = this.selectArdChannelList(new ArdChannel());
- if (channels == null || channels.isEmpty()) {
- // log.warn("没有获取到通道数据,退出同步");
- return;
- }
- List<ArdVtdu> ardVtduList = ardVtduService.selectArdVtduList(new ArdVtdu());
-
- Set<String> validNames = channels.stream()
- .map(channel -> channel.getDeviceId() + "_" + channel.getChanNo())
- .collect(Collectors.toSet());
- // 2. 合并操作:增、删、改
- channels.forEach(channel -> {
- String name = channel.getDeviceId() + "_" + channel.getChanNo(); // 生成媒体表的 name
- String cameraId = channel.getDeviceId(); // cameraId 就是通道的 deviceId
- String rtspSourceUrl = getRtspSource(channel);
- String rtspUrl =
- "rtsp://" + mediamtxConfig.getPlayHost() + ":" + mediamtxConfig.getRtspPort() + "/" + name; //
- // 拼接 webrtcUrl
- String rtmpUrl =
- "rtmp://" + mediamtxConfig.getPlayHost() + ":" + mediamtxConfig.getRtmpPort() + "/" + name; // 拼接
- // webrtcUrl
- String protocol = mediamtxConfig.isHttps() ? "https://" : "http://";
- String webrtcUrl =
- protocol + mediamtxConfig.getPlayHost() + ":" + mediamtxConfig.getWebrtcPort() + "/" + name;
- // 拼接 webrtcUrl
-
- // 先检查媒体表是否已有此记录
- Optional<ArdVtdu> existingMedia = ardVtduList.stream()
- .filter(media -> media.getName().equals(name)) // 查找是否已有对应的媒体记录
- .findFirst();
-
- if (existingMedia.isPresent()) {
- // 如果已有,更新现有记录
- ArdVtdu vtdu = existingMedia.get();
- // 更新前后内容相同则不进行更新
- if (!vtdu.getRtspSource().equals(rtspSourceUrl) ||
- !vtdu.getWebrtcUrl().equals(webrtcUrl) ||
- !vtdu.getRtspUrl().equals(rtspUrl) ||
- !vtdu.getRtmpUrl().equals(rtmpUrl)) {
- vtdu.setRtspUrl(rtspUrl);
- vtdu.setRtmpUrl(rtmpUrl);
- vtdu.setWebrtcUrl(webrtcUrl);
- ardVtduService.updateArdVtdu(vtdu);
- log.info("更新媒体记录:{}", vtdu.getName());
- }
- } else {
- // 如果没有,插入新的记录
- ArdVtdu vtdu = new ArdVtdu();
- vtdu.setName(name);
- vtdu.setRtspSource(rtspSourceUrl);
- vtdu.setCameraId(cameraId);
- vtdu.setRtspUrl(rtspUrl);
- vtdu.setRtmpUrl(rtmpUrl);
- vtdu.setWebrtcUrl(webrtcUrl);
- ardVtduService.insertArdVtdu(vtdu); // 保存到媒体表
- log.info("插入新媒体记录:{}", vtdu.getName());
- }
- });
- // 3. 删除操作:删除媒体表中多余的记录
- List<String> invalidNames = ardVtduList.stream()
- .filter(vtdu -> !validNames.contains(vtdu.getName()))
- .filter(vtdu -> !"publisher".equalsIgnoreCase(vtdu.getRtspSource())) // 不是机场流
- .map(ArdVtdu::getName)
- .collect(Collectors.toList());
-
- if (!invalidNames.isEmpty()) {
- // 将 List<String> 转换为 String[]
- String[] namesArray = invalidNames.toArray(new String[0]);
- ardVtduService.deleteArdVtduByNames(namesArray); // 传递数组
- log.info("删除不再存在的媒体记录:{}", Arrays.toString(namesArray));
- }
-
- }
-
- // 根据通道信息获取rtsp源地址
- private String getRtspSource(ArdChannel channel) {
- String rtspSource = "";
- ArdCamera ardCamera = ardCameraService.selectArdCameraById(channel.getDeviceId());
- if (ardCamera != null) {
- switch (ardCamera.getFactory()) {
- case "1":
- rtspSource =
- "rtsp://" + ardCamera.getUsername() + ":" + ardCamera.getPassword() + "@" + ardCamera.getIp() + ":" + ardCamera.getRtspPort() + "/h264/ch" + channel.getChanNo() + "/main/av_stream";
- break;
- case "2":
- rtspSource =
- "rtsp://" + ardCamera.getUsername() + ":" + ardCamera.getPassword() + "@" + ardCamera.getIp() + ":" + ardCamera.getRtspPort() + "/cam/realmonitor?channel=" + channel.getChanNo() + "&subtype=0";
- break;
- }
- }
- return rtspSource;
}
}
\ No newline at end of file
diff --git a/ard-device/src/main/java/com/ard/device/component/sdk/common/GlobalVariable.java b/ard-device/src/main/java/com/ard/device/component/sdk/common/GlobalVariable.java
index f76ae07..ec95a86 100644
--- a/ard-device/src/main/java/com/ard/device/component/sdk/common/GlobalVariable.java
+++ b/ard-device/src/main/java/com/ard/device/component/sdk/common/GlobalVariable.java
@@ -16,8 +16,7 @@
**/
@Data
public class GlobalVariable {
- //保存相机登录信息(cameraId:loginId)
- public static Map<String, Object> loginMap = new ConcurrentHashMap<>();
+
//保存相机登录信息(loginId:Camera)
public static Map<Integer, ArdCamera> hikLoginMap = new ConcurrentHashMap<>();
}
diff --git a/ard-device/src/main/java/com/ard/device/component/sdk/dh/service/impl/DaHuaSDK.java b/ard-device/src/main/java/com/ard/device/component/sdk/dh/service/impl/DaHuaSDK.java
index 54fa4d5..84468ce 100644
--- a/ard-device/src/main/java/com/ard/device/component/sdk/dh/service/impl/DaHuaSDK.java
+++ b/ard-device/src/main/java/com/ard/device/component/sdk/dh/service/impl/DaHuaSDK.java
@@ -17,6 +17,7 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
+
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.*;
@@ -102,7 +103,8 @@
public void login(ArdCamera camera) {
try {
NetSDKLib.NET_DEVICEINFO_Ex m_stDeviceInfo = new NetSDKLib.NET_DEVICEINFO_Ex();
- NetSDKLib.LLong loginId = LoginModule.login(camera.getIp(), camera.getPort(), camera.getUsername(), camera.getPassword(), m_stDeviceInfo);
+ NetSDKLib.LLong loginId = LoginModule.login(camera.getIp(), camera.getPort(), camera.getUsername(),
+ camera.getPassword(), m_stDeviceInfo);
if (loginId.longValue() <= 0) {
camera.setChanNum(0);
camera.setLoginId(-1L);
@@ -116,7 +118,7 @@
camera.setChanNum(m_stDeviceInfo.byChanNum);
camera.setStartChan(1);
camera.setLoginId(loginId.longValue());
- GlobalVariable.loginMap.put(camera.getId(), loginId);
+
//获取最新通道
List<ArdChannel> ardChannelList = getChannels(camera);
if (!ardChannelList.isEmpty()) {
@@ -135,11 +137,8 @@
* 2023/10/17 8:28:13
*/
@Override
- public void logout(String cameraId) {
- if (!GlobalVariable.loginMap.containsKey(cameraId)) {
- return;
- }
- NetSDKLib.LLong loginId = (NetSDKLib.LLong) GlobalVariable.loginMap.get(cameraId);
+ public void logout(ArdCamera ardCamera) {
+ NetSDKLib.LLong loginId = new NetSDKLib.LLong(ardCamera.getLoginId());
LoginModule.logout(loginId);
}
@@ -149,13 +148,9 @@
* 2023/10/17 8:28:13
*/
@Override
- public boolean isOnLine(CameraCmd cmd) {
+ public boolean isOnLine(ArdCamera ardCamera) {
try {
- String cameraId = cmd.getCameraId();
- if (!GlobalVariable.loginMap.containsKey(cameraId)) {
- return false;
- }
- NetSDKLib.LLong loginId = (NetSDKLib.LLong) GlobalVariable.loginMap.get(cameraId);
+ NetSDKLib.LLong loginId = new NetSDKLib.LLong(ardCamera.getLoginId());
NetSDKLib.NET_WORKSTATE dh_ptz_location_info = new NetSDKLib.NET_WORKSTATE();
boolean b = ConfigModule.queryDevState(loginId, NET_DEVSTATE_ONLINE, dh_ptz_location_info);
if (!b) {
@@ -185,8 +180,8 @@
channel.setDeviceId(camera.getId());
channel.setChanNo(i);
//获取视频编码
- CameraCmd cameraCmd = new CameraCmd(camera.getId(), channel.getChanNo());
- VideoCompressionCfg videoCompressionCfg = getVideoCompressionCfg(cameraCmd);
+ camera.setChanNo(i);
+ VideoCompressionCfg videoCompressionCfg = getVideoCompressionCfg(camera);
if (StringUtils.isNotNull(videoCompressionCfg)) {
channel.setVideoCode(videoCompressionCfg.getVideoEncType());
}
@@ -202,16 +197,12 @@
}
@Override
- public VideoCompressionCfg getVideoCompressionCfg(CameraCmd cmd) {
- String cameraId = cmd.getCameraId();
- Integer chanNo = cmd.getChanNo();
- if (!GlobalVariable.loginMap.containsKey(cameraId)) {
- return null;
- }
- NetSDKLib.LLong loginId = (NetSDKLib.LLong) GlobalVariable.loginMap.get(cameraId);
+ public VideoCompressionCfg getVideoCompressionCfg(ArdCamera ardCamera) {
+
+ NetSDKLib.LLong loginId = new NetSDKLib.LLong(ardCamera.getLoginId());
NetSDKLib.CFG_ENCODE_INFO cfg_encode_info = new NetSDKLib.CFG_ENCODE_INFO();
- cfg_encode_info.nChannelID = chanNo - 1;
- boolean b = ConfigModule.GetNewDevConfig(loginId, chanNo - 1, CFG_CMD_ENCODE, cfg_encode_info);
+ cfg_encode_info.nChannelID = ardCamera.getChanNo() - 1;
+ boolean b = ConfigModule.GetNewDevConfig(loginId, ardCamera.getChanNo() - 1, CFG_CMD_ENCODE, cfg_encode_info);
if (b) {
int emCompression = cfg_encode_info.stuMainStream[0].stuVideoFormat.emCompression;//视频格式
String videoEncType;
diff --git a/ard-device/src/main/java/com/ard/device/component/sdk/hik/service/impl/HikVisionSDK.java b/ard-device/src/main/java/com/ard/device/component/sdk/hik/service/impl/HikVisionSDK.java
index c146539..728245a 100644
--- a/ard-device/src/main/java/com/ard/device/component/sdk/hik/service/impl/HikVisionSDK.java
+++ b/ard-device/src/main/java/com/ard/device/component/sdk/hik/service/impl/HikVisionSDK.java
@@ -9,6 +9,7 @@
import com.ard.device.component.sdk.common.ResolutionEnum;
import com.ard.device.component.sdk.common.SdkErrorCodeEnum;
import com.ard.device.component.sdk.common.osSelect;
+import com.ard.device.component.sdk.dh.lib.NetSDKLib;
import com.ard.device.component.sdk.event.LoginEvent;
import com.ard.device.component.sdk.hik.lib.ExceptionCallBack;
import com.ard.device.component.sdk.hik.lib.HCNetSDK;
@@ -109,8 +110,6 @@
return;
}
log.info("Login Success 【 {}:{} 】", camera.getIp(), camera.getPort());
-
- GlobalVariable.loginMap.put(camera.getId(), loginId);
GlobalVariable.hikLoginMap.put(loginId, camera);
camera.setLoginId((long) loginId);
camera.setState("1");
@@ -138,26 +137,15 @@
* 注销
*/
@Override
- public void logout(String cameraId) {
- if (!GlobalVariable.loginMap.containsKey(cameraId)) {
- return;
- }
- Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
- boolean b = hCNetSDK.NET_DVR_Logout(userId);
- if (b) {
- GlobalVariable.loginMap.remove(cameraId);
- }
+ public void logout(ArdCamera ardCamera) {
+
+ hCNetSDK.NET_DVR_Logout(ardCamera.getLoginId().intValue());
}
@Override
- public boolean isOnLine(CameraCmd cmd) {
+ public boolean isOnLine(ArdCamera ardCamera) {
try {
- String cameraId = cmd.getCameraId();
- if (!GlobalVariable.loginMap.containsKey(cameraId)) {
- return false;
- }
- Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
- return hCNetSDK.NET_DVR_RemoteControl(userId, NET_DVR_CHECK_USER_STATUS, null, 0);
+ return hCNetSDK.NET_DVR_RemoteControl(ardCamera.getLoginId().intValue(), NET_DVR_CHECK_USER_STATUS, null, 0);
} catch (Exception ex) {
log.error("检测在线异常:{}", ex.getMessage());
return false;
@@ -169,19 +157,13 @@
*
*/
@Override
- public VideoCompressionCfg getVideoCompressionCfg(CameraCmd cmd) {
- String cameraId = cmd.getCameraId();
- Integer chanNo = cmd.getChanNo();
- if (!GlobalVariable.loginMap.containsKey(cameraId)) {
- return null;
- }
- Integer userId = (Integer) GlobalVariable.loginMap.get(cameraId);
-
+ public VideoCompressionCfg getVideoCompressionCfg(ArdCamera ardCamera) {
+ Integer chanNo = ardCamera.getChanNo();
+ int userId = ardCamera.getLoginId().intValue();
HCNetSDK.NET_DVR_COMPRESSIONCFG_V30 compressionCfg = new HCNetSDK.NET_DVR_COMPRESSIONCFG_V30();
compressionCfg.write();
Pointer point = compressionCfg.getPointer();
IntByReference ibrBytesReturned = new IntByReference(0);
-
boolean bool = hCNetSDK.NET_DVR_GetDVRConfig(userId, HCNetSDK.NET_DVR_GET_COMPRESSCFG_V30, chanNo, point,
compressionCfg.size(), ibrBytesReturned);
if (bool) {
@@ -432,8 +414,8 @@
channel.setName(channelName);
channel.setChanNo(chanNo);
//获取视频编码
- CameraCmd cameraCmd = new CameraCmd(camera.getId(), chanNo);
- VideoCompressionCfg videoCompressionCfg = getVideoCompressionCfg(cameraCmd);
+ camera.setChanNo(chanNo);
+ VideoCompressionCfg videoCompressionCfg = getVideoCompressionCfg(camera);
if (StringUtils.isNotNull(videoCompressionCfg)) {
channel.setVideoCode(videoCompressionCfg.getVideoEncType());
}
diff --git a/ard-device/src/main/java/com/ard/device/component/sdk/service/CameraSDK.java b/ard-device/src/main/java/com/ard/device/component/sdk/service/CameraSDK.java
index 5195736..91b2e37 100644
--- a/ard-device/src/main/java/com/ard/device/component/sdk/service/CameraSDK.java
+++ b/ard-device/src/main/java/com/ard/device/component/sdk/service/CameraSDK.java
@@ -20,13 +20,13 @@
void login(ArdCamera cameras);
//注销
- void logout(String cameraId);
+ void logout(ArdCamera ardCamera);
//在线状态
- boolean isOnLine(CameraCmd cmd);
+ boolean isOnLine(ArdCamera ardCamera);
//获取码流压缩参数
- VideoCompressionCfg getVideoCompressionCfg(CameraCmd cmd);
+ VideoCompressionCfg getVideoCompressionCfg(ArdCamera ardCamera);
//获取相机通道信息
List<ArdChannel> getChannels(ArdCamera camera);
diff --git a/ard-device/src/main/java/com/ard/device/component/sdk/service/CameraSDKService.java b/ard-device/src/main/java/com/ard/device/component/sdk/service/CameraSDKService.java
index 4ca608e..5de1b57 100644
--- a/ard-device/src/main/java/com/ard/device/component/sdk/service/CameraSDKService.java
+++ b/ard-device/src/main/java/com/ard/device/component/sdk/service/CameraSDKService.java
@@ -55,15 +55,12 @@
//注销
@Override
- public void logout(String cameraId) {
+ public void logout(ArdCamera ardCamera) {
try {
- ArdCamera ardCamera = redisService.getCacheObject(CacheConstants.CAMERA_LIST_KEY + cameraId);
- if (ardCamera != null) {
- String factory = ardCamera.getFactory();
- CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
- cameraSDK.logout(cameraId);
- GlobalVariable.loginMap.remove(cameraId);//移除相机登录id缓存
- }
+
+ String factory = ardCamera.getFactory();
+ CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
+ cameraSDK.logout(ardCamera);
} catch (Exception ex) {
log.error("注销异常:{}", ex.getMessage());
}
@@ -71,17 +68,11 @@
//在线检测
@Override
- public boolean isOnLine(CameraCmd cmd) {
+ public boolean isOnLine(ArdCamera ardCamera) {
try {
- boolean onLine = false;
- String cameraId = cmd.getCameraId();
- ArdCamera ardCamera = redisService.getCacheObject(CacheConstants.CAMERA_LIST_KEY + cameraId);
- if (ardCamera != null) {
- String factory = ardCamera.getFactory();
- CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
- onLine = cameraSDK.isOnLine(cmd);
- }
- return onLine;
+ String factory = ardCamera.getFactory();
+ CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
+ return cameraSDK.isOnLine(ardCamera);
} catch (Exception ex) {
log.error("检测在线异常:{}", ex.getMessage());
return false;
@@ -90,16 +81,11 @@
@Override
//获取码流压缩参数
- public VideoCompressionCfg getVideoCompressionCfg(CameraCmd cmd) {
+ public VideoCompressionCfg getVideoCompressionCfg(ArdCamera ardCamera) {
try {
- String cameraId = cmd.getCameraId();
- ArdCamera ardCamera = redisService.getCacheObject(CacheConstants.CAMERA_LIST_KEY + cameraId);
- if (ardCamera == null) {
- return null;
- }
String factory = ardCamera.getFactory();
CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
- return cameraSDK.getVideoCompressionCfg(cmd);
+ return cameraSDK.getVideoCompressionCfg(ardCamera);
} catch (Exception ex) {
log.error("获取码流压缩参数异常:{}", ex.getMessage());
return null;
diff --git a/ard-framework/src/main/java/com/ard/framework/config/ThreadPoolConfig.java b/ard-framework/src/main/java/com/ard/framework/config/ThreadPoolConfig.java
index 44329d0..76c3a93 100644
--- a/ard-framework/src/main/java/com/ard/framework/config/ThreadPoolConfig.java
+++ b/ard-framework/src/main/java/com/ard/framework/config/ThreadPoolConfig.java
@@ -62,4 +62,32 @@
}
};
}
+ @Bean("mediaVideoExecutor")
+ public ThreadPoolTaskExecutor mediaVideoExecutor() {
+ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+ executor.setCorePoolSize(10); // 核心线程数:同时处理视频的核心线程数
+ executor.setMaxPoolSize(10); // 最大线程数:线程池不会扩展超过这个数量
+ executor.setQueueCapacity(50); // 队列容量:等待执行的任务数量,之前20太小可能会拒绝任务
+ executor.setThreadNamePrefix("media-video-");
+
+ // 当线程池和队列都满时的拒绝策略
+ executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+
+ executor.initialize();
+ return executor;
+ }
+ @Bean("mediaPicExecutor")
+ public ThreadPoolTaskExecutor mediaPicExecutor() {
+ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+ executor.setCorePoolSize(10); // 核心线程数:同时处理视频的核心线程数
+ executor.setMaxPoolSize(10); // 最大线程数:线程池不会扩展超过这个数量
+ executor.setQueueCapacity(50); // 队列容量:等待执行的任务数量,之前20太小可能会拒绝任务
+ executor.setThreadNamePrefix("media-pic-");
+
+ // 当线程池和队列都满时的拒绝策略
+ executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+
+ executor.initialize();
+ return executor;
+ }
}
diff --git a/ard-quartz/pom.xml b/ard-quartz/pom.xml
index cb73cbd..fbff55e 100644
--- a/ard-quartz/pom.xml
+++ b/ard-quartz/pom.xml
@@ -34,6 +34,14 @@
<groupId>com.ard</groupId>
<artifactId>ard-common</artifactId>
</dependency>
+ <dependency>
+ <groupId>com.ard</groupId>
+ <artifactId>ard-work</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.ard</groupId>
+ <artifactId>ard-device</artifactId>
+ </dependency>
</dependencies>
diff --git a/ard-quartz/src/main/java/com/ard/quartz/task/DeviceTask.java b/ard-quartz/src/main/java/com/ard/quartz/task/DeviceTask.java
new file mode 100644
index 0000000..b51d24a
--- /dev/null
+++ b/ard-quartz/src/main/java/com/ard/quartz/task/DeviceTask.java
@@ -0,0 +1,258 @@
+package com.ard.quartz.task;
+
+import com.ard.common.constant.CacheConstants;
+import com.ard.common.core.redis.RedisCache;
+import com.ard.common.utils.DateUtils;
+import com.ard.common.utils.file.MimeTypeUtils;
+import com.ard.device.camera.domain.ArdCamera;
+import com.ard.device.camera.service.IArdCameraService;
+import com.ard.device.channel.domain.ArdChannel;
+import com.ard.device.channel.service.IArdChannelService;
+import com.ard.device.component.sdk.service.CameraSDKService;
+import com.ard.oss.service.impl.OssServiceContext;
+import com.ard.vtdu.config.MediamtxConfig;
+import com.ard.vtdu.domain.ArdVtdu;
+import com.ard.vtdu.service.IArdMediaService;
+import com.ard.vtdu.service.IArdVtduService;
+import com.ard.work.domain.entity.ArdMediaPic;
+import com.ard.work.domain.entity.ArdMediaVideo;
+import com.ard.work.mapper.ArdMediaPicMapper;
+import com.ard.work.mapper.ArdMediaVideoMapper;
+import com.ard.work.util.osSelect;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.cert.X509Certificate;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+
+/**
+ * 定时同步设备任务
+ *
+ * @author ard
+ */
+@Component("DeviceTask")
+@Slf4j
+public class DeviceTask {
+ @Resource
+ private RedisCache redisCache;
+ @Resource
+ private IArdChannelService ardChannelService;
+ @Resource
+ private IArdVtduService ardVtduService;
+ @Resource
+ private MediamtxConfig mediamtxConfig;
+ @Resource
+ private CameraSDKService cameraSDKService;
+ @Resource
+ private IArdCameraService ardCameraService;
+ @Resource
+ private IArdMediaService ardMediaService;
+
+
+
+ /**
+ * 定时执行登录失败相机重新登录
+ */
+ public void failedReconnect() {
+ try {
+ log.debug("定时执行失败相机重连任务");
+ // 从数据库取全部设备
+ ArdCamera ardCamera = new ArdCamera();
+ ardCamera.setUseDataScope(false);
+ List<ArdCamera> cameraList = ardCameraService.selectArdCameraList(ardCamera);
+ cameraList.stream()
+ // 只处理登录失败或离线的设备
+ .filter(camera -> camera.getLoginId() == null || camera.getLoginId() < 0 || "0".equals(camera.getState()))
+ .forEach(camera -> {
+ log.info("尝试重新登录设备 {}:{}", camera.getIp(), camera.getPort());
+ cameraSDKService.login(camera);
+ });
+
+ } catch (Exception ex) {
+ log.error("定时执行失败相机重连任务异常:{}", ex.getMessage());
+ }
+ }
+
+ /**
+ * 同步相机在线状态
+ */
+ public void syncCameraState() {
+ try {
+ log.debug("定时执行同步相机在线状态任务");
+ //调用查询方法
+ ArdCamera ardCamera = new ArdCamera();
+ ardCamera.setUseDataScope(false);
+ List<ArdCamera> ardCameraList = ardCameraService.selectArdCameraList(ardCamera);
+ ardCameraList
+ .forEach(camera -> {
+ boolean onLineNew = cameraSDKService.isOnLine(camera);
+ boolean onLineOld = "1".equals(camera.getState());
+ if (onLineNew != onLineOld) {
+ if (onLineNew) {
+ camera.setState("1");
+ } else {
+ camera.setState("0");
+ }
+ camera.setUpdateTime(DateUtils.getNowDate());
+ ardCameraService.updateArdCamera(camera);
+ }
+ });
+ } catch (Exception ex) {
+ log.error("同步相机在线状态异常:{}", ex.getMessage());
+ }
+ }
+
+ /**
+ * 同步相机通道
+ */
+ public void syncChannel() {
+ try {
+ log.debug("定时执行同步通道任务");
+ ArdCamera camera = new ArdCamera();
+ camera.setUseDataScope(false);
+ List<ArdCamera> ardCameraList = ardCameraService.selectArdCameraList(camera);
+ if (!ardCameraList.isEmpty()) {
+ ardCameraList
+ .forEach(ardCamera -> {
+ //SDK获取实际通道
+ List<ArdChannel> ardChannelListSDK = cameraSDKService.getChannels(ardCamera);
+ //数据库获取通道
+ ArdChannel ardChannel = new ArdChannel();
+ ardChannel.setUseDataScope(false);
+ ardChannel.setDeviceId(ardCamera.getId());
+ List<ArdChannel> ardChannelListDb = ardChannelService.selectArdChannelList(ardChannel);
+ //同步通道
+ ardCameraService.asyncChannel(ardChannelListDb, ardChannelListSDK);
+ });
+ }
+ } catch (Exception ex) {
+ log.error("定时执行同步通道任务异常:{}", ex.getMessage());
+ }
+ }
+
+ /**
+ * 同步通道流媒体
+ */
+ public void syncVtdu() {
+ log.debug("定时同步Vtdu任务");
+ ArdChannel ardChannel = new ArdChannel();
+ ardChannel.setUseDataScope(false);
+ List<ArdChannel> channels = ardChannelService.selectArdChannelList(ardChannel);
+ if (channels == null || channels.isEmpty()) {
+ // log.warn("没有获取到通道数据,退出同步");
+ return;
+ }
+ List<ArdVtdu> ardVtduList = ardVtduService.selectArdVtduList(new ArdVtdu());
+
+ Set<String> validNames = channels.stream()
+ .map(channel -> channel.getDeviceId() + "_" + channel.getChanNo())
+ .collect(Collectors.toSet());
+ // 2. 合并操作:增、删、改
+ channels.forEach(channel -> {
+ String name = channel.getDeviceId() + "_" + channel.getChanNo(); // 生成媒体表的 name
+ String cameraId = channel.getDeviceId(); // cameraId 就是通道的 deviceId
+ String rtspSourceUrl = getRtspSource(channel);
+ String rtspUrl =
+ "rtsp://" + mediamtxConfig.getPlayHost() + ":" + mediamtxConfig.getRtspPort() + "/" + name; //
+ // 拼接 webrtcUrl
+ String rtmpUrl =
+ "rtmp://" + mediamtxConfig.getPlayHost() + ":" + mediamtxConfig.getRtmpPort() + "/" + name; // 拼接
+ // webrtcUrl
+ String protocol = mediamtxConfig.isHttps() ? "https://" : "http://";
+ String webrtcUrl =
+ protocol + mediamtxConfig.getPlayHost() + ":" + mediamtxConfig.getWebrtcPort() + "/" + name;
+ // 拼接 webrtcUrl
+
+ // 先检查媒体表是否已有此记录
+ Optional<ArdVtdu> existingMedia = ardVtduList.stream()
+ .filter(media -> media.getName().equals(name)) // 查找是否已有对应的媒体记录
+ .findFirst();
+
+ if (existingMedia.isPresent()) {
+ // 如果已有,更新现有记录
+ ArdVtdu vtdu = existingMedia.get();
+ // 更新前后内容相同则不进行更新
+ if (!vtdu.getRtspSource().equals(rtspSourceUrl) ||
+ !vtdu.getWebrtcUrl().equals(webrtcUrl) ||
+ !vtdu.getRtspUrl().equals(rtspUrl) ||
+ !vtdu.getRtmpUrl().equals(rtmpUrl)) {
+ vtdu.setRtspUrl(rtspUrl);
+ vtdu.setRtmpUrl(rtmpUrl);
+ vtdu.setWebrtcUrl(webrtcUrl);
+ ardVtduService.updateArdVtdu(vtdu);
+ log.info("更新媒体记录:{}", vtdu.getName());
+ }
+ } else {
+ // 如果没有,插入新的记录
+ ArdVtdu vtdu = new ArdVtdu();
+ vtdu.setName(name);
+ vtdu.setRtspSource(rtspSourceUrl);
+ vtdu.setCameraId(cameraId);
+ vtdu.setRtspUrl(rtspUrl);
+ vtdu.setRtmpUrl(rtmpUrl);
+ vtdu.setWebrtcUrl(webrtcUrl);
+ ardVtduService.insertArdVtdu(vtdu); // 保存到媒体表
+ log.info("插入新媒体记录:{}", vtdu.getName());
+ }
+ });
+ // 3. 删除操作:删除媒体表中多余的记录
+ List<String> invalidNames = ardVtduList.stream()
+ .filter(vtdu -> !validNames.contains(vtdu.getName()))
+ .filter(vtdu -> !"publisher".equalsIgnoreCase(vtdu.getRtspSource())) // 不是机场流
+ .map(ArdVtdu::getName)
+ .collect(Collectors.toList());
+
+ if (!invalidNames.isEmpty()) {
+ // 将 List<String> 转换为 String[]
+ String[] namesArray = invalidNames.toArray(new String[0]);
+ ardVtduService.deleteArdVtduByNames(namesArray); // 传递数组
+ log.info("删除不再存在的媒体记录:{}", Arrays.toString(namesArray));
+ }
+
+ }
+
+ // 根据通道信息获取rtsp源地址
+ private String getRtspSource(ArdChannel channel) {
+ String rtspSource = "";
+ ArdCamera ardCamera = redisCache.getCacheObject(CacheConstants.CAMERA_LIST_KEY + channel.getDeviceId());
+ if (ardCamera != null) {
+ switch (ardCamera.getFactory()) {
+ case "1":
+ rtspSource =
+ "rtsp://" + ardCamera.getUsername() + ":" + ardCamera.getPassword() + "@" + ardCamera.getIp() + ":" + ardCamera.getRtspPort() + "/h264/ch" + channel.getChanNo() + "/main/av_stream";
+ break;
+ case "2":
+ rtspSource =
+ "rtsp://" + ardCamera.getUsername() + ":" + ardCamera.getPassword() + "@" + ardCamera.getIp() + ":" + ardCamera.getRtspPort() + "/cam/realmonitor?channel=" + channel.getChanNo() + "&subtype=0";
+ break;
+ }
+ }
+ return rtspSource;
+ }
+
+ /**
+ * 同步mediamtx
+ */
+ public void syncMediamtx() {
+ log.debug("定时同步MediaMTX任务");
+ List<String> nameList = ardMediaService.getNameList();
+ List<ArdVtdu> ardVtduList = ardVtduService.selectArdVtduList(new ArdVtdu());
+ ardVtduService.asyncMediaMTX(ardVtduList, nameList);
+ }
+}
diff --git a/ard-quartz/src/main/java/com/ard/quartz/task/MediaTask.java b/ard-quartz/src/main/java/com/ard/quartz/task/MediaTask.java
new file mode 100644
index 0000000..1e5258a
--- /dev/null
+++ b/ard-quartz/src/main/java/com/ard/quartz/task/MediaTask.java
@@ -0,0 +1,353 @@
+package com.ard.quartz.task;
+
+import com.ard.common.utils.StringUtils;
+import com.ard.common.utils.file.MimeTypeUtils;
+import com.ard.oss.service.impl.OssServiceContext;
+import com.ard.work.domain.entity.ArdMediaPic;
+import com.ard.work.domain.entity.ArdMediaVideo;
+import com.ard.work.mapper.ArdMediaPicMapper;
+import com.ard.work.mapper.ArdMediaVideoMapper;
+import com.ard.work.util.osSelect;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * 定时同步媒体任务
+ *
+ * @author ard
+ */
+@Component("MediaTask")
+@Slf4j
+public class MediaTask {
+ @Resource
+ private ArdMediaPicMapper ardMediaPicMapper;
+ @Resource
+ private ArdMediaVideoMapper ardMediaVideoMapper;
+ @Resource
+ private OssServiceContext ossServiceContext;
+ @Resource(name = "mediaVideoExecutor")
+ private ThreadPoolTaskExecutor mediaVideoExecutor;
+ @Resource(name = "mediaPicExecutor")
+ private ThreadPoolTaskExecutor mediaPicExecutor;
+
+ private final AtomicBoolean runningVideo = new AtomicBoolean(false);
+ private final AtomicBoolean runningPic = new AtomicBoolean(false);
+
+ public void syncVideoMediaUrl() {
+ log.warn("开始同步视频媒体");
+ if (!runningVideo.compareAndSet(false, true)) {
+ log.warn("上一次同步还没完成,跳过本次调度");
+ return;
+ }
+ try {
+ while (true) {
+ List<ArdMediaVideo> videos = ardMediaVideoMapper.selectPendingVideos(10);
+ if (videos.isEmpty()) {
+ break; // 没有待处理视频,退出循环
+ }
+ for (ArdMediaVideo video : videos) {
+ int updated = ardMediaVideoMapper.markProcessing(video.getId());
+ if (updated != 1) continue;
+ mediaVideoExecutor.execute(() -> processOneVideo(video));
+ }
+ Thread.sleep(200);
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ } finally {
+ runningVideo.set(false);
+ }
+ }
+
+ public void syncPicMediaUrl() {
+ log.warn("开始同步图片媒体");
+ if (!runningPic.compareAndSet(false, true)) {
+ log.warn("上一次同步还没完成,跳过本次调度");
+ return;
+ }
+ try {
+ while (true) {
+ List<ArdMediaPic> pics = ardMediaPicMapper.selectPendingPics(10); // 查询待处理的图片
+ if (pics.isEmpty()) {
+ break; // 没有待处理图片,退出循环
+ }
+ for (ArdMediaPic pic : pics) {
+ // 🔒 原子抢占:0 → 1
+ int updated = ardMediaPicMapper.markProcessing(pic.getId());
+ if (updated != 1) {
+ continue; // 已被别的任务抢占
+ }
+ mediaPicExecutor.execute(() -> processOnePic(pic));
+ }
+ // 短暂 sleep,避免无限循环CPU空转
+ Thread.sleep(200);
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ } finally {
+ runningPic.set(false);
+ }
+ }
+
+ private void processOneVideo(ArdMediaVideo video) {
+ int maxRetries = 3; // 最大重试次数
+ int retryDelay = 3000; // 每次重试等待 3 秒
+ int attempt = 0;
+
+ while (attempt < maxRetries) {
+ attempt++;
+ try (InputStream is = openUrlInputStream(video.getSourceUrl())) {
+ if (is != null) {
+ String mediaUrl = ossServiceContext.upload(
+ "record",
+ video.getTaskId() + "/" + video.getId() + ".mp4",
+ is,
+ MimeTypeUtils.VIDEO_MP4
+ );
+ video.setMediaUrl(mediaUrl);
+
+ // 生成视频缩略图
+ processVideoThumbnail(video);
+
+ video.setSyncStatus(2); // 成功
+ break; // 上传成功,退出循环
+ } else {
+ log.warn("视频尚未生成,尝试重试 {}/{}", attempt, maxRetries);
+ }
+ } catch (Exception e) {
+ log.error("视频同步异常 videoId={}, 尝试 {}/{}", video.getId(), attempt, maxRetries, e);
+ }
+
+ if (attempt < maxRetries) {
+ try {
+ Thread.sleep(retryDelay);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ break;
+ }
+ } else {
+ video.setSyncStatus(3); // 达到最大重试仍失败
+ }
+ }
+
+ video.setUpdateTime(new Date());
+ try {
+ ardMediaVideoMapper.updateArdMediaVideo(video);
+ } catch (Exception e) {
+ log.error("更新视频状态失败 videoId={}", video.getId(), e);
+ }
+ }
+
+ private void processOnePic(ArdMediaPic pic) {
+ int maxRetries = 3; // 最大重试次数
+ int retryDelay = 2000; // 每次重试等待 2 秒
+ int attempt = 0;
+
+ while (attempt < maxRetries) {
+ attempt++;
+ try (InputStream inputStream = openUrlInputStream(pic.getSourceUrl())) {
+ if (inputStream != null) {
+ String url = ossServiceContext.upload(
+ "pic",
+ pic.getTaskId() + "/" + pic.getId() + ".jpg",
+ inputStream,
+ MimeTypeUtils.IMAGE_JPG
+ );
+ pic.setMediaUrl(url);
+ pic.setSyncStatus(2); // 成功
+ break; // 上传成功,退出循环
+ } else {
+ log.warn("图片尚未生成,尝试重试 {}/{}", attempt, maxRetries);
+ }
+ } catch (Exception e) {
+ log.error("图片同步异常 taskId={}, photoId={}, 尝试 {}/{}", pic.getTaskId(), pic.getId(), attempt, maxRetries, e);
+ }
+
+ if (attempt < maxRetries) {
+ try {
+ Thread.sleep(retryDelay);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ break;
+ }
+ } else {
+ pic.setSyncStatus(3); // 达到最大重试仍失败
+ }
+ }
+
+ pic.setUpdateTime(new Date());
+ try {
+ ardMediaPicMapper.updatePic(pic);
+ } catch (Exception e) {
+ log.error("更新图片状态失败 photoId={}", pic.getId(), e);
+ }
+ }
+
+ /**
+ * 处理视频缩略图
+ */
+ private void processVideoThumbnail(ArdMediaVideo video) {
+ // 生成缩略图
+ try (ByteArrayInputStream in = generateThumbnail(video.getSourceUrl())) {
+ String thumbUrl = ossServiceContext.upload(
+ "record",
+ video.getTaskId() + "/" + video.getId() + ".jpg",
+ in,
+ MimeTypeUtils.IMAGE_JPEG
+ );
+ video.setThumbnailUrl(thumbUrl);
+ } catch (Exception e) {
+ log.warn("视频缩略图生成或上传失败 taskId={}, videoId={}", video.getTaskId(), video.getId(), e);
+ }
+ // 获取文件大小
+ try {
+ long videoSize = getFileSizeFromUrl(video.getSourceUrl());
+ video.setFileSize(videoSize);
+ } catch (Exception e) {
+ log.warn("获取视频大小失败 url={}", video.getSourceUrl(), e);
+ }
+ }
+
+ private long getFileSizeFromUrl(String fileUrl) throws IOException {
+ URL url = new URL(fileUrl);
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setRequestMethod("HEAD");
+ conn.setConnectTimeout(5000);
+ conn.setReadTimeout(5000);
+ conn.connect();
+ long size = conn.getContentLengthLong(); // 返回字节数
+ conn.disconnect();
+ return size;
+ }
+
+ private ByteArrayInputStream generateThumbnail(String videoFile) {
+
+ String ffmpeg = osSelect.isWindows()
+ ? "ffmpeg"
+ : "/usr/local/ffmpeg/bin/ffmpeg";
+
+ Path tempImg = null;
+ try {
+ tempImg = Files.createTempFile("thumb_", ".jpg");
+
+ List<String> cmd = new ArrayList<>();
+ cmd.add(ffmpeg);
+ cmd.add("-y");
+ cmd.add("-loglevel");
+ cmd.add("error");
+ cmd.add("-i");
+ cmd.add(videoFile);
+ cmd.add("-ss");
+ cmd.add(String.valueOf(1));
+ cmd.add("-vframes");
+ cmd.add("1");
+ cmd.add("-vf");
+ cmd.add("scale=" + 200 + ":-1");
+ cmd.add(tempImg.toAbsolutePath().toString());
+
+ log.info("ffmpeg cmd: {}", String.join(" ", cmd));
+
+ Process process = new ProcessBuilder(cmd).start();
+
+ drain(process.getErrorStream());
+
+ boolean finished = process.waitFor(15, TimeUnit.SECONDS); // 超时保护
+ if (!finished) {
+ process.destroyForcibly();
+ throw new RuntimeException("ffmpeg timeout");
+ }
+
+ if (process.exitValue() != 0) {
+ throw new RuntimeException("ffmpeg exit=" + process.exitValue());
+ }
+
+ byte[] data = Files.readAllBytes(tempImg);
+ return new ByteArrayInputStream(data);
+
+ } catch (Exception e) {
+ throw new RuntimeException("生成缩略图失败", e);
+ } finally {
+ if (tempImg != null) {
+ try {
+ Files.deleteIfExists(tempImg);
+ } catch (IOException ignore) {
+ }
+ }
+ }
+ }
+
+ private static void drain(InputStream is) {
+ new Thread(() -> {
+ try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
+ while (br.readLine() != null) {
+ }
+ } catch (IOException ignore) {
+ }
+ }, "ffmpeg-stderr").start();
+ }
+
+ /**
+ * 将 URL 转成 InputStream
+ *
+ * @param fileUrl 文件 URL
+ * @return InputStream,如果失败返回 null
+ */
+ private InputStream openUrlInputStream(String fileUrl) {
+ try {
+ URL url = new URL(fileUrl);
+ // 支持 HTTPS 信任所有证书(如果需要访问自签名证书)
+ if ("https".equalsIgnoreCase(url.getProtocol())) {
+ TrustManager[] trustAllCerts = new TrustManager[]{
+ new X509TrustManager() {
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType) {
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType) {
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+ }
+ };
+ SSLContext sc = SSLContext.getInstance("SSL");
+ sc.init(null, trustAllCerts, new java.security.SecureRandom());
+ HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+ HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
+ }
+ URLConnection connection = url.openConnection();
+ connection.setConnectTimeout(5000);
+ connection.setReadTimeout(10000);
+ return connection.getInputStream();
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+}
diff --git a/ard-route/src/main/java/com/ard/route/service/impl/ArdRouteInfoServiceImpl.java b/ard-route/src/main/java/com/ard/route/service/impl/ArdRouteInfoServiceImpl.java
index 5a0b49c..1bc4a7a 100644
--- a/ard-route/src/main/java/com/ard/route/service/impl/ArdRouteInfoServiceImpl.java
+++ b/ard-route/src/main/java/com/ard/route/service/impl/ArdRouteInfoServiceImpl.java
@@ -81,8 +81,10 @@
public ArdRouteInfo selectArdRouteInfoById(String id) {
ArdRouteInfo ardRouteInfo = ardRouteInfoMapper.selectArdRouteInfoById(id);
try {
- if (ardRouteInfo.getRouteData() != null){
- ardRouteInfo.setUavRouteReq((UavRouteReq) deserialize(ardRouteInfo.getRouteData()));
+ if (ardRouteInfo != null) {
+ if (ardRouteInfo.getRouteData() != null){
+ ardRouteInfo.setUavRouteReq((UavRouteReq) deserialize(ardRouteInfo.getRouteData()));
+ }
}
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException(e);
@@ -144,18 +146,7 @@
}
ardRouteInfo.getUavRouteReq().setDroneType(subStringDroneType(ardRouteInfo.getAircraft()));
KmzResultVo kmzResult = routeService.buildKmz(ardRouteInfo.getUavRouteReq(),ardRouteInfo.getName());
- if (M350_RTK.getValue().equals(ardRouteInfo.getUavRouteReq().getDroneType())) {
- // 变焦数值加工
- for (RoutePointReq routePointReq : ardRouteInfo.getUavRouteReq().getRoutePointList()) {
- for (ActionGroupReq actionGroupReq : routePointReq.getActionGroupList()) {
- for (PointActionReq action : actionGroupReq.getActions()) {
- if (action.getZoom() != null){
- action.setZoom(divided_23(action.getZoom()));
- }
- }
- }
- }
- }
+ zoomProcessing(ardRouteInfo);
ardRouteInfo.setPath(kmzResult.getPath());
ardRouteInfo.setReadOnly("0");
ardRouteInfoMapper.insertArdRouteInfo(dataProcessing(ardRouteInfo));
@@ -179,6 +170,8 @@
// 先删除航线
delOssService(route);
// 再生成航线
+ ardRouteInfo.getUavRouteReq().setDroneType(subStringDroneType(ardRouteInfo.getAircraft()));
+ zoomProcessing(ardRouteInfo);
kmzResult = routeService.buildKmz(ardRouteInfo.getUavRouteReq(), ardRouteInfo.getName());
if ("更新航线kmz文件失败".equals(kmzResult.getData())) {
return 0;
@@ -186,6 +179,22 @@
ardRouteInfo.setPath(kmzResult.getPath());
}
return ardRouteInfoMapper.updateArdRouteInfo(dataProcessing(ardRouteInfo));
+ }
+
+ // 变倍加工方法
+ private void zoomProcessing(ArdRouteInfo ardRouteInfo) {
+ if (M350_RTK.getValue().equals(ardRouteInfo.getUavRouteReq().getDroneType())) {
+ // 变焦数值加工
+ for (RoutePointReq routePointReq : ardRouteInfo.getUavRouteReq().getRoutePointList()) {
+ for (ActionGroupReq actionGroupReq : routePointReq.getActionGroupList()) {
+ for (PointActionReq action : actionGroupReq.getActions()) {
+ if (action.getZoom() != null){
+ action.setZoom(divided_23(action.getZoom()));
+ }
+ }
+ }
+ }
+ }
}
// 新增信息加工
@@ -413,7 +422,7 @@
public Boolean routeBegins(String id,String boxSn) {
ArdRouteInfo route = ardRouteInfoMapper.selectArdRouteInfoById(id);
// 判断是否循环航线
- if ("1".equals(route.getIsLoop())) {
+ if (null != route && "0".equals(route.getIsLoop())){
deleteArdRouteInfoById(id);
}
WayLineBeginDTO wayLineBeginDTO = new WayLineBeginDTO(boxSn);
diff --git a/ard-route/src/main/java/com/ard/route/util/RouteFileUtils.java b/ard-route/src/main/java/com/ard/route/util/RouteFileUtils.java
index 955a11b..ceeb180 100644
--- a/ard-route/src/main/java/com/ard/route/util/RouteFileUtils.java
+++ b/ard-route/src/main/java/com/ard/route/util/RouteFileUtils.java
@@ -541,7 +541,11 @@
}else {
kmlActionActuatorFuncParam.setFileSuffix("panoramicPhoto_360");
}
- kmlActionActuatorFuncParam.setUseGlobalPayloadLensIndex(String.valueOf(pointActionReq.getUseGlobalImageFormat()));
+ if (pointActionReq.getUseGlobalImageFormat() != null) {
+ kmlActionActuatorFuncParam.setUseGlobalPayloadLensIndex(String.valueOf(pointActionReq.getUseGlobalImageFormat()));
+ }else {
+ kmlActionActuatorFuncParam.setUseGlobalPayloadLensIndex("0");
+ }
if (ObjectUtil.equals(pointActionReq.getUseGlobalImageFormat(), 0)) {
kmlActionActuatorFuncParam.setPayloadLensIndex(pointActionReq.getImageFormat());
} else {
diff --git a/ard-sample/src/main/java/com/ard/sample/manage/service/impl/LiveStreamServiceImpl.java b/ard-sample/src/main/java/com/ard/sample/manage/service/impl/LiveStreamServiceImpl.java
index 0940bbd..8a6d437 100644
--- a/ard-sample/src/main/java/com/ard/sample/manage/service/impl/LiveStreamServiceImpl.java
+++ b/ard-sample/src/main/java/com/ard/sample/manage/service/impl/LiveStreamServiceImpl.java
@@ -21,7 +21,6 @@
import com.ard.sample.manage.service.ILiveStreamService;
import com.ard.vtdu.config.MediamtxConfig;
import com.ard.vtdu.domain.ArdVtdu;
-import com.ard.vtdu.service.IArdMediaService;
import com.ard.vtdu.service.IArdVtduService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
diff --git a/ard-system/src/main/java/com/ard/data/map/mapper/ArdMapMapper.java b/ard-system/src/main/java/com/ard/data/map/mapper/ArdMapMapper.java
index ae12f02..3aaaeaf 100644
--- a/ard-system/src/main/java/com/ard/data/map/mapper/ArdMapMapper.java
+++ b/ard-system/src/main/java/com/ard/data/map/mapper/ArdMapMapper.java
@@ -1,6 +1,7 @@
package com.ard.data.map.mapper;
import com.ard.data.map.domain.ArdMap;
+import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -59,4 +60,13 @@
* @return 结果
*/
public int deleteArdMapByIds(String[] ids);
+
+ /**
+ * 校验地图管理信息名称是否唯一
+ *
+ * @param mapName 名称
+ * @return 结果
+ */
+ public ArdMap checkArdMapNameUnique(@Param("mapName") String mapName);
+
}
diff --git a/ard-system/src/main/java/com/ard/data/map/service/IArdMapService.java b/ard-system/src/main/java/com/ard/data/map/service/IArdMapService.java
index 028ab9b..996eba2 100644
--- a/ard-system/src/main/java/com/ard/data/map/service/IArdMapService.java
+++ b/ard-system/src/main/java/com/ard/data/map/service/IArdMapService.java
@@ -59,4 +59,13 @@
* @return 结果
*/
public int deleteArdMapById(String id);
+
+ /**
+ * 校验地图管理信息名称是否唯一
+ *
+ * @param ardMap 地图管理
+ * @return 结果
+ */
+ public String checkArdMapNameUnique(ArdMap ardMap);
+
}
diff --git a/ard-system/src/main/java/com/ard/data/map/service/impl/ArdMapServiceImpl.java b/ard-system/src/main/java/com/ard/data/map/service/impl/ArdMapServiceImpl.java
index 869117b..362b632 100644
--- a/ard-system/src/main/java/com/ard/data/map/service/impl/ArdMapServiceImpl.java
+++ b/ard-system/src/main/java/com/ard/data/map/service/impl/ArdMapServiceImpl.java
@@ -1,5 +1,6 @@
package com.ard.data.map.service.impl;
+import com.ard.common.constant.DeviceConstants;
import com.ard.common.utils.uuid.IdUtils;
import com.ard.data.map.domain.ArdMap;
import com.ard.data.map.mapper.ArdMapMapper;
@@ -87,4 +88,24 @@
public int deleteArdMapById(String id) {
return ardMapMapper.deleteArdMapById(id);
}
+
+ /**
+ * 校验地图管理信息名称是否唯一
+ *
+ * @param ardMap 地图管理
+ * @return 结果
+ */
+ @Override
+ public String checkArdMapNameUnique(ArdMap ardMap) {
+ String id = ardMap.getId();
+ String mapName = ardMap.getMapName();
+
+ ArdMap map = ardMapMapper.checkArdMapNameUnique(mapName);
+
+ if (map != null && (id == null || !id.equals(map.getId()))) {
+ return DeviceConstants.NOT_UNIQUE;
+ }
+ return DeviceConstants.UNIQUE;
+ }
+
}
diff --git a/ard-system/src/main/java/com/ard/data/model/mapper/ArdModelMapper.java b/ard-system/src/main/java/com/ard/data/model/mapper/ArdModelMapper.java
index 2f60299..9ead264 100644
--- a/ard-system/src/main/java/com/ard/data/model/mapper/ArdModelMapper.java
+++ b/ard-system/src/main/java/com/ard/data/model/mapper/ArdModelMapper.java
@@ -1,6 +1,7 @@
package com.ard.data.model.mapper;
import com.ard.data.model.domain.ArdModel;
+import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -59,4 +60,13 @@
* @return 结果
*/
public int deleteArdModelByIds(String[] ids);
+
+ /**
+ * 校验模型管理信息名称是否唯一
+ *
+ * @param modelName 名称
+ * @return 结果
+ */
+ public ArdModel checkArdModelNameUnique(@Param("modelName") String modelName);
+
}
diff --git a/ard-system/src/main/java/com/ard/data/model/service/IArdModelService.java b/ard-system/src/main/java/com/ard/data/model/service/IArdModelService.java
index 12fb816..66776cc 100644
--- a/ard-system/src/main/java/com/ard/data/model/service/IArdModelService.java
+++ b/ard-system/src/main/java/com/ard/data/model/service/IArdModelService.java
@@ -59,4 +59,13 @@
* @return 结果
*/
public int deleteArdModelById(String id);
+
+ /**
+ * 校验模型管理信息名称是否唯一
+ *
+ * @param ardModel 模型管理
+ * @return 结果
+ */
+ public String checkArdModelNameUnique(ArdModel ardModel);
+
}
diff --git a/ard-system/src/main/java/com/ard/data/model/service/impl/ArdModelServiceImpl.java b/ard-system/src/main/java/com/ard/data/model/service/impl/ArdModelServiceImpl.java
index 8b3a1a5..b000909 100644
--- a/ard-system/src/main/java/com/ard/data/model/service/impl/ArdModelServiceImpl.java
+++ b/ard-system/src/main/java/com/ard/data/model/service/impl/ArdModelServiceImpl.java
@@ -2,6 +2,7 @@
import java.util.List;
+import com.ard.common.constant.DeviceConstants;
import com.ard.common.utils.uuid.IdUtils;
import com.ard.data.model.domain.ArdModel;
import com.ard.data.model.mapper.ArdModelMapper;
@@ -87,4 +88,24 @@
public int deleteArdModelById(String id) {
return ardModelMapper.deleteArdModelById(id);
}
+
+ /**
+ * 校验模型管理信息名称是否唯一
+ *
+ * @param ardModel 模型管理
+ * @return 结果
+ */
+ @Override
+ public String checkArdModelNameUnique(ArdModel ardModel) {
+ String id = ardModel.getId();
+ String modelName = ardModel.getModelName();
+
+ ArdModel model = ardModelMapper.checkArdModelNameUnique(modelName);
+
+ if (model != null && (id == null || !id.equals(model.getId()))) {
+ return DeviceConstants.NOT_UNIQUE;
+ }
+ return DeviceConstants.UNIQUE;
+ }
+
}
diff --git a/ard-system/src/main/java/com/ard/data/noflyzone/mapper/ArdNoFlyZoneMapper.java b/ard-system/src/main/java/com/ard/data/noflyzone/mapper/ArdNoFlyZoneMapper.java
index 5b59628..1419745 100644
--- a/ard-system/src/main/java/com/ard/data/noflyzone/mapper/ArdNoFlyZoneMapper.java
+++ b/ard-system/src/main/java/com/ard/data/noflyzone/mapper/ArdNoFlyZoneMapper.java
@@ -2,6 +2,7 @@
import java.util.List;
import com.ard.data.noflyzone.domain.ArdNoFlyZone;
+import org.apache.ibatis.annotations.Param;
/**
* 禁飞区管理Mapper接口
@@ -58,4 +59,12 @@
* @return 结果
*/
public int deleteArdNoFlyZoneByIds(String[] ids);
+
+ /**
+ * 校验禁飞区名称是否唯一
+ *
+ * @param name 禁飞区名称
+ * @return 禁飞区信息
+ */
+ public ArdNoFlyZone checkArdNoFlyZoneNameUnique(@Param("name") String name);
}
diff --git a/ard-system/src/main/java/com/ard/data/noflyzone/service/IArdNoFlyZoneService.java b/ard-system/src/main/java/com/ard/data/noflyzone/service/IArdNoFlyZoneService.java
index 72ecbd5..e7ace4d 100644
--- a/ard-system/src/main/java/com/ard/data/noflyzone/service/IArdNoFlyZoneService.java
+++ b/ard-system/src/main/java/com/ard/data/noflyzone/service/IArdNoFlyZoneService.java
@@ -58,4 +58,12 @@
* @return 结果
*/
public int deleteArdNoFlyZoneById(String id);
+
+ /**
+ * 校验禁飞区名称是否唯一
+ *
+ * @param ardNoFlyZone 禁飞区实体
+ * @return 结果
+ */
+ public String checkArdNoFlyZoneNameUnique(ArdNoFlyZone ardNoFlyZone);
}
diff --git a/ard-system/src/main/java/com/ard/data/noflyzone/service/impl/ArdNoFlyZoneServiceImpl.java b/ard-system/src/main/java/com/ard/data/noflyzone/service/impl/ArdNoFlyZoneServiceImpl.java
index 56e2c48..d4949eb 100644
--- a/ard-system/src/main/java/com/ard/data/noflyzone/service/impl/ArdNoFlyZoneServiceImpl.java
+++ b/ard-system/src/main/java/com/ard/data/noflyzone/service/impl/ArdNoFlyZoneServiceImpl.java
@@ -1,8 +1,11 @@
package com.ard.data.noflyzone.service.impl;
import java.util.List;
+
+import com.ard.common.constant.DeviceConstants;
import com.ard.common.utils.DateUtils;
import com.ard.common.utils.SecurityUtils;
+import com.ard.common.utils.StringUtils;
import com.ard.common.utils.uuid.IdUtils;
import com.ard.data.noflyzone.service.IArdNoFlyZoneService;
import org.springframework.stereotype.Service;
@@ -14,49 +17,45 @@
/**
* 禁飞区管理Service业务层处理
- *
+ *
* @author ard
* @date 2025-10-14
*/
@Service
-public class ArdNoFlyZoneServiceImpl implements IArdNoFlyZoneService
-{
+public class ArdNoFlyZoneServiceImpl implements IArdNoFlyZoneService {
@Resource
private ArdNoFlyZoneMapper ardNoFlyZoneMapper;
/**
* 查询禁飞区管理
- *
+ *
* @param id 禁飞区管理主键
* @return 禁飞区管理
*/
@Override
- public ArdNoFlyZone selectArdNoFlyZoneById(String id)
- {
+ public ArdNoFlyZone selectArdNoFlyZoneById(String id) {
return ardNoFlyZoneMapper.selectArdNoFlyZoneById(id);
}
/**
* 查询禁飞区管理列表
- *
+ *
* @param ardNoFlyZone 禁飞区管理
* @return 禁飞区管理
*/
@Override
- public List<ArdNoFlyZone> selectArdNoFlyZoneList(ArdNoFlyZone ardNoFlyZone)
- {
+ public List<ArdNoFlyZone> selectArdNoFlyZoneList(ArdNoFlyZone ardNoFlyZone) {
return ardNoFlyZoneMapper.selectArdNoFlyZoneList(ardNoFlyZone);
}
/**
* 新增禁飞区管理
- *
+ *
* @param ardNoFlyZone 禁飞区管理
* @return 结果
*/
@Override
- public int insertArdNoFlyZone(ArdNoFlyZone ardNoFlyZone)
- {
+ public int insertArdNoFlyZone(ArdNoFlyZone ardNoFlyZone) {
ardNoFlyZone.setId(IdUtils.simpleUUID());
ardNoFlyZone.setCreateTime(DateUtils.getNowDate());
ardNoFlyZone.setCreateBy(SecurityUtils.getUsername());
@@ -65,13 +64,12 @@
/**
* 修改禁飞区管理
- *
+ *
* @param ardNoFlyZone 禁飞区管理
* @return 结果
*/
@Override
- public int updateArdNoFlyZone(ArdNoFlyZone ardNoFlyZone)
- {
+ public int updateArdNoFlyZone(ArdNoFlyZone ardNoFlyZone) {
ardNoFlyZone.setUpdateBy(SecurityUtils.getUsername());
ardNoFlyZone.setUpdateTime(DateUtils.getNowDate());
return ardNoFlyZoneMapper.updateArdNoFlyZone(ardNoFlyZone);
@@ -79,27 +77,42 @@
/**
* 批量删除禁飞区管理
- *
+ *
* @param ids 需要删除的禁飞区管理主键
* @return 结果
*/
@Override
- public int deleteArdNoFlyZoneByIds(String[] ids)
- {
+ public int deleteArdNoFlyZoneByIds(String[] ids) {
return ardNoFlyZoneMapper.deleteArdNoFlyZoneByIds(ids);
}
/**
* 删除禁飞区管理信息
- *
+ *
* @param id 禁飞区管理主键
* @return 结果
*/
@Override
- public int deleteArdNoFlyZoneById(String id)
- {
+ public int deleteArdNoFlyZoneById(String id) {
return ardNoFlyZoneMapper.deleteArdNoFlyZoneById(id);
}
+ /**
+ * 校验禁飞区名称是否唯一
+ *
+ * @param ardNoFlyZone 禁飞区实体
+ * @return 结果
+ */
+ @Override
+ public String checkArdNoFlyZoneNameUnique(ArdNoFlyZone ardNoFlyZone) {
+ String id = ardNoFlyZone.getId();
+ String name = ardNoFlyZone.getName();
+ ArdNoFlyZone info = ardNoFlyZoneMapper.checkArdNoFlyZoneNameUnique(name);
+
+ if (info != null && (id == null || !id.equals(info.getId()))) {
+ return DeviceConstants.NOT_UNIQUE;
+ }
+ return DeviceConstants.UNIQUE;
+ }
}
diff --git a/ard-system/src/main/java/com/ard/data/tile/mapper/ArdTileMapper.java b/ard-system/src/main/java/com/ard/data/tile/mapper/ArdTileMapper.java
index 13edb58..656bfd6 100644
--- a/ard-system/src/main/java/com/ard/data/tile/mapper/ArdTileMapper.java
+++ b/ard-system/src/main/java/com/ard/data/tile/mapper/ArdTileMapper.java
@@ -1,6 +1,7 @@
package com.ard.data.tile.mapper;
import com.ard.data.tile.domain.ArdTile;
+import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -59,4 +60,13 @@
* @return 结果
*/
public int deleteArdTileByIds(String[] ids);
+
+ /**
+ * 校验tile管理信息名称是否唯一
+ *
+ * @param tilesName 名称
+ * @return 结果
+ */
+ public ArdTile checkArdTileNameUnique(@Param("tilesName") String tilesName);
+
}
diff --git a/ard-system/src/main/java/com/ard/data/tile/service/IArdTileService.java b/ard-system/src/main/java/com/ard/data/tile/service/IArdTileService.java
index 1a7b6ce..b08ba82 100644
--- a/ard-system/src/main/java/com/ard/data/tile/service/IArdTileService.java
+++ b/ard-system/src/main/java/com/ard/data/tile/service/IArdTileService.java
@@ -59,4 +59,13 @@
* @return 结果
*/
public int deleteArdTileById(String id);
+
+ /**
+ * 校验tile管理信息名称是否唯一
+ *
+ * @param ardTile tile管理
+ * @return 结果
+ */
+ public String checkArdTileNameUnique(ArdTile ardTile);
+
}
diff --git a/ard-system/src/main/java/com/ard/data/tile/service/impl/ArdTileServiceImpl.java b/ard-system/src/main/java/com/ard/data/tile/service/impl/ArdTileServiceImpl.java
index c068545..8014252 100644
--- a/ard-system/src/main/java/com/ard/data/tile/service/impl/ArdTileServiceImpl.java
+++ b/ard-system/src/main/java/com/ard/data/tile/service/impl/ArdTileServiceImpl.java
@@ -2,6 +2,7 @@
import java.util.List;
+import com.ard.common.constant.DeviceConstants;
import com.ard.common.utils.uuid.IdUtils;
import com.ard.data.tile.domain.ArdTile;
import com.ard.data.tile.mapper.ArdTileMapper;
@@ -87,4 +88,24 @@
public int deleteArdTileById(String id) {
return ardTileMapper.deleteArdTileById(id);
}
+
+ /**
+ * 校验tile管理信息名称是否唯一
+ *
+ * @param ardTile tile管理
+ * @return 结果
+ */
+ @Override
+ public String checkArdTileNameUnique(ArdTile ardTile) {
+ String id = ardTile.getId();
+ String tilesName = ardTile.getTilesName();
+
+ ArdTile tile = ardTileMapper.checkArdTileNameUnique(tilesName);
+
+ if (tile != null && (id == null || !id.equals(tile.getId()))) {
+ return DeviceConstants.NOT_UNIQUE;
+ }
+ return DeviceConstants.UNIQUE;
+ }
+
}
diff --git a/ard-system/src/main/resources/mapper/data/ArdMapMapper.xml b/ard-system/src/main/resources/mapper/data/ArdMapMapper.xml
index a5ecaac..11bc45f 100644
--- a/ard-system/src/main/resources/mapper/data/ArdMapMapper.xml
+++ b/ard-system/src/main/resources/mapper/data/ArdMapMapper.xml
@@ -85,4 +85,9 @@
#{id}
</foreach>
</delete>
+
+ <select id="checkArdMapNameUnique" resultMap="ArdMapResult">
+ select * from ard_map where map_name = #{mapName} limit 1
+ </select>
+
</mapper>
\ No newline at end of file
diff --git a/ard-system/src/main/resources/mapper/data/ArdModelMapper.xml b/ard-system/src/main/resources/mapper/data/ArdModelMapper.xml
index a014f0e..8d84bee 100644
--- a/ard-system/src/main/resources/mapper/data/ArdModelMapper.xml
+++ b/ard-system/src/main/resources/mapper/data/ArdModelMapper.xml
@@ -87,4 +87,9 @@
#{id}
</foreach>
</delete>
+
+ <select id="checkArdModelNameUnique" parameterType="String" resultMap="ArdModelResult">
+ select * from ard_model where model_name = #{modelName} limit 1
+ </select>
+
</mapper>
\ No newline at end of file
diff --git a/ard-system/src/main/resources/mapper/data/ArdNoFlyZoneMapper.xml b/ard-system/src/main/resources/mapper/data/ArdNoFlyZoneMapper.xml
index cf49160..28ffec0 100644
--- a/ard-system/src/main/resources/mapper/data/ArdNoFlyZoneMapper.xml
+++ b/ard-system/src/main/resources/mapper/data/ArdNoFlyZoneMapper.xml
@@ -83,4 +83,9 @@
#{id}
</foreach>
</delete>
+
+ <select id="checkArdNoFlyZoneNameUnique" resultMap="ArdNoFlyZoneResult">
+ select * from ard_no_fly_zone where name = #{name} limit 1
+ </select>
+
</mapper>
\ No newline at end of file
diff --git a/ard-system/src/main/resources/mapper/data/ArdTileMapper.xml b/ard-system/src/main/resources/mapper/data/ArdTileMapper.xml
index 2ed3409..d0fce45 100644
--- a/ard-system/src/main/resources/mapper/data/ArdTileMapper.xml
+++ b/ard-system/src/main/resources/mapper/data/ArdTileMapper.xml
@@ -104,4 +104,9 @@
#{id}
</foreach>
</delete>
+
+ <select id="checkArdTileNameUnique" parameterType="String" resultMap="ArdTileResult">
+ select * from ard_tile where tiles_name = #{tilesName} limit 1
+ </select>
+
</mapper>
\ No newline at end of file
diff --git a/ard-vtdu/src/main/java/com/ard/vtdu/service/impl/ArdVtduServiceImpl.java b/ard-vtdu/src/main/java/com/ard/vtdu/service/impl/ArdVtduServiceImpl.java
index a0c5f7b..806b065 100644
--- a/ard-vtdu/src/main/java/com/ard/vtdu/service/impl/ArdVtduServiceImpl.java
+++ b/ard-vtdu/src/main/java/com/ard/vtdu/service/impl/ArdVtduServiceImpl.java
@@ -38,14 +38,6 @@
mediaService.clearAll();
}
- @Scheduled(cron = "0/5 * * * * ?")
- public void syncMediamtx() {
- log.debug("定时同步MediaMTX任务");
- List<String> nameList = mediaService.getNameList();
- List<ArdVtdu> ardVtduList = selectArdVtduList(new ArdVtdu());
- asyncMediaMTX(ardVtduList, nameList);
- }
-
/**
* 查询流媒体管理
*
diff --git a/ard-work/src/main/java/com/ard/work/domain/entity/ArdMedia.java b/ard-work/src/main/java/com/ard/work/domain/entity/ArdMedia.java
deleted file mode 100644
index f5b97d5..0000000
--- a/ard-work/src/main/java/com/ard/work/domain/entity/ArdMedia.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.ard.work.domain.entity;
-
-import com.ard.common.core.domain.BaseEntity;
-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
- private Integer taskId; // 任务ID(外键关联飞行任务)
- private Integer mediaType; // 媒体类型(0"photo" 或 1"video")
- private Long fileSize; // 文件大小
- 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
-}
diff --git a/ard-work/src/main/java/com/ard/work/domain/entity/ArdMediaPic.java b/ard-work/src/main/java/com/ard/work/domain/entity/ArdMediaPic.java
new file mode 100644
index 0000000..d415301
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/work/domain/entity/ArdMediaPic.java
@@ -0,0 +1,28 @@
+package com.ard.work.domain.entity;
+
+import com.ard.common.core.domain.BaseEntity;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.*;
+
+import java.util.Date;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class ArdMediaPic extends BaseEntity {
+ private Long id;
+ private Integer taskId;
+ private Long fileSize;
+ private String fileMd5;
+ private String mediaUrl;
+ private String sourceUrl;
+ private Double longitude;
+ private Double latitude;
+ private Double height;
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date captureTime;
+ //同步状态 0待处理 1处理中 2成功 3失败
+ private Integer syncStatus;
+}
diff --git a/ard-work/src/main/java/com/ard/work/domain/entity/ArdMediaVideo.java b/ard-work/src/main/java/com/ard/work/domain/entity/ArdMediaVideo.java
new file mode 100644
index 0000000..f6d7220
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/work/domain/entity/ArdMediaVideo.java
@@ -0,0 +1,30 @@
+package com.ard.work.domain.entity;
+
+
+import com.ard.common.core.domain.BaseEntity;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.*;
+
+import java.util.Date;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class ArdMediaVideo extends BaseEntity {
+ private Long id;
+ private String name;
+ private Long fileSize;
+ private String mediaUrl;
+ private String sourceUrl;
+ private String thumbnailUrl;
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date startTime;
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date endTime;
+ private Integer spanSeconds;
+ private Integer taskId;
+ //同步状态 0待处理 1处理中 2成功 3失败
+ private Integer syncStatus;
+}
diff --git a/ard-work/src/main/java/com/ard/work/mapper/ArdMediaMapper.java b/ard-work/src/main/java/com/ard/work/mapper/ArdMediaMapper.java
deleted file mode 100644
index 5a45bf6..0000000
--- a/ard-work/src/main/java/com/ard/work/mapper/ArdMediaMapper.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.ard.work.mapper;
-
-import com.ard.work.domain.entity.ArdMedia;
-import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-
-public interface ArdMediaMapper {
-
- /**
- * 查询媒体数据列表
- *
- * @param ardMedia 媒体数据
- * @return 媒体数据集合
- */
- List<ArdMedia> selectArdMedia(ArdMedia ardMedia); // 动态查询
-
- List<ArdMedia> selectArdMediaByTaskId(Integer taskId); // 根据任务ID查询
-
- List<ArdMedia> selectArdMediaByTaskIdAndType(@Param("taskId") Integer taskId, @Param("mediaType") Integer mediaType); //
-
- /**
- * 插入媒体数据记录
- *
- * @param ardMedia 媒体数据
- */
- void insertArdMedia(ArdMedia ardMedia); // 插入单个记录
-
- void insertArdMediaList(List<ArdMedia> ardMediaList); // 插入批量记录
-
- void updateArdMedia(ArdMedia ardMedia); // 更新记录
-
- void deleteArdMediaById(Integer id); // 根据ID删除记录
-
- void deleteArdMediaByIds(List<Integer> mediaIds); // 批量删除记录
-
- void deleteArdMediaByTaskId(Integer taskId); // 批量删除记录
-}
diff --git a/ard-work/src/main/java/com/ard/work/mapper/ArdMediaPicMapper.java b/ard-work/src/main/java/com/ard/work/mapper/ArdMediaPicMapper.java
new file mode 100644
index 0000000..161b5bb
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/work/mapper/ArdMediaPicMapper.java
@@ -0,0 +1,60 @@
+package com.ard.work.mapper;
+
+import com.ard.work.domain.entity.ArdMediaPic;
+import com.ard.work.domain.entity.ArdMediaVideo;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface ArdMediaPicMapper {
+
+ /**
+ * 查询图片列表(条件查询)
+ */
+ List<ArdMediaPic> selectPicList(ArdMediaPic query);
+
+ /**
+ * 查询待处理图片(sync_status = 0)
+ */
+ List<ArdMediaPic> selectPendingPics(@Param("limit") int limit);
+ /**
+ * 根据任务ID查询图片
+ */
+ List<ArdMediaPic> selectPicByTaskId(@Param("taskId") Integer taskId);
+
+ /**
+ * 新增图片
+ */
+ int insertPic(ArdMediaPic pic);
+
+ /**
+ * 更新图片
+ */
+ int updatePic(ArdMediaPic pic);
+ /**
+ * 原子抢占:0 → 1
+ */
+ int markProcessing(@Param("id") Long id);
+
+ /**
+ * 更新同步状态
+ * 0 = 待处理
+ * 1 = 处理中
+ * 2 = 已完成
+ */
+ int updateSyncStatus(@Param("id") Long id, @Param("status") Integer status);
+
+ /**
+ * 根据ID删除图片
+ */
+ int deletePicById(@Param("id") String id);
+
+ /**
+ * 根据任务ID删除图片
+ */
+ int deletePicByTaskId(@Param("taskId") Integer taskId);
+
+
+}
diff --git a/ard-work/src/main/java/com/ard/work/mapper/ArdMediaVideoMapper.java b/ard-work/src/main/java/com/ard/work/mapper/ArdMediaVideoMapper.java
new file mode 100644
index 0000000..bb465eb
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/work/mapper/ArdMediaVideoMapper.java
@@ -0,0 +1,59 @@
+package com.ard.work.mapper;
+
+import com.ard.work.domain.entity.ArdMediaVideo;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface ArdMediaVideoMapper {
+
+ /**
+ * 查询视频列表(条件查询)
+ */
+ List<ArdMediaVideo> selectArdMediaVideoList(ArdMediaVideo query);
+
+ /**
+ * 查询待处理视频(sync_status = 0)
+ */
+ List<ArdMediaVideo> selectPendingVideos(@Param("limit") int limit);
+
+ /**
+ * 原子抢占:0 → 1
+ */
+ int markProcessing(@Param("id") Long id);
+
+ /**
+ * 更新同步状态
+ * 0 = 待处理
+ * 1 = 处理中
+ * 2 = 已完成
+ */
+ int updateSyncStatus(@Param("id") Long id, @Param("status") Integer status);
+
+ /**
+ * 根据任务ID查询视频
+ */
+ List<ArdMediaVideo> selectArdMediaVideoByTaskId(@Param("taskId") Integer taskId);
+
+ /**
+ * 新增视频
+ */
+ int insertArdMediaVideo(ArdMediaVideo video);
+
+ /**
+ * 更新视频
+ */
+ int updateArdMediaVideo(ArdMediaVideo video);
+
+ /**
+ * 根据ID删除视频
+ */
+ int deleteArdMediaVideoById(@Param("id") String id);
+
+ /**
+ * 根据任务ID删除视频
+ */
+ int deleteArdMediaVideoByTaskId(@Param("taskId") Integer taskId);
+}
diff --git a/ard-work/src/main/java/com/ard/work/service/IArdDroneInfoService.java b/ard-work/src/main/java/com/ard/work/service/IArdDroneInfoService.java
index 907d94e..5d84897 100644
--- a/ard-work/src/main/java/com/ard/work/service/IArdDroneInfoService.java
+++ b/ard-work/src/main/java/com/ard/work/service/IArdDroneInfoService.java
@@ -77,7 +77,7 @@
* @param deptId 部门ID
* @return 结果
*/
- public int insertArdDroneLs(String[] boxSn,Long deptId);
+ public int insertArdDroneLs(String[] boxSn,Long deptId,String serverId);
/**
* 修改无人机状态
diff --git a/ard-work/src/main/java/com/ard/work/service/IArdMediaService.java b/ard-work/src/main/java/com/ard/work/service/IArdMediaService.java
index 356ed7a..8356b0c 100644
--- a/ard-work/src/main/java/com/ard/work/service/IArdMediaService.java
+++ b/ard-work/src/main/java/com/ard/work/service/IArdMediaService.java
@@ -1,7 +1,8 @@
package com.ard.work.service;
-import com.ard.work.domain.entity.ArdMedia;
-
+import com.ard.work.domain.entity.ArdFlightTask;
+import com.ard.work.domain.entity.ArdMediaPic;
+import com.ard.work.domain.entity.ArdMediaVideo;
import java.util.List;
/**
@@ -10,11 +11,12 @@
* Date: 2025年11月18日13:15
**/
public interface IArdMediaService {
- /**
- * 查询媒体数据列表
- *
- * @param ardMedia 媒体数据
- * @return 媒体数据集合
- */
- public List<ArdMedia> selectArdMediaList(ArdMedia ardMedia);
+
+ List<ArdMediaPic> selectArdMediaPicList(ArdMediaPic ardMediaPic);
+ List<ArdMediaVideo> selectArdMediaVideoList(ArdMediaVideo ardMediaVideo);
+ void insertPhotoToDatabase(ArdFlightTask flightTask, String serverId, String boxSn);
+ void insertVideoToDatabase(ArdFlightTask flightTask, String serverId, String boxSn);
+ void syncPicToDatabase(ArdFlightTask flightTask, String serverId, String boxSn);
+ void syncVideoToDatabase(ArdFlightTask flightTask, String serverId, String boxSn);
+
}
diff --git a/ard-work/src/main/java/com/ard/work/service/IArdServerInfoService.java b/ard-work/src/main/java/com/ard/work/service/IArdServerInfoService.java
index 2e25e77..78b1125 100644
--- a/ard-work/src/main/java/com/ard/work/service/IArdServerInfoService.java
+++ b/ard-work/src/main/java/com/ard/work/service/IArdServerInfoService.java
@@ -28,8 +28,6 @@
*/
public List<ArdServerInfo> selectArdServerInfoList(ArdServerInfo ardServerInfo);
- public List<ArdServerInfo> selectArdServerInfoListNo(ArdServerInfo ardServerInfo);
-
/**
* 新增服务器管理
*
diff --git a/ard-work/src/main/java/com/ard/work/service/ITyService.java b/ard-work/src/main/java/com/ard/work/service/ITyService.java
index 18db889..d21a331 100644
--- a/ard-work/src/main/java/com/ard/work/service/ITyService.java
+++ b/ard-work/src/main/java/com/ard/work/service/ITyService.java
@@ -36,7 +36,7 @@
*
* @return
*/
- AccessTokenReceiver getAccessToken(String ServerId);
+ AccessTokenReceiver getAccessToken(String serverId);
/**
* 获取全部服务器云盒列表
diff --git a/ard-work/src/main/java/com/ard/work/service/impl/ArdDroneInfoServiceImpl.java b/ard-work/src/main/java/com/ard/work/service/impl/ArdDroneInfoServiceImpl.java
index 053cfa6..7064f3f 100644
--- a/ard-work/src/main/java/com/ard/work/service/impl/ArdDroneInfoServiceImpl.java
+++ b/ard-work/src/main/java/com/ard/work/service/impl/ArdDroneInfoServiceImpl.java
@@ -164,7 +164,7 @@
* @return 成功插入的记录数
*/
@Override
- public int insertArdDroneLs(String[] boxSn, Long deptId) {
+ public int insertArdDroneLs(String[] boxSn,Long deptId,String serverId) {
// 参数校验
if (boxSn == null || boxSn.length == 0) {
log.warn("传入的盒子编码为空");
@@ -176,10 +176,12 @@
try {
// 1. 检查已存在的无人机盒子
List<ArdDroneInfo> existingDrones = getExistingDrones(boxSn);
+ // 1.1 新增时不能添加重复的boxSn
+ checkDuplicateBox(existingDrones, boxSn);
// 2. 授权数量验证
validateAuthorization(existingDrones.size(), boxSn.length);
// 3. 获取并组装新的无人机信息
- List<ArdDroneInfo> newDrones = assembleNewDrones(boxSn, deptId);
+ List<ArdDroneInfo> newDrones = assembleNewDrones(boxSn,deptId,serverId);
// 4. 批量插入
return batchInsertDrones(newDrones);
} catch (Exception e) {
@@ -204,6 +206,29 @@
.map(ArdDroneInfoMapper::selectArdDroneByBoxSn)
.filter(Objects::nonNull)
.collect(Collectors.toList());
+ }
+
+ /**
+ * 检查是否有重复的盒子编码
+ */
+ private void checkDuplicateBox(List<ArdDroneInfo> existingDrone,String[] boxSn) {
+ Set<String> existingBoxSnSet = new HashSet<>();
+ for (ArdDroneInfo droneInfo : existingDrone) {
+ existingBoxSnSet.add(droneInfo.getBoxSn());
+ }
+
+ // 检查是否有重复的盒子编码
+ List<String> duplicateBoxSns = new ArrayList<>();
+ for (String sn : boxSn) {
+ if (existingBoxSnSet.contains(sn)) {
+ duplicateBoxSns.add(sn);
+ }
+ }
+
+ if (!duplicateBoxSns.isEmpty()) {
+ log.warn("存在重复的无人机盒子编码: {}", duplicateBoxSns);
+ throw new ServiceException("以下无人机盒子编码已存在: " + String.join(", ", duplicateBoxSns));
+ }
}
/**
@@ -236,19 +261,19 @@
/**
* 组装新的无人机信息
*/
- private List<ArdDroneInfo> assembleNewDrones(String[] boxSn, Long deptId) {
+ private List<ArdDroneInfo> assembleNewDrones(String[] boxSn,Long deptId,String serverId) {
List<BoxInfoReceiver> allBoxes = tyService.getBoxList();
Set<String> targetBoxSnSet = new HashSet<>(Arrays.asList(boxSn));
return allBoxes.stream()
.filter(box -> targetBoxSnSet.contains(box.getBoxSn()))
- .map(box -> createDroneInfo(box, deptId))
+ .map(box -> createDroneInfo(box, deptId, serverId))
.collect(Collectors.toList());
}
/**
* 创建无人机信息对象
*/
- private ArdDroneInfo createDroneInfo(BoxInfoReceiver box, Long deptId) {
+ private ArdDroneInfo createDroneInfo(BoxInfoReceiver box, Long deptId ,String serverId) {
ArdDroneInfo drone = new ArdDroneInfo();
drone.setId(IdUtils.simpleUUID());
drone.setBoxSn(box.getBoxSn());
@@ -259,21 +284,13 @@
drone.setVideoPort(box.getVideoPort());
drone.setLastTaskId(box.getLastTaskId());
drone.setDeptId(deptId);
-
- // 设置创建信息和更新信息
- setCreateAndUpdateInfo(drone);
-
+ drone.setCreateTime(new Date());
+ drone.setUpdateTime(new Date());
+ drone.setServerId(serverId);
+ drone.setBoxVersion(box.getBoxVersion());
return drone;
}
- /**
- * 设置创建和更新信息
- */
- private void setCreateAndUpdateInfo(ArdDroneInfo drone) {
- Date currentTime = new Date();
- drone.setCreateTime(currentTime);
- drone.setUpdateTime(currentTime);
- }
/**
* 批量插入无人机信息
@@ -345,32 +362,5 @@
}
- /**
- * 更新 localBoxInfo 的字段,如果有变化返回 true,否则返回 false
- */
- private boolean updateChangedAttributes(ArdDroneInfo localBoxInfo, BoxInfoReceiver remoteArdDrone) {
- boolean changed = false;
-
- if (!Objects.equals(localBoxInfo.getBoxName(), remoteArdDrone.getBoxName())) {
- localBoxInfo.setBoxName(remoteArdDrone.getBoxName());
- changed = true;
- }
- if (!Objects.equals(localBoxInfo.getBoxVersion(), remoteArdDrone.getBoxVersion())) {
- localBoxInfo.setBoxVersion(remoteArdDrone.getBoxVersion());
- changed = true;
- }
- if (!Objects.equals(localBoxInfo.getLastTaskId(), remoteArdDrone.getLastTaskId())) {
- localBoxInfo.setLastTaskId(remoteArdDrone.getLastTaskId());
- changed = true;
- }
- if (!Objects.equals(localBoxInfo.getOnLine(), remoteArdDrone.getOnLine())) {
- localBoxInfo.setOnLine(remoteArdDrone.getOnLine());
- changed = true;
- }
-
- // TODO: 更新其他属性时,如果变化也设置 changed = true
-
- return changed;
- }
}
diff --git a/ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskPartServiceImpl.java b/ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskPartServiceImpl.java
index 0917724..da66e03 100644
--- a/ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskPartServiceImpl.java
+++ b/ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskPartServiceImpl.java
@@ -1,6 +1,7 @@
package com.ard.work.service.impl;
import cn.hutool.core.util.SerializeUtil;
+import com.ard.common.utils.DateUtils;
import com.ard.work.domain.cache.UavStateCache;
import com.ard.work.domain.cache.UavTelemetryDataCache;
import com.ard.work.domain.dto.UavFlightStateDTO;
@@ -44,22 +45,22 @@
/**
* 定时任务:每秒读取一次设备状态数据
- * 注意:这里模拟读取状态,实际应该调用设备接口或缓存
*/
@Scheduled(fixedRate = 1000)
public void readTelemetryTask() {
long now = System.currentTimeMillis();
UavTelemetryDataCache.forEach((boxSn, telemetryData) -> {
-
// 1️⃣ 从状态缓存里取当前状态
UavState uavState = UavStateCache.get(boxSn);
if (uavState == null) {
+ log.warn("状态不存在,不记录");
return; // 状态不存在,不记录
}
// 2️⃣ 使用遥测自身时间戳判断是否还活着
long dataTs = telemetryData.getTimestamp(); // 设备时间 / 服务器接收时间
if (now - dataTs > 3000) {
+ log.warn("超过 3 秒没有新遥测 → 认为已离线或冻结,不记录:{}", new Date(dataTs));
return; // 超过 3 秒没有新遥测 → 认为已离线或冻结,不记录
}
@@ -71,18 +72,13 @@
flushRemaining(boxSn);
}
lastFlightStatusMap.put(boxSn, currentStatus);
-
+ log.debug("设备 {} 当前状态为:{}", boxSn, currentStatus);
// 只有飞行中才添加缓存
if (currentStatus == 2) {
+ log.warn("设备 {} 当前状态为飞行中,添加遥测数据到缓存", boxSn);
UavFlightStateDTO dto = new UavFlightStateDTO(uavState, telemetryData, dataTs);
addTelemetryData(dto);
}
- UavFlightStateDTO dto = new UavFlightStateDTO(
- uavState,
- telemetryData,
- dataTs
- );
- addTelemetryData(dto);
});
}
diff --git a/ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceImpl.java b/ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceImpl.java
index 4ab7d19..ff1016d 100644
--- a/ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceImpl.java
+++ b/ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceImpl.java
@@ -4,47 +4,23 @@
import com.ard.common.core.domain.entity.SysUser;
import com.ard.common.core.redis.RedisCache;
import com.ard.common.utils.DateUtils;
-import com.ard.common.utils.file.MimeTypeUtils;
-import com.ard.common.utils.uuid.IdUtils;
-import com.ard.oss.service.impl.OssServiceContext;
import com.ard.work.component.forest.TyClient;
import com.ard.work.domain.dto.BoxHistoryDTO;
-import com.ard.work.domain.dto.BoxPhotosDTO;
import com.ard.work.domain.entity.ArdFlightTask;
-import com.ard.work.domain.entity.ArdMedia;
import com.ard.work.domain.receiver.BoxHistoryReceiver;
-import com.ard.work.domain.receiver.BoxPhotosReceiver;
import com.ard.work.domain.receiver.TyHttpCommonReceiver;
import com.ard.work.mapper.ArdFlightTaskMapper;
-import com.ard.work.mapper.ArdMediaMapper;
import com.ard.work.service.IArdFlightTaskService;
+import com.ard.work.service.IArdMediaService;
import com.ard.work.service.IArdServerInfoService;
import com.ard.work.service.control.UavControlService;
-import com.ard.work.util.osSelect;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.net.URLConnection;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
import java.util.Date;
import java.util.List;
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Collectors;
@Slf4j
@Service
@@ -53,19 +29,16 @@
@Resource
private ArdFlightTaskMapper ardFlightTaskMapper;
@Resource
- private ArdMediaMapper ardMediaMapper;
- @Resource
private IArdServerInfoService ardServerInfoService;
@Resource
- private TyClient tyClient;
- @Resource
- private OssServiceContext ossServiceContext;
- @Resource
- private ThreadPoolTaskExecutor threadPoolTaskExecutor; // 使用线程池执行异步任务
- @Resource
private UavControlService uavControlService;
- @Autowired
+ @Resource
+ private IArdMediaService ardMediaService;
+ @Resource
private RedisCache redisCache;
+ @Resource
+ private TyClient tyClient;
+
/**
* 查询飞行架次列表
*
@@ -80,7 +53,7 @@
/**
* 同步所有服务的飞行历史
*/
- @Scheduled(fixedDelay = 10000)
+ @Scheduled(fixedDelay = 5000)
public void syncAllFlightHistory() {
List<String> serverIds = ardServerInfoService.getServerIdsList();
for (String serverId : serverIds) {
@@ -97,10 +70,18 @@
return maxStartTime != null ? maxStartTime : new Date(0); // 如果没有数据,返回 Unix 纪元时间作为起点
}
+ // 调用接口获取飞行历史数据
+ private List<BoxHistoryReceiver> getBoxHistory(String serverId, BoxHistoryDTO boxHistoryDTO) {
+ TyHttpCommonReceiver<List<BoxHistoryReceiver>> boxHistory = tyClient.getBoxHistory(serverId, boxHistoryDTO);
+ return boxHistory.getContent();
+ }
+
// 根据上次同步时间同步飞行历史
public void syncFlightHistory(String serverId, Date startTime) {
// 创建查询条件 BoxHistoryDTO,并设置 startTime 作为过滤条件
BoxHistoryDTO boxHistoryDTO = BoxHistoryDTO.builder()
+ .pageIndex(1)
+ .pageSize(20)
.startTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, startTime))
.build();
@@ -121,7 +102,11 @@
ArdFlightTask ardFlightTask = ardFlightTaskMapper.getArdFlightTaskById(boxHistoryReceiver.getTaskId());
if (ardFlightTask == null) {
// 如果不存在,则插入新记录
- log.debug("insert task {}", boxHistoryReceiver.getTaskId());
+ log.info("insert task {}", boxHistoryReceiver.getTaskId());
+ Date endTime = null;
+ if (boxHistoryReceiver.getEndTime() != null) {
+ endTime = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, boxHistoryReceiver.getEndTime());
+ }
// 创建FlightTask实体对象并填充数据
ArdFlightTask flightTask = ArdFlightTask.builder()
.taskId(boxHistoryReceiver.getTaskId())
@@ -134,7 +119,7 @@
.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()))
+ .endTime(endTime)
.flightMileage(boxHistoryReceiver.getFlightMileage())
.flightDuration(boxHistoryReceiver.getFlightDuration())
.aveSpeed(boxHistoryReceiver.getAveSpeed())
@@ -152,35 +137,37 @@
// 插入新记录
int rows = ardFlightTaskMapper.insertArdFlightTask(flightTask);
if (rows > 0) {
- // 删除旧的媒体记录,防止重复插入
- ardMediaMapper.deleteArdMediaByTaskId(flightTask.getTaskId());
-
// 插入视频
- insertVideoToDatabase(flightTask, boxHistoryReceiver.getVideoPathList());
-
+ ardMediaService.insertVideoToDatabase(flightTask, serverId, boxHistoryReceiver.getBoxSn());
// 插入图片
- insertPhotoToDatabase(flightTask, serverId, boxHistoryReceiver.getBoxSn());
+ ardMediaService.insertPhotoToDatabase(flightTask, serverId, boxHistoryReceiver.getBoxSn());
}
} else {
// 如果存在,则更新记录
- log.debug("Updating task {}", boxHistoryReceiver.getTaskId());
+ log.debug("sync task {}", boxHistoryReceiver.getTaskId());
updateFlightTask(ardFlightTask, boxHistoryReceiver);
- // 增量更新
- updateVideoToDatabase(ardFlightTask, boxHistoryReceiver.getVideoPathList());
- // 增量更新图片
- updatePhotoToDatabase(ardFlightTask, serverId, boxHistoryReceiver.getBoxSn());
-
+ // 同步任务图片
+ ardMediaService.syncPicToDatabase(ardFlightTask, serverId, boxHistoryReceiver.getBoxSn());
+ // 同步任务视频
+ ardMediaService.syncVideoToDatabase(ardFlightTask, serverId, boxHistoryReceiver.getBoxSn());
}
}
+
private void updateFlightTask(ArdFlightTask local, BoxHistoryReceiver remote) {
boolean needUpdate = false;
// endTime 更新(重要!!!)
- Date newEnd = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, remote.getEndTime());
- if (newEnd != null && (local.getEndTime() == null || !local.getEndTime().equals(newEnd))) {
- local.setEndTime(newEnd);
- needUpdate = true;
+ if (remote.getEndTime() != null) {
+ Date newEnd = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, remote.getEndTime());
+ if (local.getEndTime() == null || !local.getEndTime().equals(newEnd)) {
+ local.setEndTime(newEnd);
+ local.setAveSpeed(remote.getAveSpeed());
+ local.setMaxSpeed(remote.getMaxSpeed());
+ local.setFlightDuration(remote.getFlightDuration());
+ local.setFlightMileage(remote.getFlightMileage());
+ needUpdate = true;
+ }
}
// photoCount 更新
@@ -199,386 +186,6 @@
if (needUpdate) {
ardFlightTaskMapper.updateArdFlightTask(local);
- }
- }
-
-
- // 调用接口获取飞行历史数据
- private List<BoxHistoryReceiver> getBoxHistory(String serverId, BoxHistoryDTO boxHistoryDTO) {
- TyHttpCommonReceiver<List<BoxHistoryReceiver>> boxHistory = tyClient.getBoxHistory(serverId, boxHistoryDTO);
- return boxHistory.getContent();
- }
-
- //调用接口获取架次图片
- private List<BoxPhotosReceiver> getBoxPhotos(String serverId, BoxPhotosDTO boxPhotosDTO) {
- TyHttpCommonReceiver<List<BoxPhotosReceiver>> boxPhotos = tyClient.getBoxPhotos(serverId, boxPhotosDTO);
- return boxPhotos.getContent();
- }
-
-
- // 插入视频记录
- private void insertVideoToDatabase(ArdFlightTask flightTask, List<String> videoPathList) {
- if (videoPathList == null || videoPathList.isEmpty()) {
- return;
- }
- String boxSn = flightTask.getBoxSn();
- for (String videoPath : videoPathList) {
- //videoPath = "https://192.168.1.3:9001/record/DBM250974065008/8212fd8e89814d66b6c32f48d05f5101.mp4";
- ArdMedia media = ArdMedia.builder()
- .id(IdUtils.simpleUUID())
- .taskId(flightTask.getTaskId())
- .mediaType(1)
- .sourceUrl(videoPath)
- .fileSize(getFileSizeByUrl(videoPath))
- .build();
-
- // ---- 1. 视频上传(失败不抛异常,返回 null) ----
-
- CompletableFuture<String> videoFuture = CompletableFuture.supplyAsync(() -> {
- try (InputStream inputStream = openUrlInputStream(videoPath, 5000, 10000)) {
- if (inputStream != null) {
- return ossServiceContext.upload(
- "record",
- boxSn + "/" + media.getId() + ".mp4",
- inputStream,
- MimeTypeUtils.VIDEO_MP4
- );
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }, threadPoolTaskExecutor);
- // ---- 2. 缩略图上传(失败不抛异常,返回 null) ----
-
- CompletableFuture<String> thumbFuture = CompletableFuture.supplyAsync(() -> {
- try {
- try (ByteArrayInputStream thumbStream = generateThumbnail(videoPath, 1, 200)) {
- if (thumbStream != null) {
- return ossServiceContext.upload(
- "record",
- boxSn + "/" + media.getId() + ".jpg",
- thumbStream,
- MimeTypeUtils.IMAGE_JPEG
- );
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }, threadPoolTaskExecutor);
-
- // 两个完成后写数据库(任意失败不阻断流程)
- videoFuture.thenCombine(thumbFuture, (vUrl, tUrl) -> {
- media.setMediaUrl(vUrl);
- media.setThumbnailUrl(tUrl);
- media.setCreateTime(new Date());
- return media;
- }).thenAcceptAsync(ardMediaMapper::insertArdMedia, threadPoolTaskExecutor);
- }
- }
-
- private void updateVideoToDatabase(ArdFlightTask flightTask, List<String> videoPathList) {
- if (videoPathList == null) {
- return;
- }
- // 需要插入新的视频
- List<ArdMedia> existingVideos = ardMediaMapper.selectArdMediaByTaskIdAndType(flightTask.getTaskId(), 1);
- Integer count = existingVideos.size();//获取本地库视频数量
- int size = videoPathList.size();//获取接口返回的视频数量
- if (count != null && size > count) {
- log.info("任务【{}】录像数量不一致,需要更新数据库", flightTask.getTaskId());
-
- // 提取现有的视频路径
- List<String> existingVideoPaths = existingVideos.stream()
- .map(ArdMedia::getSourceUrl) // 获取每个视频的 URL
- .collect(Collectors.toList());
-
- // 从接口返回的视频路径中找出新的视频
- List<String> newVideos = videoPathList.stream()
- .filter(videoPath -> !existingVideoPaths.contains(videoPath)) // 过滤出新的视频
- .collect(Collectors.toList());
- if (!newVideos.isEmpty()) {
- String boxSn = flightTask.getBoxSn();
- // 插入新的视频记录
- for (String videoPath : newVideos) {
- ArdMedia ardMedia = ArdMedia.builder()
- .id(IdUtils.simpleUUID())
- .taskId(flightTask.getTaskId())
- .mediaType(1) // 1表示视频
- .fileSize(getFileSizeByUrl(videoPath))
- .sourceUrl(videoPath)
- .build();
- // ---- 1. 视频上传(失败不抛异常,返回 null) ----
- CompletableFuture<String> videoFuture = CompletableFuture.supplyAsync(() -> {
- try (InputStream inputStream = openUrlInputStream(videoPath, 5000, 10000)) {
- if (inputStream != null) {
- return ossServiceContext.upload(
- "record",
- boxSn + "/" + ardMedia.getId() + ".mp4",
- inputStream,
- MimeTypeUtils.VIDEO_MP4
- );
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }, threadPoolTaskExecutor);
- // ---- 2. 缩略图上传(失败不抛异常,返回 null) ----
- CompletableFuture<String> thumbFuture = CompletableFuture.supplyAsync(() -> {
- try {
- try (ByteArrayInputStream thumbStream = generateThumbnail(videoPath, 1, 200)) {
- if (thumbStream != null) {
- return ossServiceContext.upload(
- "record",
- boxSn + "/" + ardMedia.getId() + ".jpg",
- thumbStream,
- MimeTypeUtils.IMAGE_JPEG
- );
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }, threadPoolTaskExecutor);
- // 两个完成后写数据库(任意失败不阻断流程)
- videoFuture.thenCombine(thumbFuture, (vUrl, tUrl) -> {
- ardMedia.setMediaUrl(vUrl);
- ardMedia.setThumbnailUrl(tUrl);
- ardMedia.setCreateTime(new Date());
- return ardMedia;
- }).thenAcceptAsync(ardMediaMapper::insertArdMedia, threadPoolTaskExecutor);
- }
- // 更新任务的视频数量
- flightTask.setVideoCount(flightTask.getVideoCount() + newVideos.size());
- ardFlightTaskMapper.updateArdFlightTask(flightTask);
- }
- }
- }
-
- // 插入图片记录
- 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(500);
- List<BoxPhotosReceiver> photoList = getBoxPhotos(serverId, boxPhotosDTO);
- if (photoList != null && !photoList.isEmpty()) {
- addPhotos(flightTask, photoList);
- }
- }
-
- private void updatePhotoToDatabase(ArdFlightTask flightTask, String serverId, String boxSn) {
-
- // 获取本地数据库中已存在的图片记录(类型为 0 表示图片)
- List<ArdMedia> existingPhotos = ardMediaMapper.selectArdMediaByTaskIdAndType(flightTask.getTaskId(), 0);
- int count = existingPhotos.size(); //获取本地库图片数量
- // 查询图片
- 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 (size > count) {
- log.info("任务【{}】图片数量不一致,需要更新数据库", flightTask.getTaskId());
- // 需要插入新的视频
- // 提取现有的图片路径(根据 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) {
- String boxSn = flightTask.getBoxSn();
- 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(() -> {
- try (InputStream inputStream = openUrlInputStream(photo.getImgUrl(), 5000, 10000)) {
- if (inputStream != null) {
- return ossServiceContext.upload(
- "pic",
- boxSn + "/" + ardMedia.getId() + ".jpg",
- inputStream,
- MimeTypeUtils.IMAGE_JPG
- );
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }, threadPoolTaskExecutor)
- .thenAccept(url -> {
- ardMedia.setMediaUrl(url);
- ardMedia.setCreateTime(new Date());
- ardMediaMapper.insertArdMedia(ardMedia);
- });
- }
- }
-
- // 获取文件大小
- 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 generateThumbnail(
- String videoFile,
- int skipSeconds,
- int targetWidth) {
- String ffmpegPath = "";
- if (osSelect.isWindows()) {
- ffmpegPath = "ffmpeg";
- } else if (osSelect.isLinux()) {
- ffmpegPath = "/usr/local/ffmpeg/bin/ffmpeg";
- }
- try {
- List<String> command = new ArrayList<>();
- command.add(ffmpegPath);
-
- command.add("-timeout");
- command.add("3000000");
- command.add("-rw_timeout");
- command.add("3000000");
-
- command.add("-ss");
- command.add(String.format("00:00:%02d", skipSeconds));
- command.add("-i");
- command.add(videoFile);
- command.add("-vframes");
- command.add("1");
-
- // 等比缩放
- command.add("-vf");
- command.add("scale=" + targetWidth + ":-1");
-
- // **确保输出 JPEG**
- command.add("-f");
- command.add("mjpeg"); // 关键点:输出格式固定为 JPEG
- command.add("-vcodec");
- command.add("mjpeg");
-
- // 输出到管道
- command.add("pipe:1");
-
- // ⭐ 打印最终命令(可复制)
- log.info("ffmpeg command: {}", String.join(" ", command));
-
- ProcessBuilder pb = new ProcessBuilder(command);
- pb.redirectErrorStream(false);
- Process process = pb.start();
-
- // 读取 FFmpeg 输出(JPEG 数据)到内存
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try (InputStream is = process.getInputStream()) {
- byte[] buffer = new byte[8192];
- int len;
- while ((len = is.read(buffer)) != -1) {
- baos.write(buffer, 0, len);
- }
- }
-
- int exitCode = process.waitFor();
- if (exitCode != 0) {
- throw new RuntimeException("FFmpeg 执行失败,退出码: " + exitCode);
- }
-
- return new ByteArrayInputStream(baos.toByteArray());
-
- } catch (IOException | InterruptedException e) {
- throw new RuntimeException("FFmpeg 生成缩略图失败", e);
- }
- }
-
- /**
- * 将 URL 转成 InputStream
- *
- * @param fileUrl 文件 URL
- * @param connectTimeoutMillis 连接超时(毫秒)
- * @param readTimeoutMillis 读取超时(毫秒)
- * @return InputStream,如果失败返回 null
- */
- public InputStream openUrlInputStream(String fileUrl, int connectTimeoutMillis, int readTimeoutMillis) {
- try {
- URL url = new URL(fileUrl);
-
- // 支持 HTTPS 信任所有证书(如果需要访问自签名证书)
- if ("https".equalsIgnoreCase(url.getProtocol())) {
- TrustManager[] trustAllCerts = new TrustManager[]{
- new X509TrustManager() {
- @Override
- public void checkClientTrusted(X509Certificate[] chain, String authType) {
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] chain, String authType) {
- }
-
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return null;
- }
- }
- };
- SSLContext sc = SSLContext.getInstance("SSL");
- sc.init(null, trustAllCerts, new java.security.SecureRandom());
- HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
- HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
- }
-
- URLConnection connection = url.openConnection();
- connection.setConnectTimeout(connectTimeoutMillis);
- connection.setReadTimeout(readTimeoutMillis);
-
- return connection.getInputStream();
-
- } catch (Exception e) {
- e.printStackTrace();
- return null;
}
}
diff --git a/ard-work/src/main/java/com/ard/work/service/impl/ArdMediaServiceImpl.java b/ard-work/src/main/java/com/ard/work/service/impl/ArdMediaServiceImpl.java
index 2fe5482..8b84da8 100644
--- a/ard-work/src/main/java/com/ard/work/service/impl/ArdMediaServiceImpl.java
+++ b/ard-work/src/main/java/com/ard/work/service/impl/ArdMediaServiceImpl.java
@@ -1,31 +1,280 @@
package com.ard.work.service.impl;
-import com.ard.work.domain.entity.ArdMedia;
-import com.ard.work.mapper.ArdMediaMapper;
+import com.ard.common.utils.DateUtils;
+import com.ard.common.utils.StringUtils;
+import com.ard.common.utils.file.MimeTypeUtils;
+import com.ard.oss.service.impl.OssServiceContext;
+import com.ard.work.component.forest.TyClient;
+import com.ard.work.domain.dto.BoxPhotosDTO;
+import com.ard.work.domain.dto.BoxVideosDTO;
+import com.ard.work.domain.entity.ArdFlightTask;
+import com.ard.work.domain.entity.ArdMediaPic;
+import com.ard.work.domain.entity.ArdMediaVideo;
+import com.ard.work.domain.receiver.BoxPhotosReceiver;
+import com.ard.work.domain.receiver.BoxVideosReceiver;
+import com.ard.work.domain.receiver.TyHttpCommonReceiver;
+import com.ard.work.mapper.ArdFlightTaskMapper;
+import com.ard.work.mapper.ArdMediaPicMapper;
+import com.ard.work.mapper.ArdMediaVideoMapper;
import com.ard.work.service.IArdMediaService;
+import com.ard.work.util.osSelect;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
-import java.util.List;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.cert.X509Certificate;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
/**
* Description:
* Author: lsy
* Date: 2025年11月18日13:17
**/
+@Slf4j
@Service
public class ArdMediaServiceImpl implements IArdMediaService {
- @Resource
- private ArdMediaMapper ardMediaMapper;
- /**
- * 查询媒体数据列表
- *
- * @param ardMedia 媒体数据
- * @return 媒体数据集合
- */
+ @Resource
+ private TyClient tyClient;
+ @Resource
+ private ArdMediaPicMapper ardMediaPicMapper;
+ @Resource
+ private ArdMediaVideoMapper ardMediaVideoMapper;
+
+ @Resource
+ private ArdFlightTaskMapper ardFlightTaskMapper;
+
+
+ // 调用接口获取架次图片
+ private List<BoxPhotosReceiver> getBoxPhotos(String serverId, BoxPhotosDTO boxPhotosDTO) {
+ TyHttpCommonReceiver<List<BoxPhotosReceiver>> boxPhotos = tyClient.getBoxPhotos(serverId, boxPhotosDTO);
+ return boxPhotos.getContent();
+ }
+
+ // 调用接口获取架次视频
+ private List<BoxVideosReceiver> getBoxVideos(String serverId, BoxVideosDTO boxVideosDTO) {
+ TyHttpCommonReceiver<List<BoxVideosReceiver>> boxVideos = tyClient.getBoxVideos(serverId, boxVideosDTO);
+ return boxVideos.getContent();
+ }
+
@Override
- public List<ArdMedia> selectArdMediaList(ArdMedia ardMedia) {
- return ardMediaMapper.selectArdMedia(ardMedia);
+ public List<ArdMediaPic> selectArdMediaPicList(ArdMediaPic ardMediaPic) {
+ return ardMediaPicMapper.selectPicList(ardMediaPic);
+ }
+
+ @Override
+ public List<ArdMediaVideo> selectArdMediaVideoList(ArdMediaVideo ardMediaVideo) {
+ return ardMediaVideoMapper.selectArdMediaVideoList(ardMediaVideo);
+ }
+
+ @Override
+ public void insertPhotoToDatabase(ArdFlightTask flightTask, String serverId, String boxSn) {
+ log.warn("开始获取图片信息");
+ // 查询图片
+ BoxPhotosDTO boxPhotosDTO = new BoxPhotosDTO();
+ boxPhotosDTO.setTaskId(flightTask.getTaskId());
+ boxPhotosDTO.setBoxSn(boxSn);
+ boxPhotosDTO.setPageIndex(1);
+ boxPhotosDTO.setPageSize(100);
+ List<BoxPhotosReceiver> photoList = getBoxPhotos(serverId, boxPhotosDTO);
+ if (photoList != null && !photoList.isEmpty()) {
+ addPhotos(flightTask, photoList);
+ }
+ }
+
+ @Override
+ public void insertVideoToDatabase(ArdFlightTask flightTask, String serverId, String boxSn) {
+ log.warn("开始获取视频信息");
+ BoxVideosDTO boxVideosDTO = new BoxVideosDTO();
+ boxVideosDTO.setTaskId(flightTask.getTaskId());
+ boxVideosDTO.setBoxSn(boxSn);
+ boxVideosDTO.setPageIndex(1);
+ boxVideosDTO.setPageSize(100);
+ List<BoxVideosReceiver> videoList = getBoxVideos(serverId, boxVideosDTO);
+ if (videoList != null && !videoList.isEmpty()) {
+ addVideos(flightTask, videoList);
+ }
+ }
+
+ @Override
+ public void syncPicToDatabase(ArdFlightTask flightTask, String serverId, String boxSn) {
+
+ // 1️⃣ 查第三方图片列表
+ BoxPhotosDTO dto = BoxPhotosDTO.builder()
+ .taskId(flightTask.getTaskId())
+ .boxSn(boxSn)
+ .pageIndex(1)
+ .pageSize(100)
+ .build();
+
+ TyHttpCommonReceiver<List<BoxPhotosReceiver>> resp = tyClient.getBoxPhotos(serverId, dto);
+
+ List<BoxPhotosReceiver> photoList = resp.getContent();
+ if (photoList == null || photoList.isEmpty()) {
+ return;
+ }
+
+ // 2️⃣ 本地图片转 Map(用“业务唯一键”)
+ List<ArdMediaPic> existingList = ardMediaPicMapper.selectPicByTaskId(flightTask.getTaskId());
+
+ Map<Long, ArdMediaPic> localPicMap = existingList.stream()
+ .filter(p -> p.getId() != null)
+ .collect(Collectors.toMap(
+ ArdMediaPic::getId, // ✅ 远端 photoId
+ p -> p,
+ (a, b) -> a
+ ));
+
+
+ // 3️⃣ 逐条处理(新增 or 补全)
+ for (BoxPhotosReceiver remote : photoList) {
+
+ String imgUrl = remote.getImgUrl();
+ if (StringUtils.isBlank(imgUrl)) {
+ continue; // 第三方字段还没准备好
+ }
+ ArdMediaPic local = localPicMap.get(remote.getPhotoId());
+ if (local == null) {
+ // ✅ 新图片 → 插入
+ addPhotos(flightTask, List.of(remote));
+ continue;
+ }
+
+ // ✅ 已存在 → 补字段
+ boolean needUpdate = false;
+
+ if (local.getCaptureTime() == null && remote.getTimeStamp() != null) {
+ local.setCaptureTime(DateUtils.parseDate(remote.getTimeStamp()));
+ needUpdate = true;
+ }
+ if (local.getFileSize() == 0 && remote.getFileSize() != 0) {
+ local.setFileSize(remote.getFileSize());
+ needUpdate = true;
+ }
+ if ("0".equals(local.getFileMd5())&& !"0".equals(remote.getFileMd5())) {
+ local.setFileMd5(remote.getFileMd5());
+ needUpdate = true;
+ }
+ if (needUpdate) {
+ local.setUpdateTime(new Date());
+ ardMediaPicMapper.updatePic(local);
+ }
+ }
+ }
+
+ @Override
+ public void syncVideoToDatabase(ArdFlightTask flightTask, String serverId, String boxSn) {
+
+ // 1️⃣ 拉取远端视频列表
+ BoxVideosDTO dto = BoxVideosDTO.builder()
+ .taskId(flightTask.getTaskId())
+ .boxSn(boxSn)
+ .pageIndex(1)
+ .pageSize(100)
+ .build();
+ TyHttpCommonReceiver<List<BoxVideosReceiver>> resp = tyClient.getBoxVideos(serverId, dto);
+ List<BoxVideosReceiver> videoList = resp.getContent();
+ if (videoList == null || videoList.isEmpty()) {
+ return;
+ }
+
+ // 2️⃣ 本地视频转 Map(videoId 为唯一键)
+ List<ArdMediaVideo> existingVideos = ardMediaVideoMapper.selectArdMediaVideoByTaskId(flightTask.getTaskId());
+ Map<Long, ArdMediaVideo> localVideoMap = existingVideos.stream()
+ .filter(v -> v.getId() != null)
+ .collect(Collectors.toMap(
+ ArdMediaVideo::getId, // 远端 videoId
+ v -> v,
+ (a, b) -> a
+ ));
+
+ // 3️⃣ 遍历远端视频,逐条处理
+ for (BoxVideosReceiver remote : videoList) {
+
+ ArdMediaVideo local = localVideoMap.get(remote.getId());
+ if (local == null) {
+ // 新视频 → 立即插入
+ addVideos(flightTask, List.of(remote));
+ localVideoMap.put(remote.getId(), new ArdMediaVideo()); // 占位
+ flightTask.setVideoCount(flightTask.getVideoCount() + 1);
+ ardFlightTaskMapper.updateArdFlightTask(flightTask);
+ continue;
+ }
+
+ // 已存在 → 补字段
+ boolean needUpdate = false;
+ if (local.getName() == null && remote.getName() != null) {
+ local.setName(remote.getName());
+ needUpdate = true;
+ }
+ if (local.getStartTime() == null && remote.getStartTime() != null) {
+ local.setStartTime(DateUtils.parseDate(remote.getStartTime()));
+ needUpdate = true;
+ }
+ if (local.getEndTime() == null && remote.getEndTime() != null) {
+ local.setEndTime(DateUtils.parseDate(remote.getEndTime()));
+ needUpdate = true;
+ }
+ if (local.getSpanSeconds() == null && remote.getSpanSeconds() != null) {
+ local.setSpanSeconds(Integer.parseInt(remote.getSpanSeconds()));
+ needUpdate = true;
+ }
+ if (needUpdate) {
+ local.setUpdateTime(new Date());
+ ardMediaVideoMapper.updateArdMediaVideo(local);
+ }
+ }
+ }
+
+ private void addPhotos(ArdFlightTask flightTask, List<BoxPhotosReceiver> photoList) {
+ log.warn("开始添加图片");
+ for (BoxPhotosReceiver photo : photoList) {
+ ArdMediaPic ardMedia = ArdMediaPic.builder()
+ .id(photo.getPhotoId())
+ .taskId(flightTask.getTaskId())
+ .fileSize(photo.getFileSize())
+ .fileMd5(photo.getFileMd5())
+ .sourceUrl(photo.getImgUrl())
+ .longitude(photo.getLng())
+ .latitude(photo.getLat())
+ .height(photo.getHeight())
+ .captureTime(DateUtils.parseDate(photo.getTimeStamp()))
+ .build();
+ ardMedia.setCreateTime(new Date());
+ ardMediaPicMapper.insertPic(ardMedia);
+ }
+ }
+
+ private void addVideos(ArdFlightTask flightTask, List<BoxVideosReceiver> videoList) {
+ for (BoxVideosReceiver video : videoList) {
+ ArdMediaVideo ardMedia = ArdMediaVideo.builder()
+ .id(video.getId())
+ .name(video.getName())
+ .taskId(flightTask.getTaskId())
+// .fileSize(getFileSizeByUrl(video.getImgUrl()))
+ .sourceUrl(video.getImgUrl())
+ .startTime(DateUtils.parseDate(video.getStartTime()))
+ .endTime(DateUtils.parseDate(video.getEndTime()))
+ .spanSeconds(Integer.parseInt(video.getSpanSeconds()))
+ .build();
+ ardMedia.setCreateTime(new Date());
+ ardMediaVideoMapper.insertArdMediaVideo(ardMedia);
+ }
}
}
diff --git a/ard-work/src/main/java/com/ard/work/service/impl/ArdServerInfoServiceImpl.java b/ard-work/src/main/java/com/ard/work/service/impl/ArdServerInfoServiceImpl.java
index ad2e534..025eee6 100644
--- a/ard-work/src/main/java/com/ard/work/service/impl/ArdServerInfoServiceImpl.java
+++ b/ard-work/src/main/java/com/ard/work/service/impl/ArdServerInfoServiceImpl.java
@@ -5,14 +5,11 @@
import com.ard.work.component.forest.TyClient;
import com.ard.work.component.netty.TyTcpClientManager;
import com.ard.work.domain.dto.TokenDTO;
-import com.ard.work.domain.entity.ArdDroneInfo;
import com.ard.work.domain.entity.ArdServerInfo;
import com.ard.work.domain.receiver.AccessTokenReceiver;
import com.ard.work.domain.receiver.TyHttpCommonReceiver;
-import com.ard.work.mapper.ArdDroneInfoMapper;
import com.ard.work.mapper.ArdServerInfoMapper;
import com.ard.work.service.IArdServerInfoService;
-import com.dtflys.forest.exceptions.ForestRuntimeException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
@@ -40,9 +37,6 @@
@Resource
private TyTcpClientManager tyTcpClientManager;
- @Resource
- private ArdDroneInfoMapper ArdDroneInfoMapper;
-
/**
* 查询服务器管理
*
@@ -63,24 +57,6 @@
@Override
@DataScope(deptAlias = "d", userAlias = "u")
public List<ArdServerInfo> selectArdServerInfoList(ArdServerInfo ardServerInfo) {
- return ardServerInfoMapper.selectArdServerInfoList(ardServerInfo);
- }
-
- @Override
- @DataScope(deptAlias = "d", userAlias = "u")
- public List<ArdServerInfo> selectArdServerInfoListNo(ArdServerInfo ardServerInfo) {
-
-// List<ArdDroneInfo> ardDroneInfos = ArdDroneInfoMapper.selectArdDroneList(new ArdDroneInfo());
-// for (ArdDroneInfo ardDroneInfo : ardDroneInfos) {
-// ardDroneInfo.getBoxSn();
-// }
-// List<ArdServerInfo> servers = ardServerInfoMapper.selectArdServerInfoList(ardServerInfo);
-// for (ArdServerInfo server : servers) {
-// for (ArdDroneInfo ardDroneInfo : server.getArdDroneInfoList()) {
-// ardDroneInfo.getBoxSn();
-// }
-// }
-
return ardServerInfoMapper.selectArdServerInfoList(ardServerInfo);
}
diff --git a/ard-work/src/main/java/com/ard/work/service/impl/TyServiceImpl.java b/ard-work/src/main/java/com/ard/work/service/impl/TyServiceImpl.java
index c6a0d66..ed5d4bb 100644
--- a/ard-work/src/main/java/com/ard/work/service/impl/TyServiceImpl.java
+++ b/ard-work/src/main/java/com/ard/work/service/impl/TyServiceImpl.java
@@ -606,6 +606,10 @@
if (ardDroneInfo == null) {
throw new ControlException("未找到对应的飞行器信息,boxSn:{}" + boxSn);
}
+ //打点之前先停止打点
+ FlyPointControlCancelCmd flyPointControlCancelCmd = new FlyPointControlCancelCmd(FlyPointControlCancelDTO.builder().boxSn(boxSn).build());
+ this.sendMessage(ardDroneInfo.getServerId(), flyPointControlCancelCmd);
+
FlyPointControlCmd flyPointControlCmd = new FlyPointControlCmd(flyPointControlDTO);
this.sendMessage(ardDroneInfo.getServerId(), flyPointControlCmd);
return true;
@@ -974,7 +978,6 @@
// 处理无人机遥测消息
UavTelemetryDataCmd uavTelemetryDataCmd = (UavTelemetryDataCmd) tyCommand;
TelemetryData telemetryData = uavTelemetryDataCmd.getTelemetryData();
- telemetryData.setTimestamp(System.currentTimeMillis());//由于六合提供的状态时间戳不准,先以接收状态作为时间戳
UavTelemetryDataCache.put(telemetryData);
//logPrint("无人机遥测", uavTelemetryDataCmd.getTelemetryData().getBoxSn());
//WebSocketUtil.sendMessageAll(uavTelemetryDataCmd.getTelemetryData());
diff --git a/ard-work/src/main/resources/mapper/ArdFlightTaskMapper.xml b/ard-work/src/main/resources/mapper/ArdFlightTaskMapper.xml
index a231ccf..906d113 100644
--- a/ard-work/src/main/resources/mapper/ArdFlightTaskMapper.xml
+++ b/ard-work/src/main/resources/mapper/ArdFlightTaskMapper.xml
@@ -146,13 +146,13 @@
WHERE task_id = #{taskId}
</select>
-
<!-- 获取某个时间戳后的任务 -->
<select id="getTasksAfter" resultType="ArdFlightTask">
SELECT *
FROM ard_flight_task
WHERE end_time > #{lastSyncTime}
</select>
+
<select id="findMaxStartTimeByServerId" resultType="java.util.Date">
SELECT MAX(start_time)
FROM ard_flight_task
diff --git a/ard-work/src/main/resources/mapper/ArdMediaMapper.xml b/ard-work/src/main/resources/mapper/ArdMediaMapper.xml
deleted file mode 100644
index 2548d11..0000000
--- a/ard-work/src/main/resources/mapper/ArdMediaMapper.xml
+++ /dev/null
@@ -1,202 +0,0 @@
-<?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.work.mapper.ArdMediaMapper">
-
- <!-- 结果映射 -->
- <resultMap id="ArdMediaResult" type="ArdMedia">
- <result property="id" column="id"/>
- <result property="taskId" column="task_id"/>
- <result property="mediaType" column="media_type"/>
- <result property="fileSize" column="file_size"/>
- <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,thumbnail_url,
- photo_id, longitude, latitude, height, capture_time, create_time
- FROM ard_media
- <where>
- <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>
- <if test="fileMd5 != null">AND file_md5 = #{fileMd5}</if>
- <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
- CASE
- WHEN media_type = 0 THEN capture_time
- ELSE create_time
- END DESC
- </select>
-
-
- <!-- 根据任务ID查询媒体 -->
- <select id="selectArdMediaByTaskId" 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}
- </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
- <trim prefix="(" suffix=")" suffixOverrides=",">
- <if test="id != null">id,</if>
- <if test="taskId != null">task_id,</if>
- <if test="mediaType != null">media_type,</if>
- <if test="fileSize != null">file_size,</if>
- <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>
- <if test="mediaType != null">#{mediaType},</if>
- <if test="fileSize != null">#{fileSize},</if>
- <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(
- 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>
-
-
- <!-- 更新媒体记录 -->
- <update id="updateArdMedia" parameterType="com.ard.work.domain.entity.ArdMedia">
- UPDATE ard_media
- <set>
- <if test="mediaType != null">media_type = #{mediaType},</if>
- <if test="fileSize != null">file_size = #{fileSize},</if>
- <if test="fileMd5 != null">file_md5 = #{fileMd5},</if>
- <if test="mediaUrl != null">media_url = #{mediaUrl},</if>
- <if test="createTime != null">create_time = #{createTime},</if>
- </set>
- WHERE id = #{id}
- </update>
-
- <!-- 删除媒体记录 -->
- <delete id="deleteArdMediaById" parameterType="Integer">
- DELETE
- FROM ard_media
- WHERE id = #{id}
- </delete>
-
- <!-- 批量删除媒体记录 -->
- <delete id="deleteArdMediaByIds" parameterType="java.util.List">
- DELETE FROM ard_media WHERE id IN
- <foreach item="id" collection="list" open="(" separator="," close=")">
- #{id}
- </foreach>
- </delete>
-
- <delete id="deleteArdMediaByTaskId" parameterType="java.lang.Integer">
- DELETE
- FROM ard_media
- WHERE task_id = #{taskId}
- </delete>
-
-</mapper>
diff --git a/ard-work/src/main/resources/mapper/ArdMediaPicMapper.xml b/ard-work/src/main/resources/mapper/ArdMediaPicMapper.xml
new file mode 100644
index 0000000..986ade0
--- /dev/null
+++ b/ard-work/src/main/resources/mapper/ArdMediaPicMapper.xml
@@ -0,0 +1,115 @@
+<?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.work.mapper.ArdMediaPicMapper">
+
+ <resultMap id="ArdMediaPicResult" type="ArdMediaPic">
+ <result property="id" column="id"/>
+ <result property="fileSize" column="file_size"/>
+ <result property="fileMd5" column="file_md5"/>
+ <result property="mediaUrl" column="media_url"/>
+ <result property="sourceUrl" column="source_url"/>
+ <result property="longitude" column="longitude"/>
+ <result property="latitude" column="latitude"/>
+ <result property="height" column="height"/>
+ <result property="taskId" column="task_id"/>
+ <result property="captureTime" column="capture_time"/>
+ <result property="createTime" column="create_time"/>
+ <result property="updateTime" column="update_time"/>
+ <result property="syncStatus" column="sync_status"/>
+ </resultMap>
+
+ <!-- 查询图片列表 -->
+ <select id="selectPicList" resultMap="ArdMediaPicResult">
+ SELECT *
+ FROM ard_media_pic
+ <where>
+ <if test="taskId != null">AND task_id = #{taskId}</if>
+ <if test="syncStatus != null">AND sync_status = #{syncStatus}</if>
+ </where>
+ ORDER BY capture_time DESC
+ </select>
+ <!-- 查询待处理的图片 -->
+ <select id="selectPendingPics" resultMap="ArdMediaPicResult">
+ SELECT *
+ FROM ard_media_pic
+ WHERE sync_status = 0
+ ORDER BY id LIMIT #{limit}
+ </select>
+
+ <!-- 根据任务ID查询图片 -->
+ <select id="selectPicByTaskId" resultMap="ArdMediaPicResult">
+ SELECT * FROM ard_media_pic WHERE task_id = #{taskId}
+ ORDER BY capture_time DESC
+ </select>
+
+ <!-- 插入图片 -->
+ <insert id="insertPic" parameterType="ArdMediaPic">
+ INSERT INTO ard_media_pic (
+ id, task_id, file_size, file_md5,
+ media_url, source_url,
+ longitude, latitude, height,
+ capture_time, create_time,sync_status
+ ) VALUES (
+ #{id}, #{taskId}, #{fileSize}, #{fileMd5},
+ #{mediaUrl}, #{sourceUrl},
+ #{longitude}, #{latitude}, #{height},
+ #{captureTime}, #{createTime},0
+ )
+ </insert>
+
+ <!-- 更新图片(按需补全字段) -->
+ <update id="updatePic" parameterType="ArdMediaPic">
+ UPDATE ard_media_pic
+ <set>
+ <if test="mediaUrl != null">
+ media_url = #{mediaUrl},
+ </if>
+ <if test="fileSize != null">
+ file_size = #{fileSize},
+ </if>
+ <if test="fileMd5 != null">
+ file_md5 = #{fileMd5},
+ </if>
+ <if test="captureTime != null">
+ capture_time = #{captureTime},
+ </if>
+ <if test="longitude != null">
+ longitude = #{longitude},
+ </if>
+ <if test="latitude != null">
+ latitude = #{latitude},
+ </if>
+ <if test="height != null">
+ height = #{height},
+ </if>
+ <if test="syncStatus != null">
+ sync_status = #{syncStatus},
+ </if>
+ update_time = #{updateTime}
+ </set>
+ WHERE id = #{id}
+ </update>
+
+ <!-- 标记为处理中 -->
+ <update id="markProcessing">
+ UPDATE ard_media_pic SET sync_status = 1 WHERE id = #{id} AND sync_status = 0
+ </update>
+ <!-- 更新同步状态 -->
+ <update id="updateSyncStatus">
+ UPDATE ard_media_pic
+ SET sync_status = #{status},update_time = NOW()
+ WHERE id = #{id}
+ </update>
+
+ <delete id="deletePicById">
+ DELETE FROM ard_media_pic WHERE id = #{id}
+ </delete>
+
+ <delete id="deletePicByTaskId">
+ DELETE FROM ard_media_pic WHERE task_id = #{taskId}
+ </delete>
+
+</mapper>
diff --git a/ard-work/src/main/resources/mapper/ArdMediaVideoMapper.xml b/ard-work/src/main/resources/mapper/ArdMediaVideoMapper.xml
new file mode 100644
index 0000000..a19d361
--- /dev/null
+++ b/ard-work/src/main/resources/mapper/ArdMediaVideoMapper.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="com.ard.work.mapper.ArdMediaVideoMapper">
+
+ <!-- 结果映射 -->
+ <resultMap id="ArdMediaVideoResult" type="ArdMediaVideo">
+ <id property="id" column="id"/>
+ <result property="name" column="name"/>
+ <result property="fileSize" column="file_size"/>
+ <result property="mediaUrl" column="media_url"/>
+ <result property="sourceUrl" column="source_url"/>
+ <result property="thumbnailUrl" column="thumbnail_url"/>
+ <result property="startTime" column="start_time"/>
+ <result property="endTime" column="end_time"/>
+ <result property="spanSeconds" column="span_seconds"/>
+ <result property="taskId" column="task_id"/>
+ <result property="createTime" column="create_time"/>
+ <result property="updateTime" column="update_time"/>
+ <result property="syncStatus" column="sync_status"/>
+ </resultMap>
+
+ <!-- 查询视频列表 -->
+ <select id="selectArdMediaVideoList" resultMap="ArdMediaVideoResult">
+ SELECT
+ id, name, file_size, media_url, source_url, thumbnail_url,
+ start_time, end_time, span_seconds, task_id,
+ create_time, update_time,sync_status
+ FROM ard_media_video
+ <where>
+ <if test="taskId != null">AND task_id = #{taskId}</if>
+ <if test="name != null and name != ''">AND name LIKE CONCAT('%', #{name}, '%')</if>
+ <if test="startTime != null">AND start_time >= #{startTime}</if>
+ <if test="endTime != null">AND end_time <= #{endTime}</if>
+ <if test="syncStatus != null">AND sync_status = #{syncStatus}</if>
+ </where>
+ ORDER BY start_time DESC
+ </select>
+
+ <!-- 查询待处理的视频 -->
+ <select id="selectPendingVideos" resultMap="ArdMediaVideoResult">
+ SELECT *
+ FROM ard_media_video
+ WHERE sync_status = 0
+ ORDER BY id LIMIT #{limit}
+ </select>
+
+ <!-- 根据任务ID查询 -->
+ <select id="selectArdMediaVideoByTaskId" resultMap="ArdMediaVideoResult">
+ SELECT *
+ FROM ard_media_video
+ WHERE task_id = #{taskId}
+ ORDER BY start_time DESC
+ </select>
+
+ <!-- 新增视频 -->
+ <insert id="insertArdMediaVideo" parameterType="com.ard.work.domain.entity.ArdMediaVideo">
+ INSERT INTO ard_media_video (id, name, file_size, media_url, source_url, thumbnail_url,
+ start_time, end_time, span_seconds, task_id,
+ create_time, update_time, sync_status)
+ VALUES (#{id}, #{name}, #{fileSize}, #{mediaUrl}, #{sourceUrl}, #{thumbnailUrl},
+ #{startTime}, #{endTime}, #{spanSeconds}, #{taskId},
+ #{createTime}, #{updateTime}, 0)
+ </insert>
+
+ <!-- 更新视频 -->
+ <update id="updateArdMediaVideo">
+ UPDATE ard_media_video
+ <set>
+ <if test="name != null">name = #{name},</if>
+ <if test="fileSize != null">file_size = #{fileSize},</if>
+ <if test="mediaUrl != null">media_url = #{mediaUrl},</if>
+ <if test="sourceUrl != null">source_url = #{sourceUrl},</if>
+ <if test="thumbnailUrl != null">thumbnail_url = #{thumbnailUrl},</if>
+ <if test="startTime != null">start_time = #{startTime},</if>
+ <if test="endTime != null">end_time = #{endTime},</if>
+ <if test="spanSeconds != null">span_seconds = #{spanSeconds},</if>
+ <if test="updateTime != null">update_time = #{updateTime},</if>
+ <if test="syncStatus != null">sync_status = #{syncStatus},</if>
+ </set>
+ WHERE id = #{id}
+ </update>
+ <!-- 标记为处理中 -->
+ <update id="markProcessing">
+ UPDATE ard_media_video SET sync_status = 1 WHERE id = #{id} AND sync_status = 0
+ </update>
+ <!-- 更新同步状态 -->
+ <update id="updateSyncStatus">
+ UPDATE ard_media_video
+ SET sync_status = #{status},update_time = NOW()
+ WHERE id = #{id}
+ </update>
+ <!-- 删除 -->
+ <delete id="deleteArdMediaVideoById">
+ DELETE
+ FROM ard_media_video
+ WHERE id = #{id}
+ </delete>
+
+ <delete id="deleteArdMediaVideoByTaskId">
+ DELETE
+ FROM ard_media_video
+ WHERE task_id = #{taskId}
+ </delete>
+
+</mapper>
--
Gitblit v1.9.3