/* * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the dreamlu.net developer nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * Author: Chill 庄骞 (smallchill@163.com) */ 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.GdXingtuPilotListDTO; import org.sxkj.gd.workorder.entity.GdManageDeviceEntity; import org.sxkj.gd.workorder.param.GdManageDevicePageParam; 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.text.SimpleDateFormat; import java.util.Collections; import java.util.Date; import java.util.List; /** * 设备信息 服务实现类 * * @author lw * @since 2026-01-14 */ @Service @AllArgsConstructor @Slf4j public class GdManageDeviceServiceImpl extends BaseServiceImpl implements IGdManageDeviceService { private final JianXingtuApiService jianXingtuApiService; @Override public IPage selectGdManageDevicePage(IPage page, GdManageDevicePageParam gdManageDevice) { List gdManageDeviceVOS = baseMapper.selectGdManageDevicePage(page, gdManageDevice); return page.setRecords(gdManageDeviceVOS); } @Override public List selectGdManageDevice(GdManageDevicePageParam gdManageDevice) { return baseMapper.selectGdManageDevice(gdManageDevice); } @Override public List exportGdManageDevice(Wrapper queryWrapper) { List gdManageDeviceList = baseMapper.exportGdManageDevice(queryWrapper); // gdManageDeviceList.forEach(gdManageDevice -> { // gdManageDevice.setTypeName(DictCache.getValue(DictEnum.YES_NO, GdManageDevice.getType())); //}); return gdManageDeviceList; } /** * 保存或更新设备信息 * * @param gdManageDeviceEntity * @return * @throws Exception */ @Override public boolean saveOrUpdateDevice(GdManageDeviceEntity gdManageDeviceEntity) throws Exception { // 获取设备位置 生成缓冲区 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 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)) { count++; } } return count; } /** * 同步星图机巢设备并入库 * * @return 新增或更新数量 */ private int syncAirportDevices() throws Exception { R response = jianXingtuApiService.getDeviceAirportList(null); List 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; } /** * 按机场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.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()); } } 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()); 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()); 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 List parseList(R response, Class 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); } }