Newer
Older
laserPTZFrontV2.0 / src / views / home / control.vue
wangxitong on 26 Sep 37 KB 流媒体
<script lang="ts" setup name="videoControl">
import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { Ref } from 'vue'
import html2canvas from 'html2canvas'
import { getCurrentInstance, reactive, ref } from 'vue'
import dayjs from 'dayjs'
import useWebsocketStore from '@/store/modules/websocket'
import { initPlugin, login, logout, onlyLogin, preview } from '@/utils/HKVideo'
import { getDataHisList, getDevInfo, restartDev } from '@/api/ptz/dev'
import type { DevInfo } from '@/views/device/dev-interface'
import controlImg from '@/assets/images/control.png'
import type { lineDataI } from '@/components/Echart/echart-interface'
import type { DateReturn, TypeReturn } from '@/views/statistics/statistics-interface'
import type { LineListInfo } from '@/views/line/line-interface'
import { delAlarm, getAlarmListPage } from '@/api/ptz/alarm'
import redImg from '@/assets/images/中心.png'

import {
  devCancelAlarm,
  devControl,
  devControlWithSpeed,
  devToPosition,
  setPreset,
  specialControl,
} from '@/api/ptz/control'
import type { AlarmListInfo } from '@/views/alarm/alarm-interface'
import { isInRange, isInRangeNum } from '@/utils/validate'
import { HCCruiseRoute, HCPreset, getLineList, getSerialListPage, handleCruise } from '@/api/ptz/line'
import { exportFile } from '@/utils/exportUtils'
import devJson from '/public/config/dev.json'
import { loginMedia, playBack } from '@/api/ptz/media'
const { proxy } = getCurrentInstance()

const websocket = useWebsocketStore()
const $route = useRoute()
const deviceData: Ref<DevInfo> = ref({
  id: '',
  stationId: '',
  stationName: '',
  monitorName: '',
  deviceIp: '',
  devicePort: '',
  deviceUser: '',
  devicePassword: '',
  nvrIp: '',
  nvrPort: '',
  nvrUser: '',
  nvrPassword: '',
  nvrChannel: '',
  deviceType: '',
  deviceTypeName: '',
  doorIp: '',
  doorSn: '',
  longitude: '',
  latitude: '',
  description: '',
  location: '',
  // speed: 0,
  // stopTime: 0,
  // high: 0,
  // angle: 0,
  deviceStatus: '',
  deviceStatusName: '',
})
const wiper = ref(true)
const video = ref()
let baseUrl = ''
const playUrl = ref('')
const realppm = ref('****')
const realh = ref('****')
const realv = ref('****')
const devCH4Loading = ref(false)
const devCH4XData: Ref<string[]> = ref([])
const devCH4Data: Ref<lineDataI[]> = ref([])
const devCH4YDataMax = ref()
const tableData = ref([])
const instance = getCurrentInstance()
const loading = ref(false)
const videoControl = ref('videoControl')
const resumeTime = ref('')
const detailTxt = ref('')
const inputh = ref('')
const inputv = ref('')
const selectLine = ref('')
const selectPoint = ref('')
const controlSpeed = ref(7)
const maxSpeed = ref(63)
const exeData = ref({
  inputh: '',
  inputv: '',
})
const divPlugin = ref(null)
const lineList: Ref<LineListInfo[]> = ref([])
const pointList: Ref<any[]> = ref([])

const addData = ref({
  speed: '30',
  time: '3',
  alarm: '5000',
})
const pointName = ref('')
const showAdd = ref(false)

const isInRangeV = function (min: number, max: number) {
  return function (rule: any, value: any, callback: any) {
    if (value === '' || !isInRange(value, min, max)) {
      callback(new Error(`请输入${min.toString()}-${max.toString()}整数`))
    }
    else {
      callback()
    }
    callback()
  }
}

const isInRangeNumV = function (min: number, max: number, length: number) {
  return function (rule: any, value: any, callback: any) {
    if (isNaN(value) || value === '') {
      callback(new Error(`请输入${min.toString()}-${max.toString()}范围${length}位小数`))
    }
    else if (isInRangeNum(Number(value), min, max)) {
      if (value.toString().includes('.') && value.toString().split('.')[1].length > length) {
        callback(new Error(`请输入${min.toString()}-${max.toString()}范围${length}位小数`))
      }
      callback()
    }
    else {
      callback(new Error(`请输入${min.toString()}-${max.toString()}范围${length}位小数`))
    }
    callback()
  }
}
const exeFormRef = ref<FormInstance>()
const addFormRef = ref<FormInstance>()
// 校验规则
const exeRules = reactive<FormRules>({
  inputh: [{ required: true, message: '0~360整数/一位小数', trigger: [], validator: isInRangeNumV(0, 360, 1) }],
  inputv: [{ required: true, message: '-90~90整数/一位小数', trigger: [], validator: isInRangeNumV(-90, 90, 1) }],
})

