feat:完善监控播放器
This commit is contained in:
@@ -10,11 +10,13 @@
|
|||||||
:key="index"
|
:key="index"
|
||||||
@click="handleItem(item)"
|
@click="handleItem(item)"
|
||||||
>
|
>
|
||||||
<div>
|
<HlsPlayer :url="item.hlsUrl" />
|
||||||
|
<div class="item-unfollow" @click.stop="handleUnfollow(item.id, index)">取消关注</div>
|
||||||
|
<!-- <div>
|
||||||
<p class="item-title--primary">
|
<p class="item-title--primary">
|
||||||
{{ item.cameraName || item.cameraIndexCode }}
|
{{ item.cameraName || item.cameraIndexCode }}
|
||||||
</p>
|
</p>
|
||||||
<div class="item-unfollow" @click.stop="handleUnfollow(item.id, index)">取消关注</div>
|
|
||||||
<video
|
<video
|
||||||
class="item-img"
|
class="item-img"
|
||||||
:id="'video' + index"
|
:id="'video' + index"
|
||||||
@@ -25,7 +27,7 @@
|
|||||||
>
|
>
|
||||||
<source src="" type="application/x-mpegURL" />
|
<source src="" type="application/x-mpegURL" />
|
||||||
</video>
|
</video>
|
||||||
</div>
|
</div> -->
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -65,25 +67,25 @@
|
|||||||
pageSize: 5
|
pageSize: 5
|
||||||
})
|
})
|
||||||
list.value = res.data
|
list.value = res.data
|
||||||
nextTick(() => {
|
// nextTick(() => {
|
||||||
list.value.forEach(async (item, index) => {
|
// list.value.forEach(async (item, index) => {
|
||||||
var video = document.getElementById(`video${index}`)
|
// var video = document.getElementById(`video${index}`)
|
||||||
const hls = new Hls({
|
// const hls = new Hls({
|
||||||
enableWorker: false, // 禁用 Worker 来避免额外的线程
|
// enableWorker: false, // 禁用 Worker 来避免额外的线程
|
||||||
enableSoftwareAES: true, // 使用软件解码器以避免硬件解码的额外请求
|
// enableSoftwareAES: true, // 使用软件解码器以避免硬件解码的额外请求
|
||||||
cache: true, // 启用缓存
|
// cache: true, // 启用缓存
|
||||||
maxBufferLength: 10, // 最大缓冲长度(秒)
|
// maxBufferLength: 10, // 最大缓冲长度(秒)
|
||||||
maxMaxBufferLength: 15, // 缓冲区长度的上限
|
// maxMaxBufferLength: 15, // 缓冲区长度的上限
|
||||||
maxBufferSize: 20 * 1000 * 1000 // 最大缓冲大小(字节)
|
// maxBufferSize: 20 * 1000 * 1000 // 最大缓冲大小(字节)
|
||||||
})
|
// })
|
||||||
hls.loadSource(item.hlsUrl)
|
// hls.loadSource(item.hlsUrl)
|
||||||
hls.attachMedia(video)
|
// hls.attachMedia(video)
|
||||||
hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
// hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
||||||
video.play()
|
// video.play()
|
||||||
})
|
// })
|
||||||
hlsRefs.push(hls)
|
// hlsRefs.push(hls)
|
||||||
})
|
// })
|
||||||
})
|
// })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 释放hls实例
|
// 释放hls实例
|
||||||
@@ -177,6 +179,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
|
position: relative;
|
||||||
margin-bottom: vh(10);
|
margin-bottom: vh(10);
|
||||||
padding: vw(10);
|
padding: vw(10);
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
@@ -186,11 +189,11 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
right: vw(4);
|
right: vw(4);
|
||||||
top: vw(4);
|
top: vw(4);
|
||||||
z-index: 99;
|
z-index: 99999;
|
||||||
width: vw(64);
|
width: vw(64);
|
||||||
height: vh(24);
|
height: vw(30);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: vh(24);
|
line-height: vw(30);
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: vw(12);
|
font-size: vw(12);
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
@@ -202,10 +205,6 @@
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
& > div {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-title {
|
&-title {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|||||||
325
src/components/HlsPlayer/index.vue
Normal file
325
src/components/HlsPlayer/index.vue
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
<template>
|
||||||
|
<div v-show="isActive" class="myVideo-container">
|
||||||
|
<video
|
||||||
|
class="myVideo"
|
||||||
|
ref="videoElement"
|
||||||
|
muted
|
||||||
|
:style="videoStyle"
|
||||||
|
playsinline
|
||||||
|
:controls="false"
|
||||||
|
disablePictureInPicture
|
||||||
|
></video>
|
||||||
|
<div v-if="loading" class="loading-overlay pointer-events-none">
|
||||||
|
<div class="loading-text">{{ loadingText }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Hls from 'hls.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'HlsPlayer',
|
||||||
|
props: {
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
isActive: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '100%'
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '100%'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
hls: null,
|
||||||
|
video: null,
|
||||||
|
loading: false,
|
||||||
|
loadingText: '加载中...',
|
||||||
|
retryCount: 0,
|
||||||
|
maxRetries: 3,
|
||||||
|
isReady: false,
|
||||||
|
playAttempts: 0,
|
||||||
|
maxPlayAttempts: 3,
|
||||||
|
cleanupTimeout: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
videoStyle() {
|
||||||
|
const style = {}
|
||||||
|
if (this.width) {
|
||||||
|
style.width = typeof this.width === 'number' ? `${this.width}px` : this.width
|
||||||
|
}
|
||||||
|
if (this.height) {
|
||||||
|
style.height = typeof this.height === 'number' ? `${this.height}px` : this.height
|
||||||
|
}
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
isActive: {
|
||||||
|
handler(newValue) {
|
||||||
|
if (newValue) {
|
||||||
|
this.$nextTick(this.initializePlayer)
|
||||||
|
} else {
|
||||||
|
this.immediateCleanup()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
url(newUrl) {
|
||||||
|
if (newUrl && this.isActive) {
|
||||||
|
this.initializePlayer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.video = this.$refs.videoElement
|
||||||
|
this.registerVideoEvents()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
registerVideoEvents() {
|
||||||
|
const events = ['canplay', 'waiting', 'playing', 'error', 'stalled', 'suspend']
|
||||||
|
|
||||||
|
events.forEach((event) => {
|
||||||
|
this.video.addEventListener(event, this.handleVideoEvent)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
handleVideoEvent(event) {
|
||||||
|
switch (event.type) {
|
||||||
|
case 'canplay':
|
||||||
|
this.isReady = true
|
||||||
|
break
|
||||||
|
case 'waiting':
|
||||||
|
this.showLoadingIndicator('缓冲中...')
|
||||||
|
break
|
||||||
|
case 'playing':
|
||||||
|
this.loading = false
|
||||||
|
break
|
||||||
|
case 'error':
|
||||||
|
this.handlePlaybackError()
|
||||||
|
break
|
||||||
|
case 'stalled':
|
||||||
|
this.showLoadingIndicator('播放卡顿...')
|
||||||
|
break
|
||||||
|
case 'suspend':
|
||||||
|
this.cleanupNetworkResources()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
immediateCleanup() {
|
||||||
|
// 立即停止网络请求
|
||||||
|
if (this.hls) {
|
||||||
|
this.hls.stopLoad()
|
||||||
|
this.hls.detachMedia()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 延迟完全清理以避免播放卡顿
|
||||||
|
this.cleanupTimeout = setTimeout(() => {
|
||||||
|
// 仅在不重新初始化播放器时才调用 fullCleanup
|
||||||
|
if (!this.url || !this.isActive) {
|
||||||
|
this.fullCleanup()
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
},
|
||||||
|
|
||||||
|
fullCleanup() {
|
||||||
|
if (this.hls) {
|
||||||
|
this.hls.destroy()
|
||||||
|
this.hls = null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.video) {
|
||||||
|
this.video.pause()
|
||||||
|
this.video.removeAttribute('src')
|
||||||
|
this.video.load()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loading = false
|
||||||
|
this.retryCount = 0
|
||||||
|
this.isReady = false
|
||||||
|
this.playAttempts = 0
|
||||||
|
|
||||||
|
if (this.cleanupTimeout) {
|
||||||
|
clearTimeout(this.cleanupTimeout)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
initializePlayer() {
|
||||||
|
if (!this.isActive || !this.url) return
|
||||||
|
|
||||||
|
// 如果是重新初始化播放器,先清理已存在的资源
|
||||||
|
if (this.hls) {
|
||||||
|
this.immediateCleanup()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hls = new Hls({
|
||||||
|
// 内存优化配置
|
||||||
|
maxBufferSize: 15 * 1000 * 1000, // 降低缓冲区大小(15MB)
|
||||||
|
maxBufferLength: 50, // 更小的缓冲窗口
|
||||||
|
liveSyncDuration: 1, // 紧跟直播点
|
||||||
|
liveMaxLatencyDuration: 5, // 最大延迟5秒
|
||||||
|
liveDurationInfinity: true,
|
||||||
|
lowLatencyMode: false, // 启用低延迟模式
|
||||||
|
maxMaxBufferLength: 60,
|
||||||
|
backBufferLength: 1, // 减少保留的缓冲数据
|
||||||
|
manifestLoadingTimeOut: 10000,
|
||||||
|
manifestLoadingMaxRetry: 5,
|
||||||
|
fragLoadingTimeOut: 5000,
|
||||||
|
fragLoadingMaxRetry: 2,
|
||||||
|
enableWorker: true, // 启用Web Worker
|
||||||
|
recycleVideoFrames: true, // 启用帧回收
|
||||||
|
|
||||||
|
startLevel: -1,
|
||||||
|
autoStartLoad: true,
|
||||||
|
maxBufferHole: 2, // 允许更大的时间缺口
|
||||||
|
highBufferWatchdogPeriod: 4, // 延长监控周期
|
||||||
|
nudgeMaxRetry: 5, // 增加微调重试次数
|
||||||
|
nudgeOffset: 0.05, // 微调步长(秒)
|
||||||
|
jumpGaps: false,
|
||||||
|
stallThreshold: 1000
|
||||||
|
})
|
||||||
|
|
||||||
|
this.hls.attachMedia(this.video)
|
||||||
|
this.hls.loadSource(this.url)
|
||||||
|
|
||||||
|
// 事件处理
|
||||||
|
this.hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
||||||
|
this.loading = false
|
||||||
|
this.retryCount = 0
|
||||||
|
this.safePlay()
|
||||||
|
})
|
||||||
|
|
||||||
|
this.hls.on(Hls.Events.ERROR, (event, data) => {
|
||||||
|
this.handleHlsError(data)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.hls.on(Hls.Events.BUFFER_EOS, () => {
|
||||||
|
this.cleanupNetworkResources()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
cleanupNetworkResources() {
|
||||||
|
// 清理已播放的缓冲数据
|
||||||
|
if (this.hls && this.video) {
|
||||||
|
try {
|
||||||
|
const currentTime = this.video.currentTime
|
||||||
|
this.hls.mediaBuffer = null
|
||||||
|
if (this.hls.bufferTimer) {
|
||||||
|
clearInterval(this.hls.bufferTimer)
|
||||||
|
}
|
||||||
|
this.hls.flushBuffer()
|
||||||
|
this.video.currentTime = currentTime
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Buffer cleanup error:', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleHlsError(data) {
|
||||||
|
console.error('HLS Error:', data)
|
||||||
|
if (data.fatal) {
|
||||||
|
switch (data.type) {
|
||||||
|
case Hls.ErrorTypes.NETWORK_ERROR:
|
||||||
|
this.retryLoad()
|
||||||
|
break
|
||||||
|
case Hls.ErrorTypes.MEDIA_ERROR:
|
||||||
|
this.hls.recoverMediaError()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
this.fullCleanup()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
retryLoad() {
|
||||||
|
if (this.retryCount < this.maxRetries) {
|
||||||
|
this.retryCount++
|
||||||
|
this.showLoadingIndicator(`重试第 ${this.retryCount} 次...`)
|
||||||
|
setTimeout(() => this.initializePlayer(), 2000)
|
||||||
|
} else {
|
||||||
|
this.showLoadingIndicator('视频加载失败')
|
||||||
|
this.fullCleanup()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
showLoadingIndicator(text) {
|
||||||
|
this.loading = true
|
||||||
|
this.loadingText = text
|
||||||
|
},
|
||||||
|
|
||||||
|
async safePlay() {
|
||||||
|
if (!this.video || this.playAttempts >= this.maxPlayAttempts) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.playAttempts++
|
||||||
|
if (this.video.readyState >= 2) {
|
||||||
|
await this.video.play()
|
||||||
|
this.playAttempts = 0
|
||||||
|
} else {
|
||||||
|
setTimeout(this.safePlay, 500)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('播放失败:', error)
|
||||||
|
setTimeout(this.safePlay, 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
// 移除所有事件监听
|
||||||
|
if (this.video) {
|
||||||
|
const events = ['canplay', 'waiting', 'playing', 'error', 'stalled', 'suspend']
|
||||||
|
events.forEach((event) => {
|
||||||
|
this.video.removeEventListener(event, this.handleVideoEvent)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.fullCleanup()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.myVideo-container {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.myVideo {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
// aspect-ratio: 16/9;
|
||||||
|
/* border: 1px solid #ccc; */
|
||||||
|
border-radius: vw(5);
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-text {
|
||||||
|
color: white;
|
||||||
|
padding: vw(10);
|
||||||
|
border-radius: vw(4);
|
||||||
|
background: rgba(0, 0, 0, 0.6);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -8,11 +8,13 @@
|
|||||||
:z-index="9999"
|
:z-index="9999"
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
>
|
>
|
||||||
<div v-if="src" class="dialog-box">
|
<div class="dialog-box">
|
||||||
<video class="video" ref="videoRef" muted autoplay controls>
|
<div class="video">
|
||||||
|
<HlsPlayer :url="src" />
|
||||||
|
</div>
|
||||||
|
<!-- <video class="video" ref="videoRef" muted autoplay controls>
|
||||||
<source type="application/x-mpegURL" />
|
<source type="application/x-mpegURL" />
|
||||||
</video>
|
</video> -->
|
||||||
|
|
||||||
<div class="action-box">
|
<div class="action-box">
|
||||||
<div class="action-item">
|
<div class="action-item">
|
||||||
<img src="@/assets/images/plus.png" title="焦距变大" @click="handleAction(Z00M_IN)" />
|
<img src="@/assets/images/plus.png" title="焦距变大" @click="handleAction(Z00M_IN)" />
|
||||||
@@ -33,7 +35,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p v-else class="none">暂无信号</p>
|
|
||||||
<img class="close" src="@/assets/images/close.png" @click="handleClose" />
|
<img class="close" src="@/assets/images/close.png" @click="handleClose" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -71,19 +72,19 @@
|
|||||||
let webRtcServer = null
|
let webRtcServer = null
|
||||||
let hlsRef = null
|
let hlsRef = null
|
||||||
|
|
||||||
watch(
|
// watch(
|
||||||
() => modelValue.value,
|
// () => modelValue.value,
|
||||||
(val) => {
|
// (val) => {
|
||||||
if (val) {
|
// if (val) {
|
||||||
setTimeout(() => {
|
// setTimeout(() => {
|
||||||
init()
|
// init()
|
||||||
}, 1000)
|
// }, 1000)
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
immediate: true
|
// immediate: true
|
||||||
}
|
// }
|
||||||
)
|
// )
|
||||||
|
|
||||||
const handleAction = async (e) => {
|
const handleAction = async (e) => {
|
||||||
if (e == STOP) {
|
if (e == STOP) {
|
||||||
@@ -106,8 +107,10 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
|
if (hlsRef) {
|
||||||
hlsRef.destroy()
|
hlsRef.destroy()
|
||||||
hlsRef = null
|
hlsRef = null
|
||||||
|
}
|
||||||
modelValue.value = false
|
modelValue.value = false
|
||||||
}
|
}
|
||||||
const init = () => {
|
const init = () => {
|
||||||
@@ -179,6 +182,8 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
|
width: vw(1814);
|
||||||
|
height: vw(980);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: vw(30);
|
font-size: vw(30);
|
||||||
|
|||||||
@@ -21,14 +21,20 @@
|
|||||||
<el-input placeholder="请输入内容" v-model="cameraName" clearable @input="onInput" />
|
<el-input placeholder="请输入内容" v-model="cameraName" clearable @input="onInput" />
|
||||||
<img class="search-icon" src="/src/assets/images/search-icon-1.png" alt="" />
|
<img class="search-icon" src="/src/assets/images/search-icon-1.png" alt="" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tree-box">
|
<div class="tree-box">
|
||||||
<div class="tree-item" v-for="(item, i) in regionList" :key="i">
|
<div class="tree-item" v-for="(item, i) in regionList" :key="i">
|
||||||
<div class="tree-item__node" @click="handleRegions(i)">
|
<div class="tree-item__node" @click="handleRegions(i)">
|
||||||
<img class="tree-item__icon" src="@/assets/images/node.png" alt="" />
|
<img
|
||||||
|
class="tree-item__icon"
|
||||||
|
:class="{ 'tree-item__icon-up': item.show }"
|
||||||
|
src="@/assets/images/arrow-down.png"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
<span class="tree-item__name">{{ item.regions }}</span>
|
<span class="tree-item__name">{{ item.regions }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!item.show" class="tree-item__child">
|
<div v-if="item.show" class="tree-item__child">
|
||||||
<img class="tree-item-top__icon" src="@/assets/images/node.png" alt="" />
|
<!-- <img class="tree-item-top__icon" src="@/assets/images/node.png" alt="" /> -->
|
||||||
<div
|
<div
|
||||||
class="tree-item__child-item"
|
class="tree-item__child-item"
|
||||||
v-for="(resource, x) in item.videoResources"
|
v-for="(resource, x) in item.videoResources"
|
||||||
@@ -179,6 +185,11 @@
|
|||||||
const STOP = 'STOP' // 停止操作
|
const STOP = 'STOP' // 停止操作
|
||||||
let ACTION = '0'
|
let ACTION = '0'
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
value: 'id',
|
||||||
|
label: 'label',
|
||||||
|
children: 'children'
|
||||||
|
}
|
||||||
let command = ref('')
|
let command = ref('')
|
||||||
let videoList = ref([])
|
let videoList = ref([])
|
||||||
let navList = ref([])
|
let navList = ref([])
|
||||||
@@ -377,24 +388,10 @@
|
|||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
let res = await getVideoRegionsApi({
|
let res = await getVideoRegionsApi({
|
||||||
businessScenicArea: params.businessScenicArea,
|
cameraName: cameraName.value,
|
||||||
cameraName: cameraName.value
|
businessScenicArea: params.businessScenicArea
|
||||||
})
|
})
|
||||||
regionList.value = res.data
|
regionList.value = res.data
|
||||||
console.log(regionList.value, 'regionList.value')
|
|
||||||
// .map((i) => {
|
|
||||||
// return {
|
|
||||||
// ...i,
|
|
||||||
// label: i.regions,
|
|
||||||
// children: i.videoResources.map((x) => {
|
|
||||||
// return {
|
|
||||||
// ...x,
|
|
||||||
// label: x.cameraName || x.cameraIndexCode,
|
|
||||||
// children: []
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const onMonitorChange = () => {
|
const onMonitorChange = () => {
|
||||||
@@ -517,7 +514,7 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-top: vh(20);
|
padding-top: vh(20);
|
||||||
border-left: vw(2) solid #37d8fc;
|
// border-left: vw(2) solid #37d8fc;
|
||||||
&:nth-child(1) {
|
&:nth-child(1) {
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
}
|
}
|
||||||
@@ -529,7 +526,11 @@
|
|||||||
&__icon {
|
&__icon {
|
||||||
margin-left: vw(-8);
|
margin-left: vw(-8);
|
||||||
width: vw(16);
|
width: vw(16);
|
||||||
height: vw(16);
|
height: auto;
|
||||||
|
}
|
||||||
|
&__icon-up {
|
||||||
|
@extend .tree-item__icon;
|
||||||
|
transform: rotate(180deg);
|
||||||
}
|
}
|
||||||
&__name {
|
&__name {
|
||||||
padding: 0 vw(20);
|
padding: 0 vw(20);
|
||||||
@@ -544,8 +545,8 @@
|
|||||||
&__child {
|
&__child {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-top: vh(20);
|
margin-top: vh(20);
|
||||||
margin-left: vw(40);
|
margin-left: vw(20);
|
||||||
border-left: vw(2) solid #37d8fc;
|
// border-left: vw(2) solid #37d8fc;
|
||||||
}
|
}
|
||||||
&-top__icon {
|
&-top__icon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -562,17 +563,16 @@
|
|||||||
height: vw(16);
|
height: vw(16);
|
||||||
}
|
}
|
||||||
&__child-item {
|
&__child-item {
|
||||||
cursor: pointer;
|
|
||||||
padding: vh(0) vw(20) vh(20) vw(20);
|
padding: vh(0) vw(20) vh(20) vw(20);
|
||||||
display: block;
|
cursor: pointer;
|
||||||
|
color: #999;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: vw(15);
|
font-size: vw(15);
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
color: #ffffff;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
&:nth-last-of-type(1) {
|
&:nth-last-of-type(1) {
|
||||||
padding: vh(0) vw(20);
|
padding: vh(0) vw(20);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user