Files
maimaiDX-API-Web-Server/frontend/src/views/LogsView.vue

182 lines
5.6 KiB
Vue

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import axios from 'axios'
import { ElMessage } from 'element-plus'
import LogViewer from '@/components/LogViewer.vue'
import logger, { getLogBuffer, saveLogsToFile } from '@/utils/logger'
const backendLogs = ref<any[]>([])
const frontendLogs = ref<any[]>(getLogBuffer())
const isLoading = ref(false)
const autoRefresh = ref(false)
const refreshInterval = ref<NodeJS.Timeout | null>(null)
const apiBaseUrl = `http://${window.location.hostname}:8000/api`
// 获取后端日志
async function fetchBackendLogs() {
isLoading.value = true
try {
logger.logInfo('Fetching backend logs')
const { data } = await axios.get(`${apiBaseUrl}/logs`)
if (data.error) {
throw new Error(data.error)
}
backendLogs.value = data.logs || []
ElMessage.success('后端日志获取成功')
} catch (e: any) {
logger.logError('Failed to fetch backend logs', e)
ElMessage.error('获取后端日志失败: ' + (e.response?.data?.detail || e.message))
// 使用模拟数据
backendLogs.value = [
{ timestamp: new Date().toISOString(), level: 'INFO', message: 'Backend started successfully' },
{ timestamp: new Date().toISOString(), level: 'INFO', message: 'Aime scan request received' },
{ timestamp: new Date().toISOString(), level: 'WARN', message: 'QR content validation failed' }
]
} finally {
isLoading.value = false
}
}
// 刷新所有日志
function refreshLogs() {
frontendLogs.value = getLogBuffer()
fetchBackendLogs()
}
// 开始自动刷新
function startAutoRefresh() {
if (refreshInterval.value) {
clearInterval(refreshInterval.value)
}
refreshInterval.value = setInterval(() => {
refreshLogs()
}, 5000) // 每5秒刷新一次
}
// 停止自动刷新
function stopAutoRefresh() {
if (refreshInterval.value) {
clearInterval(refreshInterval.value)
refreshInterval.value = null
}
}
// 切换自动刷新
function toggleAutoRefresh() {
if (autoRefresh.value) {
startAutoRefresh()
} else {
stopAutoRefresh()
}
}
// 保存日志到文件
function saveLogs() {
saveLogsToFile()
ElMessage.success('日志已保存到文件')
}
// 组件挂载时的操作
onMounted(() => {
refreshLogs()
})
// 组件卸载时的操作
onUnmounted(() => {
stopAutoRefresh()
})
</script>
<template>
<div class="logs-view">
<el-card header="系统日志" style="width: 100%;">
<div class="toolbar">
<el-button type="primary" @click="refreshLogs" :loading="isLoading">刷新日志</el-button>
<el-checkbox v-model="autoRefresh" @change="toggleAutoRefresh">自动刷新</el-checkbox>
<el-button @click="clearFrontendLogs">清空前端日志</el-button>
<el-button @click="saveLogs">保存日志到文件</el-button>
</div>
<el-tabs type="border-card">
<el-tab-pane label="前端日志">
<el-table :data="frontendLogs" stripe style="width: 100%" height="500">
<el-table-column prop="timestamp" label="时间" width="180">
<template #default="scope">
{{ new Date(scope.row.timestamp).toLocaleString() }}
</template>
</el-table-column>
<el-table-column prop="level" label="级别" width="80">
<template #default="scope">
<el-tag :type="scope.row.level === 'ERROR' ? 'danger' :
scope.row.level === 'WARN' ? 'warning' :
scope.row.level === 'INFO' ? 'success' : 'info'">
{{ scope.row.level }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="message" label="消息" />
<el-table-column prop="data" label="数据" width="200">
<template #default="scope">
<el-popover
v-if="scope.row.data"
placement="left"
:width="300"
trigger="hover"
>
<template #reference>
<el-button size="small">查看数据</el-button>
</template>
<pre>{{ JSON.stringify(scope.row.data, null, 2) }}</pre>
</el-popover>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="后端日志">
<el-table :data="backendLogs" stripe style="width: 100%" height="500">
<el-table-column prop="timestamp" label="时间" width="180">
<template #default="scope">
{{ new Date(scope.row.timestamp).toLocaleString() }}
</template>
</el-table-column>
<el-table-column prop="level" label="级别" width="80">
<template #default="scope">
<el-tag :type="scope.row.level === 'ERROR' ? 'danger' :
scope.row.level === 'WARN' ? 'warning' :
scope.row.level === 'INFO' ? 'success' : 'info'">
{{ scope.row.level }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="message" label="消息" />
</el-table>
</el-tab-pane>
</el-tabs>
</el-card>
</div>
</template>
<style scoped>
.logs-view {
padding: 20px;
}
.toolbar {
margin-bottom: 20px;
display: flex;
gap: 10px;
align-items: center;
}
pre {
white-space: pre-wrap;
word-wrap: break-word;
background-color: #f4f4f5;
padding: 10px;
border-radius: 4px;
max-height: 300px;
overflow-y: auto;
}
</style>