From f7b19e697ab9686106b68b48bdff2e8615b4d1bd Mon Sep 17 00:00:00 2001
From: linwei <872216696@qq.com>
Date: Mon, 09 Feb 2026 19:28:12 +0800
Subject: [PATCH] 同步机构

---
 drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/impl/GdManageDeviceServiceImpl.java |  413 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 409 insertions(+), 4 deletions(-)

diff --git a/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/impl/GdManageDeviceServiceImpl.java b/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/impl/GdManageDeviceServiceImpl.java
index 34e99ff..2500bf5 100644
--- a/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/impl/GdManageDeviceServiceImpl.java
+++ b/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/impl/GdManageDeviceServiceImpl.java
@@ -16,18 +16,36 @@
  */
 package org.sxkj.gd.workorder.service.impl;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.extern.slf4j.Slf4j;
+import org.sxkj.gd.utils.GdGeoAddressUtil;
 import org.sxkj.gd.utils.GeomUtils;
+import org.sxkj.gd.workorder.dto.GdXingtuAirportListDTO;
+import org.sxkj.gd.workorder.dto.GdXingtuPayloadListDTO;
+import org.sxkj.gd.workorder.dto.GdXingtuPilotListDTO;
 import org.sxkj.gd.workorder.entity.GdManageDeviceEntity;
+import org.sxkj.gd.workorder.entity.GdManageDevicePayloadEntity;
+import org.sxkj.gd.workorder.param.GdManageDevicePageParam;
+import org.sxkj.gd.workorder.service.IGdManageDevicePayloadService;
 import org.sxkj.gd.workorder.vo.GdManageDeviceVO;
 import org.sxkj.gd.workorder.excel.GdManageDeviceExcel;
 import org.sxkj.gd.workorder.mapper.GdManageDeviceMapper;
 import org.sxkj.gd.workorder.service.IGdManageDeviceService;
+import org.sxkj.gd.xingtu.JianXingtuApiService;
 import org.springframework.stereotype.Service;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import lombok.AllArgsConstructor;
 import org.springblade.core.mp.base.BaseServiceImpl;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.StringUtil;
 
-import java.util.List;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * 设备信息 服务实现类
@@ -36,15 +54,21 @@
  * @since 2026-01-14
  */
 @Service
