From 3c9c3db69742fe4d3e69b5619eb52f4ed5f2cfb5 Mon Sep 17 00:00:00 2001
From: rain <1679827795@qq.com>
Date: Wed, 28 Jan 2026 17:19:58 +0800
Subject: [PATCH] 同步获取吉安机巢无人机设备

---
 drone-common/src/main/java/org/sxkj/common/jaxt/JianXingTuApiClient.java                               |   30 ++
 drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/controller/GdManageDeviceController.java    |   11 
 drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/dto/GdXingtuAirportListDTO.java             |  148 +++++++++++
 drone-service/drone-gd/src/main/java/org/sxkj/gd/xingtu/JianXingtuApiService.java                      |   63 ++++
 drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/IGdManageDeviceService.java         |    6 
 drone-service/drone-gd/src/main/java/org/sxkj/gd/GdApplication.java                                    |    4 
 drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/impl/GdManageDeviceServiceImpl.java |  214 ++++++++++++++++
 drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/dto/GdXingtuPilotListDTO.java               |  154 +++++++++++
 drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/dto/GdXingtuFlyTaskSaveDTO.java             |  125 +++++++++
 drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/entity/GdManageDeviceEntity.java            |   11 
 10 files changed, 763 insertions(+), 3 deletions(-)

diff --git a/drone-common/src/main/java/org/sxkj/common/jaxt/JianXingTuApiClient.java b/drone-common/src/main/java/org/sxkj/common/jaxt/JianXingTuApiClient.java
index a20121e..a980370 100644
--- a/drone-common/src/main/java/org/sxkj/common/jaxt/JianXingTuApiClient.java
+++ b/drone-common/src/main/java/org/sxkj/common/jaxt/JianXingTuApiClient.java
@@ -24,9 +24,13 @@
 	 */
 	private static final String GET_DEVICE_LIST_URL_POST = "/webservice/webservice/devicePilot/queryList";
 	/**
-	 * 获设备列表-飞机
+	 * 获设备列表-机巢
 	 */
 	private static final String GET_PLANE_LIST_URL_POST = "/webservice/webservice/deviceAirport/queryList";
+	/**
+	 * 新增飞行任务
+	 */
+	private static final String FLY_TASK_SAVE_URL_POST = "/webservice/webservice/flyTask/save";
 
 	/**
 	 * 获取登录接口路径
@@ -35,4 +39,28 @@
 	public static String getLoginUrl() {
 		return BASE_URL + LOGIN_URL_POST;
 	}
+
+	/**
+	 * 获取设备列表-无人机接口路径
+	 * @return 设备列表-无人机接口路径
+	 */
+	public static String getDevicePilotListUrl() {
+		return BASE_URL + GET_DEVICE_LIST_URL_POST;
+	}
+
+	/**
+	 * 获取设备列表-机巢接口路径
+	 * @return 设备列表-机巢接口路径
+	 */
+	public static String getDeviceAirportListUrl() {
+		return BASE_URL + GET_PLANE_LIST_URL_POST;
+	}
+
+	/**
+	 * 获取新增飞行任务接口路径
+	 * @return 新增飞行任务接口路径
+	 */
+	public static String getFlyTaskSaveUrl() {
+		return BASE_URL + FLY_TASK_SAVE_URL_POST;
+	}
 }
