摄像头组件页面
This commit is contained in:
parent
b00dac74de
commit
c8f02faaa7
|
@ -0,0 +1,238 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-card class="camera-card">
|
||||||
|
<el-row :gutter="20" class="camera-row">
|
||||||
|
<!-- 左侧块:通道列表 -->
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-card class="channel-card" shadow="hover">
|
||||||
|
<div class="section-title">通道</div>
|
||||||
|
<div class="scroll-container">
|
||||||
|
<el-table :data="cameras" style="width: 100%;" height="250">
|
||||||
|
<el-table-column prop="id" label="ID" width="100"></el-table-column>
|
||||||
|
<el-table-column prop="name" label="名称"></el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<!-- 中间块:摄像头总数量 -->
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-card class="count-card" shadow="hover">
|
||||||
|
<div class="section-title">摄像数量</div>
|
||||||
|
<div class="camera-count-chart"></div>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<!-- 右侧块:在线/离线/异常状态 -->
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-card class="online-card" shadow="hover">
|
||||||
|
<div class="section-title">在线情况</div>
|
||||||
|
<div class="status-summary-chart"></div>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
import * as echarts from 'echarts';
|
||||||
|
import { BoxApi } from '@/utils/boxApi.ts';
|
||||||
|
|
||||||
|
const cameras = ref([]);
|
||||||
|
const cameraCount = ref(0);
|
||||||
|
const onlineCount = ref(0);
|
||||||
|
const offlineCount = ref(0);
|
||||||
|
const exceptionCount = ref(0);
|
||||||
|
|
||||||
|
const apiInstance = new BoxApi();
|
||||||
|
|
||||||
|
// 分页获取摄像头数据,直到获取所有摄像头数据
|
||||||
|
const fetchCameras = async () => {
|
||||||
|
try {
|
||||||
|
const token = localStorage.getItem('alertToken');
|
||||||
|
const limit = 20; // 每次请求 20 条数据
|
||||||
|
let offset = 0; // 从 0 开始
|
||||||
|
let allCameras = [];
|
||||||
|
|
||||||
|
// 第一次请求,用于获取总数
|
||||||
|
const firstResponse = await apiInstance.getCameras(limit, offset, token);
|
||||||
|
cameraCount.value = firstResponse.count;
|
||||||
|
allCameras = firstResponse.results;
|
||||||
|
|
||||||
|
// 根据总数继续请求剩余的数据
|
||||||
|
const total = cameraCount.value;
|
||||||
|
while (offset + limit < total) {
|
||||||
|
offset += limit;
|
||||||
|
const response = await apiInstance.getCameras(limit, offset, token);
|
||||||
|
allCameras = allCameras.concat(response.results);
|
||||||
|
}
|
||||||
|
|
||||||
|
cameras.value = allCameras;
|
||||||
|
|
||||||
|
// 统计在线、离线和异常的摄像头数量
|
||||||
|
allCameras.forEach(camera => {
|
||||||
|
if (camera.status === 'online') {
|
||||||
|
onlineCount.value++;
|
||||||
|
} else if (camera.status === 'offline') {
|
||||||
|
offlineCount.value++;
|
||||||
|
} else {
|
||||||
|
exceptionCount.value++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化中间的摄像头总数圆环图
|
||||||
|
initCountChart(cameraCount.value);
|
||||||
|
|
||||||
|
// 初始化右侧的在线/离线/异常圆环图
|
||||||
|
initStatusSummaryChart(onlineCount.value, offlineCount.value, exceptionCount.value);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching cameras:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化摄像头总数圆环图
|
||||||
|
const initCountChart = (count) => {
|
||||||
|
const chartDom = document.querySelector('.camera-count-chart');
|
||||||
|
const myChart = echarts.init(chartDom);
|
||||||
|
|
||||||
|
const option = {
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'pie',
|
||||||
|
radius: ['40%', '60%'],
|
||||||
|
avoidLabelOverlap: false,
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
position: 'center',
|
||||||
|
formatter: '{c}',
|
||||||
|
fontSize: 24,
|
||||||
|
},
|
||||||
|
data: [
|
||||||
|
{ value: count, name: '总数' }
|
||||||
|
],
|
||||||
|
itemStyle: {
|
||||||
|
color: 'rgba(80,160,225, 1)'
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
myChart.setOption(option);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化在线/离线/异常状态圆环图
|
||||||
|
const initStatusSummaryChart = (online, offline, exception) => {
|
||||||
|
const chartDom = document.querySelector('.status-summary-chart');
|
||||||
|
const myChart = echarts.init(chartDom);
|
||||||
|
|
||||||
|
const option = {
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'pie',
|
||||||
|
radius: ['40%', '60%'],
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
formatter: '{b}: {c} ({d}%)'
|
||||||
|
},
|
||||||
|
data: [
|
||||||
|
{ value: online, name: '在线' },
|
||||||
|
{ value: offline, name: '离线' },
|
||||||
|
{ value: exception, name: '异常' }
|
||||||
|
],
|
||||||
|
itemStyle: {
|
||||||
|
color: 'rgba(5,192,145, 1)'
|
||||||
|
// color: 'rgba(255,151,75, 1)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
myChart.setOption(option);
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchCameras();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.camera-card {
|
||||||
|
/* background-color: #abcef1; */
|
||||||
|
/* background-color: linear-gradient(to top, rgba(150, 206, 243, 0.2), rgba(214, 240, 250, 0.3)); */
|
||||||
|
color: #fff;
|
||||||
|
/* border-radius: 8px; */
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel-card {
|
||||||
|
background: linear-gradient(to top, rgba(150, 206, 243, 1), rgba(125, 29, 235, 0.3));
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.count-card {
|
||||||
|
background: linear-gradient(to bottom, rgba(246, 130, 85, 1), rgba(252, 186, 38, 0.3));
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.online-card {
|
||||||
|
background: linear-gradient(to top, rgba(112, 158, 228, 1), rgba(87, 204, 243, 0.3));
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.camera-header {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
border-bottom: 1px solid #3a4b5c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.camera-row {
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-card {
|
||||||
|
padding: 0;
|
||||||
|
text-align: center;
|
||||||
|
background-color: azure
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-container {
|
||||||
|
height: 180px;
|
||||||
|
/* overflow-y: scroll; */
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* .scroll-container::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
} */
|
||||||
|
|
||||||
|
.status-summary-chart,
|
||||||
|
.camera-count-chart {
|
||||||
|
width: 100%;
|
||||||
|
height: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-table {
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-table th {
|
||||||
|
background-color: #f5f7fa; /* 表头背景色 */
|
||||||
|
color: #333; /* 表头字体颜色 */
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center; /* 居中对齐 */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue