Browse Source

轨迹回放

S0025136190 1 year ago
parent
commit
7162c80542
31 changed files with 1150 additions and 51 deletions
  1. 31 0
      Backend/cloud-sdk/src/main/java/com/dji/sdk/cloudapi/device/WpmzVersion.java
  2. 1 0
      Backend/cloud-sdk/src/main/java/com/dji/sdk/mqtt/osd/OsdRouter.java
  3. 1 1
      Backend/cloud-sdk/src/main/java/com/dji/sdk/mqtt/state/RcStateDataKeyEnum.java
  4. 4 0
      Backend/cloud-sdk/src/main/java/com/dji/sdk/mqtt/state/StateRouter.java
  5. 10 8
      Backend/sample/src/main/java/com/dji/sample/common/util/CoordinateUtil.java
  6. 6 0
      Backend/sample/src/main/java/com/dji/sample/common/util/UserRequest.java
  7. 8 0
      Backend/sample/src/main/java/com/dji/sample/component/redis/RedisConst.java
  8. 2 0
      Backend/sample/src/main/java/com/dji/sample/component/websocket/model/BizCodeEnum.java
  9. 27 0
      Backend/sample/src/main/java/com/dji/sample/configuration/CustomConfiguration.java
  10. 9 12
      Backend/sample/src/main/java/com/dji/sample/manage/model/common/AMap.java
  11. 0 1
      Backend/sample/src/main/java/com/dji/sample/manage/model/enums/DeviceStatusEnum.java
  12. 21 0
      Backend/sample/src/main/java/com/dji/sample/manage/service/IDeviceRedisService.java
  13. 3 0
      Backend/sample/src/main/java/com/dji/sample/manage/service/IDeviceService.java
  14. 50 0
      Backend/sample/src/main/java/com/dji/sample/manage/service/impl/DeviceRedisServiceImpl.java
  15. 10 0
      Backend/sample/src/main/java/com/dji/sample/manage/service/impl/DeviceServiceImpl.java
  16. 183 3
      Backend/sample/src/main/java/com/dji/sample/manage/service/impl/SDKDeviceService.java
  17. 56 0
      Backend/sample/src/main/java/com/dji/sample/map/controller/FlightTaskController.java
  18. 12 0
      Backend/sample/src/main/java/com/dji/sample/map/dao/IFlightTaskMapper.java
  19. 12 0
      Backend/sample/src/main/java/com/dji/sample/map/dao/IFlightTrackMapper.java
  20. 54 0
      Backend/sample/src/main/java/com/dji/sample/map/model/dto/FlightTaskDTO.java
  21. 39 0
      Backend/sample/src/main/java/com/dji/sample/map/model/dto/FlightTrackDTO.java
  22. 71 0
      Backend/sample/src/main/java/com/dji/sample/map/model/entity/FlightTaskEntity.java
  23. 51 0
      Backend/sample/src/main/java/com/dji/sample/map/model/entity/FlightTrackEntity.java
  24. 45 0
      Backend/sample/src/main/java/com/dji/sample/map/model/enums/FlightPointTypeEnum.java
  25. 28 0
      Backend/sample/src/main/java/com/dji/sample/map/model/param/FlightTaskQueryParam.java
  26. 58 0
      Backend/sample/src/main/java/com/dji/sample/map/service/IFlightTrackTaskService.java
  27. 300 0
      Backend/sample/src/main/java/com/dji/sample/map/service/impl/FlightTrackTaskServiceImpl.java
  28. 3 0
      Backend/sample/src/main/java/com/dji/sample/media/service/IFileService.java
  29. 47 23
      Backend/sample/src/main/java/com/dji/sample/media/service/impl/FileServiceImpl.java
  30. 8 3
      Backend/sample/src/main/resources/application.yml
  31. 0 0
      Web/src/vendors/jswebrtc.min.js

+ 31 - 0
Backend/cloud-sdk/src/main/java/com/dji/sdk/cloudapi/device/WpmzVersion.java

@@ -0,0 +1,31 @@
+package com.dji.sdk.cloudapi.device;
+
+/**
+ * @author hqjiang
+ * @version 1.0
+ * @date 2024/7/26
+ */
+public class WpmzVersion {
+
+    private String wpmzVersion;
+
+    public WpmzVersion() {
+    }
+
+    @Override
+    public String toString() {
+        return "WpmzVersion{" +
+                "wpmzVersion='" + wpmzVersion + '\'' +
+                '}';
+    }
+
+    public String getWpmzVersion() {
+        return wpmzVersion;
+    }
+
+    public WpmzVersion setWpmzVersion(String wpmzVersion) {
+        this.wpmzVersion = wpmzVersion;
+        return this;
+    }
+
+}

+ 1 - 0
Backend/cloud-sdk/src/main/java/com/dji/sdk/mqtt/osd/OsdRouter.java

