33 lines
3.1 KiB
TypeScript
33 lines
3.1 KiB
TypeScript
// App shell migrated from A2A learning/apps/console/src/App.tsx.
|
|
import { useCallback, useEffect, useState } from 'react';
|
|
import { Button, Dropdown } from 'antd';
|
|
import { ChevronUp, LogOut, Moon, Sun, UserRound } from 'lucide-react';
|
|
import { SidebarNavigation } from './components/SidebarNavigation';
|
|
import { ManagedCampaignListPage } from './pages/LearningCampaignPages';
|
|
import { ProgressPage } from './pages/ProgressPage';
|
|
import { TaskDetailPage } from './pages/TaskDetailPage';
|
|
import { CandidatesPage } from './pages/CandidatesPage';
|
|
import { TestsPage } from './pages/TestsPage';
|
|
import type { AuthStatus } from './types';
|
|
|
|
function routePath() { return location.hash.slice(1) || '/tasks'; }
|
|
export function A2AWorkbench({ auth, onLogout, dark, onTheme }: { auth: AuthStatus; onLogout: () => void; dark: boolean; onTheme: () => void }) {
|
|
const [path, setPath] = useState(routePath);
|
|
useEffect(() => { const update = () => setPath(routePath()); window.addEventListener('hashchange', update); return () => window.removeEventListener('hashchange', update); }, []);
|
|
const navigate = useCallback((next: string) => { location.hash = next; }, []);
|
|
const category = path.split('/')[1] || 'tasks';
|
|
const detailId = path.split('/')[2];
|
|
const accountName = auth.user?.display_name || auth.user?.username || '维护者';
|
|
let content = <ManagedCampaignListPage navigate={navigate} />;
|
|
if (category === 'tasks' && detailId) content = <TaskDetailPage key={detailId} taskId={detailId} navigate={navigate} />;
|
|
if (category === 'overview') content = <ProgressPage navigate={navigate} />;
|
|
if (category === 'candidates') content = <CandidatesPage key={detailId || 'list'} selectedId={detailId} navigate={navigate} />;
|
|
if (category === 'validations') content = <TestsPage navigate={navigate} />;
|
|
return <div className="app-shell">
|
|
<aside className="sidebar"><SidebarNavigation category={category} navigate={navigate} /><div className="sidebar-footer"><div className="sidebar-identity">
|
|
<Dropdown menu={{ items: [{ key: 'logout', label: '退出登录', icon: <LogOut size={16} />, onClick: onLogout }] }} trigger={['click']} placement="topLeft"><button type="button" className="sidebar-account" aria-label={`当前账号:${accountName}`}><span className="sidebar-account-avatar"><UserRound size={18} aria-hidden="true" /></span><span className="sidebar-account-label"><span className="sidebar-account-name">{accountName}</span><span className="sidebar-account-meta">本机维护者</span></span><ChevronUp size={16} aria-hidden="true" /></button></Dropdown>
|
|
</div></div></aside>
|
|
<div className="workspace"><div className="topbar"><span className="breadcrumbs">学习管理 / {({ tasks: '学习批次', overview: '账本总览', candidates: '能力实体', validations: '脚本测试' } as Record<string, string>)[category] || '学习批次'}</span><Button type="text" aria-label={dark ? '切换浅色主题' : '切换深色主题'} icon={dark ? <Sun size={16} /> : <Moon size={16} />} onClick={onTheme} /></div><main className="page" key={auth.user?.id || auth.user?.username}>{content}</main></div>
|
|
</div>;
|
|
}
|