Newer
Older
smartwell_front / src / views / home / station / control / index.vue
liyaguang 4 days ago 12 KB 细节修复
<!--
  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 { getAlarmThresholdByCode } from '@/api/home/device/device'
// 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)
  })
}
const loading = ref(false)
const handlerthreshold = ref([])
// 点击树形结构
const handleNodeClick = (data: any, node: any) => {
  if (data.id.includes('station')) {
    // 点击的设备(加载视频)
    // console.log(data, '点击')
    const deviceCode = data.DEVCODE
    // const deviceCode = 'WXD7507'
    if (deviceCode) {
      loading.value = true
      clearInterval(timer.value)
      timer.value = null
      playerVideo(deviceCode)
      getAlarmThresholdByCode({ devCode: deviceCode }).then(res => {
        handlerthreshold.value = res.data
        // 更新echarts
        xAxisData.value = []
        data.value = []
        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.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)
  }
  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 || []).slice().map((item: any) => item.LOGTIME)
    // 阈值线
    let markLineData = []
    const indexDict = {
      1: '一',
      2: '二',
      3: '三',
      4: '其它',
      5: '其它',
      6: '其它',
      7: '其它',
    } as { [key: string]: any }
    const colorDict = {
      1: '#f56c6c',
      2: '#ee9611',
      3: '#ffd700',
      4: '#8dc6ea',
      5: '#8dc6ea',
      6: '#8dc6ea',
      7: '#8dc6ea',
    } as { [key: string]: any }
    markLineData = handlerthreshold.value.map((item: any) => item.alarmThreshold).map((item: string, index: number) => ({
      name: `${indexDict[index + 1]}级报警阈值:${Number(item)}${'PPM.M'}`,
      yAxis: Number(item),
      lineStyle: {
        color: colorDict[index + 1],
        join: 'round',
        cap: 'round',
      },
      label: {
        show: true,
        formatter: '{b}'
      }
    }))
    console.log(markLineData, 'markLineData')
    data.value = [
      {
        name: '浓度',
        data: (res.data || []).slice().map((item: any) => item.CONCENTRATION || '0'),
        symbol: res.data.length > 1 ? 'none' : 'circle',
        // markLineData,
        markLine: {
          data: markLineData,
          silent: true,
          lineStyle: {
            color: 'red',
            join: 'round',
            cap: 'round',
          },
        }
      },
    ]
    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 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 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="PPM.M" :grid="{
                    top: 50,
                    left: 20,
                    right: 130,
                    bottom: 10,
                    containLabel: true, // 是否包含坐标轴的刻度标签
                  }" :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 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>