feat: 重建 Sense 单路实时监看 (#68)
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<div class="sense-video-player" :aria-busy="busy ? 'true' : 'false'">
|
||||
<iframe
|
||||
v-if="playerUrl && playable"
|
||||
:key="playerUrl"
|
||||
class="sense-video-player__frame"
|
||||
:src="playerUrl"
|
||||
title="Sense 单路实时视频"
|
||||
allow="autoplay; fullscreen"
|
||||
sandbox="allow-scripts allow-same-origin allow-forms"
|
||||
referrerpolicy="no-referrer"
|
||||
@load="$emit('loaded')"
|
||||
/>
|
||||
<div v-if="state !== 'ready'" class="sense-video-player__state" :class="{ 'is-overlay': playerUrl && playable }" aria-live="polite">
|
||||
<el-icon v-if="busy" class="is-loading sense-video-player__icon" aria-hidden="true"><Loading /></el-icon>
|
||||
<el-icon v-else class="sense-video-player__icon" aria-hidden="true"><WarningFilled /></el-icon>
|
||||
<strong>{{ title }}</strong>
|
||||
<span>{{ message }}</span>
|
||||
<el-button v-if="recoverable" type="primary" :loading="retrying" @click="$emit('retry')">重新连接</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { playbackStatusDetail, playbackStatusLabel } from '@/views/sense/liveview/playbackStatus'
|
||||
import { Loading, WarningFilled } from '@element-plus/icons-vue'
|
||||
|
||||
export default {
|
||||
name: 'SenseVideoPlayer',
|
||||
components: { Loading, WarningFilled },
|
||||
props: {
|
||||
state: { type: String, default: 'loading' },
|
||||
detail: { type: String, default: '' },
|
||||
playerUrl: { type: String, default: '' },
|
||||
retrying: { type: Boolean, default: false }
|
||||
},
|
||||
emits: ['retry', 'loaded'],
|
||||
computed: {
|
||||
busy() {
|
||||
return this.state === 'loading' || this.state === 'waiting'
|
||||
},
|
||||
playable() {
|
||||
return ['loading', 'waiting', 'ready'].includes(this.state)
|
||||
},
|
||||
recoverable() {
|
||||
return !this.busy && this.state !== 'ready'
|
||||
},
|
||||
title() {
|
||||
return playbackStatusLabel(this.state)
|
||||
},
|
||||
message() {
|
||||
return playbackStatusDetail(this.state, this.detail)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.sense-video-player {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
aspect-ratio: 16 / 9;
|
||||
min-height: 280px;
|
||||
overflow: hidden;
|
||||
border-radius: var(--el-border-radius-base);
|
||||
background: #101419;
|
||||
}
|
||||
|
||||
.sense-video-player__frame {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.sense-video-player__state {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
padding: 24px;
|
||||
color: #dcdfe6;
|
||||
text-align: center;
|
||||
background: #101419;
|
||||
}
|
||||
|
||||
.sense-video-player__state.is-overlay {
|
||||
pointer-events: none;
|
||||
background: rgb(16 20 25 / 78%);
|
||||
}
|
||||
|
||||
.sense-video-player__state strong {
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.sense-video-player__state span {
|
||||
max-width: 640px;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.sense-video-player__state .el-button {
|
||||
pointer-events: auto;
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
.sense-video-player__icon {
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.sense-video-player {
|
||||
min-height: 210px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.sense-video-player__icon {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user