From 853fcbb7f34daa481e8141df8adb72cfaba6f144 Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Fri, 18 Apr 2025 15:49:12 +0800
Subject: [PATCH] feat: 控制台ai直播功能
---
src/components/CurrentTaskDetails/CurrentTaskDetails.vue | 160 ++++++++++++++++++++++++++++++++++-------------------
1 files changed, 103 insertions(+), 57 deletions(-)
diff --git a/src/components/CurrentTaskDetails/CurrentTaskDetails.vue b/src/components/CurrentTaskDetails/CurrentTaskDetails.vue
index 79e4a97..cc4fe6f 100644
--- a/src/components/CurrentTaskDetails/CurrentTaskDetails.vue
+++ b/src/components/CurrentTaskDetails/CurrentTaskDetails.vue
@@ -10,20 +10,20 @@
>
<div class="content-container" v-if="isShow">
<!-- 视频直播 -->
- <div class="video-container">
+ <div :class="`${isMaxMap ? 'minBox' : 'maxBox'}`">
<LiveVideo :videoUrl="currentLiveUrl" :controls="false" />
</div>
<!-- 展示地图 -->
- <RealTimeMap class="realTimeMap" />
+ <RealTimeMap :class="`${isMaxMap ? 'maxBox' : 'minBox'}`" />
<TaskDetailsRight v-if="isAutoControl" />
<template v-else>
<TaskDetailsHead />
+ <TaskDetailsLeft />
</template>
- <TaskDetailsLeft />
-
<!-- 控制面板,里面有方法需要立即执行,不可用v-if -->
<ControlPanel v-show="!isAutoControl" />
+ <img alt="" :src="amplifyImg" class="amplify" @click="isMaxMap = !isMaxMap" />
</div>
</el-dialog>
</template>
@@ -42,60 +42,79 @@
import TaskDetailsHead from '@/components/CurrentTaskDetails/TaskDetailsHead.vue'
import TaskDetailsLeft from '@/components/CurrentTaskDetails/TaskDetailsLeft.vue'
import TaskDetailsRight from '@/components/CurrentTaskDetails/TaskDetailsRight.vue'
+import amplifyImg from '@/assets/images/taskManagement/taskIntermediateContent/amplifyImg.png'
import { ElMessage } from 'element-plus'
import EventBus from '@/event-bus'
+import { updateDroneQualityApi } from '@/api/drc'
+import { getLiveAiLinkApi } from '@/api/payload'
+import { CURRENT_CONFIG } from '@/utils/http/config'
const isAutoControl = ref(true)
const lineQuality = ref(1) //1流畅,2标清
provide('isAutoControl', isAutoControl)
provide('lineQuality', lineQuality)
+const taskDetailsViewer = ref(null)
+provide('taskDetailsViewer', taskDetailsViewer)
+
+let taskDetails = ref({})
+provide('taskDetails', taskDetails)
+const deviceOsdInfo = ref({})
+provide('deviceOsdInfo', deviceOsdInfo)
+
+const dockSn = computed(() => taskDetails?.value?.device_sns?.[0])
+const droneSn = computed(() => deviceOsdInfo?.value?.data?.sn)
+provide('dockSn', dockSn)
+provide('droneSn', droneSn)
+
+const isAiLive = ref(false)
+provide('isAiLive', isAiLive)
+
const isShow = defineModel('show')
const props = defineProps(['id'])
const currentLiveUrl = ref('')
-const machineNestUrl = ref('')
-const droneLiveUrl = ref('')
-let taskDetails = ref({})
-const deviceOsdInfo = ref({})
-provide('taskDetails', taskDetails)
-provide('deviceOsdInfo', deviceOsdInfo)
-provide('dockSn', taskDetails?.value?.device_sns?.[0])
-provide('droneSn', deviceOsdInfo?.value?.data?.sn)
+const isTakeOff = ref(false)
+const isMaxMap = ref(false)
+let droneWebSocket //WS实例
+const video_id = ref('')
+provide('video_id', video_id)
-// 机巢直播
+// 获取机巢直播
const getDeviceLiveUrl = async () => {
- if (machineNestUrl.value) return machineNestUrl.value
- const res = await liveStart(taskDetails.value.device_sns[0], 2)
- machineNestUrl.value = res.data.data.rtcs_url
- return machineNestUrl.value
+ const res = await liveStart(dockSn.value, 2)
+ currentLiveUrl.value = res.data.data.rtcs_url
}
-// 无人机直播
-const getDroneLiveUrl = async droneSn => {
- if (droneLiveUrl.value) return droneLiveUrl.value
- const res = await liveStart(droneSn, lineQuality.value)
- droneLiveUrl.value = res.data.data.rtcs_url
- return droneLiveUrl.value
+const getAiLiveUrl = ()=>{
+ const res = getLiveAiLinkApi({ original_stream_url: `${CURRENT_CONFIG.rtmpURL}${video_id.value}`, video_id:video_id.value })
+ currentLiveUrl.value = res.data.data.rtcs_url
+ isAiLive.value = true
+}
+
+// 获取无人机直播url
+async function getDroneLiveUrl() {
+ const res = await liveStart(droneSn.value, lineQuality.value)
+ currentLiveUrl.value = res.data.data.rtcs_url
+ video_id.value = res.data.data.video_id
+ isAiLive.value = false
}
// 无人机直播画质切换
const changeLineQuality = async () => {
- const res = await liveStart(droneSn, lineQuality.value)
- droneLiveUrl.value = res.data.data.rtcs_url
- return droneLiveUrl.value
+ const res = await updateDroneQualityApi({ video_id: video_id.value, video_quality: lineQuality.value })
+ ElMessage.success('切换画质成功')
}
// 设置当前直播地址
const setCurrentLiveUrl = async () => {
const data = deviceOsdInfo.value?.data
const deviceInfo = data?.host
- const drone = data?.sn
- if ([14, 0].includes(deviceInfo.mode_code)) {
- currentLiveUrl.value = await getDeviceLiveUrl()
- } else {
- currentLiveUrl.value = await getDroneLiveUrl(drone)
- }
+ const currentIsTakeOff = ![14, 0].includes(deviceInfo.mode_code)
+ // 如果还是之前的状态,不切换
+ if (isTakeOff.value === currentIsTakeOff) return
+ isTakeOff.value = currentIsTakeOff
+ isTakeOff.value ? await getDroneLiveUrl() : await getDeviceLiveUrl()
}
// 获取任务详情获取航线文件
@@ -103,20 +122,47 @@
if (!props.id) ElMessage.warning('请检查是否传入id')
getJobDetails({ wayLineJobInfoId: props.id }).then(async res => {
taskDetails.value = res.data.data
- currentLiveUrl.value = await getDeviceLiveUrl()
+ await getDeviceLiveUrl()
taskDetails.value.workspace_id = taskDetails.value.way_lines[0]?.workspace_id
createWsConnect()
})
}
-// websocket 的消息
+const dockOsdInfo = ref({})
+provide('dockOsdInfo', dockOsdInfo)
+
+const wsInfo = ref({})
+provide('wsInfo', wsInfo)
+// websocket 的消息回调
const messageHandler = result => {
- let payload = JSON.parse(result) // 为了兼容聊天消息
+ let payload = JSON.parse(result)
+ wsInfo.value[payload.biz_code] = payload
switch (payload.biz_code) {
+ // 无人机
case EBizCode.DeviceOsd: {
deviceOsdInfo.value = payload
- // console.log(deviceOsdInfo.value,'osd信息')
setCurrentLiveUrl()
+ console.log(payload, 'DeviceOsd--信息')
+ break
+ }
+ // 遥控器
+ case EBizCode.GatewayOsd: {
+ console.log(payload, 'GatewayOsd--信息')
+ break
+ }
+ // 机巢
+ case EBizCode.DockOsd: {
+ console.log(payload, 'DockOsd--信息')
+ break
+ }
+ // PsdkWidgetValues
+ case EBizCode.PsdkWidgetValues: {
+ console.log(payload, 'PsdkWidgetValues--信息')
+ break
+ }
+ // VideoSurveillance
+ case EBizCode.VideoSurveillance: {
+ console.log(payload, 'VideoSurveillance--信息')
break
}
default:
@@ -125,35 +171,28 @@
}
// 创建ws连接
-let connectWs
const createWsConnect = () => {
const workspaceId = taskDetails.value.workspace_id
if (!workspaceId) return
let webSocketUrl = getWebsocketUrl() + '&workspace-id=' + workspaceId
// 监听ws 消息
- connectWs = useConnectWebSocket(messageHandler, webSocketUrl)
-}
-
-watch(
- () => taskDetails.value.workspace_id,
- () => {
- createWsConnect()
- }
-)
-
-const removeEvent = () => {
- connectWs?.close()
- deviceOsdInfo.value = {}
+ droneWebSocket = useConnectWebSocket(messageHandler, webSocketUrl)
}
onMounted(() => {
getTaskDetails()
EventBus.on('CurrentTaskDetails-timeStop', changeLineQuality)
+ EventBus.on('CurrentTaskDetails-getAiLiveUrl', getAiLiveUrl)
+ EventBus.on('CurrentTaskDetails-getDroneLiveUrl', getDroneLiveUrl)
})
onBeforeUnmount(() => {
+ droneWebSocket?.close()
+ deviceOsdInfo.value = {}
+ droneWebSocket = null
EventBus.off('CurrentTaskDetails-timeStop', changeLineQuality)
- removeEvent()
+ EventBus.off('CurrentTaskDetails-getAiLiveUrl', getAiLiveUrl)
+ EventBus.off('CurrentTaskDetails-getDroneLiveUrl', getDroneLiveUrl)
})
</script>
@@ -201,20 +240,27 @@
border-radius: 4rem;
overflow: hidden;
- .video-container {
+ .maxBox {
width: 100%;
height: 100%;
}
- .realTimeMap {
+ .minBox {
position: absolute;
- left: -1px;
- bottom: -1px;
- width: 218px;
- height: 217px;
+ width: 376px;
+ height: 212px;
+ left: 0;
+ bottom: 0;
border-radius: 0px 20px 0px 40px;
border: 1px solid #62a1ff;
overflow: hidden;
}
+
+ .amplify {
+ cursor: pointer;
+ position: absolute;
+ left: 340px;
+ bottom: 183px;
+ }
}
</style>
--
Gitblit v1.9.3