forked from drone/command-center-dashboard

罗广辉
2025-04-18 76a3843d1cd480a345675b56e8e45693b0bf81cb
feat: 指南针100%
7 files modified
7201 ■■■■ changed files
package.json 1 ●●●● patch | view | raw | blame | history
pnpm-lock.yaml 7045 ●●●● patch | view | raw | blame | history
src/components/CurrentTaskDetails/ControlPanel/ControlComPass/ControlComPass.vue 41 ●●●●● patch | view | raw | blame | history
src/components/CurrentTaskDetails/ControlPanel/ControlPanel.vue 89 ●●●●● patch | view | raw | blame | history
src/components/CurrentTaskDetails/CurrentTaskDetails.vue 5 ●●●●● patch | view | raw | blame | history
src/components/CurrentTaskDetails/TaskDetailsHead.vue 1 ●●●● patch | view | raw | blame | history
src/const/drc.js 19 ●●●●● patch | view | raw | blame | history
package.json
@@ -29,6 +29,7 @@
    "element-plus": "^2.9.3",
    "eventemitter3": "^5.0.1",
    "highlight.js": "^11.9.0",
    "js-audio-recorder": "^1.0.7",
    "js-base64": "^3.7.4",
    "js-cookie": "^3.0.0",
    "js-md5": "^0.7.3",
pnpm-lock.yaml
Diff too large
src/components/CurrentTaskDetails/ControlPanel/ControlComPass/ControlComPass.vue
@@ -1,20 +1,15 @@
<template>
    <div class="instrument-content">
        <div class="left-img">
            <div class="valueBox">{{props?.pitchAngle || 0}}°</div>
            <div class="valueBox">{{ props?.options?.pitchAngle || 0 }}°</div>
            <img src="@/assets/images/rightmapidentification.png" alt="" />
            <div class="triangle" :style="pitchAngleStyle"></div>
            <div class="nameBox" >俯仰角度</div>
            <div class="nameBox">俯仰角度</div>
        </div>
        <div class="instrument-center">
            <div class="compass-box" >
                <div
                    v-for="(item, index) in str"
                    :key="index"
                    class="scale"
                    :style="{ '--rotate': 30 * index - prevRotate + 'deg' }"
                >
            <div class="compass-box" :style="{ transform: `rotate(${props?.options?.yawAngle || 0}deg)` }">
                <div v-for="(item, index) in str" :key="index" class="scale" :style="{ '--rotate': 30 * index + 'deg' }">
                    <span class="text">{{ item }}</span>
                </div>
            </div>
@@ -24,7 +19,7 @@
        </div>
        <div class="right-img">
            <div class="valueBox">{{props.trueAltitude}}m</div>
            <div class="valueBox">{{ props.options?.trueAltitude }}m</div>
            <img src="@/assets/images/leftmapidentification.png" alt="" />
            <div class="rightTriangle" :style="trueAltitudeStyle"></div>
            <div class="nameBox">真空高度</div>
