diff --git a/.eslintrc-auto-import.json b/.eslintrc-auto-import.json index 2ca3adf..d979925 100644 --- a/.eslintrc-auto-import.json +++ b/.eslintrc-auto-import.json @@ -5,6 +5,10 @@ "ComputedRef": true, "DirectiveBinding": true, "EffectScope": true, + "ElLoading": true, + "ElMessage": true, + "ElMessageBox": true, + "ElNotification": true, "ExtractDefaultPropTypes": true, "ExtractPropTypes": true, "ExtractPublicPropTypes": true, diff --git a/src/utils/video.ts b/src/utils/video.ts index 3ead0da..365986e 100644 --- a/src/utils/video.ts +++ b/src/utils/video.ts @@ -3,7 +3,8 @@ import { log } from 'node:console'; let hlsInstance: Hls | null = null; // let hlsRetryCount = 0; -export const initHls = (monitorVideoUrl, monitorVideoRef) => { +export const initHls = (monitorVideoUrl, monitorVideoRef, isDialogVisible?: () => boolean) => { + console.log('isDialogVisible', isDialogVisible); const url = monitorVideoUrl.value; const video = monitorVideoRef.value; if (!url || !video) return; @@ -39,6 +40,26 @@ export const initHls = (monitorVideoUrl, monitorVideoRef) => { // 加载成功,重置重试计数 // hlsRetryCount = 0; }); + // ★ 错误自动恢复:hls.js 拿到空 m3u8 或 ts 加载失败时自动重试 + hls.on(Hls.Events.ERROR, (event, data) => { + if (data.fatal && (!isDialogVisible || isDialogVisible())) { + switch (data.type) { + case Hls.ErrorTypes.NETWORK_ERROR: + hls.startLoad(); + ElMessage.error('网络错误, 请检查网络或重试'); + break; + case Hls.ErrorTypes.MEDIA_ERROR: + // 媒体解码错误 → 尝试恢复 + hls.recoverMediaError(); + break; + default: + // 其他致命错误 → 销毁,让下一次 initHls 重建 + hls.destroy(); + hlsInstance = null; + break; + } + } + }); hlsInstance = hls; } else if (video.canPlayType('application/vnd.apple.mpegurl')) { // Safari/原生支持 HLS diff --git a/src/views/equipmentList/list.vue b/src/views/equipmentList/list.vue index fe643e1..331b81c 100644 --- a/src/views/equipmentList/list.vue +++ b/src/views/equipmentList/list.vue @@ -255,7 +255,6 @@ import { addEquipment, getDevicetList, getDeviceInfo, delDevice, actDevice, updateDeviceInfo, drawInfo } from '@/api/equipmentList/index'; import { EquipmentList, DeviceInfoForm, AlarmAreaData } from '@/api/equipmentList/types'; import { DemoVO, DemoQuery, DemoForm } from '@/api/demo/demo/types'; -import { log } from 'node:console'; import { initHls, destroyHls } from '@/utils/video'; import { nextTick } from 'vue'; import { useVideosStore } from '@/store/modules/video'; @@ -472,7 +471,7 @@ const handleSee = async (row?: any) => { // 等待 DOM 更新后初始化 Hls await nextTick(); - initHls(monitorVideoUrl, monitorVideoRef); + initHls(monitorVideoUrl, monitorVideoRef, () => dialog1.visible); // 等待视频加载完成后初始化 ResizeObserver,以便能正确获取视频尺寸 initVideoResizeObserver(); @@ -757,7 +756,7 @@ const saveImage = async () => { const handleMonitorDialogOpen = () => { // 初始化 Hls 与 video - initHls(monitorVideoUrl, monitorVideoRef); + initHls(monitorVideoUrl, monitorVideoRef, () => dialog1.visible); initVideoResizeObserver(); monitorDrawCollecting.value = false; monitorDrawPoints.value = []; @@ -804,7 +803,7 @@ const handleRefresh = async () => { monitorVideoUrl.value = videosStore.hisUrl || ''; if (monitorVideoUrl.value) { await nextTick(); - initHls(monitorVideoUrl, monitorVideoRef); + initHls(monitorVideoUrl, monitorVideoRef, () => dialog1.visible); } };