feat:完善功能

This commit is contained in:
zjc
2025-02-22 12:59:47 +08:00
parent 23fbbcdb78
commit 2d881eae08
8 changed files with 96 additions and 124 deletions

27
package-lock.json generated
View File

@@ -12,10 +12,8 @@
"echarts": "^5.5.1", "echarts": "^5.5.1",
"echarts-wordcloud": "^2.0.0", "echarts-wordcloud": "^2.0.0",
"element-plus": "^2.9.0", "element-plus": "^2.9.0",
"flv.js": "^1.6.2",
"hls.js": "^1.5.18", "hls.js": "^1.5.18",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mitt": "^3.0.1",
"pinia": "^2.2.6", "pinia": "^2.2.6",
"pubsub-js": "^1.9.5", "pubsub-js": "^1.9.5",
"vue": "^3.5.13", "vue": "^3.5.13",
@@ -1752,12 +1750,6 @@
"dev": true, "dev": true,
"peer": true "peer": true
}, },
"node_modules/es6-promise": {
"version": "4.2.8",
"resolved": "https://registry.npmmirror.com/es6-promise/-/es6-promise-4.2.8.tgz",
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
"license": "MIT"
},
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.24.0", "version": "0.24.0",
"resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.24.0.tgz", "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.24.0.tgz",
@@ -1989,16 +1981,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/flv.js": {
"version": "1.6.2",
"resolved": "https://registry.npmmirror.com/flv.js/-/flv.js-1.6.2.tgz",
"integrity": "sha512-xre4gUbX1MPtgQRKj2pxJENp/RnaHaxYvy3YToVVCrSmAWUu85b9mug6pTXF6zakUjNP2lFWZ1rkSX7gxhB/2A==",
"license": "Apache-2.0",
"dependencies": {
"es6-promise": "^4.2.8",
"webworkify-webpack": "^2.1.5"
}
},
"node_modules/follow-redirects": { "node_modules/follow-redirects": {
"version": "1.15.9", "version": "1.15.9",
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz", "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz",
@@ -2583,7 +2565,8 @@
"node_modules/mitt": { "node_modules/mitt": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz", "resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz",
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
"dev": true
}, },
"node_modules/mlly": { "node_modules/mlly": {
"version": "1.7.3", "version": "1.7.3",
@@ -4007,12 +3990,6 @@
"url": "https://opencollective.com/webpack" "url": "https://opencollective.com/webpack"
} }
}, },
"node_modules/webworkify-webpack": {
"version": "2.1.5",
"resolved": "https://registry.npmmirror.com/webworkify-webpack/-/webworkify-webpack-2.1.5.tgz",
"integrity": "sha512-2akF8FIyUvbiBBdD+RoHpoTbHMQF2HwjcxfDvgztAX5YwbZNyrtfUMgvfgFVsgDhDPVTlkbb5vyasqDHfIDPQw==",
"license": "MIT"
},
"node_modules/which": { "node_modules/which": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz",

View File

@@ -13,10 +13,8 @@
"echarts": "^5.5.1", "echarts": "^5.5.1",
"echarts-wordcloud": "^2.0.0", "echarts-wordcloud": "^2.0.0",
"element-plus": "^2.9.0", "element-plus": "^2.9.0",
"flv.js": "^1.6.2",
"hls.js": "^1.5.18", "hls.js": "^1.5.18",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mitt": "^3.0.1",
"pinia": "^2.2.6", "pinia": "^2.2.6",
"pubsub-js": "^1.9.5", "pubsub-js": "^1.9.5",
"vue": "^3.5.13", "vue": "^3.5.13",

View File

@@ -22,6 +22,7 @@
:controls="false" :controls="false"
style="object-fit: cover" style="object-fit: cover"
> >
<source src="" type="application/x-mpegURL" />
</video> </video>
</div> </div>
</li> </li>
@@ -46,45 +47,46 @@
let webRtcServerList = ref([]) let webRtcServerList = ref([])
const handleItem = (item) => { const handleItem = (item) => {
// src.value = item.hlsUrl src.value = item.hlsUrl
src.value = item.rtspUrl // src.value = item.rtspUrl
cameraIndexCode.value = item.cameraIndexCode cameraIndexCode.value = item.cameraIndexCode
videoShow.value = true videoShow.value = true
} }
const getVideoList = async () => { const getVideoList = async () => {
let res = await getVideoListApi({ let res = await getVideoListApi({
type: 'rtsp',
businessVideoDisplayPosition: '核心景区视频' businessVideoDisplayPosition: '核心景区视频'
}) })
console.log(res, '视频列表')
list.value = res.data list.value = res.data
nextTick(() => {
list.value.forEach(async (item, index) => {
let webRtcServer = new WebRtcStreamer(
`video${index}`,
`${mode == 'dev' ? baseUrl : proBaseUrl}/webrtc`
)
webRtcServer.connect(item.rtspUrl)
webRtcServerList.value.push(webRtcServer)
})
})
// nextTick(() => { // nextTick(() => {
// list.value.forEach(async (item, index) => { // list.value.forEach(async (item, index) => {
// var video = document.getElementById(`video${index}`) // let webRtcServer = new WebRtcStreamer(
// const hls = new Hls({ // `video${index}`,
// maxBufferLength: 10, // 最大缓冲长度(秒) // `${mode == 'dev' ? baseUrl : proBaseUrl}/webrtc`
// maxMaxBufferLength: 15, // 缓冲区长度的上限 // )
// maxBufferSize: 20 * 1000 * 1000 // 最大缓冲大小(字节) // webRtcServer.connect(item.rtspUrl, '', 'rtptransport=tcp')
// }) // webRtcServerList.value.push(webRtcServer)
// hls.loadSource(item.hlsUrl)
// hls.attachMedia(video)
// hls.on(Hls.Events.MANIFEST_PARSED, () => {
// video.play()
// })
// }) // })
// }) // })
nextTick(() => {
list.value.forEach(async (item, index) => {
var video = document.getElementById(`video${index}`)
const hls = new Hls({
enableWorker: false, // 禁用 Worker 来避免额外的线程
enableSoftwareAES: true, // 使用软件解码器以避免硬件解码的额外请求
cache: true, // 启用缓存
maxBufferLength: 10, // 最大缓冲长度(秒)
maxMaxBufferLength: 15, // 缓冲区长度的上限
maxBufferSize: 20 * 1000 * 1000 // 最大缓冲大小(字节)
})
hls.loadSource(item.hlsUrl)
hls.attachMedia(video)
hls.on(Hls.Events.MANIFEST_PARSED, () => {
video.play()
})
})
})
} }
onMounted(() => { onMounted(() => {
getVideoList() getVideoList()

View File

@@ -1,11 +1,18 @@
<template> <template>
<div class="dialog"> <div class="dialog">
<el-dialog v-model="modelValue" align-center :modal="false" :show-close="false" :z-index="9999"> <el-dialog
v-model="modelValue"
align-center
:modal="false"
:show-close="false"
:z-index="9999"
destroy-on-close
>
<div v-if="src" class="dialog-box"> <div v-if="src" class="dialog-box">
<!-- <video class="video" ref="videoRef" muted autoplay controls style="object-fit: cover"> <video class="video" ref="videoRef" muted autoplay controls>
<source src="" type="application/x-mpegURL" /> <source type="application/x-mpegURL" />
</video> --> </video>
<video class="video" id="bigVideo" muted autoplay controls style="object-fit: cover" /> <!-- <video class="video" id="bigVideo" muted autoplay controls style="object-fit: cover" /> -->
<div class="action-box"> <div class="action-box">
<!-- <div class="action-item"> <!-- <div class="action-item">
@@ -68,6 +75,7 @@
let modelValue = defineModel() let modelValue = defineModel()
let videoRef = ref() let videoRef = ref()
let webRtcServer = null let webRtcServer = null
let hlsRef = null
watch( watch(
() => modelValue.value, () => modelValue.value,
@@ -100,22 +108,42 @@
}) })
} }
const handleClose = () => { const handleClose = () => {
webRtcServer.disconnect() // webRtcServer.disconnect()
hlsRef.destroy()
hlsRef = null
modelValue.value = false modelValue.value = false
} }
const init = () => { const init = () => {
webRtcServer = new WebRtcStreamer('bigVideo', `${mode == 'dev' ? baseUrl : proBaseUrl}/webrtc`) // webRtcServer = new WebRtcStreamer('bigVideo', `${mode == 'dev' ? baseUrl : proBaseUrl}/webrtc`)
webRtcServer.connect(props.src) // webRtcServer.connect(props.src)
// const hls = new Hls({ hlsRef = new Hls({
// maxBufferLength: 10, // 最大缓冲长度(秒) enableWorker: false, // 禁用 Worker 来避免额外的线程
// maxMaxBufferLength: 15, // 缓冲区长度的上限 enableSoftwareAES: true, // 使用软件解码器以避免硬件解码的额外请求
// maxBufferSize: 15 * 1000 * 1000 // 最大缓冲大小(字节) cache: true, // 启用缓存
// }) maxBufferLength: 10, // 最大缓冲长度(秒)
// hls.loadSource(props.src) maxMaxBufferLength: 15, // 缓冲区长度的上限
// hls.attachMedia(videoRef.value) maxBufferSize: 20 * 1000 * 1000 // 最大缓冲大小(字节)
// hls.on(Hls.Events.MANIFEST_PARSED, () => { })
// videoRef.value.play() hlsRef.loadSource(props.src)
// }) hlsRef.attachMedia(videoRef.value)
hlsRef.on(Hls.Events.MANIFEST_PARSED, () => {
videoRef.value.play()
})
hlsRef.on(Hls.Events.ERROR, (event, data) => {
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
hlsRef.startLoad()
break
case Hls.ErrorTypes.MEDIA_ERROR:
hlsRef.recoverMediaError()
break
default:
hlsRef.destroy()
break
}
}
})
} }
</script> </script>
@@ -177,7 +205,9 @@
} }
.video { .video {
width: vw(1814); width: vw(1814);
height: vw(790); height: vw(980);
object-fit: contain;
background-color: #062b57;
} }
.close { .close {
cursor: pointer; cursor: pointer;

View File

@@ -25,6 +25,7 @@ export function useWebSocket(url) {
} }
} }
socket.value.onclose = (event) => { socket.value.onclose = (event) => {
isConnected.value = false
console.log('WebSocket close', event) console.log('WebSocket close', event)
} }
} }

