Files
local_alert/src/components/Max/LeftBottom.vue
2024-11-11 15:37:46 +08:00

431 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="alert-container">
<div class="title-count">
<!-- <el-row class="title-row">
今日事件列表
</el-row> -->
<el-row class="total-row">
<div class="total-text">
今日告警
</div>
<div class="total-text">
{{ totalItems }}
</div>
</el-row>
</div>
<el-row class="table-row">
<el-col :span="24" class="table-col">
<div class="table-container">
<el-table :data="tableData" @row-click="handleRowClick" class="table-part">
<el-table-column v-show="false" prop="id" label="告警编号" v-if="false"></el-table-column>
<el-table-column label="告警类型" :width="adjustedWidths[0]" align="center"
:show-overflow-tooltip="true">
<template v-slot="scope">
{{ typeMapping[scope.row.types] }}
</template>
</el-table-column>
<el-table-column prop="camera.name" label="告警位置" :width="adjustedWidths[1]" align="center"
:show-overflow-tooltip="true"></el-table-column>
<el-table-column label="告警时间" :width="adjustedWidths[2]" align="center"
:show-overflow-tooltip="true">
<template v-slot="scope">
{{ formatDateTime(scope.row.ended_at) }}
</template>
</el-table-column>
<el-table-column prop="status" label="告警状态" v-if="false">
<template v-slot="scope">
<el-tag :type="scope.row.status === 'pending' ? 'warning' : 'success'">{{
statusMapping[scope.row.status]
}}</el-tag>
</template>
</el-table-column>
</el-table>
</div>
</el-col>
</el-row>
<!-- <el-row class="table-row">
<el-col :span="24" class="table-col">
<div class="table-container">
<dv-scroll-board :config="tableConfig" class="table-part" @row-click="handleRowClick"></dv-scroll-board>
</div>
</el-col>
</el-row> -->
<!-- <div class="adjusted-widths-display">
当前列宽: {{ adjustedWidths.join(', ') }}
</div> -->
<el-dialog v-model="dialogVisible" title="告警详情" width="50%" class="dialog-container">
<div>
<el-row class="dialog-row">
<!-- 左侧告警图片和图片信息 -->
<el-col :span="12" class="dialog-left">
<el-row gutter class="dialog-image-container">
<!-- 根据 mediumType 显示视频或图片确保只显示一种或两种 -->
<template v-if="hasSnapshot">
<el-image :src="snapshotFile"></el-image>
</template>
<template v-if="hasVideo">
<video :src="videoFile" controls></video>
</template>
</el-row>
</el-col>
<!-- 右侧告警信息 -->
<el-col :span="11" class="dialog-right">
<el-row>
<el-col :span="24">
<p>告警编号: {{ selectedRow.id }}</p>
</el-col>
<el-col :span="24">
<p>告警类型: {{ typeMapping[selectedRow.types] }}</p>
</el-col>
<el-col :span="24">
<p>告警位置: {{ selectedRow.camera.name }}</p>
</el-col>
<el-col :span="24">
<p>告警时间: {{ selectedRow.formatted_started_at }}</p>
</el-col>
<el-col :span="24">
<p>告警状态: <el-tag :type="selectedRow.status === 'pending' ? 'warning' : 'success'">{{
statusMapping[selectedRow.status]
}}</el-tag></p>
</el-col>
<el-col :span="24">
<p>摄像头编号: {{ selectedRow.camera_id }}</p>
</el-col>
<el-col :span="24">
<p>持续时间: {{ duration }}</p>
</el-col>
<!-- <el-col :span="24">
<p>备注: {{ selectedRow.remark }}</p>
</el-col> -->
<!-- <el-col :span="24">
<el-form-item style="width: 90%;">
<el-input v-model="remark" placeholder="请描述事件原因" type="textarea" rows="5" :disabled="true"></el-input>
</el-form-item>
</el-col> -->
</el-row>
</el-col>
</el-row>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue';
import { BoxApi } from '@/utils/boxApi.ts';
const boxApi = new BoxApi();
const tableData = ref([]);
const dialogVisible = ref(false);
const remark = ref("");
const selectedRow = ref({});
const typeMapping = reactive({});
const currentPage = ref(1);
const pageSize = ref(20);
const totalItems = ref(0);
const displayTotalItems = ref(0);
const token = ref(null);
const apiInstance = new BoxApi();
const statusMapping = {
'pending': '待处理',
'assigned': '处理中',
'closed': '已处理'
};
const duration = ref('');
const hasSnapshot = ref(false);
const hasVideo = ref(false);
const snapshotFile = ref("");
const videoFile = ref("");
const originalWidths = [97, 150, 160]; // 默认宽度
const adjustedWidths = ref([...originalWidths]);
const baseWidth = 2150;
const adjustColumnWidths = () => {
const currentWidth = window.innerWidth;
// console.log(">>>>>>>>>>", currentWidth);
const scale = currentWidth / baseWidth;
// console.log(">>>>>>>>>>", scale);
// const adjustedScale = Math.max(scale, 0.5);
adjustedWidths.value = originalWidths.map(width => {
return currentWidth < baseWidth
? width * scale // 缩小
: width * scale; // 放大
});
// nextTick(() => {
// });
};
// const tableConfig = ref({
// header: ['告警类型', '告警位置', '告警时间'],
// data: [],
// rowNum: 5,
// columnWidth: [100, 160, 190],
// carousel: 'single',
// });
const fetchTypeMapping = async (token) => {
try {
const algorithms = await boxApi.getAlgorithms(token);
// console.log("Algorithms:", algorithms);
algorithms.forEach((algorithm) => {
typeMapping[algorithm.code_name] = algorithm.name;
});
} catch (error) {
console.error("Error fetching algorithms:", error);
}
};
const fetchEvents = async () => {
try {
const token = localStorage.getItem('alertToken');
const limit = 1000;
let allEvents = [];
let currentPage = 1;
const { endOfToday, startOfToday } = getDateParams();
const timeBefore = formatDateTime(endOfToday);
const timeAfter = formatDateTime(startOfToday);
// console.log("Start of today:", timeAfter);
// const firstResponse = await apiInstance.getEventsByParams(token, limit, currentPage);
const firstResponse = await apiInstance.getEventsByParams(token, limit, currentPage,timeBefore, timeAfter);
// console.log("Total items:", firstResponse);
const total = firstResponse.count;
totalItems.value = total;
allEvents = firstResponse.results;
while (allEvents.length < total) {
currentPage += 1;
const response = await apiInstance.getEventsByParams(token, limit, currentPage);
allEvents = allEvents.concat(response.results);
}
tableData.value = allEvents;
// tableConfig.value.data = allEvents.map(event => [
// typeMapping[event.types],
// event.camera.name,
// formatDateTime(event.ended_at)
// ]);
// console.log(">>>>>>>>>>events IDs:", allEvents.map(event => event.id));
} catch (error) {
console.error("Error fetching events data:", error);
}
};
const getDateParams = () => {
const today = new Date();
const startOfToday = new Date(today.getFullYear(), today.getMonth(), today.getDate());
const endOfToday = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1);
return {
startOfToday,
endOfToday,
};
};
const formatDateTime = (datetime) => {
const date = new Date(datetime);
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
const hours = date.getHours().toString().padStart(2, '0');
const minutes = date.getMinutes().toString().padStart(2, '0');
const seconds = date.getSeconds().toString().padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
};
const calculateDuration = (started_at, ended_at) => {
const start = new Date(started_at);
const end = new Date(ended_at);
const durationMs = end - start;
const minutes = Math.floor(durationMs / 60000);
const seconds = ((durationMs % 60000) / 1000).toFixed(0);
return `${minutes}${seconds < 10 ? '0' : ''}${seconds}`;
};
const handleRowClick = (row) => {
selectedRow.value = row;
duration.value = calculateDuration(row.started_at, row.ended_at);
row.formatted_started_at = formatDateTime(row.started_at);
// 重置媒体类型
hasSnapshot.value = false;
hasVideo.value = false;
snapshotFile.value = "";
videoFile.value = "";
// 判断并设置媒体文件路径
row.mediums.forEach((medium) => {
if (medium.name === "snapshot") {
hasSnapshot.value = true;
snapshotFile.value = medium.file;
} else if (medium.name === "video") {
hasVideo.value = true;
videoFile.value = medium.file;
}
});
dialogVisible.value = true;
};
const handlePageChange = (page) => {
currentPage.value = page;
fetchEvents();
};
// const calculateColumnWidths = () => {
// const containerWidth = document.querySelector('.table-container').clientWidth;
// };
onMounted(async () => {
token.value = localStorage.getItem('alertToken');
await fetchTypeMapping(token.value);
await fetchEvents();
await adjustColumnWidths();
window.addEventListener('resize', adjustColumnWidths);
});
onBeforeUnmount(() => {
window.removeEventListener('resize', adjustColumnWidths);
});
</script>
<style scoped>
.alert-container {
display: flex;
flex-direction: column;
align-items: center;
width: 90%;
height: 100%;
margin: 0 0 0 1vw;
box-sizing: border-box;
background-color: transparent;
}
.table-continer {
width: 100%;
height: 100%;
box-sizing: border-box;
}
.table-row:hover {
cursor: pointer;
}
.title-count {
width: 80%;
text-align: center;
/* background-color: transparent; */
}
/* .total-text{
padding-right: 1vw;
} */
/* title-row内容水平上下居中 */
.title-row {
display: flex;
align-items: center;
justify-content: center;
}
/* total-row左右等分分别靠左和靠右 */
.total-row {
display: flex;
/* justify-content: space-between; */
justify-content: right;
font-weight: bold;
font-size: 14px;
padding-right: 0vw;
}
.dialog-row {
gap: 30px;
display: flex;
text-align: left;
flex-direction: row;
}
.dialog-image-container {
gap: 20px;
}
.el-dialog .el-image,
.el-dialog video {
width: 100%;
}
/* 基础表格样式 */
::v-deep .el-table {
color: white;
font-size: 13px;
/* font-weight: bold; */
background-color: transparent;
padding: 0;
margin: 0;
height: 14vh;
}
/* 表头和单元格基本样式 */
::v-deep .el-table td {
border: none;
background-color: #001529;
transition: border 0.3s ease, background-color 0.3s ease;
color: white;
padding: 0;
/* height: 10px; */
/* white-space: nowrap; */
/* overflow: hidden; */
/* text-overflow: ellipsis; */
}
/* 去掉中间数据的分割线 */
/* ::v-deep .el-table .el-table__row>td{
border: none;
} */
.table-container >>> .el-table__row>td{
border: none;
}
.table-container >>> .el-table th.is-leaf{
border: none;
}
::v-deep .el-table__inner-wrapper::before{
height: 0;
}
::v-deep .el-table thead th {
color: white;
font-weight: bold;
background-color: #001529;
padding: 0;
}
::v-deep .el-table .el-table__cell:hover {
background-color: transparent;
color: rgb(238, 150, 49);
/* font-size: 26px; */
/* 保持文本为白色 */
}
.el-tooltip__popper {
font-size: 26px;
max-width:50%
}
</style>