fix: 修复实时RPM/TPM指标显示为0的问题

- 添加调试日志以追踪数据读取过程
- 修复getRealtimeSystemMetrics中的数据验证逻辑
- 添加测试脚本用于验证时间戳匹配问题
- 改进错误处理和日志记录

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
shaw
2025-07-30 14:49:39 +08:00
parent a6ab6b7abe
commit 21461863af
3 changed files with 265 additions and 11 deletions

View File

@@ -1,5 +1,45 @@
<template>
<div>
<!-- 自动刷新控制栏 -->
<div class="mb-6 bg-white rounded-lg shadow-sm p-4">
<div class="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4">
<div class="flex items-center gap-2 sm:gap-4">
<h2 class="text-lg font-semibold text-gray-800">系统仪表盘</h2>
<div v-if="refreshCountdownDisplay" class="text-sm text-gray-500 whitespace-nowrap">
<i class="fas fa-clock"></i>
{{ refreshCountdownDisplay }}
</div>
</div>
<div class="flex items-center gap-2 sm:gap-4 w-full sm:w-auto">
<!-- 手动刷新按钮 -->
<button
@click="refreshAllData"
:disabled="isRefreshing"
class="px-4 py-2 text-sm bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
>
<i :class="['fas fa-sync-alt', { 'animate-spin': isRefreshing }]"></i>
{{ isRefreshing ? '刷新中...' : '刷新数据' }}
</button>
<!-- 自动刷新开关 -->
<div class="flex items-center gap-2">
<label class="flex items-center cursor-pointer">
<input
type="checkbox"
v-model="autoRefreshEnabled"
class="sr-only peer"
>
<div class="relative w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
<span class="ml-3 text-sm font-medium text-gray-700">
自动刷新
<span class="text-xs text-gray-500">(30)</span>
</span>
</label>
</div>
</div>
</div>
</div>
<!-- 主要统计 -->
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6 mb-8">
<div class="stat-card">
@@ -221,8 +261,13 @@
</span>
</div>
<button @click="refreshChartsData()" class="btn btn-primary px-4 py-2 flex items-center gap-2">
<i class="fas fa-sync-alt"></i>刷新
<button
@click="refreshAllData()"
:disabled="isRefreshing"
class="btn btn-primary px-4 py-2 flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
>
<i :class="['fas fa-sync-alt', { 'animate-spin': isRefreshing }]"></i>
{{ isRefreshing ? '刷新中' : '刷新' }}
</button>
</div>
</div>
@@ -329,7 +374,7 @@
</template>
<script setup>
import { ref, onMounted, watch, nextTick } from 'vue'
import { ref, onMounted, onUnmounted, watch, nextTick, computed } from 'vue'
import { storeToRefs } from 'pinia'
import { useDashboardStore } from '@/stores/dashboard'
import Chart from 'chart.js/auto'
@@ -368,6 +413,20 @@ let modelUsageChartInstance = null
let usageTrendChartInstance = null
let apiKeysUsageTrendChartInstance = null
// 自动刷新相关
const autoRefreshEnabled = ref(false)
const autoRefreshInterval = ref(30) // 秒
const autoRefreshTimer = ref(null)
const refreshCountdown = ref(0)
const countdownTimer = ref(null)
const isRefreshing = ref(false)
// 计算倒计时显示
const refreshCountdownDisplay = computed(() => {
if (!autoRefreshEnabled.value || refreshCountdown.value <= 0) return ''
return `${refreshCountdown.value}秒后刷新`
})
// 格式化数字
function formatNumber(num) {
if (num >= 1000000) {
@@ -778,13 +837,90 @@ watch(apiKeysTrendData, () => {
nextTick(() => createApiKeysUsageTrendChart())
})
// 刷新所有数据
async function refreshAllData() {
if (isRefreshing.value) return
isRefreshing.value = true
try {
await Promise.all([
loadDashboardData(),
refreshChartsData()
])
} finally {
isRefreshing.value = false
}
}
// 启动自动刷新
function startAutoRefresh() {
if (!autoRefreshEnabled.value) return
// 重置倒计时
refreshCountdown.value = autoRefreshInterval.value
// 清除现有定时器
if (countdownTimer.value) {
clearInterval(countdownTimer.value)
}
if (autoRefreshTimer.value) {
clearTimeout(autoRefreshTimer.value)
}
// 启动倒计时
countdownTimer.value = setInterval(() => {
refreshCountdown.value--
if (refreshCountdown.value <= 0) {
clearInterval(countdownTimer.value)
}
}, 1000)
// 设置刷新定时器
autoRefreshTimer.value = setTimeout(async () => {
await refreshAllData()
// 递归调用以继续自动刷新
if (autoRefreshEnabled.value) {
startAutoRefresh()
}
}, autoRefreshInterval.value * 1000)
}
// 停止自动刷新
function stopAutoRefresh() {
if (countdownTimer.value) {
clearInterval(countdownTimer.value)
countdownTimer.value = null
}
if (autoRefreshTimer.value) {
clearTimeout(autoRefreshTimer.value)
autoRefreshTimer.value = null
}
refreshCountdown.value = 0
}
// 切换自动刷新
function toggleAutoRefresh() {
autoRefreshEnabled.value = !autoRefreshEnabled.value
if (autoRefreshEnabled.value) {
startAutoRefresh()
} else {
stopAutoRefresh()
}
}
// 监听自动刷新状态变化
watch(autoRefreshEnabled, (newVal) => {
if (newVal) {
startAutoRefresh()
} else {
stopAutoRefresh()
}
})
// 初始化
onMounted(async () => {
// 加载所有数据
await Promise.all([
loadDashboardData(),
refreshChartsData() // 使用refreshChartsData来确保根据当前筛选条件加载数据
])
await refreshAllData()
// 创建图表
await nextTick()
@@ -792,6 +928,21 @@ onMounted(async () => {
createUsageTrendChart()
createApiKeysUsageTrendChart()
})
// 清理
onUnmounted(() => {
stopAutoRefresh()
// 销毁图表实例
if (modelUsageChartInstance) {
modelUsageChartInstance.destroy()
}
if (usageTrendChartInstance) {
usageTrendChartInstance.destroy()
}
if (apiKeysUsageTrendChartInstance) {
apiKeysUsageTrendChartInstance.destroy()
}
})
</script>
<style scoped>
@@ -810,4 +961,18 @@ onMounted(async () => {
.custom-date-picker :deep(.el-range-input) {
font-size: 13px;
}
/* 旋转动画 */
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.animate-spin {
animation: spin 1s linear infinite;
}
</style>