| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- <template>
- <div
- class="o-video is-ratio--16_9"
- :class="{ offline: !online, mask: !isPlaying, controls, floating, fullscreen: isFullscreen }"
- @mousemove="onMouseMove"
- @click.stop="onClick"
- >
- <template v-if="online">
- <video
- ref="video"
- class="o-video__player o-simple-video"
- :poster="poster"
- autoplay
- muted
- @play="onVideoPlay"
- @pause="onVideoPause"
- @waiting="onVideoWaiting"
- @playing="onVideoPlaying"
- @error="onVideoError"
- @ended="onVideoEnded"
- />
- <div class="o-video__mask">
- <div
- class="l-flex--row center o-video__btn u-pointer"
- @click.stop="onPlayOrPause"
- >
- <i :class="statusIconClass" />
- </div>
- </div>
- </template>
- <div
- v-if="controls"
- class="l-flex--row c-footer u-font-size--sm"
- >
- <div class="l-flex__fill c-sibling-item u-ellipsis">
- {{ device.name }}
- </div>
- <slot
- name="controls"
- :can-play="canPlay"
- :on-full-screen="onFullScreen"
- :waiting-or-loading="loading || waiting"
- :online="online"
- :is-playing="isPlaying"
- >
- <template v-if="online">
- <i
- v-if="loadingQuality"
- class="c-sibling-item el-icon-loading"
- />
- <div
- v-else
- class="l-flex__none c-sibling-item o-quality-menu u-pointer"
- @click.stop="toggleQualityMenu"
- >
- <div
- v-if="showQualityMenu"
- class="o-quality-menu__list u-font-size--sm u-text--center"
- @click.stop
- >
- <div
- v-for="item in qualities"
- :key="item.value"
- class="o-quality-menu__item has-active"
- :class="{ 'u-color--success': quality.value === item.value }"
- @click.stop="changeQuality(item)"
- >
- {{ item.label }}
- </div>
- </div>
- <span class="has-active">
- {{ quality.label }}
- </span>
- </div>
- <i
- class="c-sibling-item el-icon-full-screen has-active"
- @click.stop="onFullScreen"
- />
- </template>
- </slot>
- </div>
- </div>
- </template>
- <script>
- import {
- GATEWAY,
- Quality
- } from '@/constant.js'
- import {
- authCode,
- getRecordConfig,
- addRecordConfig,
- updateRecordConfig,
- getDevice
- } from '@/api/device.js'
- import playerMixin from '../player.js'
- export default {
- name: 'DevicePlayer',
- mixins: [playerMixin],
- props: {
- device: {
- type: Object,
- required: true
- },
- checkOnline: {
- type: [Boolean, String],
- default: false
- },
- useInitial: {
- type: [Boolean, String],
- default: false
- }
- },
- data () {
- return {
- online: false,
- floating: true,
- qualities: [
- { value: 'f', label: '标清' },
- { value: 'ff', label: '高清' },
- { value: 'fff', label: '超清' }
- ],
- loadingQuality: true,
- showQualityMenu: false,
- quality: null,
- recordConfig: null
- }
- },
- computed: {
- deviceOnline () {
- return this.device.onlineStatus === 1
- },
- canPlay () {
- return !this.loading && !this.needReset
- }
- },
- watch: {
- deviceOnline (val) {
- if (this.checkOnline) {
- return
- }
- this.updateOnlineStatus(val)
- },
- isFullscreen () {
- this.onMouseMove()
- }
- },
- created () {
- this.$delayMoveTimer = -1
- this.$checkTimer = -1
- },
- mounted () {
- if (this.checkOnline && !this.useInitial) {
- this.createPlayer()
- } else {
- this.updateOnlineStatus(this.deviceOnline)
- }
- },
- beforeDestroy () {
- clearTimeout(this.$delayMoveTimer)
- clearTimeout(this.$checkTimer)
- this.hideQualityMenu()
- },
- methods: {
- onClick () {
- this.$emit('click', this.device)
- },
- onMouseMove () {
- if (this.keep) {
- return
- }
- clearTimeout(this.$delayMoveTimer)
- this.floating = false
- if (!this.isFullscreen) {
- this.$delayMoveTimer = setTimeout(() => {
- this.floating = true
- }, 3000)
- }
- },
- onVideoReset () {
- this.recordConfig = null
- this.$playerInfo = null
- },
- getRecordConfig () {
- this.loadingQuality = true
- getRecordConfig(this.device.id, { custom: true }).then(
- ({ data }) => {
- if (data) {
- this.loadingQuality = false
- this.onUpdateRecordConfig(data)
- } else {
- this.setRecordConfig(this.qualities[0])
- }
- },
- () => {
- this.loadingQuality = false
- this.onVideoDestroyByError('获取回采配置失败')
- }
- )
- },
- onUpdateRecordConfig (data) {
- const { videoWidth } = data
- const key = Object.keys(Quality).find(key => Quality[key].videoWidth === videoWidth) || 'fff'
- this.quality = this.qualities.find(({ value }) => value === key) || this.qualities[0]
- this.recordConfig = data
- this.onCreatePlayer()
- },
- setRecordConfig (quality) {
- this.loadingQuality = true
- ;(this.recordConfig ? updateRecordConfig : addRecordConfig)({
- deviceId: this.device.id,
- ...Quality[quality.value]
- }, { custom: true }).then(
- ({ data }) => {
- this.loadingQuality = false
- this.destroyPlayer()
- this.onUpdateRecordConfig(data)
- },
- () => {
- this.loadingQuality = false
- if (!this.recordConfig) {
- this.onVideoDestroyByError('设置初始回采配置失败')
- }
- }
- )
- },
- hideQualityMenu () {
- if (this.showQualityMenu) {
- this.showQualityMenu = false
- document.removeEventListener('click', this.hideQualityMenu)
- }
- },
- toggleQualityMenu () {
- if (this.showQualityMenu) {
- this.hideQualityMenu()
- } else {
- document.addEventListener('click', this.hideQualityMenu)
- this.showQualityMenu = true
- }
- },
- changeQuality (quality) {
- if (this.quality.value !== quality.value) {
- this.setRecordConfig(quality)
- } else if (this.needReset) {
- this.createPlayer()
- }
- this.hideQualityMenu()
- },
- getAuthCode () {
- this.$playerInfo = null
- authCode(this.recordConfig.stream, { custom: true }).then(
- ({ data }) => {
- this.$playerInfo = data
- this.onCreatePlayer()
- },
- () => {
- this.onVideoDestroyByError('获取授权失败')
- }
- )
- },
- updateOnlineStatus (online) {
- this.online = online
- if (online) {
- this.$nextTick(this.createPlayer)
- } else {
- this.hideQualityMenu()
- this.onVideoReset()
- this.destroyPlayer()
- }
- },
- createPlayer () {
- if (this.$timer === null) {
- return
- }
- this.loading = true
- if (this.checkOnline) {
- clearTimeout(this.$checkTimer)
- getDevice(this.device.id, { custom: true }).then(
- ({ data }) => {
- if (this.$timer === null) {
- return
- }
- if (data) {
- const online = data.onlineStatus === 1
- this.online = online
- if (online) {
- this.$nextTick(this.onCreatePlayer)
- } else {
- this.hideQualityMenu()
- this.destroyPlayer()
- this.onVideoReset()
- this.checkOnlineStatus(5000)
- }
- }
- },
- () => {
- if (this.$timer === null) {
- return
- }
- this.checkOnlineStatus(2000)
- }
- )
- } else {
- this.onCreatePlayer()
- }
- },
- onCreatePlayer () {
- if (this.$timer === null) {
- return
- }
- if (!this.recordConfig) {
- this.getRecordConfig()
- return
- }
- // if (!this.$playerInfo) {
- // this.getAuthCode()
- // return
- // }
- // const { vhost = '__defaultVhost__', token, timestamp, expire } = this.$playerInfo
- // if (Number(timestamp) + Number(expire) * 1000 <= Date.now()) {
- // this.getAuthCode()
- // return
- // }
- // this.playUrl(`${GATEWAY}/live/${this.recordConfig.stream}.flv?vhost=${vhost}&authorization=${token}×tamp=${timestamp}&expire=${expire}`)
- this.playUrl(`${GATEWAY}/live/${this.recordConfig.stream}.flv?vhost=__defaultVhost__`)
- },
- checkOnlineStatus (delay = 5000) {
- clearTimeout(this.$checkTimer)
- this.$checkTimer = setTimeout(this.createPlayer, delay + Math.random() * delay | 0)
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .o-quality-menu {
- display: inline-block;
- position: relative;
- padding: 0 $padding--xs;
- z-index: 1;
- &__list {
- position: absolute;
- right: 0;
- bottom: 100%;
- width: 100%;
- margin-bottom: $spacing--2xs;
- border-radius: $radius;
- background-color: rgba(#000, 0.85);
- z-index: -1;
- }
- &__item {
- padding: $padding--2xs 0;
- }
- }
- </style>
|