| | |
| | | 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.springframework.scheduling.annotation.Async; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | 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.springblade.core.tool.utils.StringUtil; |
| | | |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Collections; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * 设备信息 服务实现类 |
| | |
| | | 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, GdManageDevicePageParam gdManageDevice) { |
| | |
| | | * @return 同步数量 |
| | | */ |
| | | @Override |
| | | @Async |
| | | @Scheduled(cron = "0 0 0 * * ?") |
| | | public int syncXingtuDevice() throws Exception { |
| | | int total = 0; |
| | | total += syncPilotDevices(); |
| | | // 2.同步机巢设备 |
| | | total += syncAirportDevices(); |
| | | log.info("更新或新增设备"+total); |
| | | // 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); |
| | |
| | | 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); |
| | |
| | | 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) { |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 安全解析字符串为 Double |
| | | * |
| | | * @param value 字符串值 |
| | | * @return Double 或 null |
| | | */ |
| | | private Double parseDouble(String value) { |
| | | if (StringUtil.isBlank(value)) { |
| | | return null; |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 提取区域编码中的末级编码 |
| | | * |
| | | * @param regionCode 区域编码 |
| | | * @return 末级区域编码 |
| | | */ |
| | | private String extractAreaCode(String regionCode) { |
| | | if (StringUtil.isBlank(regionCode)) { |
| | | return null; |
| | |
| | | return regionCode; |
| | | } |
| | | |
| | | /** |
| | | * 解析保险信息并获取最新保险日期 |
| | | * |
| | | * @param insuranceInfo 保险信息JSON |
| | | * @return 保险日期 |
| | | */ |
| | | private Date parseInsuranceDate(String insuranceInfo) { |
| | | if (StringUtil.isBlank(insuranceInfo)) { |
| | | 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(); |