feat: improve polling recovery and session cleanup
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref } from "vue";
|
||||
import { computed, onBeforeUnmount, onMounted, reactive, ref } from "vue";
|
||||
import apiClient, { getApiErrorMessage } from "@/api/client";
|
||||
import { useViewport } from "@/composables/useViewport";
|
||||
import type { SystemLog } from "@/types";
|
||||
import { logLevelLabelMap } from "@/types";
|
||||
|
||||
const AUTO_REFRESH_INTERVAL_MS = 15000;
|
||||
|
||||
const loading = ref(false);
|
||||
const logs = ref<SystemLog[]>([]);
|
||||
const loadError = ref("");
|
||||
@@ -26,7 +28,13 @@ const totalWarnings = computed(() => logs.value.filter((item) => item.level ===
|
||||
const totalErrors = computed(() => logs.value.filter((item) => item.level === 3).length);
|
||||
const newestLogTime = computed(() => (logs.value[0] ? formatDate(logs.value[0].createdAt) : "-"));
|
||||
|
||||
let autoRefreshTimer: number | null = null;
|
||||
|
||||
async function loadLogs() {
|
||||
if (loading.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
loadError.value = "";
|
||||
|
||||
@@ -48,6 +56,34 @@ async function loadLogs() {
|
||||
}
|
||||
}
|
||||
|
||||
async function autoRefreshLogs() {
|
||||
if (document.visibilityState !== "visible") {
|
||||
return;
|
||||
}
|
||||
|
||||
await loadLogs();
|
||||
}
|
||||
|
||||
function startAutoRefresh() {
|
||||
stopAutoRefresh();
|
||||
autoRefreshTimer = window.setInterval(() => {
|
||||
void autoRefreshLogs();
|
||||
}, AUTO_REFRESH_INTERVAL_MS);
|
||||
}
|
||||
|
||||
function stopAutoRefresh() {
|
||||
if (autoRefreshTimer !== null) {
|
||||
window.clearInterval(autoRefreshTimer);
|
||||
autoRefreshTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function handleVisibilityChange() {
|
||||
if (document.visibilityState === "visible") {
|
||||
void autoRefreshLogs();
|
||||
}
|
||||
}
|
||||
|
||||
function levelTagType(level: number) {
|
||||
if (level === 3) {
|
||||
return "danger";
|
||||
@@ -64,7 +100,16 @@ function formatDate(value?: string) {
|
||||
return value ? new Date(value).toLocaleString() : "-";
|
||||
}
|
||||
|
||||
onMounted(loadLogs);
|
||||
onMounted(async () => {
|
||||
await loadLogs();
|
||||
startAutoRefresh();
|
||||
document.addEventListener("visibilitychange", handleVisibilityChange);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
stopAutoRefresh();
|
||||
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -74,7 +119,7 @@ onMounted(loadLogs);
|
||||
<div class="page-kicker">排障中心</div>
|
||||
<h1 class="page-title">系统日志</h1>
|
||||
<p class="page-subtitle">
|
||||
面向排障的原始事件流。这里保留最近发生的关键日志,可以按直播间、任务和级别快速收缩范围。
|
||||
面向排障的原始事件流。这里保留最近发生的关键日志,可以按直播间、任务和级别快速缩小范围。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -103,7 +148,7 @@ onMounted(loadLogs);
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-card__label">最新事件</div>
|
||||
<div class="stat-card__value" style="font-size: 18px; letter-spacing: -0.03em;">{{ newestLogTime }}</div>
|
||||
<div class="stat-card__value" style="font-size: 18px;">{{ newestLogTime }}</div>
|
||||
<div class="stat-card__hint">默认按时间倒序,优先展示最近发生的事件。</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -146,7 +191,7 @@ onMounted(loadLogs);
|
||||
<div class="toolbar-row">
|
||||
<div>
|
||||
<h3 class="section-title">日志列表</h3>
|
||||
<p class="section-subtitle">桌面端保留高密度表格,移动端切成事件卡片,便于单手排查。</p>
|
||||
<p class="section-subtitle">页面会自动刷新,移动端改成事件卡片,桌面端保留高密度表格。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user