Files
tangguo_admin/src/views/videoManagement/videoExamine/components/examine-all.vue
T
rootandClaude Opus 5 d999a5c0e6 Initial commit
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 12:02:35 +08:00

202 lines
4.7 KiB
Vue

<template>
<div class="examine-all">
<el-dialog
:title="title"
align="center"
:visible.sync="dialogVisible"
width="90%"
:close-on-click-modal="false"
:before-close="handleClose"
@opened="onOpened"
>
<div class="media-box">
<div
class="video-box"
v-for="(item, i) in list"
:key="item.url + '-' + i"
>
<div class="title" :title="item.title || '未知'">
{{ item.title || "未知" }}
</div>
<video
ref="videoEls"
class="preview-video"
controls
preload="auto"
playsinline
></video>
</div>
<div v-if="!list.length" class="empty-tip">当前列表没有可预览的视频</div>
</div>
</el-dialog>
</div>
</template>
<script>
import Hls from "hls.js";
import baseConfig from "@/utils/serverUrlConfig";
export default {
data() {
return {
title: "查看当前列表所有视频",
dialogVisible: false,
list: [],
hlsList: []
};
},
computed: {
token() {
return this.$store.state.token;
}
},
beforeDestroy() {
this.destroyPlayers();
},
methods: {
getVideoEl(i) {
const refs = this.$refs.videoEls;
if (!refs) return null;
return Array.isArray(refs) ? refs[i] : i === 0 ? refs : null;
},
destroyPlayers() {
this.hlsList.forEach(hls => {
if (hls) hls.destroy();
});
this.hlsList = [];
const refs = this.$refs.videoEls;
const videos = !refs ? [] : Array.isArray(refs) ? refs : [refs];
videos.forEach(video => {
if (!video) return;
video.pause();
video.removeAttribute("src");
video.load();
});
},
handleClose(done) {
this.destroyPlayers();
this.list = [];
this.dialogVisible = false;
if (typeof done === "function") {
done();
}
},
buildMediaUrl(url) {
if (!url) return "";
let path = String(url);
if (path.slice(0, 1) === "/") {
path = path.slice(1);
}
return (
baseConfig.baseServerUrl +
baseConfig.playVideoUrl +
path +
"?token=" +
this.token
);
},
initHlsPlayer(i, src) {
const video = this.getVideoEl(i);
if (!video || !src) return;
if (Hls.isSupported()) {
const hls = new Hls({
enableWorker: true,
maxBufferLength: 15,
maxMaxBufferLength: 180
});
this.hlsList[i] = hls;
hls.loadSource(src);
hls.attachMedia(video);
hls.on(Hls.Events.ERROR, (event, data) => {
if (!data.fatal || !this.hlsList[i]) return;
if (data.type === Hls.ErrorTypes.NETWORK_ERROR) {
this.hlsList[i].startLoad();
} else if (data.type === Hls.ErrorTypes.MEDIA_ERROR) {
this.hlsList[i].recoverMediaError();
} else {
this.hlsList[i].destroy();
this.hlsList[i] = null;
}
});
return;
}
// Safari 等原生 HLS
if (video.canPlayType("application/vnd.apple.mpegurl")) {
video.src = src;
}
},
initAllPlayers() {
if (!this.dialogVisible || !this.list.length) return;
// 先清旧实例,避免 opened / nextTick 重复初始化
this.destroyPlayers();
this.list.forEach((item, i) => {
this.initHlsPlayer(i, this.buildMediaUrl(item.url));
});
},
onOpened() {
this.$nextTick(() => {
this.initAllPlayers();
});
},
open(list) {
this.destroyPlayers();
this.list = (list || []).filter(item => item && item.url);
// 已打开时不会再触发 opened,需要手动初始化
if (this.dialogVisible) {
this.$nextTick(() => {
this.initAllPlayers();
});
return;
}
this.dialogVisible = true;
}
}
};
</script>
<style lang="scss">
.examine-all {
.media-box {
width: 100%;
height: 100%;
overflow: auto;
}
.el-dialog {
margin-top: 70px !important;
}
.el-dialog__body {
overflow: auto;
max-height: calc(100vh - 200px);
}
.empty-tip {
text-align: center;
color: #999;
padding: 40px 0;
}
.video-box {
width: 19%;
float: left;
height: 330px;
margin-left: 1%;
margin-bottom: 30px;
.preview-video {
width: 100%;
height: calc(100% - 30px);
background: #000;
object-fit: contain;
}
.title {
width: 100%;
height: 30px;
line-height: 30px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
</style>