| | |
| | | <script setup> |
| | | import {onMounted, ref, onUnmounted} from "vue"; |
| | | import {getUserType} from '@/utils/auth.js' |
| | | import {getFlowPointList} from '@/api/screen/index' |
| | | import {getFlowVideoData} from '@/api/screen/graphic/index.js' |
| | | import EZUIKit from 'ezuikit-js'; |
| | | import {useRoute} from "vue-router"; |
| | | |
| | | const route = useRoute(); |
| | | |
| | | const menuList = ref([]) |
| | | const userType = ref(getUserType()) |
| | | const searchVal = ref('') |
| | | const playerData = ref([]) |
| | | const hasFullScreen = ref(false) |
| | | let ezKitList = []; //视频组件实例数组 |
| | | let ezKitId = []; //视频盒子id数组 |
| | | let timer = null; |
| | | |
| | | // 全屏操作 |
| | | const handleFullScreen = () => { |
| | | const dom = document.getElementById(ezKitId[0]) |
| | | dom.requestFullscreen() |
| | | } |
| | | |
| | | // 监听全屏状态,是否要开起蒙层 |
| | | document.addEventListener('fullscreenchange', (val) => { |
| | | if (!document.fullscreenElement) { //退出全屏 |
| | | hasFullScreen.value = false; |
| | | } else { //开起全屏 |
| | | hasFullScreen.value = true; |
| | | } |
| | | }); |
| | | |
| | | // 抓拍 |
| | | const handleSnap = (index) => { |
| | | ezKitList[index].capturePicture(`capture-${new Date().getTime()}`, 0.8); // 参数:回调函数,图片格式,质量(0-1) |
| | | } |
| | | |
| | | // 获取监控点菜单 |
| | | const getMoitorList = () => { |
| | | getFlowPointList().then(res => { |
| | | menuList.value = res.data |
| | | }) |
| | | } |
| | | |
| | | // 选择菜单 |
| | | const handleSelect = (id) => { |
| | | ezKitList = [] |
| | | ezKitId = [] |
| | | playerData.value = [] |
| | | clearInterval(timer) |
| | | getPlayerList(id) |
| | | } |
| | | |
| | | // 搜索 |
| | | const handleSearch = () => { |
| | | ezKitList = [] |
| | | ezKitId = [] |
| | | playerData.value = [] |
| | | clearInterval(timer) |
| | | getPlayerList() |
| | | } |
| | | |
| | | // 获取监控点 |
| | | const getPlayerList = async (id) => { |
| | | getFlowVideoData({pointId: id, pointName: searchVal.value}).then(async res => { |
| | | res.data.forEach((item, index) => { |
| | | ezKitId[index] = `ezuikitPlayer${index}` |
| | | }) |
| | | playerData.value = res.data |
| | | await nextTick() |
| | | |
| | | // 渲染视频 |
| | | res.data.forEach((item, index) => { |
| | | ezKitList[index] = new EZUIKit.EZUIKitPlayer({ |
| | | id: ezKitId[index], |
| | | url: item.url, |
| | | accessToken: item.accessToken, |
| | | }) |
| | | }) |
| | | }) |
| | | |
| | | // 挂载定时器, 只获取数据,不重新渲染视频节点 |
| | | timer = setInterval(() => { |
| | | getFlowVideoData({pointId: id, pointName: searchVal.value}).then(res => { |
| | | playerData.value = res.data |
| | | }) |
| | | }, 10000) |
| | | } |
| | | |
| | | |
| | | onMounted(() => { |
| | | getMoitorList() |
| | | getPlayerList(route.params.id || '') |
| | | }) |
| | | |
| | | onUnmounted(() => { |
| | | if (timer) { |
| | | clearInterval(timer) |
| | | } |
| | | }) |
| | | </script> |
| | | |
| | | <template> |
| | | <div> |
| | | 图像监测 |
| | | <div class="graphic"> |
| | | <div class="graphic-menu"> |
| | | <div class="menu-t">监控点列表</div> |
| | | <el-menu class="el-menu" @select="handleSelect"> |
| | | <template v-for="(item, index) in menuList" :key="index+1"> |
| | | <template v-if="item?.childrenList?.length === 0"> |
| | | <el-menu-item :index="item.id">{{ item.pointName }}</el-menu-item> |
| | | </template> |
| | | <template v-else> |
| | | <el-sub-menu :index="item.id"> |
| | | <template #title> |
| | | <span>{{ item.pointName }}</span> |
| | | </template> |
| | | <el-menu-item v-for="(child, cidx) in item.childrenList" :key="cidx" :index="child.id"> |
| | | {{ child.pointName }} |
| | | </el-menu-item> |
| | | </el-sub-menu> |
| | | </template> |
| | | </template> |
| | | </el-menu> |
| | | </div> |
| | | <div class="graphic-monitor"> |
| | | <div class="monitor-tool"> |
| | | <div class="tool-l"> |
| | | <el-input v-model="searchVal" style="width: 20rem" placeholder="请输入监测点名称" clearable/> |
| | | <el-button @click="handleSearch"> |
| | | <el-icon> |
| | | <Search/> |
| | | </el-icon> |
| | | 搜索 |
| | | </el-button> |
| | | <el-button style="margin-left: 0" v-if="userType === '1'"> |
| | | <el-icon> |
| | | <Plus/> |
| | | </el-icon> |
| | | 新增 |
| | | </el-button> |
| | | </div> |
| | | <div class="tool-r" @click="handleFullScreen"> |
| | | <img src="@/assets/images/flow/fullscreen.png"/> |
| | | 全屏 |
| | | </div> |
| | | </div> |
| | | <div class="monitor-box"> |
| | | <div class="monitor-list"> |
| | | <div class="item" v-for="(item, index) in playerData" :key="index"> |
| | | <div class="title">{{ item.pointName }}</div> |
| | | <div class="videoBox" :id="ezKitId[index]"></div> |
| | | <div class="info"> |
| | | <div class="info-list"> |
| | | <div class="info-item"> |
| | | <div class="name">水位:</div> |
| | | <div class="val"><span>{{ item.waterLevel }}</span>m</div> |
| | | </div> |
| | | <div class="info-item"> |
| | | <div class="name">流速:</div> |
| | | <div class="val"><span>{{ item.flowVelocity }}</span>m/s</div> |
| | | </div> |
| | | <div class="info-item"> |
| | | <div class="name">瞬时流量:</div> |
| | | <div class="val"><span>{{ item.newFlow }}</span>m³/h</div> |
| | | </div> |
| | | <div class="info-item"> |
| | | <div class="name">累计流量:</div> |
| | | <div class="val"><span>{{ item.totalFlow }}</span>m³</div> |
| | | </div> |
| | | </div> |
| | | <div class="info-btn"> |
| | | <el-button style="width: 6rem" @click="handleSnap(index)">抓拍</el-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="mask" v-show="hasFullScreen"> |
| | | <div class="mask-item"></div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <style scoped lang="scss"> |
| | | .graphic { |
| | | height: 100%; |
| | | display: flex; |
| | | |
| | | &-menu { |
| | | flex-shrink: 0; |
| | | width: 20%; |
| | | height: 100%; |
| | | padding: 10px 0; |
| | | background: linear-gradient(135deg, #91BDDB 0%, #9EC2DB 99%); |
| | | overflow-y: scroll; |
| | | |
| | | &::-webkit-scrollbar { |
| | | display: none; |
| | | } |
| | | |
| | | .menu-t { |
| | | height: 40px; |
| | | line-height: 40px; |
| | | padding-left: 20px; |
| | | font-size: 26px; |
| | | color: #fff; |
| | | background: url("@/assets/images/flow/monitor-title-bg.png") no-repeat; |
| | | background-size: 100% 100%; |
| | | } |
| | | |
| | | .el-menu { |
| | | background-color: transparent; |
| | | border-right: none; |
| | | |
| | | :deep(.el-menu) { |
| | | background-color: transparent; |
| | | } |
| | | |
| | | :deep(.el-sub-menu__title:hover) { |
| | | background-color: rgba(0, 0, 0, 0.06); |
| | | } |
| | | |
| | | :deep(.el-menu-item.is-active) { |
| | | color: #fff; |
| | | } |
| | | } |
| | | } |
| | | |
| | | &-monitor { |
| | | flex-shrink: 0; |
| | | width: 80%; |
| | | height: 100%; |
| | | |
| | | .monitor-tool { |
| | | width: 100%; |
| | | height: 60px; |
| | | padding: 0 30px; |
| | | background: linear-gradient(90deg, #91BDDB 0%, #DADFE3 100%); |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | |
| | | .tool-l { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 1rem; |
| | | |
| | | .name { |
| | | font-size: 1.1rem; |
| | | } |
| | | } |
| | | |
| | | .tool-r { |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | img { |
| | | width: 25px; |
| | | margin-right: 10px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .monitor-box { |
| | | height: calc(100% - 60px); |
| | | background: linear-gradient(180deg, #91BDDB 0%, rgba(102, 102, 102, 0.5) 100%); |
| | | |
| | | .monitor-list { |
| | | height: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding: 0 30px; |
| | | |
| | | .item { |
| | | width: 48%; |
| | | height: 96%; |
| | | background: rgba(23, 108, 229, 0.3); |
| | | border: 1px solid #176CE5; |
| | | padding: 20px; |
| | | border-radius: 8px; |
| | | |
| | | .title { |
| | | height: 12%; |
| | | text-align: center; |
| | | font-size: 42px; |
| | | color: #fff; |
| | | } |
| | | |
| | | .videoBox { |
| | | width: 100%; |
| | | height: 60%; |
| | | background-color: #000; |
| | | } |
| | | |
| | | .info { |
| | | width: 100%; |
| | | height: 25%; |
| | | display: flex; |
| | | margin-top: 20px; |
| | | |
| | | .info-list { |
| | | width: 80%; |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | color: #fff; |
| | | font-size: 20px; |
| | | |
| | | .info-item { |
| | | width: 50%; |
| | | padding: 8px 0; |
| | | flex-shrink: 0; |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | .name { |
| | | width: 100px; |
| | | } |
| | | |
| | | .val span { |
| | | display: inline-block; |
| | | padding: 0 20px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .info-btn { |
| | | width: 20%; |
| | | padding: 1rem 0; |
| | | display: flex; |
| | | align-items: flex-end; |
| | | |
| | | :deep(.el-button) { |
| | | color: #fff; |
| | | background: rgba(94, 229, 92, 0.6); |
| | | border-radius: 4px 4px 4px 4px; |
| | | border: 1px solid rgba(94, 229, 92, 0.6); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .mask{ |
| | | position: absolute; |
| | | left: 0; |
| | | top: 0; |
| | | z-index: 100; |
| | | width: 100vw; |
| | | height: 100vh; |
| | | .mask-item{ |
| | | position: absolute; |
| | | left: 5%; |
| | | bottom: 10%; |
| | | height: 400px; |
| | | width: 300px; |
| | | background-color: rgba(0, 0, 0, 0.4); |
| | | } |
| | | } |
| | | } |
| | | </style> |