优化播放弹窗

This commit is contained in:
lin 2026-06-11 11:34:27 +08:00
parent f5494c0b95
commit 5eea3a19f5
8 changed files with 246 additions and 165 deletions

View File

@ -69,6 +69,14 @@ export function resetGuard(deviceId) {
}) })
} }
export function homePosition(params) {
return request({
method: 'get',
url: '/api/device/control/home_position',
params
})
}
export function subscribeCatalog(params) { export function subscribeCatalog(params) {
const { id, cycle } = params const { id, cycle } = params
return request({ return request({

View File

@ -3,6 +3,7 @@ import {
changeChannelAudio, changeChannelAudio,
deleteDevice, deleteDevice,
deviceRecord, getKeepaliveTimeStatistics, getRegisterTimeStatistics, deviceRecord, getKeepaliveTimeStatistics, getRegisterTimeStatistics,
homePosition,
queryBasicParam, queryBasicParam,
queryChannelOne, queryChannelOne,
queryChannels, queryChannels,
@ -83,6 +84,16 @@ const actions = {
}) })
}) })
}, },
homePosition({ commit }, params) {
return new Promise((resolve, reject) => {
homePosition(params).then(response => {
const { data } = response
resolve(data)
}).catch(error => {
reject(error)
})
})
},
subscribeCatalog({ commit }, params) { subscribeCatalog({ commit }, params) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
subscribeCatalog(params).then(response => { subscribeCatalog(params).then(response => {

View File

@ -1,6 +1,6 @@
<template> <template>
<div id="h265Player" ref="container" style="background-color: #000000; " @dblclick="fullscreenSwich"> <div id="h265Player" ref="container" style="background-color: #000000; position: relative; display: flex; align-items: center; justify-content: center;" @dblclick="fullscreenSwich">
<div id="glplayer" ref="playerBox" style="width: 100%; height: 100%; margin: 0 auto;" > <div id="glplayer" ref="playerBox" style="width: 100%; height: 100%; margin: 0 auto;">
<div v-if="playerLoading" class="play-loading"> <div v-if="playerLoading" class="play-loading">
<i class="el-icon-loading" /> <i class="el-icon-loading" />
视频加载中 视频加载中
@ -264,12 +264,14 @@ export default {
} }
.buttons-box { .buttons-box {
width: 100%; width: 100%;
height: 28px; height: 56px;
background-color: rgba(43, 51, 63, 0.7); background: linear-gradient(to top, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0));
position: absolute; position: absolute;
display: -webkit-box; display: -webkit-box;
display: -ms-flexbox; display: -ms-flexbox;
display: flex; display: flex;
align-items: flex-end;
padding-bottom: 10px;
left: 0; left: 0;
bottom: 0; bottom: 0;
user-select: none; user-select: none;
@ -279,7 +281,6 @@ export default {
.h265web-btn { .h265web-btn {
width: 20px; width: 20px;
color: rgb(255, 255, 255); color: rgb(255, 255, 255);
line-height: 27px;
margin: 0px 10px; margin: 0px 10px;
padding: 0px 2px; padding: 0px 2px;
cursor: pointer; cursor: pointer;
@ -290,6 +291,7 @@ export default {
.buttons-box-right { .buttons-box-right {
position: absolute; position: absolute;
right: 0; right: 0;
bottom: 10px;
} }
.player-loading { .player-loading {
width: fit-content; width: fit-content;

View File

@ -289,8 +289,6 @@ export default {
height: 28px; height: 28px;
background-color: rgba(43, 51, 63, 0.7); background-color: rgba(43, 51, 63, 0.7);
position: absolute; position: absolute;
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
left: 0; left: 0;
bottom: 0; bottom: 0;
@ -302,7 +300,7 @@ export default {
width: 20px; width: 20px;
color: rgb(255, 255, 255); color: rgb(255, 255, 255);
line-height: 27px; line-height: 27px;
margin: 0px 10px; margin: 0px 20px;
padding: 0px 2px; padding: 0px 2px;
cursor: pointer; cursor: pointer;
text-align: center; text-align: center;

View File

@ -1,65 +1,31 @@
<template> <template>
<div class="player-tabs-wrapper" ref="playerWrapper"> <div class="player-tabs-wrapper" ref="playerWrapper">
<el-tabs v-if="playerCount > 1" v-model="activePlayer" type="card" :stretch="true" @tab-click="changePlayer"> <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 label="Jessibuca" name="jessibuca"></el-tab-pane>
<div v-if="activePlayer === 'jessibuca'" class="player-video-area"> <el-tab-pane label="WebRTC" name="webRTC"></el-tab-pane>
<jessibucaPlayer <el-tab-pane label="h265web" name="h265web"></el-tab-pane>
ref="jessibuca"
style="width: 100%; height: 100%;"
:video-url="videoUrl"
:has-audio="hasAudio"
:show-button="showButton"
fluent autoplay live
/>
</div>
</el-tab-pane>
<el-tab-pane label="WebRTC" name="webRTC">
<div v-if="activePlayer === 'webRTC'" class="player-video-area">
<rtc-player
ref="webRTC"
style="width: 100%; height: 100%;"
:video-url="videoUrl"
:has-audio="hasAudio"
fluent autoplay live
/>
</div>
</el-tab-pane>
<el-tab-pane label="h265web" name="h265web">
<div v-if="activePlayer === 'h265web'" class="player-video-area">
<h265web
style="width: 100%; height: 100%;"
ref="h265web"
:video-url="videoUrl"
:has-audio="hasAudio"
:show-button="showButton"
fluent autoplay live
/>
</div>
</el-tab-pane>
</el-tabs> </el-tabs>
<div v-if="playerCount <= 1" class="player-video-area"> <div class="player-video-area">
<jessibucaPlayer <jessibucaPlayer
v-if="player.jessibuca" v-if="activePlayer === 'jessibuca'"
ref="jessibuca" ref="jessibuca"
style="width: 100%; height: 100%;" style="width: 100%; height: 100%;"
:video-url="videoUrl"
:has-audio="hasAudio" :has-audio="hasAudio"
:show-button="showButton" :show-button="showButton"
fluent autoplay live fluent autoplay live
/> />
<rtc-player <rtc-player
v-if="player.webRTC" v-if="activePlayer === 'webRTC'"
ref="webRTC" ref="webRTC"
style="width: 100%; height: 100%;" style="width: 100%; height: 100%;"
:video-url="videoUrl"
:has-audio="hasAudio" :has-audio="hasAudio"
:show-button="showButton"
fluent autoplay live fluent autoplay live
/> />
<h265web <h265web
v-if="player.h265web" v-if="activePlayer === 'h265web'"
ref="h265web" ref="h265web"
style="width: 100%; height: 100%;" style="width: 100%; height: 100%;"
:video-url="videoUrl"
:has-audio="hasAudio" :has-audio="hasAudio"
:show-button="showButton" :show-button="showButton"
fluent autoplay live fluent autoplay live
@ -77,13 +43,13 @@ export default {
name: 'PlayerTabs', name: 'PlayerTabs',
components: { jessibucaPlayer, rtcPlayer, h265web }, components: { jessibucaPlayer, rtcPlayer, h265web },
props: { props: {
videoUrl: { type: String, default: '' },
hasAudio: { type: Boolean, default: false }, hasAudio: { type: Boolean, default: false },
showButton: { type: Boolean, default: true }, showButton: { type: Boolean, default: true }
height: { type: String, default: '' }
}, },
data() { data() {
return { return {
showTab: true,
streamInfo: null,
activePlayer: 'jessibuca', 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'] }
} }
@ -99,10 +65,9 @@ export default {
} }
}, },
methods: { methods: {
getUrlByStreamInfo(streamInfo) { getUrlByStreamInfo() {
const info = streamInfo || this.streamInfo if (!this.streamInfo) return ''
if (!info) return '' const src = this.streamInfo.transcodeStream || this.streamInfo
const src = info.transcodeStream || info
if (location.protocol === 'https:') { if (location.protocol === 'https:') {
return src[this.player[this.activePlayer][1]] return src[this.player[this.activePlayer][1]]
} }
@ -110,14 +75,23 @@ export default {
}, },
changePlayer(tab) { changePlayer(tab) {
this.activePlayer = tab.name this.activePlayer = tab.name
this.$emit('player-changed', this.activePlayer) this.play()
}, },
play(url) { setStreamInfo(streamInfo) {
this.streamInfo = streamInfo
this.play()
},
play() {
let playUrl = this.getUrlByStreamInfo()
this.$nextTick(() => { this.$nextTick(() => {
if (this.$refs[this.activePlayer]) { if (this.$refs[this.activePlayer]) {
this.$refs[this.activePlayer].play(url) this.$refs[this.activePlayer].play(playUrl)
} }
}) })
const typeMap = { jessibuca: 0, webRTC: 1, h265web: 2 }
const type = typeMap[this.activePlayer] || 0
const playerUrl = window.location.origin + '/#/play/share?type=' + type + '&url=' + encodeURIComponent(playUrl)
this.$emit('playerChanged', { playUrl, playerUrl })
}, },
stop() { stop() {
if (this.$refs[this.activePlayer]) { if (this.$refs[this.activePlayer]) {

View File

@ -1,69 +1,81 @@
<template> <template>
<div class="ptz-section-inner"> <div class="ptz-section-inner">
<div class="ptz-left"> <div class="ptz-top">
<div class="ptz-dpad"> <div class="ptz-dpad">
<div class="dpad-ring"></div> <div class="dpad-ring"></div>
<button class="dpad-btn card card-up" @mousedown.prevent="$emit('ptz-move', { direction: 'up', speed: controSpeed })" @mouseup.prevent="$emit('ptz-stop')"></button> <button class="dpad-btn card card-up" @mousedown.prevent="handlePtzMove('up')" @mouseup.prevent="handlePtzStop()"></button>
<button class="dpad-btn card card-right" @mousedown.prevent="$emit('ptz-move', { direction: 'right', speed: controSpeed })" @mouseup.prevent="$emit('ptz-stop')"></button> <button class="dpad-btn card card-right" @mousedown.prevent="handlePtzMove('right')" @mouseup.prevent="handlePtzStop()"></button>
<button class="dpad-btn card card-down" @mousedown.prevent="$emit('ptz-move', { direction: 'down', speed: controSpeed })" @mouseup.prevent="$emit('ptz-stop')"></button> <button class="dpad-btn card card-down" @mousedown.prevent="handlePtzMove('down')" @mouseup.prevent="handlePtzStop()"></button>
<button class="dpad-btn card card-left" @mousedown.prevent="$emit('ptz-move', { direction: 'left', speed: controSpeed })" @mouseup.prevent="$emit('ptz-stop')"></button> <button class="dpad-btn card card-left" @mousedown.prevent="handlePtzMove('left')" @mouseup.prevent="handlePtzStop()"></button>
<button class="dpad-btn diag diag-upright" @mousedown.prevent="$emit('ptz-move', { direction: 'upright', speed: controSpeed })" @mouseup.prevent="$emit('ptz-stop')"><span style="display:inline-block;transform:rotate(45deg)"></span></button> <button class="dpad-btn diag diag-upright" @mousedown.prevent="handlePtzMove('upright')" @mouseup.prevent="handlePtzStop()"><span style="display:inline-block;transform:rotate(45deg)"></span></button>
<button class="dpad-btn diag diag-downright" @mousedown.prevent="$emit('ptz-move', { direction: 'downright', speed: controSpeed })" @mouseup.prevent="$emit('ptz-stop')"><span style="display:inline-block;transform:rotate(135deg)"></span></button> <button class="dpad-btn diag diag-downright" @mousedown.prevent="handlePtzMove('downright')" @mouseup.prevent="handlePtzStop()"><span style="display:inline-block;transform:rotate(135deg)"></span></button>
<button class="dpad-btn diag diag-downleft" @mousedown.prevent="$emit('ptz-move', { direction: 'downleft', speed: controSpeed })" @mouseup.prevent="$emit('ptz-stop')"><span style="display:inline-block;transform:rotate(225deg)"></span></button> <button class="dpad-btn diag diag-downleft" @mousedown.prevent="handlePtzMove('downleft')" @mouseup.prevent="handlePtzStop()"><span style="display:inline-block;transform:rotate(225deg)"></span></button>
<button class="dpad-btn diag diag-upleft" @mousedown.prevent="$emit('ptz-move', { direction: 'upleft', speed: controSpeed })" @mouseup.prevent="$emit('ptz-stop')"><span style="display:inline-block;transform:rotate(-45deg)"></span></button> <button class="dpad-btn diag diag-upleft" @mousedown.prevent="handlePtzMove('upleft')" @mouseup.prevent="handlePtzStop()"><span style="display:inline-block;transform:rotate(-45deg)"></span></button>
<button class="dpad-btn dpad-center" title="停止" @click="$emit('ptz-stop')"></button> <button class="dpad-btn dpad-center" title="停止" @click="$emit('ptz-stop')"></button>
</div> </div>
<div class="ptz-speed-slider"> <div class="ptz-func-col">
<span class="ptz-speed-label">速度</span> <div class="ptz-func-group" :class="{ row: btnLayout === 'row' }">
<el-slider v-model="controSpeed" :max="8" :min="1" style="flex: 1" /> <div class="ptz-func-row">
<div class="ptz-func-row">
<div class="ptz-func-btn" title="看守位" @click.prevent="$emit('ptz-guard')">
<i class="el-icon-s-home" /><span>看守位</span>
</div>
</div>
</div>
<div class="ptz-func-row">
<div class="ptz-func-btn" title="变倍+" @mousedown.prevent="handlePtzMove('zoomin')" @mouseup.prevent="handlePtzStop()">
<i class="el-icon-zoom-in" /><span>变倍+</span>
</div>
<div class="ptz-func-btn" title="变倍-" @mousedown.prevent="handlePtzMove('zoomout')" @mouseup.prevent="handlePtzStop()">
<i class="el-icon-zoom-out" /><span>变倍-</span>
</div>
</div>
<div class="ptz-func-row">
<div class="ptz-func-btn" title="聚焦+" @mousedown.prevent="$emit('focus-move', { command: 'near', speed: controSpeed })" @mouseup.prevent="$emit('focus-stop')">
<i class="iconfont icon-bianjiao-fangda" /><span>聚焦+</span>
</div>
<div class="ptz-func-btn" title="聚焦-" @mousedown.prevent="$emit('focus-move', { command: 'far', speed: controSpeed })" @mouseup.prevent="$emit('focus-stop')">
<i class="iconfont icon-bianjiao-suoxiao" /><span>聚焦-</span>
</div>
</div>
<div class="ptz-func-row">
<div class="ptz-func-btn" title="光圈+" @mousedown.prevent="$emit('iris-move', { command: 'in', speed: controSpeed })" @mouseup.prevent="$emit('iris-stop')">
<i class="iconfont icon-guangquan" /><span>光圈+</span>
</div>
<div class="ptz-func-btn" title="光圈-" @mousedown.prevent="$emit('iris-move', { command: 'out', speed: controSpeed })" @mouseup.prevent="$emit('iris-stop')">
<i class="iconfont icon-guangquan-" /><span>光圈-</span>
</div>
</div>
<div class="ptz-func-row">
<div class="ptz-func-btn" title="拉框放大" @mousedown.prevent="$emit('iris-move', { command: 'in', speed: controSpeed })" @mouseup.prevent="$emit('iris-stop')">
<i class="iconfont icon-guangquan" /><span>拉框放大</span>
</div>
</div>
</div>
</div> </div>
</div> </div>
<div class="ptz-right"> <div class="ptz-bottom">
<div class="ptz-func-group"> <div class="slider-with-controls">
<div class="ptz-func-row"> <span class="slider-label">速度</span>
<div class="ptz-func-btn" title="变倍+" @mousedown.prevent="$emit('ptz-move', { direction: 'zoomin', speed: controSpeed })" @mouseup.prevent="$emit('ptz-stop')"> <el-button type="text" icon="el-icon-minus" class="slider-btn" @click="adjustSpeed(-1)" />
<i class="el-icon-zoom-in" /><span>变倍+</span> <el-slider v-model="controSpeed" :max="100" :min="1" />
</div> <el-button type="text" icon="el-icon-plus" class="slider-btn" @click="adjustSpeed(1)" />
<div class="ptz-func-btn" title="变倍-" @mousedown.prevent="$emit('ptz-move', { direction: 'zoomout', speed: controSpeed })" @mouseup.prevent="$emit('ptz-stop')"> <span class="slider-value">{{ controSpeed }}</span>
<i class="el-icon-zoom-out" /><span>变倍-</span>
</div>
</div>
<div class="ptz-func-row">
<div class="ptz-func-btn" title="聚焦+" @mousedown.prevent="$emit('focus-move', { command: 'near', speed: controSpeed })" @mouseup.prevent="$emit('focus-stop')">
<i class="iconfont icon-bianjiao-fangda" /><span>聚焦+</span>
</div>
<div class="ptz-func-btn" title="聚焦-" @mousedown.prevent="$emit('focus-move', { command: 'far', speed: controSpeed })" @mouseup.prevent="$emit('focus-stop')">
<i class="iconfont icon-bianjiao-suoxiao" /><span>聚焦-</span>
</div>
</div>
<div class="ptz-func-row">
<div class="ptz-func-btn" title="光圈+" @mousedown.prevent="$emit('iris-move', { command: 'in', speed: controSpeed })" @mouseup.prevent="$emit('iris-stop')">
<i class="iconfont icon-guangquan" /><span>光圈+</span>
</div>
<div class="ptz-func-btn" title="光圈-" @mousedown.prevent="$emit('iris-move', { command: 'out', speed: controSpeed })" @mouseup.prevent="$emit('iris-stop')">
<i class="iconfont icon-guangquan-" /><span>光圈-</span>
</div>
</div>
</div> </div>
<ptzPrecise v-if="showPrecise" :device-id="deviceId" :channel-device-id="channelId" @position="$emit('precise-position', $event)" style="margin-top: 6px" />
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import ptzPrecise from './ptzPrecise.vue'
export default { export default {
name: 'PtzControls', name: 'PtzControls',
components: { ptzPrecise },
props: { props: {
deviceId: { type: String, default: null }, btnLayout: { type: String, default: 'column' }
channelId: { type: String, default: null },
showPrecise: { type: Boolean, default: true }
}, },
data() { data() {
return { return {
controSpeed: 5 controSpeed: 50,
currentCommand: null
} }
}, },
mounted() { mounted() {
@ -73,8 +85,24 @@ export default {
window.removeEventListener('mouseup', this.onWindowMouseUp) window.removeEventListener('mouseup', this.onWindowMouseUp)
}, },
methods: { methods: {
adjustSpeed(delta) {
const newVal = this.controSpeed + delta
if (newVal >= 1 && newVal <= 100) {
this.controSpeed = newVal
}
},
handlePtzMove(direction) {
this.currentCommand = direction
this.$emit('ptz-move', { direction, speed: this.controSpeed })
},
handlePtzStop() {
this.$emit('ptz-stop', { direction: this.currentCommand })
this.currentCommand = null
},
onWindowMouseUp() { onWindowMouseUp() {
this.$emit('ptz-stop') if (this.currentCommand) {
this.handlePtzStop()
}
} }
} }
} }
@ -83,14 +111,15 @@ export default {
<style scoped> <style scoped>
.ptz-section-inner { .ptz-section-inner {
display: flex; display: flex;
flex-direction: column;
padding: 8px 4px; padding: 8px 4px;
overflow-y: auto; overflow-y: auto;
} }
.ptz-left { .ptz-top {
display: flex; display: flex;
flex-direction: column; gap: 12px;
align-items: center; flex: 1;
margin-right: 12px; min-height: 0;
} }
.ptz-dpad { .ptz-dpad {
position: relative; position: relative;
@ -185,19 +214,14 @@ export default {
background: #337ecc; background: #337ecc;
transform: translate(-50%, -50%) scale(0.92); transform: translate(-50%, -50%) scale(0.92);
} }
.ptz-speed-slider { .ptz-func-col {
flex: 1;
display: flex; display: flex;
flex-direction: column;
align-items: center; align-items: center;
width: 120px; justify-content: center;
margin-top: 8px; min-width: 0;
} }
.ptz-speed-label {
font-size: 12px;
color: #606266;
margin-right: 6px;
white-space: nowrap;
}
.ptz-right { flex: 1; }
.ptz-func-group { .ptz-func-group {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@ -220,7 +244,7 @@ export default {
cursor: pointer; cursor: pointer;
background: #fff; background: #fff;
user-select: none; user-select: none;
font-size: 11px; font-size: 12px;
} }
.ptz-func-btn:hover { .ptz-func-btn:hover {
background: #409EFF; background: #409EFF;
@ -230,4 +254,39 @@ export default {
background: #337ecc; background: #337ecc;
} }
.ptz-func-btn i { font-size: 14px; margin-bottom: 2px; } .ptz-func-btn i { font-size: 14px; margin-bottom: 2px; }
.ptz-func-group.row .ptz-func-btn {
flex-direction: row;
gap: 4px;
}
.ptz-func-group.row .ptz-func-btn i {
margin-bottom: 0;
margin-right: 4px;
}
.ptz-bottom {
margin-top: 12px;
padding: 0 4px;
}
.slider-label {
font-size: 13px;
color: #606266;
white-space: nowrap;
}
.slider-btn {
font-weight: bold;
color: #1a1a1a;
}
.slider-with-controls {
display: flex;
align-items: center;
gap: 8px;
}
.slider-with-controls .el-slider {
flex: 1;
}
.slider-value {
min-width: 28px;
text-align: center;
font-size: 13px;
color: #606266;
}
</style> </style>

View File

@ -12,6 +12,7 @@
:show-precise="false" :show-precise="false"
@ptz-move="onPtzMove" @ptz-move="onPtzMove"
@ptz-stop="onPtzStop" @ptz-stop="onPtzStop"
@ptz-guard="onPtzGuard"
@focus-move="onFocusMove" @focus-move="onFocusMove"
@focus-stop="onFocusStop" @focus-stop="onFocusStop"
@iris-move="onIrisMove" @iris-move="onIrisMove"
@ -48,14 +49,35 @@ export default {
}, },
methods: { methods: {
ptzSpeed(speed) { ptzSpeed(speed) {
return parseInt(speed * 255 / 8) return parseInt(speed * 255 / 100)
}, },
onPtzMove(e) { onPtzMove(e) {
const speedVal = this.ptzSpeed(e.speed) const speedVal = this.ptzSpeed(e.speed)
this.$store.dispatch('frontEnd/ptz', [this.deviceId, this.channelDeviceId, e.direction, speedVal, speedVal, speedVal]) this.$store.dispatch('frontEnd/ptz', {
deviceId: this.deviceId,
channelId: this.channelDeviceId,
command: e.direction,
horizonSpeed: speedVal,
verticalSpeed: speedVal,
zoomSpeed: speedVal
})
}, },
onPtzStop() { onPtzStop() {
this.$store.dispatch('frontEnd/ptz', [this.deviceId, this.channelDeviceId, 'stop', 0, 0, 0]) this.$store.dispatch('frontEnd/ptz', {
deviceId: this.deviceId,
channelId: this.channelDeviceId,
command: 'stop',
horizonSpeed: 0,
verticalSpeed: 0,
zoomSpeed: 0
})
},
onPtzGuard() {
this.$store.dispatch('device/homePosition', {
deviceId: this.deviceId,
channelId: this.channelDeviceId,
enabled: true
})
}, },
onFocusMove(e) { onFocusMove(e) {
const speedVal = this.ptzSpeed(e.speed) const speedVal = this.ptzSpeed(e.speed)

View File

@ -15,17 +15,17 @@
<div class="player-side"> <div class="player-side">
<div class="player-container" :style="{ height: playerHeight }"> <div class="player-container" :style="{ height: playerHeight }">
<playerTabs ref="playerTabs" :video-url="videoUrl" :has-audio="hasAudio" :show-button="true" /> <playerTabs ref="playerTabs" :has-audio="hasAudio" :show-button="true" @playerChanged="playerChanged"/>
</div> </div>
</div> </div>
<div class="control-side"> <div class="control-side">
<div v-if="showPtz" class="ptz-section"> <div class="ptz-section">
<ptzControls <ptzControls
:device-id="deviceId" btn-layout="row"
:channel-id="channelId"
@ptz-move="onPtzMove" @ptz-move="onPtzMove"
@ptz-stop="onPtzStop" @ptz-stop="onPtzStop"
@ptz-guard="onPtzGuard"
@focus-move="onFocusMove" @focus-move="onFocusMove"
@focus-stop="onFocusStop" @focus-stop="onFocusStop"
@iris-move="onIrisMove" @iris-move="onIrisMove"
@ -39,31 +39,31 @@
v-if="tabActiveName === 'preset'" v-if="tabActiveName === 'preset'"
:device-id="deviceId" :device-id="deviceId"
:channel-device-id="channelId" :channel-device-id="channelId"
style="margin-top: 8px" style="margin-top: 8px;"
/> />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="实时视频" name="media"> <el-tab-pane label="实时视频" name="media">
<div v-if="tabActiveName === 'media'" class="media-info-content"> <div v-if="tabActiveName === 'media'" class="media-info-content">
<div class="media-row"> <div class="media-row">
<span class="media-label">播放地址</span> <span class="media-label">播放地址</span>
<el-input v-model="getPlayerShared.sharedUrl" :disabled="true"> <el-input v-model="playerUrlInfo.playerUrl" :disabled="true">
<template slot="append"> <template slot="append">
<i class="cpoy-btn el-icon-document-copy" title="点击拷贝" style="cursor: pointer" @click="copyUrl(getPlayerShared.sharedUrl)" /> <i class="cpoy-btn el-icon-document-copy" title="点击拷贝" style="cursor: pointer" @click="copyUrl(playerUrlInfo.playerUrl)" />
</template> </template>
</el-input> </el-input>
</div> </div>
<div class="media-row"> <div class="media-row">
<span class="media-label">iframe</span> <span class="media-label">iframe</span>
<el-input v-model="getPlayerShared.sharedIframe" :disabled="true"> <el-input v-model="sharedIframe" :disabled="true">
<template slot="append"> <template slot="append">
<i class="cpoy-btn el-icon-document-copy" title="点击拷贝" style="cursor: pointer" @click="copyUrl(getPlayerShared.sharedIframe)" /> <i class="cpoy-btn el-icon-document-copy" title="点击拷贝" style="cursor: pointer" @click="copyUrl(sharedIframe)" />
</template> </template>
</el-input> </el-input>
</div> </div>
<div class="media-row"> <div class="media-row">
<span class="media-label">资源地址</span> <span class="media-label">资源地址</span>
<el-input v-model="getPlayerShared.sharedRtmp" :disabled="true"> <el-input v-model="playerUrlInfo.playUrl" :disabled="true">
<el-button slot="append" icon="el-icon-document-copy" title="点击拷贝" style="cursor: pointer" @click="copyUrl(getPlayerShared.sharedIframe)" /> <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-dropdown v-if="streamInfo" slot="prepend" trigger="click" @command="copyUrl">
<el-button>更多地址<i class="el-icon-arrow-down el-icon--right" /></el-button> <el-button>更多地址<i class="el-icon-arrow-down el-icon--right" /></el-button>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
@ -148,25 +148,21 @@ export default {
hasAudio: false, hasAudio: false,
isLoging: false, isLoging: false,
showVideoDialog: false, showVideoDialog: false,
showPtz: true,
showBroadcast: true, showBroadcast: true,
streamInfo: null, streamInfo: null,
broadcastMode: true, broadcastMode: true,
broadcastRtc: null, broadcastRtc: null,
broadcastStatus: -1, broadcastStatus: -1,
playerHeight: '36vh' playerHeight: '48vh',
playerUrlInfo: {
playerUrl: null,
playUrl: null,
}
} }
}, },
computed: { computed: {
getPlayerShared: function() { sharedIframe: function(){
const typeMap = { jessibuca: 0, webRTC: 1, h265web: 2 } return `<iframe src="${this.playerUrlInfo.playerUrl}"></iframe>`
const type = typeMap['jessibuca'] || 0
const baseUrl = window.location.origin + '/#/play/share?type=' + type + '&url=' + encodeURIComponent(this.videoUrl)
return {
sharedUrl: baseUrl,
sharedIframe: '<iframe src="' + baseUrl + '"></iframe>',
sharedRtmp: this.videoUrl
}
} }
}, },
created() { created() {
@ -174,14 +170,35 @@ export default {
}, },
methods: { methods: {
ptzSpeed(speed) { ptzSpeed(speed) {
return parseInt(speed * 255 / 8) return parseInt(speed * 255 / 100)
}, },
onPtzMove(e) { onPtzMove(e) {
const speedVal = this.ptzSpeed(e.speed) const speedVal = this.ptzSpeed(e.speed)
this.$store.dispatch('frontEnd/ptz', [this.deviceId, this.channelId, e.direction, speedVal, speedVal, speedVal]) this.$store.dispatch('frontEnd/ptz', {
deviceId: this.deviceId,
channelId: this.channelId,
command: e.direction,
horizonSpeed: speedVal,
verticalSpeed: speedVal,
zoomSpeed: parseInt(e.speed * 15 / 100)
})
}, },
onPtzStop() { onPtzStop() {
this.$store.dispatch('frontEnd/ptz', [this.deviceId, this.channelId, 'stop', 0, 0, 0]) this.$store.dispatch('frontEnd/ptz', {
deviceId: this.deviceId,
channelId: this.channelId,
command: 'stop',
horizonSpeed: 0,
verticalSpeed: 0,
zoomSpeed: 0
})
},
onPtzGuard() {
this.$store.dispatch('device/homePosition', {
deviceId: this.deviceId,
channelId: this.channelId,
enabled: true
})
}, },
onFocusMove(e) { onFocusMove(e) {
const speedVal = this.ptzSpeed(e.speed) const speedVal = this.ptzSpeed(e.speed)
@ -221,25 +238,18 @@ export default {
this.streamInfo = streamInfo this.streamInfo = streamInfo
this.hasAudio = hasAudio this.hasAudio = hasAudio
this.isLoging = false this.isLoging = false
this.videoUrl = this.getUrlByStreamInfo(streamInfo)
this.streamId = streamInfo.stream this.streamId = streamInfo.stream
this.app = streamInfo.app this.app = streamInfo.app
this.mediaServerId = streamInfo.mediaServerId this.mediaServerId = streamInfo.mediaServerId
this.showVideoDialog = true this.showVideoDialog = true
this.$nextTick(() => { this.$nextTick(() => {
if (this.$refs.playerTabs) { if (this.$refs.playerTabs) {
this.$refs.playerTabs.play(this.videoUrl) this.$refs.playerTabs.setStreamInfo(streamInfo)
} }
}) })
}, },
getUrlByStreamInfo(streamInfo) { playerChanged: function(playerUrlInfo) {
const info = streamInfo || this.streamInfo this.playerUrlInfo = playerUrlInfo
if (!info) return ''
const src = info.transcodeStream || info
if (location.protocol === 'https:') {
return src['wss_flv']
}
return src['ws_flv']
}, },
close: function() { close: function() {
if (this.$refs.playerTabs) { if (this.$refs.playerTabs) {
@ -249,9 +259,6 @@ export default {
this.showVideoDialog = false this.showVideoDialog = false
this.stopBroadcast() this.stopBroadcast()
}, },
videoError: function(e) {
console.log('播放器错误:' + JSON.stringify(e))
},
copyUrl: function(dropdownItem) { copyUrl: function(dropdownItem) {
this.$copyText(dropdownItem).then(() => { this.$copyText(dropdownItem).then(() => {
this.$message.success({ showClose: true, message: '成功拷贝到粘贴板' }) this.$message.success({ showClose: true, message: '成功拷贝到粘贴板' })
@ -318,7 +325,7 @@ export default {
.player-container { width: 100%; } .player-container { width: 100%; }
.control-side { flex: 2; min-width: 340px; display: flex; flex-direction: column; } .control-side { flex: 2; min-width: 340px; display: flex; flex-direction: column; }
.ptz-section { flex-shrink: 0; margin-bottom: 8px; } .ptz-section { flex-shrink: 0; margin-bottom: 8px; }
.control-tabs { flex: 1; display: flex; flex-direction: column; } .control-tabs { flex: 1; display: flex; flex-direction: column; min-height: 180px}
.control-tabs .el-tabs__content { flex: 1; overflow: auto; } .control-tabs .el-tabs__content { flex: 1; overflow: auto; }
.media-info-content { overflow: auto; } .media-info-content { overflow: auto; }
.media-row { display: flex; margin-bottom: 0.5rem; height: 2.5rem; } .media-row { display: flex; margin-bottom: 0.5rem; height: 2.5rem; }