Files
fengjie-datascreen/src/components/VideoDialog/index.vue
2025-02-22 12:59:47 +08:00

222 lines
5.7 KiB
Vue

<template>
<div class="dialog">
<el-dialog
v-model="modelValue"
align-center
:modal="false"
:show-close="false"
:z-index="9999"
destroy-on-close
>
<div v-if="src" class="dialog-box">
<video class="video" ref="videoRef" muted autoplay controls>
<source type="application/x-mpegURL" />
</video>
<!-- <video class="video" id="bigVideo" muted autoplay controls style="object-fit: cover" /> -->
<div class="action-box">
<!-- <div class="action-item">
<img src="@/assets/images/plus.png" alt="" />
<span>变倍</span>
<img src="@/assets/images/minus.png" alt="" />
</div> -->
<div class="action-item">
<img src="@/assets/images/plus.png" title="焦距变大" @click="handleAction(Z00M_IN)" />
<span>聚焦</span>
<img src="@/assets/images/minus.png" title="焦距变小" @click="handleAction(Z00M_OUT)" />
</div>
<div class="action-item">
<img src="@/assets/images/up.png" title="上转" @click="handleAction(UP)" />
<img src="@/assets/images/down.png" title="下转" @click="handleAction(DOWN)" />
<img
class="pause"
src="@/assets/images/pause.png"
title="停止操作"
@click="handleAction(STOP)"
/>
<img src="@/assets/images/left.png" title="左转" @click="handleAction(LEFT)" />
<img src="@/assets/images/right.png" title="右转" @click="handleAction(RIGHT)" />
</div>
</div>
</div>
<p v-else class="none">暂无信号</p>
<img class="close" src="@/assets/images/close.png" @click="handleClose" />
</el-dialog>
</div>
</template>
<script setup>
import Hls from 'hls.js'
import { ElMessage } from 'element-plus'
import { postVideoControlApi } from '@/api/monitor'
import { mode, baseUrl, proBaseUrl } from '@/utils/config'
const Z00M_IN = 'ZOOM_IN' // 焦距变大
const Z00M_OUT = 'ZOOM_OUT' // 焦距变小
const ACTION = '0'
const UP = 'UP' // 上转
const DOWN = 'DOWN' // 下转
const LEFT = 'LEFT' // 左转
const RIGHT = 'RIGHT' // 右转
const STOP = 'STOP' // 停止操作
const props = defineProps({
src: {
type: String,
default: ''
},
cameraIndexCode: {
type: String,
default: ''
}
})
let modelValue = defineModel()
let videoRef = ref()
let webRtcServer = null
let hlsRef = null
watch(
() => modelValue.value,
(val) => {
if (val) {
setTimeout(() => {
init()
}, 1000)
}
},
{
immediate: true
}
)
const handleAction = async (e) => {
if (e == STOP) {
ACTION = '1'
} else {
ACTION = '0'
}
await postVideoControlApi({
command: e,
action: ACTION,
cameraIndexCode: props.cameraIndexCode
})
ElMessage({
message: '操作成功',
type: 'success'
})
}
const handleClose = () => {
// webRtcServer.disconnect()
hlsRef.destroy()
hlsRef = null
modelValue.value = false
}
const init = () => {
// webRtcServer = new WebRtcStreamer('bigVideo', `${mode == 'dev' ? baseUrl : proBaseUrl}/webrtc`)
// webRtcServer.connect(props.src)
hlsRef = new Hls({
enableWorker: false, // 禁用 Worker 来避免额外的线程
enableSoftwareAES: true, // 使用软件解码器以避免硬件解码的额外请求
cache: true, // 启用缓存
maxBufferLength: 10, // 最大缓冲长度(秒)
maxMaxBufferLength: 15, // 缓冲区长度的上限
maxBufferSize: 20 * 1000 * 1000 // 最大缓冲大小(字节)
})
hlsRef.loadSource(props.src)
hlsRef.attachMedia(videoRef.value)
hlsRef.on(Hls.Events.MANIFEST_PARSED, () => {
videoRef.value.play()
})
hlsRef.on(Hls.Events.ERROR, (event, data) => {
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
hlsRef.startLoad()
break
case Hls.ErrorTypes.MEDIA_ERROR:
hlsRef.recoverMediaError()
break
default:
hlsRef.destroy()
break
}
}
})
}
</script>
<style scoped lang="scss">
.dialog {
z-index: 9999;
.action {
&-box {
margin-top: vh(16);
gap: vw(20);
display: flex;
align-items: center;
justify-content: center;
}
&-item {
padding: vw(16);
display: flex;
align-items: center;
background: #0a4190;
border-radius: vw(8);
> img {
cursor: pointer;
width: vw(34);
height: auto;
}
> span {
margin: 0 vw(16);
font-weight: 400;
font-size: vw(16);
color: #ffffff;
}
.pause {
margin: 0 vw(10);
}
}
}
.none {
position: absolute;
left: 50%;
top: 50%;
color: #fff;
font-weight: bold;
font-size: vw(30);
transform: translate(-50%, -50%);
z-index: 999;
}
:deep(.el-dialog) {
position: relative;
width: vw(1940);
background: transparent !important;
}
.dialog-box {
padding: vw(40) vw(30) vw(30) vw(30);
background-image: url('@/assets/images/video-bg.png');
background-size: 100% 100%;
}
:deep(.el-dialog__header) {
padding-bottom: 0 !important;
}
.video {
width: vw(1814);
height: vw(980);
object-fit: contain;
background-color: #062b57;
}
.close {
cursor: pointer;
position: absolute;
right: vw(70);
top: vw(80);
width: vw(60);
z-index: 9999;
}
}
</style>