From dcc483518011581d6399dfba86ca0051fd7dd097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E5=B0=8F=E4=BA=91?= Date: Wed, 4 Feb 2026 16:20:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=97=A0=E4=BA=BA=E6=9C=BA=E5=85=BC=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../device/controller/AircraftController.java | 53 ++- .../device/controller/DockController.java | 59 +++- .../device/controller/GroupController.java | 62 +++- .../device/controller/StaticsController.java | 230 +++++++++++-- .../service/impl/TuohengBufferDeviceImpl.java | 325 ++++++++++++++++++ 5 files changed, 685 insertions(+), 44 deletions(-) create mode 100644 src/main/java/com/ruoyi/device/service/impl/TuohengBufferDeviceImpl.java diff --git a/src/main/java/com/ruoyi/device/controller/AircraftController.java b/src/main/java/com/ruoyi/device/controller/AircraftController.java index d01756f..77ac6e7 100644 --- a/src/main/java/com/ruoyi/device/controller/AircraftController.java +++ b/src/main/java/com/ruoyi/device/controller/AircraftController.java @@ -7,9 +7,14 @@ import com.ruoyi.device.api.domain.AircraftDetailVO; import com.ruoyi.device.api.domain.AircraftUpdateRequest; import com.ruoyi.device.controller.convert.AircraftDetailVOConvert; import com.ruoyi.device.service.api.IAircraftService; -import com.ruoyi.device.service.api.IBufferDeviceService; +import com.ruoyi.device.service.impl.BufferDeviceImpl; +import com.ruoyi.device.service.impl.TuohengBufferDeviceImpl; import com.ruoyi.device.service.dto.AircraftDetailDTO; import com.ruoyi.device.service.dto.AircraftDTO; +import com.ruoyi.device.domain.api.IAircraftDomain; +import com.ruoyi.device.domain.api.IDeviceDomain; +import com.ruoyi.device.domain.model.Aircraft; +import com.ruoyi.device.domain.model.Device; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @@ -27,7 +32,16 @@ public class AircraftController extends BaseController private IAircraftService aircraftService; @Autowired - private IBufferDeviceService bufferDeviceService; + private BufferDeviceImpl bufferDeviceService; + + @Autowired + private TuohengBufferDeviceImpl tuohengBufferDeviceService; + + @Autowired + private IAircraftDomain aircraftDomain; + + @Autowired + private IDeviceDomain deviceDomain; /** * 查看无人机详情 @@ -39,7 +53,7 @@ public class AircraftController extends BaseController @GetMapping("/detail/{aircraftId}") public R getAircraftDetail(@PathVariable("aircraftId") Long aircraftId) { - AircraftDetailDTO dto = bufferDeviceService.getAircraftDetailById(aircraftId); + AircraftDetailDTO dto = getAircraftDetailByManufacturer(aircraftId); AircraftDetailVO vo = AircraftDetailVOConvert.from(dto); return R.ok(vo); } @@ -60,4 +74,37 @@ public class AircraftController extends BaseController aircraftService.updateAircraft(dto); return R.ok(); } + + /** + * 根据无人机ID获取无人机详情(自动选择大疆或拓恒服务) + * + * @param aircraftId 无人机ID + * @return 无人机详情DTO + */ + private AircraftDetailDTO getAircraftDetailByManufacturer(Long aircraftId) { + // 查询无人机信息 + Aircraft aircraft = aircraftDomain.selectAircraftByAircraftId(aircraftId); + if (aircraft == null) { + logger.warn("无人机不存在: aircraftId={}", aircraftId); + return null; + } + + // 查询设备信息,获取厂商 + Device device = deviceDomain.selectDeviceByDeviceId(aircraft.getDeviceId()); + if (device == null) { + logger.warn("无人机对应的设备不存在: deviceId={}", aircraft.getDeviceId()); + return null; + } + + // 根据厂商选择对应的服务 + String manufacturer = device.getDeviceManufacturer(); + if ("tuoheng".equals(manufacturer)) { + logger.debug("使用拓恒服务获取无人机详情: aircraftId={}", aircraftId); + return tuohengBufferDeviceService.getAircraftDetailById(aircraftId); + } else { + logger.debug("使用大疆服务获取无人机详情: aircraftId={}, manufacturer={}", + aircraftId, manufacturer); + return bufferDeviceService.getAircraftDetailById(aircraftId); + } + } } diff --git a/src/main/java/com/ruoyi/device/controller/DockController.java b/src/main/java/com/ruoyi/device/controller/DockController.java index 305b0d9..a6a3bee 100644 --- a/src/main/java/com/ruoyi/device/controller/DockController.java +++ b/src/main/java/com/ruoyi/device/controller/DockController.java @@ -9,9 +9,14 @@ import com.ruoyi.device.api.domain.DockVO; import com.ruoyi.device.api.domain.DockWithGPSVO; import com.ruoyi.device.controller.convert.DockWithGPSVOConvert; import com.ruoyi.device.service.api.IDockService; -import com.ruoyi.device.service.api.IBufferDeviceService; +import com.ruoyi.device.service.impl.BufferDeviceImpl; +import com.ruoyi.device.service.impl.TuohengBufferDeviceImpl; import com.ruoyi.device.service.dto.DockDetailDTO; import com.ruoyi.device.service.dto.DockDTO; +import com.ruoyi.device.domain.api.IDockDomain; +import com.ruoyi.device.domain.api.IDeviceDomain; +import com.ruoyi.device.domain.model.Dock; +import com.ruoyi.device.domain.model.Device; import com.ruoyi.device.controller.convert.DockVOConvert; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -34,7 +39,16 @@ public class DockController extends BaseController private IDockService dockService; @Autowired - private IBufferDeviceService bufferDeviceService; + private BufferDeviceImpl bufferDeviceService; + + @Autowired + private TuohengBufferDeviceImpl tuohengBufferDeviceService; + + @Autowired + private IDockDomain dockDomain; + + @Autowired + private IDeviceDomain deviceDomain; /** * 搜索机场 @@ -62,7 +76,7 @@ public class DockController extends BaseController @GetMapping("/detail/{dockId}") public R getDockDetail(@PathVariable("dockId") Long dockId) { - DockDetailDTO dockDetailDTO = bufferDeviceService.getDockDetailById(dockId); + DockDetailDTO dockDetailDTO = getDockDetailByManufacturer(dockId); if (dockDetailDTO == null) { return R.fail("机场不存在: dockId=" + dockId); } @@ -102,9 +116,44 @@ public class DockController extends BaseController List dockDTOs = dockService.selectDockList(new DockDTO()); List dtoList = new ArrayList<>(); for (DockDTO dockDTO : dockDTOs) { - DockDetailDTO dockDetailDTO = bufferDeviceService.getDockDetailById(dockDTO.getDockId()); - dtoList.add(dockDetailDTO); + DockDetailDTO dockDetailDTO = getDockDetailByManufacturer(dockDTO.getDockId()); + if (dockDetailDTO != null) { + dtoList.add(dockDetailDTO); + } } return R.ok(DockWithGPSVOConvert.fromList(dtoList)); } + + /** + * 根据机场ID获取机场详情(自动选择大疆或拓恒服务) + * + * @param dockId 机场ID + * @return 机场详情DTO + */ + private DockDetailDTO getDockDetailByManufacturer(Long dockId) { + // 查询机场信息 + Dock dock = dockDomain.selectDockByDockId(dockId); + if (dock == null) { + logger.warn("机场不存在: dockId={}", dockId); + return null; + } + + // 查询设备信息,获取厂商 + Device device = deviceDomain.selectDeviceByDeviceId(dock.getDeviceId()); + if (device == null) { + logger.warn("机场对应的设备不存在: deviceId={}", dock.getDeviceId()); + return null; + } + + // 根据厂商选择对应的服务 + String manufacturer = device.getDeviceManufacturer(); + if ("tuoheng".equals(manufacturer)) { + logger.debug("使用拓恒服务获取机场详情: dockId={}", dockId); + return tuohengBufferDeviceService.getDockDetailById(dockId); + } else { + logger.debug("使用大疆服务获取机场详情: dockId={}, manufacturer={}", + dockId, manufacturer); + return bufferDeviceService.getDockDetailById(dockId); + } + } } diff --git a/src/main/java/com/ruoyi/device/controller/GroupController.java b/src/main/java/com/ruoyi/device/controller/GroupController.java index 2753afe..7f39544 100644 --- a/src/main/java/com/ruoyi/device/controller/GroupController.java +++ b/src/main/java/com/ruoyi/device/controller/GroupController.java @@ -8,8 +8,11 @@ import com.ruoyi.device.controller.convert.DockWithGPSVOConvert; import com.ruoyi.device.controller.convert.GroupVOConvert; import com.ruoyi.device.domain.api.IDockDomain; import com.ruoyi.device.domain.model.Dock; -import com.ruoyi.device.service.api.IBufferDeviceService; +import com.ruoyi.device.service.impl.BufferDeviceImpl; +import com.ruoyi.device.service.impl.TuohengBufferDeviceImpl; import com.ruoyi.device.service.api.IGroupService; +import com.ruoyi.device.domain.api.IDeviceDomain; +import com.ruoyi.device.domain.model.Device; import com.ruoyi.device.service.dto.DockDetailDTO; import com.ruoyi.device.service.dto.DockGroupDTO; import com.ruoyi.device.service.dto.GroupDTO; @@ -33,10 +36,16 @@ public class GroupController extends BaseController private IGroupService groupService; @Autowired - private IBufferDeviceService bufferDeviceService; + private BufferDeviceImpl bufferDeviceService; + + @Autowired + private TuohengBufferDeviceImpl tuohengBufferDeviceService; @Autowired private IDockDomain dockDomain; + + @Autowired + private IDeviceDomain deviceDomain; /** * 创建分组 * @@ -128,7 +137,7 @@ public class GroupController extends BaseController logger.info("getDocksByGroupId {}", groupId); if(Objects.equals(groupId, -1L)){ - List groupDTOS = groupService.getDocksByGroupId(groupId); +// List groupDTOS = groupService.getDocksByGroupId(groupId); List dtoList = new ArrayList<>(); Dock queryDock = new Dock(); List allDocks = dockDomain.selectDockList(queryDock); @@ -136,10 +145,11 @@ public class GroupController extends BaseController if (allDocks != null) { for (Dock dock : allDocks) { if (dock.getLastActiveTime() != null) { - DockDetailDTO dockDetailDTO = bufferDeviceService.getDockDetailById(dock.getDockId()); - dockDetailDTO.setLastActiveTime(dock.getLastActiveTime()); - dtoList.add(dockDetailDTO); - + DockDetailDTO dockDetailDTO = getDockDetailByManufacturer(dock.getDockId()); + if (dockDetailDTO != null) { + dockDetailDTO.setLastActiveTime(dock.getLastActiveTime()); + dtoList.add(dockDetailDTO); + } } } } @@ -150,8 +160,10 @@ public class GroupController extends BaseController List groupDTOS = groupService.getDocksByGroupId(groupId); List dtoList = new ArrayList<>(); for (DockGroupDTO dockGroupDTO : groupDTOS) { - DockDetailDTO dockDetailDTO = bufferDeviceService.getDockDetailById(dockGroupDTO.getDockId()); - dtoList.add(dockDetailDTO); + DockDetailDTO dockDetailDTO = getDockDetailByManufacturer(dockGroupDTO.getDockId()); + if (dockDetailDTO != null) { + dtoList.add(dockDetailDTO); + } } return R.ok(DockWithGPSVOConvert.fromList(dtoList)); @@ -201,4 +213,36 @@ public class GroupController extends BaseController return R.ok(groupVOS); } + + /** + * 根据机场ID获取机场详情(自动选择大疆或拓恒服务) + * + * @param dockId 机场ID + * @return 机场详情DTO + */ + private DockDetailDTO getDockDetailByManufacturer(Long dockId) { + // 查询机场信息 + Dock dock = dockDomain.selectDockByDockId(dockId); + if (dock == null) { + logger.warn("机场不存在: dockId={}", dockId); + return null; + } + + // 查询设备信息,获取厂商 + Device device = deviceDomain.selectDeviceByDeviceId(dock.getDeviceId()); + if (device == null) { + logger.warn("机场对应的设备不存在: deviceId={}", dock.getDeviceId()); + return null; + } + + // 根据厂商选择对应的服务 + String manufacturer = device.getDeviceManufacturer(); + if ("tuoheng".equals(manufacturer)) { + logger.debug("使用拓恒服务获取机场详情: dockId={}", dockId); + return tuohengBufferDeviceService.getDockDetailById(dockId); + } else { + logger.debug("使用大疆服务获取机场详情: dockId={}, manufacturer={}", dockId, manufacturer); + return bufferDeviceService.getDockDetailById(dockId); + } + } } diff --git a/src/main/java/com/ruoyi/device/controller/StaticsController.java b/src/main/java/com/ruoyi/device/controller/StaticsController.java index 4ee0f43..9663c3d 100644 --- a/src/main/java/com/ruoyi/device/controller/StaticsController.java +++ b/src/main/java/com/ruoyi/device/controller/StaticsController.java @@ -7,8 +7,11 @@ import com.ruoyi.device.api.enums.AircraftStatusEnum; import com.ruoyi.device.api.enums.DockStatusEnum; import com.ruoyi.device.api.enums.PayloadStatusEnum; import com.ruoyi.device.service.api.IAircraftService; -import com.ruoyi.device.service.api.IBufferDeviceService; +import com.ruoyi.device.service.impl.BufferDeviceImpl; +import com.ruoyi.device.service.impl.TuohengBufferDeviceImpl; import com.ruoyi.device.service.api.IDockService; +import com.ruoyi.device.domain.api.IDeviceDomain; +import com.ruoyi.device.domain.model.Device; import com.ruoyi.device.service.api.IPayloadService; import com.ruoyi.device.service.dto.AircraftDTO; import com.ruoyi.device.service.dto.AircraftDetailDTO; @@ -48,17 +51,58 @@ public class StaticsController extends BaseController private IPayloadService payloadService; @Autowired - private IBufferDeviceService bufferDeviceService; + private BufferDeviceImpl bufferDeviceService; + + @Autowired + private TuohengBufferDeviceImpl tuohengBufferDeviceService; + + @Autowired + private IDeviceDomain deviceDomain; /** - * 获取系统统计信息 + * 获取系统统计信息(合并大疆和拓恒) * * @return 统计信息 */ @GetMapping public R getStatistics() { - return R.ok(buildDjiStatisticsVO()); + log.info("========== 开始统计所有设备信息(大疆+拓恒) =========="); + + // 获取大疆统计 + StatisticsVO djiStats = buildDjiStatisticsVO(); + + // 获取拓恒统计 + StatisticsVO thStats = buildThStatisticsVO(); + + // 合并统计结果 + StatisticsVO totalStats = new StatisticsVO(); + + // 机场统计 + totalStats.setDockCount(djiStats.getDockCount() + thStats.getDockCount()); + totalStats.setIdleDockCount(djiStats.getIdleDockCount() + thStats.getIdleDockCount()); + totalStats.setWorkingDockCount(djiStats.getWorkingDockCount() + thStats.getWorkingDockCount()); + totalStats.setDebuggingDockCount(djiStats.getDebuggingDockCount() + thStats.getDebuggingDockCount()); + totalStats.setOfflineDockCount(djiStats.getOfflineDockCount() + thStats.getOfflineDockCount()); + + // 无人机统计 + totalStats.setAircraftCount(djiStats.getAircraftCount() + thStats.getAircraftCount()); + totalStats.setPowerOnInCabinCount(djiStats.getPowerOnInCabinCount() + thStats.getPowerOnInCabinCount()); + totalStats.setPowerOffInCabinCount(djiStats.getPowerOffInCabinCount() + thStats.getPowerOffInCabinCount()); + totalStats.setInMissionCount(djiStats.getInMissionCount() + thStats.getInMissionCount()); + totalStats.setDebuggingAircraftCount(djiStats.getDebuggingAircraftCount() + thStats.getDebuggingAircraftCount()); + totalStats.setOfflineAircraftCount(djiStats.getOfflineAircraftCount() + thStats.getOfflineAircraftCount()); + + // 挂载统计 + totalStats.setPayloadCount(djiStats.getPayloadCount() + thStats.getPayloadCount()); + totalStats.setOfflinePayloadCount(djiStats.getOfflinePayloadCount() + thStats.getOfflinePayloadCount()); + + log.info("========== 所有设备统计完成 =========="); + log.info("总计: 机场={}, 任务中机场={}, 无人机={}, 任务中无人机={}", + totalStats.getDockCount(), totalStats.getWorkingDockCount(), + totalStats.getAircraftCount(), totalStats.getInMissionCount()); + + return R.ok(totalStats); } @@ -75,28 +119,7 @@ public class StaticsController extends BaseController @GetMapping("/th") public R getThStatistics() { - StatisticsVO vo = new StatisticsVO(); - - // 机场统计 - vo.setDockCount(0); - vo.setIdleDockCount(0); - vo.setWorkingDockCount(0); - vo.setDebuggingDockCount(0); - vo.setOfflineDockCount(0); - - // 无人机统计 - vo.setAircraftCount(0); - vo.setPowerOnInCabinCount(0); - vo.setPowerOffInCabinCount(0); - vo.setInMissionCount(0); - vo.setDebuggingAircraftCount(0); - vo.setOfflineAircraftCount(0); - - // 挂载统计 - vo.setPayloadCount(0); - vo.setOfflinePayloadCount(0); - - return R.ok(vo); + return R.ok(buildThStatisticsVO()); } private StatisticsVO buildDjiStatisticsVO (){ @@ -227,4 +250,157 @@ public class StaticsController extends BaseController return vo; } -} \ No newline at end of file + + /** + * 构建拓恒设备统计信息 + */ + private StatisticsVO buildThStatisticsVO() { + log.info("========== 开始统计拓恒设备信息 =========="); + StatisticsVO vo = new StatisticsVO(); + + // 获取所有机场 + List allDocks = dockService.selectDockList(new DockDTO()); + + // 过滤出拓恒机场 + List thDocks = filterDocksByManufacturer(allDocks, "tuoheng"); + vo.setDockCount(thDocks.size()); + log.info("拓恒机场总数: {}", vo.getDockCount()); + + // 批量获取拓恒机场详情 + Map dockDetailsMap = null; + if (!thDocks.isEmpty()) { + List dockIds = thDocks.stream() + .map(DockDTO::getDockId) + .collect(Collectors.toList()); + dockDetailsMap = tuohengBufferDeviceService.getDockDetailsByIds(dockIds); + } + + // 统计各状态机场数量 + int idleCount = 0; + int workingCount = 0; + int debuggingCount = 0; + int offlineCount = 0; + + if (dockDetailsMap != null) { + log.info("---------- 开始统计拓恒机场状态 ----------"); + for (DockDTO dock : thDocks) { + DockDetailDTO dockDetail = dockDetailsMap.get(dock.getDockId()); + if (dockDetail != null && dockDetail.getDockStatus() != null) { + String status = dockDetail.getDockStatus(); + log.info("拓恒机场[ID:{}, Name:{}] 状态: {}", dock.getDockId(), dock.getDockName(), status); + if (DockStatusEnum.IDLE.getCode().equalsIgnoreCase(status)) { + idleCount++; + } else if (DockStatusEnum.WORKING.getCode().equalsIgnoreCase(status)) { + workingCount++; + } else if (DockStatusEnum.Debugging.getCode().equalsIgnoreCase(status)) { + debuggingCount++; + } else { + offlineCount++; + } + } + } + } + + vo.setIdleDockCount(idleCount); + vo.setWorkingDockCount(workingCount); + vo.setDebuggingDockCount(debuggingCount); + vo.setOfflineDockCount(offlineCount); + + log.info("拓恒机场状态统计 -> 空闲:{}, 任务中:{}, 调试:{}, 离线:{}", + idleCount, workingCount, debuggingCount, offlineCount); + + // 获取所有无人机 + List allAircrafts = aircraftService.selectAircraftList(new AircraftDTO()); + + // 过滤出拓恒无人机 + List thAircrafts = filterAircraftsByManufacturer(allAircrafts, "tuoheng"); + vo.setAircraftCount(thAircrafts.size()); + log.info("拓恒无人机总数: {}", vo.getAircraftCount()); + + // 批量获取拓恒无人机详情 + Map aircraftDetailsMap = null; + if (!thAircrafts.isEmpty()) { + List aircraftIds = thAircrafts.stream() + .map(AircraftDTO::getAircraftId) + .collect(Collectors.toList()); + aircraftDetailsMap = tuohengBufferDeviceService.getAircraftDetailsByIds(aircraftIds); + } + + // 统计各状态无人机数量 + int powerOnInCabinCount = 0; + int powerOffInCabinCount = 0; + int inMissionCount = 0; + int debuggingAircraftCount = 0; + int offlineAircraftCount = 0; + + if (aircraftDetailsMap != null) { + log.info("---------- 开始统计拓恒无人机状态 ----------"); + for (AircraftDTO aircraft : thAircrafts) { + AircraftDetailDTO aircraftDetail = aircraftDetailsMap.get(aircraft.getAircraftId()); + if (aircraftDetail != null && aircraftDetail.getAircraftStatus() != null) { + String status = aircraftDetail.getAircraftStatus(); + log.info("拓恒无人机[ID:{}, Name:{}] 状态: {}", + aircraft.getAircraftId(), aircraft.getAircraftName(), status); + if (AircraftStatusEnum.POWER_ON_IN_CABIN.getCode().equalsIgnoreCase(status)) { + powerOnInCabinCount++; + } else if (AircraftStatusEnum.POWER_OFF_IN_CABIN.getCode().equalsIgnoreCase(status)) { + powerOffInCabinCount++; + } else if (AircraftStatusEnum.IN_MISSION.getCode().equalsIgnoreCase(status)) { + inMissionCount++; + } else if (AircraftStatusEnum.DEBUGGING.getCode().equalsIgnoreCase(status)) { + debuggingAircraftCount++; + } else { + offlineAircraftCount++; + } + } + } + } + + vo.setPowerOnInCabinCount(powerOnInCabinCount); + vo.setPowerOffInCabinCount(powerOffInCabinCount); + vo.setInMissionCount(inMissionCount); + vo.setDebuggingAircraftCount(debuggingAircraftCount); + vo.setOfflineAircraftCount(offlineAircraftCount); + + log.info("拓恒无人机状态统计 -> 舱内开机:{}, 舱内关机:{}, 任务中:{}, 调试:{}, 离线:{}", + powerOnInCabinCount, powerOffInCabinCount, inMissionCount, + debuggingAircraftCount, offlineAircraftCount); + + // 挂载统计(拓恒设备暂时设置为0) + vo.setPayloadCount(0); + vo.setOfflinePayloadCount(0); + + log.info("========== 拓恒设备统计完成 =========="); + return vo; + } + + /** + * 根据厂商过滤机场列表 + */ + private List filterDocksByManufacturer(List docks, String manufacturer) { + if (docks == null || docks.isEmpty()) { + return List.of(); + } + return docks.stream() + .filter(dock -> { + Device device = deviceDomain.selectDeviceByDeviceId(dock.getDeviceId()); + return device != null && manufacturer.equals(device.getDeviceManufacturer()); + }) + .collect(Collectors.toList()); + } + + /** + * 根据厂商过滤无人机列表 + */ + private List filterAircraftsByManufacturer(List aircrafts, String manufacturer) { + if (aircrafts == null || aircrafts.isEmpty()) { + return List.of(); + } + return aircrafts.stream() + .filter(aircraft -> { + Device device = deviceDomain.selectDeviceByDeviceId(aircraft.getDeviceId()); + return device != null && manufacturer.equals(device.getDeviceManufacturer()); + }) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/ruoyi/device/service/impl/TuohengBufferDeviceImpl.java b/src/main/java/com/ruoyi/device/service/impl/TuohengBufferDeviceImpl.java new file mode 100644 index 0000000..69317a0 --- /dev/null +++ b/src/main/java/com/ruoyi/device/service/impl/TuohengBufferDeviceImpl.java @@ -0,0 +1,325 @@ +package com.ruoyi.device.service.impl; + +import com.ruoyi.device.domain.api.*; +import com.ruoyi.device.domain.model.*; +import com.ruoyi.device.domain.model.thingsboard.AttributeMap; +import com.ruoyi.device.domain.model.thingsboard.TelemetryMap; +import com.ruoyi.device.domain.model.thingsboard.TelemetryValue; +import com.ruoyi.device.domain.model.thingsboard.tuoheng.constants.TuohengDeviceAttributes; +import com.ruoyi.device.domain.model.thingsboard.tuoheng.constants.TuohengDeviceTelemetry; +import com.ruoyi.device.service.api.IBufferDeviceService; +import com.ruoyi.device.service.dto.AircraftDetailDTO; +import com.ruoyi.device.service.dto.DockDetailDTO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 拓恒设备缓冲服务实现 + * 专门处理拓恒设备的数据整合 + * + * @author ruoyi + * @date 2026-02-04 + */ +@Service("tuohengBufferDeviceService") +@Slf4j +public class TuohengBufferDeviceImpl implements IBufferDeviceService { + + @Autowired + private IDockDomain dockDomain; + + @Autowired + private IDeviceDomain deviceDomain; + + @Autowired + private IAircraftDomain aircraftDomain; + + @Autowired + private IDockAircraftDomain dockAircraftDomain; + + @Autowired + private IThingsBoardDomain thingsBoardDomain; + + @Override + public DockDetailDTO getDockDetailById(Long dockId) { + log.info("获取拓恒机场详情: dockId={}", dockId); + + // 查询机场基础信息 + Dock dock = dockDomain.selectDockByDockId(dockId); + if (dock == null) { + log.warn("机场不存在: dockId={}", dockId); + return null; + } + + // 查询设备信息 + Device device = deviceDomain.selectDeviceByDeviceId(dock.getDeviceId()); + if (device == null) { + log.warn("机场对应的设备不存在: deviceId={}", dock.getDeviceId()); + return null; + } + + // 检查是否是拓恒设备 + if (!"tuoheng".equals(device.getDeviceManufacturer())) { + log.warn("设备不是拓恒厂商: deviceId={}, manufacturer={}", + device.getDeviceId(), device.getDeviceManufacturer()); + return null; + } + + // 构建机场详情DTO + DockDetailDTO dto = new DockDetailDTO(); + dto.setDockId(dock.getDockId()); + dto.setDockName(dock.getDockName()); + dto.setDockLocation(dock.getDockLocation()); + dto.setDockIotId(device.getIotDeviceId()); + dto.setSnNumber(device.getDeviceSn()); + dto.setBindTime(device.getCreateTime().getTime()); + + // 获取ThingsBoard数据并填充到DTO + fillTuohengDockDetail(dto, device.getIotDeviceId()); + + // 查询关联的无人机 + List aircrafts = dockAircraftDomain.selectDockAircraftByDockId(dockId); + if (!CollectionUtils.isEmpty(aircrafts)) { + DockAircraft dockAircraft = aircrafts.get(0); + Aircraft aircraft = aircraftDomain.selectAircraftByAircraftId(dockAircraft.getAircraftId()); + if (aircraft != null) { + dto.setAircraftId(aircraft.getAircraftId()); + dto.setAircraftName(aircraft.getAircraftName()); + + Device airDevice = deviceDomain.selectDeviceByDeviceId(aircraft.getDeviceId()); + if (airDevice != null) { + dto.setAircraftIotId(airDevice.getIotDeviceId()); + + // 填充无人机状态信息 + fillTuohengAircraftStatus(dto, airDevice.getIotDeviceId()); + } + } + } + + return dto; + } + + @Override + public AircraftDetailDTO getAircraftDetailById(Long aircraftId) { + log.info("获取拓恒无人机详情: aircraftId={}", aircraftId); + + // 查询无人机基础信息 + Aircraft aircraft = aircraftDomain.selectAircraftByAircraftId(aircraftId); + if (aircraft == null) { + log.warn("无人机不存在: aircraftId={}", aircraftId); + return null; + } + + // 查询设备信息 + Device device = deviceDomain.selectDeviceByDeviceId(aircraft.getDeviceId()); + if (device == null) { + log.warn("无人机对应的设备不存在: deviceId={}", aircraft.getDeviceId()); + return null; + } + + // 检查是否是拓恒设备 + if (!"tuoheng".equals(device.getDeviceManufacturer())) { + log.warn("设备不是拓恒厂商: deviceId={}, manufacturer={}", + device.getDeviceId(), device.getDeviceManufacturer()); + return null; + } + + // 构建无人机详情DTO + AircraftDetailDTO dto = new AircraftDetailDTO(); + dto.setAircraftId(aircraft.getAircraftId()); + dto.setAircraftName(aircraft.getAircraftName()); + dto.setSnNumber(device.getDeviceSn()); + dto.setBindTime(device.getCreateTime().getTime()); + + // 获取ThingsBoard数据并填充到DTO + fillTuohengAircraftDetail(dto, device.getIotDeviceId()); + + return dto; + } + + @Override + public Map getDockDetailsByIds(List dockIds) { + if (CollectionUtils.isEmpty(dockIds)) { + return new HashMap<>(); + } + + Map resultMap = new HashMap<>(dockIds.size()); + + for (Long dockId : dockIds) { + try { + DockDetailDTO dto = getDockDetailById(dockId); + if (dto != null) { + resultMap.put(dockId, dto); + } + } catch (Exception e) { + log.error("获取拓恒机场详情失败, dockId: {}", dockId, e); + } + } + + return resultMap; + } + + @Override + public Map getAircraftDetailsByIds(List aircraftIds) { + if (CollectionUtils.isEmpty(aircraftIds)) { + return new HashMap<>(); + } + + Map resultMap = new HashMap<>(aircraftIds.size()); + + for (Long aircraftId : aircraftIds) { + try { + AircraftDetailDTO dto = getAircraftDetailById(aircraftId); + if (dto != null) { + resultMap.put(aircraftId, dto); + } + } catch (Exception e) { + log.error("获取拓恒无人机详情失败, aircraftId: {}", aircraftId, e); + } + } + + return resultMap; + } + + /** + * 填充拓恒机场详情数据 + * + * @param dto 机场详情DTO + * @param iotDeviceId ThingsBoard设备ID + */ + private void fillTuohengDockDetail(DockDetailDTO dto, String iotDeviceId) { + try { + // 获取拓恒设备属性 + AttributeMap attributes = thingsBoardDomain.getPredefinedTuohengDeviceAttributes(iotDeviceId); + // 获取拓恒设备遥测数据 + TelemetryMap telemetry = thingsBoardDomain.getPredefinedTuohengDeviceTelemetry(iotDeviceId); + + // 设置在线状态 + Boolean isActive = attributes.get(TuohengDeviceAttributes.ACTIVE).orElse(false); + if (isActive) { + telemetry.get(TuohengDeviceTelemetry.STATUS).ifPresent(statusValue -> { + String status = statusValue.getValue(); + dto.setDockStatus("online".equals(status) ? "IDLE" : "OFFLINE"); + }); + } else { + dto.setDockStatus("OFFLINE"); + } + + // 设置舱内温度和湿度 + telemetry.get(TuohengDeviceTelemetry.NEST_INNER_TEMP) + .ifPresent(value -> dto.setCabinTemperature(value.getValue())); + telemetry.get(TuohengDeviceTelemetry.NEST_INNER_HUM) + .ifPresent(value -> dto.setCabinHumidity(value.getValue())); + + // 设置环境数据 + telemetry.get(TuohengDeviceTelemetry.NEST_INNER_TEMP) + .ifPresent(value -> dto.setEnvironmentTemperature(value.getValue())); + telemetry.get(TuohengDeviceTelemetry.WEATHER_WIND_SPEED) + .ifPresent(value -> dto.setWindSpeed(value.getValue())); + telemetry.get(TuohengDeviceTelemetry.WEATHER_RAINFALL) + .ifPresent(value -> dto.setRainfall(value.getValue())); + + // 设置电池信息 + telemetry.get(TuohengDeviceTelemetry.BATTERY_LEVEL) + .ifPresent(value -> dto.setCapacity_percent(value.getValue())); + + // 设置充电状态 + telemetry.get(TuohengDeviceTelemetry.BATTERY_B_CHARGING) + .ifPresent(value -> { + dto.setChargingStatus(value.getValue() == 1 ? "CHARGING" : "FREE"); + }); + + log.debug("拓恒机场详情填充完成: iotDeviceId={}", iotDeviceId); + } catch (Exception e) { + log.error("填充拓恒机场详情失败: iotDeviceId={}, error={}", iotDeviceId, e.getMessage(), e); + } + } + + /** + * 填充拓恒无人机状态信息(用于机场详情中的无人机状态) + * + * @param dto 机场详情DTO + * @param aircraftIotDeviceId 无人机ThingsBoard设备ID + */ + private void fillTuohengAircraftStatus(DockDetailDTO dto, String aircraftIotDeviceId) { + try { + // 获取拓恒无人机遥测数据 + TelemetryMap telemetry = thingsBoardDomain.getPredefinedTuohengDeviceTelemetry(aircraftIotDeviceId); + + // 设置无人机状态 - 根据 armed 状态判断 + telemetry.get(TuohengDeviceTelemetry.ARMED).ifPresent(armedValue -> { + String armed = armedValue.getValue(); + if ("true".equals(armed) || "1".equals(armed)) { + dto.setAircraftStatus("IN_MISSION"); // 解锁状态表示在任务中 + } else { + dto.setAircraftStatus("POWER_ON_IN_CABIN"); // 未解锁表示在舱内待机 + } + }); + + // 设置作业架次 - 暂时设置为0,拓恒设备可能没有这个数据 + dto.setMissionCount(0); + + log.debug("拓恒无人机状态填充完成: aircraftIotDeviceId={}", aircraftIotDeviceId); + } catch (Exception e) { + log.error("填充拓恒无人机状态失败: aircraftIotDeviceId={}, error={}", + aircraftIotDeviceId, e.getMessage(), e); + } + } + + /** + * 填充拓恒无人机详情数据 + * + * @param dto 无人机详情DTO + * @param iotDeviceId ThingsBoard设备ID + */ + private void fillTuohengAircraftDetail(AircraftDetailDTO dto, String iotDeviceId) { + try { + // 获取拓恒设备属性 + AttributeMap attributes = thingsBoardDomain.getPredefinedTuohengDeviceAttributes(iotDeviceId); + // 获取拓恒设备遥测数据 + TelemetryMap telemetry = thingsBoardDomain.getPredefinedTuohengDeviceTelemetry(iotDeviceId); + + // 设置无人机状态 + telemetry.get(TuohengDeviceTelemetry.ARMED).ifPresent(armedValue -> { + String armed = armedValue.getValue(); + if ("true".equals(armed) || "1".equals(armed)) { + dto.setAircraftStatus("IN_MISSION"); + } else { + dto.setAircraftStatus("POWER_ON_IN_CABIN"); + } + }); + + // 设置作业架次 - 暂时设置为0 + dto.setMissionCount(0); + + // 设置GPS信号 + telemetry.get(TuohengDeviceTelemetry.SAT_COUNT) + .ifPresent(value -> dto.setGpsSignal(value.getValue())); + + // 设置电池信息 + telemetry.get(TuohengDeviceTelemetry.BATTERY_REMAIN) + .ifPresent(value -> dto.setBatteryLevel(value.getValue())); + + telemetry.get(TuohengDeviceTelemetry.VOLTAGE) + .ifPresent(value -> { + Double voltage = value.getValue(); + if (voltage != null) { + dto.setVoltage(voltage.intValue()); + } + }); + + // 设置飞行时长(秒) + telemetry.get(TuohengDeviceTelemetry.FLIGHT_TIME) + .ifPresent(value -> dto.setFlightDuration(value.getValue())); + + log.debug("拓恒无人机详情填充完成: iotDeviceId={}", iotDeviceId); + } catch (Exception e) { + log.error("填充拓恒无人机详情失败: iotDeviceId={}, error={}", iotDeviceId, e.getMessage(), e); + } + } +}