const rules = reactive<FormRules>({
  presetName: [{ required: true, message: '预置点名不能为空', trigger: ['blur', 'change'] }],
  cruiseRoute: [{ required: true, message: '巡航路径不能为空', trigger: ['blur', 'change'] }],
  speed: [{ type: 'number', required: true, message: '1~63整数', trigger: [], validator: isInRangeV(1, 63) }],
  time: [{ type: 'number', required: true, message: '0~255整数', trigger: [], validator: isInRangeV(0, 255) }],
  alarm: [{ type: 'number', required: true, message: '0~10000整数', trigger: [], validator: isInRangeV(0, 10000) }],
})

// socket更新数据
const unwatch = watch(websocket, (newVal) => {
  if (newVal.wsData && newVal.wsData.monitorId === deviceData.value.id && (newVal.wsData.type === 'gasAlarm' || newVal.wsData.type === 'AIAlarm')) {
    getAlarm()
  }
  else if (newVal.wsData && newVal.wsData.deviceIp === deviceData.value.deviceIp) {
    // if (newVal.wsData.type === 'gasAlarm' || newVal.wsData.type === 'AIAlarm') {
    // else if (newVal.wsData.type === undefined) {
    realppm.value = newVal.wsData.gasData
    realh.value = newVal.wsData.horizontal
    realv.value = newVal.wsData.verticalAngle
    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.wsData.time).format('HH:mm:ss')]
    devCH4Data.value = [{ name: 'CH4', data: devCH4Data.value[0].data.concat(newVal.wsData.gasData) }]
    devCH4Loading.value = false
    // }
  }
})

function formatTooltip(val) {
  return `转动速度:${val}`
}

function tableRowClassName({ row, rowIndex }) {
  if (rowIndex % 2 === 1) {
    return 'e-row'
  }
  return ''
}

// 刷新报警列表
function getAlarm() {
  loading.value = true
  const parans = {
    monitorId: deviceData.value.id,
    alarmStatus: '0',
    offset: 1,
    limit: 100,
  }
  getAlarmListPage(parans).then((res: { data: { rows: []; total: number } }) => {
    tableData.value = res.data.rows.map((item: any) => {
      return {
        ...item,
        position: `${item.alarmDirection},${item.alarmPitch}`,
      }
    })
    loading.value = false
  })
}

// 获取历史甲烷浓度
function getCH4() {
  devCH4Loading.value = true
  const param = {
    monitorId: $route.query.id,
    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
  })
}

// 设备消警
function deviceCancelAlarm() {
  ElMessageBox.confirm(`确定要将${deviceData.value.monitorName}设备消警?`, '设备消警', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning',
  }).then(() => {
    devCancelAlarm(deviceData.value.id).then((res) => {
      if (res.code.toString() === '200') {
        ElMessage.success('设备消警成功')
      }
      getAlarm()
    })
  })
}

// 全部消警
function cancelAllAlarm() {
  ElMessageBox.confirm('确定要将所有设备消警?', '全部消警', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning',
  }).then(() => {
    devCancelAlarm('').then((res) => {
      if (res.code.toString() === '200') {
        ElMessage.success('全部消警成功')
      }
      getAlarm()
    })
  })
}

// 消警单条
function cancelRowAlarm(row: AlarmListInfo) {
  resumeTime.value = ''
  detailTxt.value = ''
  if (row.alarmType !== '0' && row.alarmType !== '1') {
    ElMessageBox.confirm(
      h('div', [
        h('div', {
          style: {
            fontSize: '17px',
            fontWeight: 'bold',
          },
        }, '处置结果:'),
        h('textarea', {
          style: {
            padding: '4px',
            width: '100%',
            marginTop: '4px',
            lineHeight: '20px',
          },
          props: {
            value: detailTxt.value,
          },
          value: detailTxt.value,
          onInput: (e) => {
            detailTxt.value = e.target.value
          },
        }),
      ]),
      '确定要取消该条报警吗?',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      }).then(() => {
      delAlarm({ id: row.id, detail: detailTxt.value }).then((res) => {
        if (res.code.toString() === '200') {
          ElMessage.success('取消报警成功')
        }
        getAlarm()
      })
    })
  }
  else {
    ElMessageBox.confirm(
      h('div', [
        h('i', {
          style: {
            fontSize: '17px',
            fontStyle: 'normal',
            fontWeight: 'bold',
          },
        }, '恢复报警时间:'),
        h('input', {
          style: {
            padding: '4px',
            lineHeight: '20px',
            marginBottom: '2px',
            float: 'right',
            rows: '2',
          },
          props: {
            value: resumeTime.value,
          },
          value: resumeTime.value,
          onInput: (e) => {
            resumeTime.value = e.target.value
          },
        }),
        h('div', {
          style: {
            fontSize: '17px',
            fontWeight: 'bold',
          },
        }, '处置结果:'),
        h('textarea', {
          style: {
            padding: '4px',
            width: '100%',
            marginTop: '4px',
            lineHeight: '20px',
          },
          props: {
            value: detailTxt.value,
          },
          value: detailTxt.value,
          onInput: (e) => {
            detailTxt.value = e.target.value
          },
        }),
      ]),
      '确定要取消该条报警吗?',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
        beforeClose: (action, instance, done) => {
          if (action === 'confirm') {
            if (isNaN(resumeTime.value)) {
              ElMessage.error('请输入整数')
            }
            else if (!Number.isInteger(Number(resumeTime.value))) {
              ElMessage.error('请输入整数')
            }
            else {
              done()
            }
          }
          else {
            done()
          }
        },
      }).then(() => {
      delAlarm({ id: row.id, resumeTime: resumeTime.value, detail: detailTxt.value }).then((res) => {
        if (res.code.toString() === '200') {
          ElMessage.success('取消报警成功')
        }
        getAlarm()
      })
    })
  }
}

