From 6812d8038d620a50178fc63e62b9e2bfdb5d5835 Mon Sep 17 00:00:00 2001 From: WangDL Date: Sun, 24 May 2026 10:56:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20M1-05=20metrics=20page=20=E2=80=94=20AI?= =?UTF-8?q?=20+=20Worker=20performance=20tabs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 --- src/pages/Metrics.tsx | 82 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 10 deletions(-) diff --git a/src/pages/Metrics.tsx b/src/pages/Metrics.tsx index d836f5d..2800571 100644 --- a/src/pages/Metrics.tsx +++ b/src/pages/Metrics.tsx @@ -1,6 +1,6 @@ import { useQuery, useQueryClient } from '@tanstack/react-query' -import { Table, Card, Row, Col, Statistic, Button, Typography } from 'antd' -import { ReloadOutlined, DashboardOutlined } from '@ant-design/icons' +import { Table, Card, Row, Col, Statistic, Button, Typography, Tabs } from 'antd' +import { ReloadOutlined, DashboardOutlined, CloudOutlined, NodeIndexOutlined } from '@ant-design/icons' import { api } from '@/services/http-client' import dayjs from 'dayjs' @@ -12,6 +12,8 @@ function MetricsPage() { const { data: overview } = useQuery({ queryKey: ['metrics', 'overview'], queryFn: (): Promise => api.get('/admin-api/metrics/overview'), staleTime: 10_000 }) const { data: top } = useQuery({ queryKey: ['metrics', 'top'], queryFn: (): Promise => api.get('/admin-api/metrics/top?limit=15'), staleTime: 10_000 }) const { data: recent } = useQuery({ queryKey: ['metrics', 'recent'], queryFn: (): Promise => api.get('/admin-api/metrics/recent?limit=30'), staleTime: 5_000 }) + const { data: ai } = useQuery({ queryKey: ['metrics', 'ai'], queryFn: (): Promise => api.get('/admin-api/metrics/ai?days=7'), staleTime: 10_000 }) + const { data: worker } = useQuery({ queryKey: ['metrics', 'worker'], queryFn: (): Promise => api.get('/admin-api/metrics/worker?days=7'), staleTime: 10_000 }) const topCols = [ { title: '接口', dataIndex: 'path', width: 300, ellipsis: true }, @@ -28,6 +30,22 @@ function MetricsPage() { { title: '耗时', dataIndex: 'duration', width: 70, align: 'center' as const, render: (v: number) => `${v}ms` }, ] + const aiProviderCols = [ + { title: 'Provider', dataIndex: 'name', width: 120 }, + { title: '调用量', dataIndex: 'calls', width: 80, align: 'center' as const }, + { title: '平均耗时', dataIndex: 'avgLatencyMs', width: 100, align: 'center' as const, render: (v: number) => 5000 ? '#ff4d4f' : v > 2000 ? '#faad14' : '#52c41a' }}>{v}ms }, + { title: '失败率', dataIndex: 'failureRate', width: 80, align: 'center' as const }, + { title: '成本', dataIndex: 'totalCost', width: 80, align: 'center' as const, render: (v: string) => `$${v}` }, + ] + + const workerCols = [ + { title: '队列', dataIndex: 'name', width: 160 }, + { title: '总任务', dataIndex: 'total', width: 80, align: 'center' as const }, + { title: '完成', dataIndex: 'completed', width: 80, align: 'center' as const }, + { title: '失败', dataIndex: 'failed', width: 80, align: 'center' as const, render: (v: number) => v > 0 ? {v} : 0 }, + { title: '成功率', dataIndex: 'successRate', width: 80, align: 'center' as const }, + ] + return (
@@ -42,14 +60,58 @@ function MetricsPage() { - - - - - -
- - + + +
+ + +
+ + + ), + }, + { + key: 'ai', label: <> AI 性能, + children: ( + <> + + + + + + + + +
+ + +
+ + + + ), + }, + { + key: 'worker', label: <> Worker 性能, + children: ( + <> + + + + + s + q.failed, 0) || 0} valueStyle={{ color: '#ff4d4f' }} /> + + +
+ + + ), + }, + ]} /> ) }