diff --git a/src/views/monitor/components/box-2.vue b/src/views/monitor/components/box-2.vue index cb1f7ff..ede3fbb 100644 --- a/src/views/monitor/components/box-2.vue +++ b/src/views/monitor/components/box-2.vue @@ -2,27 +2,24 @@
-
-
- - - {{ item.dictLabel }} +
+
+ + {{ item }} -
-
- 收藏夹 -
-
- - +
+
+ 收藏夹 +
+
@@ -52,7 +49,7 @@ alt="" /> {{resource.regions}} - +
- +
- +
@@ -202,18 +199,19 @@ postVideoControlApi, postVideoCollectApi } from '@/api/monitor' + import mpegtsjs from 'mpegts.js' import { debounce } from 'lodash' import pubSub from 'pubsub-js' import Hls from 'hls.js' - const Z00M_IN = 'ZOOM_IN' // 焦距变大 - const Z00M_OUT = 'ZOOM_OUT' // 焦距变小 - const UP = 'UP' // 上转 - const DOWN = 'DOWN' // 下转 - const LEFT = 'LEFT' // 左转 - const RIGHT = 'RIGHT' // 右转 - const STOP = 'STOP' // 停止操作 + const Z00M_IN = 'zoomin' // 焦距变大 + const Z00M_OUT = 'zoomout' // 焦距变小 + const UP = 'up' // 上转 + const DOWN = 'down' // 下转 + const LEFT = 'left' // 左转 + const RIGHT = 'right' // 右转 + const STOP = 'stop' // 停止操作 let ACTION = '0' const props = { @@ -249,41 +247,97 @@ let timer = null const postVideoRemain = async () => { - if(!videoList.value.length) return false; - timer = setInterval(() => { - postVideoRemainApi({ - cameraIndexCode: videoList.value.map((item) => item.cameraIndexCode) - }) - }, 2000) + // if(!videoList.value.length) return false; + // timer = setInterval(() => { + // postVideoRemainApi({ + // cameraIndexCode: videoList.value.map((item) => item.cameraIndexCode) + // }) + // }, 2000) } + const createPlayer = (cameraIndexCode,videoElement) => { + getPreviewUrlApi({ + type: 'hls', + cameraIndexCode: cameraIndexCode + }).then(res=>{ + const url = res.data.url; + if(url.startsWith('ws')){ + const player = mpegtsjs.createPlayer({ + url: url, + type: 'flv', + isLive: true, + hasAudio: false + }) + player.attachMediaElement(videoElement) + player.load() + player.play() + // 错误处理和重连机制 + player.on(mpegtsjs.Events.ERROR, (err) => { + console.error('播放器错误【'+cameraIndexCode+'】:', err) + player.unload(); + player.destroy(); + // 3 秒后尝试重新加载 + setTimeout(() => { + console.error('重新加载【'+cameraIndexCode+'】' ) + createPlayer(cameraIndexCode,videoElement); + }, 3000) - const initVideo = () => { - clearHlsRefs() - nextTick(() => { - videoList.value.forEach(async (item, index) => { - const video = document.getElementById(`monitorVideo${index}`) - const hls = new Hls({ + }) + player.on(mpegtsjs.Events.LOADING_COMPLETE, (err) => { + console.error('加载完成:', err) + }) + hlsRefs.push(player) + } + else{ + const player = new Hls({ maxBufferLength: 10, // 最大缓冲长度(秒) maxMaxBufferLength: 15, // 缓冲区长度的上限 maxBufferSize: 30 * 1000 * 1000 // 最大缓冲大小(字节) }) - hls.loadSource(item.hlsUrl) - hls.attachMedia(video) - hls.on(Hls.Events.MANIFEST_PARSED, () => { - video.play() + player.loadSource(url) + player.attachMedia(videoElement) + player.on(Hls.Events.MANIFEST_PARSED, () => { + videoElement.play() }) - hlsRefs.push(hls) + player.on(Hls.Events.ERROR, (event, data) => { + // 根据错误类型进行处理 + if (data.fatal) { + switch (data.type) { + case Hls.ErrorTypes.NETWORK_ERROR: + console.log('网络错误,尝试重新加载'); + player.startLoad(); + break; + case Hls.ErrorTypes.MEDIA_ERROR: + console.log('媒体错误,尝试修复'); + player.recoverMediaError(); + break; + default: + console.log('无法恢复的错误,销毁播放器'); + // hls.destroy(); + break; + } + } + }) + hlsRefs.push(player) + } + }) + } + const initVideo = () => { + clearHlsRefs() + nextTick(() => { + videoList.value.forEach(async (item, index) => { + const videoElement = document.getElementById(`monitorVideo${index}`) + createPlayer(item.cameraIndexCode,videoElement); }) }) } const onInput = debounce((e) => { - + if(e){ getVideoRegions('search') }else{ getVideoRegions() } - + }, 500) const clearHlsRefs = () => { if (hlsRefs.length > 0) { @@ -303,7 +357,7 @@ videoList.value = [] getVideoList() } - + } const getColletList = async () => { clearHlsRefs() @@ -338,30 +392,60 @@ initVideo() } let thisVideo = ref(null) - const handleItemVideo = (url, type, code,item) => { - thisVideo.value = item + const handleItemVideo = async (url, type, code, item) => { + let res = await getPreviewUrlApi({ + cameraIndexCode: code, + type: 'hls' + }) + url = res.data.url + thisVideo.value = item videoLog.value = 2 cameraIndexCode.value = code setTimeout(() => { - hlsRef = new Hls({ - maxBufferLength: 10, // 最大缓冲长度(秒) - maxMaxBufferLength: 15, // 缓冲区长度的上限 - maxBufferSize: 30 * 1000 * 1000 // 最大缓冲大小(字节) - }) - hlsRef.loadSource(url) - hlsRef.attachMedia(videoRef.value) - hlsRef.on(Hls.Events.MANIFEST_PARSED, () => { - videoRef.value.play() - }) + if (url.startsWith('ws')) { + hlsRef = mpegtsjs.createPlayer({ + url: url, + type: 'flv', + isLive: true, + hasAudio: false + }) + hlsRef.attachMediaElement(videoRef.value) + hlsRef.load() + hlsRef.play() + // 错误处理和重连机制 + hlsRef.on('error', (err) => { + console.error('播放器错误:', err) + // 3 秒后尝试重新加载 + hlsRef.unload() + hlsRef.destroy() + // 3 秒后尝试重新加载 + setTimeout(() => { + console.error('重新加载【' + cameraIndexCode + '】') + handleItemVideo(url, 101, code, item); + }, 3000) + }) + } else { + hlsRef = new Hls({ + maxBufferLength: 10, // 最大缓冲长度(秒) + maxMaxBufferLength: 15, // 缓冲区长度的上限 + maxBufferSize: 30 * 1000 * 1000 // 最大缓冲大小(字节) + }) + hlsRef.loadSource(url) + hlsRef.attachMedia(videoRef.value) + hlsRef.on(Hls.Events.MANIFEST_PARSED, () => { + videoRef.value.play() + }) + } + if (type == 100) initVideo() }, 1000) } const handleAction = async (e) => { + command.value = e if (e == STOP) { ACTION = '1' } else { ACTION = '0' - command.value = e } await postVideoControlApi({ action: ACTION, @@ -381,18 +465,17 @@ } const handleRegList = (item,i,x)=>{ regionList.value[i].resourcesList[x].show = !regionList.value[i].resourcesList[x].show - + } const handleCamera = async (itemCode,resource) => { show.value = true let res = await getPreviewUrlApi({ type: 'hls', - cameraIndexCode:itemCode + cameraIndexCode: itemCode }) - console.log(res,'rrrrrrrrrrrrrr') cameraIndexCode.value = itemCode; - isCollect.value = resource.isCollect - isDiy.value = resource.isDiy + isCollect.value = resource.isCollect + isDiy.value = resource.isDiy videoSrc.value = res.data.url } const handleCollect = async (id, status, index) => { @@ -451,7 +534,7 @@ let res = await getVideoListApi(params) total.value = res.total if (res.data.length > 0) { - + videoList.value = res.data // console.log(videoList.value,'1111111111111111111111') // postVideoRemain() @@ -485,13 +568,13 @@ break; default: console.log('无法恢复的错误,销毁播放器'); - + // hls.destroy(); break; } } }) - + hlsRefs.push(hls) }) }) @@ -520,7 +603,7 @@ cameraName: cameraName.value, businessScenicArea: params.businessScenicArea }) - + regionList.value = res.data regionList.value.videoResources = res.data.videoResources // regionList.value[0].show = true @@ -532,7 +615,7 @@ r.show = false }) }) - + if(search=='search'){ regionList.value.forEach((item,index)=>{ item.show = true @@ -541,7 +624,7 @@ }) }) } - + console.log(regionList.value, ' regionList.value') } const onMonitorChange = () => { @@ -557,8 +640,8 @@ getVideoType() getVideoRegions() },1500) - - + + }) } onMounted(() => { @@ -588,7 +671,7 @@