<template>
|
<div class="dock-control-panel">
|
<!-- title -->
|
|
<!-- setting -->
|
<DeviceSettingBox :sn="props.sn" :deviceInfo="props.deviceInfo"></DeviceSettingBox>
|
<!-- cmd -->
|
<div class="control-cmd-wrapper">
|
<div class="control-cmd-header">
|
远程调试
|
<el-switch v-model="debugStatus" @change="onDeviceStatusChange" active-text="开" inactive-text="关"
|
class="debug-btn" style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949" />
|
<el-divider />
|
</div>
|
<div class="control-cmd-box">
|
<div v-for="(cmdItem, index) in cmdList" :key="cmdItem.cmdKey" class="control-cmd-item">
|
<div class="control-cmd-item-left">
|
<div class="item-label">{{ cmdItem.label }}</div>
|
<div class="item-status">{{ cmdItem.status }}</div>
|
</div>
|
<div class="control-cmd-item-right">
|
<el-button :disabled="!debugStatus || cmdItem.disabled" :loading="cmdItem.loading" size="small"
|
type="primary" @click="sendControlCmd(cmdItem, index)">
|
{{ cmdItem.operateText }}
|
</el-button>
|
</div>
|
</div>
|
</div>
|
|
<el-divider v-if="deviceInfo">无人机设置</el-divider>
|
<div class="control-cmd-box" v-for="(item, index) in cameras">
|
<div>
|
<el-form-item label="摄像头设置">
|
<el-select @change="cameraSettings($event, item)" v-model="videoValue" placeholder="请选择">
|
<el-option v-for="item in videoType" :key="item.value" :label="item.label" :value="item.value">
|
</el-option>
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="调色盘样式" v-if="videoValue == 'ir'">
|
<el-select @change="changs($event, item)" v-model="valueStyle" placeholder="请选择">
|
<el-option v-for="item in paletteOptions" :key="item.value" :label="item.label" :value="item.value">
|
</el-option>
|
</el-select>
|
</el-form-item>
|
</div>
|
|
<div>
|
<el-form-item label="相机模式">
|
<el-select @change="photoAndVideoCmdSettings($event, item)" v-model="cameraModeValue" placeholder="请选择">
|
<el-option v-for="item in cameraMode" :key="item.value" :label="item.label" :value="item.value">
|
</el-option>
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="照片存储设置" v-if="cameraModeValue == 0">
|
<el-select v-model="photo_storage_settings" collapse-tags @change="photoStorageTypeChang($event, item)"
|
multiple placeholder="请选择">
|
<el-option v-for="item in photoStorageType" :key="item.value" :label="item.label" :value="item.value">
|
</el-option>
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="视频存储设置" v-if="cameraModeValue == 1">
|
<el-select v-model="video_storage_settings" collapse-tags @change="videoStorageTypeChang($event, item)"
|
multiple placeholder="请选择">
|
<el-option v-for="item in photoStorageType" :key="item.value" :label="item.label" :value="item.value">
|
</el-option>
|
</el-select>
|
</el-form-item>
|
</div>
|
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script setup>
|
import { ElMessage } from 'element-plus';
|
import { EBizCode, ELocalStorageKey, ERouterName } from '@/types'
|
import { defineProps, ref, watch, reactive } from 'vue'
|
import { cmdList as baseCmdList } from '@/types/device-cmd'
|
import { useDockControl } from './use-dock-control'
|
import { EDockModeCode } from '@/types/device'
|
import { updateDeviceSettingFormModelByOsd, updateDeviceSettingInfoByOsd } from '@/utils/device-setting';
|
import { initDeviceSetting, initDeviceSettingFormModel } from '@/types/device-setting';
|
import { updateDeviceCmdInfoByOsd, updateDeviceCmdInfoByExecuteInfo } from '@/utils/device-cmd'
|
import { setThermalCurrentPaletteStyle, setPhotoStorageSet, setVideoStorageSet, getLiveStatus, setStreamsSwitch, photoAndVideoCmd } from '@/api/device-setting'
|
import DeviceSettingBox from './DeviceSettingBox.vue'
|
import Store from '@/store'
|
import { useConnectWebSocket } from '@/utils/websocket/connect-websocket';
|
import { getWebsocketUrl } from '@/utils/websocket/config';
|
import EventBus from '@/utils/eventBus';
|
import { cloneDeep } from 'lodash';
|
|
const valueStyle = ref(0)
|
const cameraModeValue = ref(0)
|
const videoValue = ref("zoom")
|
const photo_storage_settings = ref([])
|
const video_storage_settings = ref([])
|
|
|
|
let deviceSetting = ref(cloneDeep(initDeviceSetting));
|
const deviceSettingFormModelFromOsd = ref(cloneDeep(initDeviceSettingFormModel));
|
|
provide('deviceSetting', deviceSetting)
|
provide('deviceSettingFormModelFromOsd', deviceSettingFormModelFromOsd)
|
|
// 定义一个数据videoList
|
const videoList = reactive([])
|
// 摄像头信息
|
let cameras = reactive([])
|
// let cameras = reactive([
|
// {
|
// camera_mode: 0,
|
// liveview_world_region: {
|
// bottom: 0.5515424609184265,
|
// left: 0.42740535736083984,
|
// right: 0.5581043362617493,
|
// top: 0.42277535796165466
|
// },
|
// payload_index: "81-0-0",
|
// photo_state: 0,
|
// record_time: 0,
|
// recording_state: 0,
|
// remain_photo_num: 3931,
|
// remain_record_duration: 0,
|
// zoom_factor: 6.9999943,
|
// ir_zoom_factor: 2,
|
// photo_storage_settings: [
|
// "vision",
|
// "ir"
|
// ],
|
// video_storage_settings: [
|
// "vision"
|
// ]
|
// }
|
// ])
|
|
// 无人机信息
|
let deviceInfo = ref()
|
|
// camera_mode {"0":"拍照","1":"录像","2":"智能低光","3":"全景拍照","-1":"不支持的模式"}
|
const cameraMode = [
|
{ label: '拍照', value: 0 },
|
{ label: '录像', value: 1 },
|
{ label: '智能低光', value: 2 },
|
{ label: '全景拍照', value: 3 },
|
// { label: '不支持的模式', value: -1 },
|
]
|
|
// 调色盘选项数据
|
const paletteOptions = [
|
{ 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 },
|
]
|
// 视频类型 ZOOM("zoom"), WIDE("wide"), THERMAL("thermal"), NORMAL("normal"), IR("ir");
|
const videoType = [
|
{ label: '变焦', value: 'zoom' },
|
{ label: '广角', value: 'wide' },
|
// { label: '热红外', value: 'thermal' },
|
// { label: '正常', value: 'normal' },
|
{ label: '红外', value: 'ir' },
|
]
|
// 拍照存储类型{current, wide, zoom, ir},可多选
|
const photoStorageType = [
|
{ label: '当前', value: 'current' },
|
{ label: '广角', value: 'wide' },
|
{ label: '变焦', value: 'zoom' },
|
{ label: '可见光', value: 'vision' },
|
{ label: '红外', value: 'ir' },
|
]
|
|
const props = defineProps(['sn', 'deviceInfo'])
|
const initCmdList = baseCmdList.map(cmdItem => Object.assign({}, cmdItem))
|
const cmdList = ref(initCmdList)
|
// dock 控制指令
|
const debugStatus = ref(props.deviceInfo.mode_code == EDockModeCode.Remote_Debugging)
|
|
// 根据机场指令执行状态更新信息
|
watch(
|
() => Store.getters.devicesCmdExecuteInfo,
|
devicesCmdExecuteInfo => {
|
// console.log('设备指令执行状态变化', devicesCmdExecuteInfo)
|
if (props.sn && devicesCmdExecuteInfo[props.sn]) {
|
updateDeviceCmdInfoByExecuteInfo(cmdList.value, devicesCmdExecuteInfo[props.sn])
|
}
|
},
|
{
|
immediate: true,
|
deep: true,
|
}
|
)
|
watch(
|
() => Store.state.device.videoSurveillance,
|
newObj => {
|
// console.log('视频类型监听中', newObj)
|
if (newObj && newObj.live_status && newObj.live_status.length) {
|
let arr = newObj.live_status || []
|
if (videoList.length == arr.length) {
|
return
|
}
|
arr.forEach(element => {
|
let video_id = element.video_id
|
element.payIndex = video_id.split('/')[1].split('-')[1]
|
if (props.deviceInfo.child_sn == video_id.split('/')[0]) {
|
if (element.video_type == 'normal' || element.video_type == 'thermal') {
|
videoValue.value = 'wide'
|
} else {
|
videoValue.value = element.video_type
|
}
|
}
|
})
|
videoList.push(...arr) // 添加新元素
|
}
|
},
|
{
|
immediate: true,
|
deep: true,
|
}
|
)
|
|
// 根据设备osd信息更新信息
|
watch(
|
() => Store.getters.deviceState,
|
value => {
|
// console.log(value, '测试')
|
// console.log('设备状态变化', value.deviceInfo[props.deviceInfo.child_sn])
|
if (props.sn && (value.currentSn === props.deviceInfo.child_sn || value.currentSn === props.deviceInfo.device_sn)) {
|
debugStatus.value = value.dockInfo[props.deviceInfo.device_sn]?.basic_osd?.mode_code === EDockModeCode.Remote_Debugging
|
const devices = {}
|
devices['device'] = value.deviceInfo[props.deviceInfo.child_sn]
|
devices['dock'] = value.dockInfo[props.deviceInfo.device_sn]
|
devices['gateway'] = value.gatewayInfo
|
let cameraList = value.deviceInfo[props.deviceInfo.child_sn]?.cameras || []
|
cameras = cameraList
|
// console.log('设备osd.cameras信息变化', cameras)
|
// 判断cameras列表长度是否为0,如果为0,则不执行后续操作
|
if (cameras.length > 0) {
|
cameraModeValue.value = cameras[0].camera_mode
|
photo_storage_settings.value = cameras[0]?.photo_storage_settings ?? [];
|
video_storage_settings.value = cameras[0]?.video_storage_settings ?? [];
|
}
|
deviceInfo = ref(value.deviceInfo[props.deviceInfo.child_sn])
|
updateDeviceCmdInfoByOsd(cmdList.value, devices)
|
// by cpz
|
updateDeviceSettingInfoByOsd(deviceSetting, value.deviceInfo[props.deviceInfo.child_sn]);
|
updateDeviceSettingFormModelByOsd(deviceSettingFormModelFromOsd, value.deviceInfo[props.deviceInfo.child_sn])
|
}
|
},
|
{
|
immediate: true,
|
deep: true,
|
}
|
)
|
onMounted(() => {
|
const webSorketUrl = getWebsocketUrl() + '&workspace-id=' + props.deviceInfo.workspace_id
|
// 监听ws 消息
|
useConnectWebSocket(messageHandler, webSorketUrl)
|
getLiveStatuss()
|
});
|
|
async function getLiveStatuss() {
|
let result = await getLiveStatus(props.sn)
|
result.data.data.live_status.forEach(item => {
|
if (props.deviceInfo.child_sn == item.video_id.split('/')[0]) {
|
if (item.video_type == 'normal' || item.video_type == 'thermal') {
|
videoValue.value = 'wide'
|
} else {
|
videoValue.value = item.video_type
|
}
|
}
|
})
|
}
|
|
|
// 远程控制开关
|
async function onDeviceStatusChange(status) {
|
let result = false
|
if (status) {
|
result = await dockDebugOnOff(props.sn, true)
|
} else {
|
result = await dockDebugOnOff(props.sn, false)
|
}
|
|
if (!result) {
|
if (status) {
|
debugStatus.value = false
|
} else {
|
debugStatus.value = true
|
}
|
}
|
}
|
|
const { sendDockControlCmd, dockDebugOnOff } = useDockControl()
|
|
async function sendControlCmd(cmdItem, index) {
|
const params = {
|
sn: props.sn,
|
cmd: cmdItem.cmdKey,
|
action: cmdItem.action,
|
}
|
const success = await sendDockControlCmd(params, true)
|
}
|
|
// webSocket 监听
|
const messageHandler = async payload => {
|
payload = JSON.parse(payload)
|
if (!payload) {
|
return
|
}
|
switch (payload.biz_code) {
|
case EBizCode.GatewayOsd: {
|
Store.commit('SET_GATEWAY_INFO', payload.data)
|
break
|
}
|
// 飞行器
|
case EBizCode.DeviceOsd: {
|
Store.commit('SET_DEVICE_INFO', payload.data)
|
break
|
}
|
// 机场
|
case EBizCode.DockOsd: {
|
Store.commit('SET_DOCK_INFO', payload.data)
|
break
|
}
|
case EBizCode.MapElementCreate: {
|
Store.commit('SET_MAP_ELEMENT_CREATE', payload.data)
|
break
|
}
|
case EBizCode.MapElementUpdate: {
|
Store.commit('SET_MAP_ELEMENT_UPDATE', payload.data)
|
break
|
}
|
case EBizCode.MapElementDelete: {
|
Store.commit('SET_MAP_ELEMENT_DELETE', payload.data)
|
break
|
}
|
case EBizCode.DeviceOnline: {
|
Store.commit('SET_DEVICE_ONLINE', payload.data)
|
break
|
}
|
case EBizCode.DeviceOffline: {
|
Store.commit('SET_DEVICE_OFFLINE', payload.data)
|
break
|
}
|
case EBizCode.FlightTaskProgress:
|
case EBizCode.FlightTaskMediaProgress:
|
case EBizCode.FlightTaskMediaHighestPriority: {
|
EventBus.emit('flightTaskWs', payload)
|
break
|
}
|
case EBizCode.DeviceHms: {
|
Store.commit('SET_DEVICE_HMS_INFO', payload.data)
|
break
|
}
|
case EBizCode.VideoSurveillance: {
|
if (payload.data.live_status && payload.data.live_status.length) {
|
Store.commit('SAVE_VIDEO_SURVEILLANCE_INFO', payload.data)
|
}
|
break
|
}
|
case EBizCode.DeviceReboot:
|
case EBizCode.DroneOpen:
|
case EBizCode.DroneClose:
|
case EBizCode.CoverOpen:
|
case EBizCode.CoverClose:
|
case EBizCode.PutterOpen:
|
case EBizCode.PutterClose:
|
case EBizCode.ChargeOpen:
|
case EBizCode.ChargeClose:
|
case EBizCode.DeviceFormat:
|
case EBizCode.DroneFormat: {
|
Store.commit('SET_DEVICES_CMD_EXECUTE_INFO', {
|
biz_code: payload.biz_code,
|
timestamp: payload.timestamp,
|
...payload.data,
|
})
|
break
|
}
|
case EBizCode.ControlSourceChange:
|
case EBizCode.FlyToPointProgress:
|
case EBizCode.TakeoffToPointProgress:
|
case EBizCode.JoystickInvalidNotify:
|
case EBizCode.DrcStatusNotify: {
|
EventBus.emit('droneControlWs', payload)
|
break
|
}
|
default:
|
break
|
}
|
}
|
|
|
// 添加 changs 方法
|
async function changs(value, item) {
|
const payload = {
|
[item.payload_index]: {
|
thermal_current_palette_style: value
|
}
|
}
|
console.log('payload', payload)
|
let data = await setThermalCurrentPaletteStyle(props.sn, props.deviceInfo.workspace_id, payload)
|
if (data.data.code === 0) {
|
ElMessage.success('修改成功');
|
}
|
}
|
// 摄像头设置
|
async function cameraSettings(value, item) {
|
const payload = {
|
// 1581F6Q8D245U00G57GJ/81-0-0/normal-0
|
video_id: props.deviceInfo.child_sn + '/' + item.payload_index + '/normal-0',
|
video_type: value
|
}
|
let data = await setStreamsSwitch(payload)
|
if (data.data.code === 0) {
|
ElMessage.success('修改成功');
|
}
|
}
|
// 相机模式设置
|
async function photoAndVideoCmdSettings(value, item) {
|
// photo 0 video_start 1 video_stop
|
item.camera_mode = value
|
let data = await photoAndVideoCmd(props.deviceInfo.child_sn, value)
|
if (data.data.code == 0) {
|
ElMessage.success('修改成功');
|
}
|
}
|
// 照片存储设置
|
async function photoStorageTypeChang(value, item) {
|
// value 不能为空
|
if (!value) {
|
ElMessage.error('请选择存储方式');
|
return;
|
}
|
const payload = {
|
payload_index: item.payload_index,
|
photo_storage_settings: value
|
}
|
item.photo_storage_settings = value
|
let data = await setPhotoStorageSet(props.sn, payload)
|
if (data.data.code == 0) {
|
ElMessage.success('修改成功');
|
}
|
}
|
// 视频存储设置
|
async function videoStorageTypeChang(value, item) {
|
if (!value) {
|
ElMessage.error('请选择存储方式');
|
return;
|
}
|
const payload = {
|
payload_index: item.payload_index,
|
video_storage_settings: value
|
}
|
item.video_storage_settings = value
|
let data = await setVideoStorageSet(props.sn, payload)
|
if (data.data.code == 0) {
|
ElMessage.success('修改成功');
|
}
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
.dock-control-panel {
|
position: relative;
|
width: 100%;
|
height: 100%;
|
padding: 0 !important;
|
color: #000;
|
border-radius: 2px;
|
|
.control-cmd-wrapper {
|
font-size: 14px;
|
.control-cmd-header {
|
font-size: 14px;
|
//font-weight: 600;
|
padding: 10px 10px 0px;
|
|
.debug-btn {
|
margin-left: 10px;
|
// border: 1px solid #585858;
|
}
|
}
|
|
.control-cmd-box {
|
display: flex;
|
flex-wrap: wrap;
|
justify-content: space-between;
|
padding: 4px 15px;
|
|
.control-cmd-item {
|
width: 320px;
|
height: 58px;
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
border: 1px solid #666;
|
margin: 8px 0;
|
padding: 0 8px;
|
border-radius: 2px;
|
|
.control-cmd-item-left {
|
display: flex;
|
flex-direction: column;
|
|
.item-label {
|
//font-weight: 700;
|
}
|
.item-status {
|
color: #8d8b8b;
|
}
|
}
|
}
|
}
|
}
|
|
::v-deep {
|
.el-form {
|
display: flex;
|
flex-wrap: wrap;
|
justify-content: space-between;
|
padding: 4px 15px;
|
}
|
|
.el-form-item {
|
width: 320px;
|
height: 58px;
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
border: 1px solid #666;
|
margin: 8px 0;
|
padding: 0 8px;
|
border-radius: 2px;
|
}
|
|
.el-select__wrapper {
|
width: 160px;
|
}
|
}
|
}
|
</style>
|