Initial commit: tkmind admin frontend (React + Vite).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-06-16 19:44:31 +08:00
commit 8ad1a8a8da
30 changed files with 5981 additions and 0 deletions
+131
View File
@@ -0,0 +1,131 @@
import { useEffect, useState } from 'react';
import { Navigate, Route, Routes, useNavigate } from 'react-router-dom';
import { checkAuth, login, logout, setUnauthorizedHandler } from './api/client';
import { AdminLayout } from './admin/AdminLayout';
import { BillingPage } from './admin/pages/BillingPage';
import { CapabilitiesPage } from './admin/pages/CapabilitiesPage';
import { DashboardPage } from './admin/pages/DashboardPage';
import { PoliciesPage } from './admin/pages/PoliciesPage';
import { ProvidersPage } from './admin/pages/ProvidersPage';
import { SkillsPage } from './admin/pages/SkillsPage';
import { UserDetailPage } from './admin/pages/UserDetailPage';
import { UsersPage } from './admin/pages/UsersPage';
import type { PortalUser } from './types';
function AdminLoginPage({ onAuth }: { onAuth: (user: PortalUser) => void }) {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError(null);
setLoading(true);
try {
const user = await login(username, password);
if (!user || user.role !== 'admin') {
setError('无管理员权限');
return;
}
onAuth(user);
} catch (err) {
setError(err instanceof Error ? err.message : '登录失败');
} finally {
setLoading(false);
}
};
return (
<div className="admin-login-page">
<div className="admin-login-card">
<h1 className="admin-login-title"></h1>
{error && <p className="banner banner-error">{error}</p>}
<form onSubmit={handleSubmit} className="admin-login-form">
<input
className="admin-login-input"
type="text"
placeholder="用户名"
value={username}
onChange={(e) => setUsername(e.target.value)}
autoFocus
required
/>
<input
className="admin-login-input"
type="password"
placeholder="密码"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
<button type="submit" className="send-btn" disabled={loading}>
{loading ? '登录中…' : '登录'}
</button>
</form>
</div>
</div>
);
}
function AdminApp({ user, onLogout }: { user: PortalUser; onLogout: () => void }) {
return (
<Routes>
<Route path="/admin" element={<AdminLayout user={user} onLogout={onLogout} />}>
<Route index element={<DashboardPage />} />
<Route path="users" element={<UsersPage />} />
<Route path="users/:userId" element={<UserDetailPage />} />
<Route path="billing/*" element={<BillingPage />} />
<Route path="capabilities" element={<CapabilitiesPage />} />
<Route path="skills" element={<SkillsPage />} />
<Route path="policies" element={<PoliciesPage />} />
<Route path="providers" element={<ProvidersPage />} />
<Route path="*" element={<Navigate to="/admin" replace />} />
</Route>
<Route path="*" element={<Navigate to="/admin" replace />} />
</Routes>
);
}
export function App() {
const navigate = useNavigate();
const [authed, setAuthed] = useState<boolean | null>(null);
const [user, setUser] = useState<PortalUser | null>(null);
useEffect(() => {
setUnauthorizedHandler(() => {
setAuthed(false);
setUser(null);
navigate('/', { replace: true });
});
void checkAuth().then((status) => {
const isAdmin = status.authenticated && status.user?.role === 'admin';
setAuthed(isAdmin);
setUser(isAdmin ? (status.user ?? null) : null);
});
}, [navigate]);
if (authed === null) {
return <div className="app-loading"></div>;
}
if (!authed || !user) {
return (
<AdminLoginPage
onAuth={(nextUser) => {
setAuthed(true);
setUser(nextUser);
}}
/>
);
}
const handleLogout = () => {
void logout().finally(() => {
setAuthed(false);
setUser(null);
});
};
return <AdminApp user={user} onLogout={handleLogout} />;
}