diff --git a/src/App.tsx b/src/App.tsx index 3ea35ed..1566270 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,6 +10,7 @@ import PageLoading from './components/PageLoading' import AdminLayout from './layouts/AdminLayout' const Login = lazy(() => import('./pages/Login')) +const BillingPage = lazy(() => import('./pages/Billing')) const GiteaEmbed = lazy(() => import('./pages/GiteaEmbed')) const ServersPage = lazy(() => import("./pages/Servers")) const AuditLogPage = lazy(() => import("./pages/AuditLog")) @@ -72,7 +73,6 @@ function App() { } /> } /> } /> - } /> } /> } /> + }>} + /> }, - { path: '/ai-costs', name: 'AI 调用与成本', icon: }, { path: '/files', name: '文件与 COS', icon: }, { path: '/settings', name: '系统配置', icon: , requiredRole: 'ADMIN' }, + { path: '/billing', name: 'API 用量', icon: , requiredRole: 'SUPER_ADMIN' }, { path: '/git', name: '代码仓库', icon: }, { path: '/servers', name: '服务器运维', icon: , requiredRole: 'SUPER_ADMIN' }, { path: '/audit', name: '审计日志', icon: , requiredRole: 'ADMIN' }, diff --git a/src/layouts/AdminLayout.tsx b/src/layouts/AdminLayout.tsx index f39cab8..f9ff39c 100644 --- a/src/layouts/AdminLayout.tsx +++ b/src/layouts/AdminLayout.tsx @@ -18,9 +18,9 @@ const breadcrumbMap: Record = { '/knowledge/bases': '知识库列表', '/knowledge/sources': '知识源列表', '/imports': '文档导入', - '/ai-costs': 'AI 调用与成本', '/files': '文件与 COS', '/settings': '系统配置', + '/billing': 'API 用量', '/git': '代码仓库', '/servers': '服务器运维', '/audit': '审计日志', diff --git a/src/pages/Billing.tsx b/src/pages/Billing.tsx new file mode 100644 index 0000000..3f0dcf1 --- /dev/null +++ b/src/pages/Billing.tsx @@ -0,0 +1,30 @@ +import { useState } from 'react' +import { useQuery, useQueryClient } from '@tanstack/react-query' +import { Card, Row, Col, Statistic, Button, Tag, Space, Typography, App } from 'antd' +import { DollarOutlined, ReloadOutlined, LinkOutlined } from '@ant-design/icons' +import { getBilling, type BillingInfo } from '@/services/billing-api' +const { Text } = Typography +function BillingCard({ p }: { p: BillingInfo }) { + const color = p.status === 'ok' ? (parseFloat(p.balance) < 10 ? '#faad14' : '#52c41a') : '#999' + return ( + {p.name}{p.status === 'ok' ? '正常' : '未知'}} + extra={}> + {p.currency}} /> +
模型: {p.model}
{p.note}
+
+ ) +} +function BillingContent() { + const qc = useQueryClient(); const [refreshing, setRefreshing] = useState(false) + const { data } = useQuery({ queryKey: ['billing'], queryFn: getBilling, staleTime: 60_000 }) + return ( +
+
+ API 用量 + +
+ {(data?.providers || []).map(p => )} +
+ ) +} +export default function BillingPage() { return } diff --git a/src/services/billing-api.ts b/src/services/billing-api.ts new file mode 100644 index 0000000..79790ab --- /dev/null +++ b/src/services/billing-api.ts @@ -0,0 +1,5 @@ +import { api } from './http-client' +export interface BillingInfo { + name: string; model: string; balance: string; currency: string; status: 'ok' | 'unknown'; consoleUrl: string; note: string +} +export function getBilling(): Promise<{ providers: BillingInfo[] }> { return api.get('/admin-api/billing') }