<!-- Description: 场站管理-信息窗体 Author: 李亚光 Date: 2024-07-18 --> <script lang="ts" setup name="infoWindow"> import { getWellDetail } from '@/api/home/well/well' import player from '@/components/HKplayer/index.vue' import { ElMessage } from 'element-plus' import { getDeviceById } from '@/api/home/well/well' import { getDeviceID, getVideoUrl, getVideoBackUrl } from '@/api/home/station/video' import dayjs from 'dayjs' const dialogFormVisible = ref(false) const $route = useRoute() const overlay = ref() const infoWindow = ref() // 基本数据 const baseInfo = ref({ ledgerCode: '', // 场站编号 ledgerName: '', // 场站名称 lngGaode: '', latGaode: '', tagNumber: '', }) const resizePage = () => { setTimeout(() => { const resize = new Event('resize') window.dispatchEvent(resize) }) } const deviceList = ref<any[]>([]) const currentVideo = ref('') const videoType = ref('real') // 视频类型 实时real和回放playback // 详细信息 const detailInfo = ref<{ [key: string]: string }>({}) // 描述列表数据 const descriptionsList = ref([ { text: '管理单位', value: 'deptName', align: 'center', }, { text: '场站状态', value: 'onStateName', align: 'center', }, { text: '详细位置', value: 'position', align: 'center', }, { text: '负责人', value: 'personName', align: 'center', }, { text: '标签', value: 'marker', align: 'center', }, { text: '监控状态', value: 'monitorStateName', align: 'center', }, { text: '', value: '', align: 'center', }, // { // text: '当前浓度', // value: '', // align: 'center', // }, // { // text: '场站名称', // value: 'ledgerName', // align: 'center', // }, // { // text: '场站位号', // value: 'tagNumber', // align: 'center', // }, // { // text: '产权单位', // value: 'propertyOwner', // align: 'center', // }, // { // text: '联系人', // value: 'propertyPerson', // align: 'center', // }, // { // text: '联系方式', // value: 'propertyPhone', // align: 'center', // }, // { // text: '管理方式', // value: 'manageTypeName', // align: 'center', // }, // { // text: '所在区域', // value: 'area', // align: 'center', // }, // { // text: '经度', // value: 'lngGaode', // align: 'center', // }, // { // text: '纬度', // value: 'latGaode', // align: 'center', // }, ]) const currentDeviceId = ref('') const playerVideo = (devcode: string) => { if (!devcode) { ElMessage.warning('设备编号为空') return } // unref(playRef).playerFun.createPlayer('ws://172.17.240.101:559/media?version=0.1&ciphersuites=0&sessionID', 1) 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 playRef = ref() const loading = ref(true) const initDialog = (e: any) => { // console.log(e, '信息窗体接收的数据') overlay.value = e.overlay infoWindow.value = e.infoWindow baseInfo.value = e.info.row dialogFormVisible.value = true if (e.map) { e.map.setZoom(17) } resizePage() // 获取详细信息 loading.value = true getWellDetail(e.info.id).then((res) => { detailInfo.value = res.data loading.value = false if (res.data.personName && res.data.telephone) { detailInfo.value.personName = `${res.data.personName}(${res.data.telephone})` } // 处理监控状态 if (detailInfo.value.monitorStateName === '离线' && !$route.path.includes('station')) { detailInfo.value.monitorStateName = '故障(离线)' } getDeviceById(e.info.id).then(res => { deviceList.value = res.data.map((item: any) => ({ name: `${item.devcode}`, devcode: item.devcode, })) if (deviceList.value.length) { currentVideo.value = deviceList.value[0].name // 默认播放第一路视频 (先获取设备id再根据id拿视频) playerVideo(deviceList.value[0].devcode) } }) }).catch(() => { loading.value = false }) } // 关闭 const close = () => { dialogFormVisible.value = false } // 详情 const $router = useRouter() const goDetail = () => { $router.push({ path: '/station/detail', query: { id: detailInfo.value.id, }, }) close() } // 视频播放失败 const playerError = (info: string) => { ElMessage.error(info) } const changeVideo = (item: any) => { currentVideo.value = item.name // 切换云台播放 unref(playRef).playerFun.stopAllPlay() videoType.value = 'real' playerVideo(item.devcode) } defineExpose({ initDialog, close }) const handler = (type: string) => { // if (videoType.value === type) { // return // } if (!currentDeviceId.value) { ElMessage.warning('设备ID为空') return } videoType.value = type if (type === 'real') { unref(playRef).playerFun.stopAllPlay() getVideoUrl({ deviceId: currentDeviceId.value, streamType: '0' }).then(res => { const videoUrl = res.data if (!videoUrl) { ElMessage('视频地址为空,无法播放') return } // 播放视频 unref(playRef).playerFun.createPlayer(videoUrl, 1) }).catch(() => { ElMessage.warning('获取设备视频失败') }) } else if (type === 'playback') { unref(playRef).playerFun.stopAllPlay() const startTime = dayjs().subtract(0.5, 'hour').format('YYYY-MM-DD HH:mm:ss') const endTime = dayjs().format('YYYY-MM-DD HH:mm:ss') getVideoBackUrl({ deviceId: currentDeviceId.value, beginDate: startTime, endDate: endTime }).then(res => { if (!res.data) { ElMessage.warning('回放地址为空') return } // 回放时间格式要转为 format('YYYY-MM-DDTHH:mm:ss.SSSZ') unref(playRef).playerFun.replayFun({ url: res.data, startTime: dayjs(startTime).format('YYYY-MM-DDTHH:mm:ss.SSSZ'), endTime: dayjs(endTime).format('YYYY-MM-DDTHH:mm:ss.SSSZ') }) }).catch(() => { ElMessage.warning('获取回放地址失败') }) } } // const url = ref('') // const testVideo = () => { // unref(playRef).playerFun.createPlayer(url.value, 1) // } </script> <template> <div class="dialog"> <el-dialog v-model="dialogFormVisible" append-to-body class="dialog" custom-class="dialog" :show-close="false" width="950px" style="background-color: transparent;box-shadow: none;"> <div v-show="dialogFormVisible" class="container clearfix" @mouseleave="() => { }"> <div class="header"> <div style="display: flex;align-items: center;"> <el-tooltip class="box-item" effect="dark" :content="`${baseInfo.tagNumber} | ${baseInfo.ledgerName}`" placement="top"> <span class="title">{{ baseInfo.tagNumber }} | {{ baseInfo.ledgerName }}</span> </el-tooltip> <el-button size="small" style="margin-left: 10px;" @click="goDetail"> 详情 </el-button> </div> <span class="close1" @click="close">×</span> </div> <!-- 云台视频 --> <div v-if="deviceList.length" class="video"> <div class="video-menu"> <div v-for="item in deviceList" :key="item" class="menu-item" :class="item.name === currentVideo ? 'active' : ''" @click="changeVideo(item)"> {{ item.name }} </div> </div> <div class="video-container"> <div class="video-control"> <div style="width: 50%;display: flex;justify-content: center;"> <el-button :type="videoType === 'real' ? 'primary' : ''" round size="small" @click="handler('real')"> 预览 </el-button> <el-button :type="videoType === 'playback' ? 'primary' : ''" round size="small" @click="handler('playback')"> 回放 </el-button> <el-button round size="small"> 报警 </el-button> <!-- <el-button round size="small" @click="testVideo" > 测试播放 </el-button> <el-input v-model="url" style="width: 1000px;height: 30px;" clearable></el-input> --> </div> </div> <div class="video-player" style="width: 710px;height: 250px;"> <!-- <video src="" autoplay muted controls /> --> <player v-if="dialogFormVisible" ref="playRef" @error="playerError" :iWidth="710" :iHeight="250" /> </div> </div> </div> <div class="body"> <div class="descriptions" v-loading="loading"> <div v-for="(item, index) in descriptionsList" :key="item.text" :style="{ width: index % 2 === 0 ? '65%' : '32%' }" class="descriptions-item"> <div :class="index % 2 === 0 ? 'label' : 'label1'"> {{ item.text }} </div> <div v-if="item.text !== '当前浓度'" :class="index % 2 === 0 ? 'value' : 'value1'" :title="detailInfo[item.value] || ''"> {{ detailInfo[item.value] || '' }} </div> <!-- <div v-if="item.text === '当前浓度'" :class="index % 2 === 0 ? 'value' : 'value1'"> <span>0%LEL</span> <el-button size="small" style="margin-left: 10px;"> 更多 </el-button> </div> --> </div> </div> </div> </div> </el-dialog> </div> </template> <style lang="scss" scoped> .container { width: 100%; background: #fff; position: relative; border-radius: 8px; border: 1px solid #e4e7ed; overflow: hidden; box-shadow: 0 0 12px rgb(0 0 0 / 12%); .header { float: right; background-color: #0d76d4; width: 100%; display: flex; justify-content: space-between; padding: 8px 10px; align-items: center; color: #fff; .title { font-size: 16px; font-weight: 700; display: inline-block; width: 90%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } .close1 { font-size: 22px; font-weight: 700; text-align: right; padding-right: 10px; &:hover { cursor: pointer; color: #ccc; } } } .video { width: 100%; display: flex; padding: 10px; height: 290px; margin-bottom: 8px; .video-menu { width: 20%; height: 250px; padding-top: 30px; box-sizing: border-box; .menu-item { font-size: 18px; height: 24px; text-align: left; line-height: 24px; margin: 5px 0; &:hover { cursor: pointer; } } .active { background-color: rgba($color: #9ebfff, $alpha: 50%); } } .video-container { width: 79%; height: 250px; .video-control { display: flex; justify-content: center; } } .video-player { margin-top: 10px; video { width: 100%; height: 250px; } } } .body { width: 100%; padding-left: 15px; .descriptions { width: 100%; display: flex; flex-wrap: wrap; box-sizing: border-box; padding: 6px 0; padding-left: 10px; .descriptions-item { width: 48%; margin: 4px 5px; box-sizing: border-box; display: flex; padding: 0 3px; .label-no { width: 28% !important; } .label { width: 17%; box-sizing: border-box; padding: 0 1px; font-size: 15px; text-align: justify; text-align-last: justify; } .label1 { width: 40%; box-sizing: border-box; padding: 0 1px; font-size: 15px; text-align: justify; text-align-last: justify; } .value { padding-left: 5px; width: 71%; box-sizing: border-box; white-space: nowrap; font-size: 15px; color: #a39f9f; /* 确保文本在一行内显示 */ overflow: hidden; /* 超出容器部分隐藏 */ text-overflow: ellipsis; /* 文字溢出显示省略号 */ } .value1 { padding-left: 5px; width: 50%; box-sizing: border-box; white-space: nowrap; font-size: 15px; color: #a39f9f; /* 确保文本在一行内显示 */ overflow: hidden; /* 超出容器部分隐藏 */ text-overflow: ellipsis; /* 文字溢出显示省略号 */ } } } } } .dialog { background-color: transparent !important; } .dialog { ::v-deep(.el-dialog) { background-color: transparent !important; } } </style>