<!-- Description: 场站管理-视频轮询 Author: 李亚光 Date: 2024-09-05 --> <script lang="ts" setup name="StationDeviceVideo"> import { ElMessage } from 'element-plus' import { toTreeList, findPid, findParentPids1 } from '@/utils/structure' import { getDeptTreeList } from '@/api/system/dept' import { getDeptStation } from '@/api/home/station/station' import type { TreeNodeData } from 'element-plus/es/components/tree-v2/src/types' import { getDeviceID, getVideoUrl, getVideoBackUrl } from '@/api/home/station/video' import indexDB from '@/utils/indexDB' import player from '@/components/HKplayer/index.vue' import { indexDBHandler } from '@/utils/sessionData' const loadingTree = ref<boolean>(false) const searchQuery = ref('') const defaultProps = { children: 'children', label: 'name', value: 'id' } const playRef1 = ref() const playRef2 = ref() const playRef3 = ref() const playRef4 = ref() const playerVideo = (devcode: string, playRef) => { if (!devcode) { ElMessage.warning('设备编号为空') return } getDeviceID(devcode).then(res => { const deviceId = res.data if (!deviceId) { ElMessage('设备ID为空,无法获取视频') return } getVideoUrl({ deviceId: deviceId, streamType: '0' }).then(res => { const videoUrl = res.data if (!videoUrl) { ElMessage('视频地址为空,无法播放') return } // 播放视频 unref(playRef).playerFun.createPlayer(videoUrl, 1) }) }).catch(() => { ElMessage.warning('获取设备ID失败') }) } const treeData = ref<any[]>([]) const videoList = ref([]) const expandedKeys = ref<string[]>([]) // 默认展开的节点 const treeRef = ref() // 点击树形结构 const handleNodeClick = (data: any, status: boolean) => { if (!data.DEVCODE && status) { ElMessage.warning('设备编号为空') treeRef.value.setChecked(data.id, false) return } if (data.id.includes('station') && status) { if (videoList.value.filter((item: any) => item.name).length === 4) { ElMessage.warning('最多同时查看4台设备') treeRef.value.setChecked(data.id, false) return } const player = () => { console.log(videoList.value) const index = videoList.value.findIndex((item: any) => !item.name) console.log(index, '需要播放') if (index !== -1) { videoList.value[index] = data } else { videoList.value.push(data) } setTimeout(() => { const plater = { 0: playRef1.value, 1: playRef2.value, 2: playRef3.value, 3: playRef4.value, } playerVideo(data.DEVCODE, index === -1 ? plater[videoList.value.length - 1] : plater[index]) }, 100) } if (videoList.value.filter((item: any) => item.name).length < 4) { player() } else { player() // treeRef.value.setChecked(videoList.value[0].id, false) // unref(playerRef.value[0]).playerFun.stopAllPlay() // videoList.value.shift() // setTimeout(() => { // player() // }) } } else if (data.id.includes('station') && !status) { const index = videoList.value.findIndex((item) => item.id === data.id) videoList.value[index] = {} } } // 查询组织机构 const search = (value: string) => { treeRef.value!.filter(value) } const filterTree = (query: string, node: TreeNodeData) => { return node.name!.includes(query) } // 获取组织列表树数据 const fetchTreeData = () => { loadingTree.value = true const setData = (data1: any[], data2: any[]) => { const data = data2.filter((item: any) => item.DEPTID).map((item: any) => ({ ...item, checked: false, code: '', id: `station-${item.DEVCODE}-${item.LEDGER_CODE}`, // id: `station-${'WXD7507'}-${item.LEDGER_CODE}`, name: `${item.LEDGER_NAME}云台`, open: false, pCodes: '', pid: item.DEPTID, value: '', })) // ...data const all = [...data1.map(item => ({ ...item, disabled: true })).filter((item: any) => item.pid), ...data] expandedKeys.value = [] all.forEach(element => { if (!element.id.includes('station')) { expandedKeys.value.push(element.id) } }) treeData.value = toTreeList(all, '0', true) // 设置默认选中 setTimeout(() => { // data // treeRef.value.setCurrentKey() }) } const fetch = async () => { try { const res = await getDeptTreeList({ deptType: '' }) indexDBHandler('all-dept-list', JSON.stringify(res.data)) const res1 = await getDeptStation({}) indexDBHandler('all-video-list', JSON.stringify(res1.data)) setData(res.data, res1.data) loadingTree.value = false } catch (error) { loadingTree.value = false } } indexDB.getAll().then(allData => { if (allData.filter((item: any) => item.name === 'all-dept-list').length) { const list = JSON.parse(allData.filter((item: any) => item.name === 'all-dept-list')[0].data).filter((item: any) => item.id !== '0') if (allData.filter((item: any) => item.name === 'all-video-list').length) { const list1 = JSON.parse(allData.filter((item: any) => item.name === 'all-video-list')[0].data) setData(list, list1) loadingTree.value = false } else { fetch() } } else { fetch() } }) } // 视频播放失败 const playerError = (info: string) => { ElMessage.error(info) } const treeHeight = ref(0) const calcHeight = () => { const ele = document.getElementsByClassName('el-user-dept-scroll-video')[0] as HTMLElement if (ele) { treeHeight.value = ele.offsetHeight } } onMounted(() => { calcHeight() setTimeout(() => { fetchTreeData() }, 500) }) window.addEventListener('resize', () => { calcHeight() }) onBeforeUnmount(() => { window.addEventListener('resize', () => { }) }) </script> <template> <app-container style="overflow: hidden;"> <div class="container"> <!-- 左侧组织机构 --> <div v-loading="loadingTree" class="left-container"> <div class="dept-div"> <el-card class="box-card" shadow="always"> <template #header> <div class="clearfix"> <!-- <div>监控点列表</div> --> <el-input v-model="searchQuery" @change="search" placeholder="请输入搜索内容" clearable /> </div> </template> <el-scrollbar height="100%" class="user-dept-scroll el-user-dept-scroll-video"> <el-tree-v2 v-if="treeData.length" ref="treeRef" :data="treeData" :props="defaultProps" :height="treeHeight" :check-on-click-node="true" :default-expanded-keys="expandedKeys" @check-change="handleNodeClick" :filter-method="filterTree" empty-text="暂无组织数据" show-checkbox :highlight-current="true" /> </el-scrollbar> </el-card> </div> </div> <!-- 右侧表格 --> <div ref="tableContainer" class="table"> <el-card class="box-card" shadow="always"> <div style="display: flex;flex-wrap: wrap;justify-content: space-around;"> <div class="video mar-bottom"> <span class="title">{{ videoList[0]?.name }}</span> <player v-if="videoList[0]?.name" :playId="`video-player-${0}`" ref="playRef1" @error="playerError" /> <div v-else style="width: 100%;height: 100%;background-color: #000;"></div> </div> <div class="video mar-bottom"> <span class="title">{{ videoList[1]?.name }}</span> <player v-if="videoList[1]?.name" :playId="`video-player-${1}`" ref="playRef2" @error="playerError" /> <div v-else style="width: 100%;height: 100%;background-color: #000;"></div> </div> <div class="video mar-bottom"> <span class="title">{{ videoList[2]?.name }}</span> <player v-if="videoList[2]?.name" :playId="`video-player-${2}`" ref="playRef3" @error="playerError" /> <div v-else style="width: 100%;height: 100%;background-color: #000;"></div> </div> <div class="video mar-bottom"> <span class="title">{{ videoList[3]?.name }}</span> <player v-if="videoList[3]?.name" :playId="`video-player-${3}`" ref="playRef4" @error="playerError" /> <div v-else style="width: 100%;height: 100%;background-color: #000;"></div> </div> <!-- <div v-for="(item, index) in videoList" class="video" :class="`${index <= 2 ? 'mar-bottom' : ''}`"> <span class="title">{{ item.name }}</span> <player :playId="`video-player-${index}`" ref="playerRef" @error="playerError" /> </div> <div v-for="item in 4 - videoList.length" :key="item" class="video" :class="`${item <= 2 ? 'mar-bottom' : ''}`" style="background-color: #000;"></div> --> </div> </el-card> </div> </div> </app-container> </template> <style lang="scss" scoped> // ::v-deep(.el-tree-node__content) { // i,label { // display: none; // } // } // 样式 .container { width: 100%; display: flex; .left-container { width: 22%; } :deep(.el-radio__label) { display: none; } .table { width: 78%; } } .video { width: 49%; height: 40vh; position: relative; .title { position: absolute; top: 5px; right: 5px; text-align: right; color: #fff; z-index: 9; left: 10px; } } .mar-bottom { margin-bottom: 8px; } .dept-div { padding-right: 12px; :deep(.el-card) { height: 85vh; background-color: #fff; } .box-card { width: 100%; .user-dept-scroll { width: 100%; height: calc(100vh - 120px); } } } </style>