Compare commits

53 Commits

Author SHA1 Message Date
1651188051 类型:开发
描述:
2026-04-27 16:58:11 +08:00
224fa546bf 类型:开发
描述:
2026-02-09 12:20:57 +08:00
7eaa48e2cb 类型:开发
描述:
2026-02-09 10:28:57 +08:00
e21e9999c7 类型:开发
描述:
2026-02-03 23:50:29 +08:00
bc827e1cc8 类型:开发
描述:
2026-02-03 23:38:44 +08:00
5301a74ec9 类型:开发
描述:
2026-02-03 10:29:49 +08:00
duanliang
c0012f5305 fix bug修改 2026-01-28 18:54:27 +08:00
d10e504db9 类型:开发
描述:
2026-01-28 18:50:45 +08:00
01586539db 类型:开发
描述:
2026-01-28 18:42:42 +08:00
duanliang
970795110d fix bug修复 2026-01-28 12:02:22 +08:00
duanliang
bc401377a4 fix 优化 2026-01-28 09:54:41 +08:00
duanliang
dc70c68ad5 fix bug 修改 2026-01-27 11:11:15 +08:00
duanliang
ee5e891425 fix bug修改 2026-01-27 10:24:53 +08:00
duanliang
4d81265f97 fix 样式优化 2026-01-25 19:05:28 +08:00
e23a541799 类型:开发
描述:
2026-01-23 00:57:16 +08:00
7d9036ac2d 类型:开发
描述:
2026-01-23 00:56:34 +08:00
e4f42a7136 类型:开发
描述:
2026-01-23 00:23:43 +08:00
fab9537aad 类型:开发
描述:
2026-01-21 01:01:48 +08:00
bdd849f244 类型:开发
描述:
2026-01-21 00:31:03 +08:00
1ab7624913 类型:开发
描述:
2026-01-21 00:30:10 +08:00
d8ff29800a 类型:开发
描述:
2026-01-21 00:28:34 +08:00
421a842190 Merge remote-tracking branch 'origin/dlnew' into dlnew 2026-01-20 14:40:33 +08:00
duanliang
0523deed26 feat 今年游客总数弹窗 2026-01-20 12:50:41 +08:00
duanliang
9b28389836 feat 游客数弹窗 2026-01-19 15:36:27 +08:00
3db25e2536 类型:开发
描述:
2026-01-19 13:27:36 +08:00
duanliang
1e1d4e56cc fix bug修改 2026-01-15 15:04:10 +08:00
duanliang
9705c0bb26 fix bug修改 2026-01-15 14:30:57 +08:00
5d95c101ba 类型:开发
描述:
2026-01-14 09:58:27 +08:00
c5c7f6af44 类型:开发
描述:
2026-01-14 01:29:32 +08:00
80a448f9b9 类型:开发
描述:
2026-01-14 01:11:54 +08:00
3aea6f740b 类型:开发
描述:
2026-01-14 00:58:18 +08:00
ed5876c55b 类型:开发
描述:
2026-01-14 00:51:15 +08:00
4bf2d63aa4 类型:开发
描述:
2026-01-14 00:28:40 +08:00
duanliang
0a45b06fd5 fix 优化 2026-01-13 19:24:37 +08:00
duanliang
79a9226fa0 fix 优化 2026-01-13 16:39:07 +08:00
duanliang
23f1998a34 fix 优化 2026-01-13 14:17:29 +08:00
duanliang
4b77459658 fix 优化 2026-01-13 11:05:05 +08:00
duanliang
c864132820 fix 优化 2026-01-06 14:33:52 +08:00
duanliang
586fe3f80d fix 优化 2026-01-06 14:25:46 +08:00
duanliang
0ed5a3bab2 fix 优化 2026-01-04 11:21:25 +08:00
duanliang
d571dadf8c fix 优化 2026-01-04 11:13:50 +08:00
duanliang
6533857dae fix 1 2025-12-21 17:52:47 +08:00
5fd201a41a 类型:开发
描述:
2025-12-10 14:00:33 +08:00
duanliang
5cbb12f15d feat 核心视频 2025-12-10 12:50:20 +08:00
3c255f9623 类型:开发
描述:
2025-12-10 11:53:45 +08:00
69213dac03 类型:开发
描述:
2025-12-09 17:58:30 +08:00
duanliang
e967ca0514 新版式 2025-11-27 22:17:26 +08:00
duanliang
b7f4cca716 新版式 2025-11-26 23:36:37 +08:00
duanliang
d05a0f645e 新版式 2025-11-26 23:25:22 +08:00
duanliang
2f34ab23a6 新版式 2025-11-25 22:23:38 +08:00
duanliang
974b307258 新版式 2025-11-25 01:07:20 +08:00
duanliang
7d28f8b0a4 新版式 2025-11-25 00:52:18 +08:00
duanliang
5c17235581 新版式 2025-11-24 23:17:46 +08:00
76 changed files with 4162 additions and 4648 deletions

View File

@@ -3,16 +3,18 @@
</script> </script>
<template> <template>
<main class="wrapper"> <RouterView /> </main> <main class="wrapper">
<RouterView />
</main>
</template> </template>
<style scoped> <style scoped>
.wrapper { .wrapper {
display: flex; display: flex;
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
overflow: hidden; overflow: hidden;
background-color: #0a254b; background-color: #0a254b;
} }
</style> </style>

View File

@@ -1,14 +1,14 @@
import request from './request' import request from './request'
export function getTrafficEventsApi(type) { export function getTrafficEventsApi() {
return request({ return request({
url: '/fjtcc-api/api/largeScreen/monitor/trafficEvents?type='+type, url: '/fjtcc-api/api/largeScreen/monitor/trafficEvents',
method: 'get' method: 'get'
}) })
} }
export function getVideoEventApi(scenicSpotId,type) { export function getVideoEventApi(scenicSpotId) {
return request({ return request({
url: '/fjtcc-api/api/largeScreen/monitor/videoEvents?type='+type+'&scenicSpotId='+scenicSpotId, url: '/fjtcc-api/api/largeScreen/monitor/videoEvents?scenicSpotId='+scenicSpotId,
method: 'get' method: 'get'
}) })
} }

View File

@@ -12,7 +12,7 @@ const instance = axios.create({
timeout: 100000, timeout: 100000,
headers: { headers: {
Authorization: mode == 'dev' ? devToken : proToken, Authorization: mode == 'dev' ? devToken : proToken,
'User-Type': '1', 'User-Type':'2',
'Content-Type': 'application/json;charset=UTF-8' 'Content-Type': 'application/json;charset=UTF-8'
} }
}) })
@@ -42,10 +42,10 @@ instance.interceptors.response.use(
return res.data return res.data
} else { } else {
console.error("接口请求错误:"+res.data.msg) console.error("接口请求错误:"+res.data.msg)
// ElMessage({ // ElMessage({
// message: res.data.msg, // message: res.data.msg,
// type: 'error' // type: 'error'
// }) // })
return Promise.reject(res.data) return Promise.reject(res.data)
} }
}, },

View File

@@ -7,13 +7,7 @@ export function getListApi() {
method: 'get' method: 'get'
}) })
} }
// 统计
export function getDetailApi(id) {
return request({
url: '/fjtcc-api/api/largeScreen/workorder/detail/'+id,
method: 'get'
})
}
// 统计 // 统计
export function getTotalApi() { export function getTotalApi() {
return request({ return request({

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -57,7 +57,7 @@
top: '20%', top: '20%',
textStyle: { textStyle: {
color: '#00D0FF', color: '#00D0FF',
fontSize: fitChartSize(18) fontSize: fitChartSize(24)
} }
}, },
{ {
@@ -66,7 +66,7 @@
top: '50%', top: '50%',
textStyle: { textStyle: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(16) fontSize: fitChartSize(22)
} }
} }
], ],
@@ -91,13 +91,13 @@
[0, '#075199'], [0, '#075199'],
[1, '#075199'] [1, '#075199']
], ],
width: fitChartSize(6) width: fitChartSize(10)
} }
}, },
progress: { progress: {
show: true, show: true,
roundCap: false, roundCap: false,
width: fitChartSize(6) width: fitChartSize(10)
}, },
pointer: { pointer: {
// 指针 // 指针
@@ -143,13 +143,13 @@
[0, '#075199'], [0, '#075199'],
[1, '#075199'] [1, '#075199']
], ],
width: fitChartSize(6) width: fitChartSize(10)
} }
}, },
progress: { progress: {
show: true, show: true,
roundCap: false, roundCap: false,
width: fitChartSize(6) width: fitChartSize(10)
}, },
pointer: { pointer: {
// 指针 // 指针

View File

@@ -52,32 +52,34 @@
flex: 1; flex: 1;
.label { .label {
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(20);
margin-left: vw(4); margin-left: vw(4);
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
} }
.count { .count {
position: relative; position: relative;
margin-top: vh(10); margin-top: vh(30);
z-index: 1; z-index: 1;
.value { .value {
padding-left: vw(20); padding-left: vw(20);
font-weight: bold; font-weight: bold;
font-size: vw(28); font-size: font-vw(38);
color: #02f9fa; color: #02f9fa;
} }
.suffix { .suffix {
margin-top: vh(4); // margin-top: vh(34);
font-weight: bold; font-weight: bold;
font-size: vw(12); font-size: font-vw(18);
color: #02f9fa; color: #02f9fa;
margin-left:vw(5);
} }
.bg { .bg {
position: absolute; position: absolute;
left: 0; left: 0;
top: 0; top: 0;
width: vw(134); width: vw(184);
height: vh(30); height: vh(50);
line-height: vh(50);
z-index: -1; z-index: -1;
} }
} }

View File

@@ -1,352 +0,0 @@
<template>
<div v-show="isActive" class="myVideo-container">
<video
class="myVideo"
ref="videoElement"
muted
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) {
// console.log(newUrl,'77777777777777777777777777777777')
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: 0, // 降低缓冲区大小15MB
maxBufferLength: 0.1, // 更小的缓冲窗口
liveSyncDuration: 1, // 紧跟直播点
liveMaxLatencyDuration: 5, // 最大延迟5秒
liveDurationInfinity: true,
lowLatencyMode: true, // 启用低延迟模式
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) => {
console.log('核心视频错误',data.type)
// this.hls.startLoad(); //重连
if (data.type === Hls.ErrorTypes.BUFFER_STALLED_ERROR) {
console.error('缓冲停滞错误,尝试重新加载视频');
this.hls.startLoad(); // 尝试重新加载视频
}
this.handleHlsError(data)
})
this.hls.on(Hls.Events.BUFFER_EOS, () => {
this.cleanupNetworkResources()
})
},
initVideo() {
this.beforeDestroy()
this.hls = new Hls({
maxBufferLength: 30, // 最大缓冲长度(秒)
maxMaxBufferLength: 15, // 缓冲区长度的上限
maxBufferSize: 30 * 1000 * 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.hls.startLoad(); //重连
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: 100%;
// aspect-ratio: 16/9;
/* border: 1px solid #ccc; */
// border-radius: vw(5);
}
.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>

View File

@@ -1,372 +1,371 @@
<template> <template>
<div v-show="isActive" class="myVideo-container"> <div v-show="isActive" class="myVideo-container">
<video <video
class="myVideo" class="myVideo"
id="video" id="video"
ref="videoElement" ref="videoElement"
preload="auto" muted
muted playsinline
autoplay preload="auto"
:controls="false" autoplay
:controls="false"
></video> ></video>
<!-- <div v-if="loading" class="loading-overlay pointer-events-none"> <!-- <div v-if="loading" class="loading-overlay pointer-events-none">
<div class="loading-text">{{ loadingText }}</div> <div class="loading-text">{{ loadingText }}</div>
</div> --> </div> -->
</div> </div>
</template> </template>
<script> <script>
import Hls from 'hls.js' import Hls from 'hls.js'
import WebRTCWhep from 'whepts' import WebRTCWhep from "whepts";
export default { export default {
name: 'HlsPlayer', name: 'HlsPlayer',
props: { props: {
url: { url: {
type: String, type: String,
default: '' default: ''
}, },
isActive: { isActive: {
type: Boolean, type: Boolean,
default: true default: true
}, },
width: { width: {
type: [String, Number], type: [String, Number],
default: '100%' default: '100%'
}, },
height: { height: {
type: [String, Number], type: [String, Number],
default: '100%' 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) {
data() { style.height = typeof this.height === 'number' ? `${this.height}px` : this.height
return {
hls: null,
video: null,
loading: false,
loadingText: '加载中...',
retryCount: 0,
maxRetries: 3,
isReady: false,
playAttempts: 0,
maxPlayAttempts: 3,
cleanupTimeout: null
} }
}, return style
computed: { }
videoStyle() { },
const style = {} watch: {
if (this.width) { isActive: {
style.width = typeof this.width === 'number' ? `${this.width}px` : this.width handler(newValue) {
} if (newValue) {
if (this.height) { this.$nextTick(this.initializePlayer)
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) {
// console.log(newUrl,'77777777777777777777777777777777')
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.close();
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.url.startsWith('http://192.168.77.200:8050/')){
this.hls = new WebRTCWhep({
url: this.url, // WHEP 服务器地址
container: this.video, // 视频播放容器
iceServers: [{ urls: 'turn:192.168.77.200:3478',username: 'ZLMediaKit',credential: 'ZLMediaKit'}]
})
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{
// 如果是重新初始化播放器,先清理已存在的资源
if (this.hls) {
this.immediateCleanup()
}
this.hls = new Hls({
// 内存优化配置
maxBufferSize: 0, // 降低缓冲区大小15MB
maxBufferLength: 0.1, // 更小的缓冲窗口
liveSyncDuration: 1, // 紧跟直播点
liveMaxLatencyDuration: 5, // 最大延迟5秒
liveDurationInfinity: true,
lowLatencyMode: true, // 启用低延迟模式
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) => {
console.log('核心视频错误',data.type)
// this.hls.startLoad(); //重连
if (data.type === Hls.ErrorTypes.BUFFER_STALLED_ERROR) {
console.error('缓冲停滞错误,尝试重新加载视频');
this.hls.startLoad(); // 尝试重新加载视频
}
this.handleHlsError(data)
})
this.hls.on(Hls.Events.BUFFER_EOS, () => {
this.cleanupNetworkResources()
})
}
},
initVideo() {
this.beforeDestroy()
this.hls = new Hls({
maxBufferLength: 30, // 最大缓冲长度(秒)
maxMaxBufferLength: 15, // 缓冲区长度的上限
maxBufferSize: 30 * 1000 * 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.hls.startLoad(); //重连
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 { } else {
this.showLoadingIndicator('视频加载失败') this.immediateCleanup()
}
},
immediate: true
},
url(newUrl) {
// console.log(newUrl,'77777777777777777777777777777777')
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() this.fullCleanup()
} }
}, }, 1000)
},
showLoadingIndicator(text) { fullCleanup() {
this.loading = true if (this.hls) {
this.loadingText = text this.hls.destroy()
}, this.hls = null
}
async safePlay() { if (this.video) {
if (!this.video || this.playAttempts >= this.maxPlayAttempts) return this.video.pause()
this.video.removeAttribute('src')
this.video.load()
}
try { this.loading = false
this.playAttempts++ this.retryCount = 0
if (this.video.readyState >= 2) { this.isReady = false
await this.video.play() this.playAttempts = 0
this.playAttempts = 0
} else { if (this.cleanupTimeout) {
setTimeout(this.safePlay, 500) clearTimeout(this.cleanupTimeout)
}
},
initializePlayer() {
if (!this.isActive || !this.url) return
// 如果是重新初始化播放器,先清理已存在的资源
if(this.url.startsWith('http://192.168.77.200:8050/')){
this.hls = new WebRTCWhep({
url: this.url, // WHEP 服务器地址
container: this.video, // 视频播放容器
iceServers: [{ urls: 'turn:192.168.77.200:3478',username: 'ZLMediaKit',credential: 'ZLMediaKit'}]
})
this.hls.on('error', (error) => {
console.error('错误:', error.message, error.type)
if(error.type ==='REQUEST_ERROR' || error.type ==='NOT_FOUND_ERROR'){
this.initializePlayer();
} }
} catch (error) { })
console.warn('播放失败:', error) this.hls.on('play:failed', (err) => {
setTimeout(this.safePlay, 1000) // this.initializePlayer();
})
}else{
if (this.hls) {
this.immediateCleanup()
}
this.hls = new Hls({
// 内存优化配置
maxBufferSize: 0, // 降低缓冲区大小15MB
maxBufferLength: 0.1, // 更小的缓冲窗口
liveSyncDuration: 1, // 紧跟直播点
liveMaxLatencyDuration: 5, // 最大延迟5秒
liveDurationInfinity: true,
lowLatencyMode: true, // 启用低延迟模式
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) => {
console.log('核心视频错误',data.type)
// this.hls.startLoad(); //重连
if (data.type === Hls.ErrorTypes.BUFFER_STALLED_ERROR) {
console.error('缓冲停滞错误,尝试重新加载视频');
this.hls.startLoad(); // 尝试重新加载视频
}
this.handleHlsError(data)
})
this.hls.on(Hls.Events.BUFFER_EOS, () => {
this.cleanupNetworkResources()
})
}
},
initVideo() {
this.beforeDestroy()
this.hls = new Hls({
maxBufferLength: 30, // 最大缓冲长度(秒)
maxMaxBufferLength: 15, // 缓冲区长度的上限
maxBufferSize: 30 * 1000 * 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.hls.startLoad(); //重连
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)
} }
} }
}, },
beforeDestroy() {
// 移除所有事件监听 handleHlsError(data) {
if (this.video) { // console.error('HLS Error:', data)
const events = ['canplay', 'waiting', 'playing', 'error', 'stalled', 'suspend'] if (data.fatal) {
events.forEach((event) => { switch (data.type) {
this.video.removeEventListener(event, this.handleVideoEvent) 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)
} }
this.fullCleanup()
} }
},
beforeDestroy() {
// 移除所有事件监听
if (this.video) {
const events = ['canplay', 'waiting', 'playing', 'error', 'stalled', 'suspend']
events.forEach((event) => {
this.video.removeEventListener(event, this.handleVideoEvent)
})
}
this.fullCleanup()
} }
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.myVideo-container { .myVideo-container {
position: relative; position: relative;
height: 100%; height: 100%;
} }
.myVideo { .myVideo {
width: 100%; width: 100%;
height: 100%; height: 100%;
// aspect-ratio: 16/9; // aspect-ratio: 16/9;
/* border: 1px solid #ccc; */ /* border: 1px solid #ccc; */
// border-radius: vw(5); // border-radius: vw(5);
} }
.loading-overlay { .loading-overlay {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
background: rgba(0, 0, 0, 0.3); background: rgba(0, 0, 0, 0.3);
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.loading-text { .loading-text {
color: white; color: white;
padding: vw(10); padding: vw(10);
border-radius: vw(4); border-radius: vw(4);
background: rgba(0, 0, 0, 0.6); background: rgba(0, 0, 0, 0.6);
} }
</style> </style>

View File

@@ -84,7 +84,7 @@
border: 1px solid #0096FF; border: 1px solid #0096FF;
color: #fff; color: #fff;
font-weight: bold; font-weight: bold;
font-size: ${fitChartSize(16)}px; font-size: ${fitChartSize(18)}px;
border-radius: ${fitChartSize(4)}px; border-radius: ${fitChartSize(4)}px;
padding: ${fitChartSize(4)}px ${fitChartSize(12)}px;"> padding: ${fitChartSize(4)}px ${fitChartSize(12)}px;">
${valueStr}</div>` ${valueStr}</div>`
@@ -93,7 +93,7 @@
}, },
grid: { grid: {
left: '2%', left: '2%',
right: '5%', right: '10%',
bottom: '5%', bottom: '5%',
top: '10%', top: '10%',
containLabel: true containLabel: true
@@ -103,12 +103,12 @@
x: 'center', x: 'center',
y: 'top', y: 'top',
icon: 'rect', icon: 'rect',
itemWidth: fitChartSize(8), itemWidth: fitChartSize(12),
itemHeight: fitChartSize(4), itemHeight: fitChartSize(12),
itemGap: fitChartSize(10), itemGap: fitChartSize(12),
textStyle: { textStyle: {
color: '#ffffff', color: '#ffffff',
fontSize: fitChartSize(12) fontSize: fitChartSize(22)
} }
}, },
title: { title: {
@@ -127,14 +127,14 @@
} }
}, },
axisLabel: { axisLabel: {
fontSize: fitChartSize(12), fontSize: fitChartSize(18),
color: 'rgba(255,255,255,0.9)' color: 'rgba(255,255,255,0.9)'
} }
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
axisLabel: { axisLabel: {
fontSize: fitChartSize(12), fontSize: fitChartSize(18),
color: 'rgba(255,255,255,0.9)' color: 'rgba(255,255,255,0.9)'
}, },
splitLine: { splitLine: {
@@ -224,7 +224,7 @@
top:0; top:0;
width: 100%; width: 100%;
height: 100%; height: 100%;
font-size:vw(18); font-size:font-vw(18);
// color:#999; // color:#999;
color:#02f9fa; color:#02f9fa;
display: flex; display: flex;

View File

@@ -48,7 +48,10 @@
} }
}) })
const { id,chart, setOption,chartVal,dispose ,clearOption} = useEchart() const { id, setOption,chartVal,dispose ,clearOption} = useEchart()
let condShow = ref(0) let condShow = ref(0)
let aIndex = 1 let aIndex = 1
var colorList = [] var colorList = []
@@ -56,35 +59,40 @@
watch( watch(
() => props.dataList, () => props.dataList,
(newVal) => { (newVal) => {
console.log(newVal,'监听数据切换变化')
aIndex+=1 aIndex+=1
if(aIndex>=3&&!newVal.length){
condShow.value = 1
if(aIndex>=3&&!newVal.length){
condShow.value = 1
} }
if (newVal.length > 0) { if (newVal.length > 0) {
colorList = []
nextTick(() => { console.log(colorList.value,'colorList')
clearOption(); condShow.value = 2
init() nextTick(() => {
}) init()
// defaultCofig.legend.formatter = (name) => {
// let percent = props.dataList.find((item) => item.name == name).value
// return name + '\u3000' + `${percent}%`
// }
// defaultCofig.series[0].data = props.dataList
// defaultCofig.series[0].label.formatter = () => {
// return `{value|${props.total}}` + '\n' + `{name|${props.label} }`
// }
// setOption({
// ...defaultCofig,
// ...props.config
// })
})
}else{ }else{
} }
}, },
{ immediate: true } { immediate: true }
) )
const init = ()=>{ const init = ()=>{
if(condShow.value===2){
return;
}
clearOption()
colorList = [];
condShow.value = 2
const validDataList = props.dataList.filter(item => {
return item && item.name && (item.value || item.value === 0);
});
props.dataList.forEach((item,index)=>{ props.dataList.forEach((item,index)=>{
if(item.name=='负面'){ if(item.name=='负面'){
@@ -105,30 +113,21 @@
color: colorList, color: colorList,
legend: { legend: {
orient: 'vertical', orient: 'vertical',
x: '64%', x: 'center',
y: 'center', y: '60%',
itemWidth: fitChartSize(12), bottom:'20%',
itemHeight: fitChartSize(12), itemWidth: fitChartSize(20),
itemHeight: fitChartSize(20),
itemGap: fitChartSize(10), itemGap: fitChartSize(10),
textStyle: { textStyle: {
color: '#ffffff', color: '#ffffff',
fontSize: fitChartSize(14) fontSize: fitChartSize(18)
}, }
formatter: (name) => {
// let percent = props.dataList.find((item) => item.name == name).value
const item = validDataList.find((item) => item.name === name);
const percent = item ? item.value : 0;
const displayName = name || '';
return `${displayName}\u3000${percent}%`;
},
}, },
series: [ series: [
{ {
type: 'pie', type: 'pie',
center: ['30%', '50%'], center: ['50%', '30%'],
radius: ['40%', '55%'], radius: ['40%', '55%'],
itemStyle: { itemStyle: {
borderWidth: fitChartSize(4), borderWidth: fitChartSize(4),
@@ -144,63 +143,35 @@
rich: { rich: {
value: { value: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(24), fontSize: fitChartSize(18),
fontWeight: 'bold', fontWeight: 'bold',
padding: [0, 0, 5, 0] padding: [0, 0, 5, 0]
}, },
name: { name: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(12) fontSize: fitChartSize(18)
} }
} }
}, },
labelLine: { labelLine: {
show: false show: false
}, },
data: validDataList data: []
} }
] ]
} }
// defaultCofig.series[0].data = props.dataList defaultCofig.legend.formatter = (name) => {
// defaultCofig.legend.formatter = (name) => { let percent = props.dataList.find((item) => item.name == name).value
// let percent = props.dataList.find((item) => item.name == name).value return name + '\u3000' + `${percent}%`
// if(name){ }
// return name + '\u3000' + `${percent}%` defaultCofig.series[0].data = props.dataList
// }else{ defaultCofig.series[0].label.formatter = () => {
// return name + '\u3000' + `${0}%` return `{value|${props.total}}` + '\n' + `{name|${props.label} }`
// } }
// } setOption({
// defaultCofig.series[0].label.formatter = () => {
// return `{value|${props.total}}` + '\n' + `{name|${props.label} }`
// }
setOption({},true)
const changeChart = setOption({
...defaultCofig, ...defaultCofig,
...props.config ...props.config
}) })
changeChart.off('legendselectchanged');
changeChart.on('legendselectchanged', function (e) {
console.log(e,'e')
var echartsArr = [];
for (let key in e.selected) {
if (e.selected[key]) {
echartsArr.push(key)
}
}
var echartsNum = 0;
props.dataList.forEach(item => {
if(echartsArr.includes(item.name)){
echartsNum += parseFloat(item.value)
}
})
defaultCofig.series[0].label.formatter = `{value|${parseInt(echartsNum/100*props.total)}}` + '\n' + `{name|${props.label}}`;
setOption({
...defaultCofig,
...props.config
})
});
} }
</script> </script>
@@ -212,7 +183,7 @@
top:0; top:0;
width: 100%; width: 100%;
height: 100%; height: 100%;
font-size:vw(18); font-size:font-vw(22);
// color:#999; // color:#999;
color:#02f9fa; color:#02f9fa;
display: flex; display: flex;

View File

@@ -81,7 +81,8 @@
show: false show: false
}, },
legend: { legend: {
show: false show: false,
}, },
grid: { grid: {
left: '4%', left: '4%',
@@ -114,7 +115,7 @@
show: true, show: true,
axisLabel: { axisLabel: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(18), fontSize: fitChartSize(11),
verticalAlign: 'bottom', verticalAlign: 'bottom',
padding: [0, -fitChartSize(10), fitChartSize(10), 0], padding: [0, -fitChartSize(10), fitChartSize(10), 0],
inside: true, inside: true,
@@ -125,7 +126,7 @@
value: { value: {
align: 'center', align: 'center',
color: '#fff', color: '#fff',
fontSize: fitChartSize(14) fontSize: fitChartSize(20)
} }
} }
}, },
@@ -148,7 +149,7 @@
fontWeight: 500, fontWeight: 500,
position: 'left', position: 'left',
align: 'left', align: 'left',
fontSize: fitChartSize(14), fontSize: fitChartSize(20),
formatter: function (params) { formatter: function (params) {
return params.data.name ?? '其他' return params.data.name ?? '其他'
} }
@@ -186,7 +187,7 @@
top:0; top:0;
width: 100%; width: 100%;
height: 100%; height: 100%;
font-size:vw(18); font-size:vw(20);
// color:#999; // color:#999;
color:#02f9fa; color:#02f9fa;
display: flex; display: flex;
@@ -194,7 +195,7 @@
justify-content: center; justify-content: center;
} }
.top { .top {
width: vw(250); width: vw(290);
height: vh(366); height: vh(650);
} }
</style> </style>

View File

@@ -93,7 +93,7 @@
legend: { legend: {
show: true, show: true,
x: 'center', x: 'center',
y: 'bottom', y: '72%',
itemHeight: fitChartSize(12), itemHeight: fitChartSize(12),
itemWidth: fitChartSize(12), itemWidth: fitChartSize(12),
itemGap: fitChartSize(6), itemGap: fitChartSize(6),
@@ -102,7 +102,6 @@
let obj = props.list.find((item) => item.name == name) let obj = props.list.find((item) => item.name == name)
return '{name|' + name + '} {value|' + obj?.value + '}{value|%}' return '{name|' + name + '} {value|' + obj?.value + '}{value|%}'
} }
// if(obj.value){ // if(obj.value){
// obj.value?obj.value:0; // obj.value?obj.value:0;
@@ -113,12 +112,12 @@
rich: { rich: {
name: { name: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(12) fontSize: fitChartSize(18)
}, },
value: { value: {
color: '#00D5F6', color: '#00D5F6',
fontWeight: 600, fontWeight: 600,
fontSize: fitChartSize(12) fontSize: fitChartSize(18)
} }
} }
} }
@@ -165,7 +164,7 @@
top:0; top:0;
width: 100%; width: 100%;
height: 100%; height: 100%;
font-size:vw(18); font-size:fonnt-vw(20);
// color:#999; // color:#999;
color:#02f9fa; color:#02f9fa;
display: flex; display: flex;
@@ -228,12 +227,12 @@
} }
&-item-label { &-item-label {
font-weight: 400; font-weight: 400;
font-size: vw(12); font-size: vw(18);
line-height: vh(14); line-height: vh(14);
} }
&-item-value { &-item-value {
font-weight: bold; font-weight: bold;
font-size: vw(16); font-size: vw(22);
line-height: vh(18); line-height: vh(18);
} }
} }

View File

