Compare commits

..

10 Commits

Author SHA1 Message Date
046aea0f55 类型:开发
描述:
2026-02-09 12:26:18 +08:00
3e9f7133de 类型:开发
描述:
2026-02-09 10:23:14 +08:00
affc881aaa 类型:开发
描述:
2026-02-04 23:15:21 +08:00
87c115ab99 类型:开发
描述:
2026-02-04 17:26:47 +08:00
6fe84fe853 类型:开发
描述:
2026-02-03 23:46:55 +08:00
b7499f12d1 类型:开发
描述:
2026-02-03 11:55:41 +08:00
724dc4a561 类型:开发
描述:
2026-02-03 10:14:46 +08:00
duanliang
cee259db65 fix 字体大小 2026-02-02 18:50:36 +08:00
3853793886 类型:开发
描述:
2026-01-28 18:54:50 +08:00
aa75cd9cb9 类型:开发
描述:
2026-01-28 18:22:36 +08:00
12 changed files with 153 additions and 77 deletions

35
package-lock.json generated
View File

@@ -25,7 +25,7 @@
"vue-router": "^4.4.5", "vue-router": "^4.4.5",
"vue3-seamless-scroll": "^2.0.1", "vue3-seamless-scroll": "^2.0.1",
"vuedraggable": "^4.1.0", "vuedraggable": "^4.1.0",
"whepts": "^1.0.2" "whepts": "^1.1.12"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^5.2.1", "@vitejs/plugin-vue": "^5.2.1",
@@ -3335,6 +3335,12 @@
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/eventemitter3": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz",
"integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==",
"license": "MIT"
},
"node_modules/events": { "node_modules/events": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
@@ -4324,6 +4330,21 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
} }
}, },
"node_modules/nanostores": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/nanostores/-/nanostores-1.1.0.tgz",
"integrity": "sha512-yJBmDJr18xy47dbNVlHcgdPrulSn1nhSE6Ns9vTG+Nx9VPT6iV1MD6aQFp/t52zpf82FhLLTXAXr30NuCnxvwA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"engines": {
"node": "^20.0.0 || >=22.0.0"
}
},
"node_modules/neo-async": { "node_modules/neo-async": {
"version": "2.6.2", "version": "2.6.2",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
@@ -6167,10 +6188,14 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/whepts": { "node_modules/whepts": {
"version": "1.0.2", "version": "1.1.12",
"resolved": "https://registry.npmjs.org/whepts/-/whepts-1.0.2.tgz", "resolved": "https://registry.npmjs.org/whepts/-/whepts-1.1.12.tgz",
"integrity": "sha512-9P0OP514Z2ZR2ev7qMOApplw6ERMChqgPi6eWWn6HTlTpDV0gW7Zqs4kLAKIV7xqxXCDNDCorxNz8ekOYAEp5g==", "integrity": "sha512-KllGslriMAhD6BDBbG6X653M8XgeYqxnjuEyaB7U/1nIZN6NoAGSWP3Av46g690r2UaaI69bNzfPn4efJBd+kA==",
"license": "MIT" "license": "MIT",
"dependencies": {
"eventemitter3": "^5.0.4",
"nanostores": "^1.1.0"
}
}, },
"node_modules/which": { "node_modules/which": {
"version": "2.0.2", "version": "2.0.2",

View File

@@ -26,7 +26,7 @@
"vue-router": "^4.4.5", "vue-router": "^4.4.5",
"vue3-seamless-scroll": "^2.0.1", "vue3-seamless-scroll": "^2.0.1",
"vuedraggable": "^4.1.0", "vuedraggable": "^4.1.0",
"whepts": "^1.0.2" "whepts": "^1.1.12"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^5.2.1", "@vitejs/plugin-vue": "^5.2.1",

View File

@@ -160,19 +160,26 @@
initializePlayer() { initializePlayer() {
if (!this.isActive || !this.url) return if (!this.isActive || !this.url) return
// 如果是重新初始化播放器,先清理已存在的资源
if (this.hls) {
this.immediateCleanup()
}
if(this.url.startsWith('http://192.168.77.200:8050/')){ if(this.url.startsWith('http://192.168.77.200:8050/')){
this.hls = new WebRTCWhep({ this.hls = new WebRTCWhep({
url: this.url, // WHEP 服务器地址 url: this.url, // WHEP 服务器地址
container: this.video, // 视频播放容器 container: this.video, // 视频播放容器
onError: (error) => { iceServers: [{ urls: 'turn:192.168.77.200:3478',username: 'ZLMediaKit',credential: 'ZLMediaKit'}]
console.error('播放错误:', error) })
this.hls.on('error', (error) => {
console.error('错误:', error.message, error.type)
if(error.type ==='REQUEST_ERROR' || error.type ==='NOT_FOUND_ERROR'){
this.initializePlayer();
} }
}) })
this.hls.on('play:failed', (err) => {
// this.initializePlayer();
})
}else{ }else{
// 如果是重新初始化播放器,先清理已存在的资源
if (this.hls) {
this.immediateCleanup()
}
this.hls = new Hls({ this.hls = new Hls({
// 内存优化配置 // 内存优化配置
maxBufferSize: 0, // 降低缓冲区大小15MB maxBufferSize: 0, // 降低缓冲区大小15MB

View File

@@ -81,7 +81,8 @@ import {getVideoListApi, getColletListApi, getPreviewUrlApi} from '@/api/home'
console.log(item, 'iscollect') console.log(item, 'iscollect')
let res = await getPreviewUrlApi({ let res = await getPreviewUrlApi({
cameraIndexCode: item.cameraIndexCode, cameraIndexCode: item.cameraIndexCode,
type: 'hls' type: 'hls',
subStream:0
}) })
src.value = res.data.url src.value = res.data.url
isCollect.value = item.isCollect isCollect.value = item.isCollect
@@ -125,17 +126,25 @@ import {getVideoListApi, getColletListApi, getPreviewUrlApi} from '@/api/home'
const createPlayer = (cameraIndexCode,videoElement) => { const createPlayer = (cameraIndexCode,videoElement) => {
getPreviewUrlApi({ getPreviewUrlApi({
type: 'hls', type: 'hls',
cameraIndexCode: cameraIndexCode cameraIndexCode: cameraIndexCode,
subStream:1
}).then(res=>{ }).then(res=>{
const url = res.data.url; const url = res.data.url;
if(url.startsWith('http://192.168.77.200:8050/')){ if(url.startsWith('http://192.168.77.200:8050/')){
const player = new WebRTCWhep({ const player = new WebRTCWhep({
url:url, // WHEP 服务器地址 url:url, // WHEP 服务器地址
container: videoElement, // 视频播放容器 container: videoElement, // 视频播放容器
onError: (error) => { iceServers: [{ urls: 'turn:192.168.77.200:3478',username: 'ZLMediaKit',credential: 'ZLMediaKit'}]
console.error('播放错误:', error) })
player.on('error', (error) => {
console.error('错误:', error.message, error.type)
if(error.type ==='REQUEST_ERROR' || error.type ==='NOT_FOUND_ERROR'){
createPlayer(cameraIndexCode,videoElement)
} }
}) })
player.on('play:failed', (err) => {
// createPlayer(cameraIndexCode,videoElement);
})
webrtcRefs.push(player) webrtcRefs.push(player)
} }
else{ else{

View File

@@ -66,7 +66,8 @@ let isCollect = ref(0)
const handleItem = async (item) => { const handleItem = async (item) => {
let res = await getPreviewUrlApi({ let res = await getPreviewUrlApi({
cameraIndexCode: item.cameraIndexCode, cameraIndexCode: item.cameraIndexCode,
type: 'hls' type: 'hls',
subStream:0
}) })
src.value = res.data.url src.value = res.data.url
cameraIndexCode.value = item.cameraIndexCode cameraIndexCode.value = item.cameraIndexCode
@@ -87,7 +88,8 @@ let isCollect = ref(0)
const getPreviewUrl = async (code) => { const getPreviewUrl = async (code) => {
let res = await getPreviewUrlApi({ let res = await getPreviewUrlApi({
cameraIndexCode: code, cameraIndexCode: code,
type: 'hls' type: 'hls',
subStream:1
}) })
src.value = res.data.url src.value = res.data.url
videoShow.value = true videoShow.value = true
@@ -95,17 +97,24 @@ let isCollect = ref(0)
const createPlayer = (cameraIndexCode,videoElement) => { const createPlayer = (cameraIndexCode,videoElement) => {
getPreviewUrlApi({ getPreviewUrlApi({
type: 'hls', type: 'hls',
cameraIndexCode: cameraIndexCode cameraIndexCode: cameraIndexCode,
subStream:0
}).then(res=>{ }).then(res=>{
const url = res.data.url; const url = res.data.url;
if(url.startsWith('http://192.168.77.200:8050/')){ if(url.startsWith('http://192.168.77.200:8050/')){
const player = new WebRTCWhep({ const player = new WebRTCWhep({
url:url, // WHEP 服务器地址 url:url, // WHEP 服务器地址
container: videoElement, // 视频播放容器 container: videoElement, // 视频播放容器
onError: (error) => { iceServers: [{ urls: 'turn:192.168.77.200:3478',username: 'ZLMediaKit',credential: 'ZLMediaKit'}]
console.error('播放错误:', error) })
player.on('error', (error) => {
if(error.type ==='REQUEST_ERROR' || error.type ==='NOT_FOUND_ERROR'){
createPlayer(cameraIndexCode,videoElement);
} }
}) })
player.on('play:failed', (err) => {
// createPlayer(cameraIndexCode,videoElement);
})
webrtcRefs.push(player) webrtcRefs.push(player)
} }
else{ else{

View File

@@ -224,7 +224,8 @@
show.value = true show.value = true
let res = await getPreviewUrlApi({ let res = await getPreviewUrlApi({
type: 'hls', type: 'hls',
cameraIndexCode:itemCode cameraIndexCode:itemCode,
subStream:0
}) })
cameraIndexCode.value = itemCode; cameraIndexCode.value = itemCode;
isCollect.value = resource.isCollect isCollect.value = resource.isCollect
@@ -283,17 +284,26 @@
const createPlayer = (cameraIndexCode,videoElement) => { const createPlayer = (cameraIndexCode,videoElement) => {
getPreviewUrlApi({ getPreviewUrlApi({
type: 'hls', type: 'hls',
cameraIndexCode: cameraIndexCode cameraIndexCode: cameraIndexCode,
subStream:1
}).then(res=>{ }).then(res=>{
const url = res.data.url; const url = res.data.url;
if(url.startsWith('http://192.168.77.200:8050/')){ if(url.startsWith('http://192.168.77.200:8050/')){
const player = new WebRTCWhep({ const player = new WebRTCWhep({
url: url, // WHEP 服务器地址 url: url, // WHEP 服务器地址
container: videoElement, // 视频播放容器 container: videoElement, // 视频播放容器
onError: (error) => { iceServers: [{ urls: 'turn:192.168.77.200:3478',username: 'ZLMediaKit',credential: 'ZLMediaKit'}]
console.error('播放错误:', error) })
player.on('error', (error) => {
console.error('错误:', error.message, error.type)
if(error.type ==='REQUEST_ERROR' || error.type ==='NOT_FOUND_ERROR'){
createPlayer(cameraIndexCode,videoElement);
} }
}) })
player.on('play:failed', (err) => {
// console.log('播放失败:', err)
// createPlayer(cameraIndexCode,videoElement);
})
webrtcRefs.push(player) webrtcRefs.push(player)
}else{ }else{
const player = new Hls({ const player = new Hls({

View File

@@ -418,7 +418,7 @@
:deep(.el-dialog__title) { :deep(.el-dialog__title) {
color: #fff; color: #fff;
font-weight: bold; font-weight: bold;
font-size:vw(22); font-size:vw(32);
} }
.bom-box { .bom-box {
.table2{ .table2{
@@ -431,7 +431,7 @@
.header { .header {
height: vh(28); height: vh(28);
font-weight: 400; font-weight: 400;
font-size:vw(20); font-size:vw(32);
color: #fff; color: #fff;
display: flex; display: flex;
padding:0; padding:0;
@@ -446,7 +446,7 @@
} }
.list { .list {
overflow-y: auto; overflow-y: auto;
height: vh(490); height: vh(180);
/* 滚动条整体样式 */ /* 滚动条整体样式 */
&::-webkit-scrollbar { &::-webkit-scrollbar {
width: vw(4); /* 滚动条的宽度 */ width: vw(4); /* 滚动条的宽度 */
@@ -463,7 +463,7 @@
.item { .item {
height: vh(50); height: vh(50);
font-weight: 400; font-weight: 400;
font-size:vw(18); font-size:vw(28);
color: #f1f7ff; color: #f1f7ff;
display: flex; display: flex;
&:nth-child(2n + 1) { &:nth-child(2n + 1) {

View File

@@ -1,25 +1,6 @@
<template> <template>
<div class="video-box"> <div class="video-box">
<div class="left-nav"> <div class="left-nav">
<div v-if="showNav" class="ul">
<div
class="li"
:class="{ active: current == index }"
v-for="(item, index) in navList"
:key="index"
@click="handleNav(index)"
>
<span v-if="!params.businessScenicArea && index == 0"> 核心路段 </span>
<span v-else>
{{ item.dictLabel }}
</span>
</div>
<div
:class="{ active: current == 3 }"
@click="handleNav(3)" class="li">
<span>自定义</span>
</div>
</div>
<div class="bom-box"> <div class="bom-box">
<Title2 title="检索" /> <Title2 title="检索" />
<div class="search-box"> <div class="search-box">
@@ -77,14 +58,15 @@
>关注 >关注
</div> </div>
<video <video
class="video-item__video"
:id="'hotelmonitorVideo' + index" :id="'hotelmonitorVideo' + index"
preload="auto" preload="auto"
class="video-item__video"
muted muted
autoplay autoplay
:controls="false" :controls="false"
> >
<source type="application/x-mpegURL" />
<source type="application/x-mpegURL"/>
</video> </video>
<p class="video-item__title--primary"> <p class="video-item__title--primary">
{{ item.cameraName || item.cameraIndexCode }} {{ item.cameraName || item.cameraIndexCode }}
@@ -304,7 +286,8 @@
show.value = true show.value = true
let res = await getPreviewUrlApi({ let res = await getPreviewUrlApi({
type: 'hls', type: 'hls',
cameraIndexCode:itemCode cameraIndexCode:itemCode,
subStream:0
}) })
cameraIndexCode.value = itemCode; cameraIndexCode.value = itemCode;
isCollect.value = resource.isCollect isCollect.value = resource.isCollect
@@ -340,17 +323,27 @@
const createPlayer = (cameraIndexCode,videoElement) => { const createPlayer = (cameraIndexCode,videoElement) => {
getPreviewUrlApi({ getPreviewUrlApi({
type: 'hls', type: 'hls',
cameraIndexCode: cameraIndexCode cameraIndexCode: cameraIndexCode,
subStream:0
}).then(res=>{ }).then(res=>{
const url = res.data.url; const url = res.data.url;
console.log('url',url)
if(url.startsWith('http://192.168.77.200:8050/')){ if(url.startsWith('http://192.168.77.200:8050/')){
const player = new WebRTCWhep({ const player = new WebRTCWhep({
url:url, // WHEP 服务器地址 url:url, // WHEP 服务器地址
container: videoElement, // 视频播放容器 container: videoElement, // 视频播放容器
onError: (error) => { iceServers: [{ urls: 'turn:192.168.77.200:3478',username: 'ZLMediaKit',credential: 'ZLMediaKit'}]
console.error('播放错误:', error) })
player.on('error', (error) => {
console.error('错误:', error.message, error.type)
if(error.type ==='REQUEST_ERROR' || error.type ==='NOT_FOUND_ERROR'){
createPlayer(cameraIndexCode,videoElement);
} }
}) })
player.on('play:failed', (err) => {
console.error('错误:',err)
// createPlayer(cameraIndexCode,videoElement);
})
webrtcRefs.push(player) webrtcRefs.push(player)
} }
else{ else{
@@ -420,7 +413,8 @@
const handleItemVideo = async (url, type, code, item) => { const handleItemVideo = async (url, type, code, item) => {
let res = await getPreviewUrlApi({ let res = await getPreviewUrlApi({
cameraIndexCode: code, cameraIndexCode: code,
type: 'hls' type: 'hls',
subStream:0
}) })
url = res.data.url url = res.data.url
thisVideo.value = item thisVideo.value = item
@@ -431,10 +425,18 @@
hlsRef = new WebRTCWhep({ hlsRef = new WebRTCWhep({
url: url, // WHEP 服务器地址 url: url, // WHEP 服务器地址
container: videoRef.value, // 视频播放容器 container: videoRef.value, // 视频播放容器
onError: (error) => { iceServers: [{ urls: 'turn:192.168.77.200:3478',username: 'ZLMediaKit',credential: 'ZLMediaKit'}]
console.error('播放错误:', error) })
hlsRef.on('error', (error) => {
console.error('错误:', error.message, error.type)
if(error.type ==='REQUEST_ERROR' || error.type ==='NOT_FOUND_ERROR'){
handleItemVideo(url, type, code, item);
} }
}) })
hlsRef.on('play:failed', (err) => {
console.log('播放失败,尝试重新加载');
// handleItemVideo(url, type, code, item);
})
} else { } else {
hlsRef = new Hls({ hlsRef = new Hls({
maxBufferLength: 10, // 最大缓冲长度(秒) maxBufferLength: 10, // 最大缓冲长度(秒)

View File

@@ -261,7 +261,8 @@
window.addEventListener("message", async(e) => { window.addEventListener("message", async(e) => {
let {code,data} = await getPreviewUrlApi({ let {code,data} = await getPreviewUrlApi({
type: 'hls', type: 'hls',
cameraIndexCode:e.data.cameraIndexCode cameraIndexCode:e.data.cameraIndexCode,
subStream:0
}) })
if(code===200){ if(code===200){
src.value = data.url src.value = data.url

View File

@@ -366,7 +366,8 @@ let thisVideo = ref(null)
const handleItemVideo = async (url, type, code, item) => { const handleItemVideo = async (url, type, code, item) => {
let res = await getPreviewUrlApi({ let res = await getPreviewUrlApi({
cameraIndexCode: code, cameraIndexCode: code,
type: 'hls' type: 'hls',
subStream:0
}) })
url = res.data.url url = res.data.url
thisVideo.value = item thisVideo.value = item
@@ -377,8 +378,12 @@ const handleItemVideo = async (url, type, code, item) => {
hlsRef = new WebRTCWhep({ hlsRef = new WebRTCWhep({
url: url, // WHEP 服务器地址 url: url, // WHEP 服务器地址
container: videoRef.value, // 视频播放容器 container: videoRef.value, // 视频播放容器
onError: (error) => { iceServers: [{ urls: 'turn:192.168.77.200:3478',username: 'ZLMediaKit',credential: 'ZLMediaKit'}]
console.error('播放错误:', error) })
hlsRef.on('error', (error) => {
console.error('错误:', error.message, error.type)
if(error.type ==='REQUEST_ERROR' || error.type ==='NOT_FOUND_ERROR'){
handleItemVideo(url, type, code, item);
} }
}) })
} else { } else {
@@ -429,7 +434,8 @@ const handleCamera = async (itemCode, resource) => {
show.value = true show.value = true
let res = await getPreviewUrlApi({ let res = await getPreviewUrlApi({
type: 'hls', type: 'hls',
cameraIndexCode: itemCode cameraIndexCode: itemCode,
subStream:0
}) })
cameraIndexCode.value = itemCode; cameraIndexCode.value = itemCode;
isCollect.value = resource.isCollect isCollect.value = resource.isCollect
@@ -492,15 +498,20 @@ watch(
const createPlayer = (cameraIndexCode,videoElement) => { const createPlayer = (cameraIndexCode,videoElement) => {
getPreviewUrlApi({ getPreviewUrlApi({
type: 'hls', type: 'hls',
cameraIndexCode: cameraIndexCode cameraIndexCode: cameraIndexCode,
subStream:1
}).then(res=>{ }).then(res=>{
const url = res.data.url; const url = res.data.url;
if(url.startsWith('http://192.168.77.200:8050/')){ if(url.startsWith('http://192.168.77.200:8050/')){
const player = new WebRTCWhep({ const player = new WebRTCWhep({
url: url, // WHEP 服务器地址 url: url, // WHEP 服务器地址
container: videoElement, // 视频播放容器 container: videoElement, // 视频播放容器
onError: (error) => { iceServers: [{ urls: 'turn:192.168.77.200:3478',username: 'ZLMediaKit',credential: 'ZLMediaKit'}]
console.error('播放错误:', error) })
player.on('error', (error) => {
console.error('错误:', error.message, error.type)
if(error.type ==='REQUEST_ERROR' || error.type ==='NOT_FOUND_ERROR'){
createPlayer(cameraIndexCode,videoElement)
} }
}) })
webrtcRefs.push(player) webrtcRefs.push(player)

View File

@@ -174,7 +174,8 @@ import pubSub from 'pubsub-js'
window.addEventListener("message", async(e) => { window.addEventListener("message", async(e) => {
let {code,data} = await getPreviewUrlApi({ let {code,data} = await getPreviewUrlApi({
type: 'hls', type: 'hls',
cameraIndexCode:e.data.cameraIndexCode cameraIndexCode:e.data.cameraIndexCode,
subStream:0
}) })
if(code===200){ if(code===200){
src.value = data.url src.value = data.url
@@ -422,11 +423,11 @@ import pubSub from 'pubsub-js'
} }
.tag--important { .tag--important {
@extend .tag; @extend .tag;
background: #feae00; background:#d9011b;
} }
.tag--warn { .tag--warn {
@extend .tag; @extend .tag;
background: #d9011b; background: #feae00;
} }
.tag--normal { .tag--normal {
@extend .tag; @extend .tag;

View File

@@ -191,7 +191,8 @@
const getPreviewUrl = async (code) => { const getPreviewUrl = async (code) => {
let res = await getPreviewUrlApi({ let res = await getPreviewUrlApi({
cameraIndexCode: code, cameraIndexCode: code,
type: 'hls' type: 'hls',
subStream:0
}) })
src.value = res.data.url src.value = res.data.url
videoShow.value = true videoShow.value = true