吉安感知网项目-后端
linwei
2026-02-09 f7b19e697ab9686106b68b48bdff2e8615b4d1bd
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);
   }
}