|
<template>
<div class="page-main">
<t-button-group class="top-btn">
<t-button v-for="(item,index) in sceneList" :key="index" :value="item.monitorSceneId" :color="item.monitorSceneId === selectedMonitorScene ? 'primary' : 'secondary'" @click="tabClick(item.monitorSceneId)">
{{ item.monitorSceneName }}
</t-button>
</t-button-group>
<div class="page-top">
<span>风场:</span>
<t-select v-model="gateFieldData" clearable @change="getSceneList()">
<t-option v-for="(item,index) in organizationList" :key="index" :value="item.id">{{ item.name }}</t-option>
</t-select>
</div>
<div class="page-bottom grid-demo">
<t-col v-for="(item,index) in videoList" :span="viewLayoutSpan" :key="index" :value="item.resourceToolId" style="margin-top:24px">
<video-player
:ref="'video'+index"
:options="videoOptions[index]"
:playsinline="false"
:events="events"
class="vjs-custom-skin videoPlayer"
@dblclick="handlefullscreenchange"
></video-player>
</t-col>
<!-- <rtmp-video :list="getVideoPlayList(item)" @goDistinguishRecord="goDistinguishRecord(item.resourceToolId)" @videoReplay="handleReview"></rtmp-video> -->
</div>
<t-pager :page-size="videoPageSize" :current="videoCurrent" :total="videoTotal" :sizer-range="[ 1, 4, 9, 16 ]" class="pager" show-elevator @on-change="onChangeGate"></t-pager>
<replay-dialog :list="replayList" :visibled.sync="showReplayDialog" @get-list="queryMonitorVideoLog" />
</div>
</template>
<script>
import sysapi from '@/api/videoSurveillance'
import RtmpVideo from './components/rtmpVideoPlay'
import ReplayDialog from './components/ReplayDialog'
import formatDateTime from '@/utils/formatDateTime.js'
import videojs from 'video.js'
window.videojs = videojs
require('video.js/dist/lang/zh-CN.js')
require('video.js/dist/video-js.min.css')
export default {
components: { ReplayDialog, RtmpVideo },
filters: {
handleText (value) {
if (!value) return ''
if (value.length > 13) {
return value.slice(0, 13) + '...'
}
return value
}
},
data () {
return {
viewLayoutSpan: 3,
events: ['fullscreenchange'],
videoOptions: [],
videoCurrent: 1, // 大门分页数据
videoPageSize: 10, // 大门分页数据
videoTotal: 0, // 大门分页总数
tabId: 1,
paramsObj: { // 接口请求数据
page: 0,
limit: 10
},
organizationList: [], // 风场数据
gateFieldData: '',
videoList: [], // 场景数据列表
sceneList: [], // 场景列表
selectedMonitorScene: '', // 当前选择场景
videoPlayList: [],
showReplayDialog: false,
replayList: '',
beginDay: formatDateTime(new Date(+new Date() - 10 * 60 * 1000), 'yyyy-MM-dd hh:mm:ss'),
endDay: formatDateTime(new Date(), 'yyyy-MM-dd hh:mm:ss')
// beginDay: '2020-12-19 20:14:00',
// endDay: '2020-12-19 20:14:00'
}
},
computed: {
player() {
return this.$refs.videoPlayer1.player
}
},
mounted () {
this.getWindFiledList() // 获取风场列表
},
methods: {
// 修改视频组件控制栏的元素以及样式
async createMyButton () {
this.$nextTick(() => {
const bars = document.querySelectorAll('.vjs-control-bar')
let time = document.getElementsByClassName('vjs-current-time vjs-time-control vjs-control')
let start = document.getElementsByClassName('vjs-play-control vjs-control vjs-button')
let volume = document.getElementsByClassName('vjs-volume-panel vjs-control vjs-volume-panel-horizontal')
let text = document.getElementsByClassName('vjs-live-control vjs-control')
bars.forEach((item, index) => {
time.forEach(item => {
item.remove()
})
start.forEach(item => {
item.remove()
})
volume.forEach(item => {
item.remove()
})
text.forEach(item => {
item.remove()
})
let txt = document.createElement('span')
txt.innerHTML = '集控室(人脸识别)'
txt.style.marginLeft = '12px'
let btn = document.createElement('button')
btn.style.color = 'white'
btn.style.cursor = 'pointer'
btn.style.marginLeft = 'auto'
btn.className = 'aidicon aidicon-image-outline'
btn.setAttribute('title', '识别记录')
btn.addEventListener('click', () => {
this.goDistinguishRecord()
})
let btn1 = document.createElement('button')
btn1.style.color = 'white'
btn1.style.cursor = 'pointer'
btn1.className = 'aidicon aidicon-piechart-outline'
btn1.setAttribute('title', '视频回放')
btn1.addEventListener('click', () => {
this.handleReview(this.videoList[index].resourceToolId)
})
item.appendChild(txt)
item.appendChild(btn)
item.appendChild(btn1)
})
})
},
// 获取场景列表
getSceneList () {
this.sceneList = []
this.videoList = []
this.organizationList.forEach((element, index) => {
if (element.id === this.gateFieldData) {
sysapi.getMonitorScene(this.organizationList[index].id).then((resp) => {
this.sceneList = resp.data.data || []
if (resp.data.data[0].monitorViewLayout === '1X1') {
this.viewLayoutSpan = 10
this.videoPageSize = 1
} else if (resp.data.data[0].monitorViewLayout === '2X2') {
this.viewLayoutSpan = 6
this.videoPageSize = 4
} else if (resp.data.data[0].monitorViewLayout === '3X3') {
this.viewLayoutSpan = 4
this.videoPageSize = 9
} else if (resp.data.data[0].monitorViewLayout === '4X4') {
this.viewLayoutSpan = 3
this.videoPageSize = 16
}
this.tabClick(this.sceneList[0].monitorSceneId)
})
}
})
},
// 向服务器发送请求获取视频回放数据
async queryMonitorVideoLog (data) {
let res = []
if (data) {
res = await sysapi.queryMonitorVideoLog({ params: { id: this.replayId, ...data } })
} else {
res = await sysapi.queryMonitorVideoLog({ params: { id: this.replayId, beginDay: this.beginDay, endDay: this.endDay } })
}
if (res.status === 200) {
this.replayList = res.data.data
} else {
this.$Message.danger('视频列表数据获取失败!')
}
},
// 显示视频回放对话框
handleReview (id) {
this.replayId = id
this.queryMonitorVideoLog()
this.showReplayDialog = true
},
// 切换场景
async tabClick (id) {
this.selectedMonitorScene = id
this.paramsObj.page = 0
this.videoList = []
this.tabId = id
this.videoCurrent = 1
this.getVideoSurveillanceData()
},
// 获取风场下拉框列表
async getWindFiledList () {
sysapi.getDepartments().then(resp => {
this.organizationList = resp.data.data
this.gateFieldData = this.organizationList[0].id
this.getSceneList()
}, err => {
this.$Message.danger('获取风场列表失败!')
console.log(err)
})
},
handlefullscreenchange(val) {
// 因为我是又封装了一个组件,打印val会有相应所需的属性,全屏状态为:isFullscreen_
val.isFullscreen_ = !val.isFullscreen_
// this.$emit('fullscreenchange', val)
},
// 获得风场大门数据
getVideoSurveillanceData () {
var id = this.tabId
this.paramsObj.page = this.videoCurrent
sysapi.getVideoSurveillanceData({ params: { monitorSceneId: id } }).then(res => {
this.videoList = res.data.data
for (let i in res.data.data) {
let obj = {
autoplay: true, // 如果true,浏览器准备好时开始回放。
muted: true, // 默认情况下将会消除任何音频。
loop: false, // 导致视频一结束就重新开始。
preload: 'auto', // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
language: 'zh-CN',
aspectRatio: '13:10', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
// fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
// 是否流体自适应容器宽高
fluid: true,
// // 设置视频播放器的显示宽度(以像素为单位)
// width: '100px',
// // 设置视频播放器的显示高度(以像素为单位)
// height: '300px',
sources: [{
withCredentials: false,
type: 'application/x-mpegURL', // 这里的种类支持很多种:基本视频格式、直播、流媒体等,具体可以参看git网址项目
src: res.data.data[i].videoUrl // url地址
}],
flash: { hls: { withCredentials: false } },
html5: { hls: { withCredentials: false } },
notSupportedMessage: '此视频暂无法播放,请稍后再试', // 允许覆盖Video.js无法播放媒体源时显示的默认信息。
controlBar: {
timeDivider: false,
durationDisplay: false,
remainingTimeDisplay: false,
fullscreenToggle: true, // 全屏按钮,
pictureInPictureToggle: false
}
}
this.videoOptions.push(obj)
}
this.createMyButton()
})
},
// 进入识别记录界面
goDistinguishRecord (id) {
this.$router.push({ path: '/videoSurveillance/distinguishRecord', query: { videoId: id } })
},
// 风场大门分页
onChangeGate (val) {
this.videoCurrent = val
this.getVideoSurveillanceData()
}
}
}
</script>
<style lang="scss" scoped>
.page-main {
padding: 30px 24px 24px 24px;
.top-btn {
float: right;
}
.page-bottom {
display: flex;
width: 100%;
flex-wrap: wrap;
margin-left: -24px;
.card-video-first,
.card-video {
width: 354px;
height: 240px;
margin-top: 20px;
.card-image {
width: 100%;
height: 100%;
}
.bottom {
padding: 0 12px;
display: flex;
align-items: center;
background-color: rgba(0, 0, 0, 0.5);
height: 40px;
color: #fff;
font-size: 14px;
.bottom-btn {
color: #fff;
border: none;
padding: 0 !important;
&:hover {
color: #0089d4;
}
}
}
}
.card-video {
.card-footer {
padding: 0px 0 0 24px !important;
background: none;
width: 100%;
position: absolute;
border-top: none;
bottom: 0px;
}
.card-block,
.card-video-block {
margin-left: 24px;
padding: 0 !important;
}
}
}
.pager {
margin-right: auto;
margin: 21px 0px 24px 0;
float: right;
}
.vjs-custom-skin > .video-js .vjs-control-bar .vjs-fullscreen-control{
height:38px !important;
}
.video-js .vjs-control{
cursor: pointer;
width: 28px;
margin-right:12px;
}
.vjs-control-bar{
display: flex;
justify-content: center;
align-items: center;
}
.video-js button{
font-size:16px;
}
.aidicon-image-outline:hover{
color: #0089d4 !important;
}
.aidicon-piechart-outline:hover{
color: #0089d4 !important;
}
.vjs-icon-placeholder:hover{
color: #0089d4 !important;
}.vjs-icon-placeholder{
font-size: 13px;
display: flex;
justify-content: center;
align-items: center;
}
.vjs-tech {
pointer-events: none;
}
}
</style>
|