// 定位
function toPosition(row: AlarmListInfo) {
  ElMessage.info('已下发定位指令请等待')
  const params = {
    deviceIp: deviceData.value.deviceIp,
    horizontalAngle: row.alarmDirection,
    verticalAngle: row.alarmPitch,
  }
  devToPosition(params).then((res) => {
    if (res.code === 200) {
      ElMessage.success('定位成功')
    }
  })
}

// 录像
function playBackVideo(row: AlarmListInfo) {
  ElMessage.info('已下发录像指令请等待')
  loginMedia().then((response) => {
    const accessToken = response.data.accessToken
    const startTime = dayjs(row.alarmTime).subtract(5, 'second').format('YYYY-MM-DD HH:mm:ss')
    const endTime = dayjs(row.alarmTime).add(5, 'second').format('YYYY-MM-DD HH:mm:ss')
    playBack(devJson[row.monitorName], startTime, endTime, accessToken).then((res) => {
      playUrl.value = res.data.fmp4
      video.value.play()
      setTimeout(() => {
        playUrl.value = baseUrl
        video.value.play()
      }, 11000)
    })
  })
}
const canvas = ref(null)

function takePhoto() {
  const szPicName = `${deviceData.value.monitorName}_${new Date().getTime()}.png`
  const w = video.value.clientWidth
  const h = video.value.clientHeight
  canvas.value.width = w
  canvas.value.height = h // 设置宽高
  const ctx = canvas.value.getContext('2d')
  ctx?.drawImage(video.value, 0, 0, w, h) // video写入到canvas  clientHeight
  const plShareImg = new Image()
  plShareImg.crossOrigin = 'anonymous' // 添加此行anonymous必须小写
  plShareImg.src = canvas.value.toDataURL('image/png') // 最终海报
  // downloadFileByBase64(plShareImg, szPicName)

  const aLink = document.createElement('a')
  aLink.id = 'qrcodeimg'
  aLink.href = plShareImg.src
  aLink.download = szPicName
  document.body.appendChild(aLink)
  // 模拟a标签点击事件
  aLink.click()
  // 事件已经执行,删除本次操作创建的a标签对象
  document.body.removeChild(aLink)
}

// 放大
function zoomIn(isStop: string) {
  console.log(isStop)
  const params = {
    deviceIp: deviceData.value.deviceIp,
    command: 'zoomIn',
    isStop,
  }
  devControl(params).then(() => {
    // ElMessage.success('放大成功')
  })
}

// 缩小
function zoomOut(isStop: string) {
  const params = {
    deviceIp: deviceData.value.deviceIp,
    command: 'zoomOut',
    isStop,
  }
  devControl(params).then(() => {
    // ElMessage.success('缩小成功')
  })
}

// 上下左右
function controlWithSpeed(event, type, isStop) {
  // console.log(event.detail, type, isStop)
  if (event.detail === 1) {
    const params = {
      deviceIp: deviceData.value.deviceIp,
      command: type,
      isStop,
      speed: controlSpeed.value.toString(),
    }
    devControlWithSpeed(params).then(() => {})
  }
  else if (event.detail === 2) {
    // 小角度转动
    let horizontalAngle = Number(realh.value)
    let verticalAngle = Number(realv.value)
    switch (type) {
      case 'up':
        verticalAngle += deviceData.value.deviceType === '1' ? -1 : 1
        break
      case 'down':
        verticalAngle += deviceData.value.deviceType === '1' ? 1 : -1
        break
      case 'left':
        horizontalAngle += -1
        break
      case 'right':
        horizontalAngle += 1
        break
    }
    if (horizontalAngle < 0 || horizontalAngle > 360) { return }
    if (verticalAngle < -90 || verticalAngle > 90) { return }
    const params = {
      deviceIp: deviceData.value.deviceIp,
      horizontalAngle,
      verticalAngle,
    }
    devToPosition(params).then(() => {})
  }
}

