mirror of
https://gitee.com/pan648540858/wvp-GB28181-pro.git
synced 2026-06-22 02:57:49 +08:00
优化云端录像播放结构
This commit is contained in:
parent
c59bacdc2c
commit
d3e89786c2
@ -180,8 +180,6 @@ import devicePlayer from '@/views/common/channelPlayer/index.vue'
|
||||
import Edit from './edit.vue'
|
||||
import ChooseCivilCode from '../dialog/chooseCivilCode.vue'
|
||||
import ChooseGroup from '@/views/dialog/chooseGroup.vue'
|
||||
import { MessageBox } from 'element-ui'
|
||||
import store from '@/store'
|
||||
|
||||
export default {
|
||||
name: 'ChannelList',
|
||||
|
||||
@ -1,452 +0,0 @@
|
||||
<template>
|
||||
<div id="cloudRecordPlayer" style="height: 100%">
|
||||
<div class="cloud-record-playBox" :style="playBoxStyle">
|
||||
<jessibucaPlayer
|
||||
v-if="playerType === 'Jessibuca'"
|
||||
ref="recordVideoPlayer"
|
||||
:height="'calc(100% - 250px)'"
|
||||
:show-button="false"
|
||||
@playTimeChange="showPlayTimeChange"
|
||||
@playStatusChange="playingChange"
|
||||
fluent
|
||||
autoplay
|
||||
live
|
||||
/>
|
||||
<rtcPlayer
|
||||
v-if="playerType === 'WebRTC'"
|
||||
ref="recordVideoPlayer"
|
||||
:has-audio="true"
|
||||
:show-controls="false"
|
||||
style="height: calc(100% - 250px)"
|
||||
autoplay
|
||||
@playTimeChange="showPlayTimeChange"
|
||||
@playStatusChange="playingChange"
|
||||
/>
|
||||
<h265web v-if="playerType === 'H265web'" ref="recordVideoPlayer" :height="'calc(100% - 250px)'" :show-button="false" @playTimeChange="showPlayTimeChange" @playStatusChange="playingChange"/>
|
||||
</div>
|
||||
<div class="cloud-record-player-option-box">
|
||||
<div class="cloud-record-show-time">
|
||||
{{showPlayTimeValue}}
|
||||
</div>
|
||||
<div class="cloud-record-time-process" ref="timeProcess" @click="timeProcessClick($event)"
|
||||
@mouseenter="timeProcessMouseEnter($event)" @mousemove="timeProcessMouseMove($event)"
|
||||
@mouseleave="timeProcessMouseLeave($event)">
|
||||
<div v-if="streamInfo">
|
||||
<div class="cloud-record-time-process-value" :style="playTimeValue"></div>
|
||||
<transition name="el-fade-in-linear">
|
||||
<div v-show="showTimeLeft" class="cloud-record-time-process-title" :style="playTimeTitleStyle" >{{showPlayTimeTitle}}</div>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cloud-record-show-time">
|
||||
{{showPlayTimeTotal}}
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 40px; background-color: #383838; display: grid; grid-template-columns: 1fr auto 1fr">
|
||||
<div style="text-align: left;">
|
||||
<div class="cloud-record-record-play-control" style="background-color: transparent; box-shadow: 0 0 10px transparent">
|
||||
<a v-if="showListCallback" target="_blank" class="cloud-record-record-play-control-item iconfont icon-list" title="列表" @click="sidebarControl()" />
|
||||
<a target="_blank" class="cloud-record-record-play-control-item iconfont icon-camera1196054easyiconnet" title="截图" @click="snap()" />
|
||||
<!-- <a target="_blank" class="cloud-record-record-play-control-item iconfont icon-shuaxin11" title="刷新" @click="refresh()" />-->
|
||||
<!-- <a target="_blank" class="cloud-record-record-play-control-item iconfont icon-xiazai011" title="下载" />-->
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: center;">
|
||||
<div class="cloud-record-record-play-control">
|
||||
<a v-if="!lastDiable" target="_blank" class="cloud-record-record-play-control-item iconfont icon-diyigeshipin" title="上一个" @click="playLast()" />
|
||||
<a v-else style="color: #acacac; cursor: not-allowed" target="_blank" class="cloud-record-record-play-control-item iconfont icon-diyigeshipin" title="上一个" />
|
||||
<a target="_blank" class="cloud-record-record-play-control-item iconfont icon-kuaijin" title="快退五秒" @click="seekBackward()" />
|
||||
<a target="_blank" class="cloud-record-record-play-control-item iconfont icon-stop1" style="font-size: 14px" title="停止" @click="stopPLay()" />
|
||||
<a v-if="playing" target="_blank" class="cloud-record-record-play-control-item iconfont icon-zanting" title="暂停" @click="pausePlay()" />
|
||||
<a v-if="!playing" target="_blank" class="cloud-record-record-play-control-item iconfont icon-kaishi" title="播放" @click="play()" />
|
||||
<a target="_blank" class="cloud-record-record-play-control-item iconfont icon-houtui" title="快进五秒" @click="seekForward()" />
|
||||
<a v-if="!nextDiable" target="_blank" class="cloud-record-record-play-control-item iconfont icon-zuihouyigeshipin" title="下一个" @click="playNext()" />
|
||||
<a v-else style="color: #acacac; cursor: not-allowed" target="_blank" class="cloud-record-record-play-control-item iconfont icon-zuihouyigeshipin" title="下一个" @click="playNext()" />
|
||||
<el-dropdown @command="changePlaySpeed" :popper-append-to-body='false' >
|
||||
<a target="_blank" class="cloud-record-record-play-control-item record-play-control-speed" title="倍速播放">{{ playSpeed }}X</a>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item
|
||||
v-for="item in playSpeedRange"
|
||||
:key="item"
|
||||
:command="item"
|
||||
>{{ item }}X</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: right;">
|
||||
<div class="cloud-record-record-play-control" style="background-color: transparent; box-shadow: 0 0 10px transparent">
|
||||
<div class="cloud-record-record-play-control-item record-play-control-player">
|
||||
|
||||
<el-dropdown @command="changePlayerType" :popper-append-to-body='false' >
|
||||
<a target="_blank" class="cloud-record-record-play-control-item record-play-control-speed" title="选择播放器">{{ playerLabel }}</a>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="Jessibuca" >Jessibuca</el-dropdown-item>
|
||||
<el-dropdown-item command="WebRTC" >WebRTC</el-dropdown-item>
|
||||
<el-dropdown-item command="H265web" >H265web</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<a v-if="!isFullScreen" target="_blank" class="cloud-record-record-play-control-item iconfont icon-fangdazhanshi" title="全屏" @click="fullScreen()" />
|
||||
<a v-else target="_blank" class="cloud-record-record-play-control-item iconfont icon-suoxiao1" title="全屏" @click="fullScreen()" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import h265web from '../common/h265web.vue'
|
||||
import jessibucaPlayer from '@/views/common/jessibuca.vue'
|
||||
import rtcPlayer from '../common/rtcPlayer.vue'
|
||||
import moment from 'moment'
|
||||
import momentDurationFormatSetup from 'moment-duration-format'
|
||||
import screenfull from 'screenfull'
|
||||
|
||||
momentDurationFormatSetup(moment)
|
||||
|
||||
export default {
|
||||
name: 'CloudRecordPlayer',
|
||||
components: {
|
||||
jessibucaPlayer, rtcPlayer, h265web
|
||||
},
|
||||
props: ['showListCallback', 'showNextCallback', 'showLastCallback', 'lastDiable', 'nextDiable'],
|
||||
data() {
|
||||
return {
|
||||
showSidebar: false,
|
||||
videoUrl: null,
|
||||
streamInfo: null,
|
||||
timeLen: null,
|
||||
startTime: null,
|
||||
showTimeLeft: null,
|
||||
isMousedown: false,
|
||||
loading: false,
|
||||
playerTime: null,
|
||||
playSpeed: 1,
|
||||
playLoading: false,
|
||||
isFullScreen: false,
|
||||
playing: false,
|
||||
initTime: null,
|
||||
playerType: 'Jessibuca',
|
||||
playerUrls: {
|
||||
Jessibuca: ['ws_flv', 'wss_flv'],
|
||||
WebRTC: ['rtc', 'rtcs'],
|
||||
H265web: ['ws_flv', 'wss_flv']
|
||||
},
|
||||
playSpeedRange: [1, 2, 4, 6, 8, 16, 20]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
playBoxStyle() {
|
||||
return this.isFullScreen ? { height: 'calc(100vh - 61px)' } : { height: '100%' }
|
||||
},
|
||||
showPlayTimeValue() {
|
||||
return this.streamInfo === null ? '--:--:--' : moment.duration(this.playerTime, 'milliseconds').format('hh:mm:ss', {
|
||||
trim: false
|
||||
})
|
||||
},
|
||||
playTimeValue() {
|
||||
return { width: this.playerTime/this.streamInfo.duration * 100 + '%' }
|
||||
},
|
||||
showPlayTimeTotal() {
|
||||
if (this.streamInfo === null) {
|
||||
return '--:--:--'
|
||||
}else {
|
||||
return moment.duration(this.streamInfo.duration, 'milliseconds').format('hh:mm:ss', {
|
||||
trim: false
|
||||
})
|
||||
}
|
||||
},
|
||||
playTimeTotal() {
|
||||
return { left: `calc(${this.playerTime/this.streamInfo.duration * 100}% - 6px)` }
|
||||
},
|
||||
playTimeTitleStyle() {
|
||||
return { left: (this.showTimeLeft - 16) + 'px' }
|
||||
},
|
||||
showPlayTimeTitle() {
|
||||
if (this.showTimeLeft) {
|
||||
let time = this.showTimeLeft / this.$refs.timeProcess.clientWidth * this.streamInfo.duration
|
||||
let realTime = this.timeLen/this.streamInfo.duration * time + this.startTime
|
||||
return `${moment(time).format('mm:ss')}(${moment(realTime).format('HH:mm:ss')})`
|
||||
}else {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
playerLabel() {
|
||||
const labels = { Jessibuca: 'Jessibuca', WebRTC: 'WebRTC', H265web: 'H265Web' }
|
||||
return labels[this.playerType] || 'Jessibuca'
|
||||
}
|
||||
},
|
||||
created() {
|
||||
document.addEventListener('mousemove', this.timeProcessMousemove)
|
||||
document.addEventListener('mouseup', this.timeProcessMouseup)
|
||||
},
|
||||
mounted() {},
|
||||
destroyed() {
|
||||
this.$destroy('recordVideoPlayer')
|
||||
},
|
||||
methods: {
|
||||
timeProcessMouseup(event) {
|
||||
this.isMousedown = false
|
||||
},
|
||||
timeProcessMousemove(event) {
|
||||
|
||||
},
|
||||
timeProcessClick(event) {
|
||||
let x = event.offsetX
|
||||
let clientWidth = this.$refs.timeProcess.clientWidth
|
||||
this.seekRecord(x / clientWidth * this.streamInfo.duration)
|
||||
},
|
||||
timeProcessMousedown(event) {
|
||||
this.isMousedown = true
|
||||
},
|
||||
timeProcessMouseEnter(event) {
|
||||
this.showTimeLeft = event.offsetX
|
||||
},
|
||||
timeProcessMouseMove(event) {
|
||||
this.showTimeLeft = event.offsetX
|
||||
},
|
||||
timeProcessMouseLeave(event) {
|
||||
this.showTimeLeft = null
|
||||
},
|
||||
sidebarControl() {
|
||||
this.showSidebar = !this.showSidebar
|
||||
this.showListCallback(this.showSidebar)
|
||||
},
|
||||
snap() {
|
||||
this.$refs.recordVideoPlayer.screenshot()
|
||||
},
|
||||
refresh() {
|
||||
this.$refs.recordVideoPlayer.destroy()
|
||||
this.$refs.recordVideoPlayer.playBtnClick()
|
||||
},
|
||||
playLast() {
|
||||
this.showLastCallback()
|
||||
},
|
||||
playNext() {
|
||||
this.showNextCallback()
|
||||
},
|
||||
changePlaySpeed(speed) {
|
||||
// 倍速播放
|
||||
this.playSpeed = speed
|
||||
this.$store.dispatch('cloudRecord/speed', {
|
||||
mediaServerId: this.streamInfo.mediaServerId,
|
||||
app: this.streamInfo.app,
|
||||
stream: this.streamInfo.stream,
|
||||
key: this.streamInfo.key,
|
||||
speed: this.playSpeed,
|
||||
schema: 'ts'
|
||||
})
|
||||
this.$refs.recordVideoPlayer.setPlaybackRate(this.playSpeed)
|
||||
},
|
||||
changePlayerType(playerType) {
|
||||
if (this.playerType === playerType) {
|
||||
return
|
||||
}
|
||||
this.playerType = playerType
|
||||
if (this.streamInfo) {
|
||||
this.videoUrl = this.getUrlByStreamInfo()
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.recordVideoPlayer) {
|
||||
this.$refs.recordVideoPlayer.play(this.videoUrl)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
seekBackward() {
|
||||
// 快退五秒
|
||||
this.seekRecord(this.playerTime - 5 * 1000)
|
||||
},
|
||||
seekForward() {
|
||||
// 快进五秒
|
||||
this.seekRecord(this.playerTime + 5 * 1000)
|
||||
},
|
||||
stopPLay() {
|
||||
// 停止
|
||||
if (this.$refs.recordVideoPlayer) {
|
||||
this.$refs.recordVideoPlayer.destroy()
|
||||
}
|
||||
this.streamInfo = null
|
||||
this.playerTime = null
|
||||
this.playSpeed = 1
|
||||
},
|
||||
pausePlay() {
|
||||
// 暂停
|
||||
this.$refs.recordVideoPlayer.pause()
|
||||
// TODO
|
||||
},
|
||||
play() {
|
||||
if (this.$refs.recordVideoPlayer.loaded) {
|
||||
this.$refs.recordVideoPlayer.unPause()
|
||||
} else {
|
||||
this.playRecord()
|
||||
}
|
||||
},
|
||||
fullScreen() {
|
||||
// 全屏
|
||||
if (this.isFullScreen) {
|
||||
screenfull.exit()
|
||||
this.isFullScreen = false
|
||||
return
|
||||
}
|
||||
const playerWidth = this.$refs.recordVideoPlayer.playerWidth
|
||||
const playerHeight = this.$refs.recordVideoPlayer.playerHeight
|
||||
screenfull.request(document.getElementById('cloudRecordPlayer'))
|
||||
screenfull.on('change', (event) => {
|
||||
this.$refs.recordVideoPlayer.resize(playerWidth, playerHeight)
|
||||
this.isFullScreen = screenfull.isFullscreen
|
||||
})
|
||||
this.isFullScreen = true
|
||||
},
|
||||
setStreamInfo(streamInfo, timeLen, startTime) {
|
||||
const keys = this.playerUrls[this.playerType]
|
||||
if (location.protocol === 'https:') {
|
||||
this.videoUrl = streamInfo[keys[1]]
|
||||
} else {
|
||||
this.videoUrl = streamInfo[keys[0]]
|
||||
}
|
||||
console.log(location.protocol)
|
||||
this.streamInfo = streamInfo
|
||||
this.timeLen = timeLen
|
||||
this.startTime = startTime
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.recordVideoPlayer) {
|
||||
this.$refs.recordVideoPlayer.play(this.videoUrl)
|
||||
}
|
||||
})
|
||||
},
|
||||
getUrlByStreamInfo() {
|
||||
if (!this.streamInfo) return ''
|
||||
const keys = this.playerUrls[this.playerType]
|
||||
if (location.protocol === 'https:') {
|
||||
this.videoUrl = this.streamInfo[keys[1]]
|
||||
} else {
|
||||
this.videoUrl = this.streamInfo[keys[0]]
|
||||
}
|
||||
return this.videoUrl
|
||||
},
|
||||
seekRecord(playSeekValue, callback) {
|
||||
this.$store.dispatch('cloudRecord/seek', {
|
||||
mediaServerId: this.streamInfo.mediaServerId,
|
||||
app: this.streamInfo.app,
|
||||
stream: this.streamInfo.stream,
|
||||
seek: playSeekValue,
|
||||
schema: 'fmp4'
|
||||
})
|
||||
.then((data) => {
|
||||
this.playerTime = playSeekValue
|
||||
if (callback) {
|
||||
callback(playSeekValue)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error)
|
||||
})
|
||||
},
|
||||
showPlayTimeChange(val) {
|
||||
console.log(val)
|
||||
if (Number(val)) {
|
||||
this.playerTime = Number(val)
|
||||
}
|
||||
},
|
||||
playingChange(val) {
|
||||
this.playing = val
|
||||
if (!val) {
|
||||
this.stopPLay()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.cloud-record-playBox {
|
||||
width: 100%;
|
||||
background-color: #000000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.cloud-record-record-play-control {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
display: inline-block;
|
||||
width: fit-content;
|
||||
padding: 0 10px;
|
||||
-webkit-box-shadow: 0 0 10px #262626;
|
||||
box-shadow: 0 0 10px #262626;
|
||||
background-color: #262626;
|
||||
margin: 4px 0;
|
||||
}
|
||||
.cloud-record-record-play-control-item {
|
||||
display: inline-block;
|
||||
padding: 0 10px;
|
||||
color: #fff;
|
||||
margin-right: 2px;
|
||||
}
|
||||
.cloud-record-record-play-control-item:hover {
|
||||
color: #1f83e6;
|
||||
}
|
||||
.cloud-record-record-play-control-speed {
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
user-select: none;
|
||||
}
|
||||
.cloud-record-player-option-box {
|
||||
height: 20px;
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: 70px auto 70px;
|
||||
background-color: rgb(0, 0, 0);
|
||||
}
|
||||
.cloud-record-time-process {
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
margin: 6px 0 ;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #505050;
|
||||
background-color: rgb(56, 56, 56);
|
||||
cursor: pointer;
|
||||
}
|
||||
.cloud-record-show-time {
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
line-height: 20px
|
||||
}
|
||||
.cloud-record-time-process-value {
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
background-color: rgb(162, 162, 162);
|
||||
}
|
||||
.cloud-record-time-process-value1::after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background-color: rgb(192 190 190);
|
||||
border-radius: 5px;
|
||||
position: relative;
|
||||
top: -3px;
|
||||
right: -6px;
|
||||
float: right;
|
||||
}
|
||||
.cloud-record-time-process-title {
|
||||
width: fit-content;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
top: -35px;
|
||||
color: rgb(217, 217, 217);
|
||||
font-size: 14px;
|
||||
text-shadow:
|
||||
-1px -1px 0 black, /* 左上角阴影 */
|
||||
1px -1px 0 black, /* 右上角阴影 */
|
||||
-1px 1px 0 black, /* 左下角阴影 */
|
||||
1px 1px 0 black; /* 右下角阴影 */
|
||||
}
|
||||
.record-play-control-player {
|
||||
width: fit-content;
|
||||
height: 32px;
|
||||
}
|
||||
</style>
|
||||
@ -58,7 +58,7 @@
|
||||
import moment from 'moment'
|
||||
import momentDurationFormatSetup from 'moment-duration-format'
|
||||
import screenfull from 'screenfull'
|
||||
import cloudRecordPlayer from './cloudRecordPlayer.vue'
|
||||
import cloudRecordPlayer from './player.vue'
|
||||
|
||||
momentDurationFormatSetup(moment)
|
||||
|
||||
@ -284,12 +284,15 @@ export default {
|
||||
this.$refs.cloudRecordPlayer.setStreamInfo(data, this.detailFiles[this.chooseFileIndex].timeLen, this.detailFiles[this.chooseFileIndex].startTime)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error)
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
this.playLoading = false
|
||||
})
|
||||
|
||||
},
|
||||
downloadFile(file) {
|
||||
this.$store.dispatch('cloudRecord/getPlayPath', file.id)
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
<script>
|
||||
|
||||
import elDragDialog from '@/directive/el-drag-dialog'
|
||||
import cloudRecordPlayer from './cloudRecordPlayer.vue'
|
||||
import cloudRecordPlayer from './player.vue'
|
||||
|
||||
export default {
|
||||
name: 'PlayerDialog',
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<div class="player-tabs-wrapper" ref="playerWrapper">
|
||||
<el-tabs v-if="showTab && playerCount > 1" v-model="activePlayer" type="card" :stretch="true" @tab-click="changePlayer">
|
||||
<el-tab-pane label="Jessibuca" name="jessibuca"></el-tab-pane>
|
||||
<el-tab-pane label="WebRTC" name="webRTC"></el-tab-pane>
|
||||
<el-tab-pane label="h265web" name="h265web"></el-tab-pane>
|
||||
<el-tabs v-if="showTab && playerList.length > 1" v-model="activePlayer" type="card" :stretch="true" @tab-click="changePlayer">
|
||||
<el-tab-pane v-for="p in playerList" :key="p.key" :label="p.label" :name="p.key"></el-tab-pane>
|
||||
</el-tabs>
|
||||
<div class="player-video-area">
|
||||
<jessibucaPlayer
|
||||
@ -13,6 +11,8 @@
|
||||
:has-audio="hasAudio"
|
||||
:show-button="showButton"
|
||||
fluent autoplay live
|
||||
@playTimeChange="$emit('playTimeChange', $event)"
|
||||
@playStatusChange="$emit('playStatusChange', $event)"
|
||||
/>
|
||||
<rtc-player
|
||||
v-if="activePlayer === 'webRTC'"
|
||||
@ -21,6 +21,8 @@
|
||||
:has-audio="hasAudio"
|
||||
:show-button="showButton"
|
||||
fluent autoplay live
|
||||
@playTimeChange="$emit('playTimeChange', $event)"
|
||||
@playStatusChange="$emit('playStatusChange', $event)"
|
||||
/>
|
||||
<h265web
|
||||
v-if="activePlayer === 'h265web'"
|
||||
@ -29,6 +31,8 @@
|
||||
:has-audio="hasAudio"
|
||||
:show-button="showButton"
|
||||
fluent autoplay live
|
||||
@playTimeChange="$emit('playTimeChange', $event)"
|
||||
@playStatusChange="$emit('playStatusChange', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -44,38 +48,59 @@ export default {
|
||||
components: { jessibucaPlayer, rtcPlayer, h265web },
|
||||
props: {
|
||||
hasAudio: { type: Boolean, default: false },
|
||||
showButton: { type: Boolean, default: true }
|
||||
showButton: { type: Boolean, default: true },
|
||||
showTab: { type: Boolean, default: true }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showTab: true,
|
||||
streamInfo: null,
|
||||
activePlayer: 'jessibuca',
|
||||
player: { jessibuca: ['ws_flv', 'wss_flv'], webRTC: ['rtc', 'rtcs'], h265web: ['ws_flv', 'wss_flv'] }
|
||||
player: { jessibuca: ['ws_flv', 'wss_flv'], webRTC: ['rtc', 'rtcs'], h265web: ['ws_flv', 'wss_flv'] },
|
||||
allPlayerList: [
|
||||
{ key: 'jessibuca', label: 'Jessibuca' },
|
||||
{ key: 'webRTC', label: 'WebRTC' },
|
||||
{ key: 'h265web', label: 'H265web' }
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
playerList() {
|
||||
return this.allPlayerList
|
||||
},
|
||||
playerCount() {
|
||||
return Object.keys(this.player).length
|
||||
return this.playerList.length
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.playerCount === 1) {
|
||||
this.activePlayer = Object.keys(this.player)[0]
|
||||
this.activePlayer = this.playerList[0].key
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getPlayerList() {
|
||||
return this.playerList
|
||||
},
|
||||
getActivePlayer() {
|
||||
return this.activePlayer
|
||||
},
|
||||
switchPlayer(key) {
|
||||
if (this.activePlayer === key) return
|
||||
this.activePlayer = key
|
||||
if (this.streamInfo) {
|
||||
this.play()
|
||||
}
|
||||
},
|
||||
getUrlByStreamInfo() {
|
||||
if (!this.streamInfo) return ''
|
||||
const src = this.streamInfo.transcodeStream || this.streamInfo
|
||||
if (location.protocol === 'https:') {
|
||||
return src[this.player[this.activePlayer][1]]
|
||||
return this.streamInfo[this.player[this.activePlayer][1]]
|
||||
}
|
||||
return src[this.player[this.activePlayer][0]]
|
||||
return this.streamInfo[this.player[this.activePlayer][0]]
|
||||
},
|
||||
changePlayer(tab) {
|
||||
this.activePlayer = tab.name
|
||||
this.play()
|
||||
this.$emit('player-changed', this.activePlayer)
|
||||
},
|
||||
setStreamInfo(streamInfo) {
|
||||
this.streamInfo = streamInfo
|
||||
@ -103,6 +128,30 @@ export default {
|
||||
this.$refs[this.activePlayer].pause()
|
||||
}
|
||||
},
|
||||
destroy() {
|
||||
const player = this.$refs[this.activePlayer]
|
||||
if (player && player.destroy) {
|
||||
player.destroy()
|
||||
}
|
||||
},
|
||||
setPlaybackRate(rate) {
|
||||
const player = this.$refs[this.activePlayer]
|
||||
if (player && player.setPlaybackRate) {
|
||||
player.setPlaybackRate(rate)
|
||||
}
|
||||
},
|
||||
resize(width, height) {
|
||||
const player = this.$refs[this.activePlayer]
|
||||
if (player && player.resize) {
|
||||
player.resize(width, height)
|
||||
}
|
||||
},
|
||||
screenshot() {
|
||||
const player = this.$refs[this.activePlayer]
|
||||
if (player && player.screenshot) {
|
||||
return player.screenshot()
|
||||
}
|
||||
},
|
||||
getVideoRect() {
|
||||
const player = this.$refs[this.activePlayer]
|
||||
return player && player.getVideoRect ? player.getVideoRect() : null
|
||||
|
||||
@ -16,10 +16,6 @@
|
||||
<i class="iconfont icon-slider-right" style="margin-right: 6px" />
|
||||
<span>线性扫描</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="wiper">
|
||||
<i class="el-icon-umbrella" style="margin-right: 6px" />
|
||||
<span>雨刷</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="switch">
|
||||
<i class="el-icon-s-tools" style="margin-right: 6px" />
|
||||
<span>辅助开关</span>
|
||||
@ -34,7 +30,6 @@
|
||||
<ptzPresetConfig v-if="activeTab === 'preset'" :device-id="deviceId" :channel-device-id="channelDeviceId" />
|
||||
<ptzCruiseConfig v-if="activeTab === 'cruise'" :device-id="deviceId" :channel-device-id="channelDeviceId" />
|
||||
<ptzScanConfig v-if="activeTab === 'scan'" :device-id="deviceId" :channel-device-id="channelDeviceId" />
|
||||
<ptzWiperConfig v-if="activeTab === 'wiper'" :device-id="deviceId" :channel-device-id="channelDeviceId" />
|
||||
<ptzSwitchConfig v-if="activeTab === 'switch'" :device-id="deviceId" :channel-device-id="channelDeviceId" />
|
||||
</div>
|
||||
</div>
|
||||
@ -47,12 +42,11 @@ import playerPtzPanel from '../common/playerPtzPanel.vue'
|
||||
import ptzPresetConfig from '../common/ptzPresetConfig.vue'
|
||||
import ptzCruiseConfig from '../common/ptzCruiseConfig.vue'
|
||||
import ptzScanConfig from '../common/ptzScanConfig.vue'
|
||||
import ptzWiperConfig from '../common/ptzWiperConfig.vue'
|
||||
import ptzSwitchConfig from '../common/ptzSwitchConfig.vue'
|
||||
|
||||
export default {
|
||||
name: 'PtzConfigPage',
|
||||
components: { playerPtzPanel, ptzPresetConfig, ptzCruiseConfig, ptzScanConfig, ptzWiperConfig, ptzSwitchConfig },
|
||||
components: { playerPtzPanel, ptzPresetConfig, ptzCruiseConfig, ptzScanConfig, ptzSwitchConfig },
|
||||
props: {
|
||||
deviceId: { type: String, default: null },
|
||||
channelDeviceId: { type: String, default: null }
|
||||
|
||||
@ -44,7 +44,7 @@ export default {
|
||||
this.hasAudio = data.hasAudio
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.playerTabs) {
|
||||
this.$refs.playerTabs.setStreamInfo(data)
|
||||
this.$refs.playerTabs.setStreamInfo(data.transcodeStream || data)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,28 +1,59 @@
|
||||
<template>
|
||||
<div style="height: 100%; display: flex; flex-direction: column;">
|
||||
<el-form size="small" inline style="margin-bottom: 12px; padding: 16px 8px; border: 1px solid #e6e6e6; border-radius: 4px;">
|
||||
<el-form-item label="扫描组号" style="margin-bottom: 0;">
|
||||
<el-input-number v-model="scanId" :min="1" :max="255" controls-position="right" style="width: 140px" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div style="margin-bottom: 8px;">
|
||||
<el-button size="small" :loading="leftLoading" :disabled="leftLoading" @click="setLeft">设置左边界</el-button>
|
||||
<el-button size="small" :loading="rightLoading" :disabled="rightLoading" @click="setRight">设置右边界</el-button>
|
||||
<div id="ptzScanConfig" style="height: 100%; display: flex; flex-direction: column;">
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px;">
|
||||
<div>
|
||||
<el-button type="primary" :loading="adding" :disabled="adding" @click="addLineScan">添加线扫</el-button>
|
||||
<el-button @click="clearAll">清空</el-button>
|
||||
</div>
|
||||
<el-button icon="el-icon-refresh-right" circle />
|
||||
</div>
|
||||
<el-form v-if="showSpeedInput" size="mini" inline style="margin-bottom: 8px;">
|
||||
<el-form-item label="扫描速度" style="margin-bottom: 0;">
|
||||
<el-input-number v-model="scanSpeed" :min="1" :max="255" controls-position="right" style="width: 120px" />
|
||||
</el-form-item>
|
||||
<el-form-item style="margin-bottom: 0;">
|
||||
<el-button type="primary" @click="setSpeed">确定</el-button>
|
||||
<el-button @click="cancelSpeed">取消</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-button v-else size="small" style="margin-bottom: 8px;" @click="showSpeedInput = true">设置扫描速度</el-button>
|
||||
<div style="margin-top: 8px;">
|
||||
<el-button size="small" type="primary" :loading="starting" :disabled="starting" @click="startScan">开始自动扫描</el-button>
|
||||
<el-button size="small" :loading="stopping" :disabled="stopping" @click="stopScan">停止自动扫描</el-button>
|
||||
<div v-if="scanAreas.length > 0" style="flex: 1; overflow: auto;">
|
||||
<el-table :data="scanAreas" max-height="100%" stripe border highlight-current-row height="100%">
|
||||
<el-table-column label="序号" min-width="50">
|
||||
<template v-slot="{ row }">{{ row.index }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="名称" min-width="80">
|
||||
<template v-slot="{ row }">{{ row.name }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="左边界" min-width="90">
|
||||
<template v-slot="{ row }">
|
||||
<el-button type="text"
|
||||
:style="{ color: row.leftBoundary ? '#67C23A' : '#409EFF' }"
|
||||
:loading="boundaryLoading.index === row.index && boundaryLoading.side === 'Left'"
|
||||
:disabled="operatingId !== null"
|
||||
@click="setBoundary(row, 'Left')">
|
||||
{{ row.leftBoundary ? '重新保存' : '待保存' }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="右边界" min-width="90">
|
||||
<template v-slot="{ row }">
|
||||
<el-button type="text"
|
||||
:style="{ color: row.rightBoundary ? '#67C23A' : '#409EFF' }"
|
||||
:loading="boundaryLoading.index === row.index && boundaryLoading.side === 'Right'"
|
||||
:disabled="operatingId !== null"
|
||||
@click="setBoundary(row, 'Right')">
|
||||
{{ row.rightBoundary ? '重新保存' : '待保存' }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="速度" min-width="90">
|
||||
<template v-slot="{ row }">
|
||||
<el-select v-model="row.speed" :disabled="speedSaving === row.index" @change="onSpeedChange(row)">
|
||||
<el-option v-for="s in 8" :key="s" :label="s" :value="s" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" min-width="120">
|
||||
<template v-slot="{ row, $index }">
|
||||
<el-button v-if="$index === cruisingScanIndex" type="text" style="color: #F56C6C" :loading="operatingId === row.index" :disabled="operatingId !== null" @click="stopScan(row)">停用</el-button>
|
||||
<el-button v-else type="text" style="color: #409EFF" :disabled="operatingId !== null" :loading="operatingId === row.index" @click="startScan(row, $index)">启用</el-button>
|
||||
<el-button type="text" style="color: #F56C6C" :disabled="operatingId !== null" @click="deleteScan(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-else style="color: #909399; font-size: 12px; margin-bottom: 8px;">暂无线扫区域</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -35,72 +66,112 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
scanId: 1,
|
||||
showSpeedInput: false,
|
||||
scanSpeed: 5,
|
||||
leftLoading: false,
|
||||
rightLoading: false,
|
||||
starting: false,
|
||||
stopping: false
|
||||
scanAreas: [],
|
||||
cruisingScanIndex: null,
|
||||
operatingId: null,
|
||||
adding: false,
|
||||
boundaryLoading: { index: null, side: null },
|
||||
speedSaving: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setLeft() {
|
||||
this.leftLoading = true
|
||||
this.$store.dispatch('frontEnd/setLeftForScan', [this.deviceId, this.channelDeviceId, this.scanId])
|
||||
getNextAvailableIndex() {
|
||||
const used = new Set(this.scanAreas.filter(a => a.name && a.name.trim()).map(a => a.index))
|
||||
for (let i = 0; i <= 255; i++) {
|
||||
if (!used.has(i)) return i
|
||||
}
|
||||
return 0
|
||||
},
|
||||
addLineScan() {
|
||||
const nextIndex = this.getNextAvailableIndex()
|
||||
const name = '线扫' + nextIndex
|
||||
this.adding = true
|
||||
this.scanAreas.push({
|
||||
index: nextIndex,
|
||||
name: name,
|
||||
leftBoundary: false,
|
||||
rightBoundary: false,
|
||||
speed: 5
|
||||
})
|
||||
this.$nextTick(() => { this.adding = false })
|
||||
},
|
||||
setBoundary(row, boundary) {
|
||||
this.boundaryLoading = { index: row.index, side: boundary }
|
||||
const action = boundary === 'Left' ? 'setLeftForScan' : 'setRightForScan'
|
||||
this.$store.dispatch('frontEnd/' + action, [this.deviceId, this.channelDeviceId, row.index])
|
||||
.then(() => {
|
||||
this.$message({ showClose: true, message: '左边界设置成功', type: 'success' })
|
||||
}).catch(error => {
|
||||
this.$message({ showClose: true, message: error, type: 'error' })
|
||||
this.$message({ showClose: true, message: (boundary === 'Left' ? '左' : '右') + '边界设置成功', type: 'success' })
|
||||
if (boundary === 'Left') {
|
||||
row.leftBoundary = true
|
||||
} else {
|
||||
row.rightBoundary = true
|
||||
}
|
||||
}).catch(() => {
|
||||
this.$message({ showClose: true, message: '边界设置失败', type: 'error' })
|
||||
}).finally(() => {
|
||||
this.leftLoading = false
|
||||
this.boundaryLoading = { index: null, side: null }
|
||||
})
|
||||
},
|
||||
setRight() {
|
||||
this.rightLoading = true
|
||||
this.$store.dispatch('frontEnd/setRightForScan', [this.deviceId, this.channelDeviceId, this.scanId])
|
||||
onSpeedChange(row) {
|
||||
this.speedSaving = row.index
|
||||
this.$store.dispatch('frontEnd/setSpeedForScan', [this.deviceId, this.channelDeviceId, row.index, row.speed])
|
||||
.then(() => {
|
||||
this.$message({ showClose: true, message: '右边界设置成功', type: 'success' })
|
||||
}).catch(error => {
|
||||
this.$message({ showClose: true, message: error, type: 'error' })
|
||||
this.$message({ showClose: true, message: '速度已保存', type: 'success' })
|
||||
}).catch(() => {
|
||||
this.$message({ showClose: true, message: '速度保存失败', type: 'error' })
|
||||
}).finally(() => {
|
||||
this.rightLoading = false
|
||||
this.speedSaving = null
|
||||
})
|
||||
},
|
||||
setSpeed() {
|
||||
this.$store.dispatch('frontEnd/setSpeedForScan', [this.deviceId, this.channelDeviceId, this.scanId, this.scanSpeed])
|
||||
startScan(row, index) {
|
||||
this.operatingId = row.index
|
||||
this.$store.dispatch('frontEnd/startScan', [this.deviceId, this.channelDeviceId, row.index])
|
||||
.then(() => {
|
||||
this.showSpeedInput = false
|
||||
this.$message({ showClose: true, message: '速度设置成功', type: 'success' })
|
||||
}).catch(error => {
|
||||
this.$message({ showClose: true, message: error, type: 'error' })
|
||||
})
|
||||
},
|
||||
cancelSpeed() {
|
||||
this.showSpeedInput = false
|
||||
this.scanSpeed = 5
|
||||
},
|
||||
startScan() {
|
||||
this.starting = true
|
||||
this.$store.dispatch('frontEnd/startScan', [this.deviceId, this.channelDeviceId, this.scanId])
|
||||
.then(() => {
|
||||
this.$message({ showClose: true, message: '扫描启动成功', type: 'success' })
|
||||
}).catch(error => {
|
||||
this.$message({ showClose: true, message: error, type: 'error' })
|
||||
this.$message({ showClose: true, message: '启用成功', type: 'success' })
|
||||
this.cruisingScanIndex = index
|
||||
}).catch(() => {
|
||||
this.$message({ showClose: true, message: '启用失败', type: 'error' })
|
||||
}).finally(() => {
|
||||
this.starting = false
|
||||
this.operatingId = null
|
||||
})
|
||||
},
|
||||
stopScan() {
|
||||
this.stopping = true
|
||||
this.$store.dispatch('frontEnd/stopScan', [this.deviceId, this.channelDeviceId, this.scanId])
|
||||
stopScan(row) {
|
||||
this.operatingId = row.index
|
||||
this.$store.dispatch('frontEnd/stopScan', [this.deviceId, this.channelDeviceId, row.index])
|
||||
.then(() => {
|
||||
this.$message({ showClose: true, message: '扫描停止成功', type: 'success' })
|
||||
}).catch(error => {
|
||||
this.$message({ showClose: true, message: error, type: 'error' })
|
||||
this.$message({ showClose: true, message: '停用成功', type: 'success' })
|
||||
this.cruisingScanIndex = null
|
||||
}).catch(() => {
|
||||
this.$message({ showClose: true, message: '停用失败', type: 'error' })
|
||||
}).finally(() => {
|
||||
this.stopping = false
|
||||
this.operatingId = null
|
||||
})
|
||||
},
|
||||
deleteScan(row) {
|
||||
this.$confirm('确定删除线扫 ' + row.index + '?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
const idx = this.scanAreas.indexOf(row)
|
||||
if (idx !== -1) this.scanAreas.splice(idx, 1)
|
||||
if (this.cruisingScanIndex !== null && this.scanAreas[this.cruisingScanIndex] === undefined) {
|
||||
this.cruisingScanIndex = null
|
||||
}
|
||||
this.$message({ showClose: true, message: '删除成功(仅本地列表,设备端配置需手动清除)', type: 'success' })
|
||||
}).catch(() => {})
|
||||
},
|
||||
clearAll() {
|
||||
if (this.scanAreas.length === 0) return
|
||||
this.$confirm('确定清空所有线扫区域?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.scanAreas = []
|
||||
this.cruisingScanIndex = null
|
||||
this.$message({ showClose: true, message: '清空成功(仅本地列表,设备端配置需手动清除)', type: 'success' })
|
||||
}).catch(() => {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,18 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-form size="mini" inline>
|
||||
<el-form inline label-width="120px" size="small">
|
||||
<el-form-item label="开关编号" style="margin-bottom: 0;">
|
||||
<el-input-number v-model="switchId" :min="1" :max="255" controls-position="right" style="width: 140px" />
|
||||
</el-form-item>
|
||||
<el-form-item style="margin-bottom: 0;">
|
||||
<el-button size="small" :loading="loading" :disabled="loading" @click="control('on')">开启</el-button>
|
||||
<el-button size="small" :loading="loading" :disabled="loading" @click="control('off')">关闭</el-button>
|
||||
<el-button type="primary" :loading="loading" :disabled="loading" @click="control('on')">开启</el-button>
|
||||
<el-button :loading="loading" :disabled="loading" @click="control('off')">关闭</el-button>
|
||||
</el-form-item>
|
||||
<el-divider />
|
||||
|
||||
<el-form-item style="margin-bottom: 0;" label="雨刷">
|
||||
<el-button type="primary" :loading="wiperLoading" :disabled="wiperLoading" @click="wiperControl('on')">开启</el-button>
|
||||
<el-button :loading="wiperLoading" :disabled="wiperLoading" @click="wiperControl('off')">关闭</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
@ -22,10 +28,22 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
switchId: 1,
|
||||
loading: false
|
||||
loading: false,
|
||||
wiperLoading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
wiperControl(command) {
|
||||
this.wiperLoading = true
|
||||
this.$store.dispatch('frontEnd/wiper', [this.deviceId, this.channelDeviceId, command])
|
||||
.then(() => {
|
||||
this.$message({ showClose: true, message: command === 'on' ? '雨刷已开启' : '雨刷已关闭', type: 'success' })
|
||||
}).catch(error => {
|
||||
this.$message({ showClose: true, message: error, type: 'error' })
|
||||
}).finally(() => {
|
||||
this.wiperLoading = false
|
||||
})
|
||||
},
|
||||
control(command) {
|
||||
this.loading = true
|
||||
this.$store.dispatch('frontEnd/auxiliary', [this.deviceId, this.channelDeviceId, command, this.switchId])
|
||||
|
||||
@ -38,55 +38,54 @@
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="实时视频" name="media">
|
||||
<div v-if="tabActiveName === 'media'" class="media-info-content">
|
||||
<div class="media-row">
|
||||
<span class="media-label">播放地址:</span>
|
||||
<el-input v-model="playerUrlInfo.playerUrl" :disabled="true">
|
||||
<template slot="append">
|
||||
<i class="cpoy-btn el-icon-document-copy" title="点击拷贝" style="cursor: pointer" @click="copyUrl(playerUrlInfo.playerUrl)" />
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<div class="media-row">
|
||||
<span class="media-label">iframe:</span>
|
||||
<el-input v-model="sharedIframe" :disabled="true">
|
||||
<template slot="append">
|
||||
<i class="cpoy-btn el-icon-document-copy" title="点击拷贝" style="cursor: pointer" @click="copyUrl(sharedIframe)" />
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<div class="media-row">
|
||||
<span class="media-label">资源地址:</span>
|
||||
<el-input v-model="playerUrlInfo.playUrl" :disabled="true">
|
||||
<el-button slot="append" icon="el-icon-document-copy" title="点击拷贝" style="cursor: pointer" @click="copyUrl(playerUrlInfo.playUrl)" />
|
||||
<el-dropdown v-if="streamInfo" slot="prepend" trigger="click" @command="copyUrl">
|
||||
<el-button>更多地址<i class="el-icon-arrow-down el-icon--right" /></el-button>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item v-if="streamInfo.flv" :command="streamInfo.flv"><el-tag>FLV:</el-tag><span>{{ streamInfo.flv }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.https_flv" :command="streamInfo.https_flv"><el-tag>FLV(https):</el-tag><span>{{ streamInfo.https_flv }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.ws_flv" :command="streamInfo.ws_flv"><el-tag>FLV(ws):</el-tag><span>{{ streamInfo.ws_flv }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.wss_flv" :command="streamInfo.wss_flv"><el-tag>FLV(wss):</el-tag><span>{{ streamInfo.wss_flv }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.fmp4" :command="streamInfo.fmp4"><el-tag>FMP4:</el-tag><span>{{ streamInfo.fmp4 }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.https_fmp4" :command="streamInfo.https_fmp4"><el-tag>FMP4(https):</el-tag><span>{{ streamInfo.https_fmp4 }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.ws_fmp4" :command="streamInfo.ws_fmp4"><el-tag>FMP4(ws):</el-tag><span>{{ streamInfo.ws_fmp4 }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.wss_fmp4" :command="streamInfo.wss_fmp4"><el-tag>FMP4(wss):</el-tag><span>{{ streamInfo.wss_fmp4 }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.hls" :command="streamInfo.hls"><el-tag>HLS:</el-tag><span>{{ streamInfo.hls }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.https_hls" :command="streamInfo.https_hls"><el-tag>HLS(https):</el-tag><span>{{ streamInfo.https_hls }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.ws_hls" :command="streamInfo.ws_hls"><el-tag>HLS(ws):</el-tag><span>{{ streamInfo.ws_hls }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.wss_hls" :command="streamInfo.wss_hls"><el-tag>HLS(wss):</el-tag><span>{{ streamInfo.wss_hls }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.ts" :command="streamInfo.ts"><el-tag>TS:</el-tag><span>{{ streamInfo.ts }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.https_ts" :command="streamInfo.https_ts"><el-tag>TS(https):</el-tag><span>{{ streamInfo.https_ts }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.ws_ts" :command="streamInfo.ws_ts"><el-tag>TS(ws):</el-tag><span>{{ streamInfo.ws_ts }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.wss_ts" :command="streamInfo.wss_ts"><el-tag>TS(wss):</el-tag><span>{{ streamInfo.wss_ts }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.rtc" :command="streamInfo.rtc"><el-tag>RTC:</el-tag><span>{{ streamInfo.rtc }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.rtcs" :command="streamInfo.rtcs"><el-tag>RTCS:</el-tag><span>{{ streamInfo.rtcs }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.rtmp" :command="streamInfo.rtmp"><el-tag>RTMP:</el-tag><span>{{ streamInfo.rtmp }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.rtmps" :command="streamInfo.rtmps"><el-tag>RTMPS:</el-tag><span>{{ streamInfo.rtmps }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.rtsp" :command="streamInfo.rtsp"><el-tag>RTSP:</el-tag><span>{{ streamInfo.rtsp }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.rtsps" :command="streamInfo.rtsps"><el-tag>RTSPS:</el-tag><span>{{ streamInfo.rtsps }}</span></el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</el-input>
|
||||
</div>
|
||||
<el-form label-width="90px" size="small">
|
||||
<el-form-item label="播放地址">
|
||||
<el-input v-model="playerUrlInfo.playerUrl" :disabled="true">
|
||||
<template slot="append">
|
||||
<i class="cpoy-btn el-icon-document-copy" title="点击拷贝" style="cursor: pointer" @click="copyUrl(playerUrlInfo.playerUrl)" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="iframe">
|
||||
<el-input v-model="sharedIframe" :disabled="true" >
|
||||
<template slot="append">
|
||||
<i class="cpoy-btn el-icon-document-copy" title="点击拷贝" style="cursor: pointer" @click="copyUrl(sharedIframe)" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="资源地址">
|
||||
<el-input v-model="playerUrlInfo.playUrl" :disabled="true" size="mini">
|
||||
<el-button slot="append" icon="el-icon-document-copy" title="点击拷贝" style="cursor: pointer" @click="copyUrl(playerUrlInfo.playUrl)" />
|
||||
<el-dropdown v-if="streamInfo" slot="prepend" trigger="click" @command="copyUrl">
|
||||
<el-button>更多地址<i class="el-icon-arrow-down el-icon--right" size="mini"/></el-button>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item v-if="streamInfo.flv" :command="streamInfo.flv"><el-tag>FLV:</el-tag><span>{{ streamInfo.flv }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.https_flv" :command="streamInfo.https_flv"><el-tag>FLV(https):</el-tag><span>{{ streamInfo.https_flv }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.ws_flv" :command="streamInfo.ws_flv"><el-tag>FLV(ws):</el-tag><span>{{ streamInfo.ws_flv }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.wss_flv" :command="streamInfo.wss_flv"><el-tag>FLV(wss):</el-tag><span>{{ streamInfo.wss_flv }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.fmp4" :command="streamInfo.fmp4"><el-tag>FMP4:</el-tag><span>{{ streamInfo.fmp4 }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.https_fmp4" :command="streamInfo.https_fmp4"><el-tag>FMP4(https):</el-tag><span>{{ streamInfo.https_fmp4 }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.ws_fmp4" :command="streamInfo.ws_fmp4"><el-tag>FMP4(ws):</el-tag><span>{{ streamInfo.ws_fmp4 }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.wss_fmp4" :command="streamInfo.wss_fmp4"><el-tag>FMP4(wss):</el-tag><span>{{ streamInfo.wss_fmp4 }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.hls" :command="streamInfo.hls"><el-tag>HLS:</el-tag><span>{{ streamInfo.hls }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.https_hls" :command="streamInfo.https_hls"><el-tag>HLS(https):</el-tag><span>{{ streamInfo.https_hls }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.ws_hls" :command="streamInfo.ws_hls"><el-tag>HLS(ws):</el-tag><span>{{ streamInfo.ws_hls }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.wss_hls" :command="streamInfo.wss_hls"><el-tag>HLS(wss):</el-tag><span>{{ streamInfo.wss_hls }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.ts" :command="streamInfo.ts"><el-tag>TS:</el-tag><span>{{ streamInfo.ts }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.https_ts" :command="streamInfo.https_ts"><el-tag>TS(https):</el-tag><span>{{ streamInfo.https_ts }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.ws_ts" :command="streamInfo.ws_ts"><el-tag>TS(ws):</el-tag><span>{{ streamInfo.ws_ts }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.wss_ts" :command="streamInfo.wss_ts"><el-tag>TS(wss):</el-tag><span>{{ streamInfo.wss_ts }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.rtc" :command="streamInfo.rtc"><el-tag>RTC:</el-tag><span>{{ streamInfo.rtc }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.rtcs" :command="streamInfo.rtcs"><el-tag>RTCS:</el-tag><span>{{ streamInfo.rtcs }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.rtmp" :command="streamInfo.rtmp"><el-tag>RTMP:</el-tag><span>{{ streamInfo.rtmp }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.rtmps" :command="streamInfo.rtmps"><el-tag>RTMPS:</el-tag><span>{{ streamInfo.rtmps }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.rtsp" :command="streamInfo.rtsp"><el-tag>RTSP:</el-tag><span>{{ streamInfo.rtsp }}</span></el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.rtsps" :command="streamInfo.rtsps"><el-tag>RTSPS:</el-tag><span>{{ streamInfo.rtsps }}</span></el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="编码信息" name="codec">
|
||||
@ -171,7 +170,7 @@ export default {
|
||||
this.showVideoDialog = true
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.playerTabs) {
|
||||
this.$refs.playerTabs.setStreamInfo(streamInfo)
|
||||
this.$refs.playerTabs.setStreamInfo(streamInfo.transcodeStream || streamInfo)
|
||||
}
|
||||
})
|
||||
},
|
||||
@ -217,7 +216,7 @@ export default {
|
||||
.player-side { flex: 3; min-width: 0; }
|
||||
.player-container { width: 100%; }
|
||||
.control-side { flex: 2; min-width: 340px; display: flex; flex-direction: column; }
|
||||
.control-tabs { flex: 1; display: flex; flex-direction: column; min-height: 180px}
|
||||
.control-tabs { flex: 1; display: flex; flex-direction: column; min-height: 220px}
|
||||
.control-tabs .el-tabs__content { flex: 1; overflow: auto; }
|
||||
.media-info-content { overflow: auto; }
|
||||
.media-row { display: flex; margin-bottom: 0.5rem; height: 2.5rem; }
|
||||
|
||||
@ -114,7 +114,7 @@ export default {
|
||||
this.showPlayer = true
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.playerTabs) {
|
||||
this.$refs.playerTabs.setStreamInfo(data)
|
||||
this.$refs.playerTabs.setStreamInfo(data.transcodeStream || data)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Loading…
Reference in New Issue
Block a user