diff --git a/drone-service/drone-gd/src/main/java/org/sxkj/gd/GdApplication.java b/drone-service/drone-gd/src/main/java/org/sxkj/gd/GdApplication.java
index 8bc9c50..33c2687 100644
--- a/drone-service/drone-gd/src/main/java/org/sxkj/gd/GdApplication.java
+++ b/drone-service/drone-gd/src/main/java/org/sxkj/gd/GdApplication.java
@@ -22,6 +22,8 @@
 import org.springframework.boot.web.client.RestTemplateBuilder;
 import org.springframework.cloud.openfeign.EnableFeignClients;
 import org.springframework.context.annotation.Bean;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.web.client.RestTemplate;
 
 /**
@@ -31,6 +33,8 @@
 @BladeCloudApplication
 @EnableFeignClients({"org.sxkj","org.springblade","com.dji.sample"})
 @MapperScan({"org.springblade.**.mapper.**","org.sxkj.**.mapper.**"})
+@EnableScheduling
+@EnableAsync
 public class GdApplication {
 
 	public static void main(String[] args) {
diff --git a/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/controller/GdManageDeviceController.java b/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/controller/GdManageDeviceController.java
index 828b8b7..70e8d9c 100644
--- a/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/controller/GdManageDeviceController.java
+++ b/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/controller/GdManageDeviceController.java
@@ -134,6 +134,17 @@
 		return R.status(gdManageDeviceService.deleteLogic(Func.toLongList(ids)));
 	}
 
+	/**
+	 * 同步星图设备(测试接口)
+	 */
+	@PostMapping("/sync-xingtu")
+	@ApiOperationSupport(order = 8)
+	@ApiOperation(value = "同步星图设备(测试)", notes = "同步无人机和机巢到设备表")
+	public R syncXingtuDevice() throws Exception {
+		int count = gdManageDeviceService.syncXingtuDevice();
+		return R.data(count);
+	}
+
 
 	/**
 	 * 导出数据
diff --git a/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/dto/GdXingtuAirportListDTO.java b/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/dto/GdXingtuAirportListDTO.java
new file mode 100644
index 0000000..9fb67bc
--- /dev/null
+++ b/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/dto/GdXingtuAirportListDTO.java
@@ -0,0 +1,148 @@
+/*
+ *      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.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 星图接口-设备列表(机巢)数据对象
+ */
+@Data
+public class GdXingtuAirportListDTO implements Serializable {
+
+	private static final long serialVersionUID = 1L;
+
+	@ApiModelProperty("主键id")
+	private String id;
+
+	@ApiModelProperty("名称")
+	private String name;
+
+	@ApiModelProperty("型号")
+	private String type;
+
+	@ApiModelProperty("区域编码")
+	private String regionCode;
+
+	@ApiModelProperty("部门id")
+	private String deptId;
+
+	@ApiModelProperty("部门名称")
+	private String deptName;
+
+	@ApiModelProperty("设备序列号")
+	private String snCode;
+
+	@ApiModelProperty("铭牌序列号")
+	private String nameplateSnCode;
+
+	@ApiModelProperty("经度")
+	private String longitude;
+
+	@ApiModelProperty("纬度")
+	private String latitude;
+
+	@ApiModelProperty("高度")
+	private Double height;
+
+	@ApiModelProperty("作业半径")
+	private Double workRadius;
+
+	@ApiModelProperty("安全返航高度")
+	private Double safeReturnHeight;
+
+	@ApiModelProperty("安全作业高度")
+	private Double safeWorkHeight;
+
+	@ApiModelProperty("是否允许飞行")
+	private Integer isAllowFlight;
+
+	@ApiModelProperty("负责人姓名")
+	private String managerName;
+
+	@ApiModelProperty("负责人电话")
+	private String managerMobile;
+
+	@ApiModelProperty("地址")
+	private String address;
+
+	@ApiModelProperty("附件id")
+	private String fileId;
+
+	@ApiModelProperty("附件地址")
+	private String fileUrl;
+
+	@ApiModelProperty("备注")
+	private String remark;
+
+	@ApiModelProperty("是否包含无人机")
+	private Integer isHasPilot;
+
+	@ApiModelProperty("是否四合一模块")
+	private Integer isFourModule;
+
+	@ApiModelProperty("负载序列号")
+	private String loadSnCode;
+
+	@ApiModelProperty("负载类型")
+	private String loadType;
+
+	@ApiModelProperty("无人机序列号")
+	private String pilotSnCode;
+
+	@ApiModelProperty("无人机类型")
+	private String pilotType;
+
+	@ApiModelProperty("是否保险")
+	private Integer isInsurance;
+
+	@ApiModelProperty("保险信息")
+	private String insuranceInfo;
+
+	@ApiModelProperty("状态")
+	private String status;
+
+	@ApiModelProperty("禁飞原因")
+	private String noFlyReason;
+
+	@ApiModelProperty("机巢卡号")
+	private String airportSimCardNumber;
+
+	@ApiModelProperty("机巢流量包")
+	private String airportDataPackage;
+
+	@ApiModelProperty("流量包开始时间")
+	private String dataPackageValidityBegin;
+
+	@ApiModelProperty("流量包结束时间")
+	private String dataPackageValidityEnd;
+
+	@ApiModelProperty("固件版本")
+	private String firmwareVersion;
+
+	@ApiModelProperty("工作空间id")
+	private String workspaceId;
+
+	@ApiModelProperty("当前控制用户id")
+	private String currentControlUserId;
+
+	@ApiModelProperty("负载序号")
+	private String loadIndex;
+}
diff --git a/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/dto/GdXingtuFlyTaskSaveDTO.java b/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/dto/GdXingtuFlyTaskSaveDTO.java
new file mode 100644
index 0000000..f34f497
--- /dev/null
+++ b/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/dto/GdXingtuFlyTaskSaveDTO.java
@@ -0,0 +1,125 @@
+/*
+ *      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.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 星图接口-新增飞行任务请求对象
+ */
+@Data
+public class GdXingtuFlyTaskSaveDTO implements Serializable {
+
+	private static final long serialVersionUID = 1L;
+
+	@ApiModelProperty("任务名称")
+	private String name;
+
+	@ApiModelProperty("机场id")
+	private String airportId;
+
+	@ApiModelProperty("机场名称")
+	private String airportName;
+
+	@ApiModelProperty("巡检类型,字典")
+	private String inspectionType;
+
+	@ApiModelProperty("巡检类型,字典-数组格式")
+	private List<String> inspectionTypeArr;
+
+	@ApiModelProperty("任务类型:定时飞行、航线飞行")
+	private String taskType;
+
+	@ApiModelProperty("定时类型:单次执行、周期执行、自定义执行")
+	private String timingType;
+
+	@ApiModelProperty("单次任务执行时间")
+	private String singleTime;
+
+	@ApiModelProperty("周期(自定义)执行开始日期")
+	private String startDate;
+
+	@ApiModelProperty("周期(自定义)执行结束日期")
+	private String endDate;
+
+	@ApiModelProperty("周期(自定义)执行时间HH:mm:ss格式")
+	private String timeOfDay;
+
+	@ApiModelProperty("间隔周期数")
+	private Integer interval;
+
+	@ApiModelProperty("间隔单位:WEEK/MONTH")
+	private String intervalUnit;
+
+	@ApiModelProperty("周几(1-7)或几号(1-31)")
+	private Integer dayOfPeriod;
+
+	@ApiModelProperty("航线id")
+	private String airlineId;
+
+	@ApiModelProperty("航线名称")
+	private String airlineName;
+
+	@ApiModelProperty("部门id")
+	private Long deptId;
+
+	@ApiModelProperty("部门名称")
+	private String deptName;
+
+	@ApiModelProperty("地区编码,拼接")
+	private String regionCode;
+
+	@ApiModelProperty("安全返航高度")
+	private Integer safeReturnHeight;
+
+	@ApiModelProperty("是否云端录制 0否 1是")
+	private Integer isCloudRecord;
+
+	@ApiModelProperty("是否断点续飞 0否 1是")
+	private Integer isContinueFly;
+
+	@ApiModelProperty("是否开启AI识别 0否 1是")
+	private Integer isAiIdentify;
+
+	@ApiModelProperty("识别时机:实时、后置")
+	private String identifyTiming;
+
+	@ApiModelProperty("算法id,多个逗号分隔")
+	private String algorithmId;
+
+	@ApiModelProperty("识别间隔(秒/次)")
+	private Integer identifyIntervals;
+
+	@ApiModelProperty("是否自动生成工单 0否 1是")
+	private Integer isAutoGenWorkOrder;
+
+	@ApiModelProperty("异常动作配置-相机动作:镜头拍照、广角拍照、红外拍照、全景拍照")
+	private String abnormalCameraAction;
+
+	@ApiModelProperty("异常动作配置-变焦倍数")
+	private Integer abnormalZoomPhotography;
+
+	@ApiModelProperty("异常动作配置-悬停时长")
+	private Integer abnormalHoverDuration;
+
+	@ApiModelProperty("任务状态:草稿、待审核、待执行、执行中、已完成、已取消、审核不通过")
+	private String status;
+}
diff --git a/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/dto/GdXingtuPilotListDTO.java b/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/dto/GdXingtuPilotListDTO.java
new file mode 100644
index 0000000..a107544
--- /dev/null
+++ b/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/dto/GdXingtuPilotListDTO.java
@@ -0,0 +1,154 @@
+/*
+ *      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.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 星图接口-设备列表(无人机)数据对象
+ */
+@Data
+public class GdXingtuPilotListDTO implements Serializable {
+
+	private static final long serialVersionUID = 1L;
+
+	@ApiModelProperty("主键id")
+	private String id;
+
+	@ApiModelProperty("删除标记")
+	private String delFlag;
+
+	@ApiModelProperty("名称")
+	private String name;
+
+	@ApiModelProperty("型号")
+	private String type;
+
+	@ApiModelProperty("区域编码")
+	private String regionCode;
+
+	@ApiModelProperty("部门id")
+	private String deptId;
+
+	@ApiModelProperty("部门名称")
+	private String deptName;
+
+	@ApiModelProperty("设备序列号")
+	private String snCode;
+
+	@ApiModelProperty("经度")
+	private String longitude;
+
+	@ApiModelProperty("纬度")
+	private String latitude;
+
+	@ApiModelProperty("固件版本")
+	private String firmwareVersion;
+
+	@ApiModelProperty("购买时间")
+	private String buyTime;
+
+	@ApiModelProperty("使用人id")
+	private String userId;
+
+	@ApiModelProperty("使用人名称")
+	private String userName;
+
+	@ApiModelProperty("保管人")
+	private String keeper;
+
+	@ApiModelProperty("保管人电话")
+	private String keeperMobile;
+
+	@ApiModelProperty("负载序列号")
+	private String loadSnCode;
+
+	@ApiModelProperty("负载类型")
+	private String loadType;
+
+	@ApiModelProperty("是否喷涂")
+	private Integer isPainting;
+
+	@ApiModelProperty("是否四合一模块")
+	private Integer isFourModule;
+
+	@ApiModelProperty("资质文件id")
+	private String certificateFileId;
+
+	@ApiModelProperty("资质文件地址")
+	private String certificateFileUrl;
+
+	@ApiModelProperty("附件id")
+	private String fileId;
+
+	@ApiModelProperty("附件地址")
+	private String fileUrl;
+
+	@ApiModelProperty("备注")
+	private String remark;
+
+	@ApiModelProperty("是否保险")
+	private Integer isInsurance;
+
+	@ApiModelProperty("保险信息")
+	private String insuranceInfo;
+
+	@ApiModelProperty("直播类型")
+	private String liveType;
+
+	@ApiModelProperty("直播地址")
+	private String liveUrl;
+
+	@ApiModelProperty("AI直播地址")
+	private String liveUrlAi;
+
+	@ApiModelProperty("机巢卡号")
+	private String airportSimCardNumber;
+
+	@ApiModelProperty("机巢流量包")
+	private String airportDataPackage;
+
+	@ApiModelProperty("流量包开始时间")
+	private String dataPackageValidityBegin;
+
+	@ApiModelProperty("流量包结束时间")
+	private String dataPackageValidityEnd;
+
+	@ApiModelProperty("工作空间id")
+	private String workspaceId;
+
+	@ApiModelProperty("状态")
+	private String status;
+
+	@ApiModelProperty("是否带机巢")
+	private Integer isWithDock;
+
+	@ApiModelProperty("父级序列号")
+	private String parentSn;
+
+	@ApiModelProperty("负载序号")
+	private String loadIndex;
+
+	@ApiModelProperty("可控范围")
+	private Integer controlledScope;
+
+	@ApiModelProperty("清晰度")
+	private Integer liveClarity;
+}
diff --git a/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/entity/GdManageDeviceEntity.java b/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/entity/GdManageDeviceEntity.java
index ca58e0e..369f8a2 100644
--- a/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/entity/GdManageDeviceEntity.java
+++ b/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/entity/GdManageDeviceEntity.java
@@ -47,6 +47,17 @@
 	@ApiModelProperty(value = "设备编码")
 	private String deviceSn;
 	/**
+	 * 星图业务Id
+	 */
+	@ApiModelProperty(value = "设备Id(星图业务)")
+	private String airportId;
+	/**
+	 * 行政区域编号
+	 */
+	@ApiModelProperty(value = "行政区域编号")
+	@TableField("area_code")
+	private String areaCode;
+	/**
 	 * 设备型号
 	 */
 	@ApiModelProperty(value = "设备型号")