@@ -20,9 +20,9 @@
.title-1 { .title-1 {
position: relative; position: relative;
.title { .title {
margin: vh(10) auto; margin: vh(20) auto;
width: vw(468); width: vw(640);
height: vh(32); height: vh(66);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -30,7 +30,7 @@
background-size: 100% 100%; background-size: 100% 100%;
& > span { & > span {
font-weight: 800; font-weight: 800;
font-size: vw(16); font-size: font-vw(20);
background-image: linear-gradient(to bottom, #ffffff 0%, #75c1ff 100%); background-image: linear-gradient(to bottom, #ffffff 0%, #75c1ff 100%);
-webkit-background-clip: text; -webkit-background-clip: text;
background-clip: text; background-clip: text;

View File

@@ -33,8 +33,8 @@
<style scoped lang="scss"> <style scoped lang="scss">
.title-2 { .title-2 {
width: vw(240); min-width: vw(240);
height: vh(28); height: vh(80);
display: flex; display: flex;
align-items: center; align-items: center;
// background-image: url('@/assets/images/title-5.png'); // background-image: url('@/assets/images/title-5.png');
@@ -42,12 +42,12 @@
.item{ .item{
// margin-right: vw(22); // margin-right: vw(22);
padding:vw(5) vw(10); padding:vw(5) vw(10);
cursor: pointer; cursor: pointer;
// border-bottom:1px solid #ccc; // border-bottom:1px solid #ccc;
} }
& span { & span {
font-weight: bold; font-weight: bold;
font-size: vw(15); font-size: font-vw(24);
background-image: linear-gradient(to bottom, #ffffff 0%, #75c1ff 100%); background-image: linear-gradient(to bottom, #ffffff 0%, #75c1ff 100%);
-webkit-background-clip: text; -webkit-background-clip: text;
background-clip: text; background-clip: text;

View File

@@ -16,17 +16,17 @@
<style scoped lang="scss"> <style scoped lang="scss">
.title-3 { .title-3 {
position: relative; position: relative;
width: 100%; // min-width: vw(400);
height: vh(12); height: vh(22);
margin-top: vh(20); margin-top: vh(20);
background-image: url('@/assets/images/title-6.png'); background-image: url('@/assets/images/title-6.png');
background-size: 100% 100%;
background-size: 100%;
& > span { & > span {
position: absolute; position: absolute;
bottom: vh(4); bottom: vh(4);
left: vw(20); left: vw(20);
font-size: vw(15); font-size: font-vw(22);
font-weight: bold; font-weight: bold;
background-image: linear-gradient(to bottom, #ffffff 0%, #0096ff 100%); background-image: linear-gradient(to bottom, #ffffff 0%, #0096ff 100%);
-webkit-background-clip: text; -webkit-background-clip: text;

View File

@@ -1,12 +1,12 @@
<template> <template>
<div class="dialog"> <div class="dialog">
<el-dialog <el-dialog
v-model="modelValue" v-model="modelValue"
align-center align-center
:modal="false" :modal="false"
:show-close="false" :show-close="false"
:z-index="9999" :z-index="9999"
destroy-on-close destroy-on-close
> >
<div class="dialog-box"> <div class="dialog-box">
<div class="video"> <div class="video">
@@ -16,20 +16,20 @@
<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">
<div <div
v-if="colletCond == 1" v-if="colletCond == 1"
class="video-follow" class="video-follow"
@click.stop="handleCollect()" @click.stop="handleCollect()"
>取消关注 >取消关注
</div> </div>
<div <div
v-if="colletCond == 0" v-if="colletCond == 0"
class="video-unfollow" class="video-unfollow"
@click.stop="handleCollect()" @click.stop="handleCollect()"
>关注 >关注
</div> </div>
</div> </div>
<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)" />
<span>聚焦</span> <span>聚焦</span>
@@ -39,19 +39,19 @@
<img src="@/assets/images/up.png" title="上转" @click="handleAction(UP)" /> <img src="@/assets/images/up.png" title="上转" @click="handleAction(UP)" />
<img src="@/assets/images/down.png" title="下转" @click="handleAction(DOWN)" /> <img src="@/assets/images/down.png" title="下转" @click="handleAction(DOWN)" />
<img <img
class="pause" class="pause"
src="@/assets/images/pause.png" src="@/assets/images/pause.png"
title="停止操作" title="停止操作"
@click="handleAction(STOP)" @click="handleAction(STOP)"
/> />
<img src="@/assets/images/left.png" title="左转" @click="handleAction(LEFT)" /> <img src="@/assets/images/left.png" title="左转" @click="handleAction(LEFT)" />
<img src="@/assets/images/right.png" title="右转" @click="handleAction(RIGHT)" /> <img src="@/assets/images/right.png" title="右转" @click="handleAction(RIGHT)" />
</div> </div>
<div class="action-item"> <div class="action-item">
<div class="video-follow" @click="handleCollectAdd()" v-if="isDayCurr==0">收藏</div> <div class="video-follow" @click="handleCollectAdd()" v-if="isDayCurr==0">收藏</div>
<div class="video-follow" @click="handleCollectAdd()" v-if="isDayCurr==1">取消收藏</div> <div class="video-follow" @click="handleCollectAdd()" v-if="isDayCurr==1">取消收藏</div>
</div> </div>
</div> </div>
</div> </div>
@@ -61,254 +61,254 @@
</template> </template>
<script setup> <script setup>
import Hls from 'hls.js' import Hls from 'hls.js'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { postVideoControlApi,postVideoCollectApi } from '@/api/monitor' import { postVideoControlApi,postVideoCollectApi } from '@/api/monitor'
import { getColletDiyApi } from '@/api/home' import { getColletDiyApi } from '@/api/home'
import pubSub from 'pubsub-js' import pubSub from 'pubsub-js'
// const Z00M_IN = 'ZOOM_IN' // 焦距变大 // const Z00M_IN = 'ZOOM_IN' // 焦距变大
// const Z00M_OUT = 'ZOOM_OUT' // 焦距变小 // const Z00M_OUT = 'ZOOM_OUT' // 焦距变小
// const UP = 'UP' // 上转 // const UP = 'UP' // 上转
// const DOWN = 'DOWN' // 下转 // const DOWN = 'DOWN' // 下转
// const LEFT = 'LEFT' // 左转 // const LEFT = 'LEFT' // 左转
// const RIGHT = 'RIGHT' // 右转 // const RIGHT = 'RIGHT' // 右转
// const STOP = 'STOP' // 停止操作 // const STOP = 'STOP' // 停止操作
const Z00M_IN = 'zoomin' // 焦距变大 const Z00M_IN = 'zoomin' // 焦距变大
const Z00M_OUT = 'zoomout' // 焦距变小 const Z00M_OUT = 'zoomout' // 焦距变小
const UP = 'up' // 上转 const UP = 'up' // 上转
const DOWN = 'down' // 下转 const DOWN = 'down' // 下转
const LEFT = 'left' // 左转 const LEFT = 'left' // 左转
const RIGHT = 'right' // 右转 const RIGHT = 'right' // 右转
const STOP = 'stop' // 停止操作 const STOP = 'stop' // 停止操作
let ACTION = '0' let ACTION = '0'
let command = ref('') let command = ref('')
const props = defineProps({ const props = defineProps({
src: { src: {
type: String, type: String,
default: '' default: ''
}, },
cameraIndexCode: { cameraIndexCode: {
type: String, type: String,
default: '' default: ''
}, },
isCollect:{ isCollect:{
type: Number, type: Number,
default: 0 default: 0
}, },
isDiy:{ isDiy:{
type: Number, type: Number,
default: 0 default: 0
} }
}) })
let modelValue = defineModel() let modelValue = defineModel()
let videoRef = ref() let videoRef = ref()
let webRtcServer = null let webRtcServer = null
let hlsRef = null let hlsRef = null
let colletCond = ref(props.isCollect) let colletCond = ref(props.isCollect)
let isDayCurr = ref(props.isDiy) let isDayCurr = ref(props.isDiy)
watch( watch(
() =>modelValue.value, () =>modelValue.value,
(val) => { (val) => {
colletCond.value = props.isCollect colletCond.value = props.isCollect
isDayCurr.value = props.isDiy isDayCurr.value = props.isDiy
console.log(props.isDiy,'val[0].value') console.log(props.isDiy,'val[0].value')
}, },
{ {
immediate: true immediate: true
} }
) )
const emit = defineEmits(['isDiyChange']); const emit = defineEmits(['isDiyChange']);
// 收藏 // 收藏
const handleCollectAdd = async () => { const handleCollectAdd = async () => {
await getColletDiyApi({ await getColletDiyApi({
cameraIndexCode:props.cameraIndexCode, cameraIndexCode:props.cameraIndexCode,
isDiy: props.isDiy == 0 ? 1 : 0 isDiy: props.isDiy == 0 ? 1 : 0
}) })
if(props.isDiy==1){
isDayCurr.value=0
// modelValue.value = false
}else{
isDayCurr.value=1
}
emit('isDiyChange', isDayCurr.value);
pubSub.publish('videoIsDiy',{isDiy:props.isDiy,cameraIndexCode:props.cameraIndexCode} )
if(props.isDiy==1){
isDayCurr.value=0
// modelValue.value = false
}else{
isDayCurr.value=1
} }
// 关注 emit('isDiyChange', isDayCurr.value);
const handleCollect = async (id, status, index) => { pubSub.publish('videoIsDiy',{isDiy:props.isDiy,cameraIndexCode:props.cameraIndexCode} )
await postVideoCollectApi({
cameraIndexCode:props.cameraIndexCode,
isCollect: colletCond.value == 0 ? 1 : 0
})
if (colletCond.value == 0) { }
colletCond.value = 1 // 关注
} else { const handleCollect = async (id, status, index) => {
colletCond.value = 0 await postVideoCollectApi({
modelValue.value = false cameraIndexCode:props.cameraIndexCode,
} isCollect: colletCond.value == 0 ? 1 : 0
pubSub.publish('videoCollect', props.cameraIndexCode) })
} if (colletCond.value == 0) {
const handleAction = async (e) => { colletCond.value = 1
if (e == STOP) { } else {
ACTION = '1' colletCond.value = 0
command.value = e
} else {
ACTION = '0'
command.value = e
}
await postVideoControlApi({
command: command.value,
action: ACTION,
cameraIndexCode: props.cameraIndexCode
})
if (e == STOP) {
command.value = ''
}
ElMessage({
message: '操作成功',
type: 'success'
})
}
const handleClose = () => {
if (hlsRef) {
hlsRef.destroy()
hlsRef = null
}
modelValue.value = false modelValue.value = false
} }
const init = () => { pubSub.publish('videoCollect', props.cameraIndexCode)
hlsRef = new Hls({
enableWorker: false, // 禁用 Worker 来避免额外的线程 }
enableSoftwareAES: true, // 使用软件解码器以避免硬件解码的额外请求 const handleAction = async (e) => {
cache: true, // 启用缓存 if (e == STOP) {
maxBufferLength: 10, // 最大缓冲长度(秒) ACTION = '1'
maxMaxBufferLength: 15, // 缓冲区长度的上限 command.value = e
maxBufferSize: 20 * 1000 * 1000 // 最大缓冲大小(字节) } else {
}) ACTION = '0'
hlsRef.loadSource(props.src) command.value = e
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
}
}
})
} }
await postVideoControlApi({
onMounted(()=>{ command: command.value,
action: ACTION,
cameraIndexCode: props.cameraIndexCode
}) })
if (e == STOP) {
command.value = ''
}
ElMessage({
message: '操作成功',
type: 'success'
})
}
const handleClose = () => {
if (hlsRef) {
hlsRef.destroy()
hlsRef = null
}
modelValue.value = false
}
const init = () => {
hlsRef = new Hls({
enableWorker: false, // 禁用 Worker 来避免额外的线程
enableSoftwareAES: true, // 使用软件解码器以避免硬件解码的额外请求
cache: true, // 启用缓存
maxBufferLength: 10, // 最大缓冲长度(秒)
maxMaxBufferLength: 15, // 缓冲区长度的上限
maxBufferSize: 20 * 1000 * 1000 // 最大缓冲大小(字节)
})
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
}
}
})
}
onMounted(()=>{
})
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.video-follow,.video-unfollow { .video-follow,.video-unfollow {
// cursor: pointer; // cursor: pointer;
// display: none; // display: none;
// position: absolute; // position: absolute;
// right: vw(8); // right: vw(8);
// top: vw(8); // top: vw(8);
// z-index: 9999; // z-index: 9999;
// margin-left:vw(20); // margin-left:vw(20);
padding: vw(10); padding: vw(10);
// height: vh(24); // height: vh(24);
text-align: center; text-align: center;
// line-height: vh(24); // line-height: vh(24);
font-weight: 400; font-weight: 400;
font-size: vw(16); font-size:font-vw(16);
color: #ffffff; color: #ffffff;
// background-image: url('@/assets/images/unfollow.png'); // background-image: url('@/assets/images/unfollow.png');
background-size: 100% 100%; background-size: 100% 100%;
} }
.video-item__follow { .video-item__follow {
// background-image: url('@/assets/images/unfollow.png'); // background-image: url('@/assets/images/unfollow.png');
} }
.dialog { .dialog {
z-index: 9999; z-index: 9999;
.action { .action {
&-box { &-box {
margin-top: vh(16); margin-top: vh(16);
gap: vw(20); gap: vw(20);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
}
&-item {
padding: vw(16);
display: flex;
align-items: center;
background: #0a4190;
border-radius: vw(8);
> img {
cursor: pointer;
width: vw(34);
height: auto;
} }
&-item { > span {
padding: vw(16); margin: 0 vw(16);
display: flex; font-weight: 400;
align-items: center; font-size:font-vw(16);
background: #0a4190; color: #ffffff;
border-radius: vw(8); }
> img { .pause {
cursor: pointer; margin: 0 vw(10);
width: vw(34);
height: auto;
}
> span {
margin: 0 vw(16);
font-weight: 400;
font-size: vw(16);
color: #ffffff;
}
.pause {
margin: 0 vw(10);
}
} }
}
.none {
position: absolute;
left: 50%;
top: 50%;
width: vw(1814);
height: vw(980);
color: #fff;
font-weight: bold;
font-size: vw(30);
transform: translate(-50%, -50%);
z-index: 999;
}
:deep(.el-dialog) {
position: relative;
width: vw(1940);
background: transparent !important;
}
.dialog-box {
padding: vw(40) vw(30) vw(30) vw(30);
background-image: url('@/assets/images/video-bg.png');
background-size: 100% 100%;
}
:deep(.el-dialog__header) {
padding-bottom: 0 !important;
}
.video {
width: vw(1814);
height: vw(920);
object-fit: contain;
background-color: #062b57;
}
.close {
cursor: pointer;
position: absolute;
right: vw(70);
top: vw(80);
width: vw(60);
z-index: 9999;
} }
} }
.none {
position: absolute;
left: 50%;
top: 50%;
width: vw(1814);
height: vw(980);
color: #fff;
font-weight: bold;
font-size:font-vw(30);
transform: translate(-50%, -50%);
z-index: 999;
}
:deep(.el-dialog) {
position: relative;
width: vw(1940);
background: transparent !important;
}
.dialog-box {
padding: vw(40) vw(30) vw(30) vw(30);
background-image: url('@/assets/images/video-bg.png');
background-size: 100% 100%;
}
:deep(.el-dialog__header) {
padding-bottom: 0 !important;
}
.video {
width: vw(1814);
height: vw(920);
object-fit: contain;
background-color: #062b57;
}
.close {
cursor: pointer;
position: absolute;
right: vw(70);
top: vw(80);
width: vw(60);
z-index: 9999;
}
}
</style> </style>

View File

@@ -8,7 +8,7 @@
v-for="(item, index) in navList" v-for="(item, index) in navList"
:key="index" :key="index"
> >
{{ item }} {{ item.dictLabel }}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -11,11 +11,11 @@ export function useEchart() {
chart = echarts.init(dom) chart = echarts.init(dom)
} }
const setOption = (params, update = false) => { const setOption = (params, update = false) => {
initChart() initChart()
chart.setOption(params, update) chart.setOption(params, update)
return chart;
} }
const clearOption = () => { const clearOption = () => {
console.log('clearooooooooooooooooo')
// 将series设置为空数组可以清空图表内容 // 将series设置为空数组可以清空图表内容
chart.setOption({ chart.setOption({
series:[] series:[]

View File

@@ -3,7 +3,7 @@ export function useWebSocket(url) {
let socket = ref(null) // socket对象 let socket = ref(null) // socket对象
let isConnected = ref(false) // 是否连接成功 let isConnected = ref(false) // 是否连接成功
let dataRes = ref(null) // 存储推送数据 let dataRes = ref(null) // 存储推送数据
let timer=null;
const connectWebSocket = () => { const connectWebSocket = () => {
socket.value = new WebSocket(url, 'echo-protocol', { socket.value = new WebSocket(url, 'echo-protocol', {
headers: { headers: {
@@ -28,19 +28,6 @@ export function useWebSocket(url) {
socket.value.onclose = (event) => { socket.value.onclose = (event) => {
isConnected.value = false isConnected.value = false
console.log('WebSocket close',url, event) console.log('WebSocket close',url, event)
if(!timer){
timer =setInterval(() => {
if(!isConnected.value){
console.log('重连中...')
connectWebSocket()
}else if(isConnected.value){
clearInterval(timer)
timer = null;
}
}, 5000);
}
} }
} }

View File

@@ -36,7 +36,7 @@
</template> </template>
<script setup> <script setup>
import {getVideoListApi, getColletListApi, getPreviewUrlApi} from '@/api/home' import { getPreviewUrlApi,getColletListApi } from '@/api/home'
import { postVideoCollectApi } from '@/api/monitor' import { postVideoCollectApi } from '@/api/monitor'
import primary from '@/assets/images/item-primary.png' import primary from '@/assets/images/item-primary.png'
@@ -77,16 +77,11 @@ import {getVideoListApi, getColletListApi, getPreviewUrlApi} from '@/api/home'
getVideoList() getVideoList()
}) })
} }
const handleItem = async (item) => { const handleItem = (item) => {
console.log(item, 'iscollect') console.log(item,'iscollect')
let res = await getPreviewUrlApi({ src.value = item.hlsUrl
cameraIndexCode: item.cameraIndexCode, isCollect.value = item.isCollect
type: 'hls', isDiy.value = item.isDiy
subStream:0
})
src.value = res.data.url
isCollect.value = item.isCollect
isDiy.value = item.isDiy
cameraIndexCode.value = item.cameraIndexCode cameraIndexCode.value = item.cameraIndexCode
videoShow.value = true videoShow.value = true
} }
@@ -101,8 +96,9 @@ import {getVideoListApi, getColletListApi, getPreviewUrlApi} from '@/api/home'
pubSub.publish('videoCollect') pubSub.publish('videoCollect')
} }
const handleClose = () => { const handleClose = () => {
clearHlsRefs() modelValue.value = false
modelValue.value = false clearHlsRefs()
} }
const clearHlsRefs = () => { const clearHlsRefs = () => {
if (hlsRefs.length > 0) { if (hlsRefs.length > 0) {
@@ -123,64 +119,64 @@ import {getVideoListApi, getColletListApi, getPreviewUrlApi} from '@/api/home'
list.value = [] list.value = []
getVideoList() getVideoList()
} }
const createPlayer = (cameraIndexCode,videoElement) => { const createPlayer = (cameraIndexCode,videoElement) => {
getPreviewUrlApi({ getPreviewUrlApi({
type: 'hls', type: 'hls',
cameraIndexCode: cameraIndexCode, cameraIndexCode: cameraIndexCode,
subStream:1 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, // 视频播放容器
iceServers: [{ urls: 'turn:192.168.77.200:3478',username: 'ZLMediaKit',credential: 'ZLMediaKit'}] iceServers: [{ urls: 'turn:192.168.77.200:3478',username: 'ZLMediaKit',credential: 'ZLMediaKit'}]
}) })
player.on('error', (error) => { player.on('error', (error) => {
console.error('错误:', error.message, error.type) console.error('错误:', error.message, error.type)
if(error.type ==='REQUEST_ERROR' || error.type ==='NOT_FOUND_ERROR'){ if(error.type ==='REQUEST_ERROR' || error.type ==='NOT_FOUND_ERROR'){
createPlayer(cameraIndexCode,videoElement) createPlayer(cameraIndexCode,videoElement);
}
})
player.on('play:failed', (err) => {
// createPlayer(cameraIndexCode,videoElement);
})
webrtcRefs.push(player)
}
else{
const player = new Hls({
maxBufferLength: 10, // 最大缓冲长度(秒)
maxMaxBufferLength: 15, // 缓冲区长度的上限
maxBufferSize: 30 * 1000 * 1000 // 最大缓冲大小(字节)
})
player.loadSource(url)
player.attachMedia(videoElement)
player.on(Hls.Events.MANIFEST_PARSED, () => {
videoElement.play()
})
player.on(Hls.Events.ERROR, (event, data) => {
// 根据错误类型进行处理
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
console.log('网络错误,尝试重新加载');
player.startLoad();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.log('媒体错误,尝试修复');
player.recoverMediaError();
break;
default:
console.log('无法恢复的错误,销毁播放器');
hls.destroy();
break;
} }
} })
}) player.on('play:failed', (err) => {
hlsRefs.push(player) // createPlayer(cameraIndexCode,videoElement);
} })
}) webrtcRefs.push(player)
} }
else{
const player = new Hls({
maxBufferLength: 10, // 最大缓冲长度(秒)
maxMaxBufferLength: 15, // 缓冲区长度的上限
maxBufferSize: 30 * 1000 * 1000 // 最大缓冲大小(字节)
})
player.loadSource(url)
player.attachMedia(videoElement)
player.on(Hls.Events.MANIFEST_PARSED, () => {
videoElement.play()
})
player.on(Hls.Events.ERROR, (event, data) => {
// 根据错误类型进行处理
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
console.log('网络错误,尝试重新加载');
player.startLoad();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.log('媒体错误,尝试修复');
player.recoverMediaError();
break;
default:
console.log('无法恢复的错误,销毁播放器');
// hls.destroy();
break;
}
}
})
hlsRefs.push(player)
}
})
}
const getVideoList = async () => { const getVideoList = async () => {
let res = await getColletListApi(params) let res = await getColletListApi(params)
list.value = res.data list.value = res.data
@@ -202,8 +198,8 @@ const createPlayer = (cameraIndexCode,videoElement) => {
<style scoped lang="scss"> <style scoped lang="scss">
.z-dialog { .z-dialog {
:deep(.el-dialog) { :deep(.el-dialog) {
width: vw(2100); width: vw(2500);
padding: vw(8); padding: vw(15);
background-image: url('@/assets/images/dialog-bg.png') !important; background-image: url('@/assets/images/dialog-bg.png') !important;
background-size: 100% 100%; background-size: 100% 100%;
} }
@@ -214,14 +210,14 @@ const createPlayer = (cameraIndexCode,videoElement) => {
.list { .list {
margin-top: vw(30); margin-top: vw(30);
gap: vw(8); gap: vw(8);
height: vh(860); height: vh(1200);
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-content: flex-start; align-content: flex-start;
.item { .item {
position: relative; position: relative;
width: vw(410); width: vw(500);
height: vh(280); height: vh(400);
padding: vw(12); padding: vw(12);
box-sizing: border-box; box-sizing: border-box;
background-image: url('@/assets/images/item-primary.png'); background-image: url('@/assets/images/item-primary.png');
@@ -240,8 +236,8 @@ const createPlayer = (cameraIndexCode,videoElement) => {
> span { > span {
padding-left: vw(10); padding-left: vw(10);
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(18);
line-height: vw(14); line-height: vw(18);
color: #ffffff; color: #ffffff;
} }
} }
@@ -252,13 +248,15 @@ const createPlayer = (cameraIndexCode,videoElement) => {
right: vw(4); right: vw(4);
top: vw(4); top: vw(4);
z-index: 99; z-index: 99;
width: vw(64); min-width: vw(100);
height: vw(30); height: vw(50);
text-align: center; text-align: center;
line-height: vw(30); // line-height: vw(50);
font-weight: 400; font-weight: 400;
font-size: vw(12); font-size: font-vw(18);
color: #ffffff; color: #ffffff;
padding:vw(10);
box-sizing: border-box;
background-image: url('@/assets/images/unfollow.png'); background-image: url('@/assets/images/unfollow.png');
background-size: 100% 100%; background-size: 100% 100%;
} }

View File

@@ -10,14 +10,25 @@
:key="index" :key="index"
@click="handleItem(item)" @click="handleItem(item)"
> >
<video <HlsPlayer :url="item.hlsUrl" />
<div class="item-unfollow" @click.stop="handleUnfollow(item.cameraIndexCode, index)">取消关注</div>
<!-- <div>
<p class="item-title--primary">
{{ item.cameraName || item.cameraIndexCode }}
</p>
<video
class="item-img" class="item-img"
:id="'video' + index" :id="'video' + index"
muted muted
autoplay autoplay
:controls="false" :controls="false"
></video> :src="item.hlsUrl"
<div class="item-unfollow" @click.stop="handleUnfollow(item.cameraIndexCode, index)">取消关注</div> controlsList="nodownload"
>
<source src="" type="application/x-mpegURL" />
</video>
</div> -->
</li> </li>
</ul> </ul>
</div> </div>
@@ -39,7 +50,6 @@
import { useWebSocket } from '@/hooks/socket' import { useWebSocket } from '@/hooks/socket'
import { mode, socketBaseUrl, proSocketBaseUrl } from '@/utils/config' import { mode, socketBaseUrl, proSocketBaseUrl } from '@/utils/config'
import WebRTCWhep from 'whepts'
const { dataRes } = useWebSocket( const { dataRes } = useWebSocket(
`${mode == 'dev' ? socketBaseUrl : proSocketBaseUrl}/ws/securityAlerts` `${mode == 'dev' ? socketBaseUrl : proSocketBaseUrl}/ws/securityAlerts`
@@ -59,20 +69,14 @@ let isCollect = ref(0)
let cameraIndexCode = ref('') let cameraIndexCode = ref('')
let videoShow = ref(false) let videoShow = ref(false)
let allShow = ref(false) let allShow = ref(false)
let webrtcRefs = []
let hlsRefs = [] let hlsRefs = []
let timer = null let timer = null
let isDiy = ref(0) let isDiy = ref(0)
const handleItem = async (item) => { const handleItem = (item) => {
let res = await getPreviewUrlApi({ src.value = item.hlsUrl
cameraIndexCode: item.cameraIndexCode,
type: 'hls',
subStream:0
})
src.value = res.data.url
cameraIndexCode.value = item.cameraIndexCode cameraIndexCode.value = item.cameraIndexCode
isCollect.value = item.isCollect isCollect.value = item.isCollect
isDiy.value = item.isDiy isDiy.value = item.isDiy
videoShow.value = true videoShow.value = true
} }
@@ -94,76 +98,34 @@ let isCollect = ref(0)
src.value = res.data.url src.value = res.data.url
videoShow.value = true videoShow.value = true
} }
const createPlayer = (cameraIndexCode,videoElement) => {
getPreviewUrlApi({
type: 'hls',
cameraIndexCode: cameraIndexCode,
subStream:0
}).then(res=>{
const url = res.data.url;
if(url.startsWith('http://192.168.77.200:8050/')){
const player = new WebRTCWhep({
url:url, // WHEP 服务器地址
container: videoElement, // 视频播放容器
iceServers: [{ urls: 'turn:192.168.77.200:3478',username: 'ZLMediaKit',credential: 'ZLMediaKit'}]
})
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)
}
else{
const player = new Hls({
maxBufferLength: 10, // 最大缓冲长度(秒)
maxMaxBufferLength: 15, // 缓冲区长度的上限
maxBufferSize: 30 * 1000 * 1000 // 最大缓冲大小(字节)
})
player.loadSource(url)
player.attachMedia(videoElement)
player.on(Hls.Events.MANIFEST_PARSED, () => {
videoElement.play()
})
player.on(Hls.Events.ERROR, (event, data) => {
// 根据错误类型进行处理
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
console.log('网络错误,尝试重新加载');
player.startLoad();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.log('媒体错误,尝试修复');
player.recoverMediaError();
break;
default:
console.log('无法恢复的错误,销毁播放器');
// hls.destroy();
break;
}
}
})
hlsRefs.push(player)
}
})
}
const getVideoList = async () => { const getVideoList = async () => {
let res = await getColletListApi({ let res = await getColletListApi({
pageNum: 1, pageNum: 1,
pageSize: 5 pageSize: 5
}) })
list.value = res.data list.value = res.data
postVideoRemain()
if (timer) clearInterval(timer) if (timer) clearInterval(timer)
nextTick(() => { // console.log(list.value,'list.valuelist.valuelist.valuelist.value')
list.value.forEach(async (item, index) => { // nextTick(() => {
var videoElement = document.getElementById(`video${index}`) // list.value.forEach(async (item, index) => {
createPlayer(item.cameraIndexCode,videoElement); // 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()
// })
// hlsRefs.push(hls)
// })
// })
} }
watch( watch(
() => list.value, () => list.value,
@@ -181,22 +143,12 @@ let isCollect = ref(0)
}) })
hlsRefs = [] hlsRefs = []
} }
if(webrtcRefs.length>0){
webrtcRefs.map((item) => {
try{
item.close()
}catch (e) {
}
})
webrtcRefs = [];
}
getVideoList() getVideoList()
} }
const onVideoCollect = () => { const onVideoCollect = () => {
pubSub.subscribe('videoCollect', () => { pubSub.subscribe('videoCollect', () => {
clearHlsRefs() clearHlsRefs()
getVideoList() // getVideoList()
}) })
} }

View File

@@ -2,7 +2,7 @@
<div class="correspondence"> <div class="correspondence">
<div class="top-box"> <div class="top-box">
<div class="title">融合通信</div> <div class="title">融合通信</div>
<div class="icon-box flex"> <div class="icon-box flex" style="height: initial;">
<div <div
class="item" class="item"
v-for="item in deptsList" v-for="item in deptsList"
@@ -340,6 +340,8 @@
.item-name { .item-name {
width: 90%; width: 90%;
text-align: center; text-align: center;
line-height: 1.6;
font-size:vw(18);
} }
.sp-img { .sp-img {
width: vw(100); width: vw(100);
@@ -347,7 +349,8 @@
.correspondence { .correspondence {
margin: vw(8); margin: vw(8);
width: vw(300); width: vw(300);
height: vh(1070); // height: vh(1070);
height: 100%;
background-image: url('@/assets/images/bg-1.png'); background-image: url('@/assets/images/bg-1.png');
background-size: 100% 100%; background-size: 100% 100%;
} }
@@ -370,11 +373,11 @@
} }
.table { .table {
width: 100%; width: 100%;
margin-top: vh(5); margin-top: vh(20);
.header { .header {
height: vh(28); height: vh(28);
font-weight: 400; font-weight: 400;
font-size: vw(12); font-size: font-vw(20);
color: #fff; color: #fff;
display: flex; display: flex;
background: linear-gradient(180deg, rgba(0, 99, 255, 0) 0%, #0063ff 100%); background: linear-gradient(180deg, rgba(0, 99, 255, 0) 0%, #0063ff 100%);
@@ -404,7 +407,7 @@
.item { .item {
height: vh(50); height: vh(50);
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(14);
color: #f1f7ff; color: #f1f7ff;
display: flex; display: flex;
&:nth-child(2n + 1) { &:nth-child(2n + 1) {
@@ -430,7 +433,7 @@
span { span {
margin-left: vw(30); margin-left: vw(30);
font-weight: 800; font-weight: 800;
font-size: vw(15); font-size: font-vw(15);
line-height: vh(26); line-height: vh(26);
text-align: center; text-align: center;
font-style: normal; font-style: normal;
@@ -446,9 +449,10 @@
.top-box { .top-box {
width: 100%; width: 100%;
height: vh(500); height: vh(500);
height:50%;
.icon-box { .icon-box {
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(14);
color: #ffffff; color: #ffffff;
line-height: vh(16); line-height: vh(16);
flex-wrap: wrap; flex-wrap: wrap;
@@ -475,7 +479,7 @@
text-align: center; text-align: center;
line-height: vh(26); line-height: vh(26);
margin-left: vw(32.5); margin-left: vw(32.5);
font-size: vw(16); font-size: font-vw(22);
font-weight: 800; font-weight: 800;
color: #fff; color: #fff;
background-image: url('@/assets/images/title-1.png'); background-image: url('@/assets/images/title-1.png');

View File

@@ -3,6 +3,7 @@
<div v-if="isBack" class="back2" @click="handleHome"> <div v-if="isBack" class="back2" @click="handleHome">
<img class="icon" src="@/assets/images/home.png" alt="" /> 首页 <img class="icon" src="@/assets/images/home.png" alt="" /> 首页
</div> </div>
<div class="btn-all" :class="!isBack?'all-home':''" v-if="!isBack" @click="allShow = true" >核心景区视频</div>
<ul class="nav-left"> <ul class="nav-left">
<li <li
class="nav-left-item" class="nav-left-item"
@@ -85,25 +86,29 @@
<div class="weather"> <div class="weather">
<span>{{ weatherData?.temperature }}-{{ weatherData?.skycon }}</span> <span>{{ weatherData?.temperature }}-{{ weatherData?.skycon }}</span>
<span class="line">|</span> <span class="line">|</span>
<span>风速:{{ weatherData?.windSpeed }}</span>
<span class="line">|</span> <!-- <span class="line">|</span> -->
<span>空气质量:{{ weatherData?.airQuality }}</span> <span>空气质量:{{ weatherData?.airQuality }}</span>
<div class="top-20">
<span>风速:{{ weatherData?.windSpeed }}</span>
</div>
</div> </div>
<p class="date">{{ currentDate }}</p> <p class="date">{{ currentDate }}</p>
<div v-if="isBack" class="back" @click="handleBack"> <div v-if="isBack" class="back" @click="handleBack">
<img class="icon" src="@/assets/images/back.png" alt="" /> 返回 <img class="icon" src="@/assets/images/back.png" alt="" /> 返回
</div> </div>
</div> </div>
<div class="amplify" @click="handleAmplify"> <!-- <div class="amplify" @click="handleAmplify">
<img class="icon-qp" src="@/assets/images/qping.png" alt="" /> <img class="icon-qp" src="@/assets/images/qping.png" alt="" />
</div> </div> -->
<all-list v-model="allShow" />
</template> </template>
<script> <script>
</script> </script>
<script setup> <script setup>
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import allList from '../CoreVideo/allList'
import title2 from '@/assets/images/title-2.png' import title2 from '@/assets/images/title-2.png'
import title3 from '@/assets/images/title-3.png' import title3 from '@/assets/images/title-3.png'
import title2Select from '@/assets/images/title-2-select.png' import title2Select from '@/assets/images/title-2-select.png'
@@ -119,7 +124,7 @@
const homeStore = useHomeStore() const homeStore = useHomeStore()
const scenicStore = useScenicStore() const scenicStore = useScenicStore()
const router = useRouter() const router = useRouter()
let allShow = ref(false)
let currentDate = ref('') let currentDate = ref('')
let weatherData = ref({}) let weatherData = ref({})
let title = ref('') let title = ref('')
@@ -167,7 +172,6 @@
router.push('/home') router.push('/home')
} }
const handleCommand = (item, type) => { const handleCommand = (item, type) => {
current.value = '' current.value = ''
if (type === 'hotel') { if (type === 'hotel') {
otherRightLabel.value = '其他场馆' otherRightLabel.value = '其他场馆'
@@ -191,6 +195,7 @@
// 点击导航 // 点击导航
const handleNav = (item) => { const handleNav = (item) => {
if (isSkip.value) { if (isSkip.value) {
router.push(item.path) router.push(item.path)
} else { } else {
@@ -213,6 +218,7 @@
otherLeftLabel.value = '其他酒店' otherLeftLabel.value = '其他酒店'
otherRightLabel.value = '其他场馆' otherRightLabel.value = '其他场馆'
pubSub.publish('hotelChange', item) pubSub.publish('hotelChange', item)
// console.log(item,'hotelChange')
break break
} }
} }
@@ -262,7 +268,8 @@
isSkip.value = false isSkip.value = false
isBack.value = true isBack.value = true
let res = await getSpotListApi() let res = await getSpotListApi()
navLeft.value = res.data.slice(0,3) navLeft.value = res.data
current.value = res.data[0].id current.value = res.data[0].id
title.value = navLeft.value[0].name title.value = navLeft.value[0].name
pubSub.publish('scenicChange', navLeft.value[0]) pubSub.publish('scenicChange', navLeft.value[0])
@@ -306,7 +313,7 @@
scenicSpotId: '', scenicSpotId: '',
id:10086, id:10086,
}, },
...spotRes.data.slice(0,3) ...spotRes.data
] ]
if(monitorDefaultData.value){ if(monitorDefaultData.value){
current.value = monitorDefaultData.value.id current.value = monitorDefaultData.value.id
@@ -367,11 +374,12 @@
isBack.value = true isBack.value = true
let hotelRes = await getHotelListApi({ hotelStadiumType: 1 }) let hotelRes = await getHotelListApi({ hotelStadiumType: 1 })
navLeft.value = hotelRes.data.slice(0, 3) navLeft.value = hotelRes.data.slice(0, 3)
current.value = navLeft.value[0].id current.value = navLeft.value[0].id
otherLeftNav.value = hotelRes.data.slice(3, hotelRes.data.length) otherLeftNav.value = hotelRes.data.slice(3, hotelRes.data.length - 1)
let venueRes = await getHotelListApi({ hotelStadiumType: 2 }) let venueRes = await getHotelListApi({ hotelStadiumType: 2 })
// console.log(venueRes,'venueRes')
navRight.value = venueRes.data.slice(0, 3) navRight.value = venueRes.data.slice(0, 3)
otherRightNav.value = venueRes.data.slice(3, venueRes.data.length) otherRightNav.value = venueRes.data.slice(3, venueRes.data.length - 1)
pubSub.publish('hotelChange', hotelRes.data[0]) pubSub.publish('hotelChange', hotelRes.data[0])
break break
} }
@@ -411,6 +419,9 @@
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.top-20{
margin-top:vh(20);
}
.amplify{ .amplify{
position:absolute; position:absolute;
right:vw(20); right:vw(20);
@@ -424,10 +435,10 @@
left: vw(326); left: vw(326);
.weather { .weather {
position: absolute; position: absolute;
right: 0; right: vw(-300);
top: vh(10); top: vh(30);
font-weight: 400; font-weight: 400;
font-size: vw(18); font-size: font-vw(18);
color: #ffffff; color: #ffffff;
.line { .line {
margin: 0 vw(10); margin: 0 vw(10);
@@ -435,20 +446,20 @@
} }
.date { .date {
position: absolute; position: absolute;
left: 0; left: vw(-300);
top: vh(10); top: vh(30);
font-weight: 400; font-weight: 400;
font-size: vw(18); font-size: font-vw(18);
color: #ffffff; color: #ffffff;
} }
.back { .back {
position: absolute; position: absolute;
right: 0; right: vw(240);
top: vh(50); top: vh(30);
width: vw(130); width: vw(150);
height: vh(36); height: vh(56);
font-weight: 600; font-weight: 600;
font-size: vw(20); font-size: vw(22);
color: #ffffff; color: #ffffff;
cursor: pointer; cursor: pointer;
display: flex; display: flex;
@@ -459,18 +470,39 @@
background: linear-gradient(270deg, rgba(8, 41, 86, 0.16) 0%, #0b61b4 100%); background: linear-gradient(270deg, rgba(8, 41, 86, 0.16) 0%, #0b61b4 100%);
.icon { .icon {
margin-right: vw(10); margin-right: vw(10);
width: vw(24); width: vw(34);
height: auto; height: auto;
} }
} }
.btn-all{
position: absolute;
cursor: pointer;
left: vw(140);
top: vh(30);
min-width: vw(180);
padding:0 vw(15);
height: vh(56);
font-weight: 600;
font-size: vw(22);
color: #ffffff;
background: linear-gradient(270deg, rgba(8, 41, 86, 0.16) 0%, #0b61b4 100%);
border-radius: vw(60);
border: 1px solid rgba(0, 114, 220, 0.3);
display: flex;
align-items: center;
justify-content: center;
}
.all-home{
left: vw(20);
}
.back2 { .back2 {
position: absolute; position: absolute;
left: 0; left: vw(-50);
top: vh(50); top: vh(30);
width: vw(130); width: vw(150);
height: vh(36); height: vh(56);
font-weight: 600; font-weight: 600;
font-size: vw(20); font-size: vw(22);
color: #ffffff; color: #ffffff;
cursor: pointer; cursor: pointer;
display: flex; display: flex;
@@ -481,7 +513,7 @@
background: linear-gradient(270deg, rgba(8, 41, 86, 0.16) 0%, #0b61b4 100%); background: linear-gradient(270deg, rgba(8, 41, 86, 0.16) 0%, #0b61b4 100%);
.icon { .icon {
margin-right: vw(10); margin-right: vw(10);
width: vw(24); width: vw(34);
height: auto; height: auto;
} }
} }
@@ -519,7 +551,7 @@
height: vh(56); height: vh(56);
line-height: vh(46); line-height: vh(46);
font-weight: 600; font-weight: 600;
font-size: vw(28); font-size: font-vw(24);
text-align: center; text-align: center;
padding: 0 vw(50); padding: 0 vw(50);
color: rgba(208, 236, 255, 0.9); color: rgba(208, 236, 255, 0.9);
@@ -546,7 +578,7 @@
height: vh(56); height: vh(56);
line-height: vh(46); line-height: vh(46);
font-weight: 600; font-weight: 600;
font-size: vw(28); font-size: font-vw(24);
text-align: center; text-align: center;
color: rgba(208, 236, 255, 0.9); color: rgba(208, 236, 255, 0.9);
background-image: url('@/assets/images/title-3.png'); background-image: url('@/assets/images/title-3.png');

View File

@@ -1,11 +1,11 @@
<template> <template>
<Header /> <Header />
<div class="flex flex-1"> <div class="flex flex-1">
<core-video v-if="homeStore.amplify" /> <!-- <core-video v-if="homeStore.amplify" /> -->
<div class="mian"> <div class="mian">
<router-view /> <router-view />
</div> </div>
<correspondence v-if="homeStore.amplify"/> <!-- <correspondence v-if="homeStore.amplify"/> -->
</div> </div>
</template> </template>

View File

@@ -16,7 +16,7 @@ export const useScenicStore = defineStore('scenic', () => {
infoList: [ infoList: [
{ name: '游玩舒适度', type: 0, value: '空闲' }, { name: '游玩舒适度', type: 0, value: '空闲' },
// { name: '景区安全', type: 0, value: '安全' }, // { name: '景区安全', type: 0, value: '安全' },
{ name: '交通拥堵度', type: 0, value: '通畅' }, { name: '通景交通', type: 0, value: '通畅' },
{ name: '停车场负荷', type: 0, value: '空闲' } { name: '停车场负荷', type: 0, value: '空闲' }
] ]
}) })

View File

@@ -1,9 +1,10 @@
@use 'sass:math'; @use 'sass:math';
//默认设计稿的宽度 //默认设计稿的宽度
$designWidth: 3822; $designWidth: 3840;
//默认设计稿的高度 //默认设计稿的高度
$designHeight: 1080; $designHeight: 2160;
//px转为vw的函数 //px转为vw的函数
@function vw($px) { @function vw($px) {
@@ -14,3 +15,41 @@ $designHeight: 1080;
@function vh($px) { @function vh($px) {
@return math.div($px, $designHeight) * 100vh; @return math.div($px, $designHeight) * 100vh;
} }
// 字体大小转为vw的函数放大1.4倍)
/// 将像素值转换为vw单位并自动放大1.4倍
/// @param {Number} $px - 设计稿中的像素值
/// @return {String} - 转换后的vw单位值
@function font-vw($px) {
$scaled-px: $px * 1.4;
@return math.div($scaled-px, $designWidth) * 100vw;
}
// 字体大小转为vh的函数放大1.4倍)
/// 将像素值转换为vh单位并自动放大1.4倍
/// @param {Number} $px - 设计稿中的像素值
/// @return {String} - 转换后的vh单位值
@function font-vh($px) {
$scaled-px: $px * 1.4;
@return math.div($scaled-px, $designHeight) * 100vh;
}
// 字体大小声明mixin默认使用vw单位
/// 声明字体大小自动应用1.4倍放大
/// @param {Number} $px - 设计稿中的像素值
/// @param {String} $unit - 单位类型,可选'vw'或'vh',默认'vw'
@mixin font-size($px, $unit: vw) {
@if $unit == vw {
font-size: font-vw($px);
} @else if $unit == vh {
font-size: font-vh($px);
} @else {
@error "Unsupported unit: #{$unit}. Use 'vw' or 'vh'.";
}
}
// 通用放大函数
/// 将值按指定比例放大
/// @param {Number} $value - 原始值
/// @param {Number} $factor - 放大系数默认1.4
/// @return {Number} - 放大后的值
@function scale($value, $factor: 1.4) {
@return $value * $factor;
}

View File

@@ -7,6 +7,6 @@ export const proSocketBaseUrl = 'ws://192.168.77.200:8060'
export const mode = 'pro' // 测试 dev 正式 pro export const mode = 'pro' // 测试 dev 正式 pro
export const devToken = export const devToken =
'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImE1OWFmNWYwLTU3OWItNDJkNy1hZDJhLTY0Y2JlODA5ZWI1NiJ9.BTxvu6jUWbN0qONWf5K6VzXopE8T8qXzKuX-mij21VJT4U0LdgnqToyqeNDQ2OyJ6cvpdJBzQ9mEEb-dnwrTpQ11' 'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImE1OWFmNWYwLTU3OWItNDJkNy1hZDJhLTY0Y2JlODA5ZWI1NiJ9.BTxvu6jUWbN0qONWf5K6VzXopE8T8qXzKuX-mij21VJT4U0LdgnqToyqeNDQ2OyJ6cvpdJBzQ9mEEb-dnwrTpQ'
export const proToken = export const proToken =
'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImE1OWFmNWYwLTU3OWItNDJkNy1hZDJhLTY0Y2JlODA5ZWI1NiJ9.dSLZekRsYf5ZZDCYqFEOgHTi4GeHD0m10gGHXrbgpc-hD52Zt7Vw05cxhQ-lzY29yf2IxH0oYi28DBfHdtf9SA' 'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImE1OWFmNWYwLTU3OWItNDJkNy1hZDJhLTY0Y2JlODA5ZWI1NiJ9.dSLZekRsYf5ZZDCYqFEOgHTi4GeHD0m10gGHXrbgpc-hD52Zt7Vw05cxhQ-lzY29yf2IxH0oYi28DBfHdtf9SA'

View File

@@ -1,8 +1,8 @@
/* Echarts图表尺寸自适应 */ /* Echarts图表尺寸自适应 */
export const fitChartSize = (size, width = 3822) => { export const fitChartSize = (size, width = 3840) => {
let clientWidth = let clientWidth =
window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
if (!clientWidth) return size if (!clientWidth) return size
let scale = clientWidth / width let scale = clientWidth / width
return Number((size * scale).toFixed(3)) return Number((size * scale).toFixed(3))*1.4
} }

View File

@@ -1,16 +1,16 @@
//默认设计稿的宽度 //默认设计稿的宽度
const designWidth = 3822 const designWidth = 3840
//默认设计稿的高度 //默认设计稿的高度
const designHeight = 1080 const designHeight = 2160
let styleUtil = { let styleUtil = {
// px转vw // px转vw
px2vw: function (_px) { px2vw: function (_px) {
return ((_px * 100.0) / designWidth).toFixed(3) + 'vw' return ((_px * 100.0*4) / designWidth).toFixed(3) + 'vw'
}, },
// px转vh // px转vh
px2vh: function (_px) { px2vh: function (_px) {
return ((_px * 100.0) / designHeight).toFixed(3) + 'vh' return ((_px * 100.0*4) / designHeight).toFixed(3) + 'vh'
} }
} }

View File

@@ -52,363 +52,376 @@
</div> </div>
</div> </div>
<!-- <div class="pagination">
<el-pagination
v-model:current-page="params.pageNum"
:page-size="params.pageSize"
:total="total"
background
layout="prev, pager, next"
@current-change="currentChange"
/>
</div> -->
</div> </div>
<!-- <ul class="videos">
<li class="video-item" v-for="item in 8" :key="item">
<img src="@/assets/images/sxzd.png" alt="" />
<p>
<span>核心路段这是一条信息说明</span>
</p>
</li>
</ul> -->
<!-- <div class="pagination-box">
<el-pagination background layout="prev, pager, next" :total="1000" />
</div> -->
</div> </div>
<VideoDialog v-model="show" :cameraIndexCode="cameraIndexCode" @isDiyChange="isDiyChange" :isDiy="isDiy" :isCollect="isCollect" :src="videoSrc" /> <VideoDialog v-model="show" :cameraIndexCode="cameraIndexCode" @isDiyChange="isDiyChange" :isDiy="isDiy" :isCollect="isCollect" :src="videoSrc" />
</template> </template>
<script setup> <script setup>
import { getVideCollectCate,getVideCollectCateSort,getColletDiyApi,getPreviewUrlApi} from '@/api/home' import { getVideCollectCate,getVideCollectCateSort,getColletDiyApi,getPreviewUrlApi} from '@/api/home'
import { import {
getVideoTypeApi, getVideoTypeApi,
getVideoRegionsApi, getVideoRegionsApi,
postVideoRemainApi, postVideoRemainApi,
postVideoControlApi, postVideoControlApi,
postVideoCollectApi postVideoCollectApi
} from '@/api/monitor' } from '@/api/monitor'
import draggable from 'vuedraggable'; import draggable from 'vuedraggable';
import pubSub from 'pubsub-js' import pubSub from 'pubsub-js'
import Hls from 'hls.js' import Hls from 'hls.js'
import emptyIco from '@/assets/images/n-icon.png' import emptyIco from '@/assets/images/n-icon.png'
import { debounce } from 'lodash' import { debounce } from 'lodash'
import WebRTCWhep from 'whepts' import WebRTCWhep from 'whepts'
// const Z00M_IN = 'ZOOM_IN' // 焦距变大 // const Z00M_IN = 'ZOOM_IN' // 焦距变大
// const Z00M_OUT = 'ZOOM_OUT' // 焦距变小 // const Z00M_OUT = 'ZOOM_OUT' // 焦距变小
// const UP = 'UP' // 上转 // const UP = 'UP' // 上转
// const DOWN = 'DOWN' // 下转 // const DOWN = 'DOWN' // 下转
// const LEFT = 'LEFT' // 左转 // const LEFT = 'LEFT' // 左转
// const RIGHT = 'RIGHT' // 右转 // const RIGHT = 'RIGHT' // 右转
// const STOP = 'STOP' // 停止操作 // const STOP = 'STOP' // 停止操作
const Z00M_IN = 'zoomin' // 焦距变大 const Z00M_IN = 'zoomin' // 焦距变大
const Z00M_OUT = 'zoomout' // 焦距变小 const Z00M_OUT = 'zoomout' // 焦距变小
const UP = 'up' // 上转 const UP = 'up' // 上转
const DOWN = 'down' // 下转 const DOWN = 'down' // 下转
const LEFT = 'left' // 左转 const LEFT = 'left' // 左转
const RIGHT = 'right' // 右转 const RIGHT = 'right' // 右转
const STOP = 'stop' // 停止操作 const STOP = 'stop' // 停止操作
let cond = ref(false) let cond = ref(false)
let ACTION = '0' let ACTION = '0'
let hlsRefs = [] let hlsRefs = []
let webrtcRefs = [] let webrtcRefs = []
let hlsRef = null let hlsRef = null
let timer = null let timer = null
let videoLog = ref(1) let videoLog = ref(1)
let videoList = ref([]) let videoList = ref([])
let cameraIndexCode = ref('') let cameraIndexCode = ref('')
let videoRef = ref() let videoRef = ref()
let monitorChange = null let monitorChange = null
let total = ref(0) let total = ref(0)
let loading = ref(false) let loading = ref(false)
let command = ref('') let command = ref('')
let cameraName = ref('') let cameraName = ref('')
let regionList = ref() let regionList = ref()
let params = reactive({ let params = reactive({
businessScenicArea: "", businessScenicArea: "",
cameraName: "", cameraName: "",
pageNum: 1, pageNum: 1,
pageSize: 6, pageSize: 6,
}) })
let grad = ref(3) let grad = ref(3)
let show = ref(false) let show = ref(false)
const onMonitorChange = () => { const onMonitorChange = () => {
monitorChange = pubSub.subscribe('hotelChange', (res, data) => { monitorChange = pubSub.subscribe('hotelChange', (res, data) => {
params.businessScenicArea = data.name params.businessScenicArea = data.name
params.pageNum = 1 params.pageNum = 1
videoList.value = [] videoList.value = []
total.value = 0 total.value = 0
cond.value = false cond.value = false
getRegionsList() getRegionsList()
}) })
} }
//弹窗收藏监听 //弹窗收藏监听
const isDiyChange = (val)=>{ const isDiyChange = (val)=>{
console.log(val,11222) console.log(val,11222)
isDiy.value = val isDiy.value = val
if(!val){ if(!val){
show.value = false show.value = false
videoList.value[diyIndex.value].videos = videoList.value[diyIndex.value].videos.filter(item => item.cameraIndexCode !== cameraIndexCode.value); videoList.value[diyIndex.value].videos = videoList.value[diyIndex.value].videos.filter(item => item.cameraIndexCode !== cameraIndexCode.value);
}
// videoList.value[diyIndex.value].videos.forEach(async (it, i) => {
// if(it.cameraIndexCode == cameraIndexCode.value){
// it.isDiy = val
// }
// })
}
const onStart = (res)=>{
}
const onEnd = (evt)=>{
const itemIndex = parseInt(evt.to.getAttribute('data-item-index')); // 当前拖拽的 item 的下标
getVideCollectCateSort({
key:videoList.value[itemIndex].key,
cameraIndexCodes:videoList.value[itemIndex].videos.map((item) => item.cameraIndexCode)
}).then((ress)=>{
// getVideCollectCateList()
})
// postVideoRemain()
initVideo()
}
// 获取关注列表
const getVideCollectCateList = async () => {
clearHlsRefs()
params.businessVideoDisplayPosition = ''
let res = await getVideCollectCate(params)
videoList.value = res.data
if(videoList.value.length<=3){
grad.value = 3
}else if(videoList.value.length<=6){
grad.value = 2
}else{
grad.value = 1
}
postVideoRemain()
// total.value = res.total
initVideo()
}
// 收藏
const handleCollect = async (id, status, index,element) => {
await getColletDiyApi({
cameraIndexCode:id,
isDiy: status == 0 ? 1 : 0
})
if (status == 0) {
element.isDiy = 1
} else {
videoList.value[index].videos = videoList.value[index].videos.filter(item => item.cameraIndexCode !== id);
console.log('取消收藏',)
element.isDiy = 0
show.value = false
}
// pubSub.publish('videoCollect', id)
}
// 采集
const handleAction = async (e) => {
if (e == STOP) {
ACTION = '1'
command.value = e
} else {
ACTION = '0'
command.value = e
}
await postVideoControlApi({
action: ACTION,
command: command.value,
cameraIndexCode: cameraIndexCode.value
})
if (e == STOP) {
command.value = ''
}
ElMessage({
message: '操作成功',
type: 'success'
})
}
// 返回列表
const handleBack = () => {
videoLog.value = 1
hlsRef.destroy()
initVideo()
}
let isCollect = ref(0)
let isDiy = ref(0)
let videoSrc = ref('')
let diyIndex = ref(null)
const handleCamera = async (itemCode,resource,index) => {
diyIndex.value = index
show.value = true
let res = await getPreviewUrlApi({
type: 'hls',
cameraIndexCode:itemCode,
subStream:0
})
cameraIndexCode.value = itemCode;
isCollect.value = resource.isCollect
isDiy.value = resource.isDiy
videoSrc.value = res.data.url
}
//清除 hls
const clearHlsRefs = () => {
if (hlsRefs.length > 0) {
hlsRefs.map((item) => {
try{
item.destroy()
}catch (e) {
}
})
hlsRefs = []
}
if(webrtcRefs.length>0){
webrtcRefs.map((item) => {
try{
item.close()
}catch (e) {
}
})
webrtcRefs = [];
}
}
// 分页
const currentChange = (e) => {
clearHlsRefs()
videoList.value = []
getRegionsList()
}
let thisVideo = ref(null)
const handleItemVideo = (url, type, code,item) => {
thisVideo.value = item
videoLog.value = 2
cameraIndexCode.value = code
setTimeout(() => {
hlsRef = new Hls({
maxBufferLength: 10, // 最大缓冲长度(秒)
maxMaxBufferLength: 15, // 缓冲区长度的上限
maxBufferSize: 30 * 1000 * 1000 // 最大缓冲大小(字节)
})
hlsRef.loadSource(url)
hlsRef.attachMedia(videoRef.value)
hlsRef.on(Hls.Events.MANIFEST_PARSED, () => {
videoRef.value.play()
})
if (type == 100) initVideo()
}, 1000)
}
const createPlayer = (cameraIndexCode,videoElement) => {
getPreviewUrlApi({
type: 'hls',
cameraIndexCode: cameraIndexCode,
subStream:1
}).then(res=>{
const url = res.data.url;
if(url.startsWith('http://192.168.77.200:8050/')){
const player = new WebRTCWhep({
url: url, // WHEP 服务器地址
container: videoElement, // 视频播放容器
iceServers: [{ urls: 'turn:192.168.77.200:3478',username: 'ZLMediaKit',credential: 'ZLMediaKit'}]
})
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)
}else{
const player = new Hls({
maxBufferLength: 10, // 最大缓冲长度(秒)
maxMaxBufferLength: 15, // 缓冲区长度的上限
maxBufferSize: 30 * 1000 * 1000 // 最大缓冲大小(字节)
})
player.loadSource(url)
player.attachMedia(videoElement)
player.on(Hls.Events.MANIFEST_PARSED, () => {
videoElement.play()
})
player.on(Hls.Events.ERROR, (event, data) => {
// 根据错误类型进行处理
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
console.log('网络错误,尝试重新加载');
player.startLoad();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.log('媒体错误,尝试修复');
player.recoverMediaError();
break;
default:
console.log('无法恢复的错误,销毁播放器');
// hls.destroy();
break;
}
}
})
hlsRefs.push(player)
}
})
} }
const initVideo = () => { // videoList.value[diyIndex.value].videos.forEach(async (it, i) => {
clearHlsRefs()
nextTick(() => {
videoList.value.forEach(async (it, i) => {
it.videos.forEach((item,index)=>{ // if(it.cameraIndexCode == cameraIndexCode.value){
setTimeout(() => { // it.isDiy = val
const video = document.getElementById(`collectmonitorVideo${item.cameraIndexCode}`) // }
createPlayer(item.cameraIndexCode,video); // })
}, 1000) }
const onStart = (res)=>{
}) }
const onEnd = (evt)=>{
const itemIndex = parseInt(evt.to.getAttribute('data-item-index')); // 当前拖拽的 item 的下标
getVideCollectCateSort({
key:videoList.value[itemIndex].key,
cameraIndexCodes:videoList.value[itemIndex].videos.map((item) => item.cameraIndexCode)
}).then((ress)=>{
}) // getVideCollectCateList()
}) })
} // postVideoRemain()
watch( initVideo()
() => videoList.value, }
(val) => { // 获取关注列表
if (val.length) { const getVideCollectCateList = async () => {
postVideoRemain() clearHlsRefs()
} params.businessVideoDisplayPosition = ''
}, let res = await getVideCollectCate(params)
{ immediate: true } videoList.value = res.data
) if(videoList.value.length<=3){
// 更新视频 grad.value = 3
const postVideoRemain = async () => { }else if(videoList.value.length<=6){
// timer = setInterval(() => { grad.value = 2
// clearInterval(timer) }else{
// videoList.value.forEach((items,index)=>{ grad.value = 1
// setTimeout(()=>{ }
// postVideoRemainApi({ postVideoRemain()
// cameraIndexCode: items.videos.map((item) => item.cameraIndexCode) // total.value = res.total
// })
// },1500)
//
// })
//
// }, 1500)
}
const getVideoRegions = async () => {
let res = await getVideoRegionsApi({
cameraName: cameraName.value,
businessScenicArea: params.businessScenicArea
})
console.log(res,11111111111111)
regionList.value = res.data
regionList.value.forEach((item,index)=>{
// item.show = true
item.videoResources=item.resourcesList[0].videoResources
})
regionList.value[0].show = true
} initVideo()
const handleRegions = (e) => { }
regionList.value[e].show = !regionList.value[e].show // 收藏
} const handleCollect = async (id, status, index,element) => {
const onInput = debounce((e) => { await getColletDiyApi({
getVideoRegions() cameraIndexCode:id,
}, 500) isDiy: status == 0 ? 1 : 0
let hotelChange = null; })
onMounted(()=>{ if (status == 0) {
getVideCollectCateList()
console.log(draggable,'draggable')
})
onUnmounted(() => {
if (timer) clearInterval(timer)
clearHlsRefs()
}) element.isDiy = 1
} else {
videoList.value[index].videos = videoList.value[index].videos.filter(item => item.cameraIndexCode !== id);
console.log('取消收藏',)
element.isDiy = 0
show.value = false
}
// pubSub.publish('videoCollect', id)
}
// 采集
const handleAction = async (e) => {
if (e == STOP) {
ACTION = '1'
command.value = e
} else {
ACTION = '0'
command.value = e
}
await postVideoControlApi({
action: ACTION,
command: command.value,
cameraIndexCode: cameraIndexCode.value
})
if (e == STOP) {
command.value = ''
}
ElMessage({
message: '操作成功',
type: 'success'
})
}
// 返回列表
const handleBack = () => {
videoLog.value = 1
hlsRef.destroy()
initVideo()
}
let isCollect = ref(0)
let isDiy = ref(0)
let videoSrc = ref('')
let diyIndex = ref(null)
const handleCamera = async (itemCode,resource,index) => {
diyIndex.value = index
show.value = true
let res = await getPreviewUrlApi({
type: 'hls',
cameraIndexCode:itemCode,
sub_stream: 0
})
cameraIndexCode.value = itemCode;
isCollect.value = resource.isCollect
isDiy.value = resource.isDiy
videoSrc.value = res.data.url
}
//清除 hls
const clearHlsRefs = () => {
if (hlsRefs.length > 0) {
hlsRefs.map((item) => {
item.destroy()
})
hlsRefs = []
}
if (webrtcRefs.length > 0) {
webrtcRefs.map((item) => {
item.close()
})
webrtcRefs = []
}
}
// 分页
const currentChange = (e) => {
clearHlsRefs()
videoList.value = []
getRegionsList()
}
let thisVideo = ref(null)
const handleItemVideo = (url, type, code,item) => {
thisVideo.value = item
videoLog.value = 2
cameraIndexCode.value = code
setTimeout(() => {
hlsRef = new Hls({
maxBufferLength: 10, // 最大缓冲长度(秒)
maxMaxBufferLength: 15, // 缓冲区长度的上限
maxBufferSize: 30 * 1000 * 1000 // 最大缓冲大小(字节)
})
hlsRef.loadSource(url)
hlsRef.attachMedia(videoRef.value)
hlsRef.on(Hls.Events.MANIFEST_PARSED, () => {
videoRef.value.play()
})
if (type == 100) initVideo()
}, 1000)
}
const createPlayer = (cameraIndexCode,videoElement) => {
getPreviewUrlApi({
type: 'hls',
cameraIndexCode: cameraIndexCode,
subStream:1
}).then(res=>{
const url = res.data.url;
if(url.startsWith('http://192.168.77.200:8050/')){
const player = new WebRTCWhep({
url: url, // WHEP 服务器地址
container: videoElement, // 视频播放容器
iceServers: [{ urls: 'turn:192.168.77.200:3478',username: 'ZLMediaKit',credential: 'ZLMediaKit'}]
})
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)
}
else{
const player = new Hls({
maxBufferLength: 10, // 最大缓冲长度(秒)
maxMaxBufferLength: 15, // 缓冲区长度的上限
maxBufferSize: 30 * 1000 * 1000 // 最大缓冲大小(字节)
})
player.loadSource(url)
player.attachMedia(videoElement)
player.on(Hls.Events.MANIFEST_PARSED, () => {
videoElement.play()
})
player.on(Hls.Events.ERROR, (event, data) => {
// 根据错误类型进行处理
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
console.log('网络错误,尝试重新加载');
player.startLoad();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.log('媒体错误,尝试修复');
player.recoverMediaError();
break;
default:
console.log('无法恢复的错误,销毁播放器');
// hls.destroy();
break;
}
}
})
hlsRefs.push(player)
}
})
}
const initVideo = () => {
clearHlsRefs()
nextTick(() => {
videoList.value.forEach(async (it, i) => {
it.videos.forEach((item,index)=>{
setTimeout(() => {
const video = document.getElementById(`collectmonitorVideo${item.cameraIndexCode}`)
createPlayer(item.cameraIndexCode,video);
}, 1000)
})
})
})
}
watch(
() => videoList.value,
(val) => {
if (val.length) {
postVideoRemain()
}
},
{ immediate: true }
)
// 更新视频
const postVideoRemain = async () => {
// timer = setInterval(() => {
// clearInterval(timer)
// videoList.value.forEach((items,index)=>{
// setTimeout(()=>{
// postVideoRemainApi({
// cameraIndexCode: items.videos.map((item) => item.cameraIndexCode)
// })
// },1500)
//
// })
//
// }, 1500)
}
const getVideoRegions = async () => {
let res = await getVideoRegionsApi({
cameraName: cameraName.value,
businessScenicArea: params.businessScenicArea
})
regionList.value = res.data
regionList.value.forEach((item,index)=>{
// item.show = true
item.videoResources=item.resourcesList[0].videoResources
})
regionList.value[0].show = true
}
const handleRegions = (e) => {
regionList.value[e].show = !regionList.value[e].show
}
const onInput = debounce((e) => {
getVideoRegions()
}, 500)
let hotelChange = null;
onMounted(()=>{
getVideCollectCateList()
console.log(draggable,'draggable')
})
onUnmounted(() => {
if (timer) clearInterval(timer)
clearHlsRefs()
})
</script> </script>
<style></style> <style></style>
<style scoped lang="scss"> <style scoped lang="scss">
@@ -418,7 +431,7 @@
border:vw(2) solid #0096FF; border:vw(2) solid #0096FF;
padding:vh(40) vw(20); padding:vh(40) vw(20);
position:relative; position:relative;
height:vh(900); height:vh(1950);
padding-bottom:vh(20); padding-bottom:vh(20);
.item-element{ .item-element{
display: flex; display: flex;
@@ -452,7 +465,7 @@
width:100%; width:100%;
height:vh(30); height:vh(30);
padding:0 vw(30); padding:0 vw(30);
font-size:vw(24); font-size: font-vw(24);
line-height:vh(30); line-height:vh(30);
// line-height: vh(40); // line-height: vh(40);
} }
@@ -469,7 +482,7 @@
.empty-box{ .empty-box{
display:flex; display:flex;
align-items: center; align-items: center;
font-size:vw(40); font-size: font-vw(40);
height:vh(750); height:vh(750);
justify-content: center; justify-content: center;
text-align:center; text-align:center;
@@ -509,7 +522,7 @@
.video-box { .video-box {
display: flex; display: flex;
flex: 1; flex: 1;
height: vh(950); // height: vh(950);
margin-top: vh(120); margin-top: vh(120);
margin-left: vw(10); margin-left: vw(10);
padding: vh(34) vw(26); padding: vh(34) vw(26);
@@ -542,7 +555,7 @@
> span { > span {
padding-left: vw(20); padding-left: vw(20);
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(20);
color: #ffffff; color: #ffffff;
line-height: vh(40); line-height: vh(40);
} }
@@ -576,7 +589,6 @@
} }
&-list { &-list {
// gap: vw(3); // gap: vw(3);
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-content: flex-start; align-content: flex-start;
@@ -595,14 +607,13 @@
// border-radius: 5px; /* 滑块的圆角 */ // border-radius: 5px; /* 滑块的圆角 */
// } // }
// overflow: auto; // overflow: auto;
} }
&-item { &-item {
position: relative; position: relative;
// width: vw(720); // width: vw(720);
// width:48%; // width:48%;
// margin-right: 1%; // margin-right: 1%;
height: vh(275); height: vh(600);
padding: vh(10) vw(10); padding: vh(10) vw(10);
box-sizing: border-box; box-sizing: border-box;
margin-bottom:vh(6); margin-bottom:vh(6);
@@ -622,11 +633,11 @@
top: vw(8); top: vw(8);
z-index: 9999; z-index: 9999;
padding: 0 vw(20); padding: 0 vw(20);
height: vh(24); height: vh(34);
text-align: center; text-align: center;
line-height: vh(24); line-height: vh(34);
font-weight: 400; font-weight: 400;
font-size: vw(16); font-size: font-vw(18);
color: #ffffff; color: #ffffff;
background-image: url('@/assets/images/unfollow.png'); background-image: url('@/assets/images/unfollow.png');
background-size: 100% 100%; background-size: 100% 100%;
@@ -644,9 +655,9 @@
left: 0; left: 0;
bottom: 0; bottom: 0;
width: 100%; width: 100%;
padding: vh(10) vw(10); padding: vh(20) vw(20);
color: #fff; color: #fff;
font-size: vw(14); font-size: vw(20);
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@@ -654,15 +665,17 @@
} }
&-item__title--error { &-item__title--error {
@extend .video-item__title; @extend .video-item__title;
font-size: font-vw(22);
background-color: rgba(226, 27, 27, 0.72); background-color: rgba(226, 27, 27, 0.72);
} }
&-item__title--primary { &-item__title--primary {
@extend .video-item__title; @extend .video-item__title;
font-size: font-vw(22);
background-color: rgba(4, 30, 69, 0.72); background-color: rgba(4, 30, 69, 0.72);
} }
&-item__video { &-item__video {
width: 100%; width: 100%;
height: vh(260); height: vh(580);
// height:100%; // height:100%;
object-fit: fill; object-fit: fill;
} }
@@ -686,7 +699,7 @@
top: 40 (vh); top: 40 (vh);
z-index: 9; z-index: 9;
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: vw(22);
color: #ffffff; color: #ffffff;
padding: vw(20); padding: vw(20);
display: flex; display: flex;
@@ -761,7 +774,7 @@
width: 100%; width: 100%;
padding: vw(10); padding: vw(10);
color: #fff; color: #fff;
font-size: vw(14); font-size: vw(20);
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@@ -773,6 +786,7 @@
} }
&-title--primary { &-title--primary {
@extend .item-title; @extend .item-title;
font-size: font-vw(20);
background-color: rgba(4, 30, 69, 0.72); background-color: rgba(4, 30, 69, 0.72);
} }
&-img { &-img {

View File

@@ -30,16 +30,17 @@
const init = () => { const init = () => {
if (!params) { if (!params) {
let center = ['25%', '50%'] let center = ['50%', '30%']
params = { params = {
color: ['#00B1FF', '#00FFFF', '#FF3737', '#DD5627', '#D3F0FE'], color: ['#00B1FF', '#00FFFF', '#FF3737', '#DD5627', '#D3F0FE'],
legend: { legend: {
orient: 'vertical', orient: 'vertical',
right: 0, // right: 0,
y: 'center', y: '54%',
bottom:20,
itemHeight: fitChartSize(8), itemHeight: fitChartSize(8),
itemWidth: fitChartSize(8), itemWidth: fitChartSize(8),
itemGap: fitChartSize(10), itemGap: fitChartSize(12),
formatter: function (name) { formatter: function (name) {
let obj = props.list.find((item) => item.name == name) let obj = props.list.find((item) => item.name == name)
return '{name|' + name + '} {value|' + obj?.value + '}{value|%}' return '{name|' + name + '} {value|' + obj?.value + '}{value|%}'
@@ -72,7 +73,7 @@
label: { label: {
show: false, show: false,
color: '#D3F0FE', color: '#D3F0FE',
fontSize: fitChartSize(12) fontSize: fitChartSize(14)
}, },
data: props.list || [] data: props.list || []
}, },
@@ -90,7 +91,7 @@
label: { label: {
show: false, show: false,
color: '#D3F0FE', color: '#D3F0FE',
fontSize: fitChartSize(12) fontSize: fitChartSize(14)
}, },
data: props.list data: props.list
}, },
@@ -136,7 +137,7 @@
<style lang="scss" scoped> <style lang="scss" scoped>
.age { .age {
width: vw(300); width: 90%;
height: vh(150); height: vh(420);
} }
</style> </style>

View File

@@ -31,13 +31,14 @@
<span v-else class="statistic-value">暂无</span> <span v-else class="statistic-value">暂无</span>
</div> </div>
</div> </div>
<div class="flex rela"> <div class=" rela">
<Title3 title="景区排队人数" /> <Title3 title="景区排队人数"/>
</div> </div>
<div class="pt-20"> <div class="pt-20">
<Line <Line
:width="370" width="95%"
:height="140" :height="120"
:config="{ legend: false }" :config="{ legend: false }"
:data="scenicQueueList" :data="scenicQueueList"
:xAxisData="scenicQueueXAxisData" :xAxisData="scenicQueueXAxisData"
@@ -59,8 +60,8 @@
<Title3 title="今日景区承载量" /> <Title3 title="今日景区承载量" />
<div class="pt-20"> <div class="pt-20">
<Line <Line
:width="370" width="95%"
:height="140" :height="120"
:config="{ legend: false }" :config="{ legend: false }"
:data="scenicBearList" :data="scenicBearList"
:xAxisData="scenicBearXAxisData" :xAxisData="scenicBearXAxisData"
@@ -119,14 +120,14 @@
</div> </div>
</div> </div>
<div class="box-1"> <div class="box-1" >
<Title3 title="客源地TOP5" /> <Title3 title="客源地TOP5" />
<RegionTop :list="homeStore.userPortraitData.provinceRate" :width="230" :height="260" /> <RegionTop :list="homeStore.userPortraitData.provinceRate" width="100%" :height="160" />
</div> </div>
<div class="box-1"> <div class="box-1">
<Title3 title="购票渠道" /> <Title3 title="购票渠道" />
<TicketSource :list="homeStore.userPortraitData.channel" :width="230" :height="260" /> <TicketSource :list="homeStore.userPortraitData.channel" width="100%" :height="160" />
</div> </div>
</div> </div>
@@ -192,16 +193,16 @@
.select-box { .select-box {
width:vw(200); width:vw(200);
height:vh(30); height:vh(30);
font-size:vw(16); font-size: font-vw(16);
} }
.box-2 { .box-2 {
margin-top: vh(120); margin-top: vh(120);
width: vw(800); width: vw(1200);
height: vh(953); // height: vh(953);
padding: vw(8); padding: vw(8);
box-sizing: border-box; box-sizing: border-box;
background-image: url('@/assets/images/bg-2.png'); // background-image: url('@/assets/images/bg-2.png');
background-size: 100% 100%; // background-size: 100% 100%;
.dropdown { .dropdown {
position: absolute; position: absolute;
right: vw(8); right: vw(8);
@@ -209,11 +210,11 @@
z-index: 990; z-index: 990;
} }
.list { .list {
height: vh(72); height: vh(104);
} }
.item { .item {
position: relative; position: relative;
height: vh(52); height: vh(104);
margin: 0 vh(10); margin: 0 vh(10);
flex: 1; flex: 1;
z-index: 1; z-index: 1;
@@ -223,35 +224,35 @@
&-icon { &-icon {
position: absolute; position: absolute;
width: 100%; width: 100%;
height: auto; // height: 100%;
z-index: -1; z-index: -1;
} }
&-label { &-label {
position: absolute; position: absolute;
left: vw(70); left: vw(120);
top: vh(-10); top: vh(-20);
font-weight: 400; font-weight: 400;
font-size: vw(16); font-size: font-vw(20);
color: #ffffff; color: #ffffff;
} }
&-value { &-value {
position: absolute; position: absolute;
left: vw(70); left: vw(120);
.countup-wrap { .countup-wrap {
color: #02f9fa; color: #02f9fa;
font-size: vw(28); font-size: font-vw(28);
font-weight: bold; font-weight: bold;
} }
} }
} }
.unit { .unit {
color: #02f9fa; color: #02f9fa;
font-size: vw(14); font-size: font-vw(14);
margin-bottom: vh(4); margin-bottom: vh(4);
} }
.box { .box {
width: vw(384); width: 50%;
height: vh(320); height: vh(795);
background-image: url('@/assets/images/bg-3.png'); background-image: url('@/assets/images/bg-3.png');
background-size: 100% 100%; background-size: 100% 100%;
&:nth-child(1) { &:nth-child(1) {
@@ -262,7 +263,7 @@
display: flex; display: flex;
margin-top: vh(12); margin-top: vh(12);
width: 100%; width: 100%;
height: vh(88); height: vh(150);
background-image: url('@/assets/images/bg-4.png'); background-image: url('@/assets/images/bg-4.png');
background-size: 100% 100%; background-size: 100% 100%;
&-item { &-item {
@@ -274,20 +275,20 @@
cursor:pointer; cursor:pointer;
} }
&-title { &-title {
font-size: vw(16); font-size: font-vw(18);
color: #fff; color: #fff;
} }
&-value { &-value {
margin-top: vh(10); margin-top: vh(10);
font-weight: bold; font-weight: bold;
font-size: vw(20); font-size: font-vw(20);
color: #02f9fa; color: #02f9fa;
display: flex; display: flex;
align-items: flex-end; align-items: flex-end;
} }
.value { .value {
font-weight: bold; font-weight: bold;
font-size: vw(28); font-size: font-vw(28);
} }
.active{ .active{
@@ -295,14 +296,14 @@
} }
.prefix, .prefix,
.suffix { .suffix {
font-size: vw(12); font-size: font-vw(12);
margin-bottom: vh(4); margin-bottom: vh(4);
} }
} }
} }
.age-box { .age-box {
width: vw(320); width: vw(400);
height: vh(303); height: vh(680);
background-image: url('@/assets/images/bg-3.png'); background-image: url('@/assets/images/bg-3.png');
background-size: 100% 100%; background-size: 100% 100%;
&:nth-child(1) { &:nth-child(1) {
@@ -310,8 +311,9 @@
} }
} }
.box-1 { .box-1 {
width: vw(230); width: vw(400);
height: vh(303); height: vh(680);
background-image: url('@/assets/images/bg-3.png'); background-image: url('@/assets/images/bg-3.png');
background-size: 100% 100%; background-size: 100% 100%;
&:nth-child(2) { &:nth-child(2) {
@@ -322,7 +324,7 @@
margin: vh(10) vw(20) 0 vw(20); margin: vh(10) vw(20) 0 vw(20);
height: vh(24); height: vh(24);
font-weight: bold; font-weight: bold;
font-size: vw(14); font-size: font-vw(14);
color: #ffffff; color: #ffffff;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -350,7 +352,7 @@
} }
.text { .text {
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(14);
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
} }
.progress { .progress {
@@ -362,21 +364,21 @@
} }
.man { .man {
font-weight: bold; font-weight: bold;
font-size: vw(14); font-size: font-vw(14);
color: #02f9fa; color: #02f9fa;
margin-left: vw(10); margin-left: vw(10);
} }
.woman { .woman {
font-weight: bold; font-weight: bold;
font-size: vw(14); font-size: font-vw(14);
color: #f15a25; color: #f15a25;
margin-left: vw(10); margin-left: vw(10);
} }
} }
.ticket-box { .ticket-box {
margin-top: vh(20); margin-top: vh(10);
width: 100%; width: 100%;
height: vh(106); height: vh(196);
background: linear-gradient(to right, rgba(0, 77, 136, 0) 0%, rgba(0, 77, 136, 0.6) 100%); background: linear-gradient(to right, rgba(0, 77, 136, 0) 0%, rgba(0, 77, 136, 0.6) 100%);
.title { .title {
width: vw(253); width: vw(253);
@@ -388,7 +390,7 @@
& > span { & > span {
padding-left: vw(22); padding-left: vw(22);
font-weight: bold; font-weight: bold;
font-size: vw(15); font-size: font-vw(15);
background-image: linear-gradient(to bottom, #ffffff 0%, #75c1ff 100%); background-image: linear-gradient(to bottom, #ffffff 0%, #75c1ff 100%);
-webkit-background-clip: text; -webkit-background-clip: text;
background-clip: text; background-clip: text;
@@ -398,12 +400,13 @@
} }
} }
.ticket-wrap { .ticket-wrap {
margin-top: vh(8); // margin-top: vh(18);
// margin-bottom: vh(18);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
& > img { & > img {
width: vw(74); width: vw(124);
height: auto; height: auto;
} }
& > div { & > div {
@@ -417,12 +420,12 @@
.label { .label {
padding-left: vw(10); padding-left: vw(10);
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(20);
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
} }
.countup-wrap { .countup-wrap {
color: #02f9fa; color: #02f9fa;
font-size: vw(28); font-size: font-vw(28);
font-weight: bold; font-weight: bold;
} }
} }

File diff suppressed because one or more lines are too long

View File

@@ -36,8 +36,8 @@
<div class="pt-10"> <div class="pt-10">
<Title3 title="拥堵路段总数" /> <Title3 title="拥堵路段总数" />
<Line <Line
:width="250" width="95%"
:height="150" :height="100"
:config="{ legend: false }" :config="{ legend: false }"
:data="congestionData" :data="congestionData"
:xAxisData="congestionXAxisData" :xAxisData="congestionXAxisData"
@@ -91,8 +91,8 @@
<Title3 title="停车场车流量" /> <Title3 title="停车场车流量" />
<div class="pt-10"> <div class="pt-10">
<Line <Line
:width="250" width="95%"
:height="150" :height="94"
:config="{ legend: false }" :config="{ legend: false }"
:data="parkData" :data="parkData"
:xAxisData="parkXAxisData" :xAxisData="parkXAxisData"
@@ -121,17 +121,17 @@
</div> </div>
</div> </div>
<div class="flex"> <div class="flex" v-if="false">
<div class="flex-1"> <!-- <div class="flex-1">
<Title1 title="车船信息" class="title1" /> <Title1 title="车船信息" class="title1" />
</div> </div> -->
<div class="flex-1"> <div class="flex-1" >
<Title1 title="酒店信息" class="title1" /> <Title1 title="酒店信息" class="title1" />
</div> </div>
</div> </div>
<div class="flex"> <div class="flex" v-if="false">
<div class="car-ship"> <div class="car-ship" v-if="false">
<div class="mb-6"> <div class="mb-6">
<div class="car"> <div class="car">
<div class="label">车总数</div> <div class="label">车总数</div>
@@ -209,7 +209,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="hotel"> <div class="hotel" >
<div> <div>
<div class="item"> <div class="item">
<div class="label">接入总数</div> <div class="label">接入总数</div>
@@ -299,45 +299,47 @@
} }
.box-3 { .box-3 {
margin-top: vh(120); margin-top: vh(120);
width: vw(774); width: vw(1200);
height: vh(956); height:100%;
// height: vh(2056);
padding-left: vw(8); padding-left: vw(8);
box-sizing: border-box; box-sizing: border-box;
background-image: url('@/assets/images/bg-5.png'); // background-image: url('@/assets/images/bg-5.png');
background-size: 100% 100%; background-size: 100% 100%;
.traffic-info { .traffic-info {
height: vh(80); // height: vh(80);
} }
.cell { .cell {
display: flex; display: flex;
align-items: center; align-items: center;
.icon { .icon {
width: vw(64); width: vw(124);
height: auto; height: auto;
} }
.countup-wrap { .countup-wrap {
color: #02f9fa; color: #02f9fa;
font-size: vw(24); font-size: font-vw(24);
font-weight: bold; font-weight: bold;
text-shadow: 0 0 9px #0096ff; text-shadow: 0 0 9px #0096ff;
} }
.label { .label {
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(18);
margin-top: vh(10); margin-top: vh(10);
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
} }
} }
.box { .box {
width: vw(250); width: 33%;
height: vh(200); // height: vh(200);
margin-right: vw(8); margin-right: vw(8);
background-image: url('@/assets/images/bg-3.png'); background-image: url('@/assets/images/bg-3.png');
background-size: 100% 100%; background-size: 100% 100%;
} }
.box-1 { .box-1 {
width: vw(250); // width: vw(300);
height: vh(200); flex:1;
height: vh(450);
margin-right: vw(8); margin-right: vw(8);
background-image: url('@/assets/images/bg-3.png'); background-image: url('@/assets/images/bg-3.png');
background-size: 100% 100%; background-size: 100% 100%;
@@ -352,7 +354,7 @@
& > div { & > div {
flex: 1; flex: 1;
height: vh(70); height: vh(120);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-evenly; justify-content: space-evenly;
@@ -360,13 +362,13 @@
background-size: 100% 100%; background-size: 100% 100%;
.label { .label {
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(16);
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
} }
.value { .value {
margin-top: vh(10); margin-top: vh(10);
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: font-vw(22);
color: #ffffff; color: #ffffff;
} }
.error { .error {
@@ -384,20 +386,22 @@
} }
} }
.car-ship { .car-ship {
flex: 1; width:100%;
// flex: 1;
& > div { & > div {
position: relative; position: relative;
height: vh(114); height: vh(235);
display: flex; display: flex;
align-items: center; align-items: center;
background-image: url('@/assets/images/bg-4.png'); background-image: url('@/assets/images/bg-4.png');
background-size: 100% 100%; background-size: cover;
.car { .car {
@extend .icon; @extend .icon;
width: vw(352); width: vw(352);
height: vw(70); height: vw(70);
padding-left: vw(90); padding-left: vw(90);
margin-left: vw(10); margin-left: vw(30);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
@@ -419,12 +423,12 @@
.label { .label {
margin-bottom: vh(6); margin-bottom: vh(6);
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(14);
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
} }
.value { .value {
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: font-vw(22);
color: #02f9fa; color: #02f9fa;
} }
.unit { .unit {
@@ -435,27 +439,31 @@
} }
.table { .table {
position: absolute; position: absolute;
left: vw(160); left: vw(200);
width: vw(226); // width: vw(350);
height: vh(96); width:80%;
// height: vh(196);
height:90%;
z-index: 2; z-index: 2;
background: rgba(0, 150, 255, 0.17); background: rgba(0, 150, 255, 0.17);
.header { .header {
display: flex; display: flex;
height: vh(18); height: vh(48);
line-height: vh(18); line-height: vh(48);
text-align: center; text-align: center;
background: rgba(0, 150, 255, 0.4); background: rgba(0, 150, 255, 0.4);
& > div { & > div {
flex: 1; flex: 1;
font-weight: 400; font-weight: 400;
font-size: vw(12); font-size: font-vw(20);
color: #fff; color: #fff;
// height: vh(50);
// line-height: vh(50);
} }
} }
.content { .content {
overflow-y: hidden; overflow-y: hidden;
height: vh(82); // height: vh(282);
// /* 滚动条整体样式 */ // /* 滚动条整体样式 */
// &::-webkit-scrollbar { // &::-webkit-scrollbar {
// width: vw(4); /* 滚动条的宽度 */ // width: vw(4); /* 滚动条的宽度 */
@@ -472,8 +480,9 @@
} }
.cell { .cell {
display: flex; display: flex;
height: vh(27); // height: vh(50);
line-height: vh(27); // line-height: vh(50);
padding:vw(10);
text-align: center; text-align: center;
background: #074686; background: #074686;
&:nth-child(odd) { &:nth-child(odd) {
@@ -486,37 +495,39 @@
flex: 1; flex: 1;
} }
& > div:nth-child(1) { & > div:nth-child(1) {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
display: block; display: block;
white-space: nowrap; white-space: nowrap;
font-weight: 400; font-weight: 400;
font-size: vw(12); font-size: font-vw(18);
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
} }
& > div:nth-child(2) { & > div:nth-child(2) {
font-weight: bold; font-weight: bold;
font-size: vw(18); font-size: font-vw(18);
color: #ffffff; color: #ffffff;
} }
& > div:nth-child(3) { & > div:nth-child(3) {
font-weight: bold; font-weight: bold;
font-size: vw(18); font-size: font-vw(18);
color: #02f9fa; color: #02f9fa;
} }
.unit-1 { .unit-1 {
font-size: vw(12); font-size: vw(18);
} }
} }
} }
} }
} }
.hotel { .hotel {
margin: 0 vw(6); flex:1;
margin: 0 vw(6);
& > div:nth-child(1) { & > div:nth-child(1) {
display: flex; display: flex;
width: vw(360); // width: vw(360);
height: vh(70); height: vh(100);
background-image: url('@/assets/images/bg-4.png'); background-image: url('@/assets/images/bg-4.png');
background-size: 100% 100%; background-size: 100% 100%;
.item { .item {
@@ -527,13 +538,13 @@
justify-content: center; justify-content: center;
.label { .label {
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(18);
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
} }
.value { .value {
margin-top: vh(10); margin-top: vh(10);
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: font-vw(20);
color: #ffffff; color: #ffffff;
} }
.success { .success {
@@ -551,7 +562,7 @@
& > div:nth-child(2) { & > div:nth-child(2) {
padding-top: vh(6); padding-top: vh(6);
margin-top: vh(6); margin-top: vh(6);
width: vw(360); // width: vw(360);
background-image: url('@/assets/images/bg-3.png'); background-image: url('@/assets/images/bg-3.png');
background-size: 100% 100%; background-size: 100% 100%;
} }
@@ -564,7 +575,7 @@
} }
.title1 { .title1 {
:deep(.title) { :deep(.title) {
width: vw(300) !important; // width: vw(300) !important;
} }
} }
</style> </style>

View File

@@ -128,7 +128,7 @@
<style lang="scss" scoped> <style lang="scss" scoped>
.gauge { .gauge {
width: vw(120); width: vw(200);
height: vh(50); height: vh(80);
} }
</style> </style>

View File

@@ -70,14 +70,14 @@
grid: { grid: {
left: '4%', left: '4%',
right: '4%', right: '4%',
top: '4%', top: '0',
bottom: '4%', bottom: '4%',
containLabel: true containLabel: true
}, },
legend: { legend: {
orient: 'horizontal', orient: 'horizontal',
x: 'center', x: 'center',
bottom: '-3%', bottom: '5px',
itemHeight: fitChartSize(12), itemHeight: fitChartSize(12),
itemWidth: fitChartSize(12), itemWidth: fitChartSize(12),
itemGap: fitChartSize(6), itemGap: fitChartSize(6),
@@ -90,11 +90,11 @@
rich: { rich: {
name: { name: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(12) fontSize: fitChartSize(16)
}, },
value: { value: {
color: '#00D5F6', color: '#00D5F6',
fontSize: fitChartSize(12) fontSize: fitChartSize(16)
} }
} }
} }
@@ -102,7 +102,7 @@
series: [ series: [
{ {
type: 'pie', type: 'pie',
center: ['50%', '40%'], center: ['50%', '32%'],
radius: ['45%', '60%'], radius: ['45%', '60%'],
itemStyle: { itemStyle: {
borderWidth: fitChartSize(4), borderWidth: fitChartSize(4),
@@ -138,23 +138,7 @@
} else { } else {
params.series[0].data = getSeriesData() params.series[0].data = getSeriesData()
} }
const chart = setOption(params) setOption(params)
chart.on('legendselectchanged', function (e) {
var echartsArr = [];
for (let key in e.selected) {
if (e.selected[key]) {
echartsArr.push(key)
}
}
var echartsNum = 0;
props.list.forEach(item => {
if(echartsArr.includes(item.name)){
echartsNum += parseInt(item.count)
}
})
params.series[0].label.formatter = `{label|拥堵次数}` + '\n' + `{value|${echartsNum}}`;
setOption(params);
});
} }
onMounted(() => {}) onMounted(() => {})
@@ -167,7 +151,7 @@
top:0; top:0;
width: 100%; width: 100%;
height: 100%; height: 100%;
font-size:vw(18); font-size:vw(20);
// color:#999; // color:#999;
color:#02f9fa; color:#02f9fa;
display: flex; display: flex;
@@ -175,7 +159,7 @@
justify-content: center; justify-content: center;
} }
.jam-count { .jam-count {
width: vw(250); width: vw(350);
height: vh(150); height: vh(400);
} }
</style> </style>

View File

@@ -140,7 +140,7 @@
show: true, show: true,
axisLabel: { axisLabel: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(12), fontSize: fitChartSize(18),
verticalAlign: 'bottom', verticalAlign: 'bottom',
padding: [0, 0, 6, 0], padding: [0, 0, 6, 0],
inside: true, inside: true,
@@ -152,7 +152,7 @@
align: 'center', align: 'center',
color: '#fff', color: '#fff',
fontWeight: 600, fontWeight: 600,
fontSize: fitChartSize(14) fontSize: fitChartSize(18)
} }
} }
}, },
@@ -176,7 +176,7 @@
fontWeight: 500, fontWeight: 500,
position: 'left', position: 'left',
align: 'left', align: 'left',
fontSize: fitChartSize(14), fontSize: fitChartSize(18),
formatter: function (params) { formatter: function (params) {
return params.data.name return params.data.name
} }
@@ -213,7 +213,7 @@
top:0; top:0;
width: 100%; width: 100%;
height: 100%; height: 100%;
font-size:vw(18); font-size:vw(20);
// color:#999; // color:#999;
color:#02f9fa; color:#02f9fa;
display: flex; display: flex;
@@ -221,7 +221,7 @@
justify-content: center; justify-content: center;
} }
.jam { .jam {
width: vw(250); width: vw(290);
height: vh(160); height: vh(400);
} }
</style> </style>

View File

@@ -1,6 +1,6 @@
<template> <template>
<!-- 酒店入住人数及入住率 --> <!-- 酒店入住人数及入住率 -->
<div class="occupancy" :id="id" /> <div class="occupancyNew" :id="id" />
</template> </template>
<script setup> <script setup>
@@ -19,10 +19,11 @@
watch( watch(
() => props.list, () => props.list,
(val) => { (val) => {
if (val.length > 0) { if (val.length > 0) {
setTimeout(() => { setTimeout(() => {
init() init()
}, 1000) }, 1500)
} }
}, },
{ immediate: true } { immediate: true }
@@ -123,7 +124,7 @@
show: true, show: true,
axisLabel: { axisLabel: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(12), fontSize: fitChartSize(18),
verticalAlign: 'bottom', verticalAlign: 'bottom',
padding: [0, 0, 10, 0], padding: [0, 0, 10, 0],
inside: true, inside: true,
@@ -135,7 +136,7 @@
align: 'center', align: 'center',
color: '#fff', color: '#fff',
fontWeight: 600, fontWeight: 600,
fontSize: fitChartSize(14) fontSize: fitChartSize(20)
} }
} }
}, },
@@ -159,7 +160,7 @@
fontWeight: 500, fontWeight: 500,
position: 'left', position: 'left',
align: 'left', align: 'left',
fontSize: fitChartSize(14), fontSize: fitChartSize(20),
formatter: function (params) { formatter: function (params) {
return params.data.name return params.data.name
} }
@@ -190,8 +191,8 @@
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.occupancy { .occupancyNew {
width: vw(360); width: 100%;
height: vh(130); height: vh(360);
} }
</style> </style>

View File

@@ -128,7 +128,7 @@
show: true, show: true,
axisLabel: { axisLabel: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(12), fontSize: fitChartSize(16),
verticalAlign: 'bottom', verticalAlign: 'bottom',
padding: [0, 0, 6, 0], padding: [0, 0, 6, 0],
inside: true, inside: true,
@@ -141,13 +141,13 @@
align: 'center', align: 'center',
color: '#fff', color: '#fff',
fontWeight: 600, fontWeight: 600,
fontSize: fitChartSize(14) fontSize: fitChartSize(16)
}, },
total: { total: {
align: 'center', align: 'center',
color: '#fff', color: '#fff',
fontWeight: 600, fontWeight: 600,
fontSize: fitChartSize(14) fontSize: fitChartSize(16)
}, },
} }
}, },
@@ -172,7 +172,7 @@
fontWeight: 500, fontWeight: 500,
position: 'left', position: 'left',
align: 'left', align: 'left',
fontSize: fitChartSize(14), fontSize: fitChartSize(16),
formatter: function (params) { formatter: function (params) {
return params.data.name return params.data.name
} }
@@ -206,7 +206,7 @@
<style scoped lang="scss"> <style scoped lang="scss">
.vacancy { .vacancy {
width: vw(250); width: vw(400);
height: vh(160); height: vh(400);
} }
</style> </style>

View File

@@ -60,14 +60,14 @@
} }
}, },
axisLabel: { axisLabel: {
fontSize: fitChartSize(12), fontSize: fitChartSize(18),
color: 'rgba(255,255,255,0.9)' color: 'rgba(255,255,255,0.9)'
} }
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
axisLabel: { axisLabel: {
fontSize: fitChartSize(12), fontSize: fitChartSize(18),
color: 'rgba(255,255,255,0.9)' color: 'rgba(255,255,255,0.9)'
}, },
splitLine: { splitLine: {
@@ -88,7 +88,7 @@
show: true, show: true,
position: 'top', position: 'top',
color: '#fff', color: '#fff',
fontSize: fitChartSize(10) fontSize: fitChartSize(14)
}, },
itemStyle: { itemStyle: {
borderRadius: [0, 0, 0, 0], borderRadius: [0, 0, 0, 0],
@@ -125,6 +125,6 @@
<style scoped lang="scss"> <style scoped lang="scss">
.vehicle-source { .vehicle-source {
width: 100%; width: 100%;
height: vh(160); height: vh(400);
} }
</style> </style>

View File

@@ -119,11 +119,11 @@
.info { .info {
margin-top: vh(120); margin-top: vh(120);
width: vw(626); width: vw(626);
height: vh(950); // height: vh(950);
background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%); background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%);
&-header { &-header {
padding: vh(12) vw(12); padding: vh(12) vw(12);
height: vh(167); min-height: vh(330);
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
@@ -137,7 +137,7 @@
margin-left: vw(20); margin-left: vw(20);
> h2 { > h2 {
font-weight: 800; font-weight: 800;
font-size: vw(20); font-size: font-vw(24);
color: #ffffff; color: #ffffff;
margin-bottom: vh(12); margin-bottom: vh(12);
margin-top: vh(10); margin-top: vh(10);
@@ -155,36 +155,40 @@
} }
&__text { &__text {
font-weight: 400; font-weight: 400;
font-size: vw(16); font-size: font-vw(20);
color: #0096ff; color: #0096ff;
line-height: 2;
} }
} }
.statistic { .statistic {
// margin:vh(10);
&-box { &-box {
height: vh(94); height: vh(230);
margin: 0 vw(26); margin: 0 vw(26);
gap: vw(20); // gap: vw(20);
display: flex; display: flex;
align-items: center; align-items: center;
margin-top:vh(10); margin-top:vh(20);
flex-wrap: wrap;
} }
&-item { &-item {
flex: 1; // flex: 1;
width:32%;
} }
&-item__label { &-item__label {
margin-bottom: vh(16); margin-bottom: vh(26);
display: flex; display: flex;
align-items: center; align-items: center;
> span { > span {
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(16);
color: #ffffff; color: #ffffff;
margin-left: vw(4); margin-left: vw(4);
} }
} }
&-item__value { &-item__value {
width: vw(100); width: vw(200);
height: vh(30); height: vh(60);
padding-left: vw(12); padding-left: vw(12);
padding-bottom: vh(12); padding-bottom: vh(12);
display: flex; display: flex;
@@ -193,11 +197,11 @@
background-size: 100% 100%; background-size: 100% 100%;
.countup-wrap { .countup-wrap {
font-weight: bold; font-weight: bold;
font-size: vw(28); font-size: font-vw(42);
color: #02f9fa; color: #02f9fa;
} }
> span { > span {
font-size: vw(12); font-size: font-vw(24);
color: #02f9fa; color: #02f9fa;
margin-left: vw(4); margin-left: vw(4);
} }
@@ -219,11 +223,11 @@
margin: vh(20) 0 0 vw(20); margin: vh(20) 0 0 vw(20);
padding-right: vw(20); padding-right: vw(20);
overflow-y: auto; overflow-y: auto;
height: vh(200); height: vh(830);
font-weight: 400; font-weight: 400;
font-size: vw(16); font-size: font-vw(22);
color: #ffffff; color: #ffffff;
line-height: vw(26); line-height: 2;
text-align: justify; text-align: justify;
/* 滚动条整体样式 */ /* 滚动条整体样式 */
&::-webkit-scrollbar { &::-webkit-scrollbar {

File diff suppressed because it is too large Load Diff

View File

@@ -19,7 +19,7 @@
}, },
total: { total: {
type: Number, type: Number,
default: () => 0 default: () => 123456
}, },
colors: { colors: {
type: Array, type: Array,
@@ -37,29 +37,22 @@
orient: 'vertical', orient: 'vertical',
y: 'center', y: 'center',
left: '50%', left: '50%',
itemWidth: fitChartSize(12), itemWidth: fitChartSize(18),
itemHeight: fitChartSize(12), itemHeight: fitChartSize(18),
itemGap: fitChartSize(6), itemGap: fitChartSize(6),
formatter: (name) => { formatter: (name) => {
let obj = props.dataList.find((item) => item.name == name) let obj = props.dataList.find((item) => item.name == name)
let total = getTotal(); return `{name|${name}} {value|${obj?.value}}{value|%}`
if(total==0){
return `{name|${name}} {value|0}{value|%}`
}else{
let value = ((obj?.value/total).toFixed(4)*100).toFixed(2);
return `{name|${name}} {value|${value}}{value|%}`
}
}, },
textStyle: { textStyle: {
rich: { rich: {
name: { name: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(12) fontSize: fitChartSize(20)
}, },
value: { value: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(12) fontSize: fitChartSize(20)
} }
} }
} }
@@ -80,13 +73,13 @@
rich: { rich: {
value: { value: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(16), fontSize: fitChartSize(20),
fontWeight: 'bold', fontWeight: 'bold',
padding: [0, 0, 5, 0] padding: [0, 0, 5, 0]
}, },
name: { name: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(12) fontSize: fitChartSize(22)
} }
} }
}, },
@@ -133,32 +126,13 @@
return `{value|${getTotal()}}` + '\n' + `{name|告警总数}` return `{value|${getTotal()}}` + '\n' + `{name|告警总数}`
} }
} }
const changeChart = setOption(params) setOption(params)
changeChart.off('legendselectchanged');
changeChart.on('legendselectchanged', function (e) {
var echartsArr = [];
for (let key in e.selected) {
if (e.selected[key]) {
echartsArr.push(key)
}
}
var echartsNum = 0;
props.dataList.forEach(item => {
if(echartsArr.includes(item.name)){
echartsNum += parseFloat(item.value)
}
})
params.series[0].label.formatter = () => {
return `{value|${echartsNum}}` + '\n' + `{name|告警总数}`
}
setOption(params)
});
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.alarmRate { .alarmRate {
width: vw(380); width: 100%;
height: vh(180); height: vh(400);
} }
</style> </style>

View File

@@ -17,7 +17,7 @@
:end-val="aiAnalyzeData.allAnalysisPoints" :end-val="aiAnalyzeData.allAnalysisPoints"
/> />
</div> </div>
<div class="traffic-item" @click="showAbnormalList('curr')"> <div class="traffic-item" @click="showAbnormalList">
<span class="traffic-item__title">异常点位</span> <span class="traffic-item__title">异常点位</span>
<countup :class="aiAnalyzeData.abnormalPoints>0?'traffic-item__value--error':'traffic-item__value--success'" :end-val="aiAnalyzeData.abnormalPoints" /> <countup :class="aiAnalyzeData.abnormalPoints>0?'traffic-item__value--error':'traffic-item__value--success'" :end-val="aiAnalyzeData.abnormalPoints" />
</div> </div>
@@ -28,30 +28,30 @@
<span class="scenic-item__label">核心景区分析点位</span> <span class="scenic-item__label">核心景区分析点位</span>
<countup class="scenic-item__value" :end-val="scenicAiAnalyzeData.coreMonitoringPoints" /> <countup class="scenic-item__value" :end-val="scenicAiAnalyzeData.coreMonitoringPoints" />
</div> </div>
<div class="scenic-item" @click="showAbnormalList('curr')" style="cursor: pointer;" > <div class="scenic-item" @click="showAbnormalList" style="cursor: pointer;" >
<span class="scenic-item__label">异常点位</span> <span class="scenic-item__label">异常点位</span>
<countup class="scenic-item__value" :end-val="scenicAiAnalyzeData.abnormalPoints" /> <countup class="scenic-item__value" :end-val="scenicAiAnalyzeData.abnormalPoints" />
</div> </div>
<div class="scenic-item" @click="showAbnormalList('curr')" style="cursor: pointer;" > <div class="scenic-item" @click="showAbnormalList" style="cursor: pointer;" >
<span class="scenic-item__label">异常告警</span> <span class="scenic-item__label">异常告警</span>
<countup class="scenic-item__value" :end-val="scenicAiAnalyzeData.abnormalAlarm" /> <countup class="scenic-item__value" :end-val="scenicAiAnalyzeData.abnormalAlarm" />
</div> </div>
<div class="scenic-item" @click="showAbnormalList('deal')" style="cursor: pointer;"> <div class="scenic-item">
<span class="scenic-item__label">已解除</span> <span class="scenic-item__label">已解除</span>
<countup class="scenic-item__value" :end-val="scenicAiAnalyzeData.handled" /> <countup class="scenic-item__value" :end-val="scenicAiAnalyzeData.handled" />
</div> </div>
</div> </div>
<div class="flex pt-20 gap8"> <div class=" pt-20 gap8" style="margin-top:20px;">
<div class="box"> <div class="box ">
<Title3 title="异常告警" /> <Title3 title="异常告警" />
<Line <Line
:width="370" width="100%"
:height="180" :height="90"
:data="abnormalAlarm" :data="abnormalAlarm"
:xAxisData="abnormalAlarmXAxisData" :xAxisData="abnormalAlarmXAxisData"
/> />
</div> </div>
<div class="box"> <div class="box other-box" style="margin-top:20px;">
<Title3 title="异常告警占比" /> <Title3 title="异常告警占比" />
<div class="flex"> <div class="flex">
<alarmRate :dataList="abnormalData.abnormalAlarmPercent" /> <alarmRate :dataList="abnormalData.abnormalAlarmPercent" />
@@ -67,15 +67,15 @@
:end-val="trafficAiAnalyzeData.coreMonitoringPoints" :end-val="trafficAiAnalyzeData.coreMonitoringPoints"
/> />
</div> </div>
<div class="scenic-item" style="cursor: pointer" @click="showTrafficEvent('curr')"> <div class="scenic-item" style="cursor: pointer" @click="showTrafficEvent">
<span class="scenic-item__label">拥堵点位</span> <span class="scenic-item__label">拥堵点位</span>
<countup class="scenic-item__value" :end-val="trafficAiAnalyzeData.abnormalPoints" /> <countup class="scenic-item__value" :end-val="trafficAiAnalyzeData.abnormalPoints" />
</div> </div>
<div class="scenic-item" style="cursor: pointer" @click="showTrafficEvent('curr')"> <div class="scenic-item" style="cursor: pointer" @click="showTrafficEvent">
<span class="scenic-item__label">拥堵告警</span> <span class="scenic-item__label">拥堵告警</span>
<countup class="scenic-item__value" :end-val="trafficAiAnalyzeData.abnormalWarnings" /> <countup class="scenic-item__value" :end-val="trafficAiAnalyzeData.abnormalWarnings" />
</div> </div>
<div class="scenic-item" style="cursor: pointer" @click="showTrafficEvent('deal')"> <div class="scenic-item">
<span class="scenic-item__label">已解除</span> <span class="scenic-item__label">已解除</span>
<countup class="scenic-item__value" :end-val="trafficAiAnalyzeData.handled" /> <countup class="scenic-item__value" :end-val="trafficAiAnalyzeData.handled" />
</div> </div>
@@ -83,9 +83,9 @@
<div class="flex pt-20"> <div class="flex pt-20">
<div class="box"> <div class="box">
<Title3 title="平均车速(KM/H)" /> <Title3 title="平均车速(KM/H)" />
<traffic-jam :width="760" <traffic-jam width="100%"
:series="jamlData[0].data" :series="jamlData[0].data"
:data="jamXAxisData" :height="180" /> :data="jamXAxisData" height="350" />
</div> </div>
</div> </div>
</template> </template>
@@ -109,7 +109,7 @@
<iframe v-if="scenicSpotId == 'root00000000'" width="100%" height="100%" src="http://192.168.77.200/map/sxzd/sxzd.html"></iframe> <iframe v-if="scenicSpotId == 'root00000000'" width="100%" height="100%" src="http://192.168.77.200/map/sxzd/sxzd.html"></iframe>
<iframe v-if="scenicSpotId == '龙桥河'" width="100%" height="100%" src="http://192.168.77.200/map/lqh/lqh.html"></iframe> <iframe v-if="scenicSpotId == '龙桥河'" width="100%" height="100%" src="http://192.168.77.200/map/lqh/lqh.html"></iframe>
</div> </div>
<div class="flex"> <div class="">
<div class="monitor"> <div class="monitor">
<div class="t-title"> <div class="t-title">
<span>监控点位统计</span> <span>监控点位统计</span>
@@ -130,7 +130,7 @@
:end-val="pointAlarmData.analysisPoints" :end-val="pointAlarmData.analysisPoints"
/> />
</div> </div>
<div class="monitor-statistics-item" @click="showAbnormalList('curr')" style="cursor: pointer;" > <div class="monitor-statistics-item" @click="showAbnormalList" style="cursor: pointer;" >
<span class="monitor-statistics-item__label">异常点位</span> <span class="monitor-statistics-item__label">异常点位</span>
<countup <countup
class="monitor-statistics-item__value" class="monitor-statistics-item__value"
@@ -140,10 +140,10 @@
</div> </div>
</div> </div>
<div class="bg" style="cursor: pointer;" > <div class="bg" style="cursor: pointer;" >
<Title3 title="今日异常告警" @click="showAbnormalList('all')" /> <Title3 title="今日异常告警" @click="showAbnormalList" />
<Line <Line
:width="370" width="100%"
:height="180" :height="70"
:data="abnormalAlarm" :data="abnormalAlarm"
:xAxisData="abnormalAlarmXAxisData" :xAxisData="abnormalAlarmXAxisData"
/> />
@@ -155,20 +155,20 @@
</div> </div>
<div class="traffic-alarm-statistics"> <div class="traffic-alarm-statistics">
<img class="traffic-alarm-statistics-icon" src="@/assets/images/t-ico-2.png" /> <img class="traffic-alarm-statistics-icon" src="@/assets/images/t-ico-2.png" />
<div class="traffic-alarm-statistics-item" @click="showAbnormalList('curr')" style="cursor: pointer;"> <div class="traffic-alarm-statistics-item" @click="showAbnormalList" style="cursor: pointer;">
<span class="traffic-alarm-statistics-item__label">当前告警</span> <span class="traffic-alarm-statistics-item__label">当前告警</span>
<countup <countup
:class="pointAlarmData.abnormalAlarm>0?'traffic-alarm-statistics-item__error':'traffic-alarm-statistics-item__value'" :class="pointAlarmData.abnormalAlarm>0?'traffic-alarm-statistics-item__error':'traffic-alarm-statistics-item__value'"
:end-val="pointAlarmData.abnormalAlarm" :end-val="pointAlarmData.abnormalAlarm"
/> />
</div> </div>
<div class="traffic-alarm-statistics-item" @click="showAbnormalList('all')" style="cursor: pointer;"> <div class="traffic-alarm-statistics-item">
<span class="traffic-alarm-statistics-item__label">异常告警</span> <span class="traffic-alarm-statistics-item__label">异常告警</span>
<countup class="traffic-alarm-statistics-item__value" <countup class="traffic-alarm-statistics-item__value"
:end-val="pointAlarmData.allAbnormalAlarm" :end-val="pointAlarmData.allAbnormalAlarm"
/> />
</div> </div>
<div class="traffic-alarm-statistics-item" @click="showAbnormalList('deal')" style="cursor: pointer;"> <div class="traffic-alarm-statistics-item">
<span class="traffic-alarm-statistics-item__label">已解除告警</span> <span class="traffic-alarm-statistics-item__label">已解除告警</span>
<countup <countup
class="traffic-alarm-statistics-item__value traffic-alarm-statistics-item__value" class="traffic-alarm-statistics-item__value traffic-alarm-statistics-item__value"
@@ -180,7 +180,6 @@
<Title3 title="异常告警占比" /> <Title3 title="异常告警占比" />
<div class="flex"> <div class="flex">
<alarmRate :dataList="abnormalData.abnormalAlarmPercent" /> <alarmRate :dataList="abnormalData.abnormalAlarmPercent" />
</div> </div>
</div> </div>
</div> </div>
@@ -188,8 +187,8 @@
</template> </template>
</div> </div>
<video-dialog v-model="videoShow" :src="src" :cameraIndexCode="cameraIndexCode" /> <video-dialog v-model="videoShow" :src="src" :cameraIndexCode="cameraIndexCode" />
<warn-list v-model="warnShow" :type="warnType" :scenicSpotId="scenicSpotId" /> <warn-list v-model="warnShow" :scenicSpotId="scenicSpotId" />
<traffic-list v-model="trafficEventShow" :type="trafficEventType" /> <traffic-list v-model="trafficEventShow" />
</template> </template>
<script setup> <script setup>
@@ -247,29 +246,24 @@
let cameraIndexCode = ref('') let cameraIndexCode = ref('')
let videoShow = ref(false) let videoShow = ref(false)
let warnShow = ref(false) let warnShow = ref(false)
let warnType = ref('')
let trafficEventShow = ref(false) let trafficEventShow = ref(false)
let trafficEventType = ref('curr') const showAbnormalList = function (){
const showAbnormalList = function (type){
warnType.value = type;
warnShow.value = true; warnShow.value = true;
} }
const showTrafficEvent = function(type){ const showTrafficEvent = function(){
trafficEventType.value = type;
trafficEventShow.value = true; trafficEventShow.value = true;
} }
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 // cameraIndexCode.value = e.data.cameraIndexCode
cameraIndexCode.value = e.data.cameraIndexCode // videoShow.value = true
videoShow.value = true // }
} // });
});
// 异常告警 // 异常告警
let abnormalAlarm = computed(() => { let abnormalAlarm = computed(() => {
return [{ data: abnormalData.value.abnormalAlarm.map((item) => item.value) }] return [{ data: abnormalData.value.abnormalAlarm.map((item) => item.value) }]
@@ -352,7 +346,7 @@
.none { .none {
width: vw(380); width: vw(380);
height: vh(200); height: vh(200);
font-size: vw(28); font-size: font-vw(28);
color: #f2f2f2; color: #f2f2f2;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -360,7 +354,7 @@
} }
.detection-top { .detection-top {
width: 100%; width: 100%;
height: vh(560); height: vh(860);
overflow-x: auto; overflow-x: auto;
overflow-y: hidden; overflow-y: hidden;
display: flex; display: flex;
@@ -386,10 +380,10 @@
} }
} }
.monitor { .monitor {
width: vw(405); // width: vw(405);
margin-right: vw(8); margin-right: vw(8);
&-statistics { &-statistics {
height: vh(90); height: vh(110);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-evenly; justify-content: space-evenly;
@@ -403,13 +397,13 @@
&-statistics-item { &-statistics-item {
&__label { &__label {
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(20);
color: #fff; color: #fff;
} }
&__value { &__value {
margin-top: vh(10); margin-top: vh(10);
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: font-vw(24);
color: #ffffff; color: #ffffff;
} }
&:nth-child(4) { &:nth-child(4) {
@@ -423,9 +417,9 @@
} }
} }
.traffic-alarm { .traffic-alarm {
width: vw(405); // width: vw(405);
&-statistics { &-statistics {
height: vh(90); height: vh(110);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-evenly; justify-content: space-evenly;
@@ -439,20 +433,20 @@
&-statistics-item { &-statistics-item {
&__label { &__label {
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(20);
color: #fff; color: #fff;
} }
&__value { &__value {
margin-top: vh(10); margin-top: vh(10);
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: font-vw(24);
color: #02f9fa; color: #02f9fa;
text-align: center; text-align: center;
} }
&__error { &__error {
margin-top: vh(10); margin-top: vh(10);
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: font-vw(24);
color: #ff4400; color: #ff4400;
text-align: center; text-align: center;
} }
@@ -473,11 +467,11 @@
} }
} }
.t-title { .t-title {
margin: vh(10) auto; margin: vh(25) auto;
width: 100%; width: 100%;
height: vh(32); height: vh(50);
font-weight: 800; font-weight: 800;
font-size: vw(16); font-size: font-vw(22);
color: #fff; color: #fff;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -491,31 +485,31 @@
box-shadow: none; box-shadow: none;
border-top-left-radius: vh(30); border-top-left-radius: vh(30);
border-bottom-left-radius: vh(30); border-bottom-left-radius: vh(30);
font-size: vw(14); font-size: font-vw(14);
color: #fff; color: #fff;
} }
.box-1 { .box-1 {
margin-top: vh(120); margin-top: vh(120);
width: vw(800); width: vw(1100);
height: vh(950); // height: vh(950);
padding: vw(8); padding: vw(8);
box-sizing: border-box; box-sizing: border-box;
background-image: url('@/assets/images/bg-2.png'); background-image: url('@/assets/images/bg-2.png');
background-size: 100% 100%; background-size: 100% 100%;
.traffic { .traffic {
margin-top: vh(20); margin-top: vh(20);
height: vh(72); height: vh(142);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-evenly; justify-content: space-evenly;
&-item { &-item {
width: vw(229); width: vw(339);
height: vw(72); height: vw(102);
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(14);
color: #fff; color: #fff;
padding-left: vw(84); padding-left: vw(150);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
@@ -536,22 +530,22 @@
&-item__title { &-item__title {
margin-bottom: vh(6); margin-bottom: vh(6);
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(18);
color: #ffffff; color: #ffffff;
} }
&-item__value--primary { &-item__value--primary {
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: font-vw(24);
color: #12b5fd; color: #12b5fd;
} }
&-item__value--success { &-item__value--success {
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: font-vw(24);
color: #02f9fa; color: #02f9fa;
} }
&-item__value--error { &-item__value--error {
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: font-vw(24);
color: #f15a25; color: #f15a25;
} }
} }
@@ -562,13 +556,14 @@
gap: vw(20); gap: vw(20);
&-item { &-item {
width: vw(182); // width: vw(182);
height: vw(106); flex:1;
height: vw(156);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
margin:vh(20) 0;
&:nth-child(1) { &:nth-child(1) {
background-image: url('/src/assets/images/four-t-1.png'); background-image: url('/src/assets/images/four-t-1.png');
background-size: 100% 100%; background-size: 100% 100%;
@@ -609,28 +604,30 @@
} }
&-item__label { &-item__label {
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(20);
color: #fff; color: #fff;
} }
&-item__value { &-item__value {
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: font-vw(24);
margin-top: vh(10); margin-top: vh(10);
} }
} }
.unit { .unit {
color: #02f9fa; color: #02f9fa;
font-size: vw(14); font-size: font-vw(14);
margin-bottom: vh(4); margin-bottom: vh(4);
} }
.other-box{
height: vh(350) !important;
}
.box { .box {
flex: 1; flex: 1;
height: vh(220); height: vh(400);
background-image: url('@/assets/images/bg-3.png'); background-image: url('@/assets/images/bg-3.png');
background-size: 100% 100%; background-size: 100% 100%;
// .title-2 { // .title-2 {
// width: vw(253); // width: vw(253);
// height: vh(28); // height: vh(28);
@@ -641,7 +638,7 @@
// & > span { // & > span {
// padding-left: vw(22); // padding-left: vw(22);
// font-weight: bold; // font-weight: bold;
// font-size: vw(15); // font-size: font-vw(15);
// background-image: linear-gradient(to bottom, #ffffff 0%, #75c1ff 100%); // background-image: linear-gradient(to bottom, #ffffff 0%, #75c1ff 100%);
// -webkit-background-clip: text; // -webkit-background-clip: text;
// background-clip: text; // background-clip: text;
@@ -664,36 +661,36 @@
justify-content: center; justify-content: center;
} }
&-title { &-title {
font-size: vw(14); font-size: font-vw(14);
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
} }
&-value { &-value {
margin-top: vh(10); margin-top: vh(10);
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: font-vw(24);
color: #02f9fa; color: #02f9fa;
} }
&-error{ &-error{
margin-top: vh(10); margin-top: vh(10);
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: font-vw(24);
color: #ff4400; color: #ff4400;
} }
.count { .count {
font-weight: bold; font-weight: bold;
font-size: vw(28); font-size: font-vw(28);
color: #ff4400 !important; color: #ff4400 !important;
} }
.prefix, .prefix,
.suffix { .suffix {
color: #ff4400; color: #ff4400;
font-size: vw(12); font-size: font-vw(12);
} }
} }
.title-3 { .title-3 {
position: relative; position: relative;
width: vw(344); width: vw(344);
height: vh(12); height: vh(16);
margin-top: vh(20); margin-top: vh(20);
background-image: url('@/assets/images/title-6.png'); background-image: url('@/assets/images/title-6.png');
background-size: 100% 100%; background-size: 100% 100%;
@@ -702,7 +699,7 @@
position: absolute; position: absolute;
bottom: vh(4); bottom: vh(4);
left: vw(20); left: vw(20);
font-size: vw(15); font-size: font-vw(18);
font-weight: bold; font-weight: bold;
background-image: linear-gradient(to bottom, #ffffff 0%, #0096ff 100%); background-image: linear-gradient(to bottom, #ffffff 0%, #0096ff 100%);
-webkit-background-clip: text; -webkit-background-clip: text;

File diff suppressed because it is too large Load Diff

View File

@@ -46,7 +46,7 @@
left: '4%', left: '4%',
right: '8%', right: '8%',
top: '10%', top: '10%',
bottom: '14%', bottom: '2%',
containLabel: true containLabel: true
}, },
xAxis: { xAxis: {
@@ -61,7 +61,7 @@
} }
}, },
axisLabel: { axisLabel: {
fontSize: fitChartSize(12), fontSize: fitChartSize(16),
color: 'rgba(255,255,255,0.9)' color: 'rgba(255,255,255,0.9)'
}, },
data: getXAxisData() data: getXAxisData()
@@ -72,15 +72,14 @@
show: true, // 显示dataZoom组件 show: true, // 显示dataZoom组件
xAxisIndex: [0], // 控制第一个x轴 xAxisIndex: [0], // 控制第一个x轴
start: 0, // 初始起始位置 start: 0, // 初始起始位置
end: 60 // 初始结束位置,可以根据数据量调整 end: 50 // 初始结束位置,可以根据数据量调整
} }
], ],
yAxis: { yAxis: {
type: 'value', type: 'value',
offset: 15,
axisLabel: { axisLabel: {
show: true, show: true,
fontSize: fitChartSize(12), fontSize: fitChartSize(18),
color: 'rgba(255,255,255,0.9)' color: 'rgba(255,255,255,0.9)'
}, },
splitLine: { splitLine: {
@@ -95,12 +94,12 @@
{ {
type: 'bar', type: 'bar',
data: getSeriesData(), data: getSeriesData(),
barWidth: fitChartSize(20), barWidth: fitChartSize(32),
label: { label: {
show: true, show: true,
position: 'top', position: 'top',
color: '#fff', color: '#fff',
fontSize: fitChartSize(12), fontSize: fitChartSize(20),
formatter: (res) => { formatter: (res) => {
let valueMap = { let valueMap = {
1: '畅通', 1: '畅通',
@@ -140,7 +139,8 @@
<style scoped lang="scss"> <style scoped lang="scss">
.traffic-jam { .traffic-jam {
width: vw(760); margin-top: vh(10);
height: vh(180); width:100%;
height: 100%;
} }
</style> </style>

View File

@@ -1,9 +1,9 @@
<template> <template>
<div class="z-dialog"> <div class="z-dialog">
<el-dialog :title="props.type=='deal'?'已解除告警':'核心路段拥堵告警'" v-model="modelValue" align-center :modal="false" :show-close="false"> <el-dialog title="核心路段拥堵告警" v-model="modelValue" align-center :modal="false" :show-close="false">
<img class="close" src="@/assets/images/close.png" @click="handleClose" /> <img class="close" src="@/assets/images/close.png" @click="handleClose" />
<div class="no-data" v-if="cond&&!list.length"> <div class="no-data" v-if="cond&&!list.length">
{{props.type=='deal'?'暂无数据':'暂无拥堵告警'}} 暂无拥堵告警
</div> </div>
<div v-else> <div v-else>
<ul class="list" > <ul class="list" >
@@ -32,10 +32,6 @@
import pubSub from 'pubsub-js' import pubSub from 'pubsub-js'
let props = defineProps({ let props = defineProps({
type: {
type: String,
default: 'curr'
},
events: { events: {
type: String, type: String,
default: '' default: ''
@@ -131,7 +127,7 @@
} }
let cond = ref(false) let cond = ref(false)
const getVideoList = async () => { const getVideoList = async () => {
let res = await getTrafficEventsApi(props.type); let res = await getTrafficEventsApi();
list.value = res.data list.value = res.data
setTimeout(()=>{cond.value = true},1500) setTimeout(()=>{cond.value = true},1500)
} }

View File

@@ -1,12 +1,12 @@
<template> <template>
<div class="z-dialog"> <div class="z-dialog">
<el-dialog :title="props.type=='deal'?'已解除异常':'异常点位告警'" v-model="modelValue" align-center :modal="false" :show-close="false"> <el-dialog title="异常点位告警" v-model="modelValue" align-center :modal="false" :show-close="false">
<img class="close" src="@/assets/images/close.png" @click="handleClose" /> <img class="close" src="@/assets/images/close.png" @click="handleClose" />
<div class="no-data" v-if="cond&&!list.length"> <div class="no-data" v-if="cond&&!list.length">
{{props.type=='deal'?'暂无数据':'暂无异常情况'}} 暂无异常情况
</div> </div>
<div v-else> <div v-else>
<ul class="list"> <ul class="list" >
<li <li
class="item" class="item"
:style="{ backgroundImage: `url(${primary})` }" :style="{ backgroundImage: `url(${primary})` }"
@@ -44,10 +44,6 @@
type: String, type: String,
default: '' default: ''
}, },
type: {
type: String,
default: 'curr'
},
events: { events: {
type: String, type: String,
default: '' default: ''
@@ -139,7 +135,7 @@
} }
let cond = ref(false) let cond = ref(false)
const getVideoList = async () => { const getVideoList = async () => {
let res = await getVideoEventApi(props.scenicSpotId,props.type); let res = await getVideoEventApi(props.scenicSpotId);
list.value = res.data list.value = res.data
setTimeout(()=>{cond.value = true},1500) setTimeout(()=>{cond.value = true},1500)
nextTick(() => { nextTick(() => {
@@ -231,21 +227,7 @@
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-content: flex-start; align-content: flex-start;
padding:vw(10); padding:vw(10);
overflow: auto;
/* 滚动条整体样式 */
&::-webkit-scrollbar {
height: vh(4); /* 滚动条的宽度 */
}
/* 滚动条轨道 */
&::-webkit-scrollbar-track {
background: 'transparent'; /* 轨道的背景色 */
}
/* 滚动条滑块 */
&::-webkit-scrollbar-thumb {
background: rgba(0, 150, 255, 0.63); /* 滑块的背景色 */
border-radius: 5px; /* 滑块的圆角 */
}
.item { .item {
position: relative; position: relative;
width: 33%; width: 33%;

View File

@@ -49,11 +49,11 @@
rich: { rich: {
name: { name: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(12) fontSize: fitChartSize(18)
}, },
value: { value: {
color: '#00D5F6', color: '#00D5F6',
fontSize: fitChartSize(12) fontSize: fitChartSize(18)
} }
} }
} }
@@ -92,7 +92,7 @@
label: { label: {
show: false, show: false,
color: '#D3F0FE', color: '#D3F0FE',
fontSize: fitChartSize(12) fontSize: fitChartSize(18)
}, },
data: getSeriesData() data: getSeriesData()
}, },
@@ -109,7 +109,7 @@
label: { label: {
show: false, show: false,
color: '#D3F0FE', color: '#D3F0FE',
fontSize: fitChartSize(12) fontSize: fitChartSize(18)
}, },
data: getSeriesData() data: getSeriesData()
}, },
@@ -151,7 +151,7 @@
<style lang="scss" scoped> <style lang="scss" scoped>
.age { .age {
width: vw(240); width: vw(260);
height: vh(280); height: vh(850);
} }
</style> </style>

View File

@@ -650,7 +650,7 @@ let tabsIndex = ref(0)
} }
.big-car-ship { .big-car-ship {
flex: 1; flex: 1;
height: vh(820); height: vh(850);
} }
.close { .close {
cursor: pointer; cursor: pointer;

View File

@@ -14,7 +14,7 @@
</div> </div>
<div class="rt-lable"> <div class="rt-lable">
<div v-for="(item, index) in scenicStore.scenicSpotData.infoList" :key="index"> <div style="flex:1;" v-for="(item, index) in scenicStore.scenicSpotData.infoList" :key="index">
<div class="label">{{ item.name }}</div> <div class="label">{{ item.name }}</div>
<p class="value" :class="{ error: item.type==2,warning: item.type==1 }">{{ item.value }}</p> <p class="value" :class="{ error: item.type==2,warning: item.type==1 }">{{ item.value }}</p>
</div> </div>
@@ -22,19 +22,66 @@
</div> </div>
<div class="main"> <div class="main">
<a @click="hanldeToDetails" class="look-btn"> <a @click="hanldeToDetails" class="look-btn">
<!-- 查看详情--> 查看详情
<img src="@/assets/images/d-icon-1.png" /> <!-- <img src="@/assets/images/d-ico-1.png" /> -->
</a> </a>
<iframe v-if="scenicSpotId == 'root000000'" width="100%" height="100%" src="http://192.168.77.200/map/sxzd/bdc.html"></iframe> <iframe v-if="scenicSpotId == 'root000000'" width="100%" height="100%" src="http://192.168.77.200/map/sxzd/bdc.html"></iframe>
<iframe v-if="scenicSpotId == 'root00000000'" width="100%" height="100%" src="http://192.168.77.200//map/sxzd/sxzd.html"></iframe> <iframe v-if="scenicSpotId == 'root00000000'" width="100%" height="100%" src="http://192.168.77.200/map/sxzd/sxzd.html"></iframe>
<iframe v-if="scenicSpotId == '龙桥河'" width="100%" height="100%" src="http://192.168.77.200/map/lqh/lqh.html"></iframe> <iframe v-if="scenicSpotId == '龙桥河'" width="100%" height="100%" src="http://192.168.77.200/map/lqh/lqh.html"></iframe>
</div> </div>
<div class="footer">
<div class="flex"> <div class="box-1" style="padding: 0;margin:0;">
<Title1 title="停车信息" />
<div class="new-circle">
<div class=" flex flex-1">
<circle-progress
v-for="(item, index) in garageList"
:key="index"
:width="80"
:height="50"
:value="parseFloat(item.rate)"
:title="item.occupied"
:subTitle="`${item.name}`"
/>
</div>
<div class="ml-20 mb-10 flex flex-1 justify-between">
<count-item label="总停车场" :count="scenicStore.stopCarData.info.count" suffix="个" />
<count-item
label="剩余车位数"
:count="scenicStore.stopCarData.info.occupiedSpaces"
suffix="个"
/>
</div>
</div>
<div class="flex">
<div class="border mr-8 flex-1">
<div class="pt-10">
<Title3 title="今日景区车流量" />
</div>
<Line width="100%" :height="133" :data="carBearData" :xAxisData="carBearXAxisData" />
</div>
<div class="border flex-1">
<div class="pt-10">
<Title3 title="车辆归属地占比" />
</div>
<PieRow
label="今日停车累计"
:dataList="dataLists"
:total="carTotal"
width="98%"
:height="133"
/>
</div>
</div>
</div>
<div class="footer" v-if="false">
<div class="">
<div class="item"> <div class="item">
<circle-progress <circle-progress
:width="170" :width="150"
:height="90" :height="60"
:value="parseFloat(scenicStore.wordkOrderData.toDayData.rate)" :value="parseFloat(scenicStore.wordkOrderData.toDayData.rate)"
:title="`${scenicStore.wordkOrderData.toDayData.rate}%`" :title="`${scenicStore.wordkOrderData.toDayData.rate}%`"
subTitle="完成率" subTitle="完成率"
@@ -56,8 +103,8 @@
</div> </div>
<div class="item"> <div class="item">
<circle-progress <circle-progress
:width="170" :width="150"
:height="90" :height="60"
:value="parseFloat(scenicStore.wordkOrderData.warnData.rate)" :value="parseFloat(scenicStore.wordkOrderData.warnData.rate)"
:title="`${scenicStore.wordkOrderData.warnData.rate}%`" :title="`${scenicStore.wordkOrderData.warnData.rate}%`"
subTitle="完成率" subTitle="完成率"
@@ -107,21 +154,12 @@
<div class="header"> <div class="header">
<div>订票时间</div> <div>订票时间</div>
<div>订票数量</div> <div>订票数量</div>
<template v-if="scenicSpotId == 'root00000000'">
<div>徒步订票</div>
</template>
<div>团队订票</div>
<div>散客订票</div>
</div> </div>
<div class="list"> <div class="list">
<div class="item" v-for="(item, index) in gridData" :key="index"> <div class="item" v-for="(item, index) in gridData" :key="index">
<div>{{ item.time }}</div> <div>{{ item.time }}</div>
<div>{{ item.value }}</div> <div>{{ item.value }}</div>
<template v-if="scenicSpotId == 'root00000000'">
<div>{{ item.walk }}</div>
</template>
<div>{{ item.group }}</div>
<div>{{ item.single }}</div>
</div> </div>
</div> </div>
</div> </div>
@@ -148,7 +186,35 @@ import pubSub from 'pubsub-js'
const scenicStore = useScenicStore() const scenicStore = useScenicStore()
const { initMap, addMarker, map, marker } = useMap() const { initMap, addMarker, map, marker } = useMap()
import { useHomeStore } from '@/stores/home' import { useHomeStore } from '@/stores/home'
const carBearData = computed(() => {
return [{ data: scenicStore.stopCarData.dataList.map((item) => item.value) }]
})
const carBearXAxisData = computed(() => {
return scenicStore.stopCarData.dataList.map((item) => item.name)
})
const carTotal = computed(() => {
return dataLists.value.reduce((pre, cur) => {
return pre + parseInt(cur.count)
}, 0)
})
const garageList = computed(() => {
return scenicStore.stopCarData.headList
})
let dataLists = ref([])
watch(
() => scenicStore.stopCarData.dataLists,
(val) => {
console.log(val.length, 'dataListsdataListsdataLists')
if (val.length) {
dataLists.value = val
} else {
dataLists.value = []
}
},
{ immediate: true }
)
const homeStore = useHomeStore() const homeStore = useHomeStore()
let props = defineProps({ let props = defineProps({
scenicSpotId: { scenicSpotId: {
@@ -171,25 +237,26 @@ import pubSub from 'pubsub-js'
let src = ref('') let src = ref('')
let cameraIndexCode = ref('') let cameraIndexCode = ref('')
let videoShow = ref(false) let videoShow = ref(false)
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 // cameraIndexCode.value = e.data.cameraIndexCode
cameraIndexCode.value = e.data.cameraIndexCode // videoShow.value = true
videoShow.value = true // }
} // });
});
let dialogTableVisible = ref(false) let dialogTableVisible = ref(false)
let gridData = ref([]) let gridData = ref([])
let gridTitle = ref('') let gridTitle = ref('')
const handlePiaoPop = async()=>{ const handlePiaoPop = async()=>{
console.log(777777)
dialogTableVisible.value = true dialogTableVisible.value = true
let res = await getSpotTicketDate({scenicSpotId:props.scenicSpotId}) let res = await getSpotTicketDate({scenicSpotId:props.scenicSpotId})
gridData.value = res.data gridData.value = res.data
console.log(res,'res')
} }
let myElement = ref(false) let myElement = ref(false)
onMounted(() => { onMounted(() => {
@@ -228,43 +295,63 @@ import pubSub from 'pubsub-js'
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.border {
position: relative;
padding: 0 vw(10);
box-sizing: border-box;
background-image: url('@/assets/images/bg-3.png');
background-size: 100% 100%;
flex:1;
}
.coll-box{ .coll-box{
flex:1 !important; flex:1 !important;
} }
.box-1 .rt-lable{ .box-1 .rt-lable{
justify-content: center !important;
text-align: center;
.label{ .label{
font-size:vw(14) !important; font-size: font-vw(20) !important; /* 22×1.2 */
} }
.value{ .value{
font-size:vw(24) !important; font-size: font-vw(24) !important; /* 32×1.2 */
} }
} }
.box-1 { .box-1 {
margin-top: vh(120); margin-top: vh(120);
width: vw(780); min-width: vw(900);
// flex:1; // flex:1;
height: vh(950); // height: vh(950);
padding: vw(10); padding: vw(10);
box-sizing: border-box; box-sizing: border-box;
background-image: url('@/assets/images/bg-3.png'); background-image: url('@/assets/images/bg-3.png');
background-size: 100% 100%; background-size: 100% 100%;
overflow: hidden;
// height: 100%;
.border {
height:vh(612) !important;
}
.new-circle{
height:vh(340);
}
.header { .header {
display: flex; // display: flex;
margin-top: vh(10); padding: vh(20);
height:vh(240);
overflow: hidden;
&__left { &__left {
display: flex; display: flex;
align-items: center; align-items: center;
margin-right:vw(10); margin-right:vw(10);
cursor:pointer; cursor:pointer;
> img { > img {
width: vw(74); // width: vw(150);
height: auto; height: vh(100);
} }
} }
&__left-item { &__left-item {
position: relative; position: relative;
width: vw(115); width: vw(210);
height: vh(58); height: vh(120);
padding-left: vw(10); padding-left: vw(10);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -274,9 +361,9 @@ import pubSub from 'pubsub-js'
// margin-left:vw(30); // margin-left:vw(30);
.label { .label {
position: absolute; position: absolute;
top: vh(-4); top: vh(-10);
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(16);
color: #ffffff; color: #ffffff;
left:vw(0) left:vw(0)
} }
@@ -287,12 +374,12 @@ import pubSub from 'pubsub-js'
justify-content: space-between; justify-content: space-between;
.label { .label {
font-weight: 400; font-weight: 400;
font-size: vw(16); font-size: font-vw(18); /* 16×1.2 */
color: #ffffff; color: #ffffff;
} }
.value { .value {
font-weight: bold; font-weight: bold;
font-size: vw(28); font-size: font-vw(24); /* 28×1.2 */
color: #02f9fa; color: #02f9fa;
text-align: center; text-align: center;
line-height: vh(60); line-height: vh(60);
@@ -307,13 +394,13 @@ import pubSub from 'pubsub-js'
.countup-wrap { .countup-wrap {
color: #02f9fa; color: #02f9fa;
font-size: vw(28); font-size: font-vw(28); /* 36×1.2 */
font-weight: bold; font-weight: bold;
} }
} }
.main { .main {
width: 100%; width: 100%;
height: vh(600); height: vh(720);
overflow-x: auto; overflow-x: auto;
overflow-y: hidden; overflow-y: hidden;
position:relative; position:relative;
@@ -326,14 +413,14 @@ import pubSub from 'pubsub-js'
padding: vw(20); padding: vw(20);
display: flex; display: flex;
align-items: center; align-items: center;
//background: #0a4190; background: #0a4190;
border-radius: vw(4); border-radius: vw(4);
font-size: vw(16); font-size: font-vw(20); /* 22×1.2 */
font-weight:700; font-weight:700;
color: #fff; color: #fff;
z-index: 999; z-index: 999;
img{ img{
width:vw(80); width:vw(100);
// height:; // height:;
} }
} }
@@ -362,18 +449,18 @@ import pubSub from 'pubsub-js'
.footer { .footer {
.item { .item {
flex: 1; flex: 1;
height: vh(140); height: vh(280);
display: flex; display: flex;
align-items: center; align-items: center;
background-image: url('@/assets/images/bg-3.png'); background-image: url('@/assets/images/bg-3.png');
background-size: 100% 100%; background-size: cover;
&:nth-child(1) { &:nth-child(1) {
margin-right: vw(10); // margin-right: vw(10);
} }
.bg { .bg {
padding-left: vw(20); padding-left: vw(20);
//width: vw(243); //width: vw(243);
height: vh(40); height: vh(80);
display: flex; display: flex;
align-items: center; align-items: center;
background: linear-gradient(90deg, rgba(0, 150, 255, 0.34) 0%, rgba(0, 150, 255, 0) 100%); background: linear-gradient(90deg, rgba(0, 150, 255, 0.34) 0%, rgba(0, 150, 255, 0) 100%);
@@ -381,14 +468,14 @@ import pubSub from 'pubsub-js'
margin-bottom: vh(4); margin-bottom: vh(4);
} }
.label { .label {
width: vw(120); // width: vw(120);
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(24); /* 20×1.2 */
color: #fff; color: #fff;
} }
.value { .value {
font-weight: bold; font-weight: bold;
font-size: vw(28); font-size: font-vw(38.4); /* 32×1.2 */
color: #fff; color: #fff;
} }
.success { .success {
@@ -400,8 +487,8 @@ import pubSub from 'pubsub-js'
} }
} }
.list { .list {
margin-top: vh(4); margin-top: vh(10);
height: vh(116); height: vh(400);
overflow: hidden; overflow: hidden;
} }
.cell { .cell {
@@ -412,38 +499,40 @@ import pubSub from 'pubsub-js'
margin-bottom: 0; margin-bottom: 0;
} }
.tag { .tag {
padding: 0 vw(16); padding:vw(16);
font-weight: bold; font-weight: bold;
font-size: vw(14); font-size: font-vw(18); /* 14×1.2 */
color: #fff; color: #fff;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
border-radius: vw(2); border-radius: vw(2);
min-width:vw(60);
} }
.tag--important { .tag--important {
@extend .tag; @extend .tag;
background:#d9011b; background: #feae00;
} }
.tag--warn { .tag--warn {
@extend .tag; @extend .tag;
background: #feae00; background: #d9011b;
} }
.tag--normal { .tag--normal {
@extend .tag; @extend .tag;
background: #2380fb; background: #2380fb;
} }
.content { .content {
margin-left: vw(4); margin-left: vw(10);
padding: 0 vw(10); padding:vw(15);
width: vw(460); min-width: vw(840);
height: vh(24); // width:100%;
line-height: vh(24); // height: vh(24);
// line-height: vh(24);
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(18); /* 14×1.2 */
color: #ffffff; color: #ffffff;
border-radius: vw(2); border-radius: vw(2);
background: rgba(0, 150, 255, 0.28); background: rgba(0, 150, 255, 0.28);
@@ -451,8 +540,8 @@ import pubSub from 'pubsub-js'
} }
.more { .more {
cursor: pointer; cursor: pointer;
width: auto; width: vw(40);
height: vh(100); // height: vh(100);
margin-top: vh(12); margin-top: vh(12);
} }
} }
@@ -461,7 +550,7 @@ import pubSub from 'pubsub-js'
<style lang="scss" scoped> <style lang="scss" scoped>
:deep(.el-dialog__headerbtn .el-dialog__close){ :deep(.el-dialog__headerbtn .el-dialog__close){
color:#fff; color:#fff;
font-size:40px; font-size:48px; /* 40×1.2 */
position:relative; position:relative;
top:15px; top:15px;
right:15px; right:15px;
@@ -477,6 +566,7 @@ import pubSub from 'pubsub-js'
:deep(.el-dialog__title) { :deep(.el-dialog__title) {
color: #fff; color: #fff;
font-weight: bold; font-weight: bold;
font-size: font-vw(28.8); /* 24×1.2 - 补充默认弹窗标题字体放大 */
} }
.sp-ico { .sp-ico {
@@ -503,7 +593,7 @@ import pubSub from 'pubsub-js'
} }
.header-title{ .header-title{
font-size:vw(32); font-size: font-vw(38.4); /* 32×1.2 */
color:#fff; color:#fff;
text-align:center; text-align:center;
font-weight:bold; font-weight:bold;
@@ -521,7 +611,7 @@ import pubSub from 'pubsub-js'
.header { .header {
height: vh(28); height: vh(28);
font-weight: 400; font-weight: 400;
font-size: vw(24); font-size: font-vw(28.8); /* 24×1.2 */
color: #fff; color: #fff;
display: flex; display: flex;
background: linear-gradient(180deg, rgba(0, 99, 255, 0) 0%, #0063ff 100%); background: linear-gradient(180deg, rgba(0, 99, 255, 0) 0%, #0063ff 100%);
@@ -551,7 +641,7 @@ import pubSub from 'pubsub-js'
.item { .item {
height: vh(50); height: vh(50);
font-weight: 400; font-weight: 400;
font-size: vw(24); font-size: font-vw(28.8); /* 24×1.2 */
color: #f1f7ff; color: #f1f7ff;
display: flex; display: flex;
&:nth-child(2n + 1) { &:nth-child(2n + 1) {
@@ -577,7 +667,7 @@ import pubSub from 'pubsub-js'
span { span {
margin-left: vw(30); margin-left: vw(30);
font-weight: 800; font-weight: 800;
font-size: vw(15); font-size: font-vw(18); /* 15×1.2 */
line-height: vh(26); line-height: vh(26);
text-align: center; text-align: center;
font-style: normal; font-style: normal;
@@ -595,7 +685,7 @@ import pubSub from 'pubsub-js'
height: vh(500); height: vh(500);
.icon-box { .icon-box {
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(16.8); /* 14×1.2 */
color: #ffffff; color: #ffffff;
line-height: vh(16); line-height: vh(16);
flex-wrap: wrap; flex-wrap: wrap;
@@ -622,7 +712,7 @@ import pubSub from 'pubsub-js'
text-align: center; text-align: center;
line-height: vh(26); line-height: vh(26);
margin-left: vw(32.5); margin-left: vw(32.5);
font-size: vw(16); font-size: font-vw(19.2); /* 16×1.2 */
font-weight: 800; font-weight: 800;
color: #fff; color: #fff;
background-image: url('@/assets/images/title-1.png'); background-image: url('@/assets/images/title-1.png');

View File

@@ -31,24 +31,26 @@
<Title3 title="景区排队人数" /> <Title3 title="景区排队人数" />
</div> </div>
<Line <Line
:width="490" width="100%"
:height="300" :height="145"
:data="scenicQueueData" :data="scenicQueueData"
:xAxisData="scenicQueueXAxisData" :xAxisData="scenicQueueXAxisData"
/> />
</div> </div>
</div> </div>
<div class="box mr-8"> <div class="box box-9 mr-8">
<Title1 title="景区承载" /> <Title1 title="景区承载" />
<div class="flex"> <div
<circle-progress style="cursor: pointer;"
:width="200" class="count-box flex justify-between">
:height="70" <circle-progress
:width="70"
:height="35"
:value="scenicStore.scenicBearData.header.jqRate" :value="scenicStore.scenicBearData.header.jqRate"
:title="`${scenicStore.scenicBearData.header.jqRate}%`" :title="`${scenicStore.scenicBearData.header.jqRate}%`"
subTitle="景区承载率" subTitle="景区承载率"
/> />
<div class="flex flex-1 justify-between"> <div class="flex flex-1 justify-center" style="text-align: center;">
<count-item <count-item
label="景区当前在园人数" label="景区当前在园人数"
:count="scenicStore.scenicBearData.header.jrjdrs" :count="scenicStore.scenicBearData.header.jrjdrs"
@@ -66,28 +68,28 @@
<Title3 title="今日景区承载量" /> <Title3 title="今日景区承载量" />
</div> </div>
<Line <Line
:width="490" width="100%"
:height="300" :height="145"
:data="scenicBearData" :data="scenicBearData"
:xAxisData="scenicBearXAxisData" :xAxisData="scenicBearXAxisData"
/> />
</div> </div>
</div> </div>
<div class="box-1 mr-8" style="padding: 0;"> <div class="box-1 mr-8" v-if="false" style="padding: 0;">
<Title1 title="停车信息" /> <Title1 title="停车信息" />
<div class="flex"> <div class="">
<div class="height70 flex flex-1"> <div class=" flex flex-1">
<circle-progress <circle-progress
v-for="(item, index) in garageList" v-for="(item, index) in garageList"
:key="index" :key="index"
:width="140" :width="80"
:height="70" :height="50"
:value="parseFloat(item.rate)" :value="parseFloat(item.rate)"
:title="item.occupied" :title="item.occupied"
:subTitle="`${item.name}`" :subTitle="`${item.name}`"
/> />
</div> </div>
<div class="ml-20 flex flex-1 justify-between"> <div class="ml-20 mb-10 flex flex-1 justify-between">
<count-item label="总停车场" :count="scenicStore.stopCarData.info.count" suffix="个" /> <count-item label="总停车场" :count="scenicStore.stopCarData.info.count" suffix="个" />
<count-item <count-item
label="剩余车位数" label="剩余车位数"
@@ -101,7 +103,7 @@
<div class="pt-10"> <div class="pt-10">
<Title3 title="今日景区车流量" /> <Title3 title="今日景区车流量" />
</div> </div>
<Line :width="360" :height="300" :data="carBearData" :xAxisData="carBearXAxisData" /> <Line width="100%" :height="105" :data="carBearData" :xAxisData="carBearXAxisData" />
</div> </div>
<div class="border flex-1"> <div class="border flex-1">
<div class="pt-10"> <div class="pt-10">
@@ -111,18 +113,18 @@
label="今日停车累计" label="今日停车累计"
:dataList="dataLists" :dataList="dataLists"
:total="carTotal" :total="carTotal"
:width="360" width="100%"
:height="300" :height="110"
/> />
</div> </div>
</div> </div>
</div> </div>
<div class="box-2"> <div class="box-2">
<Title1 title="异常信息 " /> <Title1 title="异常信息 " />
<!-- @click="handleToWorkOrder" -->
<div style="cursor: pointer;" class="count-box flex"> <div style="cursor: pointer;" class="count-box flex">
<count-item <count-item
v-for="item in headList" v-for="item in headList"
@click="showAbnormalList(item)"
:label="item.name" :label="item.name"
:count="item.count" :count="item.count"
:type="item.type" :type="item.type"
@@ -136,16 +138,16 @@
</div> </div>
<PieRow <PieRow
label="告警总数" label="告警总数"
:dataList="scenicStore.secureData.dataList" :dataList="scenicStore?.secureData.dataList"
:total="alarmTotal" :total="alarmTotal"
:width="440" width="100%"
:height="300" :height="145"
/> />
</div> </div>
</div> </div>
</div> </div>
<div class="flex mt-8"> <div class="flex mt-8" >
<div class="box-3 mr-8"> <div class="box-3 mr-8" >
<div class="look-box"> <div class="look-box">
<Title1 title="交通信息" /> <Title1 title="交通信息" />
<div @click="hanldeLookMap" class="look-btn">查看详情</div> <div @click="hanldeLookMap" class="look-btn">查看详情</div>
@@ -166,8 +168,8 @@
<div class="border mr-8"> <div class="border mr-8">
<Title3 title="拥堵次数占比" /> <Title3 title="拥堵次数占比" />
<jam <jam
:width="220" width="100%"
:height="300" :height="200"
sub-title="拥堵频次总数" sub-title="拥堵频次总数"
:list="scenicStore.trafficData.data.countRate" :list="scenicStore.trafficData.data.countRate"
:text="'暂无拥堵'" :text="'暂无拥堵'"
@@ -177,8 +179,8 @@
<Title3 title="拥堵时长占比" /> <Title3 title="拥堵时长占比" />
<jam <jam
:text="'暂无拥堵'" :text="'暂无拥堵'"
:width="220" width="100%"
:height="300" :height="200"
sub-title="拥堵总时长(分钟)" sub-title="拥堵总时长(分钟)"
:list="scenicStore.trafficData.data.timeRate" :list="scenicStore.trafficData.data.timeRate"
/> />
@@ -188,7 +190,7 @@
<div class="box-4 mr-8"> <div class="box-4 mr-8">
<Title1 title="用户画像" /> <Title1 title="用户画像" />
<div class="flex"> <div class="flex" style="height: 90%;">
<div class="border mr-8 flex-1"> <div class="border mr-8 flex-1">
<Title3 title="年龄/性别占比" /> <Title3 title="年龄/性别占比" />
<age :list="scenicStore.userPortraitData.data.ageRate" /> <age :list="scenicStore.userPortraitData.data.ageRate" />
@@ -220,16 +222,16 @@
<Title3 title="客源地分析TOP5" /> <Title3 title="客源地分析TOP5" />
<RegionTop <RegionTop
:list="scenicStore.userPortraitData.data.provinceRate" :list="scenicStore.userPortraitData.data.provinceRate"
:width="250" width="100%"
:height="366" :height="220"
/> />
</div> </div>
<div class="border flex-1"> <div class="border flex-1">
<Title3 title="购票来源" /> <Title3 title="购票来源" />
<TicketSource <TicketSource
:list="scenicStore.userPortraitData.data.channel" :list="scenicStore.userPortraitData.data.channel"
:width="240" width="100%"
:height="330" :height="200"
/> />
</div> </div>
</div> </div>
@@ -347,14 +349,12 @@
/> />
<traMap :longitude="longitude" :latitude="latitude" v-model="traMapShow"></traMap> <traMap :longitude="longitude" :latitude="latitude" v-model="traMapShow"></traMap>
<all-list :events="scenicSpotId" v-model="allShow" /> <all-list :events="scenicSpotId" v-model="allShow" />
<warn-list v-model="warnShow" :type="warnType" :scenicSpotId="scenicSpotId" />
</template> </template>
<script setup> <script setup>
import countup from 'vue-countup-v3' import countup from 'vue-countup-v3'
import PubSub from 'pubsub-js' import PubSub from 'pubsub-js'
import allList from './allList' import allList from './allList'
import warnList from './warnList.vue'
import carIcon from '@/assets/images/car.png' import carIcon from '@/assets/images/car.png'
import carStopIcon from '@/assets/images/car-stop.png' import carStopIcon from '@/assets/images/car-stop.png'
import carOfflineIcon from '@/assets/images/car-offline.png' import carOfflineIcon from '@/assets/images/car-offline.png'
@@ -383,7 +383,6 @@
//景区排队 //景区排队
let allShow = ref(false) let allShow = ref(false)
let events = ref({}) let events = ref({})
let warnType = ref("curr")
const handleLineUp = (item)=>{ const handleLineUp = (item)=>{
allShow.value = true allShow.value = true
@@ -396,11 +395,10 @@
hIndex.value = index; hIndex.value = index;
} }
const handlePop2 = async()=>{ const handlePop2 = async()=>{
if(props.scenicSpotId=="root00000000"){ dialogTableVisible2.value = true
dialogTableVisible2.value = true let res = await getSpotPassengerFlow({scenicSpotId:props.scenicSpotId})
let res = await getSpotPassengerFlow({scenicSpotId:props.scenicSpotId}) tjArr.value = res.data
tjArr.value = res.data console.log(res,'res')
}
} }
let show = ref(false) let show = ref(false)
let scenicChange = null let scenicChange = null
@@ -410,17 +408,6 @@
//查看交通信息 //查看交通信息
let latitude = ref('') let latitude = ref('')
let longitude = ref('') let longitude = ref('')
let warnShow = ref(false)
const showAbnormalList = function (item){
if(item.name=='今日异常总数'){
warnType.value = 'all'
}else if(item.name=='当前异常数'){
warnType.value = 'curr'
}else if(item.name=='已解除异常数'){
warnType.value = 'deal'
}
warnShow.value = true;
}
const hanldeLookMap = () => { const hanldeLookMap = () => {
router.push('/traffic') router.push('/traffic')
// traMapShow.value = true // traMapShow.value = true
@@ -578,7 +565,7 @@
.box-1 { .box-1 {
// margin-top: vh(120); // margin-top: vh(120);
width: vw(900); width: vw(900);
height: vh(950); // height: vh(950);
padding: vw(10); padding: vw(10);
box-sizing: border-box; box-sizing: border-box;
background-image: url('@/assets/images/bg-3.png'); background-image: url('@/assets/images/bg-3.png');
@@ -611,7 +598,7 @@
position: absolute; position: absolute;
top: vh(-4); top: vh(-4);
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: vw(16.8); /* 14×1.2 */
color: #ffffff; color: #ffffff;
left:vw(0) left:vw(0)
} }
@@ -622,12 +609,12 @@
justify-content: space-between; justify-content: space-between;
.label { .label {
font-weight: 400; font-weight: 400;
font-size: vw(16); font-size: vw(19.2); /* 16×1.2 */
color: #ffffff; color: #ffffff;
} }
.value { .value {
font-weight: bold; font-weight: bold;
font-size: vw(28); font-size: vw(33.6); /* 28×1.2 */
color: #02f9fa; color: #02f9fa;
text-align: center; text-align: center;
line-height: vh(60); line-height: vh(60);
@@ -642,7 +629,7 @@
.countup-wrap { .countup-wrap {
color: #02f9fa; color: #02f9fa;
font-size: vw(28); font-size: vw(33.6); /* 28×1.2 */
font-weight: bold; font-weight: bold;
} }
} }
@@ -663,7 +650,7 @@
align-items: center; align-items: center;
background: #0a4190; background: #0a4190;
border-radius: vw(4); border-radius: vw(4);
font-size: vw(16); font-size: font-vw(18); /* 16×1.2 */
font-weight:700; font-weight:700;
color: #fff; color: #fff;
z-index: 999; z-index: 999;
@@ -718,12 +705,12 @@
.label { .label {
width: vw(120); width: vw(120);
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: vw(16.8); /* 14×1.2 */
color: #fff; color: #fff;
} }
.value { .value {
font-weight: bold; font-weight: bold;
font-size: vw(28); font-size: vw(33.6); /* 28×1.2 */
color: #fff; color: #fff;
} }
.success { .success {
@@ -749,7 +736,7 @@
.tag { .tag {
padding: 0 vw(16); padding: 0 vw(16);
font-weight: bold; font-weight: bold;
font-size: vw(14); font-size: vw(16.8); /* 14×1.2 */
color: #fff; color: #fff;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -778,7 +765,7 @@
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: vw(16.8); /* 14×1.2 */
color: #ffffff; color: #ffffff;
border-radius: vw(2); border-radius: vw(2);
background: rgba(0, 150, 255, 0.28); background: rgba(0, 150, 255, 0.28);
@@ -796,7 +783,7 @@
<style lang="scss" scoped> <style lang="scss" scoped>
:deep(.el-dialog__headerbtn .el-dialog__close){ :deep(.el-dialog__headerbtn .el-dialog__close){
color:#fff; color:#fff;
font-size:40px; font-size:48px; /* 40×1.2 */
position:relative; position:relative;
top:15px; top:15px;
right:15px; right:15px;
@@ -812,6 +799,7 @@
:deep(.el-dialog__title) { :deep(.el-dialog__title) {
color: #fff; color: #fff;
font-weight: bold; font-weight: bold;
font-size: vw(38.4); /* 32×1.2 */
} }
.sp-ico { .sp-ico {
@@ -838,7 +826,7 @@
} }
.header-title{ .header-title{
font-size:vw(32); font-size:vw(38.4); /* 32×1.2 */
color:#fff; color:#fff;
text-align:center; text-align:center;
font-weight:bold; font-weight:bold;
@@ -856,7 +844,7 @@
.header { .header {
height: vh(28); height: vh(28);
font-weight: 400; font-weight: 400;
font-size: vw(24); font-size: vw(28.8); /* 24×1.2 */
color: #fff; color: #fff;
display: flex; display: flex;
background: linear-gradient(180deg, rgba(0, 99, 255, 0) 0%, #0063ff 100%); background: linear-gradient(180deg, rgba(0, 99, 255, 0) 0%, #0063ff 100%);
@@ -886,7 +874,7 @@
.item { .item {
height: vh(50); height: vh(50);
font-weight: 400; font-weight: 400;
font-size: vw(24); font-size: vw(28.8); /* 24×1.2 */
color: #f1f7ff; color: #f1f7ff;
display: flex; display: flex;
&:nth-child(2n + 1) { &:nth-child(2n + 1) {
@@ -912,7 +900,7 @@
span { span {
margin-left: vw(30); margin-left: vw(30);
font-weight: 800; font-weight: 800;
font-size: vw(15); font-size: vw(18); /* 15×1.2 */
line-height: vh(26); line-height: vh(26);
text-align: center; text-align: center;
font-style: normal; font-style: normal;
@@ -930,7 +918,7 @@
height: vh(500); height: vh(500);
.icon-box { .icon-box {
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: vw(16.8); /* 14×1.2 */
color: #ffffff; color: #ffffff;
line-height: vh(16); line-height: vh(16);
flex-wrap: wrap; flex-wrap: wrap;
@@ -957,7 +945,7 @@
text-align: center; text-align: center;
line-height: vh(26); line-height: vh(26);
margin-left: vw(32.5); margin-left: vw(32.5);
font-size: vw(16); font-size: vw(19.2); /* 16×1.2 */
font-weight: 800; font-weight: 800;
color: #fff; color: #fff;
background-image: url('@/assets/images/title-1.png'); background-image: url('@/assets/images/title-1.png');
@@ -973,7 +961,7 @@
align-items: center; align-items: center;
color: #fff; color: #fff;
text-align: center; text-align: center;
font-size: vw(20); font-size: vw(24);
justify-content: center; justify-content: center;
} }
.look-box { .look-box {
@@ -989,7 +977,7 @@
align-items: center; align-items: center;
background: #0a4190; background: #0a4190;
border-radius: vw(4); border-radius: vw(4);
font-size: vw(14); font-size: font-vw(18);
color: #fff; color: #fff;
} }
} }
@@ -1057,20 +1045,21 @@
} }
&-item-label { &-item-label {
font-weight: 400; font-weight: 400;
font-size: vw(12); font-size: vw(14.4);
line-height: vh(14); line-height: vh(14);
} }
&-item-value { &-item-value {
font-weight: bold; font-weight: bold;
font-size: vw(16); font-size: vw(19.2);
line-height: vh(18); line-height: vh(18);
} }
} }
.container { .container {
margin: vh(120) 0 0 vw(10); margin: vh(120) 0 0 vw(10);
flex:1;
.count-box { .count-box {
padding: 0 vw(10); padding: 0 vw(10);
height: vh(70); height: vh(140);
} }
.bg { .bg {
background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%); background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%);
@@ -1085,39 +1074,51 @@
} }
.box { .box {
@extend .bg; @extend .bg;
width: vw(510); // width: vw(650);
height: vh(475); height: vh(880);
min-width: vw(800);
flex:1;
} }
.box-9{
// width: vw(750);
}
.box-1 { .box-1 {
@extend .bg; @extend .bg;
height: vh(475);
// height: vh(475);
} }
.box-2 { .box-2 {
@extend .bg; @extend .bg;
height: vh(475); height: vh(880);
flex:1;
} }
.box-3 { .box-3 {
@extend .bg; @extend .bg;
height: vh(465); flex:1;
// width: vw(750);
// height: vh(465);
} }
.box-4 { .box-4 {
@extend .bg; @extend .bg;
height: vh(465); flex:1;
// height: vh(465);
} }
.box-5 { .box-5 {
// width: vw(750);
@extend .bg; @extend .bg;
height: vh(465); // height: vh(465);
height:100%;
flex:1; flex:1;
} }
.car-box { .car-box {
width: vw(316); // width: vw(316);
height: vh(74); height: vh(120);
display: flex; display: flex;
align-items: center; align-items: center;
.icon { .icon {
position: absolute; position: absolute;
width: vw(350); // width: vw(350);
height: vw(74); height: vw(100);
} }
.car-item { .car-item {
flex: 1; flex: 1;
@@ -1130,25 +1131,25 @@
} }
.label { .label {
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: vw(24); /* 20×1.2 */
color: #fff; color: #fff;
} }
.value { .value {
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: vw(33.6); /* 28×1.2 */
color: #02f9fa; color: #02f9fa;
margin-top: vh(6); margin-top: vh(10);
align-items: flex-end; align-items: flex-end;
} }
.suffix { .suffix {
font-size: vw(12); font-size: vw(14.4); /* 12×1.2 */
color: #02f9fa; color: #02f9fa;
margin-bottom: vw(4); margin-bottom: vw(4);
} }
} }
.sum { .sum {
font-weight: bold; font-weight: bold;
font-size: vw(18); font-size: vw(26.4); /* 22×1.2 */
color: #02f9fa; color: #02f9fa;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -1156,7 +1157,7 @@
.car-ship { .car-ship {
// width: vw(660); // width: vw(660);
width: 100%; width: 100%;
height: vh(250); height: vh(780);
} }
.full { .full {
cursor: pointer; cursor: pointer;
@@ -1170,7 +1171,7 @@
margin: vw(20) vw(20) 0 vw(20); margin: vw(20) vw(20) 0 vw(20);
height: vh(24); height: vh(24);
font-weight: bold; font-weight: bold;
font-size: vw(14); font-size: vw(16.8); /* 14×1.2 */
color: #ffffff; color: #ffffff;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -1198,7 +1199,7 @@
} }
.text { .text {
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: vw(16.8); /* 14×1.2 */
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
} }
.progress { .progress {
@@ -1207,13 +1208,13 @@
} }
.man { .man {
font-weight: bold; font-weight: bold;
font-size: vw(14); font-size: vw(16.8); /* 14×1.2 */
color: #02f9fa; color: #02f9fa;
margin-left: vw(10); margin-left: vw(10);
} }
.woman { .woman {
font-weight: bold; font-weight: bold;
font-size: vw(14); font-size: vw(16.8); /* 14×1.2 */
color: #f15a25; color: #f15a25;
margin-left: vw(10); margin-left: vw(10);
} }
@@ -1233,7 +1234,7 @@
& > span { & > span {
padding-left: vw(22); padding-left: vw(22);
font-weight: bold; font-weight: bold;
font-size: vw(15); font-size: vw(18); /* 15×1.2 */
background-image: linear-gradient(to bottom, #ffffff 0%, #75c1ff 100%); background-image: linear-gradient(to bottom, #ffffff 0%, #75c1ff 100%);
-webkit-background-clip: text; -webkit-background-clip: text;
background-clip: text; background-clip: text;
@@ -1261,12 +1262,12 @@
.label { .label {
padding-left: vw(10); padding-left: vw(10);
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: vw(16.8); /* 14×1.2 */
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
} }
.countup-wrap { .countup-wrap {
color: #02f9fa; color: #02f9fa;
font-size: vw(28); font-size: vw(33.6); /* 28×1.2 */
font-weight: bold; font-weight: bold;
} }
} }

View File

@@ -104,11 +104,11 @@
rich: { rich: {
name: { name: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(14) fontSize: fitChartSize(18)
}, },
value: { value: {
color: '#00D5F6', color: '#00D5F6',
fontSize: fitChartSize(14) fontSize: fitChartSize(18)
} }
} }
} }
@@ -136,7 +136,7 @@
}, },
name: { name: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(12) fontSize: fitChartSize(14)
} }
} }
}, },
@@ -151,23 +151,7 @@
params.series[0].label.formatter = formatLabel() params.series[0].label.formatter = formatLabel()
params.series[0].data = getSeriesData() params.series[0].data = getSeriesData()
} }
const chart = setOption(params); setOption(params)
chart.on('legendselectchanged', function (e) {
var echartsArr = [];
for (let key in e.selected) {
if (e.selected[key]) {
echartsArr.push(key)
}
}
var echartsNum = 0;
props.list.forEach(item => {
if(echartsArr.includes(item.name)){
echartsNum += parseInt(item.count)
}
})
params.series[0].label.formatter = `{value|${echartsNum}}` + '\n' + `{name|${props.subTitle}}`;
setOption(params);
});
} }
</script> </script>
@@ -179,7 +163,7 @@
top:0; top:0;
width: 100%; width: 100%;
height: 100%; height: 100%;
font-size:vw(18); font-size:vw(22);
// color:#999; // color:#999;
color:#02f9fa; color:#02f9fa;
display: flex; display: flex;

View File

@@ -77,14 +77,14 @@
} }
}, },
axisLabel: { axisLabel: {
fontSize: fitChartSize(12), fontSize: fitChartSize(14),
color: 'rgba(255,255,255,0.9)' color: 'rgba(255,255,255,0.9)'
} }
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
axisLabel: { axisLabel: {
fontSize: fitChartSize(12), fontSize: fitChartSize(14),
color: 'rgba(255,255,255,0.9)' color: 'rgba(255,255,255,0.9)'
}, },
splitLine: { splitLine: {
@@ -99,12 +99,12 @@
{ {
type: 'bar', type: 'bar',
showBackground: true, showBackground: true,
barWidth: fitChartSize(16), barWidth: fitChartSize(18),
label: { label: {
show: true, show: true,
position: 'top', position: 'top',
color: '#fff', color: '#fff',
fontSize: fitChartSize(10) fontSize: fitChartSize(14)
}, },
itemStyle: { itemStyle: {
color: { color: {
@@ -158,6 +158,6 @@
} }
.traffic-flow { .traffic-flow {
width: vw(260); width: vw(260);
height: vh(300); height: vh(855);
} }
</style> </style>

View File

@@ -1,311 +0,0 @@
<template>
<div class="z-dialog">
<el-dialog :title="props.type=='deal'?'已解除异常':'异常点位告警'" v-model="modelValue" align-center :modal="false" :show-close="false">
<img class="close" src="@/assets/images/close.png" @click="handleClose" />
<div class="no-data" v-if="cond&&!list.length">
{{props.type=='deal'?'暂无数据':'暂无异常情况'}}
</div>
<div v-else>
<ul class="list" >
<li
class="item"
:style="{ backgroundImage: `url(${primary})` }"
v-for="(item, index) in list"
:key="index"
@click="handleImage(item)"
>
<div
class="item-title-box"
><div class="item-title">{{ item.analyzeTypeName}}</div><div class="item-num">{{ item.number}}</div></div>
<img style="width: 100%;height: 100%;" :src="item.imgurl || imageEmpty">
<p style="display: flex;justify-content: space-between;">
<span> {{ item.cameraName || item.cameraIndexCode }}</span>
<span class="cursorPointer" @click.stop="handleItem(item.cameraIndexCode)">查看监控></span>
</p>
</li>
</ul>
</div>
</el-dialog>
</div>
<video-dialog v-model="videoShow" :src="src" :isDiy="isDiy" :isCollect="isCollect" :cameraIndexCode="cameraIndexCode" />
<image-dialog v-model="imageShow" :src="imgSrc"/>
</template>
<script setup>
import { getVideoEventApi,getVideoEventObjImgApi,getPreviewUrlSubApi } from '@/api/monitor'
import primary from '@/assets/images/item-primary.png'
import imageEmpty from '@/assets/images/imgloading.png'
import pubSub from 'pubsub-js'
let props = defineProps({
type: {
type: String,
default: 'curr'
},
scenicSpotId: {
type: String,
default: ''
},
events: {
type: String,
default: ''
},
})
let modelValue = defineModel()
let isCollect = ref(0)
let list = ref([])
let hlsRefs = []
let total = ref(0)
let src = ref('')
let imgSrc = ref('')
let imageShow = ref(false)
let cameraIndexCode = ref('')
let videoShow = ref(false)
let isDiy = ref(0)
let params = reactive({
pageNum: 1,
pageSize: 6,
businessScenicArea:'',
})
watch(
() => modelValue.value,
(val) => {
if (val) {
params.pageNum = 1
cond.value = false
params.businessScenicArea = props.events
list.value = []
setTimeout(() => {
getVideoList()
}, 1000)
}
}
)
const onVideoCollect = () => {
pubSub.subscribe('videoCollect', () => {
clearHlsRefs()
getVideoList()
})
}
const handleImage = (item) => {
getVideoEventObjImgApi(item.objId).then(res=>{
imgSrc.value = res.data.url
imageShow.value = true
});
}
const handleItem = async (id) => {
let {code,data} = await getPreviewUrlSubApi({
type: 'hls',
cameraIndexCode:id
})
if(code===200){
src.value = data.url
isCollect.value = data.isCollect
isDiy.value = data.isDiy
cameraIndexCode.value = id
videoShow.value = true
}
}
const handleCollect = async (id, status) => {
await postVideoCollectApi({
cameraIndexCode:id,
isCollect: status == 0 ? 1 : 0
})
clearHlsRefs()
params.pageNum = 1
getVideoList()
pubSub.publish('videoCollect')
}
const handleClose = () => {
clearHlsRefs()
modelValue.value = false
}
const clearHlsRefs = () => {
if (hlsRefs.length > 0) {
hlsRefs.map((item) => {
item.destroy()
})
hlsRefs = []
}
}
const pageNumChange = () => {
cond.value = false
clearHlsRefs()
list.value = []
getVideoList()
}
let cond = ref(false)
const getVideoList = async () => {
let res = await getVideoEventApi(props.scenicSpotId,props.type);
list.value = res.data
setTimeout(()=>{cond.value = true},1500)
nextTick(() => {
list.value.forEach(async (item, index) => {
getVideoEventObjImgApi(item.objId).then(res=>{
list.value[index].imgurl = res.data.url
});
})
})
}
onMounted(() => {
onVideoCollect()
})
onUnmounted(() => {})
</script>
<style scoped lang="scss">
.z-dialog {
:deep(.el-dialog) {
width: vw(2100);
padding: vw(8);
background-image: url('@/assets/images/dialog-bg.png') !important;
background-size: 100% 100%;
overflow-y: auto;
&::-webkit-scrollbar {
width: vw(4); /* 滚动条的宽度 */
}
/* 滚动条轨道 */
&::-webkit-scrollbar-track {
background: 'transparent'; /* 轨道的背景色 */
}
/* 滚动条滑块 */
&::-webkit-scrollbar-thumb {
background: rgba(0, 150, 255, 0.63); /* 滑块的背景色 */
border-radius: 5px; /* 滑块的圆角 */
}
}
:deep(.el-dialog__header) {
padding-bottom: 0 !important;
margin-top: vw(10);
text-align: center;
}
:deep(.el-dialog__title) {
color: #fff;
font-weight: bold;
}
}
.item-title-box{
font-weight: 400;
z-index: 99;
height: vw(50);
font-size: vw(24);
color: #ffffff;
position: absolute;
left: 3%;
.item-title{
padding: vw(10);
display: inline-block;
background-image: url('@/assets/images/unfollow.png');
background-size: 100% 100%;
}
.item-num{
margin-left: vw(6);
padding: vw(5);
display: inline-block;
color: #ffffff;
background-color:red;
border-radius: 15%;
font-weight: bolder;
}
}
.no-data{
height:vh(860);
line-height: vh(860);
text-align: center;
font-size:vw(30);
color:#02f9fa;
}
.cursorPointer{
cursor: pointer
}
.list {
//margin-top: vw(5);
gap: vw(8);
height: vh(860);
overflow: auto;
/* 滚动条整体样式 */
&::-webkit-scrollbar {
width: vw(4); /* 滚动条的宽度 */
}
/* 滚动条轨道 */
&::-webkit-scrollbar-track {
background: 'transparent'; /* 轨道的背景色 */
}
/* 滚动条滑块 */
&::-webkit-scrollbar-thumb {
background: rgba(0, 150, 255, 0.63); /* 滑块的背景色 */
border-radius: 5px; /* 滑块的圆角 */
}
display: flex;
flex-wrap: wrap;
align-content: flex-start;
padding:vw(10);
.item {
position: relative;
width: 33%;
height: vh(400);
padding: vw(12);
margin-top:vh(20);
box-sizing: border-box;
background-image: url('@/assets/images/item-primary.png');
background-size: 100% 100%;
&-video {
width: 100%;
height: 100%;
object-fit: cover;
}
> p {
position: absolute;
bottom: vw(12);
width: calc(100% - vw(24));
padding: vw(10) 0;
background: rgba(4, 30, 69, 0.72);
> span {
padding-left: vw(10);
font-weight: 400;
font-size: vw(14);
line-height: vw(14);
color: #ffffff;
}
}
&-unfollow {
cursor: pointer;
display: none;
position: absolute;
right: vw(4);
top: vw(4);
z-index: 99;
width: vw(64);
height: vw(30);
text-align: center;
line-height: vw(30);
font-weight: 400;
font-size: vw(12);
color: #ffffff;
background-image: url('@/assets/images/unfollow.png');
background-size: 100% 100%;
}
}
}
.pagination {
padding-top: vw(20);
margin-right: vw(20);
padding-bottom: vw(20);
display: flex;
justify-content: flex-end;
}
.close {
cursor: pointer;
position: absolute;
right: vw(20);
top: vw(20);
width: vw(60);
z-index: 9999;
}
</style>

View File

@@ -55,7 +55,7 @@
if (val) { if (val) {
// console.log(val, '=====') // console.log(val, '=====')
switch (val.type) { switch (val.type) {
case 'gpsData': case 'gpsData':
scenicStore.setVehicleData(val.data) scenicStore.setVehicleData(val.data)
break break
case 'wordkOrderlist': case 'wordkOrderlist':
@@ -74,9 +74,11 @@
scenicStore.setScenicBearData(val) scenicStore.setScenicBearData(val)
break break
case 'stopCarData': case 'stopCarData':
console.log('soket 车辆归属地数据',val)
scenicStore.setStopCarData(val) scenicStore.setStopCarData(val)
break break
case 'secureData': case 'secureData':
// console.log(val,'检查soket信息')
scenicStore.setSecureData(val) scenicStore.setSecureData(val)
break break
case 'trafficInformation': case 'trafficInformation':
@@ -144,13 +146,6 @@
scenicSpotId: scenicSpotId.value scenicSpotId: scenicSpotId.value
}) })
) )
sendMessage(
JSON.stringify({
action: 'start',
type: 'secureData',
scenicSpotId: scenicSpotId.value
})
)
sendMessage( sendMessage(
JSON.stringify({ JSON.stringify({
action: 'start', action: 'start',

View File

@@ -73,7 +73,7 @@
right: vw(10); right: vw(10);
} }
.area { .area {
width: vw(840); width: 100%;
height: vh(400); height:80%;
} }
</style> </style>

View File

@@ -53,20 +53,20 @@
.header { .header {
display: flex; display: flex;
font-weight: 400; font-weight: 400;
font-size: vw(13); font-size: font-vw(24);
color: #0084ff; color: #0084ff;
height: vh(40); height: vh(80);
display: flex;
align-items: center; align-items: center;
background: rgba(3, 78, 153, 0.3); background: rgba(3, 78, 153, 0.3);
& > p { & > p {
flex: 1; flex: 1;
color: #ffffff;
text-align: center; text-align: center;
} }
} }
.list { .list {
overflow-y: auto; overflow-y: auto;
height: vh(370); height: vh(800);
/* 滚动条整体样式 */ /* 滚动条整体样式 */
&::-webkit-scrollbar { &::-webkit-scrollbar {
width: vw(4); /* 滚动条的宽度 */ width: vw(4); /* 滚动条的宽度 */
@@ -85,7 +85,7 @@
// background: #555; /* 滑块的背景色 */ // background: #555; /* 滑块的背景色 */
// } // }
.cell { .cell {
height: vh(40); height: vh(80);
display: flex; display: flex;
align-items: center; align-items: center;
&:nth-child(2n) { &:nth-child(2n) {
@@ -99,10 +99,11 @@
} }
.index { .index {
display: inline-block; display: inline-block;
width: vw(40); // width: vw(50);
height: vh(24); // height: vh(30);
padding:vw(15);
font-weight: 400; font-weight: 400;
font-size: vw(12); font-size: font-vw(20);
color: #ffffff; color: #ffffff;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -124,17 +125,18 @@
} }
.name { .name {
font-weight: 400; font-weight: 400;
font-size: vw(15); font-size: font-vw(22);
color: #ffffff; color: #ffffff;
} }
.number { .number {
font-weight: 400; font-weight: 400;
font-size: vw(15); font-size: font-vw(22);
color: #02f9fa; color: #02f9fa;
} }
.status { .status {
font-weight: 400; font-weight: 400;
font-size: vw(15); font-size: font-vw(22);
color: #e21b1b; color: #e21b1b;
} }
} }

View File

@@ -56,7 +56,7 @@
<style scoped lang="scss"> <style scoped lang="scss">
.wordCloud { .wordCloud {
width: vw(760); width: 100%;
height: vh(410); height: 80%;
} }
</style> </style>

View File

@@ -20,7 +20,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="box-2 mr-8" :class="homeStore.amplify?'':'coll-box'"> <div class="box-2 mr-8" style="flex:1;" :class="homeStore.amplify?'':'coll-box'">
<div class="flex justify-center"> <div class="flex justify-center">
<div class="top flex justify-evenly"> <div class="top flex justify-evenly">
<count-item label="今日舆情总数" :count="total" suffix="条" color="#ffffff" /> <count-item label="今日舆情总数" :count="total" suffix="条" color="#ffffff" />
@@ -31,7 +31,7 @@
<div class="flex mt-20 gap-8 ml-8 mr-8"> <div class="flex mt-20 gap-8 ml-8 mr-8">
<div v-for="(item, index) in stateList" :key="index" class="border flex-1"> <div v-for="(item, index) in stateList" :key="index" class="border flex-1">
<Title3 :title="item.name" /> <Title3 :title="item.name" />
<pie-row :width="490" :height="330" :dataList="item.data" :total="item.total" /> <pie-row :width="150" :height="200" :dataList="item.data" :total="item.total" />
</div> </div>
</div> </div>
</div> </div>
@@ -41,7 +41,7 @@
</div> </div>
</div> </div>
<div class="flex mt-8"> <div class="flex mt-8">
<div class="box-2 mr-8 rela" :class="homeStore.amplify?'':'coll-box'"> <div class="box-2 mr-8 rela" style="width: 33%;" :class="homeStore.amplify?'':'coll-box'">
<Title1 title="舆情指数" /> <Title1 title="舆情指数" />
<div class="select-box"> <div class="select-box">
<Select <Select
@@ -53,8 +53,8 @@
</div> </div>
<div class="coll-box-3"> <div class="coll-box-3">
<Line <Line
:width="1500" width="100%"
:height="400" :height="220"
:data="seriesData" :data="seriesData"
:xAxisData="xAxisData" :xAxisData="xAxisData"
:seriesConfig="{ smooth: false, symbol: 'circle' }" :seriesConfig="{ smooth: false, symbol: 'circle' }"
@@ -62,11 +62,11 @@
</div> </div>
</div> </div>
<div class="box-4 mr-8 rela"> <div class="box-4 mr-8 rela" style="width: 33%;" >
<Title1 title="地域分析" /> <Title1 title="地域分析" />
<Area /> <Area width="100%" />
</div> </div>
<div class="box-3"> <div class="box-3" style="width: 33%;" >
<Title1 title="词频分析" /> <Title1 title="词频分析" />
<word-cloud /> <word-cloud />
</div> </div>
@@ -249,7 +249,7 @@
.link { .link {
color: #1890ff; color: #1890ff;
text-decoration: none; text-decoration: none;
// font-size:vw(14); // font-size: font-vw(14);
} }
.title { .title {
@@ -332,7 +332,7 @@
} }
.header-title{ .header-title{
font-size:vw(32); font-size: font-vw(32);
color:#fff; color:#fff;
text-align:center; text-align:center;
font-weight:bold; font-weight:bold;
@@ -350,7 +350,7 @@
.header { .header {
height: vh(28); height: vh(28);
font-weight: 400; font-weight: 400;
font-size: vw(24); font-size: font-vw(24);
color: #fff; color: #fff;
display: flex; display: flex;
background: linear-gradient(180deg, rgba(0, 99, 255, 0) 0%, #0063ff 100%); background: linear-gradient(180deg, rgba(0, 99, 255, 0) 0%, #0063ff 100%);
@@ -363,8 +363,9 @@
} }
.list { .list {
overflow-y: auto; overflow-y: auto;
height: vh(490); height: vh(520);
/* 滚动条整体样式 */ /* 滚动条整体样式 */
// height:100%;
&::-webkit-scrollbar { &::-webkit-scrollbar {
width: vw(4); /* 滚动条的宽度 */ width: vw(4); /* 滚动条的宽度 */
} }
@@ -380,7 +381,7 @@
.item { .item {
height: vh(50); height: vh(50);
font-weight: 400; font-weight: 400;
font-size: vw(24); font-size: font-vw(20);
color: #f1f7ff; color: #f1f7ff;
display: flex; display: flex;
&:nth-child(2n + 1) { &:nth-child(2n + 1) {
@@ -406,7 +407,7 @@
span { span {
margin-left: vw(30); margin-left: vw(30);
font-weight: 800; font-weight: 800;
font-size: vw(15); font-size: font-vw(22);
line-height: vh(26); line-height: vh(26);
text-align: center; text-align: center;
font-style: normal; font-style: normal;
@@ -424,7 +425,7 @@
height: vh(500); height: vh(500);
.icon-box { .icon-box {
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(24);
color: #ffffff; color: #ffffff;
line-height: vh(16); line-height: vh(16);
flex-wrap: wrap; flex-wrap: wrap;
@@ -451,7 +452,7 @@
text-align: center; text-align: center;
line-height: vh(26); line-height: vh(26);
margin-left: vw(32.5); margin-left: vw(32.5);
font-size: vw(16); font-size: font-vw(16);
font-weight: 800; font-weight: 800;
color: #fff; color: #fff;
background-image: url('@/assets/images/title-1.png'); background-image: url('@/assets/images/title-1.png');
@@ -477,33 +478,35 @@
background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%); background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%);
} }
.top { .top {
width: vw(600); width: vw(800);
height: vh(50); height: vh(150);
margin-top: vh(35); margin-top: vh(35);
font-size: font-vw(22);
} }
.box-1 { .box-1 {
width: vw(790); width: vw(1000);
height: vh(470); // height: vh(470);
@extend .bg; @extend .bg;
} }
.box-2 { .box-2 {
width: vw(1514); // width: vw(1720);
height: vh(470); // min-width: vw(1440);
// height: vh(470);
@extend .bg; @extend .bg;
} }
.box-3 { .box-3 {
width: vw(810); width: vw(810);
height: vh(470); // height: vh(470);
@extend .bg; @extend .bg;
} }
.box-4{ .box-4{
width: vw(850); width: vw(850);
height: vh(470); // height: vh(470);
@extend .bg; @extend .bg;
} }
.box-5{ .box-5{
width: vw(870); width: vw(1200);
height: vh(470); // height: vh(470);
@extend .bg; @extend .bg;
} }
.border { .border {
@@ -513,7 +516,7 @@
.list { .list {
margin: 0 vw(20); margin: 0 vw(20);
overflow-y: auto; overflow-y: auto;
height: vh(400); height: vh(850);
/* 滚动条整体样式 */ /* 滚动条整体样式 */
&::-webkit-scrollbar { &::-webkit-scrollbar {
width: vw(4); /* 滚动条的宽度 */ width: vw(4); /* 滚动条的宽度 */
@@ -530,21 +533,21 @@
.item { .item {
display: flex; display: flex;
align-items: center; align-items: center;
height: vh(40); height: vh(90);
cursor: pointer;
&:nth-child(2n + 1) { &:nth-child(2n + 1) {
background: rgba(3, 78, 153, 0.3); background: rgba(3, 78, 153, 0.3);
} }
.status { .status {
width: vw(40); // width: vw(60);
height: vh(20); // height: vh(40);
line-height: vh(20); line-height: vh(40);
text-align: center; text-align: center;
margin: 0 vw(20); margin: 0 vw(20);
font-weight: 400; font-weight: 400;
font-size: vw(12); font-size: font-vw(20);
color: #ffffff; color: #ffffff;
border-radius: vw(2); border-radius: vw(2);
padding:vw(15);
&-error { &-error {
@extend .status; @extend .status;
background: #d9011b; background: #d9011b;
@@ -562,16 +565,17 @@
.content { .content {
flex: 1; flex: 1;
font-weight: 400; font-weight: 400;
font-size: vw(15); font-size: font-vw(22);
color: #ffffff; color: #ffffff;
white-space: nowrap; /* 保证文本在一行内显示 */ white-space: nowrap; /* 保证文本在一行内显示 */
overflow: hidden; /* 隐藏溢出的内容 */ overflow: hidden; /* 隐藏溢出的内容 */
text-overflow: ellipsis; /* 使用省略号表示文本溢出 */ text-overflow: ellipsis; /* 使用省略号表示文本溢出 */
margin-top:0;
} }
.date { .date {
margin: 0 vw(20); margin: 0 vw(20);
font-weight: 400; font-weight: 400;
font-size: vw(12); font-size: font-vw(18);
color: rgba(255, 255, 255, 0.7); color: rgba(255, 255, 255, 0.7);
} }
} }

View File

@@ -32,8 +32,9 @@
</div> --> </div> -->
</div> </div>
<div class="chart"> <div class="chart">
<div class="chart-item"> <div class="chart-item" >
<Title3 title="拥堵频次占比" /> <Title3 title="拥堵频次占比" />
<div class="chart__inner"> <div class="chart__inner">
<div> <div>
<spotRate <spotRate
@@ -41,8 +42,9 @@
:total="chartData.totalNum" :total="chartData.totalNum"
label="拥堵频次总数" label="拥堵频次总数"
/> />
<ul class="chart__legend"> <ul class="chart__legend flex" style="flex-wrap: wrap;">
<li <li
class="chart__legend-item" class="chart__legend-item"
v-for="(item, index) in chartData.roadNum" v-for="(item, index) in chartData.roadNum"
:key="index" :key="index"
@@ -65,6 +67,7 @@
<div class="new-ul"> <div class="new-ul">
<ul class="chart__legend"> <ul class="chart__legend">
<li <li
class="chart__legend-item" class="chart__legend-item"
v-for="(item, index) in chartData.typeNum" v-for="(item, index) in chartData.typeNum"
:key="index" :key="index"
@@ -88,8 +91,9 @@
:total="chartData.totalTime" :total="chartData.totalTime"
label="拥堵总时长" label="拥堵总时长"
/> />
<ul class="chart__legend"> <ul class="chart__legend flex" style="flex-wrap: wrap;">
<li <li
class="chart__legend-item" class="chart__legend-item"
v-for="(item, index) in chartData.roadTime" v-for="(item, index) in chartData.roadTime"
:key="index" :key="index"
@@ -116,6 +120,7 @@
<div class="new-ul"> <div class="new-ul">
<ul class="chart__legend"> <ul class="chart__legend">
<li <li
class="chart__legend-item" class="chart__legend-item"
v-for="(item, index) in chartData.typeTime" v-for="(item, index) in chartData.typeTime"
:key="index" :key="index"
@@ -179,45 +184,66 @@
<style lang="scss" scoped> <style lang="scss" scoped>
.new-vehicle{ .new-vehicle{
padding-top:vh(20); padding-top:vh(20);
width:100%;
} }
.new-ul{ .new-ul{
padding:0 vw(30); padding:0 0;
margin-top:vh(20); margin-top:vh(20);
} }
.box-1 { .box-1 {
margin-top: vh(120); margin-top: vh(120);
width: vw(626); width: vw(800);
height: vh(950); // height: vh(950);
// height: 100%;
background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%); background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%);
.chart { .chart {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: vw(8); gap: vw(4);
padding: 0 vw(8); padding: 0 vw(8);
height:100%;
overflow: auto;
padding-bottom: vh(150);
background-image: url('@/assets/images/bg-3.png');
background-size: 100% 100%;
&::-webkit-scrollbar {
width: vw(0); /* 滚动条的宽度 */
}
&-item { &-item {
width: vw(300); // display: flex;
background-image: url('@/assets/images/bg-3.png'); // align-items: center;
background-size: 100% 100%; width:100%;
flex-wrap: wrap;
justify-content: center;
position: relative;
// top:vh(-10);
// height:20%;
overflow: hidden;
// width: vw(300);
// background-image: url('@/assets/images/bg-3.png');
// background-size: 100% 100%;
} }
&__inner { &__inner {
width:100%;
display: flex; display: flex;
justify-content: center; justify-content: center;
height: vh(380); // height: vh(380);
} }
&__legend { &__legend {
flex: 1; flex: 1;
display: flex;
flex-wrap: wrap;
&-item { &-item {
position: relative; position: relative;
width: 100%; width: 50%;
height: vh(30); height: vh(50);
display: flex; display: flex;
align-items: center; align-items: center;
margin-bottom: vh(8); margin-bottom: vh(15);
background: linear-gradient(90deg, rgba(0, 150, 255, 0.34) 0%, rgba(0, 150, 255, 0) 100%); background: linear-gradient(90deg, rgba(0, 150, 255, 0.34) 0%, rgba(0, 150, 255, 0) 100%);
&::before { &::before {
@@ -236,15 +262,15 @@
.name { .name {
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(20);
color: #ffffff; color: #ffffff;
width: vw(110); // width: vw(110);
} }
.value { .value {
// padding-right: vw(20); // padding-right: vw(20);
font-weight: bold; font-weight: bold;
font-size: vw(15); font-size: font-vw(20);
color: #ffffff; color: #ffffff;
} }
} }
@@ -261,7 +287,7 @@
.item-t { .item-t {
display: flex; display: flex;
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(14);
color: #fff; color: #fff;
text-align: left; text-align: left;
margin-bottom: vh(20); margin-bottom: vh(20);
@@ -277,7 +303,7 @@
background-image: url('@/assets/images/t-box-title-bg-1.png'); background-image: url('@/assets/images/t-box-title-bg-1.png');
background-size: 100% 100%; background-size: 100% 100%;
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: font-vw(24);
color: #02f9fa; color: #02f9fa;
text-align: left; text-align: left;
font-style: normal; font-style: normal;

View File

@@ -29,7 +29,7 @@
<!-- <div class="header-left__camera" @click="videoShow = true">道路监控</div> --> <!-- <div class="header-left__camera" @click="videoShow = true">道路监控</div> -->
<!-- <div class="header-left__point" @click="videoShow = true">3号点位</div> --> <!-- <div class="header-left__point" @click="videoShow = true">3号点位</div> -->
</div> </div>
<div class="header-status" v-if="item.congestLevel>0">{{ item.congestLevelText }} </div> <div class="header-status">{{ item.congestLevelText }} </div>
</div> </div>
<div class="statistics"> <div class="statistics">
<div class="statistics-item"> <div class="statistics-item">
@@ -235,6 +235,7 @@
.flex-1{ .flex-1{
flex:1; flex:1;
overflow:hidden; overflow:hidden;
height: 100%;
} }
.title-1 { .title-1 {
position: relative; position: relative;
@@ -242,8 +243,8 @@
.title { .title {
margin: vh(10) auto; margin: vh(10) auto;
margin-top:0; margin-top:0;
width: vw(1500); width: vw(1100);
height: vh(32); height: vh(62);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -251,7 +252,7 @@
background-size: 100% 100%; background-size: 100% 100%;
& > span { & > span {
font-weight: 800; font-weight: 800;
font-size: vw(24); font-size: font-vw(24);
background-image: linear-gradient(to bottom, #ffffff 0%, #75c1ff 100%); background-image: linear-gradient(to bottom, #ffffff 0%, #75c1ff 100%);
-webkit-background-clip: text; -webkit-background-clip: text;
background-clip: text; background-clip: text;
@@ -266,8 +267,9 @@
flex:1; flex:1;
} }
.nav { .nav {
width: vw(230); width: vw(330);
height: vh(950); // height: vh(950);
height:100%;
margin-left: vw(8); margin-left: vw(8);
padding-left: vw(5); padding-left: vw(5);
overflow: auto; overflow: auto;
@@ -280,10 +282,10 @@
&-item { &-item {
cursor: pointer; cursor: pointer;
margin-bottom: vw(15); margin-bottom: vw(15);
width: vw(220); width: 100%;
height: vh(54); height: vh(100);
font-weight: bold; font-weight: bold;
font-size: vw(18); font-size: font-vw(20);
color: #ffffff; color: #ffffff;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -303,6 +305,7 @@
// width: vw(2116); // width: vw(2116);
width:100%; width:100%;
height: vh(890); height: vh(890);
height: 100%;
margin-left: vw(8); margin-left: vw(8);
box-sizing: border-box; box-sizing: border-box;
background-image: url('/src/assets/images/map-bg-2.png'); background-image: url('/src/assets/images/map-bg-2.png');
@@ -335,7 +338,7 @@
height: vh(60); height: vh(60);
font-family: Inter, Inter; font-family: Inter, Inter;
font-weight: 400; font-weight: 400;
font-size: vw(12); font-size: font-vw(12);
color: #ffffff; color: #ffffff;
line-height: vh(14); line-height: vh(14);
text-align: left; text-align: left;
@@ -344,8 +347,8 @@
} }
} }
.list { .list {
width: vw(806); width: vw(1000);
height: vh(952); height: 100%;
margin-left: vw(8); margin-left: vw(8);
overflow: auto; overflow: auto;
&::-webkit-scrollbar { &::-webkit-scrollbar {
@@ -372,7 +375,7 @@
} }
&-left__title { &-left__title {
margin-right: vw(20); margin-right: vw(20);
font-size: vw(28); font-size: font-vw(28);
font-weight: bold; font-weight: bold;
color: transparent; color: transparent;
-webkit-background-clip: text; -webkit-background-clip: text;
@@ -385,7 +388,7 @@
width: vw(120); width: vw(120);
height: vw(72); height: vw(72);
font-weight: 600; font-weight: 600;
font-size: vw(15); font-size: font-vw(15);
color: #ffffff; color: #ffffff;
padding-left: vw(42); padding-left: vw(42);
display: flex; display: flex;
@@ -400,7 +403,7 @@
width: vw(120); width: vw(120);
height: vw(72); height: vw(72);
font-weight: 600; font-weight: 600;
font-size: vw(15); font-size: font-vw(15);
color: #ffffff; color: #ffffff;
padding-left: vw(42); padding-left: vw(42);
display: flex; display: flex;
@@ -410,9 +413,9 @@
} }
&-status { &-status {
min-width: vw(150); min-width: vw(150);
height: vw(54); height: vw(64);
font-weight: 600; font-weight: 600;
font-size: vw(14); font-size: font-vw(22);
color: #fff; color: #fff;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -426,7 +429,7 @@
.chart-item { .chart-item {
padding: vw(1); padding: vw(1);
margin-top: vh(10); margin-top: vh(10);
height: vh(293); height: vh(500);
background-image: url('@/assets/images/bg-3.png'); background-image: url('@/assets/images/bg-3.png');
background-size: 100% 100%; background-size: 100% 100%;
@@ -448,7 +451,7 @@
position: absolute; position: absolute;
bottom: vh(4); bottom: vh(4);
left: vw(20); left: vw(20);
font-size: vw(15); font-size: font-vw(15);
font-weight: bold; font-weight: bold;
background-image: linear-gradient(to bottom, #ffffff 0%, #0096ff 100%); background-image: linear-gradient(to bottom, #ffffff 0%, #0096ff 100%);
-webkit-background-clip: text; -webkit-background-clip: text;
@@ -462,7 +465,7 @@
} }
.statistics { .statistics {
height: vh(90); height: vh(190);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-evenly; justify-content: space-evenly;
@@ -471,15 +474,15 @@
&-item__label { &-item__label {
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(22);
color: #fff; color: #fff;
margin-bottom: vh(10); margin-bottom: vh(30);
} }
&-item__value { &-item__value {
padding-left: vw(15); padding-left: vw(15);
height: vh(30); height: vh(90);
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: font-vw(28);
color: #02f9fa; color: #02f9fa;
background-image: url('@/assets/images/t-box-title-bg-1.png'); background-image: url('@/assets/images/t-box-title-bg-1.png');
background-size: 100% 100%; background-size: 100% 100%;
@@ -488,7 +491,7 @@
.item-t { .item-t {
display: flex; display: flex;
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(14);
color: rgba(255, 255, 255, 0.8); color: rgba(255, 255, 255, 0.8);
margin-bottom: vh(20); margin-bottom: vh(20);
img { img {
@@ -504,7 +507,7 @@
background-image: url('@/assets/images/t-box-title-bg-1.png'); background-image: url('@/assets/images/t-box-title-bg-1.png');
background-size: 100% 100%; background-size: 100% 100%;
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: font-vw(24);
color: #02f9fa; color: #02f9fa;
text-align: left; text-align: left;
font-style: normal; font-style: normal;

View File

@@ -59,13 +59,13 @@
rich: { rich: {
value: { value: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(20), fontSize: fitChartSize(24),
fontWeight: 'bold', fontWeight: 'bold',
padding: [0, 0, 5, 0] padding: [0, 0, 5, 0]
}, },
name: { name: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(12) fontSize: fitChartSize(16)
} }
} }
}, },
@@ -124,7 +124,8 @@
justify-content: center; justify-content: center;
} }
.spotRate { .spotRate {
width: vw(200); width: vw(340);
height: vh(200); height: vh(340);
margin:0 auto;
} }
</style> </style>

View File

@@ -61,7 +61,7 @@
} }
}, },
axisLabel: { axisLabel: {
fontSize: fitChartSize(12), fontSize: fitChartSize(20),
color: 'rgba(255,255,255,0.9)' color: 'rgba(255,255,255,0.9)'
}, },
data: getXAxisData() data: getXAxisData()
@@ -70,7 +70,7 @@
type: 'value', type: 'value',
axisLabel: { axisLabel: {
show: false, show: false,
fontSize: fitChartSize(12), fontSize: fitChartSize(20),
color: 'rgba(255,255,255,0.9)' color: 'rgba(255,255,255,0.9)'
}, },
splitLine: { splitLine: {
@@ -90,7 +90,7 @@
show: true, show: true,
position: 'top', position: 'top',
color: '#fff', color: '#fff',
fontSize: fitChartSize(12), fontSize: fitChartSize(20),
formatter: (res) => { formatter: (res) => {
let valueMap = { let valueMap = {
1: '畅通', 1: '畅通',
@@ -125,7 +125,8 @@
<style scoped lang="scss"> <style scoped lang="scss">
.traffic-jam { .traffic-jam {
width: vw(800); width: 100%;
height: vh(250); height: vh(430);
margin-top:vh(30);
} }
</style> </style>

View File

@@ -60,14 +60,14 @@
} }
}, },
axisLabel: { axisLabel: {
fontSize: fitChartSize(12), fontSize: fitChartSize(20),
color: 'rgba(255,255,255,0.9)' color: 'rgba(255,255,255,0.9)'
} }
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
axisLabel: { axisLabel: {
fontSize: fitChartSize(12), fontSize: fitChartSize(20),
color: 'rgba(255,255,255,0.9)' color: 'rgba(255,255,255,0.9)'
}, },
splitLine: { splitLine: {
@@ -88,7 +88,7 @@
show: true, show: true,
position: 'top', position: 'top',
color: '#fff', color: '#fff',
fontSize: fitChartSize(10) fontSize: fitChartSize(20)
}, },
itemStyle: { itemStyle: {
borderRadius: [0, 0, 0, 0], borderRadius: [0, 0, 0, 0],
@@ -124,7 +124,7 @@
<style scoped lang="scss"> <style scoped lang="scss">
.vehicle-source { .vehicle-source {
width:vw(310); width:100%;
height: vh(160); height: vh(350);
} }
</style> </style>

View File

@@ -21,6 +21,7 @@
clearable clearable
placeholder="车牌号" placeholder="车牌号"
@input="onInput" @input="onInput"
style="height:50px;margin:10px 0;"
> >
</el-input> </el-input>
<ul class="tabs"> <ul class="tabs">
@@ -504,7 +505,7 @@ import PubSub from 'pubsub-js'
.item { .item {
height: vh(50); height: vh(50);
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(20);
color: #f1f7ff; color: #f1f7ff;
display: flex; display: flex;
&:nth-child(2n + 1) { &:nth-child(2n + 1) {
@@ -542,12 +543,12 @@ import PubSub from 'pubsub-js'
justify-content: center; justify-content: center;
.t-item{ .t-item{
// margin:0 vw(10); // margin:0 vw(10);
font-size:vw(18); font-size: font-vw(24);
color:#fff; color:#fff;
padding:vh(5) 0; padding:vh(30) 0;
background: url('@/assets/images/title-2.png') no-repeat center 100%; background: url('@/assets/images/title-2.png') no-repeat center 100%;
background-size:100% 100%; background-size:100% 100%;
padding:vw(10) vw(35); padding:vw(30) vw(50);
} }
.tabs-active{ .tabs-active{
// color:#409eff; // color:#409eff;
@@ -616,7 +617,7 @@ import PubSub from 'pubsub-js'
height: vh(36); height: vh(36);
padding-left: vw(16); padding-left: vw(16);
font-weight: 600; font-weight: 600;
font-size: vw(16); font-size: font-vw(16);
color: #ffffff; color: #ffffff;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -624,20 +625,20 @@ import PubSub from 'pubsub-js'
background-size: 100% 100%; background-size: 100% 100%;
} }
&-header { &-header {
padding: vh(12) vw(14); padding: vh(12) vw(20);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
} }
&-sim { &-sim {
font-weight: 600; font-weight: 600;
font-size: vw(16); font-size: font-vw(16);
color: #ffffff; color: #ffffff;
} }
&-tag { &-tag {
padding: vh(5) vw(8); padding: vh(5) vw(8);
font-weight: 400; font-weight: 400;
font-size: vw(13); font-size: font-vw(13);
color: #0096ff; color: #0096ff;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -669,7 +670,7 @@ import PubSub from 'pubsub-js'
> p { > p {
flex: 1; flex: 1;
font-weight: 400; font-weight: 400;
font-size: vw(24); font-size: font-vw(24);
color: #ffffff; color: #ffffff;
line-height: vh(20); line-height: vh(20);
} }
@@ -678,12 +679,13 @@ import PubSub from 'pubsub-js'
</style> </style>
<style scoped lang="scss"> <style scoped lang="scss">
:deep(.el-input__inner) { :deep(.el-input__inner) {
height: vh(32); height: vh(42);
color: #fff; color: #fff;
font-size: font-vw(22);
} }
:deep(.el-input__wrapper) { :deep(.el-input__wrapper) {
margin-top: vh(8); margin-top: vh(8);
font-size: vw(16); font-size: font-vw(16);
border-radius: vw(2); border-radius: vw(2);
border: vw(1) solid #0096ff; border: vw(1) solid #0096ff;
box-shadow: none !important; box-shadow: none !important;
@@ -696,9 +698,9 @@ import PubSub from 'pubsub-js'
cursor: pointer; cursor: pointer;
position: relative; position: relative;
flex: 1; flex: 1;
height: vh(44); height: vh(88);
font-weight: 600; font-weight: 600;
font-size: vw(14); font-size: font-vw(22);
color: #fff; color: #fff;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -725,11 +727,12 @@ import PubSub from 'pubsub-js'
.dialog { .dialog {
width: vw(3170); width: vw(3170);
width:100%;
padding: vw(8); padding: vw(8);
background-image: url('@/assets/images/dialog-bg.png') !important; background-image: url('@/assets/images/dialog-bg.png') !important;
background-size: 100% 100%; background-size: 100% 100%;
margin: 0 auto; margin: 0 auto;
height:vh(930); // height:vh(930);
margin-top:vh(130); margin-top:vh(130);
:deep(.el-dialog) { :deep(.el-dialog) {
width: vw(3170); width: vw(3170);
@@ -742,14 +745,15 @@ import PubSub from 'pubsub-js'
} }
} }
.list-box { .list-box {
margin-right: vw(10); margin-right: vw(20);
background-image: url('@/assets/images/bg-3.png'); background-image: url('@/assets/images/bg-3.png');
background-size: 100% 100%; background-size: 100% 100%;
width:vw(1200);
} }
.list { .list {
// width: vw(400); // width: vw(400);
height: vh(790); height: vh(1820);
padding-top: vh(10); padding-top: vh(20);
overflow-y: auto; overflow-y: auto;
box-sizing: border-box; box-sizing: border-box;
justify-content: center; justify-content: center;
@@ -775,8 +779,8 @@ import PubSub from 'pubsub-js'
.item { .item {
cursor: pointer; cursor: pointer;
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(22);
height: vh(30); height: vh(90);
padding: 0 vw(20); padding: 0 vw(20);
color: #0096ff; color: #0096ff;
display: flex; display: flex;
@@ -816,7 +820,7 @@ import PubSub from 'pubsub-js'
} }
.big-car-ship { .big-car-ship {
flex: 1; flex: 1;
height: vh(910); height: vh(2010);
} }
.close { .close {
cursor: pointer; cursor: pointer;

View File

@@ -8,239 +8,27 @@
<span :class="item.level">{{ item.level_text }}</span> <span :class="item.level">{{ item.level_text }}</span>
<p>{{ item.title }}</p> <p>{{ item.title }}</p>
<span class="time">{{ item.time }}</span> <span class="time">{{ item.time }}</span>
<span class="btn" @click="showDetail(item.id)">详情</span>
</div> </div>
</div> </div>
<el-dialog :title="'工单详情'" center v-model="dialogVisible">
<div class="bom-box">
<div class="modal-body">
<div class="m-modal">
<div class="item-title--primary">工单信息</div>
<div class="item-col">
<div class="detail-item">
<span class="label">所属景区</span>
<span class="value">{{ detail.road }}</span>
</div>
<div class="detail-item">
<span class="label">工单类型</span>
<span class="value">{{ detail.type }}</span>
</div>
<div class="detail-item">
<span class="label">紧急程度</span>
<span :class="'value '+detail.level">{{ detail.levelText }}</span>
</div>
</div>
<div class="item-col">
<div class="detail-item">
<span class="label">具体地点</span>
<span class="value">{{ detail.address }}</span>
</div>
<div class="detail-item">
<span class="label">创建时间</span>
<span class="value">{{ detail.createTime }}</span>
</div>
<div class="detail-item">
<span class="label">完成期限</span>
<span class="value">{{ detail.completionDeadline }}</span>
</div>
</div>
<div class="item-col">
<div class="detail-item">
<span class="label">创建人</span>
<span class="value">{{ detail.unidName }}</span>
</div>
<div class="detail-item">
<span class="label">状态</span>
<span class="value important" v-if="detail.status==0">待处理</span>
<span class="value warn" v-else-if="detail.status==1">进行中</span>
<span class="value normal" v-else-if="detail.status==2">已完成</span>
<span class="value" v-else>已关闭</span>
</div>
<div class="detail-item">
<span class="label">工单内容</span>
<span class="value">{{ detail.title }}</span>
</div>
</div>
<div class="detail-item" v-if="detail.imgs">
<el-image class="img" :preview-src-list="detail.imgs.split(',')" :src="src" v-for="(src, index) in detail.imgs.split(',')"></el-image>
</div>
<div class="item-title--warning" v-if="detail.follow && detail.follow.length>0">跟进信息</div>
<template v-for="item in detail.follow">
<div class="item-col" >
<div class="detail-item">
<span class="label">跟进人</span>
<span class="value">{{ item.unidName }}</span>
</div>
<div class="detail-item">
<span class="label">跟进地点</span>
<span class="value">{{ item.address }}</span>
</div>
<div class="detail-item">
<span class="label">完成率</span>
<span class="value">{{ item.rate }}%</span>
</div>
</div>
<div class="item-col">
<div class="detail-item" style="flex: 2">
<span class="label">跟进内容</span>
<span class="value">{{ item.title }}</span>
</div>
<div class="detail-item">
<span class="label">跟进时间</span>
<span class="value">{{ item.createTime }}</span>
</div>
</div>
<div class="detail-item" v-if="item.img">
<el-image class="img" :preview-src-list="item.img.split(',')" :src="src" v-for="(src, index) in item.img.split(',')"></el-image>
</div>
<div style="border-bottom: 1px solid #ffffff;margin: 10px 0;"></div>
</template>
<div class="item-title--warning" v-if="detail.evaluate && detail.evaluate.length>0">评价信息</div>
<template v-for="item in detail.evaluate">
<div class="item-col" >
<div class="detail-item">
<span class="label">评价人</span>
<span class="value warn">{{ item.unidName }}</span>
</div>
<div class="detail-item">
<span class="label">评价内容</span>
<span class="value">{{ item.title }}</span>
</div>
<div class="detail-item">
<span class="label">评价时间</span>
<span class="value">{{ item.createTime }}</span>
</div>
</div>
<div class="detail-item" v-if="item.img">
<el-image class="img" :preview-src-list="item.img.split(',')" :src="src" v-for="(src, index) in item.img.split(',')"></el-image>
</div>
<div style="border-bottom: 1px solid #ffffff;margin: 10px 0;"></div>
</template>
</div>
</div>
</div>
</el-dialog>
</div> </div>
</template> </template>
<script setup> <script setup>
import {getDetailApi, getListApi} from '@/api/workOrder' import { getListApi } from '@/api/workOrder'
let dialogVisible = ref(false)
let list = ref([]) let list = ref([])
let detail = ref({})
const getList = async () => { const getList = async () => {
let res = await getListApi() let res = await getListApi()
list.value = res.data list.value = res.data
} }
const showDetail = async (id) => {
dialogVisible.value = true
let res = await getDetailApi(id)
console.log( res.data);
detail.value = res.data
}
onMounted(() => { onMounted(() => {
getList() getList()
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
:deep(.el-dialog__headerbtn .el-dialog__close){
color:#fff;
font-size:40px;
position:relative;
top:15px;
right:15px;
}
:deep(.el-dialog__header.show-close){
padding-right:0;
}
:deep(.el-dialog) {
background: url('/src/assets/images/map-bg-2.png') no-repeat top center;
background-size: 100% 100%;
width:vw(1500);
}
:deep(.el-dialog__title) {
color: #fff;
font-weight: bold;
}
.m-modal{
padding: vw(30);
.normal {
padding:3px 10px;
background: #2380fb;
}
.warn {
padding:3px 10px;
background: #feae00;
}
.important {
padding:3px 10px;
background: #d9011b;
}
.item-title{
font-size: 18px;
margin-bottom: vw(30);
&--primary {
@extend .item-title;
color: #02f9fa;
background-image: url('@/assets/images/mask-primary.png');
background-size: 100% 100%;
}
&--error {
@extend .item-title;
background-image: url('@/assets/images/mask-error.png');
background-size: 100% 100%;
}
&--warning {
@extend .item-title;
background-image: url('@/assets/images/mask-warning.png');
background-size: 100% 100%;
}
&--success {
@extend .item-title;
background-image: url('@/assets/images/mask-success.png');
background-size: 100% 100%;
}
}
.item-col{
display: flex;
justify-content: space-between;
}
}
.detail-item {
flex:1;
margin-bottom: 12px;
line-height: 1.5;
.img{
width:vw(200);
height: vw(200);
margin: 10px;
}
}
.bom-box {
.modal-body {
padding: 16px;
color:#fff;
height:vh(780);
overflow:auto;
/* 滚动条整体样式 */
&::-webkit-scrollbar {
width: vw(4); /* 滚动条的宽度 */
}
/* 滚动条轨道 */
&::-webkit-scrollbar-track {
background: 'transparent'; /* 轨道的背景色 */
}
/* 滚动条滑块 */
&::-webkit-scrollbar-thumb {
background: rgba(0, 150, 255, 0.63); /* 滑块的背景色 */
border-radius: 5px; /* 滑块的圆角 */
}
}
}
.work-box-1 { .work-box-1 {
width: vw(815); width: vw(1000);
height: vh(950); height:100%;
margin-top: vh(120); margin-top: vh(120);
box-sizing: border-box; box-sizing: border-box;
background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%); background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%);
@@ -261,6 +49,7 @@ import {getDetailApi, getListApi} from '@/api/workOrder'
border-radius: 5px; /* 滑块的圆角 */ border-radius: 5px; /* 滑块的圆角 */
} }
height: vh(895); height: vh(895);
height:100%;
overflow: auto; overflow: auto;
.li:nth-child(odd) { .li:nth-child(odd) {
background: rgba(3, 78, 153, 0.3); background: rgba(3, 78, 153, 0.3);
@@ -273,17 +62,17 @@ import {getDetailApi, getListApi} from '@/api/workOrder'
align-items: center; align-items: center;
justify-content: flex-start; justify-content: flex-start;
padding: vh(8) vh(10); padding: vh(8) vh(10);
font-size: vw(14);
.label { .label {
width: vw(60); // width: vw(60);
height: vh(24); // height: vh(24);
line-height: vh(24); line-height: vh(24);
color: #fff; color: #fff;
border-radius: vw(2); border-radius: vw(2);
font-size: vw(14); font-size: font-vw(20);
text-align: center; text-align: center;
display: inline-block; display: inline-block;
margin-right: vw(10); margin-right: vw(10);
padding:vw(15);
} }
.normal { .normal {
@extend .label; @extend .label;
@@ -297,25 +86,19 @@ import {getDetailApi, getListApi} from '@/api/workOrder'
@extend .label; @extend .label;
background: #d9011b; background: #d9011b;
} }
.time,.btn { .time {
font-weight: 400; font-weight: 400;
font-size: vw(12); font-size: font-vw(20);
color: rgba(255, 255, 255, 0.6); color: rgba(255, 255, 255, 0.6);
line-height: 14px; // line-height: 14px;
text-align: left; text-align: left;
font-style: normal; font-style: normal;
text-transform: none; text-transform: none;
margin-left: vw(30); margin-left: vw(30);
} }
.btn{
font-size: vw(18);
font-weight: bolder;
color: #2380fb;
cursor: pointer;
}
p { p {
font-weight: 400; font-weight: 400;
//font-size: vw(15); font-size: font-vw(22);
color: #ffffff; color: #ffffff;
text-align: left; text-align: left;
font-style: normal; font-style: normal;

View File

@@ -5,28 +5,28 @@
<Title1 title="今日工单" /> <Title1 title="今日工单" />
</div> </div>
<div class="hd-list"> <div class="hd-list">
<img class="h-icon" src="@/assets/images/work-icon-1.png" /> <!-- <img class="h-icon" src="@/assets/images/work-icon-1.png" /> -->
<div class="item item1"> <div class="item item1">
今日工单总条数 <span class="color1"><countup :end-val="totalData.total" /></span> 今日工单总条数 <span class="color1"><countup :end-val="totalData.total" /></span>
</div> </div>
<div class="item item1"> <div class="item item1">
工单完成数 <span class="color1"><countup :end-val="totalData.complete" /></span> 工单完成数 <span class="color1"><countup :end-val="totalData.complete" /></span>
</div> </div>
<div class="item item2">
重要工单数 <span class=""><countup :end-val="totalData.important" /></span>
</div>
<div class="item item3"> <div class="item item3">
紧急工单数 <span class=""><countup :end-val="totalData.warn" /></span> 紧急工单数 <span class=""><countup :end-val="totalData.warn" /></span>
</div> </div>
<div class="item item2">
重要工单数 <span class=""><countup :end-val="totalData.important" /></span>
</div>
<div class="item item1"> <div class="item item1">
普通工单数 <span class=""><countup :end-val="totalData.normal" /></span> 普通工单数 <span class=""><countup :end-val="totalData.normal" /></span>
</div> </div>
</div> </div>
<div class="chart"> <div class="chart">
<div class="chart__wrapper mr-8"> <div class="chart__wrapper">
<Title3 title="工单总数" /> <Title3 title="工单总数" />
<Line :width="680" :height="320" :data="seriesData" :xAxisData="xAxisData" /> <div style="margin-top:10px;"></div>
<Line width="100%" :height="90" :data="seriesData" :xAxisData="xAxisData" />
</div> </div>
<div class="chart__wrapper"> <div class="chart__wrapper">
<Title3 title="工单类型完成比例" /> <Title3 title="工单类型完成比例" />
@@ -68,9 +68,9 @@
</div> </div>
</div> </div>
</div> </div>
<div class="box-2 mt-8"> <div class="box-2">
<Title1 title="不同景区工单占比" /> <Title1 title="景区工单占比" />
<div class="chart"> <div class="chart" style="padding-top: 0;">
<div class="chart__wrapper"> <div class="chart__wrapper">
<Title3 title="景区工单占比" /> <Title3 title="景区工单占比" />
<div class="chart__inner"> <div class="chart__inner">
@@ -196,7 +196,7 @@
border-radius: 0; border-radius: 0;
} }
:deep(.el-progress__text) { :deep(.el-progress__text) {
font-size: vw(14) !important; font-size: font-vw(20) !important;
color: #fff; color: #fff;
} }
@@ -214,7 +214,7 @@
margin-left: vw(5); margin-left: vw(5);
display: inline-block; display: inline-block;
font-weight: 400; font-weight: 400;
font-size: vw(13); font-size: font-vw(20);
color: #0084ff; color: #0084ff;
text-align: center; text-align: center;
font-style: normal; font-style: normal;
@@ -231,25 +231,25 @@
.work-box-2 { .work-box-2 {
margin-top: vh(120); margin-top: vh(120);
margin-left: vw(8); margin-left: vw(8);
flex:1;
.box-1 { .box-1 {
padding: vw(1) 0; padding: vw(1) 0;
box-sizing: border-box; box-sizing: border-box;
background: linear-gradient(to bottom, #0b2f64 0%, #062b57 100%); background: linear-gradient(to bottom, #0b2f64 0%, #062b57 100%);
.chart { .chart {
display: flex; // display: flex;
justify-content: space-between; justify-content: space-between;
padding: vw(20) vw(15); padding: vw(20) vw(15);
&__wrapper { &__wrapper {
width: vw(740); // width: vw(740);
height: vh(370); height: vh(400);
padding: 0 vw(20); padding: 0 vw(20);
background-image: url('@/assets/images/bg-3.png'); background-image: url('@/assets/images/bg-3.png');
background-size: 100% 100%; background-size: 100% 100%;
.progress { .progress {
padding: vw(30); padding: vw(30);
padding-top: vh(40); padding-top: vh(50);
&-item { &-item {
display: flex; display: flex;
width: 100%; width: 100%;
@@ -258,7 +258,7 @@
} }
&-item__label { &-item__label {
font-weight: bold; font-weight: bold;
font-size: vw(14); font-size: font-vw(22);
color: #ffffff; color: #ffffff;
text-align: left; text-align: left;
font-style: normal; font-style: normal;
@@ -280,27 +280,27 @@
left: vw(70); left: vw(70);
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
width: vw(74); width: vw(94);
height: auto; height: auto;
} }
.item { .item {
display: flex; display: flex;
width: vw(210); min-width: vw(250);
height: vh(58); height: vh(78);
line-height: vh(58); line-height: vh(78);
padding-left: vw(10); padding-left: vw(10);
text-align: center;
margin: 0 vw(15); margin: 0 vw(15);
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(22);
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
text-align: left; text-align: left;
font-style: normal; font-style: normal;
text-transform: none; text-transform: none;
align-items: baseline;
span { span {
font-size: vw(24); font-size: font-vw(28);
position: relative; position: relative;
top: vh(2); top: vh(0);
margin-left: vw(5); margin-left: vw(5);
} }
.color1 { .color1 {
@@ -312,29 +312,29 @@
background-size: 100% 100%; background-size: 100% 100%;
} }
.item2 { .item2 {
background-image: url('@/assets/images/work-n-bg-3.png'); background-image: url('@/assets/images/work-n-bg-2.png');
background-size: 100% 100%; background-size: 100% 100%;
} }
.item3 { .item3 {
background-image: url('@/assets/images/work-n-bg-2.png'); background-image: url('@/assets/images/work-n-bg-3.png');
background-size: 100% 100%; background-size: 100% 100%;
} }
} }
} }
.box-2 { .box-2 {
padding: vw(1); // padding: vw(1);
height: vh(442); // height: vh(442);
box-sizing: border-box; box-sizing: border-box;
background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%); background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%);
.chart { .chart {
display: flex; // display: flex;
justify-content: space-between; justify-content: space-between;
padding: vw(20) vw(15); padding: vw(20) vw(15);
&__wrapper { &__wrapper {
width: vw(740); // width: vw(740);
height: vh(370); // height: vh(370);
padding: 0 vw(20); padding: 0 vw(20);
background-image: url('@/assets/images/bg-3.png'); background-image: url('@/assets/images/bg-3.png');
background-size: 100% 100%; background-size: 100% 100%;
@@ -343,15 +343,17 @@
&__inner { &__inner {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center;
} }
&__legend { &__legend {
flex: 1; // flex: 1;
width: vw(800);
margin-left:vw(50);
&-item { &-item {
position: relative; position: relative;
width: 100%; width: 50%;
height: vh(40); height: vh(60);
display: flex; display: flex;
align-items: center; align-items: center;
margin-bottom: vh(8); margin-bottom: vh(8);
@@ -365,26 +367,26 @@
position: absolute; position: absolute;
content: ''; content: '';
width: vw(4); width: vw(4);
height: vh(40); height: vh(60);
background-color: #0096ff; background-color: #0096ff;
} }
.dot { .dot {
width: vw(10); width: vw(20);
height: vw(10); height: vw(20);
margin: 0 vw(16); margin: 0 vw(16);
} }
.name { .name {
font-weight: 400; font-weight: 400;
font-size: vw(12); font-size: font-vw(22);
color: #ffffff; color: #ffffff;
width: vw(130); // width: vw(130);
} }
.value { .value {
font-weight: bold; font-weight: bold;
font-size: vw(15); font-size: font-vw(22);
color: #ffffff; color: #ffffff;
} }
} }
@@ -392,11 +394,12 @@
} }
.alarm { .alarm {
width: vw(200); width: vw(600);
background: #0a4190; background: #0a4190;
&__wrapper { &__wrapper {
width: vw(200); width: vw(400);
width:100%;
height: vh(270); height: vh(270);
background: #054581; /* 滚动条整体样式 */ background: #054581; /* 滚动条整体样式 */
&::-webkit-scrollbar { &::-webkit-scrollbar {
@@ -419,15 +422,15 @@
&:nth-child(2n) { &:nth-child(2n) {
background: #054d8d; background: #054d8d;
} }
height: vh(40); height: vh(60);
display: flex; display: flex;
align-items: center; align-items: center;
} }
&-item__rank { &-item__rank {
width: vw(24); width: vw(34);
height: vh(16); height: vh(30);
font-size: vw(12); font-size: font-vw(20);
color: #ffffff; color: #ffffff;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -446,7 +449,7 @@
&-item__content { &-item__content {
padding-left: vw(20); padding-left: vw(20);
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(20);
color: #ffffff; color: #ffffff;
} }
} }

View File

@@ -16,20 +16,20 @@
<div class="statistics-item"> <div class="statistics-item">
<div class="flex align-center"> <div class="flex align-center">
<img class="statistics-item__icon" src="@/assets/images/dot-error.svg" /> <img class="statistics-item__icon" src="@/assets/images/dot-error.svg" />
<span class="statistics-item__label">重要消息</span> <span class="statistics-item__label">紧急消息</span>
</div> </div>
<div class="statistics-item__value--error"> <div class="statistics-item__value--error">
<countup :end-val="countInfo.important" /> <countup :end-val="countInfo.warn" />
<span class="statistics-item__value-suffix"></span> <span class="statistics-item__value-suffix"></span>
</div> </div>
</div> </div>
<div class="statistics-item"> <div class="statistics-item">
<div class="flex align-center"> <div class="flex align-center">
<img class="statistics-item__icon" src="@/assets/images/dot-warning.svg" /> <img class="statistics-item__icon" src="@/assets/images/dot-warning.svg" />
<span class="statistics-item__label">紧急消息</span> <span class="statistics-item__label">重要消息</span>
</div> </div>
<div class="statistics-item__value--warning"> <div class="statistics-item__value--warning">
<countup :end-val="countInfo.warn" /> <countup :end-val="countInfo.important" />
<span class="statistics-item__value-suffix"></span> <span class="statistics-item__value-suffix"></span>
</div> </div>
</div> </div>
@@ -44,15 +44,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="chart-box"> <div class="chart-box" style="justify-content: center;align-items: center;">
<!-- <pie-->
<!-- v-for="(item, index) in newsStateList"-->
<!-- :key="index"-->
<!-- :value="item.value"-->
<!-- :label="item.name"-->
<!-- :width="150"-->
<!-- :height="150"-->
<!-- />-->
<newsRate :dataList="newsStateList" /> <newsRate :dataList="newsStateList" />
<ul class="chart__legend"> <ul class="chart__legend">
<li class="chart__legend-item" v-for="(item, index) in newsStateList" :key="index"> <li class="chart__legend-item" v-for="(item, index) in newsStateList" :key="index">
@@ -168,33 +160,34 @@
.name { .name {
font-weight: 400; font-weight: 400;
font-size: vw(12); font-size: font-vw(18);
color: #ffffff; color: #ffffff;
width: vw(130); width: vw(130);
} }
.value { .value {
font-weight: bold; font-weight: bold;
font-size: vw(15); font-size: font-vw(20);
color: #ffffff; color: #ffffff;
} }
} }
} }
} }
.work-box-3 { .work-box-3 {
width: vw(840); width: vw(1000);
margin-top: vh(120); margin-top: vh(120);
margin-left: vw(8); margin-left: vw(8);
.work-box-1 { .work-box-1 {
padding: 0 vw(20); padding: 0 vw(20);
height: vh(566); // height: vh(566);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%); background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%);
.list { .list {
height: vh(500); height: vh(1600);
// height:100%;
overflow: auto; overflow: auto;
/* 滚动条整体样式 */ /* 滚动条整体样式 */
&::-webkit-scrollbar { &::-webkit-scrollbar {
@@ -219,33 +212,43 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-start; justify-content: flex-start;
padding: vh(8) vh(10); padding: vh(20) vh(10);
.label { .label {
width: vw(60); width: vw(60);
height: vh(24); height: vh(34);
line-height: vh(24); line-height: vh(34);
color: #fff; color: #fff;
border-radius: 2px 2px 2px 2px; border-radius: 2px 2px 2px 2px;
font-size: vw(14); font-size: font-vw(20);
text-align: center; text-align: center;
display: inline-block; display: inline-block;
margin-right: vw(10); margin-right: vw(10);
} }
.label--primary { .label--primary {
@extend .label; @extend .label;
width:initial;
height:initial;
padding:vw(15);
background: #2380fb; background: #2380fb;
} }
.label--warning { .label--warning {
@extend .label; @extend .label;
background: #feae00; width:initial;
height:initial;
padding:vw(15);
background: #d9011b;
} }
.label--error { .label--error {
width:initial;
height:initial;
@extend .label; @extend .label;
background: #d9011b; padding:vw(15);
background: #feae00;
} }
.time { .time {
font-weight: 400; font-weight: 400;
font-size: vw(12); font-size: font-vw(18);
color: rgba(255, 255, 255, 0.6); color: rgba(255, 255, 255, 0.6);
line-height: 14px; line-height: 14px;
text-align: left; text-align: left;
@@ -255,7 +258,7 @@
} }
p { p {
font-weight: 400; font-weight: 400;
font-size: vw(15); font-size: font-vw(20);
color: #ffffff; color: #ffffff;
text-align: left; text-align: left;
font-style: normal; font-style: normal;
@@ -274,8 +277,8 @@
.work-2-flex { .work-2-flex {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: vh(380); // height: vh(380);
margin-bottom: vw(8); margin-bottom: vw(20);
background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%); background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%);
.chart-box { .chart-box {
@@ -291,7 +294,7 @@
justify-content: space-around; justify-content: space-around;
&-item { &-item {
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: font-vw(20);
} }
&-item__icon { &-item__icon {
width: vw(24); width: vw(24);
@@ -299,7 +302,7 @@
} }
&-item__label { &-item__label {
color: #fff; color: #fff;
font-size: vw(14); font-size: font-vw(20);
} }
&-item__value { &-item__value {
position: relative; position: relative;
@@ -309,11 +312,12 @@
display: flex; display: flex;
align-items: center; align-items: center;
font-weight: bold; font-weight: bold;
font-size: vw(28); font-size: font-vw(28);
color: #fff; color: #fff;
&--primary { &--primary {
@extend .statistics-item__value; @extend .statistics-item__value;
color: #02f9fa; color: #02f9fa;
background-image: url('@/assets/images/mask-primary.png'); background-image: url('@/assets/images/mask-primary.png');
background-size: 100% 100%; background-size: 100% 100%;
} }
@@ -334,7 +338,7 @@
} }
} }
&-item__value-suffix { &-item__value-suffix {
font-size: vw(12); font-size: font-vw(12);
margin-top: vh(6); margin-top: vh(6);
} }
} }

View File

@@ -55,11 +55,11 @@
rich: { rich: {
name: { name: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(12) fontSize: fitChartSize(18)
}, },
value: { value: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(12) fontSize: fitChartSize(18)
} }
} }
} }
@@ -80,13 +80,13 @@
rich: { rich: {
value: { value: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(16), fontSize: fitChartSize(18),
fontWeight: 'bold', fontWeight: 'bold',
padding: [0, 0, 5, 0] padding: [0, 0, 5, 0]
}, },
name: { name: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(12) fontSize: fitChartSize(18)
} }
} }
}, },
@@ -158,7 +158,8 @@
<style scoped lang="scss"> <style scoped lang="scss">
.alarmRate { .alarmRate {
width: vw(380); width: vw(440);
height: vh(180); height: vh(300);
} }
</style> </style>

View File

@@ -52,7 +52,7 @@
top: '56%', top: '56%',
textStyle: { textStyle: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(12) fontSize: fitChartSize(20)
} }
} }
], ],
@@ -175,7 +175,7 @@
<style lang="scss" scoped> <style lang="scss" scoped>
.pie { .pie {
width: vw(200); width: vw(250);
height: vh(200); height: vh(250);
} }
</style> </style>

View File

@@ -34,12 +34,36 @@
const { id, setOption } = useEchart() const { id, setOption } = useEchart()
var defaultCofig = { var defaultCofig = {
color: [], color: [],
legend: {
orient: 'vertical',
y: 'center',
left: '50%',
itemWidth: fitChartSize(18),
itemHeight: fitChartSize(18),
itemGap: fitChartSize(6),
formatter: (name) => {
let obj = props.dataList.find((item) => item.name == name)
return `{name|${name}} {value|${obj?.value}}{value|%}`
},
textStyle: {
rich: {
name: {
color: '#fff',
fontSize: fitChartSize(18)
},
value: {
color: '#fff',
fontSize: fitChartSize(18)
}
}
}
},
series: [ series: [
{ {
type: 'pie', type: 'pie',
center: ['50%', '50%'], center: ['24%', '50%'],
radius: ['70%', '90%'], radius: ['35%', '50%'],
itemStyle: { itemStyle: {
borderWidth: fitChartSize(4), borderWidth: fitChartSize(4),
borderColor: '#093672' borderColor: '#093672'
@@ -51,13 +75,13 @@
rich: { rich: {
value: { value: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(24), fontSize: fitChartSize(20),
fontWeight: 'bold', fontWeight: 'bold',
padding: [0, 0, 5, 0] padding: [0, 0, 5, 0]
}, },
name: { name: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(12) fontSize: fitChartSize(22)
} }
} }
}, },
@@ -92,7 +116,7 @@
<style scoped lang="scss"> <style scoped lang="scss">
.spotRate { .spotRate {
width: vw(240); width: vw(640);
height: vh(320); height: vh(400);
} }
</style> </style>

View File

@@ -33,7 +33,7 @@ export default defineConfig({
// target: 'http://localhost:63343/', // target: 'http://localhost:63343/',
// changeOrigin: true // changeOrigin: true
// }, // },
// '/map/lqh': { // '/lqh': {
// // 目标服务器的地址 // // 目标服务器的地址
// target: 'http://localhost:63343/', // target: 'http://localhost:63343/',
// changeOrigin: true // changeOrigin: true