吉安感知网项目-后端
rain
2026-01-28 3c9c3db69742fe4d3e69b5619eb52f4ed5f2cfb5
同步获取吉安机巢无人机设备
7 files modified
3 files added
766 ■■■■■ changed files
drone-common/src/main/java/org/sxkj/common/jaxt/JianXingTuApiClient.java 30 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/GdApplication.java 4 ●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/controller/GdManageDeviceController.java 11 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/dto/GdXingtuAirportListDTO.java 148 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/dto/GdXingtuFlyTaskSaveDTO.java 125 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/dto/GdXingtuPilotListDTO.java 154 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/entity/GdManageDeviceEntity.java 11 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/IGdManageDeviceService.java 6 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/service/impl/GdManageDeviceServiceImpl.java 214 ●●●●● patch | view | raw | blame | history
drone-service/drone-gd/src/main/java/org/sxkj/gd/xingtu/JianXingtuApiService.java 63 ●●●●● patch | view | raw | blame | history
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;
    }
}
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) {
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);
    }
    /**
     * 导出数据
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/dto/GdXingtuAirportListDTO.java
New file
@@ -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;
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/dto/GdXingtuFlyTaskSaveDTO.java
New file
@@ -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;
}
drone-service/drone-gd/src/main/java/org/sxkj/gd/workorder/dto/GdXingtuPilotListDTO.java
New file
@@ -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;
}
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 = "设备型号")
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;
}
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);
    }
}
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