diff --git a/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/IGdManageDeviceService.java b/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/IGdManageDeviceService.java
index 24cbe81..95cedc9 100644
--- a/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/IGdManageDeviceService.java
+++ b/drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/IGdManageDeviceService.java
@@ -63,4 +63,10 @@
 	 * @return
 	 */
 	boolean saveOrUpdateDevice(GdManageDeviceEntity gdManageDeviceEntity) throws Exception;
+
+	/**
+	 * 同步星图设备(无人机、机巢)
+	 * @return 同步数量
+	 */
+	int syncXingtuDevice() throws Exception;
 }
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 f0b0051..6d3fac9 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,21 +16,33 @@
  */
 package org.sxkj.gd.workorder.service.impl;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+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.sxkj.system.cache.DictCache;
-import org.sxkj.system.enums.DictEnum;
+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;
 
 /**
@@ -40,7 +52,10 @@
  * @since 2026-01-14
  */
 @Service
+@AllArgsConstructor
 public class GdManageDeviceServiceImpl extends BaseServiceImpl<GdManageDeviceMapper, GdManageDeviceEntity> implements IGdManageDeviceService {
+
+	private final JianXingtuApiService jianXingtuApiService;
 
 	@Override
 	public IPage<GdManageDeviceVO> selectGdManageDevicePage(IPage<GdManageDeviceVO> page, GdManageDevicePageParam gdManageDevice) {
@@ -80,4 +95,199 @@
 		}
 		return saveOrUpdate(gdManageDeviceEntity);
 	}