// 雨刷
function wiperChange() {
  if (wiper.value) {
    const params = {
      deviceIp: deviceData.value.deviceIp,
      command: 'clean',
      isStop: '0',
    }
    devControl(params).then((res) => {
      if (res.code.toString() === '200') {
        ElMessage.success('雨刷打开')
      }
    })
  }
  else {
    const params = {
      deviceIp: deviceData.value.deviceIp,
      command: 'clean',
      isStop: '1',
    }
    devControl(params).then((res) => {
      if (res.code.toString() === '200') {
        ElMessage.success('雨刷关闭')
      }
    })
  }
}

// 断点重启
function cq() {
  restartDev(deviceData.value.doorIp, deviceData.value.doorSn).then(() => {
    ElMessage.success('重启成功')
  })
}

// 复位
function fw() {
  // const params = {
  //   deviceIp: deviceData.value.deviceIp,
  //   command: 'restart',
  //   value: '',
  // }
  // specialControl(params).then((res) => {
  //   if (res.code.toString() === '200') {
  //     ElMessage.success('复位成功')
  //   }
  // })
  restartDev(deviceData.value.doorIp, deviceData.value.doorSn).then(() => {
    ElMessage.success('复位成功')
  })
}

// 自检
function zj() {
  const params = {
    deviceIp: deviceData.value.deviceIp,
    command: '79',
  }
  setPreset(params).then((res) => {
    if (res.code.toString() === '200') {
      ElMessage.success('自检成功')
    }
  })
}

// 角度执行
function exeAngle() {
  if (exeFormRef.value) {
    exeFormRef.value?.validate((valid: boolean) => {
      if (valid) {
        const params = {
          deviceIp: deviceData.value.deviceIp,
          horizontalAngle: exeData.value.inputh,
          verticalAngle: exeData.value.inputv,
        }
        devToPosition(params).then((res) => {
          if (res.code.toString() === '200') {
            ElMessage.success('角度执行成功')
          }
        })
      }
    })
  }
  setTimeout(() => {
    exeFormRef.value?.clearValidate()
  }, 5000)
}

// 获取设备巡航线
function fetchLineList() {
  selectLine.value = ''
  getLineList('', deviceData.value.id).then((res) => {
    lineList.value = res.data
  })
}

// 获取巡航点
function fetchPoint() {
  const arr = lineList.value.filter(item => item.id === selectLine.value)
  if (arr.length === 0) { return }
  const params = {
    monitorId: deviceData.value.id,
    lineNum: selectLine.value,
    offset: 1,
    limit: 200,
  }
  getSerialListPage(params).then(
    (res: { data: { rows: []; total: number } }) => {
      pointList.value = res.data.rows
    },
  )
  selectPoint.value = ''
}

// 开启巡航线
function startLine() {
  if (selectLine.value === '') {
    ElMessage.warning('请选择巡航路径进行开启!')
  }
  else {
    const params = {
      deviceIp: deviceData.value.deviceIp,
      command: 'start',
      cruiseRoute: selectLine.value,
      interval: '750',
    }
    handleCruise(params).then((res) => {
      console.log(res)
    })
  }
}

// 暂停巡航线
function pauseLine() {
  if (selectLine.value === '') {
    ElMessage.warning('请选择巡航路径进行暂停!')
  }
  else {
    const params = {
      deviceIp: deviceData.value.deviceIp,
      command: 'stop',
      interval: '750',
    }
    handleCruise(params).then((res) => {
      console.log(res)
    })
  }
}

// 添加巡航线
function addLine() {
  const arr = lineList.value.filter(item => item.id === selectLine.value)
  if (arr.length > 0 || selectLine.value === '') {
    // 不是新填写
    ElMessage.warning('请填写新巡航线名称!')
    return
  }
  const param = {
    deviceIp: deviceData.value.deviceIp,
    command: 'cruiseAdd',
    cruiseName: selectLine.value,
    cruiseValue: '',
  }
  HCCruiseRoute(param).then((res) => {
    if (res.code.toString() === '200') {
      ElMessage.success('巡航线添加成功')
    }
    fetchLineList()
  })
}

// 删除巡航线
function delLine() {
  const arr = lineList.value.filter(item => item.id === selectLine.value)
  if (arr.length === 0 || selectLine.value === '') {
    // 不是新填写
    ElMessage.warning('请选择要删除的巡航线!')
    return
  }
  ElMessageBox.confirm('确定要删除所选巡航线吗?', '确认删除', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning',
  }).then(() => {
    const param = {
      deviceIp: deviceData.value.deviceIp,
      command: 'cruiseDelete',
      cruiseName: arr[0].lineName,
      cruiseValue: selectLine.value,
    }
    HCCruiseRoute(param).then((res) => {
      if (res.code.toString() === '200') {
        ElMessage.success('巡航线删除成功')
      }
      fetchLineList()
    })
  })
}

