diff --git a/README.md b/README.md
index 88e0338..7281c80 100644
--- a/README.md
+++ b/README.md
@@ -93,7 +93,15 @@ redis-server.exe --service-uninstall
# 启动前端
## 1. 在frontend目录中执行
```
-#npm install
+npm install
+
+npm install --save-dev cross-env
+
+npx update-browserslist-db@latest
+
+在 package.json
+ "serve": "cross-env NODE_OPTIONS=--openssl-legacy-provider vue-cli-service serve",
+
```
## 2. 拷贝resource目录中的dt-sdk到node-modules目录
## 3. 编译前端代码
diff --git a/backend/Skyeye-sys-dev/skyeye-service-manager/pom.xml b/backend/Skyeye-sys-dev/skyeye-service-manager/pom.xml
index 57e0701..68e6f3d 100644
--- a/backend/Skyeye-sys-dev/skyeye-service-manager/pom.xml
+++ b/backend/Skyeye-sys-dev/skyeye-service-manager/pom.xml
@@ -12,6 +12,11 @@
skyeye-service-manager
+
+ com.alibaba.fastjson2
+ fastjson2
+ 2.0.60
+
com.zhangy
diff --git a/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/jm/service/impl/JmAirlinePlanServiceImpl.java b/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/jm/service/impl/JmAirlinePlanServiceImpl.java
index 2ba8fce..51fb19f 100644
--- a/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/jm/service/impl/JmAirlinePlanServiceImpl.java
+++ b/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/jm/service/impl/JmAirlinePlanServiceImpl.java
@@ -1,6 +1,7 @@
package com.zhangy.skyeye.jm.service.impl;
import cn.hutool.core.bean.BeanUtil;
+import com.alibaba.fastjson2.JSON;
import com.zhangy.skyeye.common.extend.exception.ServiceException;
import com.zhangy.skyeye.common.extend.util.ObjectUtil;
import com.zhangy.skyeye.device.consts.PayloadTypeEnum;
@@ -18,14 +19,17 @@ import com.zhangy.skyeye.py.service.IPyAirlineService;
import com.zhangy.skyeye.sar.consts.SarImageModeEnum;
import com.zhangy.skyeye.sar.dto.SarFlightPlanDTO;
import com.zhangy.skyeye.sar.util.SpotlightPlanner;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
+import java.util.stream.Collectors;
/**
* 航线规划
*/
+@Slf4j
@Service
public class JmAirlinePlanServiceImpl implements JmAirlinePlanService {
@@ -38,6 +42,8 @@ public class JmAirlinePlanServiceImpl implements JmAirlinePlanService {
@Override
public Map> plan(JmJobModeEnum jobMode, SarImageModeEnum imageMode, Integer targetType,
List uavList, List> pointList) {
+ log.info("航线规划参数:{}||{}||{}||{}|{}", jobMode, imageMode, targetType,
+ JSON.toJSONString(uavList), JSON.toJSONString(pointList));
checkParam(jobMode, imageMode, targetType);
// 非航线模式需要调算法生成航线,需要从缓存取sar坐标
Map> airlineGroup = null;
@@ -56,8 +62,6 @@ public class JmAirlinePlanServiceImpl implements JmAirlinePlanService {
*
* @param jobMode
* @param imageMode
- * @param uavList
- * @param pointList
*/
private void checkParam(JmJobModeEnum jobMode, SarImageModeEnum imageMode, Integer targetType) {
if (imageMode == SarImageModeEnum.JS) {
@@ -73,7 +77,7 @@ public class JmAirlinePlanServiceImpl implements JmAirlinePlanService {
/**
* 聚束模式
*
- * @param uav 无人机
+ * @param uav 无人机
* @param points 目标点
* @return 航线
*/
@@ -90,7 +94,7 @@ public class JmAirlinePlanServiceImpl implements JmAirlinePlanService {
uav.setStartLon(startLon);
uav.setStartLat(startLat);
JmJobPoint home = new JmJobPoint(startLon, startLat);
- for (List targets: points) {
+ for (List targets : points) {
JmJobPoint target = targets.get(0);
if (target == null) {
continue;
@@ -107,9 +111,8 @@ public class JmAirlinePlanServiceImpl implements JmAirlinePlanService {
/**
* 聚束模式
*
- * @param uav 无人机
- * @param home 起飞点
- * @param point 目标点
+ * @param uav 无人机
+ * @param home 起飞点
* @return 航线
*/
public JmAirline planJs(JmJobUav uav, JmJobPoint home, JmJobPoint target) {
@@ -119,7 +122,7 @@ public class JmAirlinePlanServiceImpl implements JmAirlinePlanService {
home.getLongitude(), home.getLatitude(),
uav.getHeight(), sar.getTheta(), sar.getDirection());
JmAirline airline = new JmAirline();
- airline.setFlightType((byte)0);
+ airline.setFlightType((byte) 0);
double height = plan.getHeight();
airline.setFlightStartLon(plan.getPowerOnLon());
airline.setFlightStartLat(plan.getPowerOnLat());
@@ -162,54 +165,79 @@ public class JmAirlinePlanServiceImpl implements JmAirlinePlanService {
* 转为航线算法参数
*/
private PyAirlineParamDTO toKtkxParam(List> pointList, List uavList) {
- List pyPointList = new ArrayList<>();
+ log.info("开始转换 PyAirlineParamDTO,pointList 大小: {}, uavList 大小: {}",
+ pointList.size(), uavList.size());
+ // 所有无人机共享相同的目标点集(扁平化所有区域的点)
+ List allPoints = pointList.stream()
+ .flatMap(List::stream)
+ .collect(Collectors.toList());
+ // 转换为 Python 需要的 double[][] 坐标格式(经度在前,纬度在后)
+ double[][] coords = allPoints.stream()
+ .map(p -> new double[]{p.getLongitude(), p.getLatitude()})
+ .toArray(double[][]::new);
+ log.info("提取到 {} 个目标点坐标", coords.length);
+
+ List pyTargets = new ArrayList<>();
List pyUavList = new ArrayList<>();
for (int i = 0; i < uavList.size(); i++) {
- JmJobUav u = uavList.get(i);
- // 区域
- List points = pointList.get(i);
- double[][] coords = points.stream()
- .map(point -> new double[] { point.getLongitude(), point.getLatitude() })
- .toArray(double[][]::new);
- pyPointList.add(new PyAirlineTargetDTO(i, coords));
-
- // 载荷
- JmJobPayload sar = u.getPayloadList()
- .stream()
- .filter(jp -> {
- Long payloadId = jp.getPayloadId();
- SkyeyePayload p = payloadService.getOne(payloadId);
- if (p != null && p.getType().equals(PayloadTypeEnum.SAR.getCode())) {
- jp.setIp(p.getIp());
- return true;
- }
- return false;
- })
- .findFirst()
- .orElseThrow( () -> ServiceException.errorLog("存在无人机缺少sar类型载荷"));
-
- PyAirlineUavDTO uav = BeanUtil.copyProperties(u, PyAirlineUavDTO.class);
- JmSarStatusDTO statusDTO = payloadService.getLastStatus(sar.getIp());
- double startLon = statusDTO.getLongitude();
- double startLat = statusDTO.getLatitude();
- if (u.getStartAltitude() == null) {
- u.setStartAltitude((double) statusDTO.getAltitude());
+ JmJobUav uav = uavList.get(i);
+ // 1. 为当前无人机创建目标(共享坐标,但 target id 不同)
+ pyTargets.add(new PyAirlineTargetDTO(i, coords));
+ // 2. 获取 SAR 载荷(必须存在,否则抛异常)
+ JmJobPayload sarPayload = findSarPayload(uav);
+ String sarIp = sarPayload.getIp(); // 已在 findSarPayload 中设置
+ // 3. 获取载荷最新状态(用于起始位置)
+ JmSarStatusDTO status = payloadService.getLastStatus(sarIp);
+ if (status == null) {
+ throw ServiceException.errorLog("无法获取 SAR载荷的最新状态");
}
- uav.setId(u.getUavId());
- uav.setStartCoord(new double[] {startLon, startLat});
- uav.setEndCoord(new double[] {startLon, startLat});
- uav.setConstraint(u.getHeight());
- PyAirlinePayloadDTO payload = BeanUtil.copyProperties(sar, PyAirlinePayloadDTO.class);
- payload.setType(PayloadTypeEnum.SAR.getCode());
- uav.setPayload(payload);
- pyUavList.add(uav);
+ // 4. 如果起飞高度为空,则使用载荷当前高度
+ if (uav.getStartAltitude() == null) {
+ uav.setStartAltitude((double) status.getAltitude());
+ log.info("无人机 {} 起飞高度为空,已使用载荷当前高度: {}", uav.getUavId(), uav.getStartAltitude());
+ }
+ // 5. 构建 Python UAV DTO
+ PyAirlineUavDTO pyUav = BeanUtil.copyProperties(uav, PyAirlineUavDTO.class);
+ pyUav.setId(uav.getUavId());
+ pyUav.setStartCoord(new double[]{status.getLongitude(), status.getLatitude()});
+ pyUav.setEndCoord(new double[]{status.getLongitude(), status.getLatitude()}); // 目前起终点相同
+ pyUav.setConstraint(uav.getHeight());
+ // 6. 构建 Payload DTO
+ PyAirlinePayloadDTO payloadDto = BeanUtil.copyProperties(sarPayload, PyAirlinePayloadDTO.class);
+ payloadDto.setType(PayloadTypeEnum.SAR.getCode());
+ pyUav.setPayload(payloadDto);
+ pyUavList.add(pyUav);
}
- PyAirlineUavDTO[] uavs = pyUavList.toArray(new PyAirlineUavDTO[pyUavList.size()]);
- PyAirlineTargetDTO[] targets = pyPointList.toArray(new PyAirlineTargetDTO[pyPointList.size()]);
-
+ // 转换为数组(Python 端需要数组格式)
+ PyAirlineTargetDTO[] targetListArray = pyTargets.toArray(new PyAirlineTargetDTO[0]);
+ PyAirlineUavDTO[] uavListArray = pyUavList.toArray(new PyAirlineUavDTO[0]);
PyAirlineParamDTO param = new PyAirlineParamDTO();
- param.setTargets(targets);
- param.setUavs(uavs);
+ param.setTargets(targetListArray);
+ param.setUavs(uavListArray);
+ log.info("转换完成,生成 PyAirlineParamDTO:{} 个目标组,{} 架无人机",
+ targetListArray.length, uavListArray.length);
return param;
}
+
+ /**
+ * 从无人机载荷列表中查找 SAR 类型载荷,并设置 IP
+ * @param uav 无人机对象
+ * @return SAR 载荷
+ * @throws ServiceException 如果没有找到 SAR 载荷
+ */
+ private JmJobPayload findSarPayload(JmJobUav uav) {
+ return uav.getPayloadList().stream()
+ .filter(payload -> {
+ Long payloadId = payload.getPayloadId();
+ SkyeyePayload skyeyePayload = payloadService.getOne(payloadId);
+ if (skyeyePayload != null && PayloadTypeEnum.SAR.getCode().equals(skyeyePayload.getType())) {
+ payload.setIp(skyeyePayload.getIp());
+ return true;
+ }
+ return false;
+ })
+ .findFirst()
+ .orElseThrow(() -> ServiceException.errorLog(
+ "存在无人机缺少sar类型载荷"));
+ }
}
diff --git a/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/jm/service/impl/JmJobServiceImpl.java b/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/jm/service/impl/JmJobServiceImpl.java
index f606576..286ac7f 100644
--- a/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/jm/service/impl/JmJobServiceImpl.java
+++ b/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/jm/service/impl/JmJobServiceImpl.java
@@ -2,6 +2,7 @@ package com.zhangy.skyeye.jm.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
+import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zhangy.skyeye.common.extend.enums.EnumUtil;
@@ -36,10 +37,6 @@ import com.zhangy.skyeye.sar.enums.SarIMUStatusEnum;
import com.zhangy.skyeye.sar.service.ISarControlService;
import com.zhangy.skyeye.sar.service.ISarMtiPointService;
import com.zhangy.skyeye.sar.service.ISarMtiTrailService;
-//import com.zhangy.skyeye.smp.dto.SmpSubscriptResDTO;
-//import com.zhangy.skyeye.smp.dto.SmpWayPointDTO;
-//import com.zhangy.skyeye.smp.service.ISmpSubscriptService;
-//import com.zhangy.skyeye.smp.service.ISmpWayPointService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -56,7 +53,7 @@ import java.util.stream.Collectors;
@Slf4j
@Service
public class JmJobServiceImpl implements JmJobService {
-
+
@Autowired
private JmJobMapper jobMapper;
@Autowired
@@ -69,43 +66,30 @@ public class JmJobServiceImpl implements JmJobService {
private JmJobStatusService jobStatusService;
@Autowired
private JmJobExecService jmJobExecService;
-
-// @Autowired
-// private ISmpWayPointService smpWayPointService;
-// @Autowired
-// private ISmpSubscriptService smpSubscriptService;
-
@Autowired
private ISarControlService sarControlService;
@Autowired
private ISarMtiPointService sarMtiPointService;
@Autowired
private ISarMtiTrailService sarMtiTrailService;
-
@Autowired
private IPayloadService payloadService;
@Autowired
private IUavService uavService;
-
@Autowired
private SysFileTypeService fileTypeService;
-
- @Autowired
- private IPyAirlineService ktkxService;
-
@Autowired
private QuartzService quartzService;
-
@Autowired
private JmAirlinePlanService jmAirlinePlanService;
-
+
@Override
public IPage selectPage(JmJobPageDTO param) {
IPage jobPage = jobMapper.selectPage(param);
loadDetail(param.getUavId(), jobPage.getRecords());
return jobPage;
}
-
+
@Override
public List selectList(JmJobQueryDTO param) {
List list = jobMapper.selectList(param);
@@ -114,8 +98,7 @@ public class JmJobServiceImpl implements JmJobService {
}
@Override
- public List selectExecJobs(JmJobQueryDTO param)
- {
+ public List selectExecJobs(JmJobQueryDTO param) {
List list = jobMapper.selectExecJobs(param);
loadDetail(param.getUavId(), list);
return list;
@@ -165,6 +148,7 @@ public class JmJobServiceImpl implements JmJobService {
@Transactional
@Override
public JmJobDTO save(JmJobModeEnum jobMode, JmJobDTO e) {
+ log.info("保存任务参数:{}||{}", JSON.toJSONString(jobMode), JSON.toJSONString(e));
SarImageModeEnum imageMode = EnumUtil.parseEx(SarImageModeEnum.class, e.getImageMode());
// 非航线模式需要调算法生成航线,需要从缓存取sar坐标
Map> airlineGroup = jmAirlinePlanService.plan(jobMode, imageMode, e.getTargetType(),
@@ -210,7 +194,7 @@ public class JmJobServiceImpl implements JmJobService {
*/
private JmJobPayload checkAndSetPayload(List payloadParamList) {
JmJobPayload sar = null;
- for(JmJobPayload p : payloadParamList) {
+ for (JmJobPayload p : payloadParamList) {
Long payloadId = p.getPayloadId();
SkyeyePayload payload = payloadService.getOne(payloadId);
if (payload == null) {
@@ -308,7 +292,7 @@ public class JmJobServiceImpl implements JmJobService {
com.zhangy.skyeye.common.extend.util.BeanUtil.validationEx(airline);
});
}
-
+
@Transactional
@Override
public int delete(Long... ids) {
@@ -347,7 +331,7 @@ public class JmJobServiceImpl implements JmJobService {
@Transactional
@Override
public void start(JmJobDTO job) {
- // SarBackImageFrameDTO.i = 1;
+ // SarBackImageFrameDTO.i = 1;
// 校验无人机、载荷
jobStatusService.checkDeviceForNewJob(job.getUavList());
// 保存任务状态
@@ -375,6 +359,7 @@ public class JmJobServiceImpl implements JmJobService {
/**
* 起飞 kmz
+ *
* @param job
*/
private void startKmz(JmJobDTO job) {
@@ -447,7 +432,7 @@ public class JmJobServiceImpl implements JmJobService {
controlParam.setIp(ip);
sarControlService.sendUdp(controlParam);
// 标记缓存状态,确保断连重新发送请求时不会重复执行
- // uav.setSarStatus(ExecStatusEnum.OVER);
+ // uav.setSarStatus(ExecStatusEnum.OVER);
});
// 删除缓存任务信息
jobStatusService.remove(id);
diff --git a/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/py/service/impl/PyAirlineServiceImpl.java b/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/py/service/impl/PyAirlineServiceImpl.java
index 28ac9d9..331eafe 100644
--- a/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/py/service/impl/PyAirlineServiceImpl.java
+++ b/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/java/com/zhangy/skyeye/py/service/impl/PyAirlineServiceImpl.java
@@ -13,6 +13,7 @@ import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
+import com.alibaba.fastjson2.*;
import java.io.IOException;
import java.net.ConnectException;
@@ -37,6 +38,9 @@ public class PyAirlineServiceImpl implements IPyAirlineService {
@Value("${skyeye.py.ktkxUrl}")
private String url;
+ @Value("${skyeye.java.ktkxUrl}")
+ private String javaUrl;
+
// 判断是否为空,并剔除无需执行任务的无人机
private boolean checkEmpty(Map uavMap) {
if (uavMap == null || uavMap.size() == 0) {
@@ -72,7 +76,17 @@ public class PyAirlineServiceImpl implements IPyAirlineService {
@Override
public Map> getAirline(PyAirlineParamDTO param) {
- HttpResponse httpResponse = null;
+ log.info("请求航线规划算法服务参数:{}", JSON.toJSONString(param));
+// HttpResponse post;
+// try {
+// post = HttpUtil.post(javaUrl, null, param);
+// } catch (IOException e) {
+// throw new RuntimeException(e);
+// }
+// PyAirlineResponse pyAirlineResponse;
+// pyAirlineResponse = JsonUtil.parse(post.body(), PyAirlineResponse.class);
+// log.info("请求航线规划算法服务响应:{}",JSON.toJSONString(pyAirlineResponse));
+ HttpResponse httpResponse;
try {
httpResponse = HttpUtil.post(url, null, param);
} catch (ConnectException ex) {
@@ -82,18 +96,20 @@ public class PyAirlineServiceImpl implements IPyAirlineService {
}
PyAirlineResponse response;
response = JsonUtil.parse(httpResponse.body(), PyAirlineResponse.class);
+ log.info("请求航线规划算法服务响应:{}", JSON.toJSONString(response));
int responseCode = httpResponse.statusCode();
if (responseCode >= 400) {
- log.warn("调用航线规划算法错误["+ responseCode + "]:" + response.getMessage() + ",参数:" + JsonUtil.toString(param));
- throw ServiceException.noLog("调用航线规划算法错误["+ responseCode + "]:" + response.getMessage());
+ log.warn("调用航线规划算法错误[{}]:{},参数:{}", responseCode, response.getMessage(), JsonUtil.toString(param));
+ throw ServiceException.noLog("调用航线规划算法错误[" + responseCode + "]:" + response.getMessage());
}
Map uavMap = response.getData();
+ log.info("航线规划算法结果:{}", JSON.toJSONString(uavMap));
if (checkEmpty(uavMap)) {
if ("success".endsWith(response.getMessage())) {
throw ServiceException.noLog("无法生成航线,可能飞行区域超过25平方公里");
}
- log.warn("调用航线规划算法未返回数据["+ responseCode + "]:" + response.getMessage() + ",参数:" + JsonUtil.toString(param));
- throw ServiceException.noLog("调用航线规划算法未返回数据["+ responseCode + "]:" + response.getMessage());
+ log.warn("调用航线规划算法未返回数据[{}]:{},参数:{}", responseCode, response.getMessage(), JsonUtil.toString(param));
+ throw ServiceException.noLog("调用航线规划算法未返回数据[" + responseCode + "]:" + response.getMessage());
}
Map> map = new HashMap<>();
diff --git a/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/resources/application-dev.yml b/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/resources/application-dev.yml
index 7a94824..583287c 100644
--- a/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/resources/application-dev.yml
+++ b/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/resources/application-dev.yml
@@ -84,6 +84,8 @@ skyeye:
py:
ktkxUrl: http://127.0.0.1:18090/ktkx/UavPlanning/SAR
detectUrl: http://127.0.0.1:18091/ktkx/detect/cpu/SARCoord
+ java:
+ ktkxUrl: http://127.0.0.1:9117/ktkx/UavPlanning/SAR
weather:
cityCode: 101120201
diff --git a/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/resources/mapping/jm/JmJobMapping.xml b/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/resources/mapping/jm/JmJobMapping.xml
index 7e89e02..5f74079 100644
--- a/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/resources/mapping/jm/JmJobMapping.xml
+++ b/backend/Skyeye-sys-dev/skyeye-service-manager/src/main/resources/mapping/jm/JmJobMapping.xml
@@ -35,7 +35,7 @@