@@ -34,31 +29,26 @@
<script setup>
const str = ['W', 30, 33, 'N', 3, 6, 'E', 12, 15, 'S', 21, 24]
const attitude_pitch = 0 // 俯仰角度数
const height = 0 // 真空高度
const prevRotate = 0
const dockHeight = 0
const props = defineProps(['pitchAngle','trueAltitude'])
const props = defineProps(['options'])
const pitchAngleStyle = computed(() => {
    const pitchAngle = props?.pitchAngle || 0;
    const pitchAngle = props?.options?.pitchAngle || 0
    // 将 [-90, 90] 映射到 [0%, 100%]
    const percentage = ((pitchAngle + 90) / 180 * 100).toFixed(2);
    const percentage = (((pitchAngle + 90) / 180) * 100).toFixed(2)
    return {
        bottom: `${percentage}%`
    };
        bottom: `${percentage}%`,
    }
})
const trueAltitudeStyle = computed(() => {
    const trueAltitude = props?.trueAltitude || 0;
    const trueAltitude = props?.options?.trueAltitude || 0
    // 将 [-240,240] 映射到 [0%, 100%]
    const percentage = ((trueAltitude + 240) / 480 * 100).toFixed(2);
    const percentage = (((trueAltitude + 240) / 480) * 100).toFixed(2)
    return {
        bottom: `${percentage}%`
    };
        bottom: `${percentage}%`,
    }
})
</script>
<style lang="scss" scoped>
@@ -137,7 +127,6 @@
            border: 30px solid rgba($color: #323931, $alpha: 0.5);
            box-shadow: 0 2px 12px 0 #158aff;
            user-select: none;
            transform: none !important;
            .scale {
                width: 135%;
src/components/CurrentTaskDetails/ControlPanel/ControlPanel.vue
@@ -68,7 +68,7 @@
        </div>
        <!--     指南针-->
        <div class="compass">
            <ControlComPass :pitchAngle="pitchAngle.angle" :trueAltitude="trueAltitude" />
            <ControlComPass :options="compassOptions" />
        </div>
        <div class="ptzControlBox">
@@ -116,7 +116,7 @@
            </div>
            <div class="divider"></div>
            <div v-for="arr in list4" class="info">
            <div v-for="arr in baseInfo" class="info">
                <div v-for="item in arr" class="infoItem">
                    <div class="infoName">{{ item.name }}</div>
                    <div class="infoValue">{{ item.value + (item.unit || '') }}</div>
@@ -147,17 +147,26 @@
import _ from 'lodash'
import BaseControl from '@/components/CurrentTaskDetails/ControlPanel/BaseControl.vue'
import EventBus from '@/event-bus'
import { getPayloadControlApi, ptzControlApi } from '@/api/payload'
import { getPayloadControlApi } from '@/api/payload'
import { directionMap } from '@/const/drc'
const deviceOsdInfo = inject('deviceOsdInfo')
const host = computed(() => deviceOsdInfo?.value?.data?.host || {})
const wsInfo = inject('wsInfo')
const device_osd_host = computed(() => wsInfo?.value?.device_osd?.data?.host || {})
const dock_osd_host = computed(() => wsInfo?.value?.dock_osd?.data?.host || {})
const taskDetails = inject('taskDetails')
const dockSn = inject('dockSn')
const droneSn = inject('droneSn')
const trueAltitude = inject('trueAltitude')
const store = useStore()
const compassOptions = computed(() => {
    return {
        pitchAngle: pitchAngle.value.angle,
        trueAltitude: trueAltitude.value,
        yawAngle: yawAngle.value.angle,
    }
})
let mqttState = null
const client_id = ref('')
const valueTime = ref('00:00:00')
@@ -186,24 +195,26 @@
    { name: '左', key: KeyCode.ARROW_LEFT, operate: 'left', style: { left: '-70%' } },
]
const list4 = computed(() => {
    const { longitude, latitude, height, payloads } = host?.value || {}
    const { gimbal_pitch } = payloads?.[0] || {} //俯仰角度
const baseInfo = computed(() => {
    const usedStorage = dock_osd_host.value?.storage?.used || 0
    const zoom_factor = device_osd_host.value?.cameras?.[0]?.zoom_factor || 0
    const usedStorageGB = _.round(usedStorage / 1024 / 1024, 2)
    return [
        [
            { name: '焦距倍数', value: '0' },
            { name: '俯仰角度', value: pitchAngle.value.angle,unit:'°' },
            { name: '横向角度', value: yawAngle.value.angle,unit:'°' },
            { name: '焦距倍数', value: zoom_factor },
            { name: '俯仰角度', value: pitchAngle.value.angle, unit: '°' },
            { name: '横向角度', value: yawAngle.value.angle, unit: '°' },
        ],
        [
            { name: '储存', value: '64.5G' },
            { name: '储存', value: usedStorageGB, unit: 'G' },
            { name: '方向', value: pitchAngle.value.direction },
            { name: '方向', value: yawAngle.value.direction },
        ],
    ]
})
const pitchAngle = computed(() => {
    const { payloads } = host?.value || {}
    const { payloads } = device_osd_host?.value || {}
    const gimbal_pitch = payloads?.[0]?.gimbal_pitch || 0
    let direction = ''
    if (gimbal_pitch > -2 && gimbal_pitch < 2) {
@@ -224,8 +235,7 @@
})
const yawAngle = computed(() => {
    let { longitude, latitude, height, payloads, attitude_head } = host?.value || {}
    const gimbal_pitch = payloads?.[0]?.gimbal_pitch || 0
    let { payloads, attitude_head } = device_osd_host?.value || {}
    const gimbal_yaw = payloads?.[0]?.gimbal_yaw || 0
    attitude_head = attitude_head || 0
    let yaw = ''
@@ -244,45 +254,16 @@
    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 = '正北'
    const roundResult = Math.round(result);
    let direction = '';
    for (const item of directionMap) {
        if (roundResult >= item.min && roundResult <= item.max) {
            direction = item.value;
            break;
        }
    }
    return {
        angle: _.round(result, 1) + '°',
        angle: _.round(result, 1),
        direction,
    }
})
@@ -400,7 +381,7 @@
// 返航或取消返航
const returnOrCancelReturn = () => {
    if (deviceOsdInfo.value?.data?.host?.mode_code === 9) {
    if (device_osd_host?.value?.mode_code === 9) {
        cancelBackDock()
    } else {
        onBackDock()
src/components/CurrentTaskDetails/CurrentTaskDetails.vue
@@ -17,10 +17,9 @@
            <RealTimeMap :class="`${isMaxMap ? 'maxBox' : 'minBox'}`" />
            <TaskDetailsRight v-if="isAutoControl" />
            <template v-else>
            </template>
            <TaskDetailsHead />
                <TaskDetailsHead />
                <TaskDetailsLeft />
            </template>
            <!--    控制面板,里面有方法需要立即执行,不可用v-if        -->
<!--            <ControlPanel />-->
src/components/CurrentTaskDetails/TaskDetailsHead.vue
@@ -92,7 +92,6 @@
    const dock_osd_host = wsInfo?.value?.dock_osd?.data?.host || {}
    const { longitude, latitude, height, horizontal_speed, vertical_speed, wind_speed, battery } = device_osd_host
    const { longitude: dockLon, latitude: dockLat, wireless_link } = dock_osd_host
    let dist = infoList.value[11].value
    if (longitude && latitude && dockLon && dockLat) {
        dist = _.round(getLnglatDist(longitude, latitude, dockLon, dockLat), 0)
src/const/drc.js
@@ -10,3 +10,22 @@
export const fourGQuality = { 0: '无信号', 1: '差', 2: '较差', 3: '一般', 4: '较好', 5: '好' }
export const SDRQuality = { 0: '无信号', 1: '差', 2: '较差', 3: '一般', 4: '较好', 5: '好' }
export const directionMap = [
    { min: 0, max: 0, value: '正北' },
    { min: 0, max: 45, value: '北偏东' },
    { min: 45, max: 45, value: '东北' },
    { min: 45, max: 90, value: '北偏东' },
    { min: 90, max: 90, value: '正东' },
    { min: 90, max: 135, value: '东偏南' },
    { min: 135, max: 135, value: '东南' },
    { min: 135, max: 180, value: '南偏东' },
    { min: 180, max: 180, value: '正南' },
    { min: 180, max: 225, value: '南偏西' },
    { min: 225, max: 225, value: '西南' },
    { min: 225, max: 270, value: '西偏南' },
    { min: 270, max: 270, value: '正西' },
    { min: 270, max: 315, value: '西偏北' },
    { min: 315, max: 315, value: '西北' },
    { min: 315, max: 360, value: '北偏西' },
    { min: 360, max: 360, value: '正北' }
];