徐景良 2025-07-12 16:02:44 +08:00
commit 6f9ce2d360
9 changed files with 555 additions and 462 deletions

View File

@ -158,7 +158,7 @@
setTimeout(() => {
uavLive.value = true;
livePreviewVisible.value = true;
}, 2000);
}, 5000);
}
};
const loadLiveStreaming = () => {

View File

@ -154,8 +154,10 @@
};
//
onBeforeUnmount(() => {
if(player){
player.dispose();
player = null;
}
});
</script>
<style lang="less" scoped>

View File

@ -1,13 +1,6 @@
<template>
<VueDragResize
:w="width"
:h="height"
:x="left"
:y="top"
:isActive="true"
:parentLimitation="true"
:isResizable="false"
>
<VueDragResize :w="width" :h="height" :x="left" :y="top" :isActive="true" :parentLimitation="true"
:isResizable="false">
<div class="flight-control" v-if="airportVal" v-drag>
<div class="title">
<div>
@ -31,89 +24,64 @@
<!-- <a-button>智能环绕</a-button> -->
<a-button @click="returnVoyage"></a-button>
<a-button @click="obtain" style="background-color: #1b71e8; border: none">
<template #icon v-if="flightGrab"><CheckOutlined /></template>
<template #icon v-if="flightGrab">
<CheckOutlined />
</template>
获取飞行器控制权
</a-button>
<a-button @click="enterDRC" style="background-color: #24d365; border: none">
<template #icon v-if="modeEnter"><CheckOutlined /></template>
<template #icon v-if="modeEnter">
<CheckOutlined />
</template>
进入飞行控制
</a-button>
<a-button @click="exitDRC" style="background-color: #e3150e; border: none"
>退出飞行控制</a-button
>
<a-button @click="exitDRC" style="background-color: #e3150e; border: none">退出飞行控制</a-button>
</div>
<div class="content-info">
<div class="info-item">
<!-- <img src="@/assets/images/flightoperation/flight_control.png" alt="" /> -->
<div class="info-item-top" title="上升" @click="changeDRC('throttle', 'up', '上升')">
<img
src="@/assets/images/flightoperation/top-active.png"
alt=""
v-if="selectName == '上升'"
/>
<div class="info-item-top" title="上升" @mousedown="changeDRC('throttle', 'up', '上升')"
@mouseup="changeDRC('throttle', 'up', '')">
<img src="@/assets/images/flightoperation/top-active.png" alt="" v-if="selectName == ''" />
<img src="@/assets/images/flightoperation/top.png" alt="" v-else />
</div>
<div class="info-item-right" title="右旋转" @click="changeDRC('yaw', 'up', '右旋转')">
<img
src="@/assets/images/flightoperation/right-active.png"
alt=""
v-if="selectName == '右旋转'"
/>
<div class="info-item-right" title="右旋转" @mousedown="changeDRC('yaw', 'up', '右旋转')"
@mouseup="changeDRC('yaw', 'up', '')">
<img src="@/assets/images/flightoperation/right-active.png" alt="" v-if="selectName == ''" />
<img src="@/assets/images/flightoperation/right.png" alt="" v-else />
</div>
<div
class="info-item-bottom"
title="下降"
@click="changeDRC('throttle', 'down', '下降')"
>
<img
src="@/assets/images/flightoperation/bottom-active.png"
alt=""
v-if="selectName == '下降'"
/>
<div class="info-item-bottom" title="下降" @mousedown="changeDRC('throttle', 'down', '下降')"
@mouseup="changeDRC('throttle', 'down', '')">
<img src="@/assets/images/flightoperation/bottom-active.png" alt="" v-if="selectName == ''" />
<img src="@/assets/images/flightoperation/bottom.png" alt="" v-else />
</div>
<div class="info-item-left" title="左旋转" @click="changeDRC('yaw', 'down', '左旋转')">
<img
src="@/assets/images/flightoperation/left-active.png"
alt=""
v-if="selectName == '左旋转'"
/>
<div class="info-item-left" title="左旋转" @mousedown="changeDRC('yaw', 'down', '左旋转')"
@mouseup="changeDRC('yaw', 'down', '')">
<img src="@/assets/images/flightoperation/left-active.png" alt="" v-if="selectName == ''" />
<img src="@/assets/images/flightoperation/left.png" alt="" v-else />
</div>
</div>
<div class="info-item">
<!-- <img src="@/assets/images/flightoperation/flight_control.png" alt="" /> -->
<div class="info-item-top" title="前进" @click="changeDRC('pitch', 'up', '前进')">
<img
src="@/assets/images/flightoperation/top-active.png"
alt=""
v-if="selectName == '前进'"
/>
<div class="info-item-top" title="前进"
@mousedown="changeDRC('pitch', 'up', '前进')" @mouseup="changeDRC('pitch', 'up', '')">
<img src="@/assets/images/flightoperation/top-active.png" alt=""
v-if="selectName == '前进'" />
<img src="@/assets/images/flightoperation/top.png" alt="" v-else />
</div>
<div class="info-item-right" title="右移" @click="changeDRC('roll', 'up', '右移')">
<img
src="@/assets/images/flightoperation/right-active.png"
alt=""
v-if="selectName == '右移'"
/>
<div class="info-item-right" title="右移"
@mousedown="changeDRC('roll', 'up', '右移')" @mouseup="changeDRC('roll', 'up', '')">
<img src="@/assets/images/flightoperation/right-active.png" alt="" v-if="selectName == ''" />
<img src="@/assets/images/flightoperation/right.png" alt="" v-else />
</div>
<div class="info-item-bottom" title="后退" @click="changeDRC('pitch', 'down', '后退')">
<img
src="@/assets/images/flightoperation/bottom-active.png"
alt=""
v-if="selectName == '后退'"
/>
<div class="info-item-bottom" title="后退"
@mousedown="changeDRC('pitch', 'down', '后退')" @mouseup="changeDRC('pitch', 'down', '')">
<img src="@/assets/images/flightoperation/bottom-active.png" alt="" v-if="selectName == '退'" />
<img src="@/assets/images/flightoperation/bottom.png" alt="" v-else />
</div>
<div class="info-item-left" title="左移" @click="changeDRC('roll', 'down', '左移')">
<img
src="@/assets/images/flightoperation/left-active.png"
alt=""
v-if="selectName == '左移'"
/>
<div class="info-item-left" title="左移"
@mousedown="changeDRC('roll', 'down', '左移')" @mouseup="changeDRC('roll', 'down', '')">
<img src="@/assets/images/flightoperation/left-active.png" alt="" v-if="selectName == ''" />
<img src="@/assets/images/flightoperation/left.png" alt="" v-else />
</div>
</div>
@ -257,17 +225,56 @@
});
};
const seq = ref(1);
const longPressTimer = ref();
const longPressInterval = ref();
const longPressDuration = ref(1000);//
const changeDRC = (type, value, name) => {
selectName.value = name;
setTimeout(() => {
selectName.value = '';
}, 2000);
if (name !== '') {
console.log('鼠标按下');
if (!flightGrab.value) {
createMessage.warning('请先获取飞行器控制权');
return;
}
if (!modeEnter.value) {
createMessage.warning('请先进入指令飞行控制');
return;
}
createMessage.info(name + '指令已发送');
let isLongPress = false;
longPressTimer.value = setTimeout(() => {
console.log('长按事件触发!');
isLongPress = true;
longPressInterval.value = setInterval(() => {
seq.value = seq.value + 1;
let querys = getDRCFlightQuery(type, value, seq);
drcDownTopicReize(querys);
createMessage.info(name + '指令已发送');
}, 1000)
}, longPressDuration.value);
if (isLongPress) {
isLongPress = false;
return;
}
seq.value = seq.value + 1;
let querys = getDRCFlightQuery(type, value, seq);
drcDownTopicReize(querys);
createMessage.info(name + '指令已发送');
} else {
if (longPressTimer.value) {
clearTimeout(longPressTimer.value);
longPressTimer.value = null;
console.log('清除延时器');
}
if (longPressInterval.value) {
clearTimeout(longPressInterval.value);
longPressInterval.value = null;
console.log('清除定时器');
}
console.log('鼠标松开');
}
};
const getDRCFlightQuery = (type, value, seq) => {
let data = {
roll: 1024,
pitch: 1024,
@ -288,7 +295,8 @@
tid: buildGUID(),
timestamp: new Date().getTime(),
};
drcDownTopicReize(querys);
console.log(querys);
return querys;
};
const drcSeq = ref(1);
const enterDRC = () => {
@ -455,6 +463,7 @@
border-radius: 6px;
backdrop-filter: blur(3px);
color: #fff;
.title {
width: 100%;
padding: 10px 0;
@ -463,65 +472,79 @@
display: flex;
align-items: center;
justify-content: space-between;
i {
color: #f2762d;
font-style: normal;
}
div {
color: #fff;
cursor: pointer;
}
}
.content-item {
display: flex;
align-items: center;
border-bottom: 1px solid #4e5778;
padding: 10px 0;
}
.content-button {
margin-top: 10px;
button {
background: none;
margin: 10px 0 0 10px;
color: #fff;
}
}
.content-info {
display: flex;
align-items: center;
justify-content: space-between;
.info-item {
position: relative;
width: 48%;
height: 116px;
margin: 24px 0 20px 20px;
img {
width: 36px;
}
.info-item-top {
position: absolute;
top: 8px;
left: 20px;
cursor: pointer;
img {
width: 62px;
}
}
.info-item-right {
position: absolute;
top: 30px;
right: 36px;
cursor: pointer;
}
.info-item-bottom {
position: absolute;
bottom: 0px;
left: 21px;
cursor: pointer;
img {
width: 62px;
}
}
.info-item-left {
position: absolute;
top: 30px;

View File

@ -286,8 +286,10 @@
};
//
onBeforeUnmount(() => {
if(player){
player.dispose();
player = null;
}
});
</script>
<style lang="less" scoped>

View File

@ -300,14 +300,15 @@
let data = {
payload_index: uav.camera_index,
locked: true,
pitch_speed: 8,
yaw_speed: 8,
pitch_speed: 0,
yaw_speed: 0,
};
if (val == 'up') {
data[type] = 8;
} else {
data[type] = -8;
}
console.log('data', data);
//
servicesTopicReize({
bid: buildGUID(),

View File

@ -67,7 +67,12 @@
value: item.Id,
};
});
if(sessionStorage.getItem('homeToFlightId')){
selectVal.project = sessionStorage.getItem('homeToFlightId');
sessionStorage.removeItem('homeToFlightId')
} else {
selectVal.project = optionsArr.projectOptions[0].value;
}
getAirPort(selectVal.project);
} else {
optionsArr.projectOptions = [];

View File

@ -10,7 +10,7 @@
<div class="interval"></div>
<div class="list">
<div v-for="item in projectList">
<div :class="`project-list-item ${activeProject == item.Id? 'active': ''}`" @click="selectProject(item)">
<div :class="`project-list-item ${props.activeProject == item.Id? 'active': ''}`" @click="selectProject(item)">
<div style="display: flex;align-items: center;">
<div class="list-item-icon"></div>
<div class="list-item-content">{{ item.WorkspaceName }}</div>
@ -36,23 +36,40 @@ import { ref, defineProps, onMounted, createVNode } from "vue"
import { GetWorkspaceList, GetWorkSpaceById, DeleteWorkspace } from '@/api/demo/projecthome'
import { message, Modal } from 'ant-design-vue'
import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
import { getClient, createConnection, clientSubscribe, destroyConnection } from '@/utils/mqtt';
onMounted(() => {
getProjectList()
})
const props = defineProps(['map'])
const props = defineProps(['map', 'activeProject', 'airPort'])
const emits = defineEmits(['update:activeProject'])
const addModal = ref(false)
const modalType = ref('')
const projectList = ref([])
const activeProject = ref('')
const updateProject = ref({})
const lastSubscriptUrl = ref('')
const addProject = () => {
modalType.value = 'insert'
addModal.value = true
}
const selectProject = (item) => {
activeProject.value = item.Id
if(props.activeProject != item.Id){
props.airPort.latitude = null
props.airPort.longitude = null
getClient().unsubscribe(lastSubscriptUrl.value,(error, res) => {})
}
emits('update:activeProject',item.Id)
let params = {
id: item.Id
}
GetWorkSpaceById(params).then(res => {
res.lasaDronePort.forEach(item => {
const topicUrl = 'thing/product/' + item.sn + '/osd';
lastSubscriptUrl.value = topicUrl
clientSubscribe(topicUrl, { qos: 0 });
})
})
}
const getProjectList = () => {
GetWorkspaceList().then(res => {

View File

@ -1,11 +1,11 @@
<template>
<div class="home-page">
<div style="width: 100%;height: calc(100vh - 80px);">
<Map @mapOnLoad="mapOnLoad"/>
<Map :airRoute="airRoute" @mapOnLoad="mapOnLoad" :airPort="airPort" @clickAirPort="clickAirPort"/>
</div>
<div ref="leftComponentRef" style="position: absolute;top: 0px;left: 0px;">
<!-- 项目列表 -->
<ProjectList :map="map"/>
<ProjectList :map="map" v-model:activeProject="activeProject" :airPort="airPort"/>
<!-- 基本信息 -->
<Info />
</div>
@ -19,20 +19,40 @@
</template>
<script setup lang="ts">
// import Map from '@/views/demo/workmanagement/workplan/components/map.vue'
import Map from './Map/index.vue'
import Map from '@/views/demo/workmanagement/workplan/components/map.vue'
// import Map from './Map/index.vue'
import ProjectList from './ProjectList/index.vue'
import Info from './Info/index.vue'
import Inspection from './Inspection/index.vue'
import Result from './Result/index.vue'
import { ref, onMounted, onBeforeUnmount, } from "vue"
import { getClient, createConnection, clientSubscribe, destroyConnection } from '@/utils/mqtt';
import { useRouter } from 'vue-router';
const router = useRouter();
const airRoute = ref({
airLineType: null,
airType: null,
airModel: null,
name: null,
});
const airPort = ref({
latitude: null,
longitude: null,
});
const activeProject = ref('')
const DESIGN_WIDTH = 1912
const DESIGN_HEIGHT = 962
const leftComponentRef = ref<HTMLElement | null>(null)
const rightComponentRef = ref<HTMLElement | null>(null)
let map
const map = ref()
const clickAirPort = () => {
sessionStorage.setItem('homeToFlightId', activeProject.value);
router.push({
path: '/workmanagement/flightoperation',
});
}
function updateScale() {
const scaleX = window.innerWidth / DESIGN_WIDTH
const scaleY = window.innerHeight / DESIGN_HEIGHT
@ -47,16 +67,28 @@ function updateScale() {
right.style.transform = `scale(${scale}) translate(-50%, -50%)`
}
}
const connectionCallback = () => {
getClient().on('message', (topic, msg) => {
if (topic.endsWith("osd")) {
const rs = JSON.parse(msg)
if (rs.data.latitude && rs.data.longitude) {
airPort.value.latitude = rs.data.latitude;
airPort.value.longitude = rs.data.longitude;
}
}
});
}
onMounted(() => {
createConnection(connectionCallback)
updateScale()
window.addEventListener('resize', updateScale)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', updateScale)
destroyConnection()
})
const mapOnLoad = (value) => {
map = value
map.value = value
}
</script>

View File

@ -148,7 +148,7 @@ const generatePreviewPoint = (placemark)=>{
}
};
const emits = defineEmits(['exitDraw', 'flyToThere']);
const emits = defineEmits(['exitDraw', 'flyToThere', 'mapOnLoad', 'clickAirPort']);
const airPoints = ref([]);
const currentAirPoint = ref({});
@ -199,6 +199,9 @@ const generatePreviewPoint = (placemark)=>{
// 线
let lineGroundPointLayer: mars3d.layer.GraphicLayer;
//
let startGraphic;
let graphic = null;
const exitDraw = () => {
@ -457,6 +460,7 @@ const generatePreviewPoint = (placemark)=>{
}
//
loadChangGuangLayer();
emits('mapOnLoad',map)
});
};
@ -1546,11 +1550,15 @@ const loadChangGuangLayer = ()=>{
//
const setAirportPosition = async () => {
if(!graphicLayer){
return
}
let point = graphicLayer.getGraphicById('set-airport');
// //
let position = [props.airPort.longitude, props.airPort.latitude, 70];
//
if (point) {
if (startGraphic) {
startGraphic.position = position
// point.setOptions({
// id: 'set-airport',
// name: '',
@ -1573,7 +1581,7 @@ const loadChangGuangLayer = ()=>{
// },
// });
} else {
let startGraphic = new mars3d.graphic.BillboardEntity({
startGraphic = new mars3d.graphic.BillboardEntity({
id: 'set-airport',
position: position,
style: {
@ -1593,6 +1601,9 @@ const loadChangGuangLayer = ()=>{
},
},
});
startGraphic.on(mars3d.EventType.click, function (event) {
emits('clickAirPort')
});
graphicLayer.addGraphic(startGraphic);
}
};