/*
|
* 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 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.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<GdManageDeviceMapper, GdManageDeviceEntity> implements IGdManageDeviceService {
|
|
private final JianXingtuApiService jianXingtuApiService;
|
|
@Override
|
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(GdManageDevicePageParam gdManageDevice) {
|
return baseMapper.selectGdManageDevice(gdManageDevice);
|
}
|
|
@Override
|
public List<GdManageDeviceExcel> exportGdManageDevice(Wrapper<GdManageDeviceEntity> queryWrapper) {
|
List<GdManageDeviceExcel> 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
|
@Scheduled(cron = "0 0 0 * * ?")
|
public int syncXingtuDevice() throws Exception {
|
int total = 0;
|
total += syncPilotDevices();
|
total += syncAirportDevices();
|
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)) {
|
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;
|
}
|
|
/**
|
* 按机场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();
|
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());
|
}
|
}
|
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()));
|
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()));
|
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);
|
}
|
}
|