forked from GuChen/maimaiDX-API-Web-Server
Initial commit: Add maimaiDX API web application with AimeDB scanning and logging features
This commit is contained in:
182
frontend/src/views/LogsView.vue
Normal file
182
frontend/src/views/LogsView.vue
Normal file
@@ -0,0 +1,182 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user