2025-09-27 16:10:17 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div class="dashboard-container">
|
|
|
|
|
|
<!-- 顶部固定区域 -->
|
2025-09-29 08:47:59 +08:00
|
|
|
|
<div class="top-fixed">
|
|
|
|
|
|
<div class="top-bar">
|
|
|
|
|
|
<div class="header-info">
|
|
|
|
|
|
<div>{{ currentTime }}</div>
|
|
|
|
|
|
</div>
|
2025-09-27 16:10:17 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-09-29 08:47:59 +08:00
|
|
|
|
|
2025-09-27 16:10:17 +08:00
|
|
|
|
<!-- 全屏地图区域(背景) -->
|
|
|
|
|
|
<div class="fullscreen-map">
|
|
|
|
|
|
<MapComponent></MapComponent>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 悬浮模块容器 -->
|
|
|
|
|
|
<div class="floating-modules">
|
|
|
|
|
|
<!-- 左侧模块组 -->
|
2025-09-29 08:47:59 +08:00
|
|
|
|
<div class="left">
|
|
|
|
|
|
<div class="left-modules">
|
|
|
|
|
|
<div class="module-card overview-card">
|
2025-09-29 11:08:17 +08:00
|
|
|
|
<!-- <div class="module-header">设备总览</div> -->
|
2025-09-29 08:47:59 +08:00
|
|
|
|
<div class="module-content">
|
|
|
|
|
|
<DeviceOverview />
|
|
|
|
|
|
</div>
|
2025-09-27 16:10:17 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-09-29 08:47:59 +08:00
|
|
|
|
<div class="module-card">
|
2025-09-29 11:08:17 +08:00
|
|
|
|
<!-- <div class="module-header">设备类别</div> -->
|
2025-09-29 08:47:59 +08:00
|
|
|
|
<div class="module-content">
|
|
|
|
|
|
<DeviceCategory />
|
|
|
|
|
|
</div>
|
2025-09-27 16:10:17 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-09-29 08:47:59 +08:00
|
|
|
|
<div class="module-card">
|
2025-09-29 11:08:17 +08:00
|
|
|
|
<!-- <div class="module-header">设备使用频次</div> -->
|
2025-09-29 08:47:59 +08:00
|
|
|
|
<div class="module-content">
|
|
|
|
|
|
<DeviceUsage />
|
|
|
|
|
|
</div>
|
2025-09-27 16:10:17 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- 右侧模块组 -->
|
2025-09-29 08:47:59 +08:00
|
|
|
|
<div class="right">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="right-modules">
|
|
|
|
|
|
<div class="module-card alarm-card">
|
2025-09-29 11:08:17 +08:00
|
|
|
|
<!-- <div class="module-header">报警数据</div> -->
|
2025-09-29 08:47:59 +08:00
|
|
|
|
<div class="module-content">
|
|
|
|
|
|
<AlarmOverview :alarmOverview="alarmOverview" />
|
|
|
|
|
|
</div>
|
2025-09-27 16:10:17 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-09-29 08:47:59 +08:00
|
|
|
|
<div class="module-card">
|
2025-09-29 11:08:17 +08:00
|
|
|
|
<!-- <div class="module-header">报警事件</div> -->
|
2025-09-29 08:47:59 +08:00
|
|
|
|
<div class="module-content">
|
|
|
|
|
|
<AlarmEvent :alarmOverview="alarmOverview" />
|
|
|
|
|
|
</div>
|
2025-09-27 16:10:17 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-09-29 08:47:59 +08:00
|
|
|
|
<div class="module-card">
|
2025-09-29 11:08:17 +08:00
|
|
|
|
<!-- <div class="module-header">报警次数</div> -->
|
2025-09-29 08:47:59 +08:00
|
|
|
|
<div class="module-content">
|
|
|
|
|
|
<AlarmCount />
|
|
|
|
|
|
</div>
|
2025-09-27 16:10:17 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 底部中间模块 -->
|
2025-09-29 08:47:59 +08:00
|
|
|
|
<div class="bottom">
|
|
|
|
|
|
<div class="bottom-middle-module">
|
|
|
|
|
|
<div class="module-card realtime-card">
|
2025-09-29 11:08:17 +08:00
|
|
|
|
<!-- <div class="module-header realtime-header">实时报警信息</div> -->
|
2025-09-29 08:47:59 +08:00
|
|
|
|
<div class="module-content">
|
|
|
|
|
|
<RealTimeAlarm />
|
|
|
|
|
|
</div>
|
2025-09-27 16:10:17 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
2025-09-28 15:28:15 +08:00
|
|
|
|
import { getAlarmStatistics } from '@/api/homeIndex'
|
2025-09-27 16:10:17 +08:00
|
|
|
|
import DeviceOverview from './components/DeviceOverview.vue';
|
|
|
|
|
|
import AlarmOverview from './components/AlarmOverview.vue';
|
|
|
|
|
|
import DeviceCategory from './components/DeviceCategory.vue';
|
|
|
|
|
|
import DeviceUsage from './components/DeviceUsage.vue';
|
|
|
|
|
|
import AlarmEvent from './components/AlarmEvent.vue';
|
|
|
|
|
|
import AlarmCount from './components/AlarmCount.vue';
|
|
|
|
|
|
import RealTimeAlarm from './components/RealTimeAlarm.vue';
|
|
|
|
|
|
import MapComponent from './components/MapComponent.vue';
|
2025-09-28 15:28:15 +08:00
|
|
|
|
const alarmOverview = ref<any>({})
|
2025-09-27 16:10:17 +08:00
|
|
|
|
// 实时时间实现
|
|
|
|
|
|
const currentDate = ref(new Date());
|
|
|
|
|
|
// 每秒更新时间
|
|
|
|
|
|
const timer = setInterval(() => {
|
|
|
|
|
|
currentDate.value = new Date();
|
|
|
|
|
|
}, 1000);
|
|
|
|
|
|
// 组件卸载时清除定时器
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
clearInterval(timer);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 格式化时间
|
|
|
|
|
|
const currentTime = computed(() => {
|
|
|
|
|
|
const now = currentDate.value;
|
|
|
|
|
|
return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`;
|
|
|
|
|
|
});
|
2025-09-28 15:28:15 +08:00
|
|
|
|
// 报警事件是同一个接口,在这里调用,两个子组件直接引入
|
|
|
|
|
|
const getData = async () => {
|
|
|
|
|
|
const res = await getAlarmStatistics({})
|
|
|
|
|
|
if (res.code == 200) {
|
|
|
|
|
|
alarmOverview.value = res.data
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
getData()
|
|
|
|
|
|
onMounted(() => {
|
2025-09-29 08:47:59 +08:00
|
|
|
|
|
2025-09-28 15:28:15 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-09-27 16:10:17 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.dashboard-container {
|
|
|
|
|
|
width: 100vw;
|
|
|
|
|
|
height: 100vh;
|
|
|
|
|
|
position: relative;
|
2025-09-29 11:08:17 +08:00
|
|
|
|
overflow: hidden;
|
2025-09-27 16:10:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-29 08:47:59 +08:00
|
|
|
|
.top-fixed {
|
|
|
|
|
|
width: 100%;
|
2025-09-29 11:08:17 +08:00
|
|
|
|
height:7vh;
|
2025-09-29 08:47:59 +08:00
|
|
|
|
background: url(@/assets/homeIndex/top.png) no-repeat;
|
|
|
|
|
|
background-size: 100% 100%;
|
|
|
|
|
|
z-index: 11;
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-27 16:10:17 +08:00
|
|
|
|
/* 顶部栏 */
|
|
|
|
|
|
.top-bar {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
z-index: 10;
|
|
|
|
|
|
height: 13vh;
|
|
|
|
|
|
background: url(@/assets/homeIndex/nav.png) no-repeat;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
background-size: 100% 100%;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header-info {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
right: 6vh;
|
2025-09-27 17:58:15 +08:00
|
|
|
|
top: 3.8vh;
|
2025-09-27 16:10:17 +08:00
|
|
|
|
color: #fff;
|
2025-09-27 17:58:15 +08:00
|
|
|
|
font-size: 1.8vh;
|
2025-09-27 16:10:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 全屏地图 */
|
|
|
|
|
|
.fullscreen-map {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 悬浮模块容器 */
|
|
|
|
|
|
.floating-modules {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
width: 100vw;
|
|
|
|
|
|
height: 100vh;
|
|
|
|
|
|
z-index: 5;
|
|
|
|
|
|
padding: 1.5vw;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-29 08:47:59 +08:00
|
|
|
|
.left {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
width: 30vw;
|
|
|
|
|
|
height: 100vh;
|
|
|
|
|
|
background: url(@/assets/homeIndex/left.png) no-repeat;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.right {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
width: 30vw;
|
|
|
|
|
|
height: 100vh;
|
|
|
|
|
|
background: url(@/assets/homeIndex/right.png) no-repeat;
|
|
|
|
|
|
}
|
2025-09-27 16:10:17 +08:00
|
|
|
|
/* 左侧模块组 */
|
|
|
|
|
|
.left-modules {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 8vh;
|
|
|
|
|
|
left: 0.5vw;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
2025-09-29 08:47:59 +08:00
|
|
|
|
width: 27.2vw;
|
2025-09-29 11:08:17 +08:00
|
|
|
|
height: calc(100vh - 8vh);
|
2025-09-27 16:10:17 +08:00
|
|
|
|
pointer-events: auto;
|
2025-09-29 08:47:59 +08:00
|
|
|
|
|
2025-09-27 16:10:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 右侧模块组 */
|
|
|
|
|
|
.right-modules {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 8vh;
|
|
|
|
|
|
right: 0.5vw;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
2025-09-29 08:47:59 +08:00
|
|
|
|
width: 27.2vw;
|
2025-09-29 11:08:17 +08:00
|
|
|
|
height: calc(100vh - 8vh);
|
2025-09-27 16:10:17 +08:00
|
|
|
|
pointer-events: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 底部中间模块 */
|
|
|
|
|
|
.bottom-middle-module {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
bottom: 0.4vw;
|
|
|
|
|
|
left: 50%;
|
|
|
|
|
|
transform: translateX(-50%);
|
|
|
|
|
|
width: 44vw;
|
2025-09-27 17:58:15 +08:00
|
|
|
|
height: calc(39vh - 9vh);
|
2025-09-27 16:10:17 +08:00
|
|
|
|
pointer-events: auto;
|
2025-09-29 08:47:59 +08:00
|
|
|
|
background: url(@/assets/homeIndex/bottom.png) no-repeat;
|
|
|
|
|
|
background-size: 100% 100%;
|
2025-09-27 16:10:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 模块卡片样式 */
|
|
|
|
|
|
.module-card {
|
2025-09-29 11:08:17 +08:00
|
|
|
|
/* background: url(@/assets/homeIndex/card.png) no-repeat; */
|
2025-09-27 16:10:17 +08:00
|
|
|
|
position: relative;
|
|
|
|
|
|
background-size: 100% 100%;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
2025-09-29 08:47:59 +08:00
|
|
|
|
border-radius: 10px;
|
2025-09-29 11:08:17 +08:00
|
|
|
|
margin-bottom: 1vh;
|
|
|
|
|
|
}
|
|
|
|
|
|
.left-modules .module-card:nth-of-type(1) {
|
|
|
|
|
|
background: url(@/assets/homeIndex/card1.png) no-repeat;
|
|
|
|
|
|
background-size: 100% 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
.left-modules .module-card:nth-of-type(2) {
|
|
|
|
|
|
background: url(@/assets/homeIndex/card2.png) no-repeat;
|
|
|
|
|
|
background-size: 100% 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
.left-modules .module-card:nth-of-type(3) {
|
|
|
|
|
|
background: url(@/assets/homeIndex/card3.png) no-repeat;
|
|
|
|
|
|
background-size: 100% 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
.right-modules .module-card:nth-of-type(1) {
|
|
|
|
|
|
background: url(@/assets/homeIndex/card4.png) no-repeat;
|
|
|
|
|
|
background-size: 100% 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
.right-modules .module-card:nth-of-type(2) {
|
|
|
|
|
|
background: url(@/assets/homeIndex/card5.png) no-repeat;
|
|
|
|
|
|
background-size: 100% 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
.right-modules .module-card:nth-of-type(3) {
|
|
|
|
|
|
background: url(@/assets/homeIndex/card6.png) no-repeat;
|
|
|
|
|
|
background-size: 100% 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
.bottom-middle-module .module-card:nth-of-type(1) {
|
|
|
|
|
|
background: url(@/assets/homeIndex/card7.png) no-repeat;
|
|
|
|
|
|
background-size: 100% 100%;
|
2025-09-27 16:10:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 模块标题 */
|
|
|
|
|
|
.module-header {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
font-size: 1.6vh;
|
2025-09-29 11:08:17 +08:00
|
|
|
|
|
2025-09-27 16:10:17 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
flex-shrink: 0;
|
2025-09-29 11:08:17 +08:00
|
|
|
|
left:4.8vh;
|
|
|
|
|
|
top:1.5vh;
|
|
|
|
|
|
font-family: SourceHanSansCN, SourceHanSansCN;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
/* font-size: 18px; */
|
|
|
|
|
|
color: #F2F8FF;
|
|
|
|
|
|
|
|
|
|
|
|
text-shadow: 3px 0px 6px rgba(3,33,42,0.5);
|
2025-09-27 16:10:17 +08:00
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-27 17:58:15 +08:00
|
|
|
|
.realtime-header {
|
2025-09-29 11:08:17 +08:00
|
|
|
|
left: 7.5vh;
|
|
|
|
|
|
top:1.5vh;
|
2025-09-27 17:58:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-27 16:10:17 +08:00
|
|
|
|
/* 模块内容 */
|
|
|
|
|
|
.module-content {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|