diff --git a/src/main/java/com/ruoyi/device/domain/api/IAircraftDomain.java b/src/main/java/com/ruoyi/device/domain/api/IAircraftDomain.java index f0c32e3..1108fed 100644 --- a/src/main/java/com/ruoyi/device/domain/api/IAircraftDomain.java +++ b/src/main/java/com/ruoyi/device/domain/api/IAircraftDomain.java @@ -27,6 +27,14 @@ public interface IAircraftDomain */ Aircraft selectAircraftByAircraftId(Long aircraftId); + /** + * 根据设备主键查询无人机 + * + * @param deviceId 设备主键 + * @return 无人机 + */ + Aircraft selectAircraftByDeviceId(Long deviceId); + /** * 新增无人机 * diff --git a/src/main/java/com/ruoyi/device/domain/api/IDeviceDomain.java b/src/main/java/com/ruoyi/device/domain/api/IDeviceDomain.java index 9bb8617..7dccac0 100644 --- a/src/main/java/com/ruoyi/device/domain/api/IDeviceDomain.java +++ b/src/main/java/com/ruoyi/device/domain/api/IDeviceDomain.java @@ -27,6 +27,14 @@ public interface IDeviceDomain */ Device selectDeviceByDeviceId(Long deviceId); + /** + * 根据IOT设备ID查询设备 + * + * @param iotDeviceId IOT设备ID + * @return 设备 + */ + Device selectDeviceByIotDeviceId(String iotDeviceId); + /** * 新增设备 * diff --git a/src/main/java/com/ruoyi/device/domain/api/IDockDomain.java b/src/main/java/com/ruoyi/device/domain/api/IDockDomain.java index cefcba3..8ef4a97 100644 --- a/src/main/java/com/ruoyi/device/domain/api/IDockDomain.java +++ b/src/main/java/com/ruoyi/device/domain/api/IDockDomain.java @@ -27,6 +27,14 @@ public interface IDockDomain */ Dock selectDockByDockId(Long dockId); + /** + * 根据设备主键查询机场 + * + * @param deviceId 设备主键 + * @return 机场 + */ + Dock selectDockByDeviceId(Long deviceId); + /** * 新增机场 * diff --git a/src/main/java/com/ruoyi/device/domain/api/IThingsBoardDomain.java b/src/main/java/com/ruoyi/device/domain/api/IThingsBoardDomain.java index b61ad0a..8e97c8d 100644 --- a/src/main/java/com/ruoyi/device/domain/api/IThingsBoardDomain.java +++ b/src/main/java/com/ruoyi/device/domain/api/IThingsBoardDomain.java @@ -55,4 +55,13 @@ public interface IThingsBoardDomain { * @return 类型安全的遥测数据映射,只包含预定义的遥测数据 */ TelemetryMap getPredefinedDeviceTelemetry(String deviceId); + + /** + * 获取设备所属的网关设备ID + * 通过 ThingsBoard 的 EntityRelation 查询设备与网关的 "Contains" 关系 + * + * @param deviceId 设备ID + * @return 网关设备ID,如果设备不属于任何网关则返回 null + */ + String getDeviceGatewayId(String deviceId); } \ No newline at end of file diff --git a/src/main/java/com/ruoyi/device/domain/impl/AircraftDomainImpl.java b/src/main/java/com/ruoyi/device/domain/impl/AircraftDomainImpl.java index a8e2961..6bac01d 100644 --- a/src/main/java/com/ruoyi/device/domain/impl/AircraftDomainImpl.java +++ b/src/main/java/com/ruoyi/device/domain/impl/AircraftDomainImpl.java @@ -40,6 +40,13 @@ public class AircraftDomainImpl implements IAircraftDomain return AircraftDomainConvert.toModel(entity); } + @Override + public Aircraft selectAircraftByDeviceId(Long deviceId) + { + AircraftEntity entity = aircraftMapper.selectAircraftByDeviceId(deviceId); + return AircraftDomainConvert.toModel(entity); + } + @Override public int insertAircraft(Aircraft aircraft) { diff --git a/src/main/java/com/ruoyi/device/domain/impl/DeviceDomainImpl.java b/src/main/java/com/ruoyi/device/domain/impl/DeviceDomainImpl.java index 57c99a5..8f5e14c 100644 --- a/src/main/java/com/ruoyi/device/domain/impl/DeviceDomainImpl.java +++ b/src/main/java/com/ruoyi/device/domain/impl/DeviceDomainImpl.java @@ -40,6 +40,13 @@ public class DeviceDomainImpl implements IDeviceDomain return DeviceDomainConvert.toModel(entity); } + @Override + public Device selectDeviceByIotDeviceId(String iotDeviceId) + { + DeviceEntity entity = deviceMapper.selectDeviceByIotDeviceId(iotDeviceId); + return DeviceDomainConvert.toModel(entity); + } + @Override public int insertDevice(Device device) { diff --git a/src/main/java/com/ruoyi/device/domain/impl/DockDomainImpl.java b/src/main/java/com/ruoyi/device/domain/impl/DockDomainImpl.java index d15ec49..04f7635 100644 --- a/src/main/java/com/ruoyi/device/domain/impl/DockDomainImpl.java +++ b/src/main/java/com/ruoyi/device/domain/impl/DockDomainImpl.java @@ -40,6 +40,13 @@ public class DockDomainImpl implements IDockDomain return DockDomainConvert.toModel(entity); } + @Override + public Dock selectDockByDeviceId(Long deviceId) + { + DockEntity entity = dockMapper.selectDockByDeviceId(deviceId); + return DockDomainConvert.toModel(entity); + } + @Override public int insertDock(Dock dock) { diff --git a/src/main/java/com/ruoyi/device/domain/impl/ThingsBoardDomainImpl.java b/src/main/java/com/ruoyi/device/domain/impl/ThingsBoardDomainImpl.java index 8768dea..7263b23 100644 --- a/src/main/java/com/ruoyi/device/domain/impl/ThingsBoardDomainImpl.java +++ b/src/main/java/com/ruoyi/device/domain/impl/ThingsBoardDomainImpl.java @@ -12,8 +12,11 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.thingsboard.rest.client.RestClient; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; import java.util.List; import java.util.Optional; @@ -173,6 +176,36 @@ public class ThingsBoardDomainImpl implements IThingsBoardDomain { return predefinedTelemetry; } + @Override + public String getDeviceGatewayId(String deviceId) { + try { + DeviceId id = new DeviceId(UUID.fromString(deviceId)); + + // 查询指向该设备的 "Contains" 关系(网关 -> 设备) + List relations = client.findByTo( + id, + EntityRelation.CONTAINS_TYPE, + RelationTypeGroup.COMMON + ); + + if (relations == null || relations.isEmpty()) { + log.debug("设备 {} 不属于任何网关", deviceId); + return null; + } + + // 获取第一个关系的 from 实体(网关设备) + EntityId gatewayEntityId = relations.get(0).getFrom(); + String gatewayId = gatewayEntityId.getId().toString(); + + log.debug("设备 {} 属于网关 {}", deviceId, gatewayId); + return gatewayId; + + } catch (Exception e) { + log.error("获取设备网关关系失败: deviceId={}, error={}", deviceId, e.getMessage(), e); + return null; + } + } + /** * 解析属性并添加到AttributeMap * 使用延迟注册机制,自动处理所有属性 diff --git a/src/main/java/com/ruoyi/device/domain/model/thingsboard/DeviceInfo.java b/src/main/java/com/ruoyi/device/domain/model/thingsboard/DeviceInfo.java index 5a2ce06..f80ecce 100644 --- a/src/main/java/com/ruoyi/device/domain/model/thingsboard/DeviceInfo.java +++ b/src/main/java/com/ruoyi/device/domain/model/thingsboard/DeviceInfo.java @@ -1,5 +1,6 @@ package com.ruoyi.device.domain.model.thingsboard; +import com.fasterxml.jackson.databind.JsonNode; import org.thingsboard.server.common.data.id.DeviceId; /** @@ -10,12 +11,14 @@ public class DeviceInfo { private final String id; private final String type; private final DeviceId deviceId; + private final JsonNode additionalInfo; - public DeviceInfo(String name, String id, String type, DeviceId deviceId) { + public DeviceInfo(String name, String id, String type, DeviceId deviceId, JsonNode additionalInfo) { this.name = name; this.id = id; this.type = type; this.deviceId = deviceId; + this.additionalInfo = additionalInfo; } public String getName() { @@ -34,12 +37,30 @@ public class DeviceInfo { return deviceId; } + public JsonNode getAdditionalInfo() { + return additionalInfo; + } + + /** + * 判断设备是否为网关 + * 根据 ThingsBoard 标准:检查 additionalInfo 中的 "gateway" 字段 + * + * @return true 如果是网关设备,否则返回 false + */ + public boolean isGateway() { + if (additionalInfo == null) { + return false; + } + return additionalInfo.has("gateway") && additionalInfo.get("gateway").asBoolean(); + } + @Override public String toString() { return "DeviceInfo{" + "name='" + name + '\'' + ", id='" + id + '\'' + ", type='" + type + '\'' + + ", isGateway=" + isGateway() + '}'; } } \ No newline at end of file diff --git a/src/main/java/com/ruoyi/device/domain/model/thingsboard/DeviceIterator.java b/src/main/java/com/ruoyi/device/domain/model/thingsboard/DeviceIterator.java index ed77903..50b96b0 100644 --- a/src/main/java/com/ruoyi/device/domain/model/thingsboard/DeviceIterator.java +++ b/src/main/java/com/ruoyi/device/domain/model/thingsboard/DeviceIterator.java @@ -50,7 +50,8 @@ public class DeviceIterator implements Iterable> { device.getName(), device.getId().getId().toString(), device.getType(), - device.getId() + device.getId(), + device.getAdditionalInfo() )) .toList(); diff --git a/src/main/java/com/ruoyi/device/domain/model/thingsboard/constants/DeviceAttributes.java b/src/main/java/com/ruoyi/device/domain/model/thingsboard/constants/DeviceAttributes.java index 9024138..4c8c2e1 100644 --- a/src/main/java/com/ruoyi/device/domain/model/thingsboard/constants/DeviceAttributes.java +++ b/src/main/java/com/ruoyi/device/domain/model/thingsboard/constants/DeviceAttributes.java @@ -84,6 +84,20 @@ public class DeviceAttributes { } ); + // 机场SN号 - String + public static final AttributeKey DOCK_SN = AttributeKey.of( + "dock_sn", + String.class, + value -> value != null ? value.toString() : null + ); + + // 子设备SN号 - String + public static final AttributeKey SUB_DEVICE_SN = AttributeKey.of( + "sub_device.device_sn", + String.class, + value -> value != null ? value.toString() : null + ); + private DeviceAttributes() { // 工具类,禁止实例化 } @@ -101,7 +115,9 @@ public class DeviceAttributes { LAST_CONNECT_TIME, ACTIVE, LAST_ACTIVITY_TIME, - LAST_DISCONNECT_TIME + LAST_DISCONNECT_TIME, + DOCK_SN, + SUB_DEVICE_SN ); } diff --git a/src/main/java/com/ruoyi/device/mapper/AircraftMapper.java b/src/main/java/com/ruoyi/device/mapper/AircraftMapper.java index b8ac407..2ac1b4a 100644 --- a/src/main/java/com/ruoyi/device/mapper/AircraftMapper.java +++ b/src/main/java/com/ruoyi/device/mapper/AircraftMapper.java @@ -19,6 +19,14 @@ public interface AircraftMapper */ AircraftEntity selectAircraftByAircraftId(Long aircraftId); + /** + * 根据设备主键查询无人机 + * + * @param deviceId 设备主键 + * @return 无人机信息 + */ + AircraftEntity selectAircraftByDeviceId(Long deviceId); + /** * 根据设备主键查询无人机列表 * diff --git a/src/main/java/com/ruoyi/device/mapper/DeviceMapper.java b/src/main/java/com/ruoyi/device/mapper/DeviceMapper.java index fc183d2..ccceeff 100644 --- a/src/main/java/com/ruoyi/device/mapper/DeviceMapper.java +++ b/src/main/java/com/ruoyi/device/mapper/DeviceMapper.java @@ -19,6 +19,14 @@ public interface DeviceMapper */ DeviceEntity selectDeviceByDeviceId(Long deviceId); + /** + * 根据IOT设备ID查询设备 + * + * @param iotDeviceId IOT设备ID + * @return 设备信息 + */ + DeviceEntity selectDeviceByIotDeviceId(String iotDeviceId); + /** * 查询设备列表 * diff --git a/src/main/java/com/ruoyi/device/mapper/DockMapper.java b/src/main/java/com/ruoyi/device/mapper/DockMapper.java index 9cbd420..c5ad0d2 100644 --- a/src/main/java/com/ruoyi/device/mapper/DockMapper.java +++ b/src/main/java/com/ruoyi/device/mapper/DockMapper.java @@ -19,6 +19,14 @@ public interface DockMapper */ DockEntity selectDockByDockId(Long dockId); + /** + * 根据设备主键查询机场 + * + * @param deviceId 设备主键 + * @return 机场信息 + */ + DockEntity selectDockByDeviceId(Long deviceId); + /** * 根据设备主键查询机场列表 * diff --git a/src/main/java/com/ruoyi/device/service/enums/DeviceType.java b/src/main/java/com/ruoyi/device/service/enums/DeviceType.java new file mode 100644 index 0000000..4c5fe80 --- /dev/null +++ b/src/main/java/com/ruoyi/device/service/enums/DeviceType.java @@ -0,0 +1,47 @@ +package com.ruoyi.device.service.enums; + +/** + * 设备类型枚举 + * Service层使用 + * + * @author ruoyi + * @date 2026-01-17 + */ +public enum DeviceType { + + /** + * 无人机 + */ + AIRCRAFT("AIRCRAFT", "无人机"), + + /** + * 机场 + */ + DOCK("DOCK", "机场"), + + /** + * 网关 + */ + GATEWAY("GATEWAY", "网关"); + + private final String code; + private final String description; + + DeviceType(String code, String description) { + this.code = code; + this.description = description; + } + + public String getCode() { + return code; + } + + public String getDescription() { + return description; + } + + @Override + public String toString() { + return code; + } +} \ No newline at end of file diff --git a/src/main/java/com/ruoyi/device/service/impl/SynService.java b/src/main/java/com/ruoyi/device/service/impl/SynService.java index 1883004..92ff19f 100644 --- a/src/main/java/com/ruoyi/device/service/impl/SynService.java +++ b/src/main/java/com/ruoyi/device/service/impl/SynService.java @@ -1,15 +1,27 @@ package com.ruoyi.device.service.impl; +import com.ruoyi.device.domain.api.IAircraftDomain; +import com.ruoyi.device.domain.api.IDeviceDomain; +import com.ruoyi.device.domain.api.IDockAircraftDomain; +import com.ruoyi.device.domain.api.IDockDomain; import com.ruoyi.device.domain.api.IThingsBoardDomain; +import com.ruoyi.device.domain.model.Aircraft; +import com.ruoyi.device.domain.model.Device; +import com.ruoyi.device.domain.model.Dock; +import com.ruoyi.device.domain.model.DockAircraft; import com.ruoyi.device.domain.model.thingsboard.AttributeMap; import com.ruoyi.device.domain.model.thingsboard.DeviceInfo; import com.ruoyi.device.domain.model.thingsboard.constants.DeviceAttributes; +import com.ruoyi.device.service.enums.DeviceType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; import java.util.List; +import java.util.Objects; import java.util.Optional; @Service @@ -19,6 +31,18 @@ public class SynService { private final IThingsBoardDomain iThingsBoardDomain; + @Autowired + private IDeviceDomain deviceDomain; + + @Autowired + private IDockDomain dockDomain; + + @Autowired + private IAircraftDomain aircraftDomain; + + @Autowired + private IDockAircraftDomain dockAircraftDomain; + public SynService(IThingsBoardDomain iThingsBoardDomain) { this.iThingsBoardDomain = iThingsBoardDomain; } @@ -39,32 +63,257 @@ public class SynService { int totalCount = 0; for (List deviceBatch : allDevices) { - for (DeviceInfo device : deviceBatch) { - // 获取设备属性以获取活跃状态 - Boolean activeStatus = false; + for (DeviceInfo deviceInfo : deviceBatch) { try { - AttributeMap attributes = iThingsBoardDomain.getDeviceAttributes(device.getId()); - // 尝试从 AttributeMap 中获取 active 属性 - Optional active = attributes.get(DeviceAttributes.ACTIVE); - if (active.isPresent()) { - activeStatus = active.get(); - } - } catch (Exception e) { - log.debug("获取设备 {} 的活跃状态失败: {}", device.getId(), e.getMessage()); - } + // 获取设备属性 + AttributeMap attributes = iThingsBoardDomain.getDeviceAttributes(deviceInfo.getId()); - log.info("Device Name: {}, Device ID: {}, Device Type: {}, Active: {}", - device.getName(), - device.getId(), - device.getType(), - activeStatus); - totalCount++; + // 判断设备类型 + DeviceType deviceType = determineDeviceType(deviceInfo, attributes); + + // 同步设备表 + Long deviceId = syncDevice(deviceInfo, attributes, deviceType); + + // 根据设备类型进行不同的处理 + if (deviceType == DeviceType.DOCK) { + // 机场:同步机场表 + syncDock(deviceId, deviceInfo.getName()); + + // 获取机场挂载的无人机SN号 + Optional subDeviceSnOpt = attributes.get(DeviceAttributes.SUB_DEVICE_SN); + if (subDeviceSnOpt.isPresent() && StringUtils.hasText(subDeviceSnOpt.get())) { + String aircraftSn = subDeviceSnOpt.get(); + // 通过SN号查找无人机设备 + Device aircraftDevice = findDeviceBySn(aircraftSn); + if (aircraftDevice != null) { + // 同步机场无人机关联 + syncDockAircraft(deviceId, aircraftDevice.getDeviceId()); + } + } + } else if (deviceType == DeviceType.AIRCRAFT) { + // 无人机:同步无人机表 + syncAircraft(deviceId, deviceInfo.getName()); + } + // 网关类型不需要额外处理 + totalCount++; + } catch (Exception e) { + log.error("同步设备失败: deviceId={}, deviceName={}, error={}", + deviceInfo.getId(), deviceInfo.getName(), e.getMessage(), e); + } } } - log.info("========== 定时任务执行完成,共打印 {} 个设备 ==========", totalCount); + log.info("========== 数据同步任务完成,共同步 {} 个设备 ==========", totalCount); } catch (Exception e) { - log.error("定时任务执行失败: {}", e.getMessage(), e); + log.error("数据同步任务执行失败: {}", e.getMessage(), e); + } + } + + /** + * 判断设备类型 + * 优化后的判断逻辑: + * 1. 优先使用 ThingsBoard 标准的 additionalInfo.gateway 字段判断网关 + * 2. 对于非网关设备,通过 dock_sn 属性区分机场和无人机 + * + * @param deviceInfo ThingsBoard设备信息 + * @param attributes 设备属性 + * @return 设备类型 + */ + private DeviceType determineDeviceType(DeviceInfo deviceInfo, AttributeMap attributes) { + String deviceName = deviceInfo.getName(); + + // 1. 使用 ThingsBoard 标准方式判断网关:检查 additionalInfo 中的 gateway 字段 + if (deviceInfo.isGateway()) { + return DeviceType.GATEWAY; + } + + // 2. 非网关设备:通过 dock_sn 属性区分机场和无人机 + Optional dockSnOpt = attributes.get(DeviceAttributes.DOCK_SN); + + if (dockSnOpt.isPresent() && StringUtils.hasText(dockSnOpt.get())) { + String dockSn = dockSnOpt.get(); + // dock_sn 等于设备名称 -> 机场 + // dock_sn 不等于设备名称 -> 无人机(挂载在该机场下) + return deviceName.equals(dockSn) ? DeviceType.DOCK : DeviceType.AIRCRAFT; + } + + // dock_sn 属性不存在或为空,无法判断设备类型 + throw new IllegalStateException("无法确定设备类型:设备 " + deviceName + " 缺少 dock_sn 属性"); + } + + /** + * 同步设备数据 + * + * @param deviceInfo ThingsBoard设备信息 + * @param attributes 设备属性 + * @param deviceType 设备类型 + * @return 设备主键ID + */ + private Long syncDevice(DeviceInfo deviceInfo, AttributeMap attributes, DeviceType deviceType) { + String iotDeviceId = deviceInfo.getId(); + String deviceName = deviceInfo.getName(); + + // 使用 ThingsBoard 标准方式获取网关设备ID(通过 EntityRelation) + String gateway = iThingsBoardDomain.getDeviceGatewayId(iotDeviceId); + + String deviceSn = deviceName; // 使用设备名称作为SN号,网关其实是没有SN号的 + + // 查询设备是否已存在 + Device existingDevice = deviceDomain.selectDeviceByIotDeviceId(iotDeviceId); + + if (existingDevice == null) { + // 设备不存在,插入新设备 + Device newDevice = new Device(); + newDevice.setDeviceName(deviceName); + newDevice.setIotDeviceId(iotDeviceId); + newDevice.setDeviceType(deviceType.getCode()); + newDevice.setDeviceSn(deviceSn); + newDevice.setGateway(gateway); + newDevice.setCreateBy("system"); + + deviceDomain.insertDevice(newDevice); + log.info("插入新设备: iotDeviceId={}, deviceName={}, deviceType={}", iotDeviceId, deviceName, deviceType); + return newDevice.getDeviceId(); + } else { + // 设备已存在,检查是否需要更新 + boolean needUpdate = false; + + if (!Objects.equals(existingDevice.getDeviceName(), deviceName)) { + existingDevice.setDeviceName(deviceName); + needUpdate = true; + } + if (!Objects.equals(existingDevice.getDeviceType(), deviceType.getCode())) { + existingDevice.setDeviceType(deviceType.getCode()); + needUpdate = true; + } + if (!Objects.equals(existingDevice.getDeviceSn(), deviceSn)) { + existingDevice.setDeviceSn(deviceSn); + needUpdate = true; + } + if (!Objects.equals(existingDevice.getGateway(), gateway)) { + existingDevice.setGateway(gateway); + needUpdate = true; + } + + if (needUpdate) { + existingDevice.setUpdateBy("system"); + deviceDomain.updateDevice(existingDevice); + log.info("更新设备: iotDeviceId={}, deviceName={}, deviceType={}", iotDeviceId, deviceName, deviceType); + } + + return existingDevice.getDeviceId(); + } + } + + /** + * 同步机场数据 + * + * @param deviceId 设备主键ID + * @param deviceName 设备名称 + */ + private void syncDock(Long deviceId, String deviceName) { + // 查询机场是否已存在 + Dock existingDock = dockDomain.selectDockByDeviceId(deviceId); + + if (existingDock == null) { + // 机场不存在,插入新机场 + Dock newDock = new Dock(); + newDock.setDockName(deviceName); + newDock.setDeviceId(deviceId); + newDock.setCreateBy("system"); + + dockDomain.insertDock(newDock); + log.info("插入新机场: deviceId={}, dockName={}", deviceId, deviceName); + } + // 机场已存在,无需更新 + } + + /** + * 同步无人机数据 + * + * @param deviceId 设备主键ID + * @param deviceName 设备名称 + * @return 无人机主键ID + */ + private Long syncAircraft(Long deviceId, String deviceName) { + // 查询无人机是否已存在 + Aircraft existingAircraft = aircraftDomain.selectAircraftByDeviceId(deviceId); + + if (existingAircraft == null) { + // 无人机不存在,插入新无人机 + Aircraft newAircraft = new Aircraft(); + newAircraft.setAircraftName(deviceName); + newAircraft.setDeviceId(deviceId); + newAircraft.setCreateBy("system"); + + aircraftDomain.insertAircraft(newAircraft); + log.info("插入新无人机: deviceId={}, aircraftName={}", deviceId, deviceName); + return newAircraft.getAircraftId(); + } + // 无人机已存在,无需更新 + return existingAircraft.getAircraftId(); + } + + /** + * 根据设备SN号查找设备 + * + * @param deviceSn 设备SN号 + * @return 设备信息 + */ + private Device findDeviceBySn(String deviceSn) { + Device queryDevice = new Device(); + queryDevice.setDeviceSn(deviceSn); + List devices = deviceDomain.selectDeviceList(queryDevice); + return (devices != null && !devices.isEmpty()) ? devices.get(0) : null; + } + + /** + * 同步机场无人机关联数据 + * 按照一个机场只会挂载一台无人机的逻辑进行处理 + * + * @param dockDeviceId 机场设备主键ID + * @param aircraftDeviceId 无人机设备主键ID + */ + private void syncDockAircraft(Long dockDeviceId, Long aircraftDeviceId) { + // 获取机场主键 + Dock dock = dockDomain.selectDockByDeviceId(dockDeviceId); + if (dock == null) { + log.warn("机场不存在,无法同步机场无人机关联: dockDeviceId={}", dockDeviceId); + return; + } + + // 获取无人机主键 + Aircraft aircraft = aircraftDomain.selectAircraftByDeviceId(aircraftDeviceId); + if (aircraft == null) { + log.warn("无人机不存在,无法同步机场无人机关联: aircraftDeviceId={}", aircraftDeviceId); + return; + } + + Long dockId = dock.getDockId(); + Long aircraftId = aircraft.getAircraftId(); + + // 查询该机场是否已有关联 + List existingRelations = dockAircraftDomain.selectDockAircraftByDockId(dockId); + + if (existingRelations == null || existingRelations.isEmpty()) { + // 机场没有关联,插入新关联 + DockAircraft newRelation = new DockAircraft(); + newRelation.setDockId(dockId); + newRelation.setAircraftId(aircraftId); + newRelation.setCreateBy("system"); + + dockAircraftDomain.insertDockAircraft(newRelation); + log.info("插入机场无人机关联: dockId={}, aircraftId={}", dockId, aircraftId); + } else { + // 机场已有关联,检查是否需要更新 + DockAircraft existingRelation = existingRelations.get(0); + if (!Objects.equals(existingRelation.getAircraftId(), aircraftId)) { + // 无人机发生变化,更新关联 + existingRelation.setAircraftId(aircraftId); + existingRelation.setUpdateBy("system"); + dockAircraftDomain.updateDockAircraft(existingRelation); + log.info("更新机场无人机关联: dockId={}, aircraftId={}", dockId, aircraftId); + } } } } diff --git a/src/main/resources/mapper/device/AircraftMapper.xml b/src/main/resources/mapper/device/AircraftMapper.xml index cc8bcd5..fb21287 100644 --- a/src/main/resources/mapper/device/AircraftMapper.xml +++ b/src/main/resources/mapper/device/AircraftMapper.xml @@ -26,6 +26,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where aircraft_id = #{aircraftId} + + + + + +