Traffic6 替换为实时监控画面,更新生产环境 API 直连地址。
Co-authored-by: Cursor <cursoragent@cursor.com>main
parent
9686f58e97
commit
131d41f036
|
|
@ -1,2 +1,2 @@
|
||||||
# 生产环境配置 目前是配置代理的方式
|
# 生产环境配置(直连实际地址,需包含应用 context path)
|
||||||
VITE_API_BASE_URL=/juntech-ysdp
|
VITE_API_BASE_URL=http://10.104.10.151:8888/juntech-ysdp
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,108 @@
|
||||||
<template>
|
<template>
|
||||||
<section class="traffic-6">
|
<section class="traffic-6">
|
||||||
<div class="traffic-image-list">
|
<div class="traffic-video-list" v-if="videoList.length">
|
||||||
<img
|
<div
|
||||||
v-for="item in imageList"
|
v-for="(item, index) in videoList.slice(0, 4)"
|
||||||
:key="item"
|
:key="index"
|
||||||
class="traffic-image"
|
class="traffic-video-wrapper"
|
||||||
:src="`./imgs/traffic/${item}`"
|
|
||||||
alt=""
|
|
||||||
>
|
>
|
||||||
|
<video
|
||||||
|
:ref="el => setVideoRef(el, index)"
|
||||||
|
class="traffic-video"
|
||||||
|
controls
|
||||||
|
autoplay
|
||||||
|
muted
|
||||||
|
playsinline
|
||||||
|
loop
|
||||||
|
></video>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
const imageList = ['image1.png', 'image2.png', 'image3.png', 'image4.png']
|
import { ref, onMounted, nextTick } from 'vue'
|
||||||
|
import HLS from 'hls.js'
|
||||||
|
import server from '@/utils/service'
|
||||||
|
|
||||||
|
const videoList = ref([])
|
||||||
|
const videoRefs = ref([])
|
||||||
|
|
||||||
|
const setVideoRef = (el, index) => {
|
||||||
|
if (el) {
|
||||||
|
videoRefs.value[index] = el
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchVideoList = async () => {
|
||||||
|
try {
|
||||||
|
const response = await server.getCommonMonitor()
|
||||||
|
if (response.data.success) {
|
||||||
|
videoList.value = response.data.data.map(item => ({
|
||||||
|
url: item.url.trim(),
|
||||||
|
line: item.line,
|
||||||
|
station: item.station,
|
||||||
|
monitor: item.monitor
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取视频列表失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const playVideo = (video, videoUrl, index) => {
|
||||||
|
if (HLS.isSupported()) {
|
||||||
|
const hls = new HLS({
|
||||||
|
debug: true,
|
||||||
|
liveSyncDuration: 3,
|
||||||
|
maxBufferLength: 30
|
||||||
|
})
|
||||||
|
|
||||||
|
hls.on(HLS.Events.ERROR, (event, data) => {
|
||||||
|
console.error('视频', index + 1, 'HLS 错误:', event, data)
|
||||||
|
if (data.fatal) {
|
||||||
|
hls.destroy()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
hls.loadSource(videoUrl)
|
||||||
|
hls.attachMedia(video)
|
||||||
|
|
||||||
|
video.play().catch(err => {
|
||||||
|
console.error('视频', index + 1, '播放失败:', err)
|
||||||
|
})
|
||||||
|
} else if (video.canPlayType('application/x-mpegURL')) {
|
||||||
|
video.src = videoUrl
|
||||||
|
video.load()
|
||||||
|
video.play().catch(err => {
|
||||||
|
console.error('视频', index + 1, '播放失败:', err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const initVideos = async () => {
|
||||||
|
await fetchVideoList()
|
||||||
|
|
||||||
|
if (!videoList.value.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
setTimeout(() => {
|
||||||
|
videoRefs.value.forEach((video, index) => {
|
||||||
|
if (!video) return
|
||||||
|
|
||||||
|
const videoItem = videoList.value[index % videoList.value.length]
|
||||||
|
if (!videoItem?.url) return
|
||||||
|
|
||||||
|
playVideo(video, videoItem.url, index)
|
||||||
|
})
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initVideos()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
@ -28,7 +117,7 @@ const imageList = ['image1.png', 'image2.png', 'image3.png', 'image4.png']
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
.traffic-image-list {
|
.traffic-video-list {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 58px;
|
top: 58px;
|
||||||
left: 24px;
|
left: 24px;
|
||||||
|
|
@ -39,14 +128,20 @@ const imageList = ['image1.png', 'image2.png', 'image3.png', 'image4.png']
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.traffic-image {
|
.traffic-video-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 419px;
|
height: 419px;
|
||||||
display: block;
|
overflow: hidden;
|
||||||
object-fit: cover;
|
|
||||||
border: 4px solid rgba(0, 102, 255, 0.72);
|
border: 4px solid rgba(0, 102, 255, 0.72);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
box-shadow: inset 0 0 18px rgba(0, 180, 255, 0.36), 0 0 10px rgba(0, 90, 255, 0.32);
|
box-shadow: inset 0 0 18px rgba(0, 180, 255, 0.36), 0 0 10px rgba(0, 90, 255, 0.32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.traffic-video {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
object-fit: fill;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue