Files
newapi-dashboard/src/App.tsx
LAMCLOD f6036cab66 feat: newapi-dashboard 全栈项目初始化
为 new-api (LLM API 网关) 构建独立前端管理面板:
- React 18 + TypeScript + Vite + Ant Design 5 前端
- Node.js + Express + better-sqlite3 BFF 后端
- 登录页: 站点选择器 + UserID + AccessToken 认证
- 仪表盘: 用户信息、额度环形图、7天趋势图、模型饼图、令牌概览、日志时间线
- 账单页: 筛选日志表格、模型消耗柱状图、充值记录、CSV/PDF 导出(HMAC签名)
- 管理员站点管理: 站点 CRUD
- API 代理: 多站点切换,会话管理

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 18:00:28 +08:00

71 lines
2.1 KiB
TypeScript

import { useEffect } from 'react'
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
import { ConfigProvider, App as AntApp, Spin } from 'antd'
import zhCN from 'antd/locale/zh_CN'
import { lightTheme } from '@/utils/theme'
import { useAuthStore } from '@/store/authStore'
import { authApi } from '@/api/auth'
import Layout from '@/components/Layout'
import Login from '@/pages/Login'
import Dashboard from '@/pages/Dashboard'
import Billing from '@/pages/Billing'
import SiteManagement from '@/pages/admin/SiteManagement'
function ProtectedRoute({ children }: { children: React.ReactNode }) {
const { isLoggedIn, loading } = useAuthStore()
if (loading) {
return (
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
<Spin size="large" tip="Loading..." />
</div>
)
}
return isLoggedIn ? <>{children}</> : <Navigate to="/login" />
}
function SessionRestore({ children }: { children: React.ReactNode }) {
const { sessionToken, login, logout, setLoading } = useAuthStore()
useEffect(() => {
if (sessionToken) {
authApi.me()
.then((res) => {
if (res.data.success) {
login(sessionToken, res.data.data.userInfo, res.data.data.site)
} else {
logout()
}
})
.catch(() => logout())
} else {
setLoading(false)
}
}, [])
return <>{children}</>
}
export default function App() {
return (
<ConfigProvider locale={zhCN} theme={lightTheme}>
<AntApp>
<BrowserRouter>
<SessionRestore>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/" element={<ProtectedRoute><Layout /></ProtectedRoute>}>
<Route index element={<Navigate to="/dashboard" />} />
<Route path="dashboard" element={<Dashboard />} />
<Route path="billing" element={<Billing />} />
<Route path="admin/sites" element={<SiteManagement />} />
</Route>
</Routes>
</SessionRestore>
</BrowserRouter>
</AntApp>
</ConfigProvider>
)
}