<!-- Description: 场站管理-设备控制 Author: 李亚光 Date: 2024-09-05 --> <script lang="ts" setup name="StationDeviceControl"> import dayjs from 'dayjs' import control from './components/control.vue' import { getDeptStation, getStationDeviceData, getDeviceGasData } from '@/api/home/station/station' import type { TreeNodeData } from 'element-plus/es/components/tree-v2/src/types' import { toTreeList } from '@/utils/structure' import { getDeptTreeList } from '@/api/system/dept' import player from '@/components/HKplayer/index.vue' import indexDB from '@/utils/indexDB' import { indexDBHandler } from '@/utils/sessionData' import { ElMessage } from 'element-plus' import { getDeviceID, getVideoUrl, getVideoBackUrl } from '@/api/home/station/video' // import { getDeviceGasData } from '@/api/home/station/station' const loadingTree = ref<boolean>(false) const searchQuery = ref('') const defaultProps = { children: 'children', label: 'name', value: 'id' } const playRef = ref() const timer = ref() const currentDeviceId = ref('') const treeData = ref<any[]>([]) const expandedKeys = ref<string[]>([]) // 默认展开的节点 const treeRef = ref() const playerVideo = (devcode: string) => { if (!devcode) { ElMessage.warning('设备编号为空') return } getDeviceID(devcode).then(res => { const deviceId = res.data if (!deviceId) { ElMessage('设备ID为空,无法获取视频') return } currentDeviceId.value = deviceId getVideoUrl({ deviceId: deviceId, streamType: '0' }).then(res => { const videoUrl = res.data if (!videoUrl) { ElMessage('视频地址为空,无法播放') return } // 播放视频 unref(playRef).playerFun.createPlayer(videoUrl, 1) }).catch(() => { ElMessage.warning('获取设备视频失败') }) }).catch(() => { currentDeviceId.value = '' ElMessage.warning('获取设备ID失败') }) } const resizePage = () => { setTimeout(() => { const resize = new Event('resize') window.dispatchEvent(resize) }, 500) } const loading = ref(false) // 点击树形结构 const handleNodeClick = (data: any, node: any) => { if (data.id.includes('station')) { // 点击的设备(加载视频) // console.log(data, '点击') const deviceCode = data.DEVICECODE // const deviceCode = 'WXD7507' if (deviceCode) { loading.value = true clearInterval(timer.value) timer.value = null playerVideo(deviceCode) // 更新echarts fetchEchartsData({ devCode: deviceCode, begTime: dayjs().subtract(7, 'day').format('YYYY-MM-DD HH:mm:ss'), endTime: dayjs().format('YYYY-MM-DD HH:mm:ss'), }) } else { ElMessage.warning('缺少设备编号') } } } // 查询组织机构 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, index: number) => ({ ...item, checked: false, code: '', // id: `station-${'WXD7507'}-${item.LEDGER_CODE}-${index}`, id: `station-${item.DEVCODE}-${item.LEDGER_CODE}-${index}`, name: `${item.LEDGER_NAME}云台`, open: false, pCodes: '', pid: item.DEPTID, value: '', })) console.log(data) const all = [...data1, ...data] expandedKeys.value = [] all.forEach(element => { if (!element.id.includes('station')) { expandedKeys.value.push(element.id) } }) treeData.value = toTreeList(all, '0', true) } 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 => { loadingTree.value = true 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() loadingTree.value = false } }) } const xAxisData = ref<string[]>([]) const data = ref<any[]>([]) const { proxy } = getCurrentInstance() as any const treeHeight = ref(0) const calcHeight = () => { const ele = document.getElementsByClassName('el-user-dept-scroll-control')[0] as HTMLElement if (ele) { treeHeight.value = ele.offsetHeight } } onMounted(() => { calcHeight() fetchTreeData() }) window.addEventListener('resize', () => { calcHeight() }) onBeforeUnmount(() => { window.addEventListener('resize', () => { }) }) // 获取echarts数据 function fetchEchartsData(obj: any) { getDeviceGasData(obj).then(res => { xAxisData.value = (res.data || []).map((item: any) => item.LOGTIME) data.value = [ { name: '浓度', data: (res.data || []).map((item: any) => item.CONCENTRATION || '0'), symbol: res.data.length > 1 ? 'none' : 'circle', }, ] resizePage() if (!timer.value && xAxisData.value.length) { if (timer.value) { clearInterval(timer.value) timer.value = null } timer.value = setInterval(() => { fetchEchartsData({ ...obj, begTime: dayjs().subtract(7, 'day').format('YYYY-MM-DD HH:mm:ss'), endTime: dayjs().format('YYYY-MM-DD HH:mm:ss') }) }, 1000 * 60 * 20); } loading.value = false }).catch(() => { loading.value = false }) } const currentConcentration = computed(() => { if (data.value[0]?.data.length) { const length = data.value[0]?.data.length return data.value[0]?.data[length - 1] } else { return '' } }) // 视频播放失败 const playerError = (info: string) => { ElMessage.error(info) } const iWidth = ref(window.innerWidth - 180) const iHeight = ref(window.innerHeight * 0.55) const complete = () => { resizePage() } onBeforeUnmount(() => { if (timer.value) { clearInterval(timer.value) timer.value = null } }) </script> <template> <app-container style="overflow: hidden;"> <div class="container"> <!-- 左侧组织机构 --> <div class="left-container"> <div class="dept-div"> <el-card v-loading="loadingTree" 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 id="el-user-dept-scroll-control" height="100%" class="user-dept-scroll el-user-dept-scroll-control"> <!-- <el-tree v-loading="loadingTree" :data="treeData" :props="defaultProps" default-expand-all :expand-on-click-node="false" @node-click="handleNodeClick" /> --> <el-tree-v2 v-if="treeData.length" ref="treeRef" :data="treeData" :props="defaultProps" :height="treeHeight" :check-on-click-node="true" :default-expanded-keys="expandedKeys" @node-click="handleNodeClick" :filter-method="filterTree" empty-text="暂无组织数据" :highlight-current="true" /> </el-scrollbar> </el-card> </div> </div> <!-- 右侧表格 --> <div ref="tableContainer" class="table"> <el-card class="box-card1" shadow="always"> <div class="container1"> <div class="left1"> <!-- <video class="video1" src="" controls autoplay /> --> <div class="video1"> <player playId="video-control" ref="playRef" @error="playerError" @complete="complete" :iWidth="iWidth" :iHeight="iHeight" /> </div> <!-- 图表 --> <div v-show="xAxisData.length"> <span>当前浓度:{{ currentConcentration }}PPM.M</span> <!-- <span style="margin-left: 50px;">报警阈值:50%LEL</span> --> </div> <div class="chart" v-loading="loading"> <line-chart v-show="xAxisData.length" :x-axis-data="xAxisData" :data="data" :gradient="false" :smooth="false" unit="%LEL" :legend="{ itemWidth: 8, itemHeight: 8, type: 'scroll', orient: 'horizontal', icon: 'roundRect', right: '60', top: '10' }" /> <el-empty v-show="!xAxisData.length" description="暂无数据" /> </div> </div> <div class="right1"> <el-card v-if="proxy.hasPerm('/station/control/video')" shadow="always"> <template #header> <div class="clearfix"> <div>云台控制</div> </div> </template> <control :deviceId="currentDeviceId" /> </el-card> </div> </div> </el-card> </div> </div> </app-container> </template> <style lang="scss" scoped> .container1 { width: 100%; display: flex; justify-content: space-between; .left1 { width: 75%; // background-color: antiquewhite; .video1 { width: 100%; height: 55vh; } .chart { width: 100%; height: 23vh; } } .right1 { width: 24%; // background-color: aquamarine; :deep(.el-card) { height: 80vh; background-color: #fff; } :deep(.el-card__body) { padding: 5px; padding-top: 10px; } // .header { // text-align: center; // font-size: 16px; // font-weight: 700; // padding: 10px; // border-bottom: 1px solid #ccc; // } } } // 样式 .container { width: 100%; display: flex; .left-container { width: 22%; } :deep(.el-radio__label) { display: none; } .table { width: 78%; } } .video { width: 49%; height: 40vh; } .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>