<template>
<div class="custom-video_container"
ref="custom-video_container"
@mouseover="handleControls($event, 'start')"
@mouseleave="handleControls($event, 'end')">
<video
class="custom-video_video"
ref="custom-video"
:poster="videoOption.poster">
<p>设备不支持</p>
</video>
<!-- 控制区域背景 -->
<transition name="fade">
<div class="custom-video_control"
v-show="!videoState.hideControl || !videoState.play">
<div class="row1">
<!-- 进度条 -->
<div class="custom-video_control-bg"
@mouseleave="handlePrograssleave"
@mousedown="handlePrograssDown"
@mouseup="handlePrograssUp"
@mousemove="handlePrograssMove">
<div class="custom-video_control-bg-outside"
ref="custom-video_control-bg-outside">
<span
class="custom-video_control-bg-inside"
ref="custom-video_control-bg-inside">
</span>
<span
class="custom-video_control-bg-inside-point"
ref="custom-video_control-bg-inside-point"
></span>
</div>
</div>
</div>
<div class="row2">
<div class="row2-left">
<!--播放按钮-->
<div class="custom-video-play-container">
<span
class="custom-video_play custom-video_play-play icon_icon_video_paly"
@click="play('btn')">
</span>
<span
class="custom-video_play custom-video_play-pause icon_icon_video_suspend"
@click="pause('btn')">
</span>
</div>
<!-- 时间 -->
<div class="custom-video_control-time">
<span>{{currentTime ? currentTime : '00:00'}}</span>
/
<span>{{duration ? duration : '00:00'}}</span>
</div>
</div>
<div class="row2-right">
<!-- 声音 -->
<div class="custom-video_control-voice"
@click="handelShowMultiple('in')"
@mouseleave="handelShowMultiple('out')">
<span class="custom-video_control-voice-play icon_icon_VMS_Set-up">
倍数
</span>
<ul v-show="voideoMultiple">
<li @click="changeMultiple(0.75)"
:class="multipleIndex === 0.75 ? 'checkedMultiple': ''">0.75倍
</li>
<li @click="changeMultiple(1)"
:class="multipleIndex === 1 ? 'checkedMultiple': ''">1倍
</li>
<li @click="changeMultiple(2)"
:class="multipleIndex === 2 ? 'checkedMultiple': ''">2倍
</li>
</ul>
</div>
<!--截图-->
<div class="custom-video_control-voice"
@click="handleScreenShot">
<span class="custom-video_control-voice-play el-icon-camera-solid">
截图
</span>
</div>
<!-- 全屏缩放 -->
<span
class="custom-video_control-full icon_icon_video_lessen"
@click="handleScreen"
></span>
</div>
</div>
</div>
</transition>
</div>
</template>
<script>
import flvjs from 'flv.js'
import $http from '@/utils/$http'
export default {
name: 'videoRecordplayer',
props: ['item'],
data() {
return {
checkFull: false,
isRecord: true,
videoOption: {
volume: 20
},
videoState: {
play: false,
hideControl: false,
distance: 0,
downState: false,
playState: false,
leftInit: 0,
screenState: false
},
voiceState: {
distance: 0,
downState: false,
topInit: 0
},
videoDom: null,
videoProOut: null,
videoPro: null,
videoPoi: null,
duration: 0,
currentTime: 0,
processWidth: 0,
voiceProOut: null,
voicePro: null,
voicePoi: null,
volProcessHeight: 0,
voideoMultiple: false,
multipleIndex: 1
}
},
created() {
window.addEventListener('resize', this.isFullScreen)
},
mounted() {
this.toScreen()
const videoDom = this.$refs['custom-video']
if (flvjs.isSupported) {
this.flvPlayer = flvjs.createPlayer({
type: 'flv',
hasAudio: false,
url: this.item.recordUrl
})
this.flvPlayer.attachMediaElement(videoDom)
this.flvPlayer.load()
this.flvPlayer.play()
this.videoDom = this.$refs['custom-video']
this.videoProOut = this.$refs['custom-video_control-bg-outside']
this.videoPro = this.$refs['custom-video_control-bg-inside']
this.videoPoi = this.$refs['custom-video_control-bg-inside-point']
this.voiceProOut = this.$refs['custom-video_control-voice-bg-outside']
this.voicePro = this.$refs['custom-video_control-voice-bg-inside']
this.voicePoi = this.$refs['custom-video_control-voice-bg-point']
this.processWidth = this.videoProOut.clientWidth
this.videoDom.volume = this.videoOption.volume / 100
this.initMedaData()
}
},
methods: {
initMedaData() {
this.videoDom.addEventListener('loadedmetadata', () => {
this.videoState.leftInit = this.getOffset(this.videoProOut).left
this.processWidth = this.videoProOut.clientWidth
if (this.videoDom.duration !== Infinity) {
this.duration = this.timeTranslate(this.videoDom.duration)
} else {
this.duration = '未知'
}
})
this.videoDom.addEventListener('click', () => {
if (this.videoDom.paused || this.videoDom.ended) {
if (this.videoDom.ended) {
this.videoDom.currentTime = 0
}
this.play('btn')
} else {
this.pause('btn')
}
})
this.videoDom.addEventListener('timeupdate', () => {
const percentage = 100 * this.videoDom.currentTime / this.videoDom.duration
this.videoPro.style.width = percentage + '%'
this.videoPoi.style.left = percentage + '%'
this.currentTime = this.timeTranslate(this.videoDom.currentTime)
})
this.videoDom.addEventListener('ended', () => {
this.videoPro.style.width = 0
this.videoPoi.style.left = 0
this.currentTime = 0
this.videoState.play = false
this.videoState.hideControl = false
})
},
play(flag) {
if (flag) this.videoState.playState = true
this.videoState.play = true
this.videoDom.play()
},
pause(flag) {
if (flag) this.videoState.playState = false
this.videoDom.pause()
this.videoState.play = false
},
handlePrograssDown(ev) {
this.videoState.downState = true
this.pause()
this.videoState.distance = ev.clientX - this.videoState.leftInit
},
handlePrograssMove(ev) {
if (!this.videoState.downState) return
let disX = ev.clientX - this.videoState.leftInit
if (disX > this.processWidth) {
disX = this.processWidth
}
if (disX < 0) {
disX = 0
}
this.videoState.distance = disX
this.videoDom.currentTime = this.videoState.distance / this.processWidth * this.videoDom.duration
},
handlePrograssleave() {
this.videoState.downState = false
},
handlePrograssUp() {
this.videoState.downState = false
this.videoDom.currentTime = 2
this.videoDom.currentTime = this.videoState.distance / this.processWidth * this.videoDom.duration
this.currentTime = this.timeTranslate(this.videoDom.currentTime)
},
handleControls(ev, flag) {
switch (flag) {
case 'start':
this.videoState.hideControl = false
break
case 'end':
this.videoState.hideControl = true
break
default:
break
}
},
handleScreen() {
this.$emit('closeVideo')
},
timeTranslate(t) {
let m = Math.floor(t / 60)
m < 10 && (m = '0' + m)
return m + ':' + (t % 60 / 100).toFixed(2).slice(-2)
},
getOffset(node, offset) {
if (!offset) {
offset = {}
offset.left = 0
offset.top = 0
}
if (node === document.body || node === null) {
return offset
}
offset.top += node.offsetTop
offset.left += node.offsetLeft
return this.getOffset(node.offsetParent, offset)
},
handelShowMultiple(type) {
if (type === 'in') this.voideoMultiple = true
else this.voideoMultiple = false
},
changeMultiple(speed) {
this.videoDom.playbackRate = speed
this.multipleIndex = speed
this.voideoMultiple = false
},
toScreen() {
let screenDom = this.$refs['custom-video_container']
if (screenDom.requestFullscreen) {
screenDom.requestFullscreen()
}
else if (screenDom.mozRequestFullScreen) {
screenDom.mozRequestFullScreen()
}
else if (screenDom.webkitRequestFullScreen) {
screenDom.webkitRequestFullScreen()
}
else if (screenDom.msRequestFullscreen) {
screenDom.msRequestFullscreen()
}
}
,
isFullScreen() {
let isFull = document.isFullScreen || document.mozIsFullScreen || document.webkitIsFullScreen
if (!isFull) this.$emit('closeVideo')
}
,
handleScreenShot() {
const video = this.$refs['custom-video']
const canvas = document.createElement('canvas')
const scale = 1
canvas.width = video.videoWidth * scale
canvas.height = video.videoHeight * scale
canvas
.getContext('2d')
.drawImage(video, 0, 0, canvas.width, canvas.height)
const base64src = canvas.toDataURL()
let obj = {
'groupId': this.item.ipcGroupId,
'ipcId': this.item.ipcId,
'ipcName': `ZC-${this.item.recordId}-SCREENSHOT-${new Date().getTime()}`,
'recordId': '',
'streamUrl': base64src
}
$http.post('/manager/recording/storageScreenshots', obj).then(res => {
if (res.status == 200) {
this.$message({
showClose: true,
message: '截图保存成功',
type: 'success'
})
}
})
}
},
beforeDestroy() {
window.removeEventListener('resize', this.isFullScreen)
}
}
</script>
<style lang="scss" scoped>
.custom-video_container {
width: 500px;
height: 300px;
margin: 0 auto;
position: relative;
overflow: hidden;
}
.custom-video_video {
width: 100%;
height: 100%;
object-fit: fill;
}
.custom-video-play-container {
width: 100px;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.custom-video_play {
display: inline-block;
width: 50%;
text-align: center;
color: #f0f0f0;
}
.custom-video_play:hover {
box-shadow: 0 0 10px #5A4180;
transition: all 0.4s;
}
.custom-video_control {
position: absolute;
width: 100%;
left: 0;
bottom: 0;
background-color: rgba(0, 0, 0, .55);
display: flex;
flex-direction: column;
justify-content: space-between;
}
.row1 {
height: 32px;
}
.row2 {
height: 26px;
display: flex;
justify-content: space-between;
padding-bottom: 10px;
}
.row2-left,
.row2-right {
display: flex;
}
.custom-video_control-bg {
flex: 1;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
margin: 0 10px;
}
.custom-video_control-bg-outside {
width: 100%;
height: 5px;
border-radius: 2.5px;
background-color: #aaa;
position: relative;
cursor: pointer;
}
.custom-video_control-bg-inside {
position: absolute;
display: inline-block;
width: 0;
height: 100%;
border-radius: 2.5px;
left: 0;
top: 0;
background-color: #fff;
transition: all 0.2s;
}
.custom-video_control-bg-inside-point {
display: inline-block;
width: 10px;
height: 10px;
background-color: #fff;
border-radius: 50%;
position: absolute;
top: -2.5px;
left: -1%;
transition: all 0.2s;
}
.custom-video_control-voice,
.custom-video_control-time,
.custom-video_control-full {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
color: #fff;
position: relative;
height: 100%;
}
.custom-video_control-voice:hover > .custom-video_control-voice-bg {
display: block;
}
.custom-video_control-voice-play {
z-index: 10;
}
.custom-video_control-voice-bg {
display: none;
position: absolute;
width: 30px;
height: 100px;
background-color: rgba(0, 0, 0, .55);
left: 0;
bottom: 0px;
border-radius: 15px;
}
.custom-video_control-voice-bg-outside {
width: 5px;
height: 70px;
border-radius: 2.5px;
background-color: #aaa;
position: absolute;
left: 50%;
transform: translate3d(-50%, 10%, 0);
cursor: pointer;
}
.custom-video_control-voice-bg-inside {
display: inline-block;
position: absolute;
width: 100%;
bottom: 0;
left: 0;
border-radius: 2.5px;
background-color: #fff;
height: 0;
}
.custom-video_control-voice-bg-point {
display: inline-block;
width: 10px;
height: 10px;
background-color: #fff;
border-radius: 50%;
position: absolute;
left: -2.5px;
bottom: -1px;
}
.custom-video_control-time {
font-size: 12px;
}
.custom-video_control-full {
font-size: 14px;
}
.custom-video_control-voice,
.custom-video_control-full {
height: 30px;
margin: 0 10px;
cursor: pointer;
}
.fade-enter-active {
transition: all .3s ease;
}
.fade-leave-active {
transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.fade-enter, .fade-leave-to {
transform: translateY(50px);
opacity: 0;
}
ul {
position: absolute;
bottom: 25px;
width: 100%;
text-align: center;
background: rgba(255, 255, 255, 0.1);
border-radius: 4px;
padding: 0 10px;
}
ul > li {
height: 35px;
line-height: 35px;
}
.checkedMultiple {
color: #328cfa;
}
</style>