|
|
@@ -1,75 +1,56 @@
|
|
|
<template>
|
|
|
<div
|
|
|
- class="return_item"
|
|
|
+ class="o-video"
|
|
|
+ :class="{ offline: !online }"
|
|
|
@mouseenter.stop="mouseOver"
|
|
|
@mouseleave.stop="mouseLeave"
|
|
|
>
|
|
|
<video
|
|
|
+ v-if="online"
|
|
|
ref="player"
|
|
|
- class="video"
|
|
|
+ class="o-video__player"
|
|
|
muted
|
|
|
autoplay
|
|
|
controls
|
|
|
- :style="{ height: returnheight }"
|
|
|
- :poster="require('@/assets//video-post.png')"
|
|
|
+ :poster="poster"
|
|
|
/>
|
|
|
<div
|
|
|
- class="onlinetip"
|
|
|
- :style="{ 'background-color': device.onlineStatus === 1 ? '#04A681' : '#E51414' }"
|
|
|
+ v-else
|
|
|
+ class="o-video__offline"
|
|
|
+ :style="{ zoom: zoomnum }"
|
|
|
>
|
|
|
- {{ device.onlineStatus === 1 ? '在线' : '离线' }}
|
|
|
+ 当前设备离线了
|
|
|
</div>
|
|
|
- <div class="mask1" />
|
|
|
<div
|
|
|
- v-if="device.onlineStatus !== 1"
|
|
|
- class="offline"
|
|
|
- >
|
|
|
- <img
|
|
|
- :src="require('@/assets/image_offline.svg')"
|
|
|
- alt=""
|
|
|
- >
|
|
|
- <div
|
|
|
- class="offlinetext"
|
|
|
- :style="{ zoom:zoomnum }"
|
|
|
- >
|
|
|
- 当前设备离线了
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ class="o-video__tip"
|
|
|
+ :class="{ online }"
|
|
|
+ />
|
|
|
+ <div class="o-video__name u-ellipsis">{{ device.name }}</div>
|
|
|
<div
|
|
|
- :style="{ display:maskshow }"
|
|
|
- class="mask"
|
|
|
+ v-show="maskShow"
|
|
|
+ class="o-video__mask"
|
|
|
>
|
|
|
<div
|
|
|
- class="playbtn"
|
|
|
- :style="{ zoom:zoomnum }"
|
|
|
- @click="videoplay"
|
|
|
+ class="o-video__btn u-pointer"
|
|
|
+ :style="{ zoom: zoomnum }"
|
|
|
+ @click="onPlay"
|
|
|
>
|
|
|
- <div
|
|
|
- :class="{ playing:device.paused, paused:!device.paused }"
|
|
|
- :style="{ display: refreshshow ? 'none' : 'block' }"
|
|
|
+ <i
|
|
|
+ class="o-video__icon has-bg"
|
|
|
+ :class="iconClass"
|
|
|
/>
|
|
|
- <img
|
|
|
- :src="require('@/assets/icon_refresh.png')"
|
|
|
- :style="{ display: refreshshow ? 'block' : 'none' }"
|
|
|
- class="refresh"
|
|
|
- alt=""
|
|
|
- >
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div class="o-video_buttom l-flex--row">
|
|
|
- <div class="l-flex__auto">{{ device.name }}</div>
|
|
|
- </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import flvjs from 'flv.js'
|
|
|
-import {
|
|
|
- authCode,
|
|
|
- detail
|
|
|
-} from '@/api/camera'
|
|
|
+import { authCode } from '@/api/camera'
|
|
|
+import videoPoster from '@/assets/video-poster.png'
|
|
|
|
|
|
const CAMERA_URL = `${location.protocol}//${process.env.VUE_APP_GATEWAY || location.host}`
|
|
|
+
|
|
|
export default {
|
|
|
name: 'DeviceCard',
|
|
|
props: {
|
|
|
@@ -80,57 +61,64 @@ export default {
|
|
|
zoomnum: {
|
|
|
type: String,
|
|
|
default: null
|
|
|
- },
|
|
|
- returnheight: {
|
|
|
- type: String,
|
|
|
- default: null
|
|
|
}
|
|
|
},
|
|
|
data () {
|
|
|
return {
|
|
|
- player: null,
|
|
|
- maskshow: 'none',
|
|
|
- refreshshow: false,
|
|
|
+ poster: videoPoster,
|
|
|
+ maskShow: false,
|
|
|
+ refreshShow: false,
|
|
|
first: false
|
|
|
}
|
|
|
},
|
|
|
+ computed: {
|
|
|
+ iconClass () {
|
|
|
+ if (this.refreshShow) {
|
|
|
+ return 'refresh'
|
|
|
+ }
|
|
|
+ return this.device.paused ? 'paused' : 'playing'
|
|
|
+ },
|
|
|
+ online () {
|
|
|
+ return this.device.onlineStatus === 1
|
|
|
+ }
|
|
|
+ },
|
|
|
created () {
|
|
|
- if (this.device.onlineStatus === 1) {
|
|
|
+ if (this.online) {
|
|
|
this.$timer = -1
|
|
|
this.getAuthCode()
|
|
|
}
|
|
|
},
|
|
|
beforeDestroy () {
|
|
|
- if (this.player) {
|
|
|
+ if (this.$player) {
|
|
|
clearTimeout(this.$timer)
|
|
|
this.destroyPlay()
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
mouseOver () {
|
|
|
- if (this.device.onlineStatus === 1) {
|
|
|
- this.maskshow = 'block'
|
|
|
+ if (this.online) {
|
|
|
+ this.maskShow = true
|
|
|
}
|
|
|
- if (this.player && !this.$refs.player.paused) {
|
|
|
+ if (this.$player && !this.$refs.player.paused) {
|
|
|
this.device.paused = false
|
|
|
} else {
|
|
|
this.device.paused = true
|
|
|
}
|
|
|
},
|
|
|
mouseLeave () {
|
|
|
- this.maskshow = 'none'
|
|
|
+ this.maskShow = false
|
|
|
},
|
|
|
- videoplay () {
|
|
|
+ onPlay () {
|
|
|
this.first = true
|
|
|
if (this.$refs.player.paused) {
|
|
|
- this.maskshow = 'none'
|
|
|
+ this.maskShow = false
|
|
|
}
|
|
|
- this.refreshshow = false
|
|
|
- if (this.player && !this.$refs.player.paused) {
|
|
|
+ this.refreshShow = false
|
|
|
+ if (this.$player && !this.$refs.player.paused) {
|
|
|
this.device.paused = true
|
|
|
- this.player.pause()
|
|
|
+ this.$player.pause()
|
|
|
} else {
|
|
|
- if (this.player) {
|
|
|
+ if (this.$player) {
|
|
|
this.destroyPlay()
|
|
|
}
|
|
|
this.device.paused = false
|
|
|
@@ -138,30 +126,20 @@ export default {
|
|
|
}
|
|
|
},
|
|
|
getAuthCode () {
|
|
|
- authCode({
|
|
|
- deviceId: this.device.id
|
|
|
- }).then(({ data }) => {
|
|
|
- const { token, expire, timestamp } = data
|
|
|
- this.getflv(timestamp, token, expire)
|
|
|
- })
|
|
|
+ authCode({ deviceId: this.device.id }).then(this.createPlayer)
|
|
|
},
|
|
|
- getDetail () {
|
|
|
- detail(this.device.id).then(({ data }) => {
|
|
|
- console.log(data)
|
|
|
- })
|
|
|
- },
|
|
|
- getflv (timestamp, token, expire) {
|
|
|
+ createPlayer ({ timestamp, token, expire }) {
|
|
|
if (flvjs.isSupported()) {
|
|
|
// 创建一个flvjs实例
|
|
|
const url = `${CAMERA_URL}/live/${this.device.id}.flv?authorization=${token}×tamp=${timestamp}&expire=${expire}`
|
|
|
- this.player = flvjs.createPlayer({
|
|
|
+ this.$player = flvjs.createPlayer({
|
|
|
type: 'flv',
|
|
|
isLive: true,
|
|
|
hasAudio: false,
|
|
|
url
|
|
|
})
|
|
|
- this.player.on('error', () => {
|
|
|
- this.refreshshow = true
|
|
|
+ this.$player.on('error', () => {
|
|
|
+ this.refreshShow = true
|
|
|
this.destroyPlay()
|
|
|
this.$message({
|
|
|
type: 'warning',
|
|
|
@@ -169,7 +147,7 @@ export default {
|
|
|
})
|
|
|
})
|
|
|
let decodedFrames = -1
|
|
|
- this.player.on('statistics_info', res => {
|
|
|
+ this.$player.on('statistics_info', res => {
|
|
|
decodedFrames = res.decodedFrames
|
|
|
})
|
|
|
this.$timer = setTimeout(() => {
|
|
|
@@ -179,18 +157,18 @@ export default {
|
|
|
type: 'warning',
|
|
|
message: `${this.device.name}设备没有视频流`
|
|
|
})
|
|
|
- this.refreshshow = true
|
|
|
+ this.refreshShow = true
|
|
|
}
|
|
|
}, 10000)
|
|
|
// 将实例挂载到video元素上面
|
|
|
- this.player.attachMediaElement(this.$refs.player)
|
|
|
+ this.$player.attachMediaElement(this.$refs.player)
|
|
|
|
|
|
try {
|
|
|
// 开始运行加载 只要流地址正常 就可以在h5页面中播放出画面了
|
|
|
- this.player.load()
|
|
|
- this.player.play()
|
|
|
+ this.$player.load()
|
|
|
+ this.$player.play()
|
|
|
if (!this.first) {
|
|
|
- this.player.pause()
|
|
|
+ this.$player.pause()
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.log('连接websocker异常', error)
|
|
|
@@ -198,145 +176,137 @@ export default {
|
|
|
}
|
|
|
},
|
|
|
destroyPlay () {
|
|
|
- this.player.pause()
|
|
|
- this.player.unload()
|
|
|
- this.player.detachMediaElement()
|
|
|
- this.player.destroy()
|
|
|
- this.player = null
|
|
|
+ this.$player.pause()
|
|
|
+ this.$player.unload()
|
|
|
+ this.$player.detachMediaElement()
|
|
|
+ this.$player.destroy()
|
|
|
+ this.$player = null
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
-//所有控件
|
|
|
-video::-webkit-media-controls-enclosure {
|
|
|
+video::-webkit-media-controls-fullscreen-button {
|
|
|
display: none;
|
|
|
}
|
|
|
-.video {
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- background-color: #000;
|
|
|
- object-fit: cover;
|
|
|
+
|
|
|
+video::-webkit-media-controls-enclosure {
|
|
|
+ display: none;
|
|
|
}
|
|
|
-.return_item {
|
|
|
- height: 100%;
|
|
|
+
|
|
|
+.o-video {
|
|
|
position: relative;
|
|
|
- // &:hover .mask{
|
|
|
- // display: block;
|
|
|
- // }
|
|
|
- .onlinetip {
|
|
|
+ padding-top: 56.25%;
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ &.offline {
|
|
|
+ background: url("~@/assets/image_offline.svg") 0 0 / 100% 100% no-repeat;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__player {
|
|
|
position: absolute;
|
|
|
top: 0;
|
|
|
- right: 0;
|
|
|
- font-size: 14px;
|
|
|
- text-align: center;
|
|
|
- color: #fff;
|
|
|
- width: 48px;
|
|
|
- height: 24px;
|
|
|
- line-height: 24px;
|
|
|
- background-color: #04a681;
|
|
|
- border-radius: 0px 4px 0px 4px;
|
|
|
- z-index: 2;
|
|
|
- }
|
|
|
- .mask1 {
|
|
|
+ left: 0;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__offline {
|
|
|
position: absolute;
|
|
|
- left: 0;
|
|
|
- top: 0;
|
|
|
+ top: 73%;
|
|
|
+ left: 50%;
|
|
|
+ color: $info;
|
|
|
+ font-size: 24px;
|
|
|
+ transform: translateX(-50%);
|
|
|
}
|
|
|
- .offline {
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
+
|
|
|
+ &__tip {
|
|
|
position: absolute;
|
|
|
- left: 0;
|
|
|
top: 0;
|
|
|
- img {
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- object-fit: cover;
|
|
|
- border-radius: 4px;
|
|
|
+ right: 0;
|
|
|
+ width: 48px;
|
|
|
+ height: 24px;
|
|
|
+ color: #fff;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 24px;
|
|
|
+ text-align: center;
|
|
|
+ border-radius: 0 0 0 4px;
|
|
|
+ background-color: $error--dark;
|
|
|
+ z-index: 9;
|
|
|
+
|
|
|
+ &::after {
|
|
|
+ content: "离线";
|
|
|
}
|
|
|
- .offlinetext {
|
|
|
- font-size: 24px;
|
|
|
- color: #fff;
|
|
|
- position: absolute;
|
|
|
- top: 72%;
|
|
|
- left: 50%;
|
|
|
- transform: translateX(-50%);
|
|
|
+
|
|
|
+ &.online {
|
|
|
+ background-color: $success--dark;
|
|
|
+
|
|
|
+ &::after {
|
|
|
+ content: "在线";
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- .mask {
|
|
|
+
|
|
|
+ &__name {
|
|
|
+ position: absolute;
|
|
|
width: 100%;
|
|
|
- height: 100%;
|
|
|
+ bottom: 0;
|
|
|
+ padding: 24px 16px 16px;
|
|
|
+ color: #fff;
|
|
|
+ background-image: linear-gradient(
|
|
|
+ to bottom,
|
|
|
+ rgba(#000, 0) 0%,
|
|
|
+ rgba(#000, 0.6) 100%
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ &__mask {
|
|
|
position: absolute;
|
|
|
- left: 0;
|
|
|
top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
background-color: rgba(0, 0, 0, 0.3);
|
|
|
- display: none;
|
|
|
z-index: 2;
|
|
|
}
|
|
|
- .playbtn {
|
|
|
+
|
|
|
+ &__btn {
|
|
|
position: absolute;
|
|
|
left: 50%;
|
|
|
top: 50%;
|
|
|
- transform: translate(-50%, -50%);
|
|
|
- width: 110px;
|
|
|
- height: 110px;
|
|
|
- background-color: rgba(244, 247, 251, 0.5);
|
|
|
+ width: 128px;
|
|
|
+ padding-top: 128px;
|
|
|
border-radius: 50%;
|
|
|
- cursor: pointer;
|
|
|
- .playing {
|
|
|
- width: 0;
|
|
|
- height: 0;
|
|
|
+ background-color: rgba(#f4f7fb, 0.5);
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+ }
|
|
|
+
|
|
|
+ &__icon {
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+
|
|
|
+ &.playing {
|
|
|
border-top: 22px solid transparent;
|
|
|
border-left: 37px solid #fff;
|
|
|
border-bottom: 22px solid transparent;
|
|
|
- border-right: 37px solid transparent;
|
|
|
- position: absolute;
|
|
|
- left: 50%;
|
|
|
- top: 50%;
|
|
|
transform: translate(-15px, -50%);
|
|
|
}
|
|
|
- .paused::before {
|
|
|
- content: "";
|
|
|
- width: 4px;
|
|
|
- height: 37px;
|
|
|
- background-color: #fff;
|
|
|
- position: absolute;
|
|
|
- left: 45px;
|
|
|
- top: 50%;
|
|
|
- transform: translateY(-50%);
|
|
|
- }
|
|
|
- .paused::after {
|
|
|
- content: "";
|
|
|
- width: 4px;
|
|
|
- height: 37px;
|
|
|
- background-color: #fff;
|
|
|
- position: absolute;
|
|
|
- right: 45px;
|
|
|
- top: 50%;
|
|
|
- transform: translateY(-50%);
|
|
|
+
|
|
|
+ &.paused {
|
|
|
+ width: 40%;
|
|
|
+ height: 60%;
|
|
|
+ border-left: 10px solid #fff;
|
|
|
+ border-right: 10px solid #fff;
|
|
|
}
|
|
|
- .refresh {
|
|
|
- width: 40px;
|
|
|
- height: 40px;
|
|
|
- position: absolute;
|
|
|
- left: 50%;
|
|
|
- top: 50%;
|
|
|
- transform: translate(-50%, -50%);
|
|
|
+
|
|
|
+ &.refresh {
|
|
|
+ width: 60%;
|
|
|
+ height: 60%;
|
|
|
+ background-image: url("~@/assets/icon_refresh.png");
|
|
|
}
|
|
|
}
|
|
|
- .o-video_buttom {
|
|
|
- position: absolute;
|
|
|
- bottom: 0px;
|
|
|
- width: 100%;
|
|
|
- height: 58px;
|
|
|
- background-image: linear-gradient(0deg, rgba(6, 11, 18, 0.9), transparent);
|
|
|
- border-radius: 0px 0px 4px 4px;
|
|
|
- color: #fff;
|
|
|
- padding: 0 16px;
|
|
|
- }
|
|
|
}
|
|
|
</style>
|