Newer
Older
smartwell_front / src / views / home / station / station / components / detailInfoDialog.vue
liyaguang on 27 Apr 13 KB 视频轮询逻辑修改
<!--
  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>