DataStatistics数据显示页面---test.vue中测试全局弹窗提示

This commit is contained in:
龚皓
2024-11-14 16:07:42 +08:00
parent a2234922c8
commit fd75d299ec
24 changed files with 3637 additions and 1582 deletions

View File

@@ -8,40 +8,52 @@
<alertChart />
</el-col>
</el-row> -->
<el-row class="middle-row">
<!-- <el-row class="middle-row">
<span>
告警总数:{{ displayTotalItems }}
</span>
</el-row>
</el-row> -->
<el-row class="filter-row">
<el-col :span="5">
<el-col :span="4">
<el-form-item label="摄像头名称">
<el-select v-model="filterParams.cameraId" placeholder="请选择摄像头" filterable>
<el-select v-model="filterParams.cameraId" placeholder="请选择摄像头" filterable clearable>
<el-option v-for="camera in cameras" :key="camera.id" :label="camera.name" :value="camera.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="4">
</el-col>
<el-col :span="3">
<el-form-item label="告警类型">
<el-select v-model="filterParams.types" placeholder="请选择告警类型">
<el-select v-model="filterParams.types" placeholder="请选择类型" clearable>
<el-option v-for="(label, key) in typeMapping" :key="key" :label="label" :value="key"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="5">
<el-col :span="3">
<el-form-item label="处理情况">
<el-select v-model="filterParams.status" placeholder="全部" clearable>
<el-option label="全部" value=""></el-option>
<el-option label="待处理" value="pending"></el-option>
<el-option label="已处理" value="closed"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="开始时间">
<el-date-picker v-model="filterParams.timeAfter" type="datetime" placeholder="请选择开始时间"></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="5">
<el-col :span="4">
<el-form-item label="结束时间">
<el-date-picker v-model="filterParams.timeBefore" type="datetime" placeholder="请选择结束时间"></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="2" class="filter-buttons">
<el-col :span="4" class="filter-buttons">
<el-button type="primary" @click="handleFilter">查询</el-button>
<el-button @click="handleReset">重置</el-button>
<el-button :disabled="isExporting" @click="exportData">
{{ isExporting ? '正在导出请勿重复点击' : '导出' }}
</el-button>
</el-col>
</el-row>
@@ -181,6 +193,9 @@ import { ref, reactive, onMounted, computed } from 'vue';
// import AlertChart from '@/components/AlertChart.vue';
import { BoxApi } from '@/utils/boxApi.ts'; // 导入 BoxApi
import { saveAs } from 'file-saver';
import Papa from 'papaparse';
// 创建 BoxApi 实例
const boxApi = new BoxApi();
@@ -208,6 +223,66 @@ const totalItems = ref(0);
const displayTotalItems = ref(0); // 用于展示的数字
const cameras = ref([]);
const formatDateTimeToISO = (datetime) => {
return new Date(datetime).toISOString().replace('.000', '');
};
const isExporting = ref(false);
// 导出数据方法
const exportData = async () => {
if (isExporting.value) return; // 如果已经在导出,直接返回,避免重复点击
isExporting.value = true; // 设置为正在导出状态
try {
const allData = [];
let page = 1;
let totalPages = 1;
const limit = 500;
// 循环分页请求所有数据
do {
const { results, count } = await boxApi.getEventsByParams(
token.value,
limit,
page,
filterParams.timeBefore ? formatDateTimeToISO(filterParams.timeBefore) : null,
filterParams.timeAfter ? formatDateTimeToISO(filterParams.timeAfter) : null,
filterParams.types,
filterParams.cameraId,
filterParams.status
);
// 格式化数据
const formattedData = results.map(item => ({
'告警编号': item.id,
'告警类型': typeMapping[item.types] || item.types,
'告警位置': item.camera ? item.camera.name : '',
'告警时间': formatDateTime(item.ended_at),
'告警状态': statusMapping[item.status] || item.status
}));
allData.push(...formattedData);
totalPages = Math.ceil(count / limit);
page += 1;
} while (page <= totalPages);
// 使用 PapaParse 将 JSON 转换为 CSV指定列标题
const csv = Papa.unparse(allData, {
columns: ['告警编号', '告警类型', '告警位置', '告警时间', '告警状态']
});
// 添加 BOM确保中文编码正确
const blob = new Blob(["\uFEFF" + csv], { type: 'text/csv;charset=utf-8;' });
saveAs(blob, 'Alert_data.csv');
} catch (error) {
console.error("导出数据错误:", error);
}finally {
isExporting.value = false;
}
};
const fetchCameras = async () => {
try {
const token = localStorage.getItem('alertToken');
@@ -240,6 +315,8 @@ const filterParams = reactive({
types: null,
timeAfter: null,
timeBefore: null,
cameraId: null,
status: null,
});
@@ -273,9 +350,10 @@ const handleFilter = async () => {
const types = filterParams.types || null;
// const timeAfter = filterParams.timeAfter ? new Date(filterParams.timeAfter).toISOString() : null;
// const timeBefore = filterParams.timeBefore ? new Date(filterParams.timeBefore).toISOString() : null;
const timeAfter = filterParams.timeAfter ? formatDateTime(new Date(filterParams.timeAfter)) : null;
const timeBefore = filterParams.timeBefore ? formatDateTime(new Date(filterParams.timeBefore)) : null;
const timeAfter = filterParams.timeAfter ? formatDateTimeToISO(new Date(filterParams.timeAfter)) : null;
const timeBefore = filterParams.timeBefore ? formatDateTimeToISO(new Date(filterParams.timeBefore)) : null;
const cameraId = filterParams.cameraId || null;
const status = filterParams.status || null;
const { results, count } = await boxApi.getEventsByParams(
token.value,
@@ -284,7 +362,8 @@ const handleFilter = async () => {
timeBefore,
timeAfter,
types,
cameraId
cameraId,
status
);
tableData.value = results;
totalItems.value = count;
@@ -298,6 +377,7 @@ const handleReset = () => {
filterParams.timeAfter = null;
filterParams.timeBefore = null;
filterParams.cameraId = null;
filterParams.status = null;
fetchEvents(); // 重置筛选条件后,重新获取所有告警数据
};
@@ -386,7 +466,7 @@ const closeDialog = () => {
// 分页处理
const handlePageChange = (page) => {
currentPage.value = page;
if (filterParams.types || filterParams.timeAfter || filterParams.timeBefore) {
if (filterParams.types || filterParams.timeAfter || filterParams.timeBefore || filterParams.cameraId || filterParams.status) {
handleFilter();
} else {
fetchEvents();
@@ -434,7 +514,9 @@ onMounted(async () => {
.alert-container {
padding: 0;
margin: 0;
background-color: #f5f7fa;
background-color: #001529;
overflow-y: auto;
height: 100%;
}
/* .top-pan {
@@ -453,7 +535,7 @@ onMounted(async () => {
border-radius: 15px;
} */
.middle-row {
/* .middle-row {
min-height: 5vw;
display: flex;
justify-content: center;
@@ -461,14 +543,43 @@ onMounted(async () => {
font-size: 30px;
font-weight: bold;
background: linear-gradient(to bottom left, rgb(150, 151, 243), rgb(215, 214, 250));
/* border-radius: 8px; */
border-radius: 8px;
} */
.filter-row {
display: flex;
justify-content: center;
align-content: center;
height: 15vh;
padding: 0px 0;
margin: 5vh 6vw 5vh 1vw;
gap: 8px;
/* font-weight: bold; */
font-size: 15px;
background-color: rgb(251, 254, 255);
border-radius: 8px;
}
.table-container {
max-width: 100%;
height: 80%;
/* min-height: 50vh; */
/* max-height: 70vh; */
overflow-x: auto;
margin: 0vh 6vw 0vh 1vw;
padding: 0;
overflow-y: hidden;
border-radius: 8px 8px 0 0;
background-color: white;
}
.pagination-container {
display: flex;
justify-content: flex-start;
background-color: #e9eefc;
padding-left: 20px;
margin: 0vh 6vw 5vh 1vw;
}
.table-header {
@@ -477,8 +588,8 @@ onMounted(async () => {
}
::v-deep .el-table th.el-table__cell {
background-color: #000;
color: #fff;
background-color: #e9eefca4;
color: #000;
}
.event-media {
@@ -522,12 +633,7 @@ onMounted(async () => {
font-weight: bold;
}
.pagination-container {
display: flex;
justify-content: flex-start;
background-color: #e8e9e4;
padding-left: 20px;
}
::v-deep .pagination-container .el-pagination__total,
::v-deep .pagination-container .el-pagination__goto,
@@ -541,15 +647,4 @@ onMounted(async () => {
align-items: center;
margin-top: 20px;
}
.filter-row {
display: flex;
justify-content: center;
align-content: center;
height: 80px;
padding: 20px;
margin-top: 20px;
gap: 20px;
font-weight: bold;
}
</style>