From 01f329228c55cdbe3c1391b427c7a54c891efada Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Tue, 15 Apr 2025 20:42:08 +0800
Subject: [PATCH] Merge branch 'master' of http://139.196.74.78:10010/r/drone/command-center-dashboard

---
 src/views/TaskManage/TaskIntermediateContent/CurrentTaskDetails/ControlPanel.vue |  412 +++++++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 275 insertions(+), 137 deletions(-)

diff --git a/src/views/TaskManage/TaskIntermediateContent/CurrentTaskDetails/ControlPanel.vue b/src/views/TaskManage/TaskIntermediateContent/CurrentTaskDetails/ControlPanel.vue
index a5abf27..5ef46bc 100644
--- a/src/views/TaskManage/TaskIntermediateContent/CurrentTaskDetails/ControlPanel.vue
+++ b/src/views/TaskManage/TaskIntermediateContent/CurrentTaskDetails/ControlPanel.vue
@@ -1,86 +1,202 @@
 <template>
 	<div class="pointControl">
+		<div class="manualControl"></div>
+
 		<div class="direction">
-			<div class="blackBg directionUp">
-				<div v-for="item in upperRowButton" :key="item.text">
-					<el-icon :class="item.icon"></el-icon>
-					<div
-						:class="{ hotkeyBtn: true, activeKey: currentKey === item.text }"
-						@click="() => mousedown(item.text)"
-						v-hold="() => mousedown(item.text)"
-					>
-						{{ item.text }}
+			<div class="boxTitle">
+				飞
+				<br />
+				行
+				<br />
+				控
+				<br />
+				制
+				<br />
+				器
+			</div>
+			<div class="btnGroup">
+				<div class="btnGroupT">
+					<div class="btnItem" v-for="item in list1">
+						<el-icon class="btnIcon">
+							<component :is="item.icon" />
+						</el-icon>
+						<div class="btn" @mousedown="onMouseDown(item.key)" @mouseup="onMouseUp">{{ item.text }}</div>
+					</div>
+				</div>
+				<div class="btnGroupB">
+					<div class="btnItem" v-for="item in list2">
+						<div class="btn" @mousedown="onMouseDown(item.key)" @mouseup="onMouseUp">{{ item.text }}</div>
+						<el-icon class="btnIcon">
+							<component :is="item.icon" />
+						</el-icon>
 					</div>
 				</div>
 			</div>
-			<div class="blackBg directionDown">
-				<div v-for="item in lowerRowButton" :key="item.text">
-					<el-icon :class="item.icon"></el-icon>
-					<div
-						:class="{ hotkeyBtn: true, activeKey: currentKey === item.text }"
-						@click="() => mousedown(item.text)"
-						v-hold="() => mousedown(item.text)"
-					>
-						{{ item.text }}
+
+			<div class="speed">
+				<el-icon class="btnIcon">
+					<Plus />
+				</el-icon>
+				<div>5<br>m/s</div>
+				<el-icon class="btnIcon">
+					<Minus />
+				</el-icon>
+			</div>
+
+
+			<div class="upAndDown">
+				<div class="btnGroupT">
+					<div class="btnItem">
+						<el-icon class="btnIcon">
+							<Top />
+						</el-icon>
+						<div class="btn" @mousedown="onMouseDown(KeyCode.ARROW_UP)" @mouseup="onMouseUp">C</div>
+					</div>
+				</div>
+				<div class="btnGroupT">
+					<div class="btnItem">
+						<div class="btn" @mousedown="onMouseDown(KeyCode.ARROW_DOWN)" @mouseup="onMouseUp">Z</div>
+						<el-icon class="btnIcon">
+							<Bottom />
+						</el-icon>
 					</div>
 				</div>
 			</div>
+
 		</div>
 
-		<ControlComPass />
+		<div class="compass">
+			<ControlComPass />
+		</div>
 
-		<div class="height-direction">
-			<div class="blackBg height-direction-btn">
-				<el-icon class="el-icon-top" />
-				<div :class="{ hotkeyBtn: true, activeKey: currentKey === 'C' }" v-hold="() => mousedown('C')">C</div>
+		<div class="ptzControl">
+			<div>
+				云
+				<br />
+				台
+				<br />
+				控
+				<br />
+				制
 			</div>
-			<div class="blackBg height-direction-btn">
-				<div :class="{ hotkeyBtn: true, activeKey: currentKey === 'Z' }" v-hold="() => mousedown('Z')">Z</div>
-				<el-icon class="el-icon-bottom" />
-			</div>
+			<div></div>
 		</div>
 	</div>
 </template>
 <script setup>
-import vHold from '@/directive/hold'
 import ControlComPass from './ControlComPass/ControlComPass.vue'
+import { KeyCode, useManualControl } from '@/hooks/controlDrone/useManualControl'
+import { droneController, exitController, postDrc, postDrcExit } from '@/api/drc'
+import { ElMessage } from 'element-plus'
+import { useStore } from 'vuex'
+import { UranusMqtt } from '@/mqtt'
+import {
+	ArrowDown,
+	ArrowLeft,
+	ArrowRight,
+	ArrowUp,
+	Bottom, Minus,
+	Plus,
+	RefreshLeft,
+	RefreshRight,
+} from '@element-plus/icons-vue'
 
-const lowerRowButton = [
-	{ icon: 'el-icon-arrow-left', text: 'A' },
-	{ icon: 'el-icon-arrow-down', text: 'S' },
-	{ icon: 'el-icon-arrow-right', text: 'D' },
+const deviceOsdInfo = inject('deviceOsdInfo')
+const taskDetails = inject('taskDetails')
+const store = useStore()
+const workspace_id = computed(() => taskDetails.value.way_lines[0].workspace_id)
+const dock_sn = computed(() => taskDetails.value.device_sns[0])
+const list1 = [
+	{ key: KeyCode.KEY_Q, text: 'Q', icon: RefreshLeft },
+	{ key: KeyCode.KEY_W, text: 'W', icon: ArrowUp },
+	{ key: KeyCode.KEY_E, text: 'E', icon: RefreshRight },
 ]
-const upperRowButton = [
-	{ icon: 'el-icon-refresh-left', text: 'Q' },
-	{ icon: 'el-icon-arrow-up', text: 'W' },
-	{ icon: 'el-icon-refresh-right', text: 'E' },
+const list2 = [
+	{ key: KeyCode.KEY_A, text: 'A', icon: ArrowLeft },
+	{ key: KeyCode.KEY_S, text: 'S', icon: ArrowDown },
+	{ key: KeyCode.KEY_D, text: 'D', icon: ArrowRight },
 ]
-let currentKey = ref('')
-let keyReset = null
-let visible = false
 
-function mousedown(key) {
-	if (key === 'Q') {
-		console.log(6666666666)
+let mqttState = null
+const client_id = ref('')
+
+const deviceTopicInfo = ref({
+	sn: deviceOsdInfo.value?.data?.sn,
+	pubTopic: '',
+	subTopic: '',
+})
+const flightController = ref(false)
+console.log('控制面板')
+
+// 控制对象
+let manualControl = {}
+
+function onMouseDown(type) {
+	manualControl?.handleKeyup(type)
+}
+
+function onMouseUp() {
+	console.log('弹起')
+	manualControl?.resetControlState()
+}
+
+// 取消手动控制
+function cancelControl() {
+	exitController({ client_id: client_id.value, dock_sn: dock_sn.value })
+		.then(res => {
+			flightController.value = false
+			deviceTopicInfo.value.subTopic = ''
+			deviceTopicInfo.value.pubTopic = ''
+			ElMessage.success('退出飞行控制成功')
+		})
+		.catch(e => {})
+}
+
+// 手动控制
+function control() {
+	if (!client_id.value) return ElMessage.error('无人机不在空中,不能进入指挥飞行模式。')
+	if (!dock_sn.value) return ElMessage.error('系统错误,未获取到dock_sn')
+	droneController({ client_id: client_id.value, dock_sn: dock_sn.value }).then(res => {
+		flightController.value = true
+		const { data } = res.data
+		if (data.sub && data.sub?.length > 0) {
+			deviceTopicInfo.value.subTopic = data.sub[0]
+		}
+		if (data.pub && data.pub?.length > 0) {
+			deviceTopicInfo.value.pubTopic = data.pub[0]
+		}
+		ElMessage.success('控制成功')
+	})
+}
+
+// 创建连接
+const createConnect = async () => {
+	const result = await postDrc({}, workspace_id.value)
+	if (result?.code === 0) {
+		const { address, client_id: clientId, username, password, expire_time } = result.data
+		mqttState = new UranusMqtt(address, { clientId, username, password })
+		mqttState?.initMqtt()
+		client_id.value = clientId
 	}
 }
 
-function handleKeydown(e) {
-	currentKey.value = e.key.toUpperCase()
-	mousedown(e.key.toUpperCase())
+// 销毁连接
+const destroyConnect = () => {
+	if (mqttState) {
+		mqttState?.destroyed()
+		mqttState = null
+		client_id.value = ''
+	}
 }
 
-function handleKeyup() {
-	currentKey.value = null
-}
-
-onMounted(() => {
-	window.addEventListener('keydown', handleKeydown)
-	window.addEventListener('keyup', handleKeyup)
+onMounted(async () => {
+	await createConnect()
+	// 使用控制
+	manualControl = useManualControl(mqttState, deviceTopicInfo.value, flightController)
 })
+
 onBeforeUnmount(() => {
-	window.removeEventListener('keydown', handleKeydown)
-	window.removeEventListener('keyup', handleKeyup)
+	destroyConnect()
 })
 </script>
 
@@ -90,110 +206,132 @@
 	align-items: center;
 }
 
-//变量
-$FSColor: #00ee8b;
-
-.hotkeyBtn {
-	background: #3c3c3c;
-	border-radius: 2px;
-	width: 24px;
-	height: 24px;
-	font-size: 14px;
-	line-height: 24px;
-	text-align: center;
-	color: #fff;
-	cursor: pointer;
-	-webkit-user-select: none;
-	user-select: none;
-
-	&:hover {
-		background: $FSColor;
-	}
-}
 
 .pointControl {
+	position: absolute;
+	bottom: 0;
+	right: 0;
+	width: 1540px;
+	height: 217px;
+	background: rgb(0, 0, 0, 0.4); /* 半透明背景 */
+	backdrop-filter: blur(5px);
+	border-radius: 40px 0px 40px 40px;
 	display: flex;
 	justify-content: center;
-	align-items: flex-end;
+	align-items: center;
 	color: white;
 	gap: 0 10px;
 	pointer-events: all;
-	width: 100%;
-	height: 200px;
-
-	.activeKey {
-		background: $FSColor;
-	}
-
-	.blackBg {
-		background: rgba(0, 0, 0, 0.65);
-		padding: 5px 5px;
-		border-radius: 5px;
-	}
 
 	.direction {
+		width: 476px;
+		height: 188px;
+		background: rgb(0, 0, 0, 0.4); /* 半透明背景 */
+		border-radius: 40px 40px 40px 40px;
 		display: flex;
-		flex-direction: column;
-		width: 100px;
-
-		.speedBox {
-			color: $FSColor;
-			font-size: 16px;
-			font-weight: 600;
-			margin: 5px 0;
-			gap: 0 5px;
+		align-items: center;
+		justify-content: space-around;
+		.boxTitle{
+			font-family: Segoe UI, Segoe UI;
+			font-weight: 400;
+			font-size: 14px;
+			color: #D2E8FA;
 		}
 
-		.editBox {
+		.btnGroup {
 			display: flex;
-			justify-content: end;
-			gap: 0 5px;
-			margin-bottom: 5px;
-
-			.current-point {
-				font-size: 20px;
-				display: flex;
-				align-items: center;
-				color: $FSColor;
-			}
-
-			.editPointBtn {
-				&:hover {
-					cursor: pointer;
-					background: $FSColor;
-				}
+			flex-direction: column;
+			gap: 10px 0;
+			.btnGroupT,
+			.btnGroupB {
+				width: 238px;
+				height: 73px;
 			}
 		}
-
-		.directionUp,
-		.directionDown {
+		.upAndDown{
 			display: flex;
-			justify-content: space-around;
-			text-align: center;
-			height: 55px;
-
-			> div {
-				display: flex;
-				flex-direction: column;
-				justify-content: space-between;
+			flex-direction: column;
+			gap: 10px 0;
+			.btnGroupT,
+			.btnGroupB {
+				width: 58px;
+				height: 73px;
 			}
 		}
-	}
-
-	.height-direction {
-		width: 100px;
-		display: flex;
-		flex-direction: column;
-		align-items: end;
-		gap: 5px 0;
-
-		.height-direction-btn {
-			width: 35px;
-			height: 55px;
-			text-align: center;
+		.speed{
 			display: flex;
 			flex-direction: column;
 			justify-content: space-between;
+			align-items: center;
+			width: 58px;
+			height: 155px;
+			background: #37393F;
+			box-shadow: 2px 4px 6px 0px rgba(0,13,26,0.42);
+			border-radius: 8px 8px 8px 8px;
+			text-align: center;
+			padding: 5px 0;
+			.btnIcon{
+				font-size: 20px;
+			}
+		}
+
+	}
+
+	.manualControl {
+		width: 188px;
+		height: 188px;
+		background: rgb(0, 0, 0, 0.4); /* 半透明背景 */
+		border-radius: 40px 40px 40px 40px;
+	}
+
+	.ptzControl {
+		width: 406px;
+		height: 188px;
+		background: rgb(0, 0, 0, 0.4); /* 半透明背景 */
+		border-radius: 40px 40px 40px 40px;
+	}
+
+	.compass {
+		width: 356px;
+		height: 188px;
+		background: rgba(157, 173, 189, 0.11);
+		background: rgb(0, 0, 0, 0.4); /* 半透明背景 */
+		border-radius: 40px 40px 40px 40px;
+	}
+
+
+	.btnGroupT,
+	.btnGroupB {
+		background: #37393f;
+		box-shadow: 2px 4px 6px 0px rgba(0, 13, 26, 0.42);
+		border-radius: 8px 8px 8px 8px;
+		display: flex;
+		align-items: center;
+		text-align: center;
+		justify-content: center;
+		gap: 0 45px;
+
+		.btnItem {
+			.btnIcon {
+				font-size: 20px;
+
+				&:first-child {
+					margin-bottom: 5px;
+				}
+			}
+
+			.btn {
+				width: 35px;
+				height: 35px;
+				background: #222324;
+				line-height: 35px;
+				border-radius: 5px;
+				cursor: pointer;
+
+				&:first-child {
+					margin-bottom: 5px;
+				}
+			}
 		}
 	}
 }

--
Gitblit v1.9.3