|
@@ -1,832 +0,0 @@
|
|
-<template>
|
|
|
|
- <div class="radar-monitoring-screen">
|
|
|
|
- <!-- 顶部区域 -->
|
|
|
|
- <div class="header">
|
|
|
|
- <div class="system-name">雷能社区智慧大屏</div>
|
|
|
|
- <div class="running-days">已安全守护 {{ runningDays }} 天</div>
|
|
|
|
- <div class="time-info">{{ currentTime }}</div>
|
|
|
|
- <div class="data-flow header-flow"></div>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <!-- 内容区域 -->
|
|
|
|
- <div class="content-area">
|
|
|
|
- <!-- 左侧面板 -->
|
|
|
|
- <div class="panel">
|
|
|
|
- <div class="panel-title">今日监测概览</div>
|
|
|
|
- <div class="panel-content">
|
|
|
|
- <div class="data-grid">
|
|
|
|
- <DataCard title="检测到人数" :value="todayData.detectedCount" />
|
|
|
|
- <DataCard title="长者活跃度" :value="`${todayData.activeRate}%`" />
|
|
|
|
- <DataCard title="跌倒统计次数" :value="todayData.alarmCount" />
|
|
|
|
- <DataCard title="告警统计次数" :value="todayData.fallingCount" />
|
|
|
|
- <DataCard
|
|
|
|
- title="设备在线率"
|
|
|
|
- :value="`${((todayData.onlineCount / todayData.deviceCount) * 100).toFixed(2)}%`"
|
|
|
|
- :change="`${todayData.onlineCount} / ${todayData.deviceCount} 台`"
|
|
|
|
- />
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div class="panel-title" style="margin-top: 15px">设备分布情况</div>
|
|
|
|
- <div class="chart-container" ref="deviceChartRef"></div>
|
|
|
|
-
|
|
|
|
- <div class="panel-title">设备年龄层次</div>
|
|
|
|
- <div class="chart-container" ref="ageChartRef"></div>
|
|
|
|
- </div>
|
|
|
|
- <div class="data-flow"></div>
|
|
|
|
- <div class="glow-effect"></div>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <!-- 中间面板 -->
|
|
|
|
- <div class="panel center-panel">
|
|
|
|
- <div class="map-container">
|
|
|
|
- <img class="map-img" src="../../assets/img/map.jpg" alt="小区地图" />
|
|
|
|
- <!-- <div class="map-label">雷能小区</div> -->
|
|
|
|
- <div class="map-label building-1">1号楼</div>
|
|
|
|
- <div class="map-label building-2">2号楼</div>
|
|
|
|
- <div class="map-label building-3">物业中心</div>
|
|
|
|
- <div class="map-label building-4">3号楼</div>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <!-- 右侧面板 -->
|
|
|
|
- <div class="panel">
|
|
|
|
- <div class="panel-title" style="margin-top: 15px">检测对象分布</div>
|
|
|
|
- <div class="chart-container" ref="objectChartRef"></div>
|
|
|
|
-
|
|
|
|
- <div class="panel-title" style="margin-top: 15px">历史告警统计</div>
|
|
|
|
- <div class="chart-container" ref="alarmHistoryRef"></div>
|
|
|
|
-
|
|
|
|
- <div class="panel-title" style="margin-top: 15px">历史跌倒统计</div>
|
|
|
|
- <div class="chart-container" ref="fallingHistoryRef"></div>
|
|
|
|
- <div class="data-flow"></div>
|
|
|
|
- <div class="glow-effect"></div>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <!-- 底部区域 -->
|
|
|
|
- <!-- <div class="footer">
|
|
|
|
- <div>智慧养老雷达监控系统 © 2023 版本 v2.5.1 | 技术支持:400-123-4567</div>
|
|
|
|
- </div> -->
|
|
|
|
- </div>
|
|
|
|
-</template>
|
|
|
|
-
|
|
|
|
-<script setup lang="ts">
|
|
|
|
-import { ref, onMounted, onUnmounted } from 'vue'
|
|
|
|
-import * as echarts from 'echarts'
|
|
|
|
-import DataCard from '../dataCard/index.vue'
|
|
|
|
-import { type TodayData } from '../../types'
|
|
|
|
-
|
|
|
|
-defineOptions({
|
|
|
|
- name: 'ScreenPage',
|
|
|
|
-})
|
|
|
|
-
|
|
|
|
-// 响应式数据
|
|
|
|
-const currentTime = ref('')
|
|
|
|
-const runningDays = ref(328)
|
|
|
|
-const todayData = ref<TodayData>({
|
|
|
|
- deviceCount: 30,
|
|
|
|
- onlineCount: 25,
|
|
|
|
- systemGuardDay: 328,
|
|
|
|
- alarmCount: 3,
|
|
|
|
- fallingCount: 1,
|
|
|
|
- detectedCount: 142,
|
|
|
|
- activeRate: 78,
|
|
|
|
-})
|
|
|
|
-
|
|
|
|
-// 历史告警统计数据(最近7天)
|
|
|
|
-const alarmHistoryData = ref({
|
|
|
|
- dates: ['1月1日', '1月2日', '1月3日', '1月4日', '1月5日', '1月6日', '1月7日'],
|
|
|
|
- values: [3, 5, 2, 7, 4, 6, 3],
|
|
|
|
-})
|
|
|
|
-
|
|
|
|
-// 历史跌倒统计数据(最近7天)
|
|
|
|
-const fallingHistoryData = ref({
|
|
|
|
- dates: ['1月1日', '1月2日', '1月3日', '1月4日', '1月5日', '1月6日', '1月7日'],
|
|
|
|
- values: [1, 2, 0, 1, 3, 1, 0],
|
|
|
|
-})
|
|
|
|
-
|
|
|
|
-// 图表引用
|
|
|
|
-const deviceChartRef = ref<HTMLElement | null>(null)
|
|
|
|
-const ageChartRef = ref<HTMLElement | null>(null)
|
|
|
|
-const objectChartRef = ref<HTMLElement | null>(null)
|
|
|
|
-const alarmHistoryRef = ref<HTMLElement | null>(null)
|
|
|
|
-const fallingHistoryRef = ref<HTMLElement | null>(null)
|
|
|
|
-
|
|
|
|
-let deviceChart: echarts.ECharts | null = null
|
|
|
|
-let ageChart: echarts.ECharts | null = null
|
|
|
|
-let objectChart: echarts.ECharts | null = null
|
|
|
|
-let alarmHistoryChart: echarts.ECharts | null = null
|
|
|
|
-let fallingHistoryChart: echarts.ECharts | null = null
|
|
|
|
-const updateInterval: ReturnType<typeof setInterval> | null = null
|
|
|
|
-
|
|
|
|
-// 更新时间
|
|
|
|
-const updateTime = () => {
|
|
|
|
- const now = new Date()
|
|
|
|
- currentTime.value = now.toLocaleString('zh-CN', {
|
|
|
|
- year: 'numeric',
|
|
|
|
- month: '2-digit',
|
|
|
|
- day: '2-digit',
|
|
|
|
- hour: '2-digit',
|
|
|
|
- minute: '2-digit',
|
|
|
|
- second: '2-digit',
|
|
|
|
- hour12: false,
|
|
|
|
- })
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// 初始化图表
|
|
|
|
-const initCharts = () => {
|
|
|
|
- if (!deviceChartRef.value) return
|
|
|
|
-
|
|
|
|
- // 设备分布情况图表(安装位置)
|
|
|
|
- deviceChart = echarts.init(deviceChartRef.value)
|
|
|
|
-
|
|
|
|
- deviceChart.setOption({
|
|
|
|
- grid: { top: 10, right: 10, bottom: 10, left: 10 },
|
|
|
|
- tooltip: {
|
|
|
|
- trigger: 'item',
|
|
|
|
- formatter: '{a} <br/>{b}: {c} ({d}%)',
|
|
|
|
- },
|
|
|
|
- series: [
|
|
|
|
- {
|
|
|
|
- name: '安装位置',
|
|
|
|
- type: 'pie',
|
|
|
|
- radius: ['20%', '70%'],
|
|
|
|
- roseType: 'area',
|
|
|
|
- itemStyle: {
|
|
|
|
- borderColor: '#0a0e17',
|
|
|
|
- borderWidth: 2,
|
|
|
|
- },
|
|
|
|
- label: {
|
|
|
|
- show: true,
|
|
|
|
- formatter: '{b}: {c}',
|
|
|
|
- color: '#fff', // 设置文字颜色为白色
|
|
|
|
- fontSize: 14,
|
|
|
|
- fontWeight: 'bold',
|
|
|
|
- textBorderColor: 'rgba(0, 0, 0, 0.8)', // 添加黑色描边
|
|
|
|
- textBorderWidth: 2, // 描边宽度
|
|
|
|
- textShadowColor: 'rgba(0, 0, 0, 0.5)', // 添加文字阴影
|
|
|
|
- textShadowBlur: 4, // 阴影模糊程度
|
|
|
|
- textShadowOffsetX: 1, // 阴影X偏移
|
|
|
|
- textShadowOffsetY: 1, // 阴影Y偏移
|
|
|
|
- },
|
|
|
|
- emphasis: {
|
|
|
|
- label: {
|
|
|
|
- show: true,
|
|
|
|
- fontWeight: 'bold',
|
|
|
|
- fontSize: 16, // 放大强调时的文字
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- data: [
|
|
|
|
- { value: 12, name: '卫生间', itemStyle: { color: '#4dc9e6' } },
|
|
|
|
- { value: 8, name: '卧室', itemStyle: { color: '#6de4ff' } },
|
|
|
|
- { value: 6, name: '客厅', itemStyle: { color: '#2572ed' } },
|
|
|
|
- { value: 4, name: '餐厅', itemStyle: { color: '#1a57c9' } },
|
|
|
|
- ],
|
|
|
|
- },
|
|
|
|
- ],
|
|
|
|
- })
|
|
|
|
-
|
|
|
|
- // 设备年龄层次图表
|
|
|
|
- if (ageChartRef.value) {
|
|
|
|
- ageChart = echarts.init(ageChartRef.value)
|
|
|
|
- ageChart.setOption({
|
|
|
|
- grid: { top: 10, right: 10, bottom: 10, left: 10 },
|
|
|
|
- tooltip: {
|
|
|
|
- trigger: 'item',
|
|
|
|
- formatter: '{a} <br/>{b}: {c} ({d}%)',
|
|
|
|
- },
|
|
|
|
- series: [
|
|
|
|
- {
|
|
|
|
- name: '设备年龄',
|
|
|
|
- type: 'pie',
|
|
|
|
- radius: ['30%', '70%'],
|
|
|
|
- itemStyle: {
|
|
|
|
- borderColor: '#0a0e17',
|
|
|
|
- borderWidth: 2,
|
|
|
|
- },
|
|
|
|
- label: {
|
|
|
|
- show: true,
|
|
|
|
- formatter: '{b}: {c}',
|
|
|
|
- color: '#fff',
|
|
|
|
- fontSize: 14,
|
|
|
|
- fontWeight: 'bold',
|
|
|
|
- },
|
|
|
|
- emphasis: {
|
|
|
|
- label: {
|
|
|
|
- show: true,
|
|
|
|
- fontWeight: 'bold',
|
|
|
|
- fontSize: 16,
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- data: [
|
|
|
|
- { value: 15, name: '1年内', itemStyle: { color: '#4dc9e6' } },
|
|
|
|
- { value: 10, name: '1-2年', itemStyle: { color: '#2572ed' } },
|
|
|
|
- { value: 5, name: '2-3年', itemStyle: { color: '#6de4ff' } },
|
|
|
|
- { value: 2, name: '3年以上', itemStyle: { color: '#1a57c9' } },
|
|
|
|
- ],
|
|
|
|
- },
|
|
|
|
- ],
|
|
|
|
- })
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 检测对象图表
|
|
|
|
- if (objectChartRef.value) {
|
|
|
|
- objectChart = echarts.init(objectChartRef.value)
|
|
|
|
- objectChart.setOption({
|
|
|
|
- grid: { top: 10, right: 10, bottom: 10, left: 10 },
|
|
|
|
- tooltip: {
|
|
|
|
- trigger: 'item',
|
|
|
|
- formatter: '{a} <br/>{b}: {c} ({d}%)',
|
|
|
|
- },
|
|
|
|
- series: [
|
|
|
|
- {
|
|
|
|
- name: '检测对象',
|
|
|
|
- type: 'pie',
|
|
|
|
- radius: ['30%', '70%'],
|
|
|
|
- itemStyle: {
|
|
|
|
- borderColor: '#0a0e17',
|
|
|
|
- borderWidth: 2,
|
|
|
|
- },
|
|
|
|
- label: {
|
|
|
|
- show: true,
|
|
|
|
- formatter: '{b}: {c}',
|
|
|
|
- color: '#fff',
|
|
|
|
- fontSize: 14,
|
|
|
|
- fontWeight: 'bold',
|
|
|
|
- },
|
|
|
|
- emphasis: {
|
|
|
|
- label: {
|
|
|
|
- show: true,
|
|
|
|
- fontWeight: 'bold',
|
|
|
|
- fontSize: 16,
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- data: [
|
|
|
|
- { value: 45, name: '长者', itemStyle: { color: '#2ecc71' } },
|
|
|
|
- { value: 20, name: '访客', itemStyle: { color: '#f39c12' } },
|
|
|
|
- { value: 35, name: '工作人员', itemStyle: { color: '#e74c3c' } },
|
|
|
|
- ],
|
|
|
|
- },
|
|
|
|
- ],
|
|
|
|
- })
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 历史告警统计图表
|
|
|
|
- if (alarmHistoryRef.value) {
|
|
|
|
- alarmHistoryChart = echarts.init(alarmHistoryRef.value)
|
|
|
|
- alarmHistoryChart.setOption({
|
|
|
|
- grid: { top: 10, right: 20, bottom: 30, left: 30 },
|
|
|
|
- tooltip: {
|
|
|
|
- trigger: 'axis',
|
|
|
|
- axisPointer: {
|
|
|
|
- type: 'shadow',
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- xAxis: {
|
|
|
|
- type: 'category',
|
|
|
|
- data: alarmHistoryData.value.dates,
|
|
|
|
- axisLine: {
|
|
|
|
- lineStyle: {
|
|
|
|
- color: '#2a3b5a',
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- axisLabel: {
|
|
|
|
- color: '#9cc5e0',
|
|
|
|
- fontSize: 12,
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- yAxis: {
|
|
|
|
- type: 'value',
|
|
|
|
- axisLine: {
|
|
|
|
- lineStyle: {
|
|
|
|
- color: '#2a3b5a',
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- axisLabel: {
|
|
|
|
- color: '#9cc5e0',
|
|
|
|
- fontSize: 12,
|
|
|
|
- },
|
|
|
|
- splitLine: {
|
|
|
|
- lineStyle: {
|
|
|
|
- color: 'rgba(42, 59, 90, 0.3)',
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- series: [
|
|
|
|
- {
|
|
|
|
- name: '告警次数',
|
|
|
|
- type: 'line',
|
|
|
|
- smooth: true,
|
|
|
|
- symbol: 'circle',
|
|
|
|
- symbolSize: 8,
|
|
|
|
- data: alarmHistoryData.value.values,
|
|
|
|
- itemStyle: {
|
|
|
|
- color: '#f39c12',
|
|
|
|
- },
|
|
|
|
- lineStyle: {
|
|
|
|
- width: 3,
|
|
|
|
- color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
|
|
|
- { offset: 0, color: '#f39c12' },
|
|
|
|
- { offset: 1, color: '#e74c3c' },
|
|
|
|
- ]),
|
|
|
|
- },
|
|
|
|
- areaStyle: {
|
|
|
|
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
|
- { offset: 0, color: 'rgba(243, 156, 18, 0.3)' },
|
|
|
|
- { offset: 1, color: 'rgba(243, 156, 18, 0.1)' },
|
|
|
|
- ]),
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- ],
|
|
|
|
- })
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 历史跌倒统计图表
|
|
|
|
- if (fallingHistoryRef.value) {
|
|
|
|
- fallingHistoryChart = echarts.init(fallingHistoryRef.value)
|
|
|
|
- fallingHistoryChart.setOption({
|
|
|
|
- grid: { top: 10, right: 20, bottom: 30, left: 30 },
|
|
|
|
- tooltip: {
|
|
|
|
- trigger: 'axis',
|
|
|
|
- axisPointer: {
|
|
|
|
- type: 'shadow',
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- xAxis: {
|
|
|
|
- type: 'category',
|
|
|
|
- data: fallingHistoryData.value.dates,
|
|
|
|
- axisLine: {
|
|
|
|
- lineStyle: {
|
|
|
|
- color: '#2a3b5a',
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- axisLabel: {
|
|
|
|
- color: '#9cc5e0',
|
|
|
|
- fontSize: 12,
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- yAxis: {
|
|
|
|
- type: 'value',
|
|
|
|
- axisLine: {
|
|
|
|
- lineStyle: {
|
|
|
|
- color: '#2a3b5a',
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- axisLabel: {
|
|
|
|
- color: '#9cc5e0',
|
|
|
|
- fontSize: 12,
|
|
|
|
- },
|
|
|
|
- splitLine: {
|
|
|
|
- lineStyle: {
|
|
|
|
- color: 'rgba(42, 59, 90, 0.3)',
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- series: [
|
|
|
|
- {
|
|
|
|
- name: '跌倒次数',
|
|
|
|
- type: 'line',
|
|
|
|
- smooth: true,
|
|
|
|
- symbol: 'circle',
|
|
|
|
- symbolSize: 8,
|
|
|
|
- data: fallingHistoryData.value.values,
|
|
|
|
- itemStyle: {
|
|
|
|
- color: '#e74c3c',
|
|
|
|
- },
|
|
|
|
- lineStyle: {
|
|
|
|
- width: 3,
|
|
|
|
- color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
|
|
|
- { offset: 0, color: '#e74c3c' },
|
|
|
|
- { offset: 1, color: '#c0392b' },
|
|
|
|
- ]),
|
|
|
|
- },
|
|
|
|
- areaStyle: {
|
|
|
|
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
|
- { offset: 0, color: 'rgba(231, 76, 60, 0.3)' },
|
|
|
|
- { offset: 1, color: 'rgba(231, 76, 60, 0.1)' },
|
|
|
|
- ]),
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- ],
|
|
|
|
- })
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// 更新图表数据
|
|
|
|
-// const updateChartData = () => {
|
|
|
|
-// // 模拟数据更新
|
|
|
|
-// todayData.value = {
|
|
|
|
-// detected: Math.max(
|
|
|
|
-// 100,
|
|
|
|
-// Math.min(200, todayData.value.detected + Math.floor(Math.random() * 10 - 5))
|
|
|
|
-// ),
|
|
|
|
-// activity: Math.max(
|
|
|
|
-// 60,
|
|
|
|
-// Math.min(95, todayData.value.activity + Math.floor(Math.random() * 5 - 2))
|
|
|
|
-// ),
|
|
|
|
-// alerts: Math.max(0, Math.min(10, todayData.value.alerts + Math.floor(Math.random() * 3 - 1))),
|
|
|
|
-// onlineRate: Math.max(
|
|
|
|
-// 90,
|
|
|
|
-// Math.min(100, todayData.value.onlineRate + Math.floor(Math.random() * 3 - 1))
|
|
|
|
-// ),
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-
|
|
|
|
-// 组件挂载时初始化
|
|
|
|
-onMounted(() => {
|
|
|
|
- updateTime()
|
|
|
|
- initCharts()
|
|
|
|
-
|
|
|
|
- // 设置定时器
|
|
|
|
- setInterval(updateTime, 1000)
|
|
|
|
-
|
|
|
|
- // 移除对已注释函数的调用
|
|
|
|
- // updateInterval = setInterval(updateChartData, 5000)
|
|
|
|
-
|
|
|
|
- // 窗口大小变化时调整图表大小
|
|
|
|
- const handleResize = () => {
|
|
|
|
- // 调整安装位置图表大小
|
|
|
|
- if (deviceChart && deviceChartRef.value) {
|
|
|
|
- // 强制重新计算容器大小
|
|
|
|
- const containerWidth = deviceChartRef.value.offsetWidth
|
|
|
|
- const containerHeight = deviceChartRef.value.offsetHeight
|
|
|
|
-
|
|
|
|
- // 确保有有效的尺寸
|
|
|
|
- if (containerWidth > 0 && containerHeight > 0) {
|
|
|
|
- deviceChart.resize()
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 调整设备年龄层次图表大小
|
|
|
|
- if (ageChart && ageChartRef.value) {
|
|
|
|
- const containerWidth = ageChartRef.value.offsetWidth
|
|
|
|
- const containerHeight = ageChartRef.value.offsetHeight
|
|
|
|
-
|
|
|
|
- if (containerWidth > 0 && containerHeight > 0) {
|
|
|
|
- ageChart.resize()
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 调整检测对象图表大小
|
|
|
|
- if (objectChart && objectChartRef.value) {
|
|
|
|
- const containerWidth = objectChartRef.value.offsetWidth
|
|
|
|
- const containerHeight = objectChartRef.value.offsetHeight
|
|
|
|
-
|
|
|
|
- if (containerWidth > 0 && containerHeight > 0) {
|
|
|
|
- objectChart.resize()
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 调整历史告警统计图表大小
|
|
|
|
- if (alarmHistoryChart && alarmHistoryRef.value) {
|
|
|
|
- const containerWidth = alarmHistoryRef.value.offsetWidth
|
|
|
|
- const containerHeight = alarmHistoryRef.value.offsetHeight
|
|
|
|
-
|
|
|
|
- if (containerWidth > 0 && containerHeight > 0) {
|
|
|
|
- alarmHistoryChart.resize()
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 调整历史跌倒统计图表大小
|
|
|
|
- if (fallingHistoryChart && fallingHistoryRef.value) {
|
|
|
|
- const containerWidth = fallingHistoryRef.value.offsetWidth
|
|
|
|
- const containerHeight = fallingHistoryRef.value.offsetHeight
|
|
|
|
-
|
|
|
|
- if (containerWidth > 0 && containerHeight > 0) {
|
|
|
|
- fallingHistoryChart.resize()
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- window.addEventListener('resize', handleResize)
|
|
|
|
-
|
|
|
|
- // 组件挂载后立即触发一次调整,确保图表正确显示
|
|
|
|
- setTimeout(() => {
|
|
|
|
- handleResize()
|
|
|
|
- }, 100)
|
|
|
|
-})
|
|
|
|
-
|
|
|
|
-// 组件卸载时清理
|
|
|
|
-onUnmounted(() => {
|
|
|
|
- if (updateInterval) {
|
|
|
|
- clearInterval(updateInterval)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (deviceChart) {
|
|
|
|
- deviceChart.dispose()
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (ageChart) {
|
|
|
|
- ageChart.dispose()
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (objectChart) {
|
|
|
|
- objectChart.dispose()
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (alarmHistoryChart) {
|
|
|
|
- alarmHistoryChart.dispose()
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (fallingHistoryChart) {
|
|
|
|
- fallingHistoryChart.dispose()
|
|
|
|
- }
|
|
|
|
-})
|
|
|
|
-</script>
|
|
|
|
-
|
|
|
|
-<style lang="less" scoped>
|
|
|
|
-@bg-color: #22284a;
|
|
|
|
-@text-color: #e0e0e0;
|
|
|
|
-@panel-bg: #0b173f;
|
|
|
|
-@border-color: #2a3b5a;
|
|
|
|
-@primary-color: #4dc9e6;
|
|
|
|
-@secondary-color: #6de4ff;
|
|
|
|
-@accent-color: #2572ed;
|
|
|
|
-@success-color: #2ecc71;
|
|
|
|
-@warning-color: #f39c12;
|
|
|
|
-@danger-color: #e74c3c;
|
|
|
|
-@gradient-start: #181c41;
|
|
|
|
-@gradient-end: #22284a;
|
|
|
|
-@glow-color: rgba(77, 201, 230, 0.2);
|
|
|
|
-@data-flow-color: rgba(77, 201, 230, 0.7);
|
|
|
|
-
|
|
|
|
-* {
|
|
|
|
- margin: 0;
|
|
|
|
- padding: 0;
|
|
|
|
- box-sizing: border-box;
|
|
|
|
- font-family: 'Microsoft YaHei', Arial, sans-serif;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.radar-monitoring-screen {
|
|
|
|
- background-color: @bg-color;
|
|
|
|
- color: @text-color;
|
|
|
|
- overflow: hidden;
|
|
|
|
- height: 100vh;
|
|
|
|
- padding: 12px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* 顶部区域 */
|
|
|
|
-.header {
|
|
|
|
- height: 70px;
|
|
|
|
- display: flex;
|
|
|
|
- justify-content: space-between;
|
|
|
|
- align-items: center;
|
|
|
|
- padding: 0 20px;
|
|
|
|
- // background: linear-gradient(90deg, rgba(19, 28, 51, 0.8) 0%, rgba(32, 40, 65, 0.8) 100%);
|
|
|
|
- background-color: @panel-bg;
|
|
|
|
- border: 1px solid @border-color;
|
|
|
|
- border-radius: 8px;
|
|
|
|
- box-shadow: 0 0 15px rgba(0, 180, 255, 0.2);
|
|
|
|
- margin-bottom: 12px;
|
|
|
|
- position: relative;
|
|
|
|
- overflow: hidden;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.system-name {
|
|
|
|
- font-size: 24px;
|
|
|
|
- background: linear-gradient(90deg, @primary-color, @secondary-color);
|
|
|
|
- -webkit-background-clip: text;
|
|
|
|
- -webkit-text-fill-color: transparent;
|
|
|
|
- text-shadow: 0 0 10px rgba(109, 228, 255, 0.5);
|
|
|
|
- letter-spacing: 2px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.running-days {
|
|
|
|
- font-size: 22px;
|
|
|
|
- color: @secondary-color;
|
|
|
|
- text-shadow: 0 0 8px rgba(109, 228, 255, 0.7);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.time-info {
|
|
|
|
- font-size: 16px;
|
|
|
|
- color: @primary-color;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* 内容区域 */
|
|
|
|
-.content-area {
|
|
|
|
- display: flex;
|
|
|
|
- height: calc(100vh - 110px);
|
|
|
|
- gap: 12px;
|
|
|
|
- margin-bottom: 12px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.panel {
|
|
|
|
- flex: 1;
|
|
|
|
- background: @panel-bg;
|
|
|
|
- border: 1px solid @border-color;
|
|
|
|
- border-radius: 8px;
|
|
|
|
- padding: 15px;
|
|
|
|
- box-shadow: 0 0 15px rgba(0, 180, 255, 0.1);
|
|
|
|
- display: flex;
|
|
|
|
- flex-direction: column;
|
|
|
|
- position: relative;
|
|
|
|
- overflow: hidden;
|
|
|
|
-
|
|
|
|
- &::after {
|
|
|
|
- content: '';
|
|
|
|
- position: absolute;
|
|
|
|
- top: 0;
|
|
|
|
- left: 0;
|
|
|
|
- right: 0;
|
|
|
|
- height: 3px;
|
|
|
|
- background: linear-gradient(90deg, @primary-color, @accent-color);
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.panel-title {
|
|
|
|
- font-size: 16px;
|
|
|
|
- color: @secondary-color;
|
|
|
|
- margin-bottom: 15px;
|
|
|
|
- display: flex;
|
|
|
|
- align-items: center;
|
|
|
|
- padding-bottom: 8px;
|
|
|
|
- border-bottom: 1px solid rgba(42, 59, 90, 0.5);
|
|
|
|
-
|
|
|
|
- i {
|
|
|
|
- margin-right: 8px;
|
|
|
|
- font-size: 18px;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.panel-content {
|
|
|
|
- flex: 1;
|
|
|
|
- overflow: hidden;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.center-panel {
|
|
|
|
- flex: 1.5;
|
|
|
|
- display: flex;
|
|
|
|
- justify-content: center;
|
|
|
|
- align-items: center;
|
|
|
|
- background: #0b173f;
|
|
|
|
- min-width: min-content;
|
|
|
|
- height: 100%;
|
|
|
|
- position: relative;
|
|
|
|
- padding: 10px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* 地图容器 - 作为标记点的相对定位参考系 */
|
|
|
|
-.map-container {
|
|
|
|
- position: relative;
|
|
|
|
- display: inline-block;
|
|
|
|
- // width: 100%;
|
|
|
|
- // height: 100%;
|
|
|
|
- // max-width: 600px;
|
|
|
|
- // max-height: 400px;
|
|
|
|
- border-radius: 6px;
|
|
|
|
- overflow: hidden;
|
|
|
|
- background-color: #2ecc71;
|
|
|
|
- /* 确保容器有明确的宽高,以便内部元素可以基于百分比定位 */
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* 地图图片 - 确保图片始终完全显示在容器内 */
|
|
|
|
-.map-img {
|
|
|
|
- width: 100%;
|
|
|
|
- height: 100%;
|
|
|
|
- object-fit: contain;
|
|
|
|
- display: block;
|
|
|
|
- border-radius: 6px;
|
|
|
|
- /* 确保图片不会超出容器,同时保持原始比例 */
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* 地图标签基础样式 - 确保基于地图容器的相对定位 */
|
|
|
|
-.map-label {
|
|
|
|
- position: absolute;
|
|
|
|
- background: rgba(32, 40, 65, 0.9);
|
|
|
|
- border: 1px solid @border-color;
|
|
|
|
- border-radius: 4px;
|
|
|
|
- padding: 4px 8px;
|
|
|
|
- font-size: 14px;
|
|
|
|
- color: @secondary-color;
|
|
|
|
- font-weight: bold;
|
|
|
|
- text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
|
|
|
|
- z-index: 10;
|
|
|
|
- transform: translate(-50%, -50%);
|
|
|
|
- animation: pulse 2s infinite;
|
|
|
|
- pointer-events: none;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* 小区名称特殊样式 */
|
|
|
|
-.map-label:not([class*='building-']) {
|
|
|
|
- top: 10%;
|
|
|
|
- left: 50%;
|
|
|
|
- background: rgba(77, 201, 230, 0.9);
|
|
|
|
- color: #000;
|
|
|
|
- font-size: 18px;
|
|
|
|
- padding: 6px 12px;
|
|
|
|
- border: 2px solid #fff;
|
|
|
|
- animation: glow 2s infinite alternate;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* 建筑位置 - 使用百分比定位确保基于图片相对位置 */
|
|
|
|
-.building-1 {
|
|
|
|
- top: 30%;
|
|
|
|
- left: 30%;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.building-2 {
|
|
|
|
- top: 50%;
|
|
|
|
- left: 70%;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.building-3 {
|
|
|
|
- top: 70%;
|
|
|
|
- left: 50%;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.building-4 {
|
|
|
|
- top: 40%;
|
|
|
|
- left: 20%;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* 位置标记动画效果 */
|
|
|
|
-@keyframes pulse {
|
|
|
|
- 0% {
|
|
|
|
- transform: translate(-50%, -50%) scale(1);
|
|
|
|
- box-shadow: 0 0 0 0 rgba(77, 201, 230, 0.4);
|
|
|
|
- }
|
|
|
|
- 70% {
|
|
|
|
- transform: translate(-50%, -50%) scale(1.05);
|
|
|
|
- box-shadow: 0 0 0 5px rgba(77, 201, 230, 0);
|
|
|
|
- }
|
|
|
|
- 100% {
|
|
|
|
- transform: translate(-50%, -50%) scale(1);
|
|
|
|
- box-shadow: 0 0 0 0 rgba(77, 201, 230, 0);
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* 小区名称发光效果 */
|
|
|
|
-@keyframes glow {
|
|
|
|
- from {
|
|
|
|
- box-shadow: 0 0 5px rgba(77, 201, 230, 0.7);
|
|
|
|
- }
|
|
|
|
- to {
|
|
|
|
- box-shadow:
|
|
|
|
- 0 0 15px rgba(77, 201, 230, 1),
|
|
|
|
- 0 0 20px rgba(77, 201, 230, 0.7);
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.data-grid {
|
|
|
|
- display: grid;
|
|
|
|
- grid-template-columns: 1fr 1fr;
|
|
|
|
- gap: 12px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.chart-container {
|
|
|
|
- width: 100%;
|
|
|
|
- height: 200px; /* 设置固定高度 */
|
|
|
|
- min-height: 200px; /* 确保最小高度 */
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.status-list {
|
|
|
|
- list-style: none;
|
|
|
|
- max-height: 250px;
|
|
|
|
- overflow-y: auto;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* 底部区域 */
|
|
|
|
-.footer {
|
|
|
|
- height: 50px;
|
|
|
|
- display: flex;
|
|
|
|
- justify-content: center;
|
|
|
|
- align-items: center;
|
|
|
|
- background: @panel-bg;
|
|
|
|
- border: 1px solid @border-color;
|
|
|
|
- border-radius: 8px;
|
|
|
|
- color: @primary-color;
|
|
|
|
- font-size: 14px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.glow-effect {
|
|
|
|
- position: absolute;
|
|
|
|
- width: 100%;
|
|
|
|
- height: 100%;
|
|
|
|
- top: 0;
|
|
|
|
- left: 0;
|
|
|
|
- pointer-events: none;
|
|
|
|
- background:
|
|
|
|
- radial-gradient(circle at 20% 30%, rgba(37, 114, 237, 0.1) 0%, transparent 50%),
|
|
|
|
- radial-gradient(circle at 80% 70%, rgba(77, 201, 230, 0.1) 0%, transparent 50%);
|
|
|
|
- z-index: -1;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.data-flow {
|
|
|
|
- position: absolute;
|
|
|
|
- bottom: 0;
|
|
|
|
- left: 0;
|
|
|
|
- width: 100%;
|
|
|
|
- height: 3px;
|
|
|
|
- background: linear-gradient(90deg, transparent, rgba(77, 201, 230, 0.7), transparent);
|
|
|
|
- animation: dataFlow 3s linear infinite;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-@keyframes dataFlow {
|
|
|
|
- 0% {
|
|
|
|
- transform: translateX(-100%);
|
|
|
|
- }
|
|
|
|
- 100% {
|
|
|
|
- transform: translateX(100%);
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-</style>
|
|
|