<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>