Files
par/web/src/views/ApiLogs.vue

106 lines
4.3 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>
<h2>API 访问日志</h2>
<!-- 筛选 -->
<el-card style="margin-top:16px">
<el-form :inline="true" :model="filter" size="small">
<el-form-item label="邮箱"><el-input v-model="filter.email" placeholder="支持模糊搜索" clearable /></el-form-item>
<el-form-item label="路径"><el-input v-model="filter.path" placeholder="/api/v1/..." clearable /></el-form-item>
<el-form-item label="状态"><el-select v-model="filter.success" clearable placeholder="全部"><el-option label="成功" :value="true" /><el-option label="失败" :value="false" /></el-select></el-form-item>
<el-form-item><el-button type="primary" @click="fetchLogs">查询</el-button></el-form-item>
</el-form>
</el-card>
<!-- 统计 -->
<el-row :gutter="16" style="margin-top:16px">
<el-col :span="12">
<el-card header="按调用方统计(24h)">
<el-table :data="emailStats" size="small">
<el-table-column prop="email" label="邮箱" />
<el-table-column prop="cnt" label="总次数" width="80" />
<el-table-column prop="ok" label="成功" width="60" />
<el-table-column prop="err" label="失败" width="60" />
</el-table>
</el-card>
</el-col>
<el-col :span="12">
<el-card header="按接口统计(24h)">
<el-table :data="pathStats" size="small">
<el-table-column prop="path" label="路径" />
<el-table-column prop="cnt" label="次数" width="80" />
<el-table-column prop="avg_ms" label="平均耗时" width="80">
<template #default="scope">{{ Math.round(scope.row.avg_ms) }}ms</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
</el-row>
<!-- 日志列表 -->
<el-card style="margin-top:16px">
<el-table :data="logs" v-loading="loading" size="small" stripe>
<el-table-column prop="method" label="方法" width="60" />
<el-table-column prop="path" label="路径" min-width="160" />
<el-table-column prop="email" label="邮箱" width="160" />
<el-table-column prop="clientIp" label="IP" width="120" />
<el-table-column prop="pskVersion" label="PSK版本" width="90" />
<el-table-column label="User-Agent" min-width="140">
<template #default="scope">
<span class="text-xs text-muted">{{ scope.row.userAgent || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="状态" width="70">
<template #default="scope">
<el-tag size="small" :type="scope.row.success ? 'success' : 'danger'">{{ scope.row.statusCode }}</el-tag>
</template>
</el-table-column>
<el-table-column label="耗时" width="70">
<template #default="scope">{{ scope.row.responseMs }}ms</template>
</el-table-column>
<el-table-column label="错误" min-width="150">
<template #default="scope">
<span v-if="scope.row.errorMessage" style="color:#f56c6c;font-size:12px">{{ scope.row.errorMessage }}</span>
</template>
</el-table-column>
<el-table-column prop="createdAt" label="时间" width="160" />
</el-table>
<div style="margin-top:12px;text-align:center">
<el-pagination small background layout="prev,next" :total="total" :page-size="filter.size" v-model:current-page="filter.page" @current-change="fetchLogs" />
</div>
</el-card>
</div>
</template>
<script setup>
import api from '../api'
const logs = ref([]), loading = ref(false), total = ref(0)
const emailStats = ref([]), pathStats = ref([])
const filter = reactive({ page: 1, size: 50, email: '', path: '', success: null })
const fetchLogs = async () => {
loading.value = true
try {
const r = await api.logs.list(filter)
logs.value = r.data.records || []
total.value = r.data.total || 0
} catch { ElMessage.error('获取日志失败') }
finally { loading.value = false }
}
const fetchStats = async () => {
try {
const [e, p] = await Promise.all([api.logs.emailStats(), api.logs.pathStats()])
emailStats.value = e.data || []
pathStats.value = p.data || []
} catch {}
}
onMounted(() => { fetchLogs(); fetchStats() })
</script>
<style scoped>
.text-muted { color: #909399; }
</style>