// 删除预置点
function delPoint() {
  if (selectLine.value === '' || selectPoint.value === '') {
    ElMessage.warning('请选择预置点!')
  }
  else {
    const point = pointList.value.filter(item => item.id === selectPoint.value)[0]
    ElMessageBox.confirm(`确定要删除${point.serialName}预置点吗?`, '确认删除', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
    }).then(() => {
      const params = {
        deviceIp: deviceData.value.deviceIp,
        command: 'presetDel',
        presetIndex: point.serialNum,
        cruiseRoute: point.lineNum,
        presetName: point.serialName,
        cruiseName: point.lineName,
      }
      HCPreset(params).then((res) => {
        if (res.code.toString() === '200') {
          ElMessage.success('删除成功')
        }
        fetchPoint()
      })
    })
  }
}

// 转至预置点
function toPoint() {
  if (selectLine.value === '' || selectPoint.value === '') {
    ElMessage.warning('请选择预置点!')
  }
  else {
    const point = pointList.value.filter(item => item.id === selectPoint.value)[0]
    const params = {
      deviceIp: deviceData.value.deviceIp,
      horizontalAngle: point.direction,
      verticalAngle: point.pitch,
    }
    devToPosition(params).then((res) => {
      if (res.code.toString() === '200') {
        ElMessage.success('定位成功')
      }
    })
  }
}

// 插入弹窗
function addShow() {
  pointName.value = ''
  showAdd.value = true
}

// 添加预置点
function addPoint() {
  if (selectLine.value === '') {
    ElMessage.warning('请选择巡航线!')
    return
  }
  const arr = pointList.value.filter(item => item.id === selectPoint.value)
  if (arr.length > 0 || selectPoint.value === '') {
    // 不是新填写
    ElMessage.warning('请填写新预置点名称!')
    return
  }
  // 判断新填写
  if (addFormRef.value) {
    addFormRef.value?.validate((valid: boolean) => {
      if (valid) {
        const params = {
          deviceIp: deviceData.value.deviceIp,
          command: 'presetAdd',
          presetIndex: '',
          cruiseRoute: selectLine.value,
          presetName: selectPoint.value,
          cruiseName: lineList.value.filter(item => item.id === selectLine.value)[0].lineName,
          direction: realh.value,
          pitch: realv.value,
          speed: addData.value.speed,
          stopTime: addData.value.time,
          alarmValue: addData.value.alarm,
        }
        HCPreset(params).then((res) => {
          if (res.code.toString() === '200') {
            ElMessage.success('预置点添加成功')
          }
        })
      }
    })
  }
  setTimeout(() => {
    addFormRef.value?.clearValidate()
  }, 5000)
}
// 插入预置点
function insertPoint() {
  if (selectLine.value === '') {
    ElMessage.warning('请选择巡航线!')
    return
  }
  const arr = pointList.value.filter(item => item.id === selectPoint.value)
  if (arr.length === 0) {
    ElMessage.warning('请选择被插入预置点!')
    return
  }
  if (pointName.value === '') {
    ElMessage.warning('请选择插入预置点名称!')
    return
  }
  // 判断新填写
  if (addFormRef.value) {
    addFormRef.value?.validate((valid: boolean) => {
      if (valid) {
        const params = {
          deviceIp: deviceData.value.deviceIp,
          command: 'presetInsert',
          presetIndex: selectPoint.value,
          cruiseRoute: selectLine.value,
          presetName: pointName.value,
          cruiseName: lineList.value.filter(item => item.id === selectLine.value)[0].lineName,
          direction: realh.value,
          pitch: realv.value,
          speed: addData.value.speed,
          stopTime: addData.value.time,
          alarmValue: addData.value.alarm,
        }
        HCPreset(params).then((res) => {
          if (res.code.toString() === '200') {
            ElMessage.success('预置点添加成功')
          }
        })
      }
    })
  }
  setTimeout(() => {
    addFormRef.value?.clearValidate()
  }, 5000)
}

