告警列表

This commit is contained in:
龚皓 2024-09-30 15:48:48 +08:00
parent 8acedde40f
commit 677804fbf6
1 changed files with 166 additions and 201 deletions

View File

@ -1,28 +1,42 @@
<template> <template>
<div class="home"> <div class="alert-container">
<el-row> <el-row class="top-pan">
<el-col :span="16"> <el-col :sm="24" :md="12" class="panel-section">
<statistics />
</el-col>
<el-col :sm="24" :md="12" class="panel-section">
<alertChart />
</el-col>
</el-row>
<el-row class="middle-row">
<span>
告警总数:{{ totalItems }}
</span>
</el-row>
<el-row class="table-row">
<el-col :span="24">
<div class="table-container"> <div class="table-container">
<el-table :data="paginatedData"> <el-table :data="tableData" style="width:100%; height: 100%;" header-row-class-name="table-header"
<el-table-column prop="id" label="告警编号" width="140"></el-table-column> :fit="true">
<el-table-column label="告警类型" width="140"> <el-table-column prop="id" label="告警编号" min-width="100"></el-table-column>
<el-table-column label="告警类型" min-width="150">
<template v-slot="scope"> <template v-slot="scope">
<!-- {{ typeMapping[scope.row.types] || codenameTranslate(scope.row.types) }} -->
{{ typeMapping[scope.row.types] }} {{ typeMapping[scope.row.types] }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="camera.name" label="告警位置" width="180"></el-table-column> <el-table-column prop="camera.name" label="告警位置" min-width="150"></el-table-column>
<el-table-column label="告警时间" width="180"> <el-table-column label="告警时间" min-width="200">
<template v-slot="scope"> <template v-slot="scope">
{{ formatDateTime(scope.row.started_at) }} {{ formatDateTime(scope.row.ended_at) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="status" label="告警状态" width="140"> <el-table-column prop="status" label="告警状态" min-width="100">
<template v-slot="scope"> <template v-slot="scope">
<el-tag :type="scope.row.status === 'pending' ? 'warning' : 'success'">{{ statusMapping[scope.row.status] }}</el-tag> <el-tag :type="scope.row.status === 'pending' ? 'warning' : 'success'">{{ statusMapping[scope.row.status]
}}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="140"> <el-table-column label="操作" min-width="100">
<template v-slot="scope"> <template v-slot="scope">
<el-button type="text" @click="handleView(scope.row)">查看</el-button> <el-button type="text" @click="handleView(scope.row)">查看</el-button>
</template> </template>
@ -30,23 +44,11 @@
</el-table> </el-table>
</div> </div>
<div class="pagination-container"> <div class="pagination-container">
<el-pagination background layout="total, sizes, prev, pager, next, jumper" :total="tableData.length" <el-pagination @size-change="handleSizeChange" @current-change="handlePageChange" :current-page="currentPage"
:page-size="pageSize" :current-page.sync="currentPage" @current-change="handlePageChange" :page-size="pageSize" :total="totalItems" layout="total, sizes, prev, pager, next, jumper">
@size-change="handleSizeChange">
</el-pagination> </el-pagination>
</div> </div>
</el-col> </el-col>
<el-col :span="8">
<div class="right-panel">
<div class="panel-section">
<statistics />
</div>
<div class="panel-section">
<alertChart />
</div>
</div>
</el-col>
</el-row> </el-row>
<el-dialog v-model="dialogVisible" title="告警详情" width="80%"> <el-dialog v-model="dialogVisible" title="告警详情" width="80%">
<div> <div>
@ -55,7 +57,6 @@
<p>告警编号: {{ selectedRow.id }}</p> <p>告警编号: {{ selectedRow.id }}</p>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<!-- <p>告警类型: {{ typeMapping[selectedRow.types] || codenameTranslate(selectedRow.types) }}</p> -->
<p>告警类型: {{ typeMapping[selectedRow.types] }}</p> <p>告警类型: {{ typeMapping[selectedRow.types] }}</p>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
@ -67,7 +68,8 @@
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="6"> <el-col :span="6">
<p>告警状态: <el-tag :type="selectedRow.status === 'pending' ? 'warning' : 'success'">{{ statusMapping[selectedRow.status] <p>告警状态: <el-tag :type="selectedRow.status === 'pending' ? 'warning' : 'success'">{{
statusMapping[selectedRow.status]
}}</el-tag></p> }}</el-tag></p>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
@ -100,126 +102,88 @@
</div> </div>
</template> </template>
<script> <script setup>
import * as echarts from 'echarts'; import { ref, reactive, onMounted } from 'vue';
import Statistics from '@/components/Statistics.vue'; import Statistics from '@/components/Statistics.vue';
import AlertChart from '@/components/AlertChart.vue'; import AlertChart from '@/components/AlertChart.vue';
import { login, getEvents, initCodeNameMap, codenameTranslate, getAlgorithms } from '@/utils/superbox.js'; import { BoxApi } from '@/utils/boxApi.ts'; // BoxApi
const username = 'turingvideo'; // BoxApi
const password = '1234qwer!'; const boxApi = new BoxApi();
export default { //
name: 'AlertManagement', const tableData = ref([]);
components: { const dialogVisible = ref(false);
Statistics, const selectedRow = ref({});
AlertChart, const mediums = ref([]);
}, const duration = ref('');
data() { const typeMapping = reactive({});
return { const statusMapping = {
tableData: [],
dialogVisible: false,
selectedRow: {},
mediums: {},
duration: '',
typeMapping: {
// 'abnormal:525': '',
// 'car_blocking:512': '',
// 'car_blocking:514': '',
// 'escalator_status:518': '',
// 'gathering:520': '',
// 'gathering:521': '',
// 'intrude:513': '',
// 'long_term_door_status:526': '',
// 'lying_down:527': '',
// 'minizawu:531': '',
// 'minizawu:532': '',
// 'personnel_stay:535': '',
// 'vacant:524': '',
// 'zawu:516': '',
// 'zawu:517': '',
// 'zawu:519': '',
// 'zawu:523': '绿',
},
statusMapping: {
'pending': '待处理', 'pending': '待处理',
'closed': '已处理' 'closed': '已处理'
}, };
currentPage: 1, const currentPage = ref(1);
pageSize: 20, const pageSize = ref(20);
const totalItems = ref(0);
const token = ref(null);
} //
}, const fetchTypeMapping = async (token) => {
async created() {
try { try {
const token = await login(username, password); const algorithms = await boxApi.getAlgorithms(token); // 使 BoxApi getAlgorithms
// await initCodeNameMap(token); const additionalMappings = [{ code_name: 'minizawu:532', name: '杂物堆积' }];
this.tableData = await getEvents(token);
this.typeMapping = await this.fetchTypeMapping(token);
console.log(this.tableData);
} catch (error) {
console.error("Error fetching events:", error);
}
},
computed: {
paginatedData() {
const start = (this.currentPage - 1) * this.pageSize;
const end = start + this.pageSize;
return this.tableData.slice(start, end);
}
},
methods: {
async fetchTypeMapping(token) {
let algorithms = await getAlgorithms(token);
const additionalMappings = [
{ code_name: 'minizawu:532', name: '杂物堆积' },
];
algorithms = algorithms.concat(additionalMappings);
let mapping = {};
algorithms.forEach((algorithm) => { algorithms.forEach((algorithm) => {
mapping[algorithm.code_name] = algorithm.name; typeMapping[algorithm.code_name] = algorithm.name;
}); });
} catch (error) {
// console.log("mapping: ", mapping); console.error("Error fetching algorithms:", error);
return mapping;
},
handleView(row) {
this.selectedRow = row;
this.duration = this.calculateDuration(row.started_at, row.ended_at);
row.formatted_started_at = this.formatDateTime(row.started_at);
// console.log("duration: ", row.started_at);
// console.log("duration: ", row.ended_at);
// console.log("duration: ", this.duration);
this.dialogVisible = true;
this.mediums = row.mediums || {};
if (Array.isArray(row.mediums)) {
row.mediums.forEach(medium => {
// console.log("medium: ", medium.file);
// console.log("medium: ", medium.id);
});
} else {
// console.log("No mediums available");
} }
}, };
handlePageChange(page) {
this.currentPage = page; //
}, const fetchEvents = async () => {
handleSizeChange(size) { try {
this.pageSize = size; const { tableData: data, totalItems: total } = await boxApi.getEvents(token.value, pageSize.value, currentPage.value); // 使 BoxApi getEvents
}, tableData.value = data;
calculateDuration(started_at, ended_at) { totalItems.value = total;
} catch (error) {
console.error("Error fetching events data:", error);
}
};
//
const handleView = (row) => {
selectedRow.value = row;
duration.value = calculateDuration(row.started_at, row.ended_at);
row.formatted_started_at = formatDateTime(row.started_at);
dialogVisible.value = true;
mediums.value = row.mediums || [];
};
//
const handlePageChange = (page) => {
currentPage.value = page;
fetchEvents();
};
//
const handleSizeChange = (size) => {
pageSize.value = size;
fetchEvents();
};
//
const calculateDuration = (started_at, ended_at) => {
const start = new Date(started_at); const start = new Date(started_at);
const end = new Date(ended_at); const end = new Date(ended_at);
const duration = end - start; const durationMs = end - start;
const minutes = Math.floor(duration / 60000); const minutes = Math.floor(durationMs / 60000);
const seconds = ((duration % 60000) / 1000).toFixed(0); const seconds = ((durationMs % 60000) / 1000).toFixed(0);
return `${minutes}${(seconds < 10 ? '0' : '')}${seconds}`; return `${minutes}${seconds < 10 ? '0' : ''}${seconds}`;
}, };
formatDateTime(datetime) {
//
const formatDateTime = (datetime) => {
const date = new Date(datetime); const date = new Date(datetime);
const year = date.getFullYear(); const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0'); const month = (date.getMonth() + 1).toString().padStart(2, '0');
@ -228,94 +192,90 @@ export default {
const minutes = date.getMinutes().toString().padStart(2, '0'); const minutes = date.getMinutes().toString().padStart(2, '0');
const seconds = date.getSeconds().toString().padStart(2, '0'); const seconds = date.getSeconds().toString().padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
}
}; };
//
onMounted(async () => {
token.value = localStorage.getItem('alertToken');
await fetchTypeMapping(token.value);
await fetchEvents();
});
</script> </script>
<style scoped> <style scoped>
.home { .alert-container {
padding: 40px; padding: 0;
margin: 0;
background-color: #f5f7fa; background-color: #f5f7fa;
} }
.breadcrumb { .top-pan {
margin-bottom: 30px; padding: 0px;
} margin: 0px;
.top-scroll {
width: 100%;
overflow-x: auto;
}
.top-scroll-content {
/* 高度滚动条显示出来默认值 */
height: 1px;
}
.table-container {
width: 80%;
max-height: 1000px;
overflow-x: auto;
padding-left: 7%;
}
.right-panel {
display: flex; display: flex;
flex-direction: column; gap: 10px;
gap: 20px; background-color: #fff;
padding: 10px 10px 400px 10px; overflow: auto;
background-color: #f5f5f5;
height: 600px;
overflow-y: auto;
} }
.panel-section { .panel-section {
flex: 1; flex: 1;
background-color: #fff; background-color: #fff;
padding: 20px;
box-shadow: 0 20px 8px rgba(0, 0, 0, 0.1); box-shadow: 0 20px 8px rgba(0, 0, 0, 0.1);
border-radius: 15px;
}
.middle-row {
min-height: 5vw;
display: flex;
justify-content: center;
align-content: center;
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;
} }
/* 弹窗> 显示左右等分*/ .table-container {
width: 100%;
height: 380px;
min-height: 60%;
overflow-x: auto;
}
.table-header {
background-color: #f7f8fa;
font-weight: bold;
}
::v-deep .el-table th.el-table__cell {
background-color: #000;
color: #fff;
}
.event-media { .event-media {
/* display: flex;
flex-direction: column;
gap: 10px;
margin-top: 20px; */
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
/* 添加这个属性来左右等分 */
flex-wrap: wrap; flex-wrap: wrap;
} }
.media-container { .media-container {
flex: 0 0 48%; flex: 0 0 48%;
/* 确保每块区域占据一行的48% */
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
/* 使内容在区域内居中 */
margin-bottom: 20px; margin-bottom: 20px;
/* 添加底部间距,使多个元素之间有间隔 */
box-sizing: border-box; box-sizing: border-box;
/* 确保padding和border不会影响大小 */
padding: 10px; padding: 10px;
/* 添加内边距,使内容不靠近边框 */
} }
.video-item video, .video-item video,
.image-item img { .image-item img {
width: 100%; width: 100%;
/* 保证视频和图片在容器内等宽 */
height: auto; height: auto;
/* 保证视频和图片比例正常 */
border-radius: 8px; border-radius: 8px;
/* 圆润效果 */
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
/* 阴影效果 */
} }
.video-item p, .video-item p,
@ -328,7 +288,12 @@ export default {
.pagination-container { .pagination-container {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
margin-top: 20px; background-color: #e8e9e4;
margin-right: 150px; }
::v-deep .pagination-container .el-pagination__total,
::v-deep .pagination-container .el-pagination__goto,
::v-deep .pagination-container .el-pagination__classifier {
color: #000;
} }
</style> </style>