From 61e6956be147e1e84e7104f16dd47e9f87f20dfd Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Fri, 18 Apr 2025 10:57:32 +0800
Subject: [PATCH] feat: 控制台显示一些信息
---
src/components/CurrentTaskDetails/RealTimeMap.vue | 45 ++++----
src/hooks/controlDrone/useManualControl.js | 9 -
src/components/CurrentTaskDetails/ControlPanel/ControlPanel.vue | 117 ++++++++++++++++++++--
src/hooks/controlDrone/useMqtt.js | 1
src/api/payload.js | 2
src/components/CurrentTaskDetails/TaskDetailsLeft.vue | 8
src/components/CurrentTaskDetails/TaskDetailsHead.vue | 86 +++++++++++++---
src/components/CurrentTaskDetails/ControlPanel/ControlComPass/ControlComPass.vue | 6
src/components/CurrentTaskDetails/CurrentTaskDetails.vue | 13 ++
9 files changed, 219 insertions(+), 68 deletions(-)
diff --git a/src/api/payload.js b/src/api/payload.js
index 77b9be3..517dbf1 100644
--- a/src/api/payload.js
+++ b/src/api/payload.js
@@ -44,7 +44,7 @@
// 拍照和录像
export async function callPhotoAndVideoCmd(sn, type) {
return await request({
- url:`/drone-device-core/droneAirport/liveStreamApi/${sn}/payload/photoAndVideoCmd/${type}`,
+ url:`${API_PREFIX}/devices/${sn}/payload/photoAndVideoCmd/${type}`,
method:'get',
})
}
diff --git a/src/components/CurrentTaskDetails/ControlComPass/ControlComPass.vue b/src/components/CurrentTaskDetails/ControlPanel/ControlComPass/ControlComPass.vue
similarity index 97%
rename from src/components/CurrentTaskDetails/ControlComPass/ControlComPass.vue
rename to src/components/CurrentTaskDetails/ControlPanel/ControlComPass/ControlComPass.vue
index 8ec1d8b..5685ca1 100644
--- a/src/components/CurrentTaskDetails/ControlComPass/ControlComPass.vue
+++ b/src/components/CurrentTaskDetails/ControlPanel/ControlComPass/ControlComPass.vue
@@ -3,7 +3,7 @@
<div class="left-img" :data-text="`${attitude_pitch}°`">
<div class="scaleImg">
<p class="scale" :style="{ top: 45 + ScaleTop + 'px' }"></p>
- <img src="../../../assets/images/rightmapidentification.png" />
+ <img src="../../../../assets/images/rightmapidentification.png" />
</div>
</div>
<div class="instrument-center">
@@ -14,13 +14,13 @@
</div>
</div>
<div class="center-show">
- <img src="../../../assets/images/mapidentification.png" />
+ <img src="../../../../assets/images/mapidentification.png" />
</div>
<div class="rotat-btn"></div>
</div>
<div class="right-img" :data-text="`${height}m`">
<div class="ident-arrow">
- <img src="../../../assets/images/leftmapidentification.png" />
+ <img src="../../../../assets/images/leftmapidentification.png" />
<div class="arrow-box" :style="{ bottom: realHeight }">
<div class="arrow"></div>
</div>
diff --git a/src/components/CurrentTaskDetails/ControlPanel/ControlPanel.vue b/src/components/CurrentTaskDetails/ControlPanel/ControlPanel.vue
index 546ab80..901d30d 100644
--- a/src/components/CurrentTaskDetails/ControlPanel/ControlPanel.vue
+++ b/src/components/CurrentTaskDetails/ControlPanel/ControlPanel.vue
@@ -126,7 +126,7 @@
</div>
</template>
<script setup>
-import ControlComPass from '../ControlComPass/ControlComPass.vue'
+import ControlComPass from '@/components/CurrentTaskDetails/ControlPanel/ControlComPass/ControlComPass.vue'
import { KeyCode, useManualControl } from '@/hooks/controlDrone/useManualControl'
import { droneController, exitController, postDrc, returnHome, returnHomeCancel } from '@/api/drc'
import { ElMessage } from 'element-plus'
@@ -144,12 +144,13 @@
RefreshLeft,
RefreshRight,
} from '@element-plus/icons-vue'
-
+import _ from 'lodash'
import BaseControl from '@/components/CurrentTaskDetails/ControlPanel/BaseControl.vue'
import EventBus from '@/event-bus'
import { getPayloadControlApi, ptzControlApi } from '@/api/payload'
const deviceOsdInfo = inject('deviceOsdInfo')
+const host = computed(() => deviceOsdInfo?.value?.data?.host || {})
const taskDetails = inject('taskDetails')
const dockSn = inject('dockSn')
const droneSn = inject('droneSn')
@@ -183,18 +184,106 @@
{ name: '左', key: KeyCode.ARROW_LEFT, operate: 'left', style: { left: '-70%' } },
]
-const list4 = [
- [
- { name: '焦距倍数', value: '0' },
- { name: '俯仰角度', value: '0.0°' },
- { name: '横向角度', value: '0.0°' },
- ],
- [
- { name: '储存', value: '64.5G' },
- { name: '方向', value: '正北' },
- { name: '方向', value: '正北' },
- ],
-]
+const list4 = computed(() => {
+ const { longitude, latitude, height, payloads } = host?.value || {}
+ const { gimbal_pitch } = payloads?.[0] || {} //俯仰角度
+ return [
+ [
+ { name: '焦距倍数', value: '0' },
+ { name: '俯仰角度', value: pitchAngle.value.angle },
+ { name: '横向角度', value: yawAngle.value.angle },
+ ],
+ [
+ { name: '储存', value: '64.5G' },
+ { name: '方向', value: pitchAngle.value.direction },
+ { name: '方向', value: yawAngle.value.direction },
+ ],
+ ]
+})
+const pitchAngle = computed(() => {
+ const { longitude, latitude, height, payloads } = host?.value || {}
+ const gimbal_pitch = payloads?.[0]?.gimbal_pitch || 0
+ let direction = ''
+ if (gimbal_pitch > -2 && gimbal_pitch < 2) {
+ direction = '正前'
+ } else if (gimbal_pitch >= 2 && gimbal_pitch < 90) {
+ direction = '斜上'
+ } else if (gimbal_pitch === 90) {
+ direction = '正上'
+ } else if (gimbal_pitch <= -2 && gimbal_pitch > -90) {
+ direction = '斜下'
+ } else if (gimbal_pitch === -90 || gimbal_pitch < -90) {
+ direction = '正下'
+ }
+ return {
+ angle: _.round(gimbal_pitch || 0, 1) + '°',
+ direction,
+ }
+})
+
+const yawAngle = computed(() => {
+ let { longitude, latitude, height, payloads, attitude_head } = host?.value || {}
+ const gimbal_pitch = payloads?.[0]?.gimbal_pitch || 0
+ const gimbal_yaw = payloads?.[0]?.gimbal_yaw || 0
+ attitude_head = attitude_head || 0
+ let yaw = ''
+ if (gimbal_yaw > 180) {
+ yaw = gimbal_yaw
+ } else {
+ yaw = gimbal_yaw - attitude_head
+ }
+ let result = 0
+ if (yaw < 0) {
+ result = yaw + 360
+ }
+ if (yaw > 0) {
+ result = yaw
+ }
+ if ((yaw > -2 && yaw < 2) || parseInt(attitude_head) === parseInt(gimbal_yaw)) {
+ result = attitude_head < 0 ? 180 + (180 + attitude_head) : attitude_head
+ }
+ let direction = ''
+ const roundResult = Math.round(result)
+ if (roundResult === 0) {
+ direction = '正北'
+ } else if (roundResult > 0 && roundResult < 45) {
+ direction = '北偏东'
+ } else if (roundResult === 45) {
+ direction = '东北'
+ } else if (roundResult > 45 && roundResult < 90) {
+ direction = '北偏东'
+ } else if (roundResult === 90) {
+ direction = '正东'
+ } else if (roundResult > 90 && roundResult < 135) {
+ direction = '东偏南'
+ } else if (roundResult === 135) {
+ direction = '东南'
+ } else if (roundResult > 135 && roundResult < 180) {
+ direction = '南偏东'
+ } else if (roundResult === 180) {
+ direction = '正南'
+ } else if (roundResult > 180 && roundResult < 225) {
+ direction = '南偏西'
+ } else if (roundResult === 225) {
+ direction = '西南'
+ } else if (roundResult > 225 && roundResult < 270) {
+ direction = '西偏南'
+ } else if (roundResult === 270) {
+ direction = '正西'
+ } else if (roundResult > 270 && roundResult < 315) {
+ direction = '西偏北'
+ } else if (roundResult === 315) {
+ direction = '西北'
+ } else if (roundResult > 315 && roundResult < 360) {
+ direction = '北偏西'
+ } else if (roundResult === 360) {
+ direction = '正北'
+ }
+ return {
+ angle: _.round(result, 1) + '°',
+ direction,
+ }
+})
const deviceTopicInfo = ref({
pubTopic: '',
diff --git a/src/components/CurrentTaskDetails/CurrentTaskDetails.vue b/src/components/CurrentTaskDetails/CurrentTaskDetails.vue
index c93ba94..5d11eee 100644
--- a/src/components/CurrentTaskDetails/CurrentTaskDetails.vue
+++ b/src/components/CurrentTaskDetails/CurrentTaskDetails.vue
@@ -52,6 +52,9 @@
provide('isAutoControl', isAutoControl)
provide('lineQuality', lineQuality)
+const taskDetailsViewer = ref(null)
+provide('taskDetailsViewer', taskDetailsViewer)
+
let taskDetails = ref({})
const deviceOsdInfo = ref({})
provide('taskDetails', taskDetails)
@@ -119,7 +122,15 @@
case EBizCode.DeviceOsd: {
deviceOsdInfo.value = payload
setCurrentLiveUrl()
- console.log(deviceOsdInfo.value, 'device_osd信息')
+ console.log(payload, 'DeviceOsd--信息')
+ break
+ }
+ case EBizCode.GatewayOsd: {
+ console.log(payload, 'GatewayOsd--信息')
+ break
+ }
+ case EBizCode.DockOsd: {
+ console.log(payload, 'GatewayOsd--信息')
break
}
default:
diff --git a/src/components/CurrentTaskDetails/RealTimeMap.vue b/src/components/CurrentTaskDetails/RealTimeMap.vue
index 4a63684..c5c01bc 100644
--- a/src/components/CurrentTaskDetails/RealTimeMap.vue
+++ b/src/components/CurrentTaskDetails/RealTimeMap.vue
@@ -26,12 +26,14 @@
tilingScheme: new AmapMercatorTilingScheme(),
credit: 'amap_SL',
})
-let viewer = null
+
+const taskDetailsViewer = inject('taskDetailsViewer')
+
const taskDetails = inject('taskDetails')
const deviceOsdInfo = inject('deviceOsdInfo')
const initMap = () => {
- viewer = new Viewer('currentTaskMap', {
+ taskDetailsViewer.value = new Viewer('currentTaskMap', {
terrain: Terrain.fromWorldTerrain(),
infoBox: false, // 禁用沙箱,解决控制台报错
animation: false, // 左下角的动画仪表盘
@@ -45,17 +47,17 @@
baseLayer: false,
fullscreenButton: false,
})
- const gdLayer = viewer.imageryLayers.addImageryProvider(imageryProvider_ammapSL)
+ const gdLayer = taskDetailsViewer?.value.imageryLayers.addImageryProvider(imageryProvider_ammapSL)
const options = {
bInvertColor: true,
bFilterColor: true,
filterColor: '#4e70a6',
}
// 添加蓝色滤镜
- addBlueFilter(options, viewer, gdLayer)
- viewer.scene.morphTo2D(0)
+ addBlueFilter(options, taskDetailsViewer?.value, gdLayer)
+ taskDetailsViewer?.value.scene.morphTo2D(0)
//设置默认点
- viewer.camera.setView({
+ taskDetailsViewer?.value.camera.setView({
destination: Cartesian3.fromDegrees(115.763819, 28.787374, 5000),
})
}
@@ -66,7 +68,7 @@
return Cartesian3.fromDegrees(Number(lon), Number(lat))
})
// 起点
- viewer.entities.add({
+ taskDetailsViewer?.value.entities.add({
position: positions[0],
billboard: {
image: new Cesium.ConstantProperty(rwqfdImg),
@@ -75,7 +77,7 @@
},
})
// 终点
- viewer.entities.add({
+ taskDetailsViewer?.value.entities.add({
position: positions[positions.length - 1],
billboard: {
image: new Cesium.ConstantProperty(endPointImg),
@@ -85,7 +87,7 @@
},
})
// 路径线
- viewer.entities.add({
+ taskDetailsViewer?.value.entities.add({
polyline: {
width: 4,
positions: positions,
@@ -108,29 +110,28 @@
const waylinesXMLObj = removeTextKey(waylinesXMLJSON.Folder)
if (!waylinesXMLObj.Placemark.length) return
const allPoint = waylinesXMLObj.Placemark.map(item => item.Point.coordinates.split(','))
- flyVisual(allPoint, viewer)
+ flyVisual(allPoint, taskDetailsViewer?.value)
drawWayline(waylinesXMLObj)
}
const removeMap = () => {
- viewer.entities.removeAll()
- viewer.destroy()
+ taskDetailsViewer?.value.entities.removeAll()
+ taskDetailsViewer?.value.destroy()
}
-
let viewInfoFrustum
// 设置视椎
const setCreateFrustum = () => {
- const deviceInfo = deviceOsdInfo.value?.data?.host
- if (!deviceInfo) return
+ const host = deviceOsdInfo.value?.data?.host
+ if (!host) return
viewInfoFrustum?.clear()
- if ([14, 0].includes(deviceInfo.mode_code)) return
- const attitude_head = 180 + deviceInfo.attitude_head
- const gimbal_pitch = 90 - Number(deviceInfo?.payloads[0]?.gimbal_pitch) || 0
- viewInfoFrustum = new CreateFrustum(viewer, {
+ if ([14, 0].includes(host.mode_code)) return
+ const attitude_head = 180 + host.attitude_head
+ const gimbal_pitch = 90 - Number(host?.payloads[0]?.gimbal_pitch) || 0
+ viewInfoFrustum = new CreateFrustum(taskDetailsViewer?.value, {
position: {
- longitude: deviceInfo.longitude,
- latitude: deviceInfo.latitude,
- altitude: deviceInfo.height,
+ longitude: host.longitude,
+ latitude: host.latitude,
+ altitude: host.height,
},
width: 30,
height: 30,
diff --git a/src/components/CurrentTaskDetails/TaskDetailsHead.vue b/src/components/CurrentTaskDetails/TaskDetailsHead.vue
index 91ed227..708ce52 100644
--- a/src/components/CurrentTaskDetails/TaskDetailsHead.vue
+++ b/src/components/CurrentTaskDetails/TaskDetailsHead.vue
@@ -8,7 +8,9 @@
</div>
</div>
<div class="controlBtn">
- <el-icon class="refresh"><Refresh /></el-icon>
+ <el-icon class="refresh">
+ <Refresh />
+ </el-icon>
<div class="switchBtn" @click="switchBtn">
<div :class="{ open: open }">NO</div>
<div :class="{ open: !open }">OFF</div>
@@ -19,26 +21,74 @@
<script setup>
import { Refresh } from '@element-plus/icons-vue'
+import { getFlightStatistics } from '@/api/home/machineNest'
+import { throttle } from 'lodash'
+import { getLnglatAltitude } from '@/utils/cesium/mapUtil'
+import _ from 'lodash'
+const taskDetailsViewer = inject('taskDetailsViewer')
+const deviceOsdInfo = inject('deviceOsdInfo')
+const dockSn = inject('dockSn')
const open = ref(true)
+const singleTotal = ref({})
+const host = computed(() => deviceOsdInfo?.value?.data?.host || {})
+
+const infoList = computed(() => {
+ const { longitude, latitude, height, payloads } = host?.value || {}
+ return [
+ { title: '实时真高', value: '0' },
+ { title: '绝对高度', value: _.round(height || 0, 1) + 'm' },
+ { title: '水平速度', value: '0' },
+ { title: '垂直速度', value: '0' },
+ { title: '经度', value: _.round(longitude || 0, 2) },
+ { title: '纬度', value: _.round(latitude || 0, 2) },
+ { title: '4G信号', value: '0' },
+ { title: 'SDR信号', value: '0' },
+ { title: 'GPS搜星数', value: '0' },
+ { title: 'RTK搜星数', value: '0' },
+ { title: '距离机场', value: '0' },
+ { title: '飞行时长', value: (singleTotal.value?.hour_count || 0) + '小时' },
+ { title: '电池电量', value: (host?.value?.battery?.capacity_percent || 0) + '%' },
+ ]
+})
+
const switchBtn = () => {
open.value = !open.value
}
-const infoList = [
- { title: '实时真高', value: '0' },
- { title: '绝对高度', value: '0' },
- { title: '水平速度', value: '0' },
- { title: '垂直速度', value: '0' },
- { title: '经度', value: '0' },
- { title: '纬度', value: '0' },
- { title: '4G信号', value: '0' },
- { title: 'SDR信号', value: '0' },
- { title: 'GPS搜星数', value: '0' },
- { title: 'RTK搜星数', value: '0' },
- { title: '距离机场', value: '0' },
- { title: '飞行时长', value: '0' },
- { title: '电池电量', value: '0' },
-]
+
+function getFlightStatisticsFun() {
+ if (!dockSn.value) return
+ getFlightStatistics(dockSn.value).then(res => {
+ singleTotal.value = res.data.data
+ })
+}
+
+function getRealTimeReallyHigh() {
+ if (!taskDetailsViewer?.value) return
+ const { latitude, longitude, height } = host?.value || {}
+ if (!latitude) return
+ getLnglatAltitude(longitude, latitude, taskDetailsViewer.value).then(res => {
+ const findIndex = infoList.value.findIndex(item => item.title === '实时真高')
+ infoList.value[findIndex].value = _.round(height - res?.height, 1) + 'm'
+ })
+}
+
+const getRealTimeReallyHighThrottle = throttle(getRealTimeReallyHigh, 500, { leading: true, trailing: true })
+watch(
+ deviceOsdInfo,
+ () => {
+ getRealTimeReallyHighThrottle()
+ },
+ { immediate: true }
+)
+
+watch(
+ dockSn,
+ () => {
+ getFlightStatisticsFun()
+ },
+ { immediate: true }
+)
</script>
<style scoped lang="scss">
@@ -48,7 +98,7 @@
z-index: 5;
width: 100%;
height: 68px;
- background: rgb(0,0,0,.4); /* 半透明背景 */
+ background: rgb(0, 0, 0, 0.4); /* 半透明背景 */
backdrop-filter: blur(5px);
padding: 0 31px;
display: flex;
@@ -98,7 +148,7 @@
align-items: center;
justify-content: space-between;
- .refresh{
+ .refresh {
color: white;
font-size: 30px;
cursor: pointer;
diff --git a/src/components/CurrentTaskDetails/TaskDetailsLeft.vue b/src/components/CurrentTaskDetails/TaskDetailsLeft.vue
index 861e33f..89b9174 100644
--- a/src/components/CurrentTaskDetails/TaskDetailsLeft.vue
+++ b/src/components/CurrentTaskDetails/TaskDetailsLeft.vue
@@ -22,8 +22,8 @@
<div @click="recordFun">{{ isRecording ? '录像中...' : '录像' }}</div>
</div>
<div class="multiCol">
- <div>喊话</div>
- <div>广播</div>
+ <div @click="ElMessage.warning('加急开发中...')">喊话</div>
+ <div @click="ElMessage.warning('加急开发中...')">广播</div>
</div>
<div class="cameraZoom">
@@ -116,7 +116,7 @@
const msg = isRecording.value ? '停止录像' : '开始录像'
const emitType = isRecording.value ? 'controlPanel-timeStop' : 'controlPanel-timeStart'
- callPhotoAndVideoCmd(droneSn.value, type).then(res => {
+ callPhotoAndVideoCmd(dockSn.value, type).then(res => {
ElMessage.success(msg)
EventBus.emit(emitType)
isRecording.value = !isRecording.value
@@ -126,7 +126,7 @@
// 拍照
function takePictures() {
// photo拍照,video_start开始录像,video_stop结束录像
- callPhotoAndVideoCmd(droneSn.value, 'photo').then(res => {
+ callPhotoAndVideoCmd(dockSn.value, 'photo').then(res => {
ElMessage.success('拍照成功')
})
}
diff --git a/src/hooks/controlDrone/useManualControl.js b/src/hooks/controlDrone/useManualControl.js
index 4ccce9f..c21c5c6 100644
--- a/src/hooks/controlDrone/useManualControl.js
+++ b/src/hooks/controlDrone/useManualControl.js
@@ -38,7 +38,7 @@
export function useManualControl(mqttState,deviceTopicInfo, isCurrentFlightController,paramsRef) {
let activeCodeKey = null
let genPortOne = true //是一代机场
- const mqttHooks = useMqtt(mqttState,deviceTopicInfo)
+ let mqttHooks = useMqtt(mqttState,deviceTopicInfo)
let seq = 0
const keysPressed = [
{key: 'KeyQ', value: false},
@@ -281,11 +281,10 @@
{ immediate: true }
)
- onBeforeUnmount(()=>{
- mqttHooks?.d
- })
-
onUnmounted(() => {
+ deviceTopicInfo.subTopic = ''
+ deviceTopicInfo.pubTopic = ''
+ mqttHooks = null
closeKeyboardManualControl()
})
diff --git a/src/hooks/controlDrone/useMqtt.js b/src/hooks/controlDrone/useMqtt.js
index caaff48..8ac4679 100644
--- a/src/hooks/controlDrone/useMqtt.js
+++ b/src/hooks/controlDrone/useMqtt.js
@@ -67,6 +67,7 @@
// 2.发心跳
publishDrcPing(deviceTopicInfo.sn)
} else {
+ console.log('清除pingInterval')
clearInterval(state.heartState.get(deviceTopicInfo.sn)?.pingInterval)
state.heartState.delete(deviceTopicInfo.sn)
heartBeatSeq.value = 0
--
Gitblit v1.9.3