const handleDoubleClick = (index, fullSceen, event) => {
  console.log(event.point)
  const x = (event.point[0] - 0.5) * 59.8
  const y = (event.point[1] - 0.5) * 30 // (29.9 * divPlugin.value.clientHeight / divPlugin.value.clientWidth)
  console.log(x, y)
  const params = {
    deviceIp: deviceData.value.deviceIp,
    horizontalAngle: Number(realh.value) + x,
    verticalAngle: Number(realv.value) - y,
  }
  devToPosition(params).then(() => {
    // ElMessage.success('定位成功')
  })
}
// 登录设备
function loginDevice() {
  login(
    deviceData.value.deviceIp,
    deviceData.value.id === '1655767080138518529' ? '81' : '80',
    deviceData.value.deviceUser,
    deviceData.value.devicePassword,
    0)
  if (proxy.NVR) {
    login(
      deviceData.value.nvrIp,
      deviceData.value.nvrPort,
      deviceData.value.nvrUser,
      deviceData.value.nvrPassword,
      0,
      true,
      deviceData.value.nvrChannel)

    // onlyLogin(
    //   deviceData.value.nvrIp,
    //   deviceData.value.nvrPort,
    //   deviceData.value.nvrUser,
    //   deviceData.value.nvrPassword,
    //   0,
    //   true,
    //   deviceData.value.nvrChannel)
  }
}

onMounted(() => {
  console.log($route.query)
  // 从路由中获取页面类型参数
  if ($route.query && $route.query.id) {
    getDevInfo($route.query.id.toString()).then((response) => {
      deviceData.value = response.data
      playUrl.value = `http://192.168.2.4:8091/rtp/11010820001110020000_${devJson[deviceData.value.monitorName]}.live.mp4`
      baseUrl = `http://192.168.2.4:8091/rtp/11010820001110020000_${devJson[deviceData.value.monitorName]}.live.mp4`
      video.value.play()
      setTimeout(() => {
        // 甲烷历史浓度
        getCH4()
        // 设备报警
        getAlarm()
        // 获取巡航线
        fetchLineList()
      }, 200)
    })
  }
})

onBeforeUnmount(() => {
  unwatch()
  window.location.reload()
})
</script>

