DataStatistics数据显示页面---test.vue中测试全局弹窗提示
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user