+
+	/**
+	 * 同步星图设备(无人机、机巢)
+	 *
+	 * @return 同步数量
+	 */
+	@Override
+	@Async
+	@Scheduled(cron = "0 0 0 * * ?")
+	public int syncXingtuDevice() throws Exception {
+		int total = 0;
+		total += syncPilotDevices();
+		total += syncAirportDevices();
+		return total;
+	}
+
+	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;
+	}
+
+	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;
+	}
+
+	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);
+	}
+
+	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;
+	}
+
+	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;
+	}
+
+	private Long parseModeCode(String status) {
+		if ("在线".equals(status)) {
+			return 0L;
+		}
+		if ("离线".equals(status)) {
+			return 1L;
+		}
+		return null;
+	}
+
+	private Double parseDouble(String value) {
+		if (StringUtil.isBlank(value)) {
+			return null;
+		}
+		try {
+			return Double.valueOf(value);
+		} catch (Exception ignored) {
+			return null;
+		}
+	}
+
+	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;
+	}
+
+	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;
+		}
+	}
+
+	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);
+	}
 }
diff --git a/drone-service/drone-gd/src/main/java/org/sxkj/gd/xingtu/JianXingtuApiService.java b/drone-service/drone-gd/src/main/java/org/sxkj/gd/xingtu/JianXingtuApiService.java
index 4001dff..1e506ec 100644
--- a/drone-service/drone-gd/src/main/java/org/sxkj/gd/xingtu/JianXingtuApiService.java
+++ b/drone-service/drone-gd/src/main/java/org/sxkj/gd/xingtu/JianXingtuApiService.java
@@ -3,10 +3,15 @@
 import lombok.SneakyThrows;
 import org.springblade.core.redis.cache.BladeRedis;
 import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
 import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Service;
 import org.springframework.web.client.RestTemplate;
 import org.sxkj.common.jaxt.JianXingTuApiClient;
