feat:初版

This commit is contained in:
2025-12-25 18:41:09 +08:00
commit 1429e0e66a
52 changed files with 2688 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
'use client'
import { useState, useEffect } from 'react'
const API_BASE = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:8000'
interface Stats {
date: string
request_count: number
input_tokens: number
output_tokens: number
cached_count: number
error_count: number
}
interface Realtime {
rpm: number
tpm: number
}
export default function StatsPage() {
const [providerId, setProviderId] = useState(1)
const [stats, setStats] = useState<Stats | null>(null)
const [realtime, setRealtime] = useState<Realtime>({ rpm: 0, tpm: 0 })
const getToken = () => localStorage.getItem('admin_token') || ''
const fetchStats = async () => {
const res = await fetch(
`${API_BASE}/api/v1/admin/stats/daily/${providerId}`,
{ headers: { Authorization: `Bearer ${getToken()}` } }
)
if (res.ok) setStats(await res.json())
}
const fetchRealtime = async () => {
const res = await fetch(
`${API_BASE}/api/v1/admin/stats/realtime/${providerId}`,
{ headers: { Authorization: `Bearer ${getToken()}` } }
)
if (res.ok) setRealtime(await res.json())
}
useEffect(() => {
fetchStats()
fetchRealtime()
const interval = setInterval(fetchRealtime, 5000)
return () => clearInterval(interval)
}, [providerId])
return (
<div>
<h1 className="text-2xl font-bold mb-6">使</h1>
{/* 实时指标 */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
<div className="bg-white p-4 rounded shadow">
<h3 className="text-gray-500 text-sm">RPM ()</h3>
<p className="text-2xl font-bold">{realtime.rpm}</p>
</div>
<div className="bg-white p-4 rounded shadow">
<h3 className="text-gray-500 text-sm">TPM (Token)</h3>
<p className="text-2xl font-bold">{realtime.tpm}</p>
</div>
</div>
{/* 今日统计 */}
{stats && (
<div className="bg-white p-6 rounded shadow">
<h2 className="text-lg font-bold mb-4"> ({stats.date})</h2>
<div className="grid grid-cols-2 md:grid-cols-5 gap-4">
<div>
<p className="text-gray-500 text-sm"></p>
<p className="text-xl font-bold">{stats.request_count}</p>
</div>
<div>
<p className="text-gray-500 text-sm"> Token</p>
<p className="text-xl font-bold">{stats.input_tokens}</p>
</div>
<div>
<p className="text-gray-500 text-sm"> Token</p>
<p className="text-xl font-bold">{stats.output_tokens}</p>
</div>
<div>
<p className="text-gray-500 text-sm"></p>
<p className="text-xl font-bold">{stats.cached_count}</p>
</div>
<div>
<p className="text-gray-500 text-sm"></p>
<p className="text-xl font-bold text-red-600">{stats.error_count}</p>
</div>
</div>
</div>
)}
</div>
)
}