@@ -48,6 +48,7 @@ public class OsdRouter {
                     GatewayManager gateway = SDKManager.getDeviceSDK(response.getGateway());
                     OsdDeviceTypeEnum typeEnum = OsdDeviceTypeEnum.find(gateway.getType(), response.getFrom().equals(response.getGateway()));
                     Map<String, Object> data = (Map<String, Object>) response.getData();
+                    System.out.println("=====================OsdRcDrone:" + data.toString());
                     if (!typeEnum.isGateway()) {
                         List payloadData = (List) data.getOrDefault(PayloadModelConst.PAYLOAD_KEY, new ArrayList<>());
                         PayloadModelConst.getAllIndexWithPosition().stream().filter(data::containsKey)

+ 1 - 1
Backend/cloud-sdk/src/main/java/com/dji/sdk/mqtt/state/RcStateDataKeyEnum.java

@@ -26,7 +26,7 @@ public enum RcStateDataKeyEnum {
 
     PAYLOAD_FIRMWARE(PayloadModelConst.getAllModelWithPosition(), PayloadFirmwareVersion.class),
 
-//    WPMZ_VERSION(Set.of("wpmz_version"),DockDroneWpmzVersion.class)
+    WPMZ_VERSION(Set.of("wpmz_version"),WpmzVersion.class)
     ;
 
     private final Set<String> keys;

+ 4 - 0
Backend/cloud-sdk/src/main/java/com/dji/sdk/mqtt/state/StateRouter.java

@@ -45,6 +45,10 @@ public class StateRouter {
                         TopicStateRequest response = Common.getObjectMapper().readValue((byte[]) source.getPayload(), new TypeReference<TopicStateRequest>() {});
                         String topic = String.valueOf(source.getHeaders().get(MqttHeaders.RECEIVED_TOPIC));
                         String from = topic.substring((THING_MODEL_PRE + PRODUCT).length(), topic.indexOf(STATE_SUF));
+                        Set<String> keys = ((Map<String, Object>) response.getData()).keySet();
+                        if(keys.contains("cameras")) {
+                            System.out.println("================cameras:" + response.getData().toString());
+                        }
                         return response.setFrom(from)
                                 .setData(Common.getObjectMapper().convertValue(response.getData(), getTypeReference(response.getGateway(), response.getData())));
                     } catch (IOException e) {

+ 10 - 8
Backend/sample/src/main/java/com/dji/sample/common/util/CoordinateUtil.java

@@ -83,6 +83,14 @@ public class CoordinateUtil {
      */
     private static double ee = 0.00669342162296594323;
 
+    public static double checkValidVal(double value) {
+        String logStr = String.valueOf(value);
+        if(logStr.indexOf("E") > 0) {
+           return 0d;
+        }
+        return value;
+    }
+
     /**
      * 经纬度 GPS转高德
      *
@@ -91,14 +99,8 @@ public class CoordinateUtil {
      * @return 转化后的经纬度坐标
      */
     public static AMap transform(double wgLon, double wgLat) {
-        String logStr = String.valueOf(wgLon);
-        if(logStr.indexOf("E") > 0) {
-            wgLon = Double.valueOf(logStr.substring(0, logStr.indexOf(".") + 6));
-        }
-        String latStr = String.valueOf(wgLat);
-        if(latStr.indexOf("E") > 0) {
-            wgLat = Double.valueOf(latStr.substring(0, latStr.indexOf(".") + 6));
-        }
+        wgLon = checkValidVal(wgLon);
+        wgLat = checkValidVal(wgLat);
 
         if (outOfChina(wgLat, wgLon)) {
             return new AMap(wgLon, wgLat);

+ 6 - 0
Backend/sample/src/main/java/com/dji/sample/common/util/UserRequest.java

@@ -14,7 +14,13 @@ import static com.dji.sample.component.AuthInterceptor.TOKEN_CLAIM;
  */
 public class UserRequest {
     public static CustomClaim getCurrentUser() {
+        if(RequestContextHolder.getRequestAttributes() == null) {
+            return null;
+        }
         HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+        if(request == null) {
+            return null;
+        }
         CustomClaim customClaim = (CustomClaim)request.getAttribute(TOKEN_CLAIM);
         return customClaim;
     }

+ 8 - 0
Backend/sample/src/main/java/com/dji/sample/component/redis/RedisConst.java

@@ -62,4 +62,12 @@ public final class RedisConst {
     public static final String FILE_UPLOADING_PREFIX = "file_uploading" + DELIMITER;
 
     public static final String DRONE_CONTROL_PREFiX = "control_source" + DELIMITER;
+    //飞行任务(轨迹)
+    public static final String DRONE_FLIGHT_TASK = "drone_flight_task" + DELIMITER;
+    //飞行航点采集
+    public static final String DRONE_LAST_TRACK = "drone_last_track" + DELIMITER;
+    //Home点
+    public static final String DRONE_HOME = "drone_home" + DELIMITER;
+    //home 经纬度过期时间
+    public static final Integer DRONE_HOME_ALIVE_SECOND = 3600;
 }

+ 2 - 0
Backend/sample/src/main/java/com/dji/sample/component/websocket/model/BizCodeEnum.java

@@ -79,6 +79,8 @@ public enum BizCodeEnum {
 
     FLIGHT_AREAS_UPDATE("flight_areas_update"),
 
+    HOME_CHANGE("home_change"),
+
     ;
 
     private String code;

+ 27 - 0
Backend/sample/src/main/java/com/dji/sample/configuration/CustomConfiguration.java

@@ -0,0 +1,27 @@
+package com.dji.sample.configuration;
+
+import com.dji.sdk.cloudapi.storage.OssTypeEnum;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author hqjiang
+ * @version 0.1
+ * @date 2024/7/24
+ */
+@ConfigurationProperties(prefix = "custom-config")
+@Component
+public class CustomConfiguration {
+
+    /**
+     * 航点采集频次
+     */
+    public static int frequency;
+
+    public void setFrequency(int frequency) {
+        CustomConfiguration.frequency = frequency;
+    }
+}
+
+
+

+ 9 - 12
Backend/sample/src/main/java/com/dji/sample/manage/model/common/AMap.java

@@ -1,11 +1,20 @@
 package com.dji.sample.manage.model.common;
 
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
 /**
  * 高德经纬度类
  * @author hqjiang
  * @version 1.0
  * @date 2024/7/2
  */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
 public class AMap {
     /**
      * 经度
@@ -17,16 +26,4 @@ public class AMap {
      */
     private double latitude;
 
-    public AMap(double longitude, double latitude) {
-        this.longitude = longitude;
-        this.latitude = latitude;
-    }
-
-    public double getLongitude() {
-        return longitude;
-    }
-
-    public double getLatitude() {
-        return latitude;
-    }
 }

+ 0 - 1
Backend/sample/src/main/java/com/dji/sample/manage/model/enums/DeviceStatusEnum.java

@@ -84,7 +84,6 @@ public enum DeviceStatusEnum {
         return val;
     }
 
-    @JsonValue
     public String getText() {
         return text;
     }

+ 21 - 0
Backend/sample/src/main/java/com/dji/sample/manage/service/IDeviceRedisService.java

@@ -1,7 +1,10 @@
 package com.dji.sample.manage.service;
 
 import com.dji.sample.component.mqtt.model.EventsReceiver;
+import com.dji.sample.manage.model.common.AMap;
 import com.dji.sample.manage.model.dto.DeviceDTO;
+import com.dji.sample.map.model.dto.FlightTaskDTO;
+import com.dji.sample.map.model.entity.FlightTrackEntity;
 import com.dji.sdk.cloudapi.firmware.OtaProgress;
 
 import java.util.Optional;
@@ -109,4 +112,22 @@ public interface IDeviceRedisService {
     void gatewayOffline(String gatewaySn);
 
     void subDeviceOffline(String deviceSn);
+
+    void setDroneFlightTask(String deviceSn, FlightTaskDTO flightTaskDTO);
+
+    Optional<FlightTaskDTO> getDroneFlightTask(String sn);
+
+    Boolean delDroneFlightTask(String sn);
+
+    void setLastDroneTrack(String deviceSn, FlightTrackEntity flightTrackEntity);
+
+    Optional<FlightTrackEntity> getLastDroneTrack(String sn);
+
+    Boolean delLastDroneTrack(String sn);
+
+    void setDroneHomeChange(String deviceSn, AMap homePoint);
+
+    Optional<AMap> getDroneHomeChange(String sn);
+
+    Boolean delDroneHomeChange(String sn);
 }

+ 3 - 0
Backend/sample/src/main/java/com/dji/sample/manage/service/IDeviceService.java

@@ -2,6 +2,7 @@ package com.dji.sample.manage.service;
 
 import com.dji.sample.common.model.CustomClaim;
 import com.dji.sample.component.websocket.model.BizCodeEnum;
+import com.dji.sample.manage.model.common.AMap;
 import com.dji.sample.manage.model.dto.DeviceDTO;
 import com.dji.sample.manage.model.dto.DeviceFirmwareUpgradeDTO;
 import com.dji.sample.manage.model.dto.TopologyDeviceDTO;
@@ -210,4 +211,6 @@ public interface IDeviceService {
     void pushOsdDataToWeb(String workspaceId, BizCodeEnum codeEnum, String sn, Object data);
 
     void updateFlightControl(DeviceDTO gateway, ControlSourceEnum controlSource);
+
+    void updateHome(DeviceDTO drone, AMap homePoint);
 }

+ 50 - 0
Backend/sample/src/main/java/com/dji/sample/manage/service/impl/DeviceRedisServiceImpl.java

@@ -3,9 +3,12 @@ package com.dji.sample.manage.service.impl;
 import com.dji.sample.component.mqtt.model.EventsReceiver;
 import com.dji.sample.component.redis.RedisConst;
 import com.dji.sample.component.redis.RedisOpsUtils;
+import com.dji.sample.manage.model.common.AMap;
 import com.dji.sample.manage.model.dto.DeviceDTO;
 import com.dji.sample.manage.service.ICapacityCameraService;
 import com.dji.sample.manage.service.IDeviceRedisService;
+import com.dji.sample.map.model.dto.FlightTaskDTO;
+import com.dji.sample.map.model.entity.FlightTrackEntity;
 import com.dji.sdk.cloudapi.firmware.OtaProgress;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -106,4 +109,51 @@ public class DeviceRedisServiceImpl implements IDeviceRedisService {
         delHmsKeysBySn(deviceSn);
         capacityCameraService.deleteCapacityCameraByDeviceSn(deviceSn);
     }
+
+    @Override
+    public void setDroneFlightTask(String deviceSn, FlightTaskDTO flightTaskDTO) {
+        RedisOpsUtils.setWithExpire(RedisConst.DRONE_FLIGHT_TASK + deviceSn, flightTaskDTO, RedisConst.DEVICE_ALIVE_SECOND);
+    }
+
+    @Override
+    public Optional<FlightTaskDTO> getDroneFlightTask(String sn) {
+        return Optional.ofNullable((FlightTaskDTO) RedisOpsUtils.get(RedisConst.DRONE_FLIGHT_TASK + sn));
+    }
+
+    @Override
+    public Boolean delDroneFlightTask(String sn) {
+        return RedisOpsUtils.del(RedisConst.DRONE_FLIGHT_TASK + sn);
+    }
+
+    @Override
+    public void setLastDroneTrack(String deviceSn, FlightTrackEntity flightTrackEntity) {
+        RedisOpsUtils.setWithExpire(RedisConst.DRONE_LAST_TRACK + deviceSn, flightTrackEntity, RedisConst.DEVICE_ALIVE_SECOND);
+    }
+
+    @Override
+    public Optional<FlightTrackEntity> getLastDroneTrack(String sn) {
+        return Optional.ofNullable((FlightTrackEntity) RedisOpsUtils.get(RedisConst.DRONE_LAST_TRACK + sn));
+    }
+
+    @Override
+    public Boolean delLastDroneTrack(String sn) {
+        return RedisOpsUtils.del(RedisConst.DRONE_LAST_TRACK + sn);
+    }
+
+    @Override
+    public void setDroneHomeChange(String deviceSn, AMap homePoint) {
+        RedisOpsUtils.setWithExpire(RedisConst.DRONE_HOME + deviceSn, homePoint, RedisConst.DRONE_HOME_ALIVE_SECOND);
+    }
+
+    @Override
+    public Optional<AMap> getDroneHomeChange(String sn) {
+        return Optional.ofNullable((AMap) RedisOpsUtils.get(RedisConst.DRONE_HOME + sn));
+    }
+
+    @Override
+    public Boolean delDroneHomeChange(String sn) {
+        return RedisOpsUtils.del(RedisConst.DRONE_HOME + sn);
+    }
+
+
 }

+ 10 - 0
Backend/sample/src/main/java/com/dji/sample/manage/service/impl/DeviceServiceImpl.java

@@ -10,6 +10,7 @@ import com.dji.sample.component.websocket.model.BizCodeEnum;
 import com.dji.sample.component.websocket.service.IWebSocketMessageService;
 import com.dji.sample.control.model.enums.DroneAuthorityEnum;
 import com.dji.sample.manage.dao.IDeviceMapper;
+import com.dji.sample.manage.model.common.AMap;
 import com.dji.sample.manage.model.dto.*;
 import com.dji.sample.manage.model.entity.DeviceEntity;
 import com.dji.sample.manage.model.enums.DeviceFirmwareStatusEnum;
@@ -708,6 +709,15 @@ public class DeviceServiceImpl implements IDeviceService {
                         .build());
     }
 
+    @Override
+    public void updateHome(DeviceDTO drone, AMap homePoint) {
+        deviceRedisService.setDroneHomeChange(drone.getDeviceSn(),homePoint);
+
+        webSocketMessageService.sendBatch(drone.getWorkspaceId(), UserTypeEnum.WEB.getVal(),
+                BizCodeEnum.HOME_CHANGE.getCode(),
+                homePoint);
+    }
+
     /**
      * Convert device data transfer object into database entity object.
      * @param dto

+ 183 - 3
Backend/sample/src/main/java/com/dji/sample/manage/service/impl/SDKDeviceService.java

@@ -1,7 +1,12 @@
 package com.dji.sample.manage.service.impl;
 
+import cn.hutool.core.date.DateUtil;
+import com.dji.sample.common.util.CoordinateUtil;
+import com.dji.sample.common.util.UserRequest;
 import com.dji.sample.component.websocket.model.BizCodeEnum;
 import com.dji.sample.component.websocket.service.IWebSocketMessageService;
+import com.dji.sample.configuration.CustomConfiguration;
+import com.dji.sample.manage.model.common.AMap;
 import com.dji.sample.manage.model.dto.DeviceDTO;
 import com.dji.sample.manage.model.dto.DevicePayloadReceiver;
 import com.dji.sample.manage.model.enums.DeviceFirmwareStatusEnum;
@@ -10,6 +15,12 @@ import com.dji.sample.manage.service.IDeviceDictionaryService;
 import com.dji.sample.manage.service.IDevicePayloadService;
 import com.dji.sample.manage.service.IDeviceRedisService;
 import com.dji.sample.manage.service.IDeviceService;
+import com.dji.sample.map.model.dto.FlightTaskDTO;
+import com.dji.sample.map.model.dto.FlightTrackDTO;
+import com.dji.sample.map.model.entity.FlightTaskEntity;
+import com.dji.sample.map.model.entity.FlightTrackEntity;
+import com.dji.sample.map.model.enums.FlightPointTypeEnum;
+import com.dji.sample.map.service.IFlightTrackTaskService;
 import com.dji.sdk.cloudapi.device.*;
 import com.dji.sdk.cloudapi.device.api.AbstractDeviceService;
 import com.dji.sdk.cloudapi.tsa.DeviceIconUrl;
@@ -23,11 +34,14 @@ import com.dji.sdk.mqtt.status.TopicStatusRequest;
 import com.dji.sdk.mqtt.status.TopicStatusResponse;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.support.AbstractCacheManager;
 import org.springframework.messaging.MessageHeaders;
 import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
 
 import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.Date;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
@@ -57,6 +71,9 @@ public class SDKDeviceService extends AbstractDeviceService {
     @Autowired
     private IDevicePayloadService devicePayloadService;
 
+    @Autowired
+    private IFlightTrackTaskService flightTaskService;
+
     @Override
     public TopicStatusResponse<MqttReply> updateTopoOnline(TopicStatusRequest<UpdateTopo> request, MessageHeaders headers) {
         UpdateTopoSubDevice updateTopoSubDevice = request.getData().getSubDevices().get(0);
@@ -238,6 +255,164 @@ public class SDKDeviceService extends AbstractDeviceService {
                         .setHorizontalSpeed(data.getHorizontalSpeed())
                         .setVerticalSpeed(data.getVerticalSpeed()));
         deviceService.pushOsdDataToWeb(device.getWorkspaceId(), BizCodeEnum.DEVICE_OSD, from, data);
+        //添加航点轨迹信息
+        toAddFilghtPoint(device, data);
+
+    }
+
+    private void toAddFilghtPoint(DeviceDTO device,OsdRcDrone data) {
+
+        switch (data.getModeCode()) {
+            case TAKEOFF_FINISHED:
+            case MANUAL:
+            case TAKEOFF_AUTO:
+            case WAYLINE:
+            case PANORAMIC_SHOT:
+            case ACTIVE_TRACK:
+            case ADS_B_AVOIDANCE:
+            case RETURN_AUTO:
+            case LIVE_FLIGHT_CONTROLS:
+            case LANDING_THREE_PROPELLER:
+                //添加飞行轨迹
+                addFlightPoint(device,data);
+                break;
+            case LANDING_AUTO:
+            case LANDING_FORCED:
+                //飞行结束
+
+                //添加飞行轨迹
+                FlightTaskDTO task = addFlightPoint(device,data);
+                //更新飞行任务
+                if(task != null) {
+                    updateFlightTask(task);
+                }
+                //移除redis
+                deviceRedisService.delDroneFlightTask(device.getDeviceSn());
+                break;
+
+        }
+    }
+
+    private FlightTaskDTO addFlightPoint(DeviceDTO device,OsdRcDrone data) {
+        synchronized (device.getDeviceSn().intern()) {
+            Optional<FlightTrackEntity> lastPoint = deviceRedisService.getLastDroneTrack(device.getDeviceSn());
+            long curTime = System.currentTimeMillis();
+            boolean isAdd = false;
+            if (!lastPoint.isPresent()) {
+                isAdd = true;
+                log.info("添加飞行轨迹: 首次记录,workspaceID:" + device.getWorkspaceId() + ",sn:" + device.getDeviceSn()
+                        + ",飞行器状态:" + data.getModeCode().name() + ",经度:" + data.getLongitude() + ",维度:" + data.getLatitude()
+                        + "高度:" + data.getHeight());
+
+            } else {
+                long btwTime = curTime - lastPoint.get().getCreateTime();
+                log.info("添加飞行轨迹: workspaceID:" + device.getWorkspaceId() + ",sn:" + device.getDeviceSn() + "当前时间:" + curTime  + "上次添加时间:" + lastPoint.get().getCreateTime()
+                        + ",间隔时间(毫秒):" + btwTime + "是否添加航点:" + (btwTime >= CustomConfiguration.frequency * 1000));
+                if(btwTime >= CustomConfiguration.frequency * 1000) {
+                    isAdd = true;
+                    log.info("添加飞行轨迹: workspaceID:" + device.getWorkspaceId() + ",sn:" + device.getDeviceSn()
+                            + ",间隔时间(毫秒):" + btwTime + ",采集频率(秒)" + CustomConfiguration.frequency
+                            + ",飞行器状态:" + data.getModeCode().name() + ",经度:" + data.getLongitude() + ",维度:" + data.getLatitude()
+                            + "高度:" + data.getHeight());
+                }
+                if(isSamePoint(data,lastPoint.get())) {
+                    log.info("添加飞行轨迹:workspaceID:" + device.getWorkspaceId() + ",sn:" + device.getDeviceSn() +
+                            "相同坐标,不做记录" + data.toString());
+                    isAdd = false;
+                }
+            }
+            if(isAdd) {
+                //获取飞行任务(轨迹)
+                FlightTaskDTO task = getFlightTask(device, data);
+                log.info("获取飞行轨迹任务:" + task.toString());
+                //添加Home信息
+                if(!lastPoint.isPresent()) {
+                    Optional<AMap> homeOpt = deviceRedisService.getDroneHomeChange(device.getDeviceSn());
+                    if(homeOpt.isPresent()) {
+                        FlightTrackEntity flightTrackEntity = FlightTrackEntity.builder()
+                                .taskId(task.getId())
+                                .modeCode(data.getModeCode().getCode())
+                                .longitude(CoordinateUtil.checkValidVal(homeOpt.get().getLongitude()))
+                                .latitude(CoordinateUtil.checkValidVal(homeOpt.get().getLatitude()))
+                                .type(FlightPointTypeEnum.HOME.getType())
+                                .createTime(System.currentTimeMillis()).build();
+                        flightTaskService.addHomePoint(flightTrackEntity);
+                    }
+                }
+                //添加轨迹信息
+                FlightTrackEntity flightTrackEntity = FlightTrackEntity.builder()
+                        .taskId(task.getId())
+                        .modeCode(data.getModeCode().getCode())
+                        .longitude(data.getLongitude().doubleValue())
+                        .latitude(data.getLatitude().doubleValue())
+                        .altitude(data.getHeight().doubleValue())
+                        .elevation(data.getElevation().doubleValue())
+                        .type(FlightPointTypeEnum.HAND.getType())
+                        .createTime(System.currentTimeMillis()).build();
+                flightTaskService.addFlightPoint(flightTrackEntity);
+                log.info("添加轨迹完成: task:" + task.getTaskName());
+                //记录添加时间
+                deviceRedisService.setLastDroneTrack(device.getDeviceSn(), flightTrackEntity);
+                return task;
+            }
+            return null;
+        }
+    }
+
+    private boolean isSamePoint(OsdRcDrone data,FlightTrackEntity lastPoint) {
+        return data.getLongitude().doubleValue() == lastPoint.getLongitude().doubleValue()
+                && data.getLatitude().doubleValue() == lastPoint.getLatitude().doubleValue()
+                && data.getHeight().doubleValue() == lastPoint.getAltitude().doubleValue()
+                && data.getElevation().doubleValue() == lastPoint.getElevation().doubleValue();
+    }
+
+    private int updateFlightTask(FlightTaskDTO task) {
+        if(task != null && task.getId() != null) {
+            log.info("飞行结束 更新轨迹任务: " + task.toString());
+            long endTime = System.currentTimeMillis();
+            long beginTime = task.getBeginTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
+            long flyTime = endTime  - beginTime;
+            FlightTaskEntity entity = flightTaskService.dtoToEntity(task);
+            entity.setEndTime(endTime);
+            entity.setFlyTime(flyTime);
+            entity.setUpdateTime(endTime);
+            return flightTaskService.updateFlightTask(entity);
+        }
+        return 0;
+    }
+
+    private FlightTaskDTO getFlightTask(DeviceDTO device,OsdRcDrone data) {
+        //获取任务名称
+        FlightTaskDTO flightTaskDTO = null;
+        Optional<FlightTaskDTO> opt = deviceRedisService.getDroneFlightTask(device.getDeviceSn());
+        if(opt.isPresent()) {
+            return opt.get();
+        } else {
+            //查询当天未完成的任务
+            flightTaskDTO = flightTaskService.getCurrentFlightTask(device.getWorkspaceId(),device.getDeviceSn());
+        }
+        if(flightTaskDTO == null) {
+            Date curTime = new Date();
+            String taskName = getTaskName(curTime, device.getDeviceSn());
+            flightTaskDTO = flightTaskService.createFlightTask(FlightTaskEntity.builder()
+                    .taskName(taskName)
+                    .workspaceId(device.getWorkspaceId())
+                    .deviceSn(device.getDeviceSn())
+                    .deviceName(device.getDeviceName())
+                    .payload(device.getPayloadsList() == null ? null : device.getPayloadsList().get(0).getPayloadName())
+                    .beginTime(curTime.getTime())
+                    .createTime(curTime.getTime())
+                    .username(UserRequest.getCurrentUser() != null ? UserRequest.getCurrentUser().getUsername() : "system")
+                    .build());
+            deviceRedisService.setDroneFlightTask(device.getDeviceSn(),flightTaskDTO);
+        }
+        return flightTaskDTO;
+    }
+
+    //飞行器sn yyyy-MM-dd HH:mm:ss
+    private String getTaskName(Date curTime,String droneSn) {
+        String format = DateUtil.format(curTime, "yyyy-MM-dd HH:mm:ss");
+        return droneSn + " " + format;
     }
 
     @Override
@@ -325,12 +500,17 @@ public class SDKDeviceService extends AbstractDeviceService {
         if (deviceOpt.isEmpty()) {
             return;
         }
-        Optional<DeviceDTO> dockOpt = deviceRedisService.getDeviceOnline(request.getGateway());
-        if (dockOpt.isEmpty()) {
+        Optional<DeviceDTO> rcOpt = deviceRedisService.getDeviceOnline(request.getGateway());
+        if (rcOpt.isEmpty()) {
             return;
         }
 
-        deviceService.updateFlightControl(dockOpt.get(), request.getData().getControlSource());
+        //home点更新
+        deviceService.updateHome(deviceOpt.get(), AMap.builder()
+                .longitude(CoordinateUtil.checkValidVal(request.getData().getHomeLongitude()))
+                .latitude(CoordinateUtil.checkValidVal(request.getData().getHomeLatitude()))
+                .build());
+        deviceService.updateFlightControl(rcOpt.get(), request.getData().getControlSource());
         devicePayloadService.updatePayloadControl(deviceOpt.get(),
                 request.getData().getPayloads().stream()
                         .map(p -> DevicePayloadReceiver.builder()

+ 56 - 0
Backend/sample/src/main/java/com/dji/sample/map/controller/FlightTaskController.java

@@ -0,0 +1,56 @@
+package com.dji.sample.map.controller;
+
+import com.dji.sample.map.model.dto.FlightTaskDTO;
+import com.dji.sample.map.model.dto.FlightTrackDTO;
+import com.dji.sample.map.model.param.FlightTaskQueryParam;
+import com.dji.sample.map.service.IFlightTrackTaskService;
+import com.dji.sdk.common.HttpResultResponse;
+import com.dji.sdk.common.PaginationData;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * @author sean
+ * @version 1.9
+ * @date 2024/7/23
+ */
+
+@RestController
+@RequestMapping("${url.map.prefix}${url.map.version}/workspaces")
+public class FlightTaskController {
+
+    @Autowired
+    private IFlightTrackTaskService flightTaskService;
+    /**
+     * 获取工作空间下的所有飞行任务(轨迹)信息
+     * @param workspaceId
+     * @return
+     */
+    @GetMapping("/{workspace_id}/flight-tasks")
+    public HttpResultResponse<PaginationData<FlightTaskDTO>> getFlightTaskList(FlightTaskQueryParam flightTaskQueryParam,
+                                                                        @RequestParam(defaultValue = "1") Long page,
+                                                                        @RequestParam(name = "page_size", defaultValue = "10") Long pageSize,
+                                                                        @PathVariable(name = "workspace_id") String workspaceId
+    ) {
+        PaginationData<FlightTaskDTO> taskList = flightTaskService.getFlightTasksPaginationByWorkspaceId(workspaceId, flightTaskQueryParam,page, pageSize);
+
+        return HttpResultResponse.success(taskList);
+    }
+
+    /**
+     * 获取飞行任务轨迹信息
+     * @param workspaceId
+     * @return
+     */
+    @GetMapping("/{workspace_id}/flight-task/{task_id}")
+    public HttpResultResponse<List<FlightTrackDTO>> getFlightTaskTrackList(
+                                                                        @PathVariable(name = "workspace_id") String workspaceId,
+                                                                        @PathVariable(name = "task_id") String taskId
+    ) {
+        List<FlightTrackDTO> taskTrackList = flightTaskService.getFlightTrackByTaskId(taskId);
+
+        return HttpResultResponse.success(taskTrackList);
+    }
+}

+ 12 - 0
Backend/sample/src/main/java/com/dji/sample/map/dao/IFlightTaskMapper.java

@@ -0,0 +1,12 @@
+package com.dji.sample.map.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.dji.sample.map.model.entity.FlightTaskEntity;
+
+/**
+ * @author hqjiang
+ * @version 1.0
+ * @date 2024/7/23
+ */
+public interface IFlightTaskMapper extends BaseMapper<FlightTaskEntity> {
+}

+ 12 - 0
Backend/sample/src/main/java/com/dji/sample/map/dao/IFlightTrackMapper.java

@@ -0,0 +1,12 @@
+package com.dji.sample.map.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.dji.sample.map.model.entity.FlightTrackEntity;
+
+/**
+ * @author hqjiang
+ * @version 1.0
+ * @date 2024/7/23
+ */
+public interface IFlightTrackMapper extends BaseMapper<FlightTrackEntity> {
+}

+ 54 - 0
Backend/sample/src/main/java/com/dji/sample/map/model/dto/FlightTaskDTO.java

@@ -0,0 +1,54 @@
+package com.dji.sample.map.model.dto;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * @author hqjiang
+ * @version 1.0
+ * @date 2024/7/23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class FlightTaskDTO {
+
+    private Integer id;
+
+    private String workspaceId;
+
+    private String taskName;
+
+    private String deviceSn;
+
+    private String deviceName;
+
+    private String payload;
+
+    private String waylineName;
+
+    private Long distance;
+
+    private Long flyTime;
+
+    private LocalDateTime beginTime;
+
+    private LocalDateTime endTime;
+
+    private LocalDateTime createTime;
+
+    private LocalDateTime updateTime;
+
+    private String username;
+
+    private String templateType;
+}

+ 39 - 0
Backend/sample/src/main/java/com/dji/sample/map/model/dto/FlightTrackDTO.java

@@ -0,0 +1,39 @@
+package com.dji.sample.map.model.dto;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author hqjiang
+ * @version 1.0
+ * @date 2024/7/23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class FlightTrackDTO {
+
+    private Integer taskId;
+
+    private Double longitude;
+
+    private Double latitude;
+
+    private Double altitude;
+
+    private LocalDateTime createTime;
+
+    private Integer modeCode;
+
+    private Double elevation;
+
+    private Integer type;
+
+    private Integer index;
+}

+ 71 - 0
Backend/sample/src/main/java/com/dji/sample/map/model/entity/FlightTaskEntity.java

@@ -0,0 +1,71 @@
+package com.dji.sample.map.model.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @author hqjiang
+ * @version 1.0
+ * @date 2024/7/23
+ */
+@TableName(value = "manage_task")
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class FlightTaskEntity implements Serializable {
+
+    @TableId(type = IdType.AUTO)
+    private Integer id;
+
+    @TableField("workspace_id")
+    private String workspaceId;
+
+    @TableField("task_name")
+    private String taskName;
+
+    @TableField("device_sn")
+    private String deviceSn;
+
+    @TableField("device_name")
+    private String deviceName;
+
+    @TableField("payload")
+    private String payload;
+
+    @TableField("wayline_name")
+    private String waylineName;
+
+    @TableField("distance")
+    private Long distance;
+
+    @TableField("fly_time")
+    private Long flyTime;
+
+    @TableField("begin_time")
+    private Long beginTime;
+
+    @TableField("end_time")
+    private Long endTime;
+
+    @TableField("create_time")
+    private Long createTime;
+
+    @TableField("update_time")
+    private Long updateTime;
+
+    @TableField("username")
+    private String username;
+
+    @TableField("template_type")
+    private String templateType;
+}
+

+ 51 - 0
Backend/sample/src/main/java/com/dji/sample/map/model/entity/FlightTrackEntity.java

@@ -0,0 +1,51 @@
+package com.dji.sample.map.model.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @author hqjiang
+ * @version 1.0
+ * @date 2024/7/23
+ */
+@TableName(value = "flight_track")
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class FlightTrackEntity implements Serializable {
+
+    @TableField("task_id")
+    private Integer taskId;
+
+    @TableField("longitude")
+    private Double longitude;
+
+    @TableField("latitude")
+    private Double latitude;
+
+    @TableField("altitude")
+    private Double altitude;
+
+    @TableField("create_time")
+    private Long createTime;
+
+    @TableField("mode_code")
+    private Integer modeCode;
+
+    @TableField("elevation")
+    private Double elevation;
+
+    @TableField("type")
+    private Integer type;
+
+    @TableField("type")
+    private Integer index;
+}
+

+ 45 - 0
Backend/sample/src/main/java/com/dji/sample/map/model/enums/FlightPointTypeEnum.java

@@ -0,0 +1,45 @@
+package com.dji.sample.map.model.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+import java.util.Arrays;
+
+/**
+ * @author sean
+ * @version 1.9
+ * @date 2024/7/26
+ */
+public enum FlightPointTypeEnum {
+
+    //起飞点
+    HOME(0),
+
+    //飞行轨迹
+    HAND(1),
+
+    //航线轨迹
+    WAYLINE(2),
+
+    //图片轨迹
+    PICTURE(3)
+
+    ;
+
+    private final int type;
+
+    FlightPointTypeEnum(int type) {
+        this.type = type;
+    }
+
+    @JsonValue
+    public Integer getType() {
+        return type;
+    }
+
+    @JsonCreator
+    public static FlightPointTypeEnum find(int type) {
+        return Arrays.stream(values()).filter(flightPointTypeEnum -> flightPointTypeEnum.type==type).findAny()
+            .orElseThrow(() -> new RuntimeException("This FlightPointType(" + type + ") is not supported."));
+    }
+}

+ 28 - 0
Backend/sample/src/main/java/com/dji/sample/map/model/param/FlightTaskQueryParam.java

@@ -0,0 +1,28 @@
+package com.dji.sample.map.model.param;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+/**
+ * @author hqjiang
+ * @version 1.0
+ * @date 2024/7/23
+ */
+@Data
+public class FlightTaskQueryParam {
+
+    @JsonProperty("begin_time")
+    private Long beginTime;
+
+    @JsonProperty("end_time")
+    private Long endTime;
+
+    @JsonProperty("template_type")
+    private String templateType;
+
+    @JsonProperty("payload")
+    private String payload;
+
+    @JsonProperty("search_info")
+    private String searchInfo;
+}

+ 58 - 0
Backend/sample/src/main/java/com/dji/sample/map/service/IFlightTrackTaskService.java

@@ -0,0 +1,58 @@
+package com.dji.sample.map.service;
+
+import com.dji.sample.map.model.dto.FlightTaskDTO;
+import com.dji.sample.map.model.dto.FlightTrackDTO;
+import com.dji.sample.map.model.entity.FlightTaskEntity;
+import com.dji.sample.map.model.entity.FlightTrackEntity;
+import com.dji.sample.map.model.param.FlightTaskQueryParam;
+import com.dji.sdk.common.PaginationData;
+
+import java.util.List;
+
+/**
+ * @author hqjiang
+ * @version 1.0
+ * @date 2024/7/23
+ */
+public interface IFlightTrackTaskService {
+
+    PaginationData<FlightTaskDTO> getFlightTasksPaginationByWorkspaceId(String workspaceId, FlightTaskQueryParam param, long page, long pageSize);
+
+    FlightTaskDTO getCurrentFlightTask(String workspaceId, String droneSn);
+
+    /**
+     * 通过目录名称查找目录
+     * @param flightPoint
+     * @return
+     */
+    Integer addFlightPoint(FlightTrackDTO flightPoint);
+
+    Integer addFlightPoint(FlightTrackEntity flightPoint);
+
+    Integer addHomePoint(FlightTrackEntity flightPoint);
+
+    /**
+     * 通过任务ID获取飞行轨迹
+     * @param taskId
+     * @return
+     */
+    List<FlightTrackDTO> getFlightTrackByTaskId(String taskId);
+
+    /**
+     * 创建飞行任务
+     * @param flightTaskDTO
+     * @return
+     */
+    Integer createFlightTask(FlightTaskDTO flightTaskDTO);
+
+    Integer updateFlightTask(FlightTaskEntity flightTaskEntity);
+
+    /**
+     * 创建飞行任务
+     * @param flightTaskEntity
+     * @return
+     */
+    FlightTaskDTO createFlightTask(FlightTaskEntity flightTaskEntity);
+
+    FlightTaskEntity dtoToEntity(FlightTaskDTO flightTask);
+}

+ 300 - 0
Backend/sample/src/main/java/com/dji/sample/map/service/impl/FlightTrackTaskServiceImpl.java

@@ -0,0 +1,300 @@
+package com.dji.sample.map.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dji.sample.map.dao.IFlightTaskMapper;
+import com.dji.sample.map.dao.IFlightTrackMapper;
+import com.dji.sample.map.model.dto.FlightTaskDTO;
+import com.dji.sample.map.model.dto.FlightTrackDTO;
+import com.dji.sample.map.model.entity.FlightTaskEntity;
+import com.dji.sample.map.model.entity.FlightTrackEntity;
+import com.dji.sample.map.model.enums.FlightPointTypeEnum;
+import com.dji.sample.map.model.param.FlightTaskQueryParam;
+import com.dji.sample.map.service.IFlightTrackTaskService;
+import com.dji.sample.media.model.MediaFileEntity;
+import com.dji.sample.media.service.IFileService;
+import com.dji.sample.wayline.model.enums.WaylineTemplateTypeEnum;
+import com.dji.sdk.common.Pagination;
+import com.dji.sdk.common.PaginationData;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * @author hqjiang
+ * @version 1.0
+ * @date 2024/7/23
+ */
+@Service
+@Transactional
+public class FlightTrackTaskServiceImpl implements IFlightTrackTaskService {
+
+    @Autowired
+    private IFlightTaskMapper mapper;
+
+    @Autowired
+    private IFlightTrackMapper trackMapper;
+
+    @Autowired
+    private IFileService fileService;
+
+    @Override
+    public PaginationData<FlightTaskDTO> getFlightTasksPaginationByWorkspaceId(String workspaceId, FlightTaskQueryParam param, long page, long pageSize) {
+        Page<FlightTaskEntity> pageData = mapper.selectPage(
+                new Page<FlightTaskEntity>(page, pageSize),
+                new LambdaQueryWrapper<FlightTaskEntity>()
+                        .eq(FlightTaskEntity::getWorkspaceId, workspaceId)
+                        .ge(param != null && param.getBeginTime() != null, FlightTaskEntity::getCreateTime,param.getBeginTime())
+                        .le(param != null && param.getEndTime() != null, FlightTaskEntity::getCreateTime,param.getEndTime())
+                        .eq(param != null && StringUtils.hasText(param.getTemplateType()), FlightTaskEntity::getTemplateType,param.getTemplateType())
+                        .eq(param != null && StringUtils.hasText(param.getPayload()), FlightTaskEntity::getPayload,param.getPayload())
+                        .and(StringUtils.hasText(param.getSearchInfo()),
+                                wrapper -> wrapper .like( FlightTaskEntity::getTaskName, param.getSearchInfo())
+                                        .or().like( FlightTaskEntity::getPayload, param.getSearchInfo())
+                                        .or().like( FlightTaskEntity::getWaylineName, param.getSearchInfo())
+                        )
+                        .orderByDesc(FlightTaskEntity::getCreateTime));
+        List<FlightTaskDTO> records = pageData.getRecords()
+                .stream()
+                .map(this::entityToDto)
+                .collect(Collectors.toList());
+
+        return new PaginationData<FlightTaskDTO>(records, new Pagination(pageData.getCurrent(), pageData.getSize(), pageData.getTotal()));
+    }
+
+    @Override
+    public FlightTaskDTO getCurrentFlightTask(String workspaceId, String droneSn) {
+        FlightTaskEntity entity = mapper.selectOne(new LambdaQueryWrapper<FlightTaskEntity>()
+                .eq(FlightTaskEntity::getWorkspaceId, workspaceId)
+                .eq(FlightTaskEntity::getDeviceSn, droneSn)
+                .le(FlightTaskEntity::getBeginTime,System.currentTimeMillis())
+                .isNull(FlightTaskEntity::getEndTime)
+                .orderByDesc(FlightTaskEntity::getBeginTime)
+                .last("limit 1")
+        );
+        if(entity == null) {
+            return null;
+        }
+        return entityToDto(entity);
+    }
+
+
+    private FlightTaskDTO getFlightTaskById(String taskId) {
+        FlightTaskEntity entity = mapper.selectOne(new LambdaQueryWrapper<FlightTaskEntity>()
+                .eq(FlightTaskEntity::getId, taskId)
+        );
+        if(entity == null) {
+            return null;
+        }
+        return entityToDto(entity);
+    }
+
+    @Override
+    public Integer addFlightPoint(FlightTrackDTO flightPoint) {
+        FlightTrackEntity flightTrackEntity = this.flightTrackDtoToEntity(flightPoint);
+        return trackMapper.insert(flightTrackEntity);
+    }
+
+    @Override
+    public Integer addFlightPoint(FlightTrackEntity flightPoint) {
+        return trackMapper.insert(flightPoint);
+    }
+
+    @Override
+    public Integer addHomePoint(FlightTrackEntity flightPoint) {
+        FlightTrackEntity homePoint = trackMapper.selectOne(new LambdaQueryWrapper<FlightTrackEntity>()
+                .eq(FlightTrackEntity::getTaskId, flightPoint.getTaskId())
+                .eq(FlightTrackEntity::getType, FlightPointTypeEnum.HOME));
+        if(homePoint == null) {
+            return trackMapper.insert(flightPoint);
+        }
+        return 0;
+    }
+
+
+    @Override
+    public List<FlightTrackDTO> getFlightTrackByTaskId(String taskId) {
+        List<FlightTrackEntity> filghtPoints = trackMapper.selectList(new LambdaQueryWrapper<FlightTrackEntity>()
+                .eq(FlightTrackEntity::getTaskId, taskId)
+                .orderByAsc(FlightTrackEntity::getCreateTime));
+        if(!CollectionUtils.isEmpty(filghtPoints)) {
+            //查询任务信息
+            FlightTaskEntity task = mapper.selectOne(new LambdaQueryWrapper<FlightTaskEntity>() .eq(FlightTaskEntity::getId, taskId));
+            //查询图片文件
+            long endTime = task.getEndTime() == null ? System.currentTimeMillis():task.getEndTime();
+            //飞行坐标
+            List<FlightTrackEntity> normalPoints = filghtPoints.stream().filter(fp -> fp.getType() == null || FlightPointTypeEnum.HAND.getType().intValue() == fp.getType().intValue())
+                    .sorted(Comparator.comparing(FlightTrackEntity::getCreateTime)).collect(Collectors.toList());
+            //航线坐标
+            List<FlightTrackEntity> waylinePoints = filghtPoints.stream().filter(fp ->FlightPointTypeEnum.WAYLINE.getType().intValue() == fp.getType().intValue())
+                    .sorted(Comparator.comparing(FlightTrackEntity::getIndex)).collect(Collectors.toList());
+
+            //照片坐标
+            List<MediaFileEntity> mediaFileEntities = fileService.getFlightTrackMediaFiles(task.getWorkspaceId(),task.getDeviceSn(),task.getBeginTime(),endTime);
+
+            //Home点
+            Optional<FlightTrackEntity> homePointOpt = filghtPoints.stream().filter(fp ->FlightPointTypeEnum.HOME.getType().intValue() == fp.getType().intValue()).findFirst();
+            FlightTrackEntity homePoint = null;
+            if(homePointOpt.isPresent()) {
+                homePoint = homePointOpt.get();
+            } else {
+                homePoint = FlightTrackEntity.builder().type(FlightPointTypeEnum.HOME.getType())
+                        .latitude(normalPoints.get(0).getLatitude())
+                        .longitude(normalPoints.get(0).getLongitude())
+                        .build();
+            }
+            FlightTrackEntity firstPoint = normalPoints.get(0);
+            FlightTrackEntity lastPoint = normalPoints.get(waylinePoints.size() - 1);
+
+            List<FlightTrackEntity> newFilghtTrackList = null;
+            //航线飞行
+            if(!CollectionUtils.isEmpty(waylinePoints)) {
+                newFilghtTrackList = waylinePoints;
+                newFilghtTrackList.add(0,firstPoint);
+                newFilghtTrackList.add(lastPoint);
+            //照片
+            } else if(!CollectionUtils.isEmpty(mediaFileEntities)) {
+                List<FlightTrackEntity> mediaTrackList = mediaFileEntities.stream().map(m -> mediaDTOToFlightTrackDTO(task.getId(), m)).sorted(Comparator.comparing(FlightTrackEntity::getCreateTime)).collect(Collectors.toList());
+                newFilghtTrackList = mediaTrackList;
+                newFilghtTrackList.add(0,firstPoint);
+                newFilghtTrackList.add(lastPoint);
+            } else {
+                newFilghtTrackList = normalPoints;
+            }
+
+            newFilghtTrackList.add(0,homePoint);
+
+            return newFilghtTrackList.stream().map(this::flightTrackEntityToDto).collect(Collectors.toList());
+        }
+        return null;
+    }
+
+    private FlightTrackEntity mediaDTOToFlightTrackDTO(Integer taskId, MediaFileEntity mediaFileEntity) {
+        return FlightTrackEntity.builder().taskId(taskId)
+                .longitude(mediaFileEntity.getLongitude().doubleValue())
+                .latitude(mediaFileEntity.getLatitude().doubleValue())
+                .altitude(mediaFileEntity.getAbsoluteAltitude().doubleValue())
+                .createTime(mediaFileEntity.getPictureTime())
+                .type(FlightPointTypeEnum.PICTURE.getType())
+                .build();
+    }
+
+
+    @Override
+    public Integer createFlightTask(FlightTaskDTO flightTaskDTO) {
+        FlightTaskEntity flightTaskEntity = this.dtoToEntity(flightTaskDTO);
+        return mapper.insert(flightTaskEntity);
+    }
+
+    @Override
+    public Integer updateFlightTask(FlightTaskEntity flightTaskEntity) {
+        return mapper.updateById(flightTaskEntity);
+    }
+
+    @Override
+    public FlightTaskDTO createFlightTask(FlightTaskEntity flightTaskEntity) {
+        FlightTaskEntity entity = mapper.selectOne(new LambdaQueryWrapper<FlightTaskEntity>()
+                .eq(FlightTaskEntity::getTaskName, flightTaskEntity.getTaskName())
+                .eq(FlightTaskEntity::getWorkspaceId,flightTaskEntity.getWorkspaceId()));
+        if(entity  == null) {
+            int result = mapper.insert(flightTaskEntity);
+            if (result > 0) {
+                return entityToDto(flightTaskEntity);
+            }
+        }
+        return entityToDto(entity);
+    }
+
+    @Override
+    public FlightTaskEntity dtoToEntity(FlightTaskDTO flightTask) {
+        FlightTaskEntity.FlightTaskEntityBuilder builder = FlightTaskEntity.builder();
+
+        if (flightTask != null) {
+            builder.workspaceId(flightTask.getWorkspaceId())
+                    .id(flightTask.getId())
+                    .taskName(flightTask.getTaskName())
+                    .deviceSn(flightTask.getDeviceSn())
+                    .deviceName(flightTask.getDeviceName())
+                    .payload(flightTask.getPayload())
+                    .waylineName(flightTask.getWaylineName())
+                    .templateType(flightTask.getTemplateType())
+                    .distance(flightTask.getDistance())
+                    .flyTime(flightTask.getFlyTime())
+                    .beginTime(flightTask.getBeginTime() != null ?
+                            flightTask.getBeginTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() : null)
+                    .endTime(flightTask.getEndTime() != null ?
+                            flightTask.getEndTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() : null)
+                    .createTime(flightTask.getCreateTime() != null ?
+                            flightTask.getCreateTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() : null)
+                    .updateTime(flightTask.getUpdateTime() != null ?
+                            flightTask.getUpdateTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() : null)
+                    .username(flightTask.getUsername());
+        }
+        return builder.build();
+    }
+
+    private FlightTrackEntity flightTrackDtoToEntity(FlightTrackDTO flightPoint) {
+        FlightTrackEntity.FlightTrackEntityBuilder builder = FlightTrackEntity.builder();
+
+        if (flightPoint != null) {
+            builder.taskId(flightPoint.getTaskId())
+                    .longitude(flightPoint.getLongitude())
+                    .latitude(flightPoint.getLatitude())
+                    .altitude(flightPoint.getAltitude())
+                    .modeCode(flightPoint.getModeCode())
+                    .elevation(flightPoint.getElevation())
+                    .createTime(flightPoint.getCreateTime() != null ?
+                            flightPoint.getCreateTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() : null);
+
+        }
+        return builder.build();
+    }
+
+    private FlightTrackDTO flightTrackEntityToDto(FlightTrackEntity flightTrackEntity) {
+        FlightTrackDTO.FlightTrackDTOBuilder builder = FlightTrackDTO.builder();
+        if (flightTrackEntity != null) {
+            builder.taskId(flightTrackEntity.getTaskId())
+                    .longitude(flightTrackEntity.getLongitude())
+                    .latitude(flightTrackEntity.getLatitude())
+                    .altitude(flightTrackEntity.getAltitude())
+                    .modeCode(flightTrackEntity.getModeCode())
+                    .elevation(flightTrackEntity.getElevation())
+                    .createTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(flightTrackEntity.getCreateTime()), ZoneId.systemDefault()))
+                    ;
+        }
+        return builder.build();
+    }
+
+    private FlightTaskDTO entityToDto(FlightTaskEntity flightTaskEntity) {
+        FlightTaskDTO.FlightTaskDTOBuilder builder = FlightTaskDTO.builder();
+        if (flightTaskEntity != null) {
+            builder.id(flightTaskEntity.getId())
+                    .workspaceId(flightTaskEntity.getWorkspaceId())
+                    .taskName(flightTaskEntity.getTaskName())
+                    .deviceSn(flightTaskEntity.getDeviceSn())
+                    .deviceName(flightTaskEntity.getDeviceName())
+                    .payload(flightTaskEntity.getPayload())
+                    .waylineName(flightTaskEntity.getWaylineName())
+                    .distance(flightTaskEntity.getDistance())
+                    .flyTime(flightTaskEntity.getFlyTime())
+                    .beginTime(flightTaskEntity.getBeginTime() != null ? LocalDateTime.ofInstant(Instant.ofEpochMilli(flightTaskEntity.getBeginTime()), ZoneId.systemDefault()) : null)
+                    .endTime(flightTaskEntity.getEndTime() != null ? LocalDateTime.ofInstant(Instant.ofEpochMilli(flightTaskEntity.getEndTime()), ZoneId.systemDefault()) : null)
+                    .templateType( StringUtils.hasText(flightTaskEntity.getTemplateType()) ? WaylineTemplateTypeEnum.find(flightTaskEntity.getTemplateType()).get().getType() : "")
+                    .createTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(flightTaskEntity.getCreateTime()), ZoneId.systemDefault()))
+                    .updateTime(flightTaskEntity.getUpdateTime() != null ? LocalDateTime.ofInstant(Instant.ofEpochMilli(flightTaskEntity.getUpdateTime()), ZoneId.systemDefault()) : null)
+                    .username(flightTaskEntity.getUsername());
+        }
+        return builder.build();
+    }
+
+}

+ 3 - 0
Backend/sample/src/main/java/com/dji/sample/media/service/IFileService.java

@@ -2,6 +2,7 @@ package com.dji.sample.media.service;
 
 import com.dji.sample.map.model.param.MediaFileQueryParam;
 import com.dji.sample.media.model.MediaFileDTO;
+import com.dji.sample.media.model.MediaFileEntity;
 import com.dji.sdk.cloudapi.media.MediaUploadCallbackRequest;
 import com.dji.sdk.common.PaginationData;
 import org.springframework.web.multipart.MultipartFile;
@@ -81,6 +82,8 @@ public interface IFileService {
 
     List<MediaFileDTO> getMediaFilesByDirId(String dirId);
 
+    List<MediaFileEntity> getFlightTrackMediaFiles(String workspaceId, String droneSn, long startTime, long endTime);
+
     void deleteFiles(List<String> fileIds);
 
     void dowloadDirsToZip(String workspaceId, List<String> dirIds, HttpServletResponse response) throws Exception;

+ 47 - 23
Backend/sample/src/main/java/com/dji/sample/media/service/impl/FileServiceImpl.java

@@ -83,6 +83,7 @@ public class FileServiceImpl implements IFileService {
     private static final String DOT = ".";
     private static final String SPLIT_DOT = "\\.";
     private static final String JPEG = "JPEG";
+    private static final String MP4 = "MP4";
 
     private Optional<MediaFileEntity> getMediaByFingerprint(String workspaceId, String fingerprint) {
         MediaFileEntity fileEntity = mapper.selectOne(new LambdaQueryWrapper<MediaFileEntity>()
@@ -245,31 +246,54 @@ public class FileServiceImpl implements IFileService {
         return records;
     }
 
+    @Override
+    public List<MediaFileEntity> getFlightTrackMediaFiles(String workspaceId, String droneSn, long startTime, long endTime) {
+        List<MediaFileEntity> listData = mapper.selectList(
+                new LambdaQueryWrapper<MediaFileEntity>()
+                        .select(MediaFileEntity::getWorkspaceId,
+                                MediaFileEntity::getDrone,
+                                MediaFileEntity::getLongitude,
+                                MediaFileEntity::getLatitude,
+                                MediaFileEntity::getAbsoluteAltitude,
+                                MediaFileEntity::getPictureTime)
+                        .eq(MediaFileEntity::getWorkspaceId, workspaceId)
+                        .eq(MediaFileEntity::getDrone, droneSn)
+                        .ge(MediaFileEntity::getPictureTime,startTime)
+                        .le(MediaFileEntity::getPictureTime,endTime)
+                        .ne(MediaFileEntity::getLongitude,0)
+                        .orderByAsc(MediaFileEntity::getPictureTime));
+
+        return listData;
+    }
+
     /**
      * Convert the received file object into a database entity object.
      * @param file
      * @return
      */
-    private synchronized MediaFileEntity fileUploadConvertToEntity(String workspaceId, MediaUploadCallbackRequest file) {
+    private MediaFileEntity fileUploadConvertToEntity(String workspaceId, MediaUploadCallbackRequest file) {
         //通过path 获取航线名称,文件夹名称
         String waylineName = getWaylineName(file.getPath());
         String dirName = getDirName(waylineName, file.getPath());
-        MediaDirDTO dirDto = mediaDirService.getMediaDirByName(workspaceId,dirName,null);
-        //文件夹不存在,则创建文件夹
-        if(dirDto == null) {
-            Optional<GetWaylineListResponse> waylineOpt = waylineFileService.getWaylineByWaylineName(workspaceId,waylineName);
-            MediaDirEntity.MediaDirEntityBuilder dirBuilder = MediaDirEntity.builder();
-            dirBuilder.dirName(dirName)
-                    .workspaceId(workspaceId)
-                    .waylineName(waylineName)
-                    .createTime(System.currentTimeMillis())
-                    .deviceName(getDeviceNameByModelKey(file.getExt().getDroneModelKey()))
-                    .payload(getDeviceNameByModelKey(file.getExt().getPayloadModelKey()))
-                    .username(UserRequest.getCurrentUser().getUsername());
-            if(waylineOpt.isPresent()) {
-                waylineOpt.ifPresent(wayline -> dirBuilder.templateType(wayline.getTemplateTypes().get(0).name()));
+        MediaDirDTO dirDto = null;
+        synchronized(dirName.intern()) {
+            dirDto = mediaDirService.getMediaDirByName(workspaceId, dirName, null);
+            //文件夹不存在,则创建文件夹
+            if (dirDto == null) {
+                Optional<GetWaylineListResponse> waylineOpt = waylineFileService.getWaylineByWaylineName(workspaceId, waylineName);
+                MediaDirEntity.MediaDirEntityBuilder dirBuilder = MediaDirEntity.builder();
+                dirBuilder.dirName(dirName)
+                        .workspaceId(workspaceId)
+                        .waylineName(waylineName)
+                        .createTime(System.currentTimeMillis())
+                        .deviceName(getDeviceNameByModelKey(file.getExt().getDroneModelKey()))
+                        .payload(getDeviceNameByModelKey(file.getExt().getPayloadModelKey()))
+                        .username(UserRequest.getCurrentUser().getUsername());
+                if (waylineOpt.isPresent()) {
+                    waylineOpt.ifPresent(wayline -> dirBuilder.templateType(wayline.getTemplateTypes().get(0).name()));
+                }
+                dirDto = mediaDirService.createDir(dirBuilder.build());
             }
-            dirDto = mediaDirService.createDir(dirBuilder.build());
         }
         //生成缩略图
         String tObjectKey = getThumbnailObjectKey(file.getName());
@@ -283,7 +307,7 @@ public class FileServiceImpl implements IFileService {
 
             //经纬度转换
             //AMap aMap = CoordinateUtil.transform(file.getMetadata().getShootPosition().getLng(),file.getMetadata().getShootPosition().getLat());
-            AMap aMap = CoordinateUtil.transform(exif.getLongitude(),exif.getLatitude());
+            //AMap aMap = CoordinateUtil.transform(exif.getLongitude(),exif.getLatitude());
             builder.fileName(file.getName())
                     .filePath(file.getPath())
                     .fingerprint(file.getFingerprint())
@@ -300,10 +324,10 @@ public class FileServiceImpl implements IFileService {
                     .imageHeight(exif.getImageHeight())
                     .xResolution(exif.getXResolution())
                     .yResolution(exif.getYResolution())
-                    .latitude(BigDecimal.valueOf(aMap.getLatitude()).setScale(6, RoundingMode.DOWN))
-                    .longitude( BigDecimal.valueOf(aMap.getLongitude()).setScale(6, RoundingMode.DOWN))
-                    .absoluteAltitude(BigDecimal.valueOf(file.getMetadata().getAbsoluteAltitude()).setScale(6, RoundingMode.DOWN))
-                    .relativeAltitude(BigDecimal.valueOf(file.getMetadata().getRelativeAltitude()).setScale(6, RoundingMode.DOWN))
+                    .latitude(BigDecimal.valueOf(CoordinateUtil.checkValidVal(exif.getLatitude())).setScale(14, RoundingMode.DOWN))
+                    .longitude( BigDecimal.valueOf(CoordinateUtil.checkValidVal(exif.getLongitude())).setScale(14, RoundingMode.DOWN))
+                    .absoluteAltitude(BigDecimal.valueOf(CoordinateUtil.checkValidVal(file.getMetadata().getAbsoluteAltitude())).setScale(6, RoundingMode.DOWN))
+                    .relativeAltitude(BigDecimal.valueOf(CoordinateUtil.checkValidVal(file.getMetadata().getRelativeAltitude())).setScale(6, RoundingMode.DOWN))
                     .size(ossService.getObjectSize(OssConfiguration.bucket, file.getObjectKey()))
                     .pictureTime(file.getMetadata().getCreatedTime() != null ? file.getMetadata().getCreatedTime().atZone(ZoneId.of("UTC+0")).toInstant().toEpochMilli() : null)
                     .longitudeRef(exif.getLongitudeRef())
@@ -454,13 +478,13 @@ public class FileServiceImpl implements IFileService {
 
     private MediaTypeEnum convertMediaType(MediaFileEntity entity) {
         if(StringUtils.hasText(entity.getMediaType())) {
-            if (entity.getMediaType().startsWith(IMAGE)) {
+            if (entity.getMediaType().startsWith(IMAGE) || JPEG.equalsIgnoreCase(entity.getMediaType())) {
                 if (entity.getIsOriginal()) {
                     return MediaTypeEnum.PIC_ORIGIN;
                 } else {
                     return MediaTypeEnum.PIC_SHOT;
                 }
-            } else if (entity.getMediaType().startsWith(VIDEO)) {
+            } else if (entity.getMediaType().startsWith(VIDEO) || MP4.equalsIgnoreCase(entity.getPictureType())) {
                 return MediaTypeEnum.VIDEO;
             } else if (entity.getMediaType().startsWith("jfif")) {
                 return MediaTypeEnum.PIC_PANORAMA;

+ 8 - 3
Backend/sample/src/main/resources/application.yml

@@ -125,9 +125,9 @@ oss:
   region: us-east-1
   object-dir-prefix: wayline
 
-# 高德地图 trans: CUSTOM 自定义  GAODE 高德API
+# 高德地图 trans: CUSTOM 自定义  GAODE 高德API  96d7df07675b274a4078b107e56b2a4a
 amap:
-  key: 96d7df07675b274a4078b107e56b2a4a
+  key: 9ccf8815eb701c6aab8cd63e739df0fa
   type: CUSTOM
 
 logging:
@@ -175,4 +175,9 @@ livestream:
 
     # Webrtc: Only supports using whip standard
     whip:
-      url: Please enter the rtmp access address. #  Example:http://192.168.1.1:1985/rtc/v1/whip/?app=live&stream=
+      url: Please enter the rtmp access address. #  Example:http://192.168.1.1:1985/rtc/v1/whip/?app=live&stream=
+
+#自定义配置
+custom-config:
+  #航点采集频次(秒)
+  frequency: 3

File diff suppressed because it is too large
+ 0 - 0
Web/src/vendors/jswebrtc.min.js


Some files were not shown because too many files changed in this diff