+@AllArgsConstructor
+@Slf4j
 public class GdManageDeviceServiceImpl extends BaseServiceImpl<GdManageDeviceMapper, GdManageDeviceEntity> implements IGdManageDeviceService {
 
+	private final JianXingtuApiService jianXingtuApiService;
+	private final IGdManageDevicePayloadService iGdManageDevicePayloadService;
+
 	@Override
-	public IPage<GdManageDeviceVO> selectGdManageDevicePage(IPage<GdManageDeviceVO> page, GdManageDeviceVO gdManageDevice) {
-		return page.setRecords(baseMapper.selectGdManageDevicePage(page, gdManageDevice));
+	public IPage<GdManageDeviceVO> selectGdManageDevicePage(IPage<GdManageDeviceVO> page, GdManageDevicePageParam gdManageDevice) {
+		List<GdManageDeviceVO> gdManageDeviceVOS = baseMapper.selectGdManageDevicePage(page, gdManageDevice);
+		return page.setRecords(gdManageDeviceVOS);
 	}
 
 	@Override
-	public List<GdManageDeviceVO> selectGdManageDevice(GdManageDeviceVO gdManageDevice) {
+	public List<GdManageDeviceVO> selectGdManageDevice(GdManageDevicePageParam gdManageDevice) {
 		return baseMapper.selectGdManageDevice(gdManageDevice);
 	}
 
@@ -70,7 +94,388 @@
 		if (gdManageDeviceEntity.getLongitude() != null && gdManageDeviceEntity.getLatitude() != null) {
 			String bufferAroundPointAsString = GeomUtils.getBufferAroundPointAsString(gdManageDeviceEntity.getLongitude(), gdManageDeviceEntity.getLatitude(), 5 * 1000);
 			gdManageDeviceEntity.setGeom(bufferAroundPointAsString);
+			String location = GdGeoAddressUtil.getFormattedAddress(gdManageDeviceEntity.getLongitude(), gdManageDeviceEntity.getLatitude());
+			gdManageDeviceEntity.setLocation(location);
 		}
 		return saveOrUpdate(gdManageDeviceEntity);
 	}
+
+	/**
+	 * 同步星图设备(无人机、机巢)
+	 *
+	 * @return 同步数量
+	 */
+	@Override
+	public int syncXingtuDevice() throws Exception {
+		int total = 0;
+		// 2.同步机巢设备
+		total += syncAirportDevices();
+		// 1.同步无人机设备
+		total += syncPilotDevices();
+		log.info("更新或新增设备" + total);
+		return total;
+	}
+
+	/**
+	 * 同步星图无人机设备并入库
+	 *
+	 * @return 新增或更新数量
+	 */
+	private int syncPilotDevices() throws Exception {
+		R response = jianXingtuApiService.getDevicePilotList(null);
+		List<GdXingtuPilotListDTO> items = parseList(response, GdXingtuPilotListDTO.class);
+		if (items.isEmpty()) {
+			return 0;
+		}
+		int count = 0;
+		for (GdXingtuPilotListDTO item : items) {
+			GdManageDeviceEntity entity = buildFromPilot(item);
+			if (entity == null) {
+				continue;
+			}
+			if (saveOrUpdateByAirportId(entity)) {
+				// 同步负载设备
+				List<GdXingtuPayloadListDTO> loadList = item.getLoadList();
+				syncPayloadDevices(loadList);
+				count++;
+			}
+		}
+		return count;
+	}
+
+	/**
+	 * 同步星图机巢设备并入库
+	 *
+	 * @return 新增或更新数量
+	 */
+	private int syncAirportDevices() throws Exception {
+		R response = jianXingtuApiService.getDeviceAirportList(null);
+		List<GdXingtuAirportListDTO> items = parseList(response, GdXingtuAirportListDTO.class);
+		if (items.isEmpty()) {
+			return 0;
+		}
+		int count = 0;
+		for (GdXingtuAirportListDTO item : items) {
+			GdManageDeviceEntity entity = buildFromAirport(item);
+			if (entity == null) {
+				continue;
+			}
+			if (saveOrUpdateByAirportId(entity)) {
+				count++;
+			}
+		}
+		return count;
+	}
+
+	/**
+	 * 同步负载设备
+	 *
+	 * @param loadList 负载设备列表
+	 */
+	private void syncPayloadDevices(List<GdXingtuPayloadListDTO> loadList) throws Exception {
+		// 1. 收集所有负载设备的飞行员序列号,用于后续查询和删除操作
+		Set<String> allPilotSnCodes = new HashSet<>();
+		if (loadList != null && !loadList.isEmpty()) {
+			for (GdXingtuPayloadListDTO load : loadList) {
+				if (load.getPilotSnCode() != null) {
+					allPilotSnCodes.add(load.getPilotSnCode());
+				}
+			}
+		}
+
+		// 2. 获取当前数据库中这些飞行员序列号对应的所有负载设备
+		List<GdManageDevicePayloadEntity> existingPayloads = new ArrayList<>();
+		if (!allPilotSnCodes.isEmpty()) {
+			existingPayloads = iGdManageDevicePayloadService.list(
+				Wrappers.<GdManageDevicePayloadEntity>lambdaQuery().in(GdManageDevicePayloadEntity::getPilotSnCode, allPilotSnCodes)
+			);
+		}
+
+		// 3. 创建现有负载设备的序列号映射,用于快速查找
+		Map<String, GdManageDevicePayloadEntity> existingPayloadMap = new HashMap<>();
+		for (GdManageDevicePayloadEntity payload : existingPayloads) {
+			if (payload.getPilotSnCode() != null && payload.getSnCode() != null) {
+				existingPayloadMap.put(payload.getPilotSnCode() + "_" + payload.getSnCode() + "_" + payload.getName(), payload);
+			}
+		}
+
+		// 4. 处理负载设备列表
+		if (loadList != null && !loadList.isEmpty()) {
+			List<GdManageDevicePayloadEntity> toSaveOrUpdate = new ArrayList<>();
+			Set<String> currentPayloadKeys = new HashSet<>();
+
+			// 对负载设备列表进行去重处理,确保每个负载设备只被处理一次
+			Map<String, GdXingtuPayloadListDTO> uniqueLoadMap = new HashMap<>();
+			for (GdXingtuPayloadListDTO load : loadList) {
+				if (load.getSnCode() != null && load.getPilotSnCode() != null) {
+					String payloadKey = load.getPilotSnCode() + "_" + load.getSnCode() + "_" + load.getName();
+					uniqueLoadMap.put(payloadKey, load);
+				}
+			}
+
+			// 处理去重后的负载设备列表
+			for (GdXingtuPayloadListDTO load : uniqueLoadMap.values()) {
+				String snCode = load.getSnCode();
+				String pilotSnCode1 = load.getPilotSnCode();
+				String name = load.getName();
+				String payloadKey = pilotSnCode1 + "_" + snCode + "_" + name;
+				currentPayloadKeys.add(payloadKey);
+
+				// 检查是否已存在
+				GdManageDevicePayloadEntity existing = existingPayloadMap.remove(payloadKey);
+				if (existing != null) {
+					// 更新现有负载
+					existing.setName(load.getName());
+					existing.setType(load.getType());
+					toSaveOrUpdate.add(existing);
+				} else {
+					// 新增负载
+					GdManageDevicePayloadEntity newPayload = new GdManageDevicePayloadEntity();
+					newPayload.setName(load.getName());
+					newPayload.setType(load.getType());
+					newPayload.setSnCode(snCode);
+					newPayload.setPilotSnCode(pilotSnCode1);
+					// 可以根据需要设置区域编码等其他字段
+					toSaveOrUpdate.add(newPayload);
+				}
+			}
+
+			// 4. 批量保存或更新负载设备
+			if (!toSaveOrUpdate.isEmpty()) {
+				iGdManageDevicePayloadService.saveOrUpdateBatch(toSaveOrUpdate);
+			}
+
+			// 5. 删除数据库中存在但负载列表中不存在的负载设备
+			if (!existingPayloadMap.isEmpty()) {
+				List<Long> toDeleteIds = existingPayloadMap.values().stream()
+					.map(GdManageDevicePayloadEntity::getId)
+					.collect(Collectors.toList());
+				iGdManageDevicePayloadService.removeByIds(toDeleteIds);
+			}
+		} else {
+			// 如果负载列表为空,删除该飞行员序列号对应的所有负载设备
+			if (!existingPayloads.isEmpty()) {
+				List<Long> toDeleteIds = existingPayloads.stream()
+					.map(GdManageDevicePayloadEntity::getId)
+					.collect(Collectors.toList());
+				iGdManageDevicePayloadService.removeByIds(toDeleteIds);
+			}
+		}
+	}
+
+	/**
+	 * 按机场ID保存或更新设备信息
+	 *
+	 * @param entity 设备信息
+	 * @return 是否保存成功
+	 */
+	private boolean saveOrUpdateByAirportId(GdManageDeviceEntity entity) throws Exception {
+		if (StringUtil.isBlank(entity.getAirportId())) {
+			return false;
+		}
+		// 获取设备信息
+		GdManageDeviceEntity exist = lambdaQuery()
+			.eq(GdManageDeviceEntity::getAirportId, entity.getAirportId())
+			.one();
+		// 获取父级设备信息
+		GdManageDeviceEntity parent = getOne(Wrappers.<GdManageDeviceEntity>lambdaQuery().eq(GdManageDeviceEntity::getChildSn, entity.getDeviceSn()));
+		if (exist != null) {
+			entity.setId(exist.getId());
+			if (entity.getLongitude() == null) {
+				entity.setLongitude(exist.getLongitude());
+			}
+			if (entity.getLatitude() == null) {
+				entity.setLatitude(exist.getLatitude());
+			}
+			if (entity.getInsureExpiredTime() == null) {
+				entity.setInsureExpiredTime(exist.getInsureExpiredTime());
+			}
+			// 获取父级设备位置信息
+			if (parent != null) {
+				entity.setLongitude(parent.getLongitude());
+				entity.setLatitude(parent.getLatitude());
+				entity.setHeight(parent.getHeight());
+				entity.setModeCode(Long.valueOf(parent.getStatus()));
+			}
+		}
+		return saveOrUpdateDevice(entity);
+	}
+
+	/**
+	 * 从星图无人机数据构建设备实体
+	 *
+	 * @param item 星图无人机数据
+	 * @return 设备实体
+	 */
+	private GdManageDeviceEntity buildFromPilot(GdXingtuPilotListDTO item) {
+		if (item == null) {
+			return null;
+		}
+		GdManageDeviceEntity entity = new GdManageDeviceEntity();
+		entity.setAirportId(item.getId());
+		entity.setDeviceSn(item.getSnCode());
+		entity.setDeviceName(item.getName());
+		entity.setNickname(item.getName());
+		entity.setDeviceType(1);
+		entity.setLongitude(parseDouble(item.getLongitude()));
+		entity.setLatitude(parseDouble(item.getLatitude()));
+		entity.setFirmwareVersion(item.getFirmwareVersion());
+		entity.setModeCode(parseModeCode(item.getStatus()));
+		entity.setInsureExpiredTime(parseInsuranceDate(item.getInsuranceInfo()));
+		entity.setAreaCode(extractAreaCode(item.getRegionCode()));
+		entity.setIsWithDock(item.getIsWithDock());
+		entity.setCreateDept(item.getDeptId());
+		entity.setDevicePayload(
+			Optional.ofNullable(item.getLoadList())
+				.orElse(Collections.emptyList())
+				.stream()
+				.filter(Objects::nonNull)
+				.map(load -> load.getName())
+				.filter(Objects::nonNull)
+				.distinct()  // 添加去重逻辑
+				.collect(Collectors.joining(","))
+		);
+
+		return entity;
+	}
+
+	/**
+	 * 从星图机巢数据构建设备实体
+	 *
+	 * @param item 星图机巢数据
+	 * @return 设备实体
+	 */
+	private GdManageDeviceEntity buildFromAirport(GdXingtuAirportListDTO item) {
+		if (item == null) {
+			return null;
+		}
+		GdManageDeviceEntity entity = new GdManageDeviceEntity();
+		entity.setAirportId(item.getId());
+		entity.setDeviceSn(item.getSnCode());
+		entity.setDeviceName(item.getName());
+		entity.setNickname(item.getName());
+		entity.setDeviceType(0);
+		entity.setLongitude(parseDouble(item.getLongitude()));
+		entity.setLatitude(parseDouble(item.getLatitude()));
+		entity.setFirmwareVersion(item.getFirmwareVersion());
+		entity.setChildSn(item.getPilotSnCode());
+		entity.setModeCode(parseModeCode(item.getStatus()));
+		entity.setInsureExpiredTime(parseInsuranceDate(item.getInsuranceInfo()));
+		entity.setAreaCode(extractAreaCode(item.getRegionCode()));
+		entity.setHeight(item.getHeight());
+		entity.setCreateDept(item.getDeptId());
+		return entity;
+	}
+
+	/**
+	 * 将设备在线状态转换为模式码
+	 *
+	 * @param status 状态文本
+	 * @return 模式码
+	 */
+	private Long parseModeCode(String status) {
+		if ("在线".equals(status)) {
+			return 0L;
+		}
+		if ("离线".equals(status)) {
+			return 1L;
+		}
+		return null;
+	}
+
+	/**
+	 * 安全解析字符串为 Double
+	 *
+	 * @param value 字符串值
+	 * @return Double 或 null
+	 */
+	private Double parseDouble(String value) {
+		if (StringUtil.isBlank(value)) {
+			return null;
+		}
+		try {
+			return Double.valueOf(value);
+		} catch (Exception ignored) {
+			return null;
+		}
+	}
+
+	/**
+	 * 提取区域编码中的末级编码
+	 *
+	 * @param regionCode 区域编码
+	 * @return 末级区域编码
+	 */
+	private String extractAreaCode(String regionCode) {
+		if (StringUtil.isBlank(regionCode)) {
+			return null;
+		}
+		String[] parts = regionCode.split(",");
+		if (parts.length == 1) {
+			parts = regionCode.split("-");
+		}
+		for (int i = parts.length - 1; i >= 0; i--) {
+			if (StringUtil.isNotBlank(parts[i])) {
+				return parts[i];
+			}
+		}
+		return regionCode;
+	}
+
+	/**
+	 * 解析保险信息并获取最新保险日期
+	 *
+	 * @param insuranceInfo 保险信息JSON
+	 * @return 保险日期
+	 */
+	private Date parseInsuranceDate(String insuranceInfo) {
+		if (StringUtil.isBlank(insuranceInfo)) {
+			return null;
+		}
+		try {
+			JSONArray array = JSON.parseArray(insuranceInfo);
+			if (array == null || array.isEmpty()) {
+				return null;
+			}
+			JSONObject last = array.getJSONObject(array.size() - 1);
+			if (last == null) {
+				return null;
+			}
+			Object dateValue = last.get("isInsuranceDate");
+			String dateStr = null;
+			if (dateValue instanceof JSONArray) {
+				JSONArray dateArray = (JSONArray) dateValue;
+				if (!dateArray.isEmpty()) {
+					dateStr = dateArray.getString(dateArray.size() - 1);
+				}
+			} else if (dateValue != null) {
+				dateStr = String.valueOf(dateValue);
+			}
+			if (StringUtil.isBlank(dateStr)) {
+				return null;
+			}
+			SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
+			return format.parse(dateStr);
+		} catch (Exception ignored) {
+			return null;
+		}
+	}
+
+	/**
+	 * 解析星图接口返回的列表数据
+	 *
+	 * @param response 接口响应
+	 * @param clazz    目标类型
+	 * @return 列表数据
+	 */
+	private <T> List<T> parseList(R response, Class<T> clazz) {
+		if (response == null || !response.isSuccess() || response.getData() == null) {
+			return Collections.emptyList();
+		}
+		Object data = response.getData();
+		if (data instanceof String && StringUtil.isBlank((String) data)) {
+			return Collections.emptyList();
+		}
+		return JSON.parseArray(JSON.toJSONString(data), clazz);
+	}
 }

--
Gitblit v1.9.3