+import org.sxkj.gd.workorder.dto.GdXingtuFlyTaskSaveDTO;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -74,6 +79,64 @@
 	}
 
 	/**
+	 * 设备列表-无人机
+	 * @param name 名称
+	 * @return 接口响应
+	 */
+	public R getDevicePilotList(String name) {
+		String url = JianXingTuApiClient.getDevicePilotListUrl();
+		return postWithAuthHeader(url, buildListParams(name));
+	}
+
+	/**
+	 * 设备列表-机巢
+	 * @param name 名称
+	 * @return 接口响应
+	 */
+	public R getDeviceAirportList(String name) {
+		String url = JianXingTuApiClient.getDeviceAirportListUrl();
+		return postWithAuthHeader(url, buildListParams(name));
+	}
+
+	/**
+	 * 新增飞行任务
+	 * @param param 请求参数
+	 * @return 接口响应
+	 */
+	public R saveFlyTask(GdXingtuFlyTaskSaveDTO param) {
+		String url = JianXingTuApiClient.getFlyTaskSaveUrl();
+		return postWithAuthHeader(url, param);
+	}
+
+	private Map<String, Object> buildListParams(String name) {
+		Map<String, Object> params = new HashMap<>();
+		if (StringUtil.isNotBlank(name)) {
+			params.put("name", name);
+		}
+		return params;
+	}
+
+	private R postWithAuthHeader(String url, Object body) {
+		String token = getToken();
+		if (StringUtil.isBlank(token) || "获取token失败".equals(token)) {
+			return R.fail("获取token失败");
+		}
+		HttpHeaders headers = new HttpHeaders();
+		headers.set("authorization", token);
+
+		HttpEntity<Object> entity = new HttpEntity<>(body, headers);
+		ResponseEntity<R> response = restTemplate.exchange(url, HttpMethod.POST, entity, R.class);
+		if (response.getStatusCode().is2xxSuccessful()) {
+			R responseBody = response.getBody();
+			if (responseBody != null) {
+				return responseBody;
+			}
+			return R.fail("接口返回为空");
+		}
+		return R.fail("请求外部接口失败");
+	}
+
+	/**
 	 * 解析JSON字符串为Map
 	 * @param input JSON字符串
 	 * @return 解析后的Map

--
Gitblit v1.9.3