Newer
Older
laserPTZFrontV2.0 / src / views / map / map.vue
wangxitong on 26 Sep 10 KB 流媒体
<script lang="ts" setup name="Map">
import type { Ref } from 'vue'
import { getCurrentInstance, ref } from 'vue'
import dayjs from 'dayjs'
import L from 'leaflet'
import devJson from 'public/config/dev.json'
import type { PointListInfo } from '../device/dev-interface'
// import aMap from '@/components/aMap/aMap.vue'
import { getDataHisList, getDevInfo, getDevMap } from '@/api/ptz/dev'
import useWebsocketStore from '@/store/modules/websocket'
import type { lineDataI } from '@/components/Echart/echart-interface'
import type { DateReturn, TypeReturn } from '@/views/statistics/statistics-interface'
import 'leaflet/dist/leaflet.css'
import HKVideo from '@/components/HKVideo/index.vue'
import 'leaflet.label'
import { getIsOffLine } from '@/utils/auth'

const { proxy } = getCurrentInstance()
const websocket = useWebsocketStore()
const video: any = ref()
const toParentsMap = ref({
  lat: '',
  lng: '',
})

const map = ref(null)
const baseLayer = ref([])
const keyword = ref('')
const refreshMarker = ref(false)
const isRightShow = ref(false)
const pointList: Ref<PointListInfo[]> = ref([])
const currentName = ref('')
const src = ref('')
const monitorId = ref('')
const deviceIp = ref('')
const device = ref({})
const devCH4Loading = ref(false)
const devCH4XData: Ref<string[]> = ref([])
const devCH4Data: Ref<lineDataI[]> = ref([])
const devCH4YDataMax = ref()
const webRtcServer = ref(null)
const amap = ref() // 组件

function search() {
  refreshMarker.value = false
  map.value.eachLayer((layer) => {
    if (getIsOffLine() === 'true') {
      if (layer !== baseLayer.value[0]) {
        layer.remove()
      }
    }
    else if (getIsOffLine() === 'false') {
      if (layer !== baseLayer.value[0] && layer !== baseLayer.value[1]) {
        layer.remove()
      }
    }
  })
  getDevMap(keyword.value).then((res) => {
    res.data.forEach((item: any) => {
      let icon
      let color
      switch (item.deviceStatus) {
        case '0':
          icon = './marker/gray.png'
          color = 'gray'
          break
        case '1':
          icon = './marker/green.png'
          color = 'green'
          break
        case '2':
          icon = './marker/red.png'
          color = 'red'
          break
      }
      const Icon = L.icon({
        iconUrl: icon,
        iconSize: [40, 40],
      })
      const message
        = `<div style="padding: 10px;width: 230px;font-size: 16px;">
              <div style="font-weight: bold;margin-bottom: 10px">${item.monitorName || ''}</div>
              <div><span>所在场站:</span>${item.stationName || ''}</div>
              <div style="color: ` + `${color}` + `"><span style="color: black">设备状态:</span>${item.deviceStatusName || ''}</div>
              <div style="margin-bottom: 10px; word-break: break-all; "><span>详细位置:</span>${item.location || ''}</div>
              <div class="btnDetail" style="color: #3776ff;margin-left: 170px;cursor: pointer;font-size: 15px" id="btnDetail_${item.monitorId || ''}">详情</div>
           </div>`
      const popup = L.popup().setContent(message)
      // const marker = L.marker([item.latitude, item.longitude], { icon: Icon, slug: item }).addTo(map.value).bindPopup(popup)
      const divIcon = L.divIcon({
        html: `<div style="display: flex">
                <image src="${icon}" width="35" height="35">
                <span style="background: white;border-radius: 2px;height: 21px;padding: 0 2px;border: solid 1px #2121d7;width: max-content;position: absolute;top: 8px;left: 36px;">${item.monitorName || ''}</span>
              </div>`,
        className: 'my-div-icon',
        iconSize: [50, 50],
      })

      const marker = L.marker([item.latitude, item.longitude], { icon: divIcon }).addTo(map.value).bindPopup(popup)
      marker.on('click', (e) => {
        document.getElementById(`btnDetail_${item.monitorId}`).onclick = function () {
          clickRecall(item)
        }
      })
    })
    refreshMarker.value = true
    // 定位
    if (res.data.length > 0) {
      map.value.setView({ lat: res.data[0].latitude, lng: res.data[0].longitude })
    }
  })
}

