<template>
|
<div class="consoleRight">
|
<img
|
:src="recordMode ? xjqhSvg : lxqhSvg"
|
alt=""
|
@click="() => cameraDisable || (recordMode = !recordMode)"
|
:class="{ cameraDisable }"
|
:style="{ visibility: isRecording ? 'hidden' : 'visible' }"
|
/>
|
<div class="circle" @click="takePicOrRecord" :class="{ cameraDisable }">
|
<div :class="{ videoRecording: recordMode, pauseRecording: isRecording, pzhlx: true }"></div>
|
<div class="recordingTime" v-if="recordingTime !== '00:00:00'">{{ recordingTime }}</div>
|
</div>
|
|
<img
|
:src="hhSvg"
|
alt=""
|
@click="shoutDlg"
|
:style="{ visibility: loadDevice.speakIndex !== -1 && !isBackDock ? 'visible' : 'hidden' }"
|
/>
|
</div>
|
|
<Teleport to=".content-container" v-if="showSelectDlg">
|
<div class="selectShout">
|
<van-icon name="cross" class="closeDlg" @click="showSelectDlg = false" />
|
<div>请选择广播/喊话</div>
|
<div class="funBtn">
|
<div class="broadcast" @click="broadcastBtnFun">广播</div>
|
<div class="shoutBtn" @click="shoutBtnFun">喊话</div>
|
</div>
|
</div>
|
</Teleport>
|
|
<ShoutComponent v-model:show="showShouting" v-if="showShouting" />
|
<BroadcastComponent v-model:show="showBroadcast" v-if="showBroadcast" />
|
</template>
|
|
<script setup>
|
import EventBus from '@/utils/eventBus'
|
import _ from 'lodash'
|
import {
|
callPhotoAndVideoCmd,
|
cameraParamsChangeApi,
|
ptzResetModeApi,
|
setWidgetSetApi,
|
setThermalCurrentPaletteStyle,
|
openSendWsApi,
|
closeSendWsApi,
|
startVoice,
|
voiceMode,
|
} from '@/api/payload'
|
import getBaseConfig from '@/buildConfig/config'
|
import xjqhSvg from '@/appDataSource/inspectionTask/droneConsole/相机切换.svg'
|
import lxqhSvg from '@/appDataSource/inspectionTask/droneConsole/录像.svg'
|
import hhSvg from '@/appDataSource/inspectionTask/droneConsole/喊话.svg'
|
import { showToast } from 'vant'
|
import ShoutComponent from '@/components/CurrentTaskDetails/AppConsoleRight/ShoutComponent.vue'
|
import BroadcastComponent from '@/components/CurrentTaskDetails/AppConsoleRight/BroadcastComponent.vue'
|
|
const showSelectDlg = ref(false)
|
const showShouting = ref(false)
|
const showBroadcast = ref(false)
|
|
const wsInfo = inject('wsInfo')
|
const zoomFactor = inject('zoomFactor')
|
const activeSlider = inject('activeSlider')
|
const isRecording = inject('isRecording')
|
const recordingTime = inject('recordingTime')
|
const cameraParams = inject('cameraParams')
|
const isManualControl = inject('isManualControl')
|
const droneSn = inject('droneSn')
|
const dockSn = inject('dockSn')
|
const lineQuality = inject('lineQuality')
|
const usedControl = inject('usedControl')
|
const irModeStyleType = inject('irModeStyleType')
|
const loadDevice = inject('loadDevice')
|
const workspace_id = inject('workspace_id')
|
const hasPayloadControl = inject('hasPayloadControl')
|
const isRouteRecord = inject('isRouteRecord')
|
const showUpKeyPanel = inject('showUpKeyPanel')
|
const showFunBlock = inject('showFunBlock')
|
const zoomText = computed(() => cameraParams.value.zoom_factor + 'X')
|
const hasAiTypeStr = inject('hasAiTypeStr')
|
const delayedRecepAuto = inject('delayedRecepAuto')
|
const isBackDock = inject('isBackDock')
|
const droneStatus = inject('droneStatus')
|
const modeCode = computed(() => droneStatus?.value?.mode_code)
|
const cameraDisable = computed(() => hasAiTypeStr.value|| isBackDock.value || photoAndVideoLoading.value)
|
const editCameraDebounce = _.debounce(fn => {
|
fn()
|
}, 1000) //修改相机信息节流版
|
const photoAndVideoLoading = ref(false) //拍照录像接口加载中
|
const recordMode = ref(false)
|
|
function takePicOrRecord() {
|
if (cameraDisable.value) return
|
recordMode.value ? recordFun() : takePictures()
|
}
|
|
function shoutDlg() {
|
showSelectDlg.value = true
|
}
|
|
function shoutBtnFun() {
|
showSelectDlg.value = false
|
showShouting.value = true
|
}
|
|
function broadcastBtnFun() {
|
showSelectDlg.value = false
|
showBroadcast.value = true
|
}
|
|
function droneContinues() {
|
EventBus.emit('controlPanel-cancelManualControl')
|
}
|
|
function switchDronePaused() {
|
usedControl.value = true
|
EventBus.emit('controlPanel-control')
|
}
|
|
// 返航
|
function turnBack() {
|
EventBus.emit('controlPanel-returnOrCancelReturn')
|
}
|
|
// 延迟4秒接收相机信息
|
function delayedRecepCamera(key) {
|
cameraParams.value.camera_type = key
|
delayedRecepAuto()
|
}
|
|
const popperOptions = {
|
placement: 'right',
|
modifiers: [
|
{
|
name: 'offset',
|
options: {
|
offset: [120, 35],
|
},
|
},
|
],
|
}
|
|
const hasIr = inject('hasIr')
|
const list1 = computed(() => {
|
return [
|
{ name: '广角', key: 'wide', show: true },
|
{ name: '变焦', key: 'zoom', show: true },
|
]
|
})
|
|
// 调色盘选项数据
|
const paletteOptions = ref([
|
{ label: '白热', value: 0 },
|
{ label: '黑热', value: 1 },
|
{ label: '描红', value: 2 },
|
{ label: '医疗', value: 3 },
|
{ label: '彩虹1', value: 5 },
|
{ label: '铁红', value: 6 },
|
{ label: '北极', value: 8 },
|
{ label: '熔岩', value: 11 },
|
{ label: '热铁', value: 12 },
|
{ label: '彩虹2', value: 13 },
|
])
|
|
// 探照灯选项数据
|
const searchlightModeList = ref([
|
{ label: '关闭', value: 0 },
|
{ label: '爆闪', value: 2 },
|
{ label: '常亮', value: 1 },
|
])
|
|
const qualityList = [
|
{ name: '自适应', id: 0 },
|
{ name: '流畅', id: 1 },
|
{ name: '标清', id: 2 },
|
{ name: '高清', id: 3 },
|
{ name: '超清', id: 4 },
|
]
|
|
const ptzResetMode = _.throttle(resetMode => {
|
ptzResetModeApi({ sn: dockSn.value, resetMode })
|
}, 2000)
|
|
// 创建一个防抖函数,延迟 2000 毫秒执行
|
const debouncedActiveSlider = _.debounce(() => (activeSlider.value = false), 4000)
|
// 修改相机参数-节流版
|
const cameraParamsChangeThrottle = _.throttle(cameraParamsChange, 500)
|
|
// 倍率调整
|
function sliderChange(val) {
|
if (cameraParams.value.camera_type !== 'ir') {
|
cameraParams.value.camera_type = val > zoomFactor.value.zoom.min - 1 ? 'zoom' : 'wide'
|
}
|
cameraParamsChangeThrottle()
|
debouncedActiveSlider()
|
}
|
|
function setOtherCamera(item) {
|
editCameraDebounce(() => setCameraType(item))
|
delayedRecepCamera(item.key)
|
}
|
|
function setIrCamera() {
|
editCameraDebounce(irSettingItemClick)
|
delayedRecepCamera('ir')
|
}
|
|
// 修改相机参数
|
async function cameraParamsChange() {
|
const { camera_type, zoom_factor } = cameraParams.value
|
await cameraParamsChangeApi({
|
sn: dockSn.value,
|
...cameraParams.value,
|
zoom_factor: camera_type === 'wide' ? undefined : zoom_factor,
|
})
|
}
|
|
function switchDroneAction() {}
|
|
// 快捷键变焦
|
function quickZoomIn(val) {
|
activeSlider.value = true
|
const { camera_type, zoom_factor } = cameraParams.value
|
const max = camera_type === 'ir' ? zoomFactor.value.ir.max : zoomFactor.value.zoom.max
|
const min = camera_type === 'ir' ? 2 : 1
|
let zoomVal = val > 0 ? Math.min(max, zoom_factor + val) : Math.max(min, zoom_factor + val)
|
zoomVal = zoomVal >= 2 ? zoomVal : 1
|
if (camera_type === 'ir') {
|
const arr = [2, 4, 7, 14, 28]
|
let index = arr.findIndex(item => item >= cameraParams.value.zoom_factor)
|
index = val > 0 ? (arr[index + 1] ? index + 1 : arr.length - 1) : arr[index - 1] ? index - 1 : 0
|
zoomVal = arr[index]
|
} else {
|
cameraParams.value.camera_type = zoomVal >= 2 ? 'zoom' : 'wide'
|
}
|
cameraParams.value.zoom_factor = _.round(zoomVal, 1)
|
debouncedActiveSlider()
|
cameraParamsChange()
|
}
|
|
//红外调色盘设置
|
async function irSettingItemClick(row) {
|
searchlightChange()
|
const payload_index = wsInfo?.value?.device_osd?.data?.host?.cameras?.[0]?.payload_index
|
if (!payload_index) return
|
await setCameraType({ key: 'ir' })
|
if (row?.value === undefined) return
|
const params = {
|
[payload_index]: { thermal_current_palette_style: row.value },
|
}
|
setThermalCurrentPaletteStyle(dockSn.value, workspace_id.value, params)
|
}
|
|
// 修改相机类型
|
async function setCameraType(row) {
|
cameraParams.value.camera_type = row.key
|
const zoomMin = zoomFactor.value?.zoom?.min
|
const irMin = zoomFactor.value?.ir?.min
|
if (row.key === 'wide') {
|
cameraParams.value.zoom_factor = zoomMin ? zoomMin - 1 : 0
|
}
|
if (row.key === 'zoom') {
|
cameraParams.value.zoom_factor = zoomMin ? zoomMin : 5
|
}
|
if (row.key === 'ir') {
|
cameraParams.value.zoom_factor = irMin || 2
|
}
|
await cameraParamsChange()
|
}
|
|
// 画质切换
|
function qualityChange(row) {
|
lineQuality.value = row.id
|
EventBus.emit('CurrentTaskDetails-changeLineQuality')
|
}
|
|
const searchlightMode = inject('searchlightMode')
|
|
function searchlightChange() {
|
isTxtVideo.value = ''
|
isBroadcast.value = false
|
}
|
|
// 设置探照灯模式
|
async function searchlightSet(row) {
|
searchlightMode.value = row.value
|
delayedRecepAuto()
|
// 三代灯走mqtt,一代走接口
|
if (loadDevice.value?.lightIndex === 5) {
|
EventBus.emit('controlPanel-setSearchlight', row.value)
|
} else {
|
const params = { psdk_index: 2, index: 3, value: row.value }
|
await setWidgetSetApi(dockSn.value, params)
|
}
|
if (row.value === 0) {
|
closeSendWsApi(droneSn.value, { type: 'SEARCHLIGHT' })
|
} else {
|
openSendWsApi(droneSn.value, { type: 'SEARCHLIGHT' }, { value: row.value })
|
}
|
}
|
|
const recordFun = _.throttle(() => {
|
if (cameraDisable.value) return
|
const type = isRecording.value ? 'video_stop' : 'video_start'
|
const msg = isRecording.value ? '停止录像' : '开始录像'
|
return photoAndVideoFun(type, msg)
|
}, 4000)
|
|
const takePictures = _.throttle(async () => {
|
if (cameraDisable.value) return
|
await photoAndVideoFun('photo', '拍照成功')
|
}, 2000)
|
|
// 拍照和录像
|
async function photoAndVideoFun(type, msg) {
|
const camera_type = cameraParams.value.camera_type
|
let params = { cameraType: '' }
|
if (camera_type === 'wide' || camera_type === 'zoom') {
|
params.cameraType = droneSn.value === '1581F5BMD22CK0014H2U' ? 'wide' : 'vision'
|
} else {
|
params.cameraType = camera_type
|
}
|
photoAndVideoLoading.value = true
|
return callPhotoAndVideoCmd(dockSn.value, type, params)
|
.then(res => {
|
showToast(msg)
|
})
|
.finally(() => {
|
setTimeout(() => {
|
photoAndVideoLoading.value = false
|
}, 2000)
|
})
|
}
|
|
// 记录喊话是否开始阶段
|
const isRecordShouting = ref(true)
|
const percent = ref(0) // 滚动条滚动百分比
|
const isBroadcast = ref(false)
|
|
// 广播
|
function broadcastFun() {
|
// 是否需要判断有控制权限
|
// 弹出框选择文件
|
isTxtVideo.value = ''
|
isBroadcast.value = true
|
// 获取文件接口
|
// getFileList()
|
}
|
|
// 文字和音频广播
|
const isTxtVideo = ref('')
|
|
function txtVideoClick(type) {
|
if (type === 'soundRecord') {
|
isBroadcast.value = false
|
}
|
isTxtVideo.value = type
|
}
|
|
function closeClick() {
|
isTxtVideo.value = ''
|
isBroadcast.value = false
|
}
|
|
// 滚轮变焦
|
const monitorWheel = _.throttle(e => {
|
if (!hasPayloadControl.value) return
|
e.preventDefault()
|
const delta = e.deltaY || e.detail || e.wheelDelta
|
quickZoomIn(delta > 0 ? -1 : 1)
|
}, 1000)
|
|
// 触发M键
|
let isMKey = ref(false)
|
|
function shoutMKeyClick() {
|
isMKey.value = !isMKey.value
|
isBroadcast.value = isMKey.value ? true : closeClick()
|
isTxtVideo.value = isMKey.value ? 'video' : closeClick()
|
}
|
|
// 触发N键
|
let isNKey = ref(false)
|
|
function shoutNKeyClick(value) {
|
isNKey.value = !isNKey.value
|
isTxtVideo.value = isNKey.value ? 'soundRecord' : closeClick()
|
}
|
|
// 触发B键
|
let isBKey = ref(false)
|
|
function txtShoutBKeyClick(value) {
|
isBKey.value = !isBKey.value
|
isBroadcast.value = isBKey.value ? true : closeClick()
|
isTxtVideo.value = isBKey.value ? 'txt' : closeClick()
|
}
|
|
// let isStartShout = ref(false)
|
// watch(
|
// () => wsInfo.value.dock_osd,
|
// async newVal => {
|
// if (!newVal?.data?.host?.psdk_widget_values?.speaker) return
|
// const objSpeaker = newVal?.data.host.psdk_widget_values.speaker
|
// if (objSpeaker?.system_state !== 0) {
|
// isStartShout.value = true
|
// }
|
// if (isTxtVideo.value === 'videoNKey' && objSpeaker?.system_state === 0 && isStartShout.value) {
|
// isTxtVideo.value = ''
|
// isStartShout.value = false
|
// }
|
// },
|
// {
|
// deep: true,
|
// }
|
// )
|
|
watch(recordingTime,()=>{
|
if (recordingTime.value !== '00:00:00'){
|
recordMode.value = true
|
}
|
})
|
|
onMounted(() => {
|
const videoBoxDom = document.querySelector('#liveVideoBox')
|
videoBoxDom.addEventListener('wheel', monitorWheel)
|
EventBus.on('TaskDetailsLeft-takePictures', takePictures)
|
EventBus.on('TaskDetailsLeft-recordFun', recordFun)
|
EventBus.on('TaskDetailsLeft-quickZoomIn', quickZoomIn)
|
EventBus.on('TaskDetailsLeft-broadcastList', shoutMKeyClick)
|
EventBus.on('TaskDetailsLeft-shoutList', shoutNKeyClick)
|
EventBus.on('TaskDetailsLeft-txtShoutList', txtShoutBKeyClick)
|
})
|
onBeforeUnmount(() => {
|
const videoBoxDom = document.querySelector('#liveVideoBox')
|
videoBoxDom.removeEventListener('wheel', monitorWheel)
|
EventBus.off('TaskDetailsLeft-takePictures', takePictures)
|
EventBus.off('TaskDetailsLeft-recordFun', recordFun)
|
EventBus.off('TaskDetailsLeft-quickZoomIn', quickZoomIn)
|
EventBus.off('TaskDetailsLeft-broadcastList', shoutMKeyClick)
|
EventBus.off('TaskDetailsLeft-shoutList', shoutNKeyClick)
|
EventBus.on('TaskDetailsLeft-txtShoutList', txtShoutBKeyClick)
|
})
|
</script>
|
|
<style scoped lang="scss">
|
.selectShout {
|
position: absolute;
|
left: 50%;
|
top: 50%;
|
transform: translate(-50%, -50%);
|
background: rgba(230, 230, 230, 0.9);
|
//backdrop-filter: blur(5px);
|
font-size: half(13);
|
text-align: center;
|
padding: half(20) half(20) half(10) half(20);
|
border-radius: half(10);
|
z-index: 1;
|
|
.closeDlg {
|
position: absolute;
|
right: half(5);
|
top: half(5);
|
}
|
|
.funBtn {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
gap: 0 half(20);
|
padding-top: half(15);
|
|
> div {
|
width: half(57);
|
height: half(32);
|
text-align: center;
|
line-height: half(32);
|
border-radius: half(4);
|
}
|
}
|
|
.shoutBtn {
|
background: #1d6fe9;
|
color: #ffffff;
|
}
|
|
.broadcast {
|
background: #ffffff;
|
}
|
}
|
|
.consoleRight {
|
position: absolute;
|
width: half(101);
|
height: calc(100% - 17px);
|
top: half(34);
|
right: half(0);
|
background: rgba(22, 22, 22, 0.5);
|
padding: half(30) 0;
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: space-between;
|
z-index: 1;
|
|
.cameraDisable {
|
opacity: 0.3;
|
}
|
|
.recordingTime {
|
}
|
|
> img {
|
width: half(50);
|
height: half(50);
|
}
|
|
.circle {
|
width: half(60);
|
height: half(60);
|
background: transparent;
|
border-radius: 50%;
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
border: 1.5px solid #ffffff;
|
position: relative;
|
|
> .pzhlx {
|
width: half(48);
|
height: half(48);
|
background: #ffffff;
|
border-radius: 50%;
|
}
|
|
.recordingTime {
|
position: absolute;
|
color: #ffffff;
|
left: 50%;
|
bottom: -15px;
|
white-space: nowrap;
|
transform: translate(-50%, 0);
|
}
|
|
.videoRecording {
|
background: red;
|
}
|
|
.pauseRecording {
|
width: half(25);
|
height: half(25);
|
border-radius: 10%;
|
background: red;
|
}
|
}
|
}
|
</style>
|