Files
fengjie-datascreen/src/components/VideoDialog/index.vue
2025-03-25 12:41:26 +08:00

287 lines
7.0 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 class="dialog-box">
<div class="video">
<HlsPlayer :url="src" />
</div>
<!-- <video class="video" ref="videoRef" muted autoplay controls>
<source type="application/x-mpegURL" />
</video> -->
<div class="action-box">
<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 class="action-item">
<div
v-if="isCollect == 1"
class="video-follow"
@click.stop="handleCollect()"
>取消关注
</div>
<div
v-if="isCollect == 0"
class="video-unfollow"
@click.stop="handleCollect()"
>关注
</div>
</div>
</div>
</div>
<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 {
postVideoCollectApi
} from '@/api/monitor'
import { postVideoControlApi } from '@/api/monitor'
import pubSub from 'pubsub-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' // 停止操作
let ACTION = '0'
let command = ref('')
const props = defineProps({
src: {
type: String,
default: ''
},
cameraIndexCode: {
type: String,
default: ''
},
isCollect:{
type: Number,
default: 0
}
})
let colletCond = ref(0)
let modelValue = defineModel()
let videoRef = ref()
let webRtcServer = null
let hlsRef = null
watch(
() => props.isCollect,
(val) => {
if (val) {
console.log(val,'val 2222222222222222222222')
colletCond.value = val
// setTimeout(() => {
// init()
// }, 1000)
}else{
colletCond.value = 0
}
},
{
immediate: true
}
)
// 关注
const handleCollect = async (id, status, index) => {
// console.log(props.isCollect,777788888)
await postVideoCollectApi({
cameraIndexCode:props.cameraIndexCode,
isCollect: props.isCollect == 0 ? 1 : 0
})
if (props.isCollect == 0) {
props.isCollect = 1
} else {
props.isCollect = 0
}
pubSub.publish('videoCollect', props.cameraIndexCode)
modelValue.value = false
}
const handleAction = async (e) => {
if (e == STOP) {
ACTION = '1'
} else {
ACTION = '0'
command.value = e
}
await postVideoControlApi({
command: command.value,
action: ACTION,
cameraIndexCode: props.cameraIndexCode
})
if (e == STOP) {
command.value = ''
}
ElMessage({
message: '操作成功',
type: 'success'
})
}
const handleClose = () => {
if (hlsRef) {
hlsRef.destroy()
hlsRef = null
}
modelValue.value = false
}
const init = () => {
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
}
}
})
}
onMounted(()=>{
})
</script>
<style scoped lang="scss">
.video-follow,.video-unfollow {
// cursor: pointer;
// display: none;
// position: absolute;
// right: vw(8);
// top: vw(8);
// z-index: 9999;
// margin-left:vw(20);
padding: 0 vw(20);
height: vh(24);
text-align: center;
line-height: vh(24);
font-weight: 400;
font-size: vw(16);
color: #ffffff;
// background-image: url('@/assets/images/unfollow.png');
background-size: 100% 100%;
}
.video-item__follow {
// background-image: url('@/assets/images/unfollow.png');
}
.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%;
width: vw(1814);
height: vw(980);
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>