onBeforeMount(() => {
  toParentsMap.value.lat = proxy.$position.lat
  toParentsMap.value.lng = proxy.$position.lng
})

onMounted(() => {
  map.value = L.map('map', {
    minZoom: Number(proxy.$zoom.minZoom),
    maxZoom: Number(proxy.$zoom.maxZoom),
    center: [toParentsMap.value.lat, toParentsMap.value.lng],
    zoom: Number(proxy.$zoom.zoom),
    zoomControl: false,
    attributionControl: false,
    crs: L.CRS.EPSG3857,
  })
  const str = getIsOffLine() === 'true' ? '/static/tiles/{z}/{x}/{y}.png' : 'https://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=216ee92889e17ab1b083fae665d522b8'
  baseLayer.value.push(L.tileLayer(str).addTo(map.value))
  if (getIsOffLine() === 'false') {
    baseLayer.value.push(L.tileLayer('https://t0.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=216ee92889e17ab1b083fae665d522b8').addTo(map.value))
  }
  search()
})

// 右侧弹窗
function clickRecall(item: any) {
  webRtcServer.value = null
  isRightShow.value = true
  currentName.value = item.monitorName
  monitorId.value = item.monitorId
  deviceIp.value = item.deviceIp
  nextTick(() => {
    monitorId.value && getDevInfo(monitorId.value).then((res) => {
      device.value = res.data
      src.value = `http://192.168.2.4:8091/rtp/11010820001110020000_${devJson[res.data.monitorName]}.live.mp4` // res.data.playUrl
      video.value.play()
      // const devInfo = res.data
      // webRtcServer.value = new WebRtcStreamer('video', proxy.rtspServer)
      // webRtcServer.value.connect(`rtsp://${devInfo.deviceUser}:${devInfo.devicePassword}@${devInfo.deviceIp}`)
      // console.log(`rtsp://${devInfo.deviceUser}:${devInfo.devicePassword}@${devInfo.deviceIp}`)
    })
    devCH4Loading.value = true
    const param = {
      monitorId: item.monitorId,
      startTime: dayjs(Date.now() - 1 * 60 * 1000).format('YYYY-MM-DD HH:mm:ss'),
      endTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    }
    getDataHisList(param).then((res) => {
      const yValue = res.data.reverse().map((item: DateReturn) => {
        if (Object.keys(item).toString().includes('num')) {
          Number(item.num)
        }
        else {
          Number(item.concentration)
        }
      })
      devCH4YDataMax.value = Math.max(yValue) > 10 ? Math.max(yValue) : 10
      devCH4XData.value = res.data.map((item: TypeReturn) => item.logTime ? item.logTime.split(' ')[1] : '')
      devCH4Data.value = [{ name: 'CH4', data: yValue }]
      devCH4Loading.value = false
    })
  })
}

// watch监听websocket变化
const unwatch = watch(websocket, (newVal) => {
  if (newVal.refreshMap) {
    search()
  }
  if (newVal.lineData && Object.keys(newVal.lineData).length >= 1 && isRightShow.value) {
    // console.log('监测到新的数据,并且右侧面板开启!')
    // 匹配id
    if (newVal.lineData.deviceIp === deviceIp.value) {
      devCH4Loading.value = true
      // 判断数据长度
      if (devCH4XData.value.length > 300) {
        devCH4XData.value.splice(0, 100)
        devCH4Data.value[0].data.splice(0, 100)
      }
      devCH4XData.value = [...devCH4XData.value, dayjs(newVal.lineData.time).format('HH:mm:ss')]
      devCH4Data.value = [{ name: 'CH4', data: devCH4Data.value[0].data.concat(newVal.lineData.gasData) }]
      devCH4Loading.value = false
    }
  }
})

onBeforeUnmount(() => {
  if (webRtcServer.value && typeof webRtcServer.value.disconnect === 'function') {
    webRtcServer.value.disconnect()
    webRtcServer.value = null
  }
  unwatch()
})
</script>

<template>
  <div id="map" style="height: calc(100vh - 110px);" />
  <div class="input">
    <el-input v-model="keyword" type="text" placeholder="场站/设备名称关键字" clearable style="width: 200px;" />
    <el-button type="primary" style="margin-left: 5px;" @click="search">
      查询
    </el-button>
  </div>
  <div class="cover">
    <div class="green" />
    <div class="gray" />
    <div class="red" />
    <div class="item">
      正常
    </div>
    <div class="item">
      离线
    </div>
    <div class="item">
      报警
    </div>
  </div>
  <div v-if="isRightShow" class="right">
    <svg-icon name="icon-close" class="close" @click="isRightShow = false" />
    <div class="devName">
      {{ currentName }}
    </div>
    <bench-col id="home" icon="icon-video" title="视频监控" height="250px" style="background: #faefe0;padding: 0;">
      <!--      <h-k-video style="width: 100%;height: 100%;background:currentColor;" id="map" :device="device"/> -->
      <video id="video" ref="video" :src="src" autoPlay controls style="width: 100%;height: 100%;background: currentcolor;" />
    </bench-col>
    <bench-col v-loading="devCH4Loading" icon="icon-line" title="浓度监控(ppm·m)" height="250px" style="background: #faefe0;padding: 0;">
      <line-chart :x-axis-data="devCH4XData" width="340px" :data="devCH4Data" unit="" :grid="{ top: 10, left: 10, right: 30, bottom: 20, containLabel: true }" />
    </bench-col>
  </div>
</template>

<style lang="scss" scoped>
.map {
  width: 100%;
  height: 100%;
}

.right {
  z-index: 1000 !important;
  position: absolute;
  right: 20px;
  top: 10px;
  width: 350px;
  height: calc(100vh - var(--g-topbar-height) - var(--g-header-height) - 20px);
  background: #faefe0;
  border-radius: 10px;
  padding: 20px 0;

  .devName {
    padding-left: 10px;
    margin-bottom: 10px;
    font-size: 19px;
    font-weight: bold;
  }

  .title {
    font-size: 17px;
    font-weight: bold;
    margin: 10px 0;
    color: #464646;
  }

  .close {
    width: 20px;
    height: 20px;
    position: absolute;
    right: 10px;
    top: 20px;
  }
}

.input {
  position: absolute;
  top: 20px;
  left: 20px;
  width: 280px;
  height: 34px;
  display: flex;
}

.cover {
  position: absolute;
  bottom: 25px;
  left: 5px;
  width: 120px;
  height: 170px;
  border-radius: 10px;
  background: #faefe0;
  z-index: 1111;
  display: flex;
  flex-flow: column wrap;
  justify-content: space-evenly;
  align-items: center;

  .item {
    width: 50px;
    height: 45px;
    padding-top: 10px;
    font-weight: bold;
    color: #5f5f5f;
  }

  .green {
    background: url("../../assets/images/marker/green.png") no-repeat center / cover;
    width: 45px;
    height: 45px;
  }

  .red {
    background: url("../../assets/images/marker/red.png") no-repeat center / cover;
    width: 45px;
    height: 45px;
  }

  .gray {
    background: url("../../assets/images/marker/gray.png") no-repeat center / cover;
    width: 45px;
    height: 45px;
  }
}
</style>

<style>
.my-div-icon {
  color: black;
  font-size: 14px;
  text-align: center;
  pointer-events: none; /* Prevent mouse events from firing */
}
</style>