From 3e67c83ced187fdf211735da03042466754e3fe6 Mon Sep 17 00:00:00 2001 From: Teo <2642673902@qq.com> Date: Wed, 14 May 2025 18:31:25 +0800 Subject: [PATCH] =?UTF-8?q?=E6=97=A0=E4=BA=BA=E6=9C=BA=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 4 + index.html | 1 + package.json | 3 + src/api/air/index.ts | 430 +++++++ src/api/fileMangement/index.ts | 118 ++ src/api/gis/index.ts | 16 +- src/api/gis/type.ts | 4 + src/components/webrtc/index.vue | 57 + src/main.ts | 11 + src/router/index.ts | 5 + src/store/modules/drone.ts | 42 + src/utils/auth.ts | 26 + src/utils/bus.ts | 22 + src/utils/index.ts | 12 +- src/utils/moveDiv.ts | 40 + src/utils/reconnecting-websocket.js | 382 ++++++ src/utils/requset2.ts | 55 + .../drone/components/airRoute/advancedSet.vue | 370 ++++++ .../components/airRoute/js/pointSetup.js | 750 ++++++++++++ src/views/drone/components/airRoute/list.vue | 627 ++++++++++ .../drone/components/airRoute/pointSetup.vue | 881 +++++++++++++ .../drone/components/bottomTabs/index.vue | 143 +++ .../components/component/dialog/index.vue | 114 ++ .../components/component/plusReduce/index.vue | 121 ++ .../components/component/progress/index.vue | 143 +++ src/views/drone/components/flyer/1.jpg | Bin 0 -> 146997 bytes src/views/drone/components/flyer/index.vue | 37 + .../AircraftInformationDetails/index.vue | 447 +++++++ .../AircraftMonitoringLiveBroadcast/index.vue | 1068 ++++++++++++++++ .../AirportInformationDetails/index.vue | 485 ++++++++ .../AirportRemoteDebugging/DebugItem.vue | 121 ++ .../AirportRemoteDebugging/index.vue | 811 ++++++++++++ .../home/components/ModuleItem/index.vue | 80 ++ .../components/MonitorLiveStreaming/index.vue | 755 ++++++++++++ .../MonitorLiveStreaming/index1.vue | 784 ++++++++++++ src/views/drone/components/home/homeLeft.vue | 53 + src/views/drone/components/home/homeRight.vue | 67 + src/views/drone/components/home/index.vue | 27 + src/views/drone/components/medium/index.vue | 264 ++++ .../drone/components/medium/mediumHome.vue | 620 ++++++++++ .../drone/components/medium/mediumHomeAi.vue | 609 +++++++++ src/views/drone/components/medium/preview.vue | 272 +++++ .../drone/components/planLank/histroy.vue | 130 ++ src/views/drone/components/planLank/index.vue | 837 +++++++++++++ src/views/drone/components/selcet/index.vue | 74 ++ .../components/virtualWarehouse/api/index.js | 26 + .../DataPresentation/icons/FlightTime.svg | 4 + .../DataPresentation/icons/Remaining.svg | 4 + .../DataPresentation/icons/battery.svg | 4 + .../components/DataPresentation/icons/big.svg | 4 + .../DataPresentation/icons/memory.svg | 4 + .../DataPresentation/icons/picture.svg | 4 + .../DataPresentation/icons/plane.svg | 4 + .../DataPresentation/icons/quantity.svg | 4 + .../DataPresentation/icons/satellite.svg | 4 + .../components/DataPresentation/index.vue | 199 +++ .../components/DroneVideo/index.vue | 282 +++++ .../components/FlightSetup/icons/icon1.svg | 6 + .../components/FlightSetup/icons/icon2.svg | 6 + .../components/FlightSetup/icons/icon3.svg | 4 + .../components/FlightSetup/icons/line.png | Bin 0 -> 436 bytes .../components/FlightSetup/index.vue | 187 +++ .../components/GraduatedScale/index.vue | 203 +++ .../components/Tips/icons/close.png | Bin 0 -> 240 bytes .../components/Tips/icons/warn.svg | 4 + .../components/Tips/index.vue | 126 ++ .../ToolPresentation/icons/fight.svg | 12 + .../components/ToolPresentation/index.vue | 98 ++ .../components/Typecontrols/index.vue | 68 ++ .../components/Typecontrols/typeValue.vue | 38 + .../components/articulation/index.vue | 69 ++ .../controlFightTool/icons/close.png | Bin 0 -> 214 bytes .../components/controlFightTool/index.vue | 285 +++++ .../components/inputNumber/index.vue | 116 ++ .../components/modeControl/icons/icon1.svg | 6 + .../components/modeControl/icons/icon2.svg | 4 + .../components/modeControl/icons/icon2_en.svg | 4 + .../components/modeControl/icons/icon3.svg | 4 + .../components/modeControl/icons/icon3_en.svg | 4 + .../components/modeControl/icons/icon4.svg | 4 + .../components/modeControl/icons/icon4_en.svg | 4 + .../components/modeControl/icons/icon5.svg | 4 + .../components/modeControl/icons/icon5_en.svg | 4 + .../components/modeControl/icons/power.svg | 4 + .../components/modeControl/icons/record.svg | 6 + .../modeControl/icons/start_record.svg | 6 + .../components/modeControl/index.vue | 305 +++++ .../components/myLoading/icons/loading2.png | Bin 0 -> 40968 bytes .../components/myLoading/index.vue | 46 + .../components/ptzControl/icons/btn.svg | 4 + .../components/ptzControl/icons/ptz.svg | 13 + .../components/ptzControl/icons/ptz1.svg | 6 + .../components/ptzControl/index.vue | 369 ++++++ .../virtualWarehouse/icons/Refresh.svg | 6 + .../icons/aircraft-camera-active.png | Bin 0 -> 282 bytes .../components/virtualWarehouse/icons/bj.png | Bin 0 -> 449141 bytes .../virtualWarehouse/icons/cerams.svg | 4 + .../virtualWarehouse/icons/close.png | Bin 0 -> 240 bytes .../virtualWarehouse/icons/close1.png | Bin 0 -> 434 bytes .../virtualWarehouse/icons/lamp.svg | 11 + .../virtualWarehouse/icons/line.png | Bin 0 -> 436 bytes .../virtualWarehouse/icons/photo.svg | 6 + .../virtualWarehouse/icons/reset.svg | 4 + .../virtualWarehouse/icons/shouTip.svg | 14 + .../virtualWarehouse/icons/shrink.svg | 4 + .../virtualWarehouse/icons/start.svg | 4 + .../virtualWarehouse/icons/tool.svg | 4 + .../virtualWarehouse/icons/tool1.svg | 4 + .../virtualWarehouse/icons/uav-bgd-open.png | Bin 0 -> 239 bytes .../virtualWarehouse/icons/uav-bgd.png | Bin 0 -> 353 bytes .../components/virtualWarehouse/index.js | 5 + .../components/virtualWarehouse/index.vue | 1088 +++++++++++++++++ .../virtualWarehouse/style/comm.scss | 122 ++ src/views/drone/images/add.png | Bin 0 -> 664 bytes src/views/drone/images/add_plan.png | Bin 0 -> 299 bytes src/views/drone/images/addh.png | Bin 0 -> 640 bytes src/views/drone/images/after_f.png | Bin 0 -> 304 bytes src/views/drone/images/air.png | Bin 0 -> 574 bytes src/views/drone/images/airlist.png | Bin 0 -> 11853 bytes src/views/drone/images/airsetup.png | Bin 0 -> 13302 bytes src/views/drone/images/back.png | Bin 0 -> 336 bytes src/views/drone/images/back_h.png | Bin 0 -> 332 bytes src/views/drone/images/bottom_r.png | Bin 0 -> 348 bytes src/views/drone/images/climb.png | Bin 0 -> 10906 bytes src/views/drone/images/close.png | Bin 0 -> 214 bytes src/views/drone/images/close1.png | Bin 0 -> 643 bytes .../drone/images/control_Isochronous.png | Bin 0 -> 3218 bytes src/views/drone/images/control_add.png | Bin 0 -> 2331 bytes src/views/drone/images/control_aircraft.png | Bin 0 -> 2860 bytes .../drone/images/control_equidistant.png | Bin 0 -> 3474 bytes src/views/drone/images/control_hover.png | Bin 0 -> 3415 bytes src/views/drone/images/control_interval.png | Bin 0 -> 3168 bytes src/views/drone/images/control_more.png | Bin 0 -> 1436 bytes src/views/drone/images/control_panorama.png | Bin 0 -> 3281 bytes src/views/drone/images/control_photograph.png | Bin 0 -> 2742 bytes src/views/drone/images/control_pitch.png | Bin 0 -> 2292 bytes src/views/drone/images/control_start.png | Bin 0 -> 2616 bytes src/views/drone/images/control_suspend.png | Bin 0 -> 2416 bytes src/views/drone/images/control_yaw.png | Bin 0 -> 2287 bytes src/views/drone/images/control_zoom.png | Bin 0 -> 2182 bytes src/views/drone/images/del.png | Bin 0 -> 347 bytes src/views/drone/images/delh.png | Bin 0 -> 438 bytes src/views/drone/images/edit.png | Bin 0 -> 395 bytes src/views/drone/images/edith.png | Bin 0 -> 401 bytes src/views/drone/images/eq.png | Bin 0 -> 413 bytes src/views/drone/images/fanhang.png | Bin 0 -> 2825 bytes src/views/drone/images/feiji.png | Bin 0 -> 342 bytes src/views/drone/images/flyh.png | Bin 0 -> 1764 bytes src/views/drone/images/guaqi.png | Bin 0 -> 2681 bytes src/views/drone/images/head.png | Bin 0 -> 112594 bytes src/views/drone/images/home/UAV-bg.png | Bin 0 -> 7296 bytes src/views/drone/images/home/action.png | Bin 0 -> 427 bytes .../images/home/aircraft-camera-active.png | Bin 0 -> 282 bytes .../drone/images/home/aircraft-camera.png | Bin 0 -> 280 bytes src/views/drone/images/home/aircraft.png | Bin 0 -> 2080 bytes src/views/drone/images/home/border-lb.png | Bin 0 -> 532 bytes src/views/drone/images/home/border-lt.png | Bin 0 -> 350 bytes src/views/drone/images/home/border-rb.png | Bin 0 -> 344 bytes src/views/drone/images/home/border-rt.png | Bin 0 -> 392 bytes src/views/drone/images/home/cabin.png | Bin 0 -> 3021 bytes src/views/drone/images/home/calibration.png | Bin 0 -> 273 bytes src/views/drone/images/home/debug-cg.png | Bin 0 -> 331 bytes src/views/drone/images/home/debug-fxq.png | Bin 0 -> 441 bytes src/views/drone/images/home/debug-jccc.png | Bin 0 -> 359 bytes src/views/drone/images/home/debug-jcxt.png | Bin 0 -> 338 bytes src/views/drone/images/home/debug-jyms.png | Bin 0 -> 289 bytes src/views/drone/images/home/debug-kt.png | Bin 0 -> 238 bytes src/views/drone/images/home/debug-tg.png | Bin 0 -> 331 bytes src/views/drone/images/home/debug-zqtc.png | Bin 0 -> 343 bytes src/views/drone/images/home/file.png | Bin 0 -> 233 bytes src/views/drone/images/home/jicang.png | Bin 0 -> 245 bytes src/views/drone/images/home/live-stop.png | Bin 0 -> 3297 bytes src/views/drone/images/home/loading.png | Bin 0 -> 784554 bytes src/views/drone/images/home/local-point.png | Bin 0 -> 241 bytes .../drone/images/home/module-item-title.png | Bin 0 -> 6289 bytes src/views/drone/images/home/over.png | Bin 0 -> 416 bytes src/views/drone/images/home/paizhao.png | Bin 0 -> 263 bytes src/views/drone/images/home/pzsyl.png | Bin 0 -> 272 bytes src/views/drone/images/home/recharge.png | Bin 0 -> 247 bytes src/views/drone/images/home/satellite.png | Bin 0 -> 307 bytes src/views/drone/images/home/uav-bgd-open.png | Bin 0 -> 239 bytes src/views/drone/images/home/uav-bgd.png | Bin 0 -> 353 bytes src/views/drone/images/home/uav-close.png | Bin 0 -> 289 bytes src/views/drone/images/home/uav-local.png | Bin 0 -> 218 bytes src/views/drone/images/home/uav-monitor.png | Bin 0 -> 402 bytes src/views/drone/images/home/uav-reset.png | Bin 0 -> 309 bytes .../drone/images/home/uav-screen-esc.png | Bin 0 -> 223 bytes src/views/drone/images/home/uav-screen.png | Bin 0 -> 287 bytes src/views/drone/images/home/uav-set.png | Bin 0 -> 349 bytes src/views/drone/images/home/uav.png | Bin 0 -> 294 bytes src/views/drone/images/hover.png | Bin 0 -> 786 bytes src/views/drone/images/huifu.png | Bin 0 -> 2102 bytes src/views/drone/images/importpath.png | Bin 0 -> 421 bytes src/views/drone/images/importpathh.png | Bin 0 -> 418 bytes src/views/drone/images/jichang.png | Bin 0 -> 1742 bytes src/views/drone/images/left.png | Bin 0 -> 487 bytes src/views/drone/images/left_f.png | Bin 0 -> 295 bytes src/views/drone/images/loading.png | Bin 0 -> 198 bytes src/views/drone/images/loadingdow.gif | Bin 0 -> 5735 bytes src/views/drone/images/medium/arrow.png | Bin 0 -> 2296 bytes src/views/drone/images/medium/close.png | Bin 0 -> 2297 bytes src/views/drone/images/medium/delete.png | Bin 0 -> 443 bytes src/views/drone/images/medium/down-load.png | Bin 0 -> 363 bytes src/views/drone/images/medium/files-icon.png | Bin 0 -> 2370 bytes src/views/drone/images/medium/medium-img.png | Bin 0 -> 536 bytes .../drone/images/medium/medium-storage.png | Bin 0 -> 570 bytes .../drone/images/medium/medium-video.png | Bin 0 -> 465 bytes src/views/drone/images/medium/prview-icon.png | Bin 0 -> 405 bytes src/views/drone/images/medium/refresh.png | Bin 0 -> 3725 bytes src/views/drone/images/medium/video-icon.png | Bin 0 -> 1586 bytes src/views/drone/images/more1.png | Bin 0 -> 224 bytes src/views/drone/images/more2.png | Bin 0 -> 224 bytes src/views/drone/images/point.png | Bin 0 -> 377 bytes src/views/drone/images/right.png | Bin 0 -> 463 bytes src/views/drone/images/right_f.png | Bin 0 -> 305 bytes src/views/drone/images/save.png | Bin 0 -> 303 bytes src/views/drone/images/saveh.png | Bin 0 -> 307 bytes src/views/drone/images/shanchu.png | Bin 0 -> 1282 bytes src/views/drone/images/switch.png | Bin 0 -> 426 bytes src/views/drone/images/switchh.png | Bin 0 -> 413 bytes src/views/drone/images/tab.png | Bin 0 -> 17677 bytes src/views/drone/images/tab_h.png | Bin 0 -> 27073 bytes src/views/drone/images/time.png | Bin 0 -> 339 bytes src/views/drone/images/title.png | Bin 0 -> 214 bytes src/views/drone/images/top.png | Bin 0 -> 330 bytes src/views/drone/images/top_r.png | Bin 0 -> 341 bytes src/views/drone/images/wurenji.png | Bin 0 -> 648 bytes src/views/drone/images/zanting.png | Bin 0 -> 1763 bytes src/views/drone/index.vue | 648 ++++++++++ src/views/drone/style/common.scss | 62 + src/views/drone/utils/options.js | 107 ++ src/views/gisHome/index.vue | 44 +- 232 files changed, 16610 insertions(+), 7 deletions(-) create mode 100644 src/api/air/index.ts create mode 100644 src/api/fileMangement/index.ts create mode 100644 src/components/webrtc/index.vue create mode 100644 src/store/modules/drone.ts create mode 100644 src/utils/bus.ts create mode 100644 src/utils/moveDiv.ts create mode 100644 src/utils/reconnecting-websocket.js create mode 100644 src/utils/requset2.ts create mode 100644 src/views/drone/components/airRoute/advancedSet.vue create mode 100644 src/views/drone/components/airRoute/js/pointSetup.js create mode 100644 src/views/drone/components/airRoute/list.vue create mode 100644 src/views/drone/components/airRoute/pointSetup.vue create mode 100644 src/views/drone/components/bottomTabs/index.vue create mode 100644 src/views/drone/components/component/dialog/index.vue create mode 100644 src/views/drone/components/component/plusReduce/index.vue create mode 100644 src/views/drone/components/component/progress/index.vue create mode 100644 src/views/drone/components/flyer/1.jpg create mode 100644 src/views/drone/components/flyer/index.vue create mode 100644 src/views/drone/components/home/components/AircraftInformationDetails/index.vue create mode 100644 src/views/drone/components/home/components/AircraftMonitoringLiveBroadcast/index.vue create mode 100644 src/views/drone/components/home/components/AirportInformationDetails/index.vue create mode 100644 src/views/drone/components/home/components/AirportRemoteDebugging/DebugItem.vue create mode 100644 src/views/drone/components/home/components/AirportRemoteDebugging/index.vue create mode 100644 src/views/drone/components/home/components/ModuleItem/index.vue create mode 100644 src/views/drone/components/home/components/MonitorLiveStreaming/index.vue create mode 100644 src/views/drone/components/home/components/MonitorLiveStreaming/index1.vue create mode 100644 src/views/drone/components/home/homeLeft.vue create mode 100644 src/views/drone/components/home/homeRight.vue create mode 100644 src/views/drone/components/home/index.vue create mode 100644 src/views/drone/components/medium/index.vue create mode 100644 src/views/drone/components/medium/mediumHome.vue create mode 100644 src/views/drone/components/medium/mediumHomeAi.vue create mode 100644 src/views/drone/components/medium/preview.vue create mode 100644 src/views/drone/components/planLank/histroy.vue create mode 100644 src/views/drone/components/planLank/index.vue create mode 100644 src/views/drone/components/selcet/index.vue create mode 100644 src/views/drone/components/virtualWarehouse/api/index.js create mode 100644 src/views/drone/components/virtualWarehouse/components/DataPresentation/icons/FlightTime.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/DataPresentation/icons/Remaining.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/DataPresentation/icons/battery.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/DataPresentation/icons/big.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/DataPresentation/icons/memory.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/DataPresentation/icons/picture.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/DataPresentation/icons/plane.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/DataPresentation/icons/quantity.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/DataPresentation/icons/satellite.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/DataPresentation/index.vue create mode 100644 src/views/drone/components/virtualWarehouse/components/DroneVideo/index.vue create mode 100644 src/views/drone/components/virtualWarehouse/components/FlightSetup/icons/icon1.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/FlightSetup/icons/icon2.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/FlightSetup/icons/icon3.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/FlightSetup/icons/line.png create mode 100644 src/views/drone/components/virtualWarehouse/components/FlightSetup/index.vue create mode 100644 src/views/drone/components/virtualWarehouse/components/GraduatedScale/index.vue create mode 100644 src/views/drone/components/virtualWarehouse/components/Tips/icons/close.png create mode 100644 src/views/drone/components/virtualWarehouse/components/Tips/icons/warn.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/Tips/index.vue create mode 100644 src/views/drone/components/virtualWarehouse/components/ToolPresentation/icons/fight.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/ToolPresentation/index.vue create mode 100644 src/views/drone/components/virtualWarehouse/components/Typecontrols/index.vue create mode 100644 src/views/drone/components/virtualWarehouse/components/Typecontrols/typeValue.vue create mode 100644 src/views/drone/components/virtualWarehouse/components/articulation/index.vue create mode 100644 src/views/drone/components/virtualWarehouse/components/controlFightTool/icons/close.png create mode 100644 src/views/drone/components/virtualWarehouse/components/controlFightTool/index.vue create mode 100644 src/views/drone/components/virtualWarehouse/components/inputNumber/index.vue create mode 100644 src/views/drone/components/virtualWarehouse/components/modeControl/icons/icon1.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/modeControl/icons/icon2.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/modeControl/icons/icon2_en.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/modeControl/icons/icon3.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/modeControl/icons/icon3_en.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/modeControl/icons/icon4.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/modeControl/icons/icon4_en.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/modeControl/icons/icon5.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/modeControl/icons/icon5_en.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/modeControl/icons/power.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/modeControl/icons/record.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/modeControl/icons/start_record.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/modeControl/index.vue create mode 100644 src/views/drone/components/virtualWarehouse/components/myLoading/icons/loading2.png create mode 100644 src/views/drone/components/virtualWarehouse/components/myLoading/index.vue create mode 100644 src/views/drone/components/virtualWarehouse/components/ptzControl/icons/btn.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/ptzControl/icons/ptz.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/ptzControl/icons/ptz1.svg create mode 100644 src/views/drone/components/virtualWarehouse/components/ptzControl/index.vue create mode 100644 src/views/drone/components/virtualWarehouse/icons/Refresh.svg create mode 100644 src/views/drone/components/virtualWarehouse/icons/aircraft-camera-active.png create mode 100644 src/views/drone/components/virtualWarehouse/icons/bj.png create mode 100644 src/views/drone/components/virtualWarehouse/icons/cerams.svg create mode 100644 src/views/drone/components/virtualWarehouse/icons/close.png create mode 100644 src/views/drone/components/virtualWarehouse/icons/close1.png create mode 100644 src/views/drone/components/virtualWarehouse/icons/lamp.svg create mode 100644 src/views/drone/components/virtualWarehouse/icons/line.png create mode 100644 src/views/drone/components/virtualWarehouse/icons/photo.svg create mode 100644 src/views/drone/components/virtualWarehouse/icons/reset.svg create mode 100644 src/views/drone/components/virtualWarehouse/icons/shouTip.svg create mode 100644 src/views/drone/components/virtualWarehouse/icons/shrink.svg create mode 100644 src/views/drone/components/virtualWarehouse/icons/start.svg create mode 100644 src/views/drone/components/virtualWarehouse/icons/tool.svg create mode 100644 src/views/drone/components/virtualWarehouse/icons/tool1.svg create mode 100644 src/views/drone/components/virtualWarehouse/icons/uav-bgd-open.png create mode 100644 src/views/drone/components/virtualWarehouse/icons/uav-bgd.png create mode 100644 src/views/drone/components/virtualWarehouse/index.js create mode 100644 src/views/drone/components/virtualWarehouse/index.vue create mode 100644 src/views/drone/components/virtualWarehouse/style/comm.scss create mode 100644 src/views/drone/images/add.png create mode 100644 src/views/drone/images/add_plan.png create mode 100644 src/views/drone/images/addh.png create mode 100644 src/views/drone/images/after_f.png create mode 100644 src/views/drone/images/air.png create mode 100644 src/views/drone/images/airlist.png create mode 100644 src/views/drone/images/airsetup.png create mode 100644 src/views/drone/images/back.png create mode 100644 src/views/drone/images/back_h.png create mode 100644 src/views/drone/images/bottom_r.png create mode 100644 src/views/drone/images/climb.png create mode 100644 src/views/drone/images/close.png create mode 100644 src/views/drone/images/close1.png create mode 100644 src/views/drone/images/control_Isochronous.png create mode 100644 src/views/drone/images/control_add.png create mode 100644 src/views/drone/images/control_aircraft.png create mode 100644 src/views/drone/images/control_equidistant.png create mode 100644 src/views/drone/images/control_hover.png create mode 100644 src/views/drone/images/control_interval.png create mode 100644 src/views/drone/images/control_more.png create mode 100644 src/views/drone/images/control_panorama.png create mode 100644 src/views/drone/images/control_photograph.png create mode 100644 src/views/drone/images/control_pitch.png create mode 100644 src/views/drone/images/control_start.png create mode 100644 src/views/drone/images/control_suspend.png create mode 100644 src/views/drone/images/control_yaw.png create mode 100644 src/views/drone/images/control_zoom.png create mode 100644 src/views/drone/images/del.png create mode 100644 src/views/drone/images/delh.png create mode 100644 src/views/drone/images/edit.png create mode 100644 src/views/drone/images/edith.png create mode 100644 src/views/drone/images/eq.png create mode 100644 src/views/drone/images/fanhang.png create mode 100644 src/views/drone/images/feiji.png create mode 100644 src/views/drone/images/flyh.png create mode 100644 src/views/drone/images/guaqi.png create mode 100644 src/views/drone/images/head.png create mode 100644 src/views/drone/images/home/UAV-bg.png create mode 100644 src/views/drone/images/home/action.png create mode 100644 src/views/drone/images/home/aircraft-camera-active.png create mode 100644 src/views/drone/images/home/aircraft-camera.png create mode 100644 src/views/drone/images/home/aircraft.png create mode 100644 src/views/drone/images/home/border-lb.png create mode 100644 src/views/drone/images/home/border-lt.png create mode 100644 src/views/drone/images/home/border-rb.png create mode 100644 src/views/drone/images/home/border-rt.png create mode 100644 src/views/drone/images/home/cabin.png create mode 100644 src/views/drone/images/home/calibration.png create mode 100644 src/views/drone/images/home/debug-cg.png create mode 100644 src/views/drone/images/home/debug-fxq.png create mode 100644 src/views/drone/images/home/debug-jccc.png create mode 100644 src/views/drone/images/home/debug-jcxt.png create mode 100644 src/views/drone/images/home/debug-jyms.png create mode 100644 src/views/drone/images/home/debug-kt.png create mode 100644 src/views/drone/images/home/debug-tg.png create mode 100644 src/views/drone/images/home/debug-zqtc.png create mode 100644 src/views/drone/images/home/file.png create mode 100644 src/views/drone/images/home/jicang.png create mode 100644 src/views/drone/images/home/live-stop.png create mode 100644 src/views/drone/images/home/loading.png create mode 100644 src/views/drone/images/home/local-point.png create mode 100644 src/views/drone/images/home/module-item-title.png create mode 100644 src/views/drone/images/home/over.png create mode 100644 src/views/drone/images/home/paizhao.png create mode 100644 src/views/drone/images/home/pzsyl.png create mode 100644 src/views/drone/images/home/recharge.png create mode 100644 src/views/drone/images/home/satellite.png create mode 100644 src/views/drone/images/home/uav-bgd-open.png create mode 100644 src/views/drone/images/home/uav-bgd.png create mode 100644 src/views/drone/images/home/uav-close.png create mode 100644 src/views/drone/images/home/uav-local.png create mode 100644 src/views/drone/images/home/uav-monitor.png create mode 100644 src/views/drone/images/home/uav-reset.png create mode 100644 src/views/drone/images/home/uav-screen-esc.png create mode 100644 src/views/drone/images/home/uav-screen.png create mode 100644 src/views/drone/images/home/uav-set.png create mode 100644 src/views/drone/images/home/uav.png create mode 100644 src/views/drone/images/hover.png create mode 100644 src/views/drone/images/huifu.png create mode 100644 src/views/drone/images/importpath.png create mode 100644 src/views/drone/images/importpathh.png create mode 100644 src/views/drone/images/jichang.png create mode 100644 src/views/drone/images/left.png create mode 100644 src/views/drone/images/left_f.png create mode 100644 src/views/drone/images/loading.png create mode 100644 src/views/drone/images/loadingdow.gif create mode 100644 src/views/drone/images/medium/arrow.png create mode 100644 src/views/drone/images/medium/close.png create mode 100644 src/views/drone/images/medium/delete.png create mode 100644 src/views/drone/images/medium/down-load.png create mode 100644 src/views/drone/images/medium/files-icon.png create mode 100644 src/views/drone/images/medium/medium-img.png create mode 100644 src/views/drone/images/medium/medium-storage.png create mode 100644 src/views/drone/images/medium/medium-video.png create mode 100644 src/views/drone/images/medium/prview-icon.png create mode 100644 src/views/drone/images/medium/refresh.png create mode 100644 src/views/drone/images/medium/video-icon.png create mode 100644 src/views/drone/images/more1.png create mode 100644 src/views/drone/images/more2.png create mode 100644 src/views/drone/images/point.png create mode 100644 src/views/drone/images/right.png create mode 100644 src/views/drone/images/right_f.png create mode 100644 src/views/drone/images/save.png create mode 100644 src/views/drone/images/saveh.png create mode 100644 src/views/drone/images/shanchu.png create mode 100644 src/views/drone/images/switch.png create mode 100644 src/views/drone/images/switchh.png create mode 100644 src/views/drone/images/tab.png create mode 100644 src/views/drone/images/tab_h.png create mode 100644 src/views/drone/images/time.png create mode 100644 src/views/drone/images/title.png create mode 100644 src/views/drone/images/top.png create mode 100644 src/views/drone/images/top_r.png create mode 100644 src/views/drone/images/wurenji.png create mode 100644 src/views/drone/images/zanting.png create mode 100644 src/views/drone/index.vue create mode 100644 src/views/drone/style/common.scss create mode 100644 src/views/drone/utils/options.js diff --git a/.env.development b/.env.development index 130d28f..3c4befe 100644 --- a/.env.development +++ b/.env.development @@ -7,6 +7,10 @@ VITE_APP_ENV = 'development' # 开发环境 VITE_APP_BASE_API = 'http://192.168.110.8:8899' +# 无人机接口地址 + +VITE_APP_BASE_DRONE_API = 'http://192.168.110.8:9136' + # 应用访问路径 例如使用前缀 /admin/ VITE_APP_CONTEXT_PATH = '/' diff --git a/index.html b/index.html index 62132b4..d1d62af 100644 --- a/index.html +++ b/index.html @@ -210,6 +210,7 @@ + diff --git a/package.json b/package.json index e71cc07..c8c9d9e 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,9 @@ "js-cookie": "3.0.5", "js-md5": "^0.8.3", "jsencrypt": "3.3.2", + "jszip": "^3.10.1", + "lodash": "^4.17.21", + "md5": "^2.3.0", "mitt": "^3.0.1", "nprogress": "0.2.0", "ol": "^10.5.0", diff --git a/src/api/air/index.ts b/src/api/air/index.ts new file mode 100644 index 0000000..0804f13 --- /dev/null +++ b/src/api/air/index.ts @@ -0,0 +1,430 @@ +import { request } from '../../utils/requset2.js'; + +// 开关空调 +export function airConditionerModeSwitch(data) { + return request({ + url: '/dj/remote/debug/airConditionerModeSwitch', + method: 'post', + data + }); +} +// 生成航线文件 +export function waypoint(data) { + return request({ + url: '/dj/router/waypoint', + method: 'post', + data + }); +} +// 创建任务 /dj/task/create +export function taskCreate(data) { + return request({ + url: '/dj/missions/create', + method: 'post', + data + }); +} +// 下发任务 /dj/flightTaskPrepare +export function flightTaskPrepare(data) { + return request({ + url: '/dj/flightTaskPrepare', + method: 'post', + data + }); +} +// 执行任务 +export function flightTaskExecute(data) { + return request({ + url: '/dj/flightTaskExecute', + method: 'post', + data + }); +} + +// 取消任务 +export function flightTaskUndo(data) { + return request({ + url: '/dj/flightTaskUndo', + method: 'post', + data + }); +} + +// 恢复航线 +export function flightTaskRecovery(data) { + return request({ + url: '/dj/flightTaskRecovery', + method: 'post', + data + }); +} + +// 恢复航线 +export function flightTaskPause(data) { + return request({ + url: '/dj/flightTaskPause', + method: 'post', + data + }); +} + +// 一键返航 +export function returnHome(data) { + return request({ + url: '/dj/returnHome', + method: 'post', + data + }); +} + +// 无参飞行指令 +export function noDataFlight(data) { + return request({ + url: '/dj/cmdFly/noDataFlight', + method: 'post', + data + }); +} + +// 有参飞行指令 +export function hasDataFlight(data) { + return request({ + url: '/dj/cmdFly/hasDataFlight', + method: 'post', + data + }); +} +// 开启指令 +export function drcModeEnte(data) { + return request({ + url: '/dj/cmdFly/drcModeEnter', + method: 'post', + data + }); +} + +// 查询航线文件信息列表 +export function listPaths(query) { + return request({ + url: '/system/paths/list', + method: 'get', + params: query + }); +} + +// 删除航线文件信息 +export function delPaths(id) { + return request({ + url: '/system/paths/' + id, + method: 'delete' + }); +} + +// 查询任务列表 +export function listTasks(query) { + return request({ + url: '/system/tasks/list', + method: 'get', + params: query + }); +} + +// 查询无人机任务列表 +export function listMissions(query) { + return request({ + url: '/system/missions/list', + method: 'get', + params: query + }); +} + +// 删除无人机任务 +export function delMissions(id) { + return request({ + url: '/system/missions/' + id, + method: 'delete' + }); +} + +// 远程调试 +export function remoteDebug(data) { + return request({ + url: '/dj/remote/debug/service', + method: 'post', + data + }); +} +// 增强图传 +export function sdrWorkmodeSwitch(data) { + return request({ + url: '/dj/remote/debug/sdrWorkmodeSwitch', + method: 'post', + data + }); +} + +// 查询视频设备列表 +export function listInfo(query) { + return request({ + url: '/system/info/list', + method: 'get', + params: query + }); +} +// 登录 +export function login(data) { + return request({ + url: '/login', + headers: { + isToken: false, + repeatSubmit: false + }, + method: 'post', + data: data + }); +} + +// 获取文件 +export function getFileByflightId(data) { + return request({ + url: '/dj/getFileByflightId', + method: 'post', + data + }); +} + +// 机场列表 +export function droneList(data) { + return request({ + url: '/system/drone/list', + method: 'get', + data + }); +} + +// 监听网关 +export function gatewaysAdd(data) { + return request({ + url: '/dj/gateways/add', + method: 'post', + data + }); +} + +// 关闭网关 +export function gatewaysRemove(data) { + return request({ + url: '/dj/gateways/remove', + method: 'delete', + data + }); +} + +// 添加航线 +export function routerAdd(data) { + return request({ + url: '/dj/router/add', + method: 'post', + data + }); +} + +// 复制航线 /dj/router/copy/{id} +export function routerCopy(id) { + return request({ + url: '/dj/router/copy/' + id, + method: 'post' + }); +} +// 重命名文件 + +export function routerRename(data) { + return request({ + url: '/dj/router/rename', + method: 'post', + data + }); +} +// 获取文件 +export function takeoffList(data) { + return request({ + url: '/system/takeoff/list', + method: 'get', + data + }); +} + +// 切换直播流 +export function liveChange(data) { + return request({ + url: '/dj/live/change', + method: 'post', + data + }); +} + +// 设置清晰度 /dj/live/quality +export function liveChangeQuality(data) { + return request({ + url: '/dj/live/quality', + method: 'post', + data + }); +} + +// 开启直播 +export function liveStart(data) { + return request({ + url: '/dj/live/start', + method: 'post', + data + }); +} +// 关闭直播 +export function liveStop(data) { + return request({ + url: '/dj/live/stop', + method: 'post', + data + }); +} +// 静音模式开关 +export function propertySet(data) { + return request({ + url: '/property/set', + method: 'post', + data + }); +} + +// 直播相机切换 +export function cameraChange(data) { + return request({ + url: '/dj/live/camera/change', + method: 'post', + data + }); +} + +// 新建计划 +export function taskAdd(data) { + return request({ + url: '/dj/task/add', + method: 'post', + data + }); +} + +// 计划列表 +export function taskList(data) { + return request({ + url: '/dj/task/list', + method: 'get', + params: data + }); +} +// 新暂停 +export function flightTaskPauseNew(data) { + return request({ + url: '/dj/task/flightTaskPause', + method: 'post', + data + }); +} +// 新恢复 +export function flightTaskRecoveryNew(data) { + return request({ + url: '/dj/task/flightTaskRecovery', + method: 'post', + data + }); +} +// 取消任务 +export function flightTaskUndoNew(data) { + return request({ + url: '/dj/task/flightTaskUndo', + method: 'post', + data + }); +} +// 一键返航 post +export function returnHomeNew(data) { + return request({ + url: '/dj/task/returnHome', + method: 'post', + data + }); +} +// 删除 +export function delMissionsNew(id) { + return request({ + url: '/system/new/missions/' + id, + method: 'delete' + }); +} + +// drc飞行控制 /dj/cmdFly/droneControl +export function droneControl(data) { + return request({ + url: '/dj/cmdFly/droneControl', + method: 'post', + data + }); +} + +// drc急停 /dj/cmdFly/droneEmergencyStop +export function droneEmergencyStop(data) { + return request({ + url: '/dj/cmdFly/droneEmergencyStop', + method: 'post', + data + }); +} + +// 取消返航 /dj/returnHomeCancel +export function returnHomeCancel(data) { + return request({ + url: '/dj/returnHomeCancel', + method: 'post', + data + }); +} + +// 导入航线 +export function returnImport(data) { + return request({ + url: '/dj/router/import', + method: 'post', + data, + headers: { + 'Content-Type': 'multipart/form-data' + } + }); +} + +// DRC心跳 +export function heartBeat(data) { + return request({ + url: '/dj/cmdFly/heartBeat', + method: 'post', + data + }); +} + +// AI识别 +export function aiInfo(data) { + return request({ + url: '/minio/ai/info', + method: 'get', + params: data + }); +} + +// 当前最新任务 +export function getLatest(data) { + return request({ + url: '/dj/task/getLatest', + method: 'get', + params: data + }); +} diff --git a/src/api/fileMangement/index.ts b/src/api/fileMangement/index.ts new file mode 100644 index 0000000..4c7b9df --- /dev/null +++ b/src/api/fileMangement/index.ts @@ -0,0 +1,118 @@ +import { request } from '../../utils/requset2'; +// 获取文件列表 +export function getFiles(data) { + return request({ + url: '/minio/file', + method: 'get', + data, + params: data + }); +} +// 获取ai文件列表 +export function getAiFiles(data) { + return request({ + url: '/minio/ai/file', + method: 'get', + data, + params: data + }); +} +// 获取文件信息 +export function getInfo(data) { + return request({ + url: '/minio/info', + method: 'get', + data, + params: data, + timeout: 30000 + }); +} +// 获取ai文件信息 +export function getAiInfo(data) { + return request({ + url: '/minio/ai/info', + method: 'get', + data, + params: data, + timeout: 30000 + }); +} +// 下载文件 +export function fileDownload(params, onProgress) { + return request({ + url: '/minio/download', + method: 'post', + params, + responseType: 'blob', + timeout: 0, + // header: { + // "Content-Length": Buffer.byteLength(JSON.stringify(params)), + // }, + onDownloadProgress: (progressEvent) => { + if (onProgress && typeof onProgress === 'function') { + const { loaded, total } = progressEvent; + console.log('progressEvent', progressEvent); + const percentage = Math.round((loaded / total) * 100); // 计算百分比 + onProgress(percentage); // 调用传入的 onProgress 回调函数 + } + } + }); +} +// 删除文件 +export function deleteFile(data) { + return request({ + url: '/minio/deleteBatch', + method: 'delete', + data, + timeout: 0 + }); +} +// 删除ai文件 +export function deleteAiFile(data) { + return request({ + url: '/minio/ai/deleteBatch', + method: 'delete', + data, + timeout: 0 + }); +} +// 批量下载文件或目录 +export function downloadBatch(data, onProgress) { + return request({ + url: '/minio/downloadBatch', + method: 'post', + responseType: 'blob', + data, + timeout: 0, + onDownloadProgress: (progressEvent) => { + if (onProgress && typeof onProgress === 'function') { + const { loaded, total } = progressEvent; + console.log('progressEvent', progressEvent); + const percentage = Math.round((loaded / total) * 100); // 计算百分比 + onProgress(percentage); // 调用传入的 onProgress 回调函数 + } + } + }); +} + +// 获取某个目录下面的所有文件的URL列表 +export function getUrlList(data) { + return request({ + url: '/minio/urlList', + method: 'post', + data, + params: data, + timeout: 0 + }); +} +// 获取某个目录下面的所有文件的URL列表 + +export function getAiUrlList(data) { + return request({ + url: '/minio/ai/urlList', + method: 'post', + data, + params: data, + timeout: 0 + }); +} diff --git a/src/api/gis/index.ts b/src/api/gis/index.ts index 5413341..e6c9de9 100644 --- a/src/api/gis/index.ts +++ b/src/api/gis/index.ts @@ -9,7 +9,8 @@ import { projectNewsVO, safetyInspectionVO, projectNewsDetailVO, - weatherVO + weatherVO, + safetyDayVO } from './type'; /** * 查询大屏质量信息 @@ -120,3 +121,16 @@ export const getweatherList = (id?: string): AxiosPromise => { method: 'get' }); }; + +/** + * 查询项目安全天数 + * @param query + * @returns {*} + */ + +export const getSafetyDay = (id?: string): AxiosPromise => { + return request({ + url: '/project/project/safetyDay/' + id, + method: 'get' + }); +}; diff --git a/src/api/gis/type.ts b/src/api/gis/type.ts index badb6ac..adfaf92 100644 --- a/src/api/gis/type.ts +++ b/src/api/gis/type.ts @@ -86,3 +86,7 @@ export interface weatherVO { sunRise: string; sunSet: string; } + +export interface safetyDayVO { + safetyDay: string; +} diff --git a/src/components/webrtc/index.vue b/src/components/webrtc/index.vue new file mode 100644 index 0000000..7f240ed --- /dev/null +++ b/src/components/webrtc/index.vue @@ -0,0 +1,57 @@ + + + + + diff --git a/src/main.ts b/src/main.ts index 463e8f5..7bd461b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -46,11 +46,21 @@ VXETable.config({ zIndex: 999999 }); +//本地保存飞机配置 +import { setLocal } from './utils'; +setLocal('dockair', 'http://192.168.110.24:9136'); +setLocal('aiurl', 'http://192.168.110.23:8000'); +setLocal('host', '192.168.110.199'); +setLocal('rtmpport', '1935'); +setLocal('rtcport', '1985'); +setLocal('dockSocketUrl', 'ws://192.168.110.8:9136/websocket'); + // 修改 el-dialog 默认点击遮照为不关闭 /*import { ElDialog } from 'element-plus'; ElDialog.props.closeOnClickModal.default = false;*/ // **main.js** import { vue3ScrollSeamless } from 'vue3-scroll-seamless'; +import bus from './utils/bus'; const app = createApp(App); @@ -62,6 +72,7 @@ app.use(print); app.use(i18n); app.use(VXETable); app.use(plugins); +app.use(bus); app.component('vue3ScrollSeamless', vue3ScrollSeamless); // 自定义指令 directive(app); diff --git a/src/router/index.ts b/src/router/index.ts index e5174d3..0c7f264 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -98,6 +98,11 @@ export const constantRoutes: RouteRecordRaw[] = [ path: '/gisHome', component: () => import('@/views/gisHome/index.vue'), hidden: true + }, + { + path: '/drone', + component: () => import('@/views/drone/index.vue'), + hidden: true } ]; diff --git a/src/store/modules/drone.ts b/src/store/modules/drone.ts new file mode 100644 index 0000000..4b6feeb --- /dev/null +++ b/src/store/modules/drone.ts @@ -0,0 +1,42 @@ +// stores/useAirStore.js +import { getLocal } from '@/utils'; +import { defineStore } from 'pinia'; + +export const useAirStore = defineStore('air', { + state: () => ({ + debugValue: false, // 远程调试模式 + HatchCoverValue: false, // 舱盖 + AerocraftValue: false, // 飞行器 + gateWay: JSON.parse(getLocal('airGateway')) || null, // + queryParams: { + target_height: 100, //目标点高度 + rth_altitude: 100, //返航高度 + commander_flight_height: 100, //指点飞行高度 + rc_lost_action: 2, //遥控器失控动作 + rth_mode: 1, //返航模式设置值 + commander_mode_lost_action: 1, //指点飞行失控动作 + commander_flight_mode: 1, //指点飞行模式设置值 + max_speed: 12, //一键起飞的飞行过程中能达到的最大速度 + security_takeoff_height: 100, //安全起飞高度 + target_latitude: 0, //目标点纬度 + target_longitude: 0, //目标点经度 + height: 100 + } + }), + + actions: { + UP_debugValue(payload) { + localStorage.setItem('debugValue', JSON.stringify(payload)); + }, + UP_HatchCoverValue(payload) { + localStorage.setItem('HatchCoverValue', JSON.stringify(payload)); + }, + UP_AerocraftValue(payload) { + localStorage.setItem('AerocraftValue', JSON.stringify(payload)); + }, + SET_GATEWAY(gateWay) { + this.gateWay = gateWay; + localStorage.setItem('airGateway', JSON.stringify(gateWay)); + } + } +}); diff --git a/src/utils/auth.ts b/src/utils/auth.ts index db50ac9..0b21b0b 100644 --- a/src/utils/auth.ts +++ b/src/utils/auth.ts @@ -1,3 +1,5 @@ +import { getLocal } from '.'; + const TokenKey = 'Admin-Token'; const tokenStorage = useStorage(TokenKey, null); @@ -7,3 +9,27 @@ export const getToken = () => tokenStorage.value; export const setToken = (access_token: string) => (tokenStorage.value = access_token); export const removeToken = () => (tokenStorage.value = null); + +export const getDockSocketUrl = () => { + return getLocal('dockSocketUrl'); +}; + +export const getHost = () => { + return getLocal('host'); +}; + +export const getRtmpPort = () => { + return getLocal('rtmpPort'); +}; + +export const getRtcPort = () => { + return getLocal('rtcPort'); +}; + +export const getDockAir = () => { + return getLocal('dockAir'); +}; + +export const getAiUrl = () => { + return getLocal('aiUrl'); +}; diff --git a/src/utils/bus.ts b/src/utils/bus.ts new file mode 100644 index 0000000..10905eb --- /dev/null +++ b/src/utils/bus.ts @@ -0,0 +1,22 @@ +import mitt from 'mitt'; + +const emitter = mitt(); + +export default { + install(app) { + // 发送事件 + app.config.globalProperties.$sendChanel = (event, payload) => { + emitter.emit(event, payload); + }; + + // 监听事件(返回取消函数) + app.config.globalProperties.$recvChanel = (event, handler) => { + emitter.on(event, handler); + + // 可选:返回解绑函数,方便使用 + return () => { + emitter.off(event, handler); + }; + }; + } +}; diff --git a/src/utils/index.ts b/src/utils/index.ts index 2b0aad5..1f12e5e 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,5 +1,5 @@ import { parseTime } from '@/utils/ruoyi'; - +import $cache from '@/plugins/cache'; /** * 表格时间格式化 */ @@ -15,6 +15,14 @@ export const formatDate = (cellValue: string) => { return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds; }; +export const setLocal = (key, value) => { + return $cache.local.set(key, value); +}; + +export const getLocal = (key) => { + return $cache.local.get(key); +}; + /** * @param {number} time * @param {string} option @@ -316,3 +324,5 @@ export const removeClass = (ele: HTMLElement, cls: string) => { export const isExternal = (path: string) => { return /^(https?:|http?:|mailto:|tel:)/.test(path); }; + +export { parseTime }; diff --git a/src/utils/moveDiv.ts b/src/utils/moveDiv.ts new file mode 100644 index 0000000..1895e22 --- /dev/null +++ b/src/utils/moveDiv.ts @@ -0,0 +1,40 @@ +export function setMove(downId, moveID) { + let moveDiv = document.getElementById(downId) + moveDiv.style.cssText += ';cursor:move;' + let informationBox = document.getElementById(moveID) + const sty = (() => { + if (window.document.currentStyle) { + return (dom, attr) => dom.currentStyle[attr]; + } else { + return (dom, attr) => getComputedStyle(dom, false)[attr]; + } + })() + moveDiv.onmousedown = (e) => { + // 鼠标按下,计算当前元素距离可视区的距离 + const disX = e.clientX - moveDiv.offsetLeft; + const disY = e.clientY - moveDiv.offsetTop; + // 获取到的值带px 正则匹配替换 + let styL = sty(informationBox, 'left'); + let styT = sty(informationBox, 'top'); + // 第一次获取到的值为组件自带50% 移动之后赋值为px + if (styL.includes('%')) { + styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100); + styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100); + } else { + styL = +styL.replace(/\px/g, ''); + styT = +styT.replace(/\px/g, ''); + } + document.onmousemove = function (e) { + // 通过事件委托,计算移动的距离 + let left = e.clientX - disX; + let top = e.clientY - disY; + // 移动当前元素 + informationBox.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`; + }; + document.onmouseup = function (e) { + document.onmousemove = null; + document.onmouseup = null; + }; + } +} + diff --git a/src/utils/reconnecting-websocket.js b/src/utils/reconnecting-websocket.js new file mode 100644 index 0000000..40218d3 --- /dev/null +++ b/src/utils/reconnecting-websocket.js @@ -0,0 +1,382 @@ +// MIT License: +// +// Copyright (c) 2010-2012, Joe Walnes +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/** + * This behaves like a WebSocket in every way, except if it fails to connect, + * or it gets disconnected, it will repeatedly poll until it successfully connects + * again. + * + * It is API compatible, so when you have: + * ws = new WebSocket('ws://....'); + * you can replace with: + * ws = new ReconnectingWebSocket('ws://....'); + * + * The event stream will typically look like: + * onconnecting + * onopen + * onmessage + * onmessage + * onclose // lost connection + * onconnecting + * onopen // sometime later... + * onmessage + * onmessage + * etc... + * + * It is API compatible with the standard WebSocket API, apart from the following members: + * + * - `bufferedAmount` + * - `extensions` + * - `binaryType` + * + * Latest version: https://github.com/joewalnes/reconnecting-websocket/ + * - Joe Walnes + * + * Syntax + * ====== + * var socket = new ReconnectingWebSocket(url, protocols, options); + * + * Parameters + * ========== + * url - The url you are connecting to. + * protocols - Optional string or array of protocols. + * options - See below + * + * Options + * ======= + * Options can either be passed upon instantiation or set after instantiation: + * + * var socket = new ReconnectingWebSocket(url, null, { debug: true, reconnectInterval: 4000 }); + * + * or + * + * var socket = new ReconnectingWebSocket(url); + * socket.debug = true; + * socket.reconnectInterval = 4000; + * + * debug + * - Whether this instance should log debug messages. Accepts true or false. Default: false. + * + * automaticOpen + * - Whether or not the websocket should attempt to connect immediately upon instantiation. The socket can be manually opened or closed at any time using ws.open() and ws.close(). + * + * reconnectInterval + * - The number of milliseconds to delay before attempting to reconnect. Accepts integer. Default: 1000. + * + * maxReconnectInterval + * - The maximum number of milliseconds to delay a reconnection attempt. Accepts integer. Default: 30000. + * + * reconnectDecay + * - The rate of increase of the reconnect delay. Allows reconnect attempts to back off when problems persist. Accepts integer or float. Default: 1.5. + * + * timeoutInterval + * - The maximum time in milliseconds to wait for a connection to succeed before closing and retrying. Accepts integer. Default: 2000. + * + */ +// (function (global, factory) { +// if (typeof define === 'function' && define.amd) { +// define([], factory); +// } else if (typeof module !== 'undefined' && module.exports){ +// module.exports = factory(); +// } else { +// global.ReconnectingWebSocket = factory(); +// } +// })(this, function () { +// +// if (!('WebSocket' in window)) { +// return; +// } + +function ReconnectingWebSocket(url, protocols, options) { + + // Default settings + var settings = { + + /** Whether this instance should log debug messages. */ + debug: false, + + /** Whether or not the websocket should attempt to connect immediately upon instantiation. */ + automaticOpen: true, + + /** The number of milliseconds to delay before attempting to reconnect. */ + reconnectInterval: 1000, + /** The maximum number of milliseconds to delay a reconnection attempt. */ + maxReconnectInterval: 30000, + /** The rate of increase of the reconnect delay. Allows reconnect attempts to back off when problems persist. */ + reconnectDecay: 1.5, + + /** The maximum time in milliseconds to wait for a connection to succeed before closing and retrying. */ + timeoutInterval: 2000, + + /** The maximum number of reconnection attempts to make. Unlimited if null. */ + maxReconnectAttempts: null, + + /** The binary type, possible values 'blob' or 'arraybuffer', default 'blob'. */ + binaryType: 'blob' + } + if (!options) { + options = {}; + } + + // Overwrite and define settings with options if they exist. + for (var key in settings) { + if (typeof options[key] !== 'undefined') { + this[key] = options[key]; + } else { + this[key] = settings[key]; + } + } + + // These should be treated as read-only properties + + /** The URL as resolved by the constructor. This is always an absolute URL. Read only. */ + this.url = url; + + /** The number of attempted reconnects since starting, or the last successful connection. Read only. */ + this.reconnectAttempts = 0; + + /** + * The current state of the connection. + * Can be one of: WebSocket.CONNECTING, WebSocket.OPEN, WebSocket.CLOSING, WebSocket.CLOSED + * Read only. + */ + this.readyState = WebSocket.CONNECTING; + + /** + * A string indicating the name of the sub-protocol the server selected; this will be one of + * the strings specified in the protocols parameter when creating the WebSocket object. + * Read only. + */ + this.protocol = null; + + // Private state variables + + var self = this; + var ws; + var forcedClose = false; + var timedOut = false; + var eventTarget = document.createElement('div'); + + // Wire up "on*" properties as event handlers + + eventTarget.addEventListener('open', function (event) { + self.onopen(event); + }); + eventTarget.addEventListener('close', function (event) { + self.onclose(event); + }); + eventTarget.addEventListener('connecting', function (event) { + self.onconnecting(event); + }); + eventTarget.addEventListener('message', function (event) { + self.onmessage(event); + }); + eventTarget.addEventListener('error', function (event) { + self.onerror(event); + }); + + // Expose the API required by EventTarget + + this.addEventListener = eventTarget.addEventListener.bind(eventTarget); + this.removeEventListener = eventTarget.removeEventListener.bind(eventTarget); + this.dispatchEvent = eventTarget.dispatchEvent.bind(eventTarget); + + /** + * This function generates an event that is compatible with standard + * compliant browsers and IE9 - IE11 + * + * This will prevent the error: + * Object doesn't support this action + * + * http://stackoverflow.com/questions/19345392/why-arent-my-parameters-getting-passed-through-to-a-dispatched-event/19345563#19345563 + * @param s String The name that the event should use + * @param args Object an optional object that the event will use + */ + function generateEvent(s, args) { + var evt = document.createEvent("CustomEvent"); + evt.initCustomEvent(s, false, false, args); + return evt; + }; + + this.open = function (reconnectAttempt) { + ws = new WebSocket(self.url, protocols || []); + ws.binaryType = this.binaryType; + + if (reconnectAttempt) { + if (this.maxReconnectAttempts && this.reconnectAttempts > this.maxReconnectAttempts) { + return; + } + } else { + eventTarget.dispatchEvent(generateEvent('connecting')); + this.reconnectAttempts = 0; + } + + if (self.debug || ReconnectingWebSocket.debugAll) { + console.debug('ReconnectingWebSocket', 'attempt-connect', self.url); + } + + var localWs = ws; + var timeout = setTimeout(function () { + if (self.debug || ReconnectingWebSocket.debugAll) { + console.debug('ReconnectingWebSocket', 'connection-timeout', self.url); + } + timedOut = true; + localWs.close(); + timedOut = false; + }, self.timeoutInterval); + + ws.onopen = function (event) { + clearTimeout(timeout); + if (self.debug || ReconnectingWebSocket.debugAll) { + console.debug('ReconnectingWebSocket', 'onopen', self.url); + } + self.protocol = ws.protocol; + self.readyState = WebSocket.OPEN; + self.reconnectAttempts = 0; + var e = generateEvent('open'); + e.isReconnect = reconnectAttempt; + reconnectAttempt = false; + eventTarget.dispatchEvent(e); + }; + + ws.onclose = function (event) { + clearTimeout(timeout); + ws = null; + if (forcedClose) { + self.readyState = WebSocket.CLOSED; + eventTarget.dispatchEvent(generateEvent('close')); + } else { + self.readyState = WebSocket.CONNECTING; + var e = generateEvent('connecting'); + e.code = event.code; + e.reason = event.reason; + e.wasClean = event.wasClean; + eventTarget.dispatchEvent(e); + if (!reconnectAttempt && !timedOut) { + if (self.debug || ReconnectingWebSocket.debugAll) { + console.debug('ReconnectingWebSocket', 'onclose', self.url); + } + eventTarget.dispatchEvent(generateEvent('close')); + } + + var timeout = self.reconnectInterval * Math.pow(self.reconnectDecay, self.reconnectAttempts); + setTimeout(function () { + self.reconnectAttempts++; + self.open(true); + }, timeout > self.maxReconnectInterval ? self.maxReconnectInterval : timeout); + } + }; + ws.onmessage = function (event) { + if (self.debug || ReconnectingWebSocket.debugAll) { + console.debug('ReconnectingWebSocket', 'onmessage', self.url, event.data); + } + var e = generateEvent('message'); + e.data = event.data; + eventTarget.dispatchEvent(e); + }; + ws.onerror = function (event) { + if (self.debug || ReconnectingWebSocket.debugAll) { + console.debug('ReconnectingWebSocket', 'onerror', self.url, event); + } + eventTarget.dispatchEvent(generateEvent('error')); + }; + } + + // Whether or not to create a websocket upon instantiation + if (this.automaticOpen == true) { + this.open(false); + } + + /** + * Transmits data to the server over the WebSocket connection. + * + * @param data a text string, ArrayBuffer or Blob to send to the server. + */ + this.send = function (data) { + if (ws) { + if (self.debug || ReconnectingWebSocket.debugAll) { + console.debug('ReconnectingWebSocket', 'send', self.url, data); + } + return ws.send(data); + } else { + throw 'INVALID_STATE_ERR : Pausing to reconnect websocket'; + } + }; + + /** + * Closes the WebSocket connection or connection attempt, if any. + * If the connection is already CLOSED, this method does nothing. + */ + this.close = function (code, reason) { + // Default CLOSE_NORMAL code + if (typeof code == 'undefined') { + code = 1000; + } + forcedClose = true; + if (ws) { + ws.close(code, reason); + } + }; + + /** + * Additional public API method to refresh the connection if still open (close, re-open). + * For example, if the app suspects bad data / missed heart beats, it can try to refresh. + */ + this.refresh = function () { + if (ws) { + ws.close(); + } + }; +} + +/** + * An event listener to be called when the WebSocket connection's readyState changes to OPEN; + * this indicates that the connection is ready to send and receive data. + */ +ReconnectingWebSocket.prototype.onopen = function (event) { +}; +/** An event listener to be called when the WebSocket connection's readyState changes to CLOSED. */ +ReconnectingWebSocket.prototype.onclose = function (event) { +}; +/** An event listener to be called when a connection begins being attempted. */ +ReconnectingWebSocket.prototype.onconnecting = function (event) { +}; +/** An event listener to be called when a message is received from the server. */ +ReconnectingWebSocket.prototype.onmessage = function (event) { +}; +/** An event listener to be called when an error occurs. */ +ReconnectingWebSocket.prototype.onerror = function (event) { +}; + +/** + * Whether all instances of ReconnectingWebSocket should log debug messages. + * Setting this to true is the equivalent of setting all instances of ReconnectingWebSocket.debug to true. + */ +ReconnectingWebSocket.debugAll = false; + +ReconnectingWebSocket.CONNECTING = WebSocket.CONNECTING; +ReconnectingWebSocket.OPEN = WebSocket.OPEN; +ReconnectingWebSocket.CLOSING = WebSocket.CLOSING; +ReconnectingWebSocket.CLOSED = WebSocket.CLOSED; + +// return ReconnectingWebSocket; +// }); diff --git a/src/utils/requset2.ts b/src/utils/requset2.ts new file mode 100644 index 0000000..03ff7b9 --- /dev/null +++ b/src/utils/requset2.ts @@ -0,0 +1,55 @@ +import $modal from '@/plugins/modal'; +import axios from 'axios'; + +// 创建一个 Axios 实例并设置默认配置 +const axiosInstance = axios.create({ + baseURL: import.meta.env.VITE_APP_BASE_DRONE_API, + timeout: 5000 +}); + +// 请求拦截器,添加 token 到每个请求头 +axiosInstance.interceptors.request.use( + (config) => { + let air = localStorage.getItem('airToken'); + let token = ''; + if (air) { + token = JSON.parse(air).access_token; // 假设 token 存储在 localStorage 中 + } + if (token) { + config.headers['Authorization'] = `Bearer ${token}`; + } + return config; + }, + (error) => { + return Promise.reject(error); + } +); +// 处理消息显示 +function showMessage(message, type = 'error') { + $modal.msg({ + message: message, + type: type, + duration: 5 * 1000 + }); +} + +export function request(params) { + // 如果有取消请求的需求,可以在此处添加 CancelToken + // const source = axios.CancelToken.source(); + // params.cancelToken = source.token; + + // 确保 URL 是完整的 + // if (!params.url.startsWith(process.env.AIR)) { + // params.url = process.env.AIR; + // } + + return axiosInstance(params).then((res) => { + if (res.data.code === 200) { + return res.data; + } else { + if (!res.data.code) return res.data; + showMessage(res.data.message || res.data.msg); + return Promise.reject(res.data); + } + }); +} diff --git a/src/views/drone/components/airRoute/advancedSet.vue b/src/views/drone/components/airRoute/advancedSet.vue new file mode 100644 index 0000000..396b7cb --- /dev/null +++ b/src/views/drone/components/airRoute/advancedSet.vue @@ -0,0 +1,370 @@ + + + + diff --git a/src/views/drone/components/airRoute/js/pointSetup.js b/src/views/drone/components/airRoute/js/pointSetup.js new file mode 100644 index 0000000..2f2ac36 --- /dev/null +++ b/src/views/drone/components/airRoute/js/pointSetup.js @@ -0,0 +1,750 @@ +import { waypoint } from "@/api/air"; +export default { + data() { + return { + leftShow: false, + pzDisabled: false, + keywordShow: false, + setupShow: false, + selectId: null, + inputShow: false, + selectObj: { + label: "", + params: {}, + type: "", + }, // 选中的动作 + selectIndexF: null, + selectIndexS: null, + checkboxGroup1: ["visable", "ir"], + checkboxGroup2: ["wide", "ir", "zoom"], + startPoint: null, + pohoto: [ + { + label: "可见光", + value: "visable", + }, + { + label: "红外照片", + value: "ir", + }, + ], + pohoto1: [ + { + label: "广角照片", + value: "wide", + }, + { + label: "红外照片", + value: "ir", + }, + { + label: "变焦照片", + value: "zoom", + }, + ], + dropdownList: [ + { + label: "新增航点(前)", + value: 1, + type: "before", + }, + { + label: "新增航点(后)", + value: 2, + type: "after", + }, + { + label: "删除", + value: 3, + }, + ], + controls: [ + { + url: require("../../../images/control_start.png"), + label: "开始录像", + value: "startRecord", + svg: "start_record", + params: { + fileSuffix: "123456", + payloadPositionIndex: 0, + useGlobalPayloadLensIndex: 1, //是否使用全局 1为使用全局 0不使用全局 + payloadLensIndex: "visable,ir", + }, + }, + { + url: require("../../../images/control_suspend.png"), + label: "停止录像", + value: "stopRecord", + svg: "stop_record", + params: { + payloadPositionIndex: 0, + }, + }, + // { + // url: require("../../../images/control_Isochronous.png"), + // label: "开始等时间隔拍照", + // value: "takePhoto", + // svg: "interval_time", + // params: { + // payloadPositionIndex: 0, + // useGlobalPayloadLensIndex: 1, + // payloadLensIndex: "visable,ir", + // }, + // actionTrigger: { + // actionTriggerType: "multipleTiming", + // actionTriggerParam: 10, + // }, + // }, + // { + // url: require("../../../images/control_equidistant.png"), + // label: "开始等距间隔拍照", + // value: "takePhoto", + // svg: "interval_distance", + // params: { + // payloadPositionIndex: 0, + // useGlobalPayloadLensIndex: 1, + // payloadLensIndex: "visable,ir", + // }, + // actionTrigger: { + // actionTriggerType: "multipleDistance", + // actionTriggerParam: 10, + // }, + // }, + // { + // url: require("../../../images/control_interval.png"), + // label: "结束间隔拍照", + // value: "", + // svg: "interval_stop", + // }, + { + url: require("../../../images/control_hover.png"), + label: "悬停", + value: "hover", + svg: "hover", + params: { + hoverTime: 10, + }, + }, + { + url: require("../../../images/control_aircraft.png"), + label: "飞行器偏航角", + value: "rotateYaw", + svg: "drone_yaw", + params: { + aircraftHeading: 0, + aircraftPathMode: "counterClockwise", + }, + }, + // { + // url: require("../../../images/control_yaw.png"), + // label: "云台偏航角", + // value: "gimbalRotate", + // svg: "action_gimbal_pitch", + // params: { + // gimbalHeadingYawBase: "north", + // gimbalRotateMode: "absoluteAngle", + // gimbalPitchRotateEnable: 1, + // gimbalPitchRotateAngle: 0, + // gimbalRollRotateEnable: 0, + // gimbalRollRotateAngle: 0, + // gimbalYawRotateEnable: 0, + // gimbalYawRotateAngle: 0, + // gimbalRotateTimeEnable: 0, + // gimbalRotateTime: 0, + // payloadPositionIndex: 0, + // }, + // }, + { + url: require("../../../images/control_pitch.png"), + label: "云台俯仰角", + value: "gimbalRotate", + svg: "action_gimbal_pitch", + params: { + gimbalHeadingYawBase: "north", + gimbalRotateMode: "absoluteAngle", + gimbalPitchRotateEnable: 1, + gimbalPitchRotateAngle: 0, // 变化的值 + gimbalRollRotateEnable: 0, + gimbalRollRotateAngle: 0, + gimbalYawRotateEnable: 0, + gimbalYawRotateAngle: 0, + gimbalRotateTimeEnable: 0, + gimbalRotateTime: 0, + payloadPositionIndex: 0, + }, + }, + { + url: require("../../../images/control_photograph.png"), + label: "拍照", + value: "takePhoto", + svg: "take_photo", + params: { + payloadPositionIndex: 0, + useGlobalPayloadLensIndex: 1, + payloadLensIndex: "wide,zoom,ir", + }, + }, + { + url: require("../../../images/control_zoom.png"), + label: "相机变焦", + value: "zoom", + svg: "camera_zoom", + params: { + focalLength: 24, + isUseFocalFactor: 0, + payloadPositionIndex: 0, + }, + }, + { + url: require("../../../images/control_panorama.png"), + label: "全景拍照", + value: "panoShot", + svg: "pano_shot", + params: { + payloadPositionIndex: 0, + useGlobalPayloadLensIndex: 0, + payloadLensIndex: "visable,ir", + panoShotSubMode: "panoShot_360", + }, + }, + ], + points: [], + obj: { + type: 0, // 航线类型 + imageFormat: "wide,zoom,ir,narrow_band,visable", // 拍照配置 + estimateTime: "", // 预计执行时间 sdk + photoNum: 0, // 航点拍照数量 sdk + waylineLen: "", // 航线长度 sdk + flag: "", + // 0-91-1 + droneInfo: { + // 无人机的型号及其子类型 + droneEnumValue: "91", + droneSubEnumValue: "1", + }, + // 3-2-0 + payloadInfo: { + // 负载类型和子类型以及负载的位置 + payloadEnumValue: "81", + payloadPositionIndex: "0", + payloadSubEnumValue: "0", + }, + placemarkList: [], // 经纬度 + globalHeight: 120, // 相对起飞点高度 + autoFlightSpeed: 10, // 全局航线速度 + globalShootHeight: 60, + // remark: undefined, + // imageFormat: '', + takeOffSecurityHeight: 100, //安全起飞高度 + globalTransitionalSpeed: 10, //飞向首航点速度 + takeOffRefPoint: { + lng: undefined, + lat: undefined, + alt: undefined, + }, + }, + networkState: {}, + length: 0, + time: 0, + gensui: true, + inputDiv: false, + }; + }, + mounted() { + this.createTongBu(); + // let points = JSON.parse(localStorage.getItem("routePoints")); + let pointsAndTakeOff = JSON.parse(this.routeLine.points); + console.log( + "pointsAndTakeOff", + this.routeLine, + this.routeLine.normalHeight + ); + + // console.log("points", points); + if (pointsAndTakeOff) { + this.points = pointsAndTakeOff.points; + + console.log(".takeOffRefPoint", pointsAndTakeOff); + // return; + let takeOff = pointsAndTakeOff.takeOffRefPoint.split(","); + this.obj.takeOffRefPoint = { + lng: takeOff[1] - 0, + lat: takeOff[0] - 0, + alt: takeOff[2] - 0, + }; + console.log("this.obj.takeOffRefPoint", this.obj.takeOffRefPoint); + + if (!window.airLine) { + console.log("this.points", this.routeLine.normalHeight); + this.renderRouter(this.points); + } + if (!window.PointEntity) { + this.renderStart(this.obj.takeOffRefPoint); + } + } else { + this.drawStart(); + } + }, + computed: { + getPhotoNum() { + let photoNum = 0; + this.points.forEach((item) => { + if (item.actions.length > 0) { + item.actions.forEach((item1) => { + if (item1.type == "takePhoto" || item1.type == "panoShot") { + photoNum++; + } + }); + } + }); + return photoNum; + }, + }, + methods: { + // 创建地球 + createTongBu() { + window.EarthTongbu = new YJ.YJEarth("tongbuEarth"); + YJ.Global.setKeyboardEventActive(window.EarthTongbu, false); + const obj = { + compass: false, //罗盘 + legend: false, //比例尺 + info: false, //信息栏 + frame: false, //刷新率 + }; + let viewer = window.EarthTongbu.viewer; + YJ.Global.CesiumContainer(window.EarthTongbu, obj); + viewer.terrainProvider = new Cesium.createWorldTerrain(); + let imageryProvider = new Cesium.ArcGisMapServerImageryProvider({ + url: + "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer", + }); + viewer.imageryLayers.addImageryProvider(imageryProvider); + viewer.scene.screenSpaceCameraController.enableRotate = false; + viewer.scene.screenSpaceCameraController.enableZoom = false; + viewer.scene.screenSpaceCameraController.enableTilt = false; + }, + // 跟随航线 + genliuhangxian() { + this.gensui = !this.gensui; + if (this.gensui) { + this.selectObj.params.useGlobalPayloadLensIndex = 1; + } else { + this.selectObj.params.useGlobalPayloadLensIndex = 0; + } + }, + // genliuhangxian + genliuhangxian2() { + this.selectObj.params.useGlobalPayloadLensIndex = 1; + }, + // 保存成功 + saveSuucess() { + this.inputDiv = false; + this.$message.success("保存成功"); + }, + // 删除成功 + deleteSuucess() { + this.$message.success("删除成功"); + this.inputShow = false; + this.selectObj.params.fileSuffix = ""; + }, + changeGroup() { + this.selectObj.params.payloadLensIndex = this.checkboxGroup1.join(); + }, + changeGroup1() { + this.selectObj.params.payloadLensIndex = this.checkboxGroup2.join(); + }, + interval_distance(value) { + let svg = this.selectObj.svg; + if (svg == "interval_time" || svg == "interval_distance") { + this.selectObj.actionTrigger.actionTriggerParam = value; + } + if (svg == "hover") { + console.log("hoverTime", this.selectObj.params.hoverTime); + this.selectObj.params.hoverTime = value; + } + }, + // + hpr(value) { + let svg = this.selectObj.svg; + if (svg == "drone_yaw") { + this.selectObj.params.aircraftHeading = value; + let h = value == 0 ? 0 : value; + window.airLine.frustum.updateFrustumHPR( + h, + window.airLine.frustum.pitch, + window.airLine.frustum.roll, + true, + "alone" + ); + } + if (svg == "action_gimbal_pitch") { + function mapValue(x, a1, b1, a2, b2) { + // 线性映射公式 + return a2 + ((x - a1) / (b1 - a1)) * (b2 - a2); + } + + // 原始区间和目标区间 + const range1 = [35, -90]; // 原始区间 + const range2 = [60, 180]; // 目标区间 + let mappedValue = mapValue( + value, + range1[0], + range1[1], + range2[0], + range2[1] + ); + this.selectObj.params.gimbalPitchRotateAngle = value; + let p = mappedValue == 0 ? 90 : mappedValue; + // return; + let hh = Cesium.Math.toDegrees(window.airLine.frustum.hpr.heading); + window.airLine.frustum.updateFrustumHPR(hh, p, 0, true, "alone"); + } + if (svg == "camera_zoom") { + this.selectObj.params.focalLength = value * 24; + } + }, + closeSetup() { + this.setupShow = false; + this.selectIndexS = null; + }, + beforeHandleDropMenu(dropId, airLine) { + return { + dropId: dropId, + airLine: airLine, + }; + }, + handleDropMenu(command) { + const { dropId, airLine } = command; + if (dropId == 1 || dropId == 2) { + let draw = new YJ.Draw.DrawPoint(window.Earth1); + draw.start((err, params) => { + if (params != undefined) { + let position = { + ...params, + actions: [], + }; + if (dropId == 1) { + if (window.airLine) { + this.points.splice(this.selectId, 0, position); + window.airLine.addPoint(this.points); + } + } + if (dropId == 2) { + if (window.airLine) { + if (this.selectId == this.points.length - 1) { + this.points.push(position); + } else { + this.points.splice(this.selectId + 1, 0, position); + } + window.airLine.addPoint(this.points); + } + } + } + }); + } + if (dropId == 3) { + const index = this.points.findIndex((obj) => obj.lng == airLine.lng); + this.points = this.points.filter((obj) => obj.lng !== airLine.lng); + if (window.airLine) { + window.airLine.delPosition(index, this); + } + } + }, + // 新增航点 + addPoint() { + let draw = new YJ.Draw.DrawPoint(window.Earth1); + draw.start((err, params) => { + if (params != undefined) { + let position = { + ...params, + actions: [], + }; + this.points.push(position); + window.airLine.addPoint(this.points); + this.save(() => {}, false); + } + }); + }, + // 选中 + select(index) { + this.selectId = index; + let item = this.points[index]; + let obj = item.actions[0]; + + if (obj) { + this.openSet(index, 0, obj); + } else { + this.setupShow = false; + this.selectIndexS = null; + } + if (window.airLine) { + //判断动作组中有value为rotateYaw、gimbalRotate时就不执行window.airLine.updateFrustumPosition(index); + let flag = item.actions.some( + (obj) => obj.value == "rotateYaw" || obj.value == "gimbalRotate" + ); + if (!flag) { + window.airLine.updateFrustumPosition(index); + } + } + }, + add() {}, + more() { + this.leftShow = !this.leftShow; + }, + // 打开高级设置 + senior() { + this.save(() => { + this.$emit("seniorSet"); + }); + }, + // 返回 + back() { + if (this.points.length > 0) { + this.save(() => { + if (airLine) { + window.airLine.remove(); + window.airLine = null; + } + if (window.PointEntity) { + window.PointEntity.remove(); + window.PointEntity = null; + } + this.$emit("back"); + }, false); + } else { + this.$emit("back"); + } + this.$changeComponentShow(".bottomTabs", true); + }, + // 绘制航线 + draw() { + let draw = new YJ.Draw.DrawPolyline(window.Earth1, { + tipText: "请选择航点(左键确定,右键结束)", + }); + draw.start((err, positions) => { + if (positions.length == 0) { + return; + } + positions.forEach((el) => { + el.actions = []; + return el; + }); + this.points = [...positions]; + this.renderRouter(positions); + }); + }, + // 绘制起飞点 + drawStart() { + let draw = new YJ.Draw.DrawTakeOff(window.Earth1, { + tipText: "选择参考起飞点(左键确定)", + }); + draw.start((err, params, flag) => { + if (params != undefined) { + if (!flag) { + this.renderStart(params); + this.obj.takeOffRefPoint = window.PointEntity.options.positions; + } else { + this.obj.takeOffRefPoint = window.airportEntity.options.positions; + } + this.draw(); + } + }); + }, + // 渲染参考起飞点 + renderStart(positions) { + let option = { + positions, + label: { + text: "参考起飞点", + fontSize: 20, + }, + billboard: { + image: "/static/sdk/img/start.png", + }, + }; + window.PointEntity = new YJ.Obj.BillboardObject(window.Earth1, option); + window.PointEntity.picking = false; + window.PointEntity.onClick = () => { + setTimeout(() => { + window.PointEntity.positionEditing = true; + }, 100); + }; + }, + // 渲染航线 + renderRouter(positions) { + console.log("globalPointHeight", this.routeLine.globalPointHeight); + + let airLine = new YJ.Obj.newAirLine( + { + positions, + image: "/static/img/定位.png", + saveFun: this.save, + selectFun: this.select, + normalHeight: this.routeLine.globalPointHeight, + airHeight: this.routeLine.height, + }, + window.Earth1.viewer, + window.EarthTongbu.viewer + ); + window.airLine = airLine; + window.airLine.flyTo(); + this.length = airLine.countLength(); + this.time = airLine.countTime(); + // console.log("airLine", airLine); + }, + // 添加动作到航点 + onClick(item) { + console.log("item", item); + // 添加动作时, + // console.log("this.selectId, item", this.selectId, item); + if (this.selectId === null) { + this.$message.warning("请选择航点,再进行动作添加"); + return; + } + let selectItem = this.points[this.selectId]; + selectItem.actions.push({ + label: item.label, + type: item.value, + params: item.params, + svg: item.svg, + actionTrigger: item.actionTrigger, + }); + // 打开当前动作设置 + // this.openSet(this.selectId, selectItem.actions.length - 1, item); + // console.log("this.points", this.points); + }, + // 点击动作图标 + openSet(indexF, indexS, item) { + this.selectIndexF = indexF; + this.selectIndexS = indexS; + this.selectObj = item; + console.log("this.selectObj", this.selectObj); + if ( + this.selectObj.type == "takePhoto" || + this.selectObj.type == "startRecord" + ) { + this.checkboxGroup2 = this.selectObj.params.payloadLensIndex.split(","); + if (this.selectObj.params.fileSuffix) { + this.inputDiv = false; + this.inputShow = true; + } else { + this.inputShow = false; + this.inputDiv = true; + } + } + this.setupShow = true; + }, + // 删除动作 + delAction() { + let curAction = this.points[this.selectIndexF]; + curAction.actions.splice(this.selectIndexS, 1); + this.setupShow = false; + // console.log( + // "curActioncurActioncurActioncurAction", + // curAction, + // this.selectIndexS + // ); + }, + + // 在保存之前判断每个点中得动作组,如果前一个动作组中有开始录像,后面的动作组中有全景拍照的动作,就提示用户该航线因为全景拍照的动作处于录像过程中,无法执行,并返回当前有问题的航点的索引 + saveBefore() { + let flag = true; + let indexf = null; + this.points.forEach((item, index) => { + if (item.actions.length > 0) { + let startRecord = item.actions.find( + (obj) => obj.type == "startRecord" + ); + if (startRecord) { + let nextAction = this.points[index + 1]; + if (nextAction) { + let panoShot = nextAction.actions.find( + (obj) => obj.type == "panoShot" + ); + if (panoShot) { + flag = false; + indexf = index + 1; + } + } + } + } + }); + return { + flag: !flag, + index: indexf, + }; + }, + // 保存操作 + save(cb = null, flag = true) { + let before = this.saveBefore(); + if (before.flag) { + this.$message.warning( + `${before.index + + 1}#航点的全景拍照动作处于录像过程中,无法执行。请删除该动作后再保存` + ); + return; + } + let positions = window.airLine.getNewPositions(); + let newPoints = []; + this.points.forEach((item1, index1) => { + let obj = { + actions: item1.actions, + }; + positions.forEach((item, index) => { + if (index == index1) { + obj.lng = item.lng; + obj.lat = item.lat; + obj.alt = item.alt - this.routeLine.globalPointHeight; + obj.longitude = item.lng; + obj.latitude = item.lat; + obj.altitude = + item.alt - + this.routeLine.height + + this.routeLine.globalPointHeight; + } + }); + newPoints.push(obj); + }); + this.points = newPoints; + this.obj.placemarkList = newPoints; + this.obj.id = this.routeLine.id; + if (typeof this.obj.takeOffRefPoint == "object") { + this.obj.takeOffRefPoint = + this.obj.takeOffRefPoint.lat + + "," + + this.obj.takeOffRefPoint.lng + + "," + + this.obj.takeOffRefPoint.alt; + } else { + this.obj.takeOffRefPoint = this.obj.takeOffRefPoint; + } + + let obj = { + points: newPoints, + takeOffRefPoint: this.obj.takeOffRefPoint, + }; + if (!obj.points[0].lng) { + this.obj.points = []; + this.takeOffRefPoint = ""; + window.PointEntity.remove(); + window.PointEntity = null; + } + this.obj.points = JSON.stringify(obj); + waypoint(this.obj).then((res) => { + if (flag) { + this.$message.success("操作成功"); + } + if (typeof cb == "function") { + cb(); + } + }); + }, + // 航线航点移动 + towardsLeft() {}, + up() {}, + towardsRight() {}, + left() {}, + after() {}, + right() {}, + }, +}; diff --git a/src/views/drone/components/airRoute/list.vue b/src/views/drone/components/airRoute/list.vue new file mode 100644 index 0000000..e4ab6e7 --- /dev/null +++ b/src/views/drone/components/airRoute/list.vue @@ -0,0 +1,627 @@ + + + + diff --git a/src/views/drone/components/airRoute/pointSetup.vue b/src/views/drone/components/airRoute/pointSetup.vue new file mode 100644 index 0000000..7acb896 --- /dev/null +++ b/src/views/drone/components/airRoute/pointSetup.vue @@ -0,0 +1,881 @@ + + + + diff --git a/src/views/drone/components/bottomTabs/index.vue b/src/views/drone/components/bottomTabs/index.vue new file mode 100644 index 0000000..051e93a --- /dev/null +++ b/src/views/drone/components/bottomTabs/index.vue @@ -0,0 +1,143 @@ + + + + diff --git a/src/views/drone/components/component/dialog/index.vue b/src/views/drone/components/component/dialog/index.vue new file mode 100644 index 0000000..d4d80fc --- /dev/null +++ b/src/views/drone/components/component/dialog/index.vue @@ -0,0 +1,114 @@ + + + + diff --git a/src/views/drone/components/component/plusReduce/index.vue b/src/views/drone/components/component/plusReduce/index.vue new file mode 100644 index 0000000..2214dd6 --- /dev/null +++ b/src/views/drone/components/component/plusReduce/index.vue @@ -0,0 +1,121 @@ + + + + diff --git a/src/views/drone/components/component/progress/index.vue b/src/views/drone/components/component/progress/index.vue new file mode 100644 index 0000000..d783813 --- /dev/null +++ b/src/views/drone/components/component/progress/index.vue @@ -0,0 +1,143 @@ + + + + diff --git a/src/views/drone/components/flyer/1.jpg b/src/views/drone/components/flyer/1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..503815ce97de335cd9c391d52bf94bd5fca04a7a GIT binary patch literal 146997 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

yr+ALcPiM!(z7Anu68F^VfNhLG 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