View File

@@ -1,9 +1,11 @@
<template> <template>
<Header /> <Header />
<div class="flex flex-1"> <div class="flex flex-1">
<CoreVideo /> <core-video />
<div class="mian"><RouterView /></div> <div class="mian">
<Correspondence /> <router-view />
</div>
<correspondence />
</div> </div>
</template> </template>

View File

@@ -147,22 +147,6 @@
const scenicQueueXAxisData = computed(() => { const scenicQueueXAxisData = computed(() => {
return homeStore.scenicQueueData.dataList.map((item) => item.name) return homeStore.scenicQueueData.dataList.map((item) => item.name)
}) })
// 年龄占比 - 游客总数
const ageRateTotal = computed(() => {
return homeStore?.userPortraitData?.genderRate.reduce(
(total, current) => Number(current.count) + total,
0
)
})
// 购票来源 - 游客总数
const channelTotal = computed(() => {
return homeStore.userPortraitData?.channel.reduce(
(total, current) => Number(current.count) + total,
0
)
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -56,10 +56,10 @@
<video <video
class="video-item__video" class="video-item__video"
:id="'monitorVideo' + index" :id="'monitorVideo' + index"
preload="auto"
muted muted
autoplay autoplay
:controls="false" :controls="false"
style="object-fit: cover"
> >
<source src="" type="application/x-mpegURL" /> <source src="" type="application/x-mpegURL" />
</video> </video>
@@ -158,7 +158,7 @@
businessScenicArea: '', businessScenicArea: '',
businessVideoDisplayPosition: '' businessVideoDisplayPosition: ''
}) })
let hlsRefs = []
// const postVideoRemain = async () => { // const postVideoRemain = async () => {
// setInterval(() => { // setInterval(() => {
// postVideoRemainApi({ // postVideoRemainApi({
@@ -181,6 +181,7 @@
hls.on(Hls.Events.MANIFEST_PARSED, () => { hls.on(Hls.Events.MANIFEST_PARSED, () => {
video.play() video.play()
}) })
hlsRefs.push(hls)
}) })
}) })
} }
@@ -255,6 +256,7 @@
hls.on(Hls.Events.MANIFEST_PARSED, () => { hls.on(Hls.Events.MANIFEST_PARSED, () => {
video.play() video.play()
}) })
hlsRefs.push(hls)
}) })
}) })
} }
@@ -325,6 +327,12 @@
onMonitorChange() onMonitorChange()
}) })
onUnmounted(() => { onUnmounted(() => {
// 释放hls实例
if (hlsRefs.length > 0) {
hlsRefs.map((item) => {
item.destroy()
})
}
PubSub.unsubscribe(monitorChange) PubSub.unsubscribe(monitorChange)
}) })
</script> </script>
@@ -459,36 +467,6 @@
} }
} }
} }
.tree-b::before {
position: absolute;
top: vw(-8);
left: vw(-8);
content: '';
width: vw(12);
height: vw(12);
background-image: url('/src/assets/images/icon-a-1.png');
background-size: 100% 100%;
}
// .tree-b {
// position: relative;
// border-left: vw(3) solid;
// border-image: linear-gradient(311deg, rgba(0, 11, 36, 0), rgba(55, 216, 252, 1)) 1 1;
// margin-left: vw(30);
// margin-top: vh(10);
// .name-2 {
// cursor: pointer;
// padding: 0 vw(20);
// display: block;
// font-weight: 400;
// font-size: vw(15);
// color: #ffffff;
// height: vh(30);
// line-height: vh(30);
// white-space: nowrap; /* 保证文本在一行内显示 */
// overflow: hidden; /* 隐藏溢出的内容 */
// text-overflow: ellipsis; /* 使用省略号表示文本溢出 */
// }
// }
} }
} }
.ul { .ul {
@@ -591,8 +569,8 @@
&-item__video { &-item__video {
width: 100%; width: 100%;
height: vh(406); height: vh(406);
object-fit: cover;
} }
&-detail { &-detail {
margin-left: vw(10); margin-left: vw(10);
display: flex; display: flex;