Files
Developer b2c17e3eca feat: 题库管理功能完善
- QuestionBankView: 添加删除按钮、卡片点击跳转详情页
- QuestionBankDetailView: 新建题库详情页(题目CRUD/AI生成/审核)
- questionBankService: 添加generateQuestions方法
- index.tsx: 添加详情页路由
2026-05-13 21:51:33 +08:00

123 lines
5.3 KiB
TypeScript

import './index.css';
import React, { lazy, Suspense } from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { AuthProvider, useAuth } from './src/contexts/AuthContext';
import { LanguageProvider } from './contexts/LanguageContext';
import { ToastProvider } from './contexts/ToastContext';
import { ConfirmProvider } from './contexts/ConfirmContext';
import Login from './src/pages/auth/Login';
import WorkspaceLayout from './src/components/layouts/WorkspaceLayout';
// Lazy-loaded page components
const ChatPage = lazy(() => import('./src/pages/workspace/ChatPage'));
const AgentsPage = lazy(() => import('./src/pages/workspace/AgentsPage'));
const AssessmentPage = lazy(() => import('./src/pages/workspace/AssessmentPage'));
const PluginsPage = lazy(() => import('./src/pages/workspace/PluginsPage'));
const KnowledgePage = lazy(() => import('./src/pages/workspace/KnowledgePage'));
const NotebooksPage = lazy(() => import('./src/pages/workspace/NotebooksPage'));
const MemosPage = lazy(() => import('./src/pages/workspace/MemosPage'));
const SettingsPage = lazy(() => import('./src/pages/workspace/SettingsPage'));
const QuestionBankView = lazy(() => import('./components/views/QuestionBankView'));
const QuestionBankDetailView = lazy(() => import('./components/views/QuestionBankDetailView'));
const AssessmentStatsView = lazy(() => import('./components/views/AssessmentStatsView'));
const PageLoader = () => (
<div className="flex h-full items-center justify-center">
<div className="w-8 h-8 border-4 border-blue-600 border-t-transparent rounded-full animate-spin" />
</div>
);
function ProtectedRoute({ children, allowedRoles }: { children: React.ReactNode, allowedRoles?: string[] }) {
const { user, isLoading } = useAuth();
if (isLoading) {
return (
<div className="flex h-screen items-center justify-center bg-slate-50">
<PageLoader />
</div>
);
}
if (!user) return <Navigate to="/login" replace />;
if (allowedRoles && !allowedRoles.includes(user.role)) return <Navigate to="/" replace />;
return <>{children}</>;
}
function OverviewPage() {
const { user } = useAuth();
return (
<div className="p-8 bg-white rounded-2xl shadow-sm border border-slate-100">
<h1 className="text-2xl font-bold text-slate-900">Welcome back 👋</h1>
<p className="mt-2 text-slate-500">
Signed in as <span className="font-semibold">{user?.displayName || user?.username}</span>{' '}
· role <span className="font-semibold text-blue-600">{user?.role?.replace(/_/g, ' ')}</span>
</p>
</div>
);
}
function App() {
return (
<LanguageProvider>
<ToastProvider>
<ConfirmProvider>
<AuthProvider>
<BrowserRouter>
<Suspense
fallback={
<div className="flex h-screen items-center justify-center bg-slate-50">
<PageLoader />
</div>
}
>
<Routes>
{/* Public */}
<Route path="/login" element={<Login />} />
{/* Workspace */}
<Route
path="/*"
element={
<ProtectedRoute>
<WorkspaceLayout />
</ProtectedRoute>
}
>
<Route index element={<OverviewPage />} />
<Route path="chat" element={<ChatPage />} />
<Route path="agents" element={<AgentsPage />} />
<Route path="assessment" element={<AssessmentPage />} />
<Route path="assessment-stats" element={<AssessmentStatsView />} />
<Route path="question-banks" element={<QuestionBankView isAdmin={true} />} />
<Route path="question-banks/:id" element={<QuestionBankDetailView />} />
<Route path="plugins" element={<PluginsPage />} />
<Route path="notebook" element={<MemosPage />} />
<Route path="knowledge/*" element={<KnowledgePage />} />
<Route path="settings" element={<SettingsPage />} />
<Route path="users" element={<SettingsPage initialTab="user" />} />
<Route path="models" element={<SettingsPage initialTab="model" />} />
<Route path="kb-settings" element={<SettingsPage initialTab="knowledge_base" />} />
<Route path="tenants" element={<ProtectedRoute allowedRoles={['SUPER_ADMIN']}><SettingsPage initialTab="tenants" /></ProtectedRoute>} />
</Route>
{/* Remove standalone Admin routes as we integrated Dashboard into Settings */}
</Routes>
</Suspense>
</BrowserRouter>
</AuthProvider>
</ConfirmProvider>
</ToastProvider>
</LanguageProvider>
);
}
// ── Mount ──────────────────────────────────────────────────────────────────────
const container = document.getElementById('root')!;
createRoot(container).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);