<template>
|
<div class="consoleLeft">
|
<img class="continueOrPause" v-if="isManualControl" @click="droneContinues" :src="jxrwSvg" alt="" />
|
<img class="continueOrPause" v-else @click="switchDronePaused" :src="ztrwSvg" alt="" />
|
|
<div
|
class="btnFun"
|
v-for="item in list1.filter(i => i.show)"
|
@click="setOtherCamera(item)"
|
:class="{ activeBtn: item.key === cameraParams.camera_type }"
|
>
|
{{ item.name }}
|
</div>
|
<div class="btnFun" v-if="hasIr" :class="{ activeBtn: 'ir' === cameraParams.camera_type }" @click="setIrCamera">红外</div>
|
|
<img class="returnVoyage" v-if="[9, 10, 11, 12].includes(modeCode)" @click="turnBack" :src="qxfhSvg" alt="" />
|
<img class="returnVoyage" v-else @click="turnBack" :src="fhSvg" alt="" />
|
|
<van-slider
|
v-if="cameraParams.camera_type !== 'wide'"
|
v-model="cameraParams.zoom_factor"
|
vertical
|
active-color="#1D6FE9"
|
inactive-color="#ffffff"
|
@change="sliderChange"
|
@update:model-value="activeSlider = true"
|
:reverse="true"
|
:min="2"
|
:max="(cameraParams.camera_type === 'ir' ? zoomFactor.ir.max : zoomFactor.zoom.max) || 100"
|
>
|
<template #button>
|
<div class="custom-button">{{ cameraParams.zoom_factor }}</div>
|
</template>
|
</van-slider>
|
</div>
|
</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 { ElMessage, ElMessageBox } from 'element-plus'
|
import { throttle } from 'lodash'
|
import getBaseConfig from '@/buildConfig/config'
|
import SvgIcon from '@/components/SvgIcon.vue'
|
import dayjs from 'dayjs'
|
import Recorder from 'js-audio-recorder'
|
import hkSvg from '@/appDataSource/inspectionTask/droneConsole/滑块.svg'
|
import sjSvg from '@/appDataSource/inspectionTask/droneConsole/时间.svg'
|
import ztrwSvg from '@/appDataSource/inspectionTask/droneConsole/暂停任务.svg'
|
import jxrwSvg from '@/appDataSource/inspectionTask/droneConsole/继续任务.svg'
|
import fhSvg from '@/appDataSource/inspectionTask/droneConsole/返航.svg'
|
import qxfhSvg from '@/appDataSource/inspectionTask/droneConsole/qxfh.svg'
|
import { showToast } from 'vant'
|
|
const { showConsoleSearchlight, showConsoleMegaphone } = getBaseConfig()
|
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 taskDetails = inject('taskDetails')
|
const modeCode = computed(() => droneStatus?.value?.mode_code)
|
const cameraDisable = computed(() => {
|
return (taskDetails.value.ai_type_str && !isBackDock.value) || photoAndVideoLoading.value
|
})
|
const editCameraDebounce = _.debounce(fn => {
|
fn()
|
}, 1000) //修改相机信息节流版
|
const photoAndVideoLoading = ref(false) //拍照录像接口加载中
|
|
const value = ref(10)
|
|
function onChange(val) {
|
console.log(val)
|
}
|
|
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
|
if (!isRecording.value) {
|
await photoAndVideoFun('photo', '拍照成功')
|
return
|
}
|
await ElMessageBox.confirm('停止录像后才可拍照,点击确认将停止录像?', '提示', {
|
confirmButtonText: '确定',
|
cancelButtonText: '取消',
|
customClass: 'ztzf-message-box-grey',
|
type: 'warning',
|
})
|
await photoAndVideoFun('video_stop', '停止录像')
|
setTimeout(() => {
|
photoAndVideoFun('photo', '拍照成功')
|
}, 2000)
|
}, 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,
|
// }
|
// )
|
|
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">
|
|
.custom-button{
|
width: half(26);
|
color: #fff;
|
font-size: half(10);
|
line-height: half(18);
|
text-align: center;
|
background-color: var(--van-primary-color);
|
border-radius: half(100);
|
}
|
.consoleLeft {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
position: absolute;
|
gap: half(12);
|
top: half(50);
|
left: half(40);
|
z-index: 5000;
|
|
.continueOrPause{
|
margin-bottom: half(7);
|
}
|
|
.returnVoyage{
|
margin-top: half(7);
|
}
|
//
|
//.btnFun{
|
// margin: half(17) 0;
|
//}
|
//.btnFun:nth-child(3) {
|
// /* 第二个 .btnFun 的样式 */
|
// color: red;
|
// margin: half(10) 0 !important;
|
//}
|
|
> img {
|
width: half(33);
|
height: half(33);
|
}
|
|
.btnFun {
|
background: #ffffff;
|
width: half(57);
|
height: half(32);
|
text-align: center;
|
line-height: half(32);
|
border-radius: half(4);
|
font-size: half(13);
|
&.activeBtn{
|
background: #1d6fe9;
|
color: #ffffff;
|
}
|
}
|
|
.van-slider {
|
position: absolute;
|
left: half(100);
|
top: half(0);
|
}
|
}
|
</style>
|