Newer
Older
safe_production_front / src / views / ycjg / sjhf / index-hk.vue
<script lang="ts" setup name="ResourceList">
import type { Ref } from 'vue'
import { getCurrentInstance, nextTick, reactive, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import dayjs from 'dayjs'
import { videoTree } from '@/api/ycjg/aqbb'
import { log } from '@/utils/log'
import { getPlaybackUrl } from '@/utils/hik'
// import './public/isc/h5player.min.js'
const router = useRouter()

const treeRef = ref(null)
const filterText = ref('')
const timeRange = ref<[any, any]>(['', ''])
// 默认查询条件
const defaultQuery = {
  id: '',
  startTime: '',
  endTime: '',
}
const listQuery = reactive({ ...defaultQuery })

const data = ref([])
const defaultProps = ref({
  children: 'children',
  label: 'name',
  isDisabled: 'disabled',
})

const { proxy } = getCurrentInstance() as any
const width = ref(0)
const height = ref(0)
const loading = ref(false)
const src = ref('')
const player = ref(null)
let treeClickCount = 0
let currentCameras: any = null
let isRecording = false

const resize = () => {
  const divPlugin = document.getElementById('home')
  width.value = divPlugin!.clientWidth - 40
  height.value = divPlugin!.clientHeight - 60
  if (player.value !== null) {
    player.value!.JS_Resize()
  }
}

function search() {
  play(currentCameras)
}

function handleDateChange(value: any) {
  if (value && value.length === 2) {
    listQuery.startTime = value[0]
    listQuery.endTime = value[1]

    const start = new Date(value[0])
    const end = new Date(value[1])
    const diff = end.getTime() - start.getTime()
    if (diff > (3 * 24 * 60 * 60 * 1000)) {
      ElMessage({
        message: '选定的日期范围不能超过三天',
        type: 'error',
      })
      timeRange.value = [dayjs(end.getTime() - 3 * 24 * 60 * 60 * 1000).format('YYYY-MM-DD HH:mm:ss'), value[1]]
    }
  }
}

function createPlayer() {
  player.value = new window.JSPlugin({
    szId: 'player',
    szBasePath: './',
    iMaxSplit: 1,
    iCurrentSplit: 2,
    openDebug: true,
    iWidth: width.value,
    iHeight: height.value,
    oStyle: {
      borderSelect: '#FFCC00',
    },
  })
}

function filterNode(value: any, data: { name: string | any[] }) {
  if (value === '' || value === null) {
    return true
  }
  return data.name.includes(value)
}

function recordStart() {
  if (currentCameras === null) {
    ElMessage({
      message: '视频录制需要有正在播放的回放',
      type: 'warning',
    })
    return
  }
  if (isRecording) {
    ElMessage({
      message: '正在录制中,请先结束录制',
      type: 'warning',
    })
    return
  }
  // const codeMap = { MP4: 5, PS: 2 }
  const time = dayjs().format('YYYY-MM-DD HH:mm:ss')
  const fileName = `${currentCameras.name}${time}.mp4`
  player.value!.JS_StartSaveEx(0, fileName, 5).then(
    () => {
      isRecording = true
      ElMessage({
        message: '开始录制',
        type: 'success',
      })
      log('开始录制视频', `${currentCameras.name}-开始录制时间:${time}`)
    },
    (e: any) => {
      ElMessage({
        message: '开始录制失败',
        type: 'error',
      })
    },
  )
}

function recordStop() {
  if (currentCameras === null) {
    ElMessage({
      message: '视频录制需要有正在播放的回放',
      type: 'warning',
    })
    return
  }
  if (!isRecording) {
    ElMessage({
      message: '请先开始录制',
      type: 'warning',
    })
    return
  }
  const time = dayjs().format('YYYY-MM-DD HH:mm:ss')
  player.value!.JS_StopSave(0).then(
    () => {
      isRecording = false
      log('结束录制视频', `${currentCameras.name}-结束录制时间:${time}`)
    },
    (e: any) => {
      ElMessage({
        message: '结束录制失败',
        type: 'error',
      })
    },
  )
}

async function play(data: any) {
  listQuery.startTime = timeRange.value[0]
  listQuery.endTime = timeRange.value[1]

  const playURL = await getPlaybackUrl(data.device.cameraIndexCode,
    `${listQuery.startTime.replace(' ', 'T')}.000+08:00`,
    `${listQuery.endTime.replace(' ', 'T')}.000+08:00`)
  player.value!.JS_Play(playURL, { playURL, mode: 0 }, 0,
    `${listQuery.startTime.replace(' ', 'T')}Z`,
    `${listQuery.endTime.replace(' ', 'T')}Z`).then(
    () => {
      console.log('playbackStart success')
    },
    (e: any) => { console.error(e) },
  )
  currentCameras = data
  // 提交日志
  log('场景回放', `${data.name}-回放时间:${listQuery.startTime}-${listQuery.endTime}`)
}

// 回放
async function handleNodeClick(data: any, node: any, self: any) {
  const now = new Date().getTime()
  console.log(now)
  if (now - treeClickCount < 300) { // 双击事件的判断,300毫秒内重复点击
    console.log('Double click on:', data)
    if (data.device === '') { // 点击父亲
      return
    }
    play(data)
  }
  treeClickCount = now
}

const unwatch = watch(filterText, (newVal) => {
  treeRef.value.filter(newVal)
})

// 搜索重置
function reset() {
  Object.assign(listQuery, defaultQuery)
  listQuery.startTime = dayjs(Date.now() - 3 * 24 * 60 * 60 * 1000).format('YYYY-MM-DD HH:mm:ss')
  listQuery.endTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
  listQuery.id = ''
  timeRange.value = [listQuery.startTime, listQuery.endTime]
}

onBeforeUnmount(() => {
  unwatch()
  window.removeEventListener('resize', resize)
})

function solveData(data: any) {
  data.forEach((item: any) => {
    if (item.device) {
      item.name = `${item.name} (${item.device.deviceStatusName})`
      console.log('修改后的name', item.name)
    }
    if (item.children && item.children.length) {
      solveData(item.children)
    }
  })
  return data
}

onMounted(() => {
  videoTree().then((response) => {
    if (response.code === 200) {
      data.value = response.data
      data.value = solveData(data.value)
    }
  })
  setTimeout(() => {
    window.addEventListener('resize', resize)
    resize()
    createPlayer()
    reset()
  }, 1000)
})
</script>

<template>
  <app-container style="height: calc(100vh - 110px)">
    <div style="display: flex;height: 100%">
      <el-card class="left">
        <el-input
          v-model="filterText"
          placeholder="设备名称过滤"
        />
        <el-tree
          ref="treeRef"
          class="filter-tree"
          style="width: 100%;height: 100%"
          :data="data"
          :filter-node-method="filterNode"
          node-key="id"
          :default-expand-all="true"
          :props="defaultProps"
          @node-click="handleNodeClick"
          >
          <template #default="{ node }">
            <span style="display: flex;align-items: center;">
              <el-icon v-if="node.label.slice(node.label.indexOf('(')) === '(在线)'" style="margin-right: 5px">
                <svg-icon name="icon-online" />
              </el-icon>
              <el-icon v-if="node.label.slice(node.label.indexOf('(')) === '(离线)'" style="margin-right: 5px">
                <svg-icon name="icon-offline" />
              </el-icon>
              <el-tooltip
                class="box-item"
                effect="dark"
                :content="node.label"
                placement="right"
              >
                <span v-if="node.label.indexOf('(') === -1">{{ node.label }}</span>
              </el-tooltip>
              <el-tooltip
                class="box-item"
                effect="dark"
                :content="node.label.slice(0, node.label.indexOf('('))"
                placement="right"
              >
                <span v-if="node.label.indexOf('(') !== -1" :style="{ 'color': node.label.slice(node.label.indexOf('(')) === '(在线)' ? '#0e932e' : '#606266', 'font-weight': node.label.slice(node.label.indexOf('(')) === '(在线)' ? 600 : 500 }">{{ node.label.slice(0, node.label.indexOf('(')) }}</span>
              </el-tooltip>
              <!-- <span v-if="node.label.slice(node.label.indexOf('(')) === '(在线)' || node.label.slice(node.label.indexOf('(')) === '(离线)'" :style="{ color: node.label.slice(node.label.indexOf('(')) === '(在线)' ? 'green' : 'red' ,  'font-weight': 600 }">{{ node.label.slice(node.label.indexOf('(')) }}</span> -->
            </span>
          </template>
        </el-tree>
      </el-card>
      <div id="home" class="right">
        <div style="display:flex;">
          <search-area :need-clear="true" @search="search" @clear="reset" style="width: calc(100% - 268px)">
            <search-item>
              <el-date-picker
                v-model="timeRange"
                type="datetimerange"
                range-separator="到"
                format="YYYY-MM-DD HH:mm:ss"
                value-format="YYYY-MM-DD HH:mm:ss"
                start-placeholder="开始时间"
                end-placeholder="结束时间"
                @change="handleDateChange"
                style="width: 450px;"
                :clearable="false"
              />
            </search-item>
          </search-area>
          <div style="position: absolute;right: 20px;top: 22px">
            <el-button type="primary" @click="recordStart()" plain>录制MP4</el-button>
            <el-button @click="recordStop" type="info" plain>停止录制并保存文件</el-button>
          </div>
        </div>
        <div id="player" :style="`width:${width}px;height:${height}px;`" style="margin: 0 10px"></div>
      </div>
    </div>
  </app-container>
</template>

<style lang="scss" scoped>
.left {
  width: 300px;
  height: 100%;
  padding: 10px;
  overflow-y: scroll;
}
.right {
  width: calc(100% - 310px);
  margin-left: 10px;
  background-color: white;
}
.video-container {
  display: flex;
  flex: 1;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  margin-bottom: 5px;
}
video {
  position: relative;
  object-fit: fill;
  overflow: hidden;
  background: #000;
}
</style>