Files
ipad/src/layouts/MainLayout.tsx
2025-12-16 10:17:11 +08:00

104 lines
3.2 KiB
TypeScript

import { Outlet, useLocation, useNavigate } from 'react-router-dom';
import { useEffect, useMemo, useState } from 'react';
import type { QuickActionType } from '../data/mockData';
import { QuickActionModal } from '../components/modals/QuickActionModal';
import { LoginModal } from '../components/modals/LoginModal';
import { Sidebar, type SectionKey } from '../components/layout/Sidebar';
import { TopBar } from '../components/layout/TopBar';
export interface MainLayoutContext {
search: string;
setSearch: (value: string) => void;
}
const sectionToRoute: Record<SectionKey, string> = {
home: '/home',
exam: '/exam',
booking: '/booking',
support: '/support',
};
const routeToSection = Object.entries(sectionToRoute).reduce<Record<string, SectionKey>>(
(acc, [section, route]) => {
acc[route] = section as SectionKey;
return acc;
},
{},
);
export const MainLayout = () => {
const [search, setSearch] = useState('');
const [quickAction, setQuickAction] = useState<QuickActionType>('none');
const [noteText, setNoteText] = useState('');
const [loginModalOpen, setLoginModalOpen] = useState(false);
const [operatorName, setOperatorName] = useState<string>('');
const navigate = useNavigate();
const location = useLocation();
const activeSection: SectionKey = useMemo(() => {
const matched = Object.entries(routeToSection).find(([path]) => location.pathname.startsWith(path));
return (matched?.[1] || 'home') as SectionKey;
}, [location.pathname]);
const handleNavigate = (section: SectionKey) => {
navigate(sectionToRoute[section]);
};
const handleLoginSuccess = (phone: string) => {
// 实际项目中应该从后端获取用户信息
// 这里暂时使用手机号后4位作为操作员名称
const displayName = phone.slice(-4);
setOperatorName(displayName);
// 可以存储到 localStorage 或状态管理中
localStorage.setItem('operatorPhone', phone);
localStorage.setItem('operatorName', displayName);
};
// 初始化时检查是否有已登录的操作员
useEffect(() => {
const savedName = localStorage.getItem('operatorName');
if (savedName) {
setOperatorName(savedName);
}
}, []);
return (
<div className='h-screen bg-gray-50 text-gray-900 grid grid-cols-[240px_1fr] overflow-hidden'>
<Sidebar active={activeSection} onNavigate={handleNavigate} onQuickAction={setQuickAction} />
<div className='flex flex-col h-screen overflow-hidden'>
<TopBar
search={search}
onSearch={setSearch}
enableSearch={activeSection === 'exam'}
operatorName={operatorName}
onLoginClick={() => setLoginModalOpen(true)}
/>
<main className='p-6 flex-1 overflow-auto'>
<Outlet context={{ search, setSearch }} />
</main>
</div>
{loginModalOpen && (
<LoginModal
onClose={() => setLoginModalOpen(false)}
onLoginSuccess={handleLoginSuccess}
/>
)}
{quickAction !== 'none' && (
<QuickActionModal
action={quickAction}
noteText={noteText}
onNoteChange={setNoteText}
onClose={() => setQuickAction('none')}
/>
)}
</div>
);
};