<template>
  <div class="video-wrap">
    <div class="left-box">
      <div class="box-card" style="display: flex;height: 42%;">
        <div style="width: 110px;overflow: hidden;">
          <div class="control-title">
            实时监控
          </div>
          <div style="color: #0a0a0a;background-color: #dcdcdc;margin: 6px 2px;text-align: center;">
            {{ deviceData.monitorName }}
          </div>
          <div class="real-text">
            气体浓度:
          </div>
          <div class="real-text" style="margin-left: 10px;font-weight: bold;">
            {{ realppm }}ppm·m
          </div>
          <div class="real-text">
            水平,垂直:
          </div>
          <div class="real-text" style="margin-left: 10px;font-weight: bold;">
            {{ realh }}°,{{ realv }}°
          </div>
          <!--          <div class="real-text"> -->
          <!--            垂直角度: -->
          <!--          </div> -->
          <!--          <div class="real-text" style="margin-left: 20px"> -->
          <!--            {{ realv }}° -->
          <!--          </div> -->
        </div>
        <div v-loading="devCH4Loading" class="ppm-line">
          <line-chart :x-axis-data="devCH4XData" width="100%" :data="devCH4Data" unit="" :grid="{ top: 10, left: 10, right: 10, bottom: 20, containLabel: true }" />
        </div>
      </div>
      <div class="box-card" style="height: calc(58% - 10px);">
        <div class="control-title">
          告警列表
        </div>
        <div style="top: -30px;position: relative;float: right;margin-right: 10px;">
          <el-button type="primary" round style="height: 26px;" @click="deviceCancelAlarm">
            设备消警
          </el-button>
          <el-button type="primary" round style="height: 26px;" @click="cancelAllAlarm">
            全部消警
          </el-button>
        </div>
        <el-table
          v-loading="loading"
          :data="tableData"
          class="alarm-table"
          :row-class-name="tableRowClassName"
          border
          size="small"
        >
          <el-table-column prop="alarmTime" label="时 间" align="center" />
          <el-table-column prop="alarmValue" label="告警值" align="center" />
          <el-table-column prop="position" label="方 位" align="center" />
          <el-table-column prop="alarmTypeName" label="告警事件" align="center" />
          <el-table-column label="操 作" align="center" width="110">
            <template #default="scope">
              <el-button type="primary" link size="small" class="table-text-button" @click="cancelRowAlarm(scope.row)">
                消警
              </el-button>
              <el-button type="primary" link size="small" class="table-text-button" @click="toPosition(scope.row)">
                定位
              </el-button>
              <el-button type="primary" link size="small" class="table-text-button" @click="playBackVideo(scope.row)">
                录像
              </el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </div>
    <div class="bottom">
      <div class="box-card" style="height: 100%;width: calc(80% - 5px);">
        <div class="control-title">
          云台控制
        </div>
        <div name="four">
          <el-image style="width: 130px; height: 130px;position: absolute;top: 10px;left: 110px;" :src="controlImg" fit="fill" />
          <div>
            <div class="round-btn" style="top: 13px;left: 155px;" @mousedown="controlWithSpeed($event, 'up', '0')" @mouseup="controlWithSpeed($event, 'up', '1')" />
            <div class="round-btn" style="top: 95px;left: 155px;" @mousedown="controlWithSpeed($event, 'down', '0')" @mouseup="controlWithSpeed($event, 'down', '1')" />
            <div class="round-btn" style="top: 53px;left: 113px;" @mousedown="controlWithSpeed($event, 'left', '0')" @mouseup="controlWithSpeed($event, 'left', '1')" />
            <div class="round-btn" style="top: 53px;left: 195px;" @mousedown="controlWithSpeed($event, 'right', '0')" @mouseup="controlWithSpeed($event, 'right', '1')" />
          </div>
          <el-slider v-model="controlSpeed" style="width: 140px;position: absolute;bottom: 5px;left: 110px;" :max="maxSpeed" :format-tooltip="formatTooltip" />
        </div>
        <div class="control-row" style="top: 10px;">
          <span style="margin: 0 10px;">巡航号</span>
          <el-select
            v-model="selectLine" placeholder="巡航号" clearable
            filterable
            allow-create
            default-first-option
            style="width: 200px;margin-right: 10px;" @change="fetchPoint"
          >
            <el-option
              v-for="item in lineList"
              :key="item.id"
              :label="item.lineName"
              :value="item.id"
            />
          </el-select>
          <icon-button v-show="lineList.length < 5" icon="icon-add" title="新增巡航线" @click="addLine" />
          <icon-button icon="icon-delete" title="删除巡航线" style="margin-left: 10px;" @click="delLine" />
          <icon-button icon="icon-play" title="开启巡航" @click="startLine" />
          <icon-button icon="icon-pause" title="停止巡航" style="margin-left: 10px;" @click="pauseLine" />
        </div>
        <div class="control-row" style="top: 70px;">
          <span style="margin: 0 10px;">预置点</span>
          <el-select
            v-model="selectPoint"
            placeholder="预置点"
            filterable
            allow-create
            default-first-option
            style="width: 200px;margin-right: 10px;"
          >
            <el-option
              v-for="item in pointList"
              :key="item.id"
              :label="item.serialName"
              :value="item.id"
            />
          </el-select>
          <icon-button v-show="pointList.length < 200" icon="icon-add" title="新增预置点" @click="addPoint" />
          <icon-button icon="icon-delete" title="删除预置点" style="margin-left: 10px;" @click="delPoint" />
          <icon-button icon="icon-to-position" title="转至预置点" @click="toPoint" />
          <icon-button v-show="deviceData.deviceType !== '2' && pointList.length < 200" id="addLineBtn" icon="icon-insert" title="插入预置点" style="margin-left: 10px;" @click="addShow" />
          <div v-show="showAdd" id="addLineDiv" class="add-line">
            <el-input v-model="pointName" placeholder="预置点名称" style="width: 150px;" />
            <icon-button
              icon="search-up"
              title="提交"
              style="margin-left: 5px;"
              @click="insertPoint"
            />
            <div style="margin-left: 5px;color: #4788fe;margin-top: -5px;font-weight: 800;cursor: pointer;" @click="showAdd = false">
              ×
            </div>
          </div>
        </div>
        <div class="control-row" style="top: 130px;">
          <el-form ref="addFormRef" :model="addData" :rules="rules" label-position="right" label-width="110px" size="default" @submit.prevent>
            <el-row>
              <el-form-item label="巡航速度(°/s)" prop="speed">
                <el-input v-model="addData.speed" placeholder="例如:30" style="width: 120px;" />
              </el-form-item>
              <el-form-item label="停留时间(s)" prop="time">
                <el-input v-model="addData.time" placeholder="例如:3" style="width: 120px;" />
              </el-form-item>
              <el-form-item label="阈值(ppm·m)" prop="alarm">
                <el-input v-model="addData.alarm" placeholder="例如:5000" style="width: 120px;" />
              </el-form-item>
            </el-row>
          </el-form>
        </div>
        <div class="ptz-control">
          <el-icon style="font-size: 20px;margin-right: 5px;margin-top: 5px;">
            <svg-icon name="icon-clean" />
          </el-icon>
          <el-tooltip :content="`雨刷:${wiper ? '开' : '关'} `" placement="bottom">
            <el-switch v-model="wiper" @change="wiperChange" />
          </el-tooltip>
          <icon-button icon="icon-fw" title="复 位" style="margin-left: 15px;" @click="fw" />
          <icon-button icon="icon-zj" title="自 检" size="26" @click="zj" />
          <!--          <icon-button icon="icon-cq" title="重 启" size="26" @click="cq" /> -->
          <el-form ref="exeFormRef" :model="exeData" :rules="exeRules" label-position="left" label-width="10px" size="default" @submit.prevent>
            <el-form-item label="" prop="inputh">
              <el-input v-model="exeData.inputh" placeholder="水平角度" style="width: 120px;" />
            </el-form-item>
            <el-form-item label="" prop="inputv">
              <el-input v-model="exeData.inputv" placeholder="垂直角度" style="width: 120px;" />
            </el-form-item>
            <el-button type="primary" round style="margin-left: 25px;margin-top: -5px;height: 30px;" @click="exeAngle">
              角度执行
            </el-button>
          </el-form>
        </div>
      </div>
      <div class="box-card b2">
        <div class="control-title">
          视频控制
        </div>
        <el-button type="primary" round class="btn" @click="takePhoto">
          <el-icon style="margin-right: 5px;">
            <svg-icon name="icon-camera" />
          </el-icon>
          抓 拍
        </el-button>
        <div>
          <el-button type="primary" round class="btn" @mousedown="zoomIn('0')" @mouseup="zoomIn('1')">
            <el-icon style="margin-right: 5px;">
              <svg-icon name="icon-zoomin" />
            </el-icon>
            放 大
          </el-button>
        </div>
        <div>
          <el-button type="primary" round class="btn" @mousedown="zoomOut('0')" @mouseup="zoomOut('1')">
            <el-icon style="margin-right: 5px;">
              <svg-icon name="icon-zoomout" />
            </el-icon>
            缩 小
          </el-button>
        </div>
      </div>
    </div>
    <video id="video" ref="video" crossOrigin="anonymous" :src="playUrl" controls autoPlay class="plugin" :class="videoControl" />
    <canvas v-show="false" id="canvas" ref="canvas" />
    <el-image :src="redImg" class="red-img-control" />
  </div>
</template>

<style lang="scss">
.video-wrap {
  padding: 0 5px;
  width: calc(100% - 10px);
  height: 100%;
  margin-left: 5px;
}

.videoControl {
  float: right;
  height: calc(76vh - 70px);
  width: 65%;
  position: relative;
}

.red-img-control {
  position: absolute;
  top: calc((76vh - 70px) / 2 - 20px);
  right: calc(34.125% - 20px);
  width: 40px;
  height: 40px;
  z-index: 999999;
}

.left-box {
  width: 35%;
  height: calc(76vh - 60px);
  position: absolute;
  left: 0;
  top: 0;
  padding: 5px;
}

.bottom {
  width: 100%;
  height: calc(24vh + 5px);
  position: absolute;
  left: 0;
  bottom: 5px;
  display: flex;
  justify-content: space-between;
  padding: 0 5px;
  overflow: hidden;
}

.box-card {
  width: 100%;
  height: calc(50% - 5px);
  margin-bottom: 5px;
  padding: 5px !important;
  box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
  overflow: hidden;
}

.control-title {
  color: white;
  background-color: #ff9f11;
  border-radius: 10px;
  width: 100px;
  height: 30px;
  line-height: 30px;
  font-weight: bold;
  text-align: center;
  letter-spacing: 1px;
  font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", SimSun, sans-serif;
}

.b2 {
  height: 100%;
  width: 20%;
  text-align: center;
  overflow: hidden;
}

.btn {
  margin: 3px auto;
  width: 100px;
}

.control-row {
  display: flex;
  position: absolute;
  left: 260px;
  width: 60%;
  overflow: hidden;
  justify-content: flex-start;
  align-items: center;
}

.real-text {
  margin: 6px 10px;
  color: #6e6e6e;
}

.ppm-line {
  padding: 0;
  height: 100%;
  flex: 1;
}

.alarm-table {
  width: calc(100% - 20px);
  height: calc(58% - 60px);
  position: absolute;
  margin-top: 5px;
  overflow-y: scroll;
}

.el-table .e-row {
  background: #9ed7ff;
}

.el-message-box {
  position: absolute !important;
  top: calc(50% - 68px) !important;
  left: 100px !important;
}

.ptz-control {
  width: 400px;
  position: absolute;
  right: 18%;
  top: 5px;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  flex-wrap: wrap;
}

.round-btn {
  position: absolute;
  top: 14px;
  left: 129px;
  width: 42px;
  height: 42px;
  z-index: 111111;
  border-radius: 21px;
  cursor: pointer;
}

.round-btn:hover {
  background-color: rgb(61 125 254 / 53%);
}

.icon-button {
  background-color: #d6e5fc;
  border-color: #d6e5fc;
  padding: 6px;
  border-radius: 6px;
  color: #4384ff;

  :deep(.el-icon) {
    width: 18px;
    height: 18px;
  }

  &:hover {
    background-color: #c3dafd;
    color: #fff;
  }
}

.add-line {
  width: 250px;
  display: flex;
  margin-left: 10px;
  z-index: 1111111;
}
</style>