feat:日志报警页面更新

This commit is contained in:
吉浩茹
2025-10-01 04:07:37 +08:00
parent deb4d99393
commit 5f20cc7cd3
7 changed files with 833 additions and 516 deletions

View File

@ -25,8 +25,8 @@
<view class="table-cell header-cell type-column">种类</view>
<view class="table-cell header-cell time-column">时间</view>
<view class="table-cell header-cell level-column">级别</view>
<view class="table-cell header-cell action-column">处置</view>
<view class="table-cell header-cell action-time-column">时间</view>
<!-- <view class="table-cell header-cell action-column">处置</view> -->
<!-- <view class="table-cell header-cell action-time-column">时间</view> -->
</view>
<!-- 表格内容 -->
@ -55,11 +55,12 @@
<view class="table-cell content-column">{{ alarm.content }}</view>
<view class="table-cell type-column">{{ alarm.type }}</view>
<view class="table-cell time-column">{{ alarm.time }}</view>
<view class="table-cell level-column" :class="getLevelClass(alarm.level)">
<!-- <view class="table-cell level-column" :class="getLevelClass(alarm.level)"> -->
<view class="table-cell level-column">
{{ alarm.level }}
</view>
<view class="table-cell action-column">{{ alarm.action }}</view>
<view class="table-cell action-time-column">{{ alarm.actionTime }}</view>
<!-- <view class="table-cell action-column">{{ alarm.action }}</view> -->
<!-- <view class="table-cell action-time-column">{{ alarm.actionTime }}</view> -->
</view>
</template>
@ -73,6 +74,17 @@
<text class="table-empty-text">暂无数据</text>
</view>
<!-- 加载更多提示 -->
<view class="load-more-container" v-if="isLoadingMore">
<view class="load-more-spinner"></view>
<text class="load-more-text">正在加载更多...</text>
</view>
<!-- 没有更多数据提示 -->
<!-- <view class="no-more-container" v-if="!hasMoreData && alarmList.length > 0 && !isLoadingMore">
<text class="no-more-text">已加载全部数据</text>
</view> -->
<!-- 底部间距确保最后一条记录完全显示 -->
<view class="table-bottom-spacing"></view>
</scroll-view>
@ -84,6 +96,7 @@
<script setup>
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue';
import { alertApi, eventApi } from '@/utils/api.js';
// 报警数据
const alarmList = ref([]);
@ -91,6 +104,12 @@ const isLoading = ref(false);
const isConnected = ref(false);
const hasInitialized = ref(false);
// 分页相关
const currentPage = ref(0);
const pageSize = ref(20);
const hasMoreData = ref(true);
const isLoadingMore = ref(false);
// 滚动相关
const scrollTop = ref(0);
const isScrolling = ref(false);
@ -100,167 +119,107 @@ const isScrolling = ref(false);
// MQTT报警服务接口预留
const mqttAlarmService = {
// 连接MQTT服务器
connect: async () => {
console.log('MQTT报警服务连接中...');
try {
// 模拟连接延迟
await new Promise(resolve => setTimeout(resolve, 1000));
isConnected.value = true;
console.log('MQTT报警服务连接成功');
return Promise.resolve();
} catch (error) {
console.error('MQTT报警连接失败:', error);
isConnected.value = false;
return Promise.reject(error);
}
},
// connect: async () => {
// console.log('MQTT报警服务连接中...');
// try {
// // 模拟连接延迟
// await new Promise(resolve => setTimeout(resolve, 1000));
// isConnected.value = true;
// console.log('MQTT报警服务连接成功');
// return Promise.resolve();
// } catch (error) {
// console.error('MQTT报警连接失败:', error);
// isConnected.value = false;
// return Promise.reject(error);
// }
// },
// 订阅报警数据
subscribeAlarmData: () => {
console.log('订阅系统报警数据');
// 这里后期会实现真实的MQTT报警订阅
return Promise.resolve();
},
// subscribeAlarmData: () => {
// console.log('订阅系统报警数据');
// // 这里后期会实现真实的MQTT报警订阅
// return Promise.resolve();
// },
// 获取历史报警记录
getHistoryAlarms: async (limit = 50) => {
console.log(`获取历史报警记录,限制${limit}`);
// 获取历史报警记录(分页)
getHistoryAlarms: async (page = 0, size = 20, isLoadMore = false) => {
console.log(`获取历史报警记录,页码:${page}, 每页:${size}`);
try {
isLoading.value = true;
hasInitialized.value = true;
// 模拟请求延迟
await new Promise(resolve => setTimeout(resolve, 800));
if (!isLoadMore) {
isLoading.value = true;
hasInitialized.value = true;
} else {
isLoadingMore.value = true;
}
// 模拟报警数据
const mockAlarms = [
{
content: '湿度45%超标',
type: '参数超标',
time: '2025-9-3-12:01',
level: 'A',
action: '恢复',
actionTime: '2025-9-3-13:11'
},
{
content: '温度28℃过高',
type: '参数超标',
time: '2025-9-3-11:45',
level: 'B',
action: '调整',
actionTime: '2025-9-3-12:30'
},
{
content: '洁净度异常',
type: '环境异常',
time: '2025-9-3-11:20',
level: 'A',
action: '清理',
actionTime: '2025-9-3-11:50'
},
{
content: '设备通讯中断',
type: '设备故障',
time: '2025-9-3-10:55',
level: 'C',
action: '重启',
actionTime: '2025-9-3-11:05'
},
{
content: '压力值偏低',
type: '参数异常',
time: '2025-9-3-10:30',
level: 'B',
action: '检查',
actionTime: '2025-9-3-10:45'
},
{
content: '电源电压不稳',
type: '电气故障',
time: '2025-9-3-10:10',
level: 'A',
action: '更换',
actionTime: '2025-9-3-10:25'
},
{
content: '传感器数据异常',
type: '设备异常',
time: '2025-9-3-09:50',
level: 'B',
action: '校准',
actionTime: '2025-9-3-10:00'
},
{
content: '网络连接超时',
type: '通讯故障',
time: '2025-9-3-09:30',
level: 'C',
action: '重连',
actionTime: '2025-9-3-09:35'
},
{
content: '内存使用率过高',
type: '系统异常',
time: '2025-9-3-09:15',
level: 'B',
action: '清理',
actionTime: '2025-9-3-09:20'
},
{
content: '磁盘空间不足',
type: '存储异常',
time: '2025-9-3-09:00',
level: 'A',
action: '扩容',
actionTime: '2025-9-3-09:10'
},
{
content: 'CPU温度过高',
type: '硬件故障',
time: '2025-9-3-08:45',
level: 'A',
action: '散热',
actionTime: '2025-9-3-08:50'
},
{
content: '数据库连接失败',
type: '数据异常',
time: '2025-9-3-08:30',
level: 'B',
action: '修复',
actionTime: '2025-9-3-08:35'
},
{
content: '配置文件损坏',
type: '配置异常',
time: '2025-9-3-08:15',
level: 'C',
action: '恢复',
actionTime: '2025-9-3-08:20'
},
{
content: '服务进程异常',
type: '进程故障',
time: '2025-9-3-08:00',
level: 'B',
action: '重启',
actionTime: '2025-9-3-08:05'
},
{
content: '日志文件过大',
type: '存储异常',
time: '2025-9-3-07:45',
level: 'C',
action: '压缩',
actionTime: '2025-9-3-07:50'
// 调用分页获取告警接口
const response = await alertApi.getList({
page: page,
size: size
});
console.log('📊 获取告警数据响应:', response);
// 处理响应数据
if (response && response.data) {
const newAlarms = response.data.map(item => ({
content: item.content || '未知报警',
type: item.category || '未知类型',
time: formatDateTime(item.alertTime) || '未知时间',
level: mapLevelToDisplay(item.level) || 'C',
action: item.action || '待处理',
actionTime: formatDateTime(item.actionTime) || '未知时间'
}));
if (isLoadMore) {
// 加载更多时追加数据
alarmList.value = [...alarmList.value, ...newAlarms];
} else {
// 首次加载时替换数据
alarmList.value = newAlarms;
}
];
// 判断是否还有更多数据
hasMoreData.value = newAlarms.length === size;
currentPage.value = page;
// 保存查询事件(只在首次加载时保存)
if (!isLoadMore) {
await createQueryEvent('success', newAlarms.length);
}
} else {
console.warn('⚠️ 响应数据格式异常:', response);
if (!isLoadMore) {
alarmList.value = [];
}
hasMoreData.value = false;
// 保存查询事件(无数据)
if (!isLoadMore) {
await createQueryEvent('empty', 0);
}
}
alarmList.value = mockAlarms;
isLoading.value = false;
return Promise.resolve(mockAlarms);
isLoadingMore.value = false;
return Promise.resolve(response);
} catch (error) {
console.error('获取历史报警记录失败:', error);
console.error('获取历史报警记录失败:', error);
isLoading.value = false;
isLoadingMore.value = false;
// 保存查询事件(错误)
if (!isLoadMore) {
await createQueryEvent('error', 0);
}
// 显示错误提示
uni.showToast({
title: '获取报警记录失败',
icon: 'error',
duration: 2000
});
return Promise.reject(error);
}
},
@ -367,6 +326,39 @@ const mqttAlarmService = {
}
};
// 映射报警级别到显示格式
const mapLevelToDisplay = (level) => {
const levelMap = {
'高危': 'A',
'中危': 'B',
'低危': 'C',
'high': 'A',
'medium': 'B',
'low': 'C'
};
return levelMap[level] || 'C';
};
// 格式化时间
const formatDateTime = (dateString) => {
if (!dateString) return '未知时间';
try {
const date = new Date(dateString);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
} catch (error) {
console.error('时间格式化失败:', error);
return dateString; // 如果格式化失败,返回原始字符串
}
};
// 获取级别样式类
const getLevelClass = (level) => {
switch (level) {
@ -400,8 +392,19 @@ const onScroll = (e) => {
};
const onScrollToLower = () => {
console.log('滚动到底部');
// 可以在这里添加加载更多数据的逻辑
console.log('滚动到底部,尝试加载更多数据');
// 如果正在加载或没有更多数据,则不处理
if (isLoadingMore.value || !hasMoreData.value) {
console.log('正在加载中或无更多数据,跳过');
return;
}
// 加载下一页数据
const nextPage = currentPage.value + 1;
console.log(`📄 加载第${nextPage}页数据`);
mqttAlarmService.getHistoryAlarms(nextPage, pageSize.value, true);
};
// 滚动到顶部
@ -442,16 +445,78 @@ const stopRealtimeAlarm = () => {
}
};
// 创建查询事件
const createQueryEvent = async (status, dataCount) => {
try {
const currentTime = formatDateTime(new Date().toISOString())
const queryEvent = {
eventType: "报警记录查询",
eventTime: currentTime,
status: getEventStatus(status),
description: getEventDescription(status, dataCount),
deviceId: "ALARM_QUERY_001"
}
console.log('📤 提交报警查询事件:', queryEvent)
const response = await eventApi.create(queryEvent)
console.log('✅ 报警查询事件创建成功:', response)
} catch (error) {
console.error('❌ 报警查询事件创建失败:', error)
}
};
// 获取事件状态
const getEventStatus = (status) => {
const statusMap = {
'success': '已完成',
'empty': '已完成',
'error': '失败'
};
return statusMap[status] || '未知';
};
// 获取事件描述
const getEventDescription = (status, dataCount) => {
const descriptions = {
'success': `成功查询到${dataCount}条报警记录数据`,
'empty': '查询报警记录,但未找到数据',
'error': '查询报警记录时发生错误'
};
return descriptions[status] || '未知查询状态';
};
// 刷新数据方法
const refreshData = async () => {
console.log('🔄 刷新报警记录数据')
try {
// 重置分页状态
currentPage.value = 0;
hasMoreData.value = true;
alarmList.value = [];
// 重新获取第一页数据
await mqttAlarmService.getHistoryAlarms(0, pageSize.value, false);
} catch (error) {
console.error('❌ 刷新数据失败:', error);
}
};
// 暴露方法给父组件
defineExpose({
refreshData
});
// 组件生命周期
onMounted(async () => {
try {
// 连接MQTT并初始化
await mqttAlarmService.connect();
await mqttAlarmService.subscribeAlarmData();
await mqttAlarmService.getHistoryAlarms();
// await mqttAlarmService.connect();
// await mqttAlarmService.subscribeAlarmData();
await mqttAlarmService.getHistoryAlarms(0, pageSize.value, false);
// 开始实时报警获取
startRealtimeAlarm();
// startRealtimeAlarm();
} catch (error) {
console.error('报警系统初始化失败:', error);
uni.showToast({
@ -838,4 +903,44 @@ onUnmounted(() => {
font-size: 30rpx;
}
}
// 加载更多样式
.load-more-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 30rpx 20rpx;
gap: 15rpx;
background-color: #ffffff;
}
.load-more-spinner {
width: 40rpx;
height: 40rpx;
border: 3rpx solid #e8eaed;
border-top: 3rpx solid #5f6368;
border-radius: 50%;
animation: spin 1s linear infinite;
}
.load-more-text {
font-size: 24rpx;
color: #5f6368;
font-weight: 400;
}
.no-more-container {
display: flex;
justify-content: center;
align-items: center;
padding: 30rpx 20rpx;
background-color: #ffffff;
}
.no-more-text {
font-size: 24rpx;
color: #9aa0a6;
font-weight: 400;
}
</style>