0df8aa77d9
- 员工花名册管理(加密存储、导入导出) - 薪酬管理(发薪批次、薪酬模版、加班费计算、工资条) - 社保公积金(多城市配置、版本管理、基数调整) - 解聘管理(6步流程、证据链、工作交接) - AI 助手(合同审查、风险预测、RAG 知识库) - Dashboard 仪表盘 - 设置与通知
96 lines
4.5 KiB
TypeScript
96 lines
4.5 KiB
TypeScript
import { lazy, Suspense } from 'react'
|
|
import { Routes, Route, Navigate } from 'react-router-dom'
|
|
import { Toaster } from 'sonner'
|
|
import { useAuthStore } from './store/authStore'
|
|
import TopNav from './components/layout/TopNav'
|
|
import MobileTabBar from './components/layout/MobileTabBar'
|
|
import PageContainer from './components/layout/PageContainer'
|
|
import { SkeletonPage } from './components/ui/Skeleton'
|
|
import OnboardingGuide from './components/OnboardingGuide'
|
|
|
|
const Login = lazy(() => import('./pages/auth/Login'))
|
|
const Register = lazy(() => import('./pages/auth/Register'))
|
|
const ForgotPassword = lazy(() => import('./pages/auth/ForgotPassword'))
|
|
const Dashboard = lazy(() => import('./pages/Dashboard'))
|
|
const Money = lazy(() => import('./pages/Money'))
|
|
const SocialInsurance = lazy(() => import('./pages/SocialInsurance'))
|
|
const Roster = lazy(() => import('./pages/Roster'))
|
|
const Termination = lazy(() => import('./pages/Termination'))
|
|
const AIAssistant = lazy(() => import('./pages/AIAssistant'))
|
|
const Settings = lazy(() => import('./pages/Settings'))
|
|
const PortalLogin = lazy(() => import('./pages/portal/PortalLogin'))
|
|
const Payslip = lazy(() => import('./pages/portal/Payslip'))
|
|
const MyContract = lazy(() => import('./pages/portal/MyContract'))
|
|
const Onboarding = lazy(() => import('./pages/portal/Onboarding'))
|
|
const ContractConfirm = lazy(() => import('./pages/portal/ContractConfirm'))
|
|
|
|
function ProtectedRoute({ children }: { children: React.ReactNode }) {
|
|
const isAuthenticated = useAuthStore((s) => s.isAuthenticated)
|
|
if (!isAuthenticated) return <Navigate to="/login" replace />
|
|
return <>{children}</>
|
|
}
|
|
|
|
function PublicRoute({ children }: { children: React.ReactNode }) {
|
|
const isAuthenticated = useAuthStore((s) => s.isAuthenticated)
|
|
if (isAuthenticated) return <Navigate to="/" replace />
|
|
return <>{children}</>
|
|
}
|
|
|
|
function AdminLayout({ children }: { children: React.ReactNode }) {
|
|
return (
|
|
<div className="min-h-screen flex flex-col">
|
|
<TopNav />
|
|
<main className="flex-1 py-6 pb-20 md:pb-6">
|
|
<PageContainer>
|
|
<Suspense fallback={<SkeletonPage />}>{children}</Suspense>
|
|
</PageContainer>
|
|
</main>
|
|
<MobileTabBar />
|
|
<OnboardingGuide />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function PortalLayout({ children }: { children: React.ReactNode }) {
|
|
return (
|
|
<div className="min-h-screen bg-surface">
|
|
<main className="max-w-md mx-auto py-6 px-4">
|
|
<Suspense fallback={<SkeletonPage />}>{children}</Suspense>
|
|
</main>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default function App() {
|
|
return (
|
|
<>
|
|
<Routes>
|
|
{/* 管理端认证页面 */}
|
|
<Route path="/login" element={<Suspense fallback={<SkeletonPage />}><PublicRoute><Login /></PublicRoute></Suspense>} />
|
|
<Route path="/register" element={<Suspense fallback={<SkeletonPage />}><PublicRoute><Register /></PublicRoute></Suspense>} />
|
|
<Route path="/forgot-password" element={<Suspense fallback={<SkeletonPage />}><PublicRoute><ForgotPassword /></PublicRoute></Suspense>} />
|
|
|
|
{/* 管理端业务页面 */}
|
|
<Route path="/" element={<ProtectedRoute><AdminLayout><Dashboard /></AdminLayout></ProtectedRoute>} />
|
|
<Route path="/roster" element={<ProtectedRoute><AdminLayout><Roster /></AdminLayout></ProtectedRoute>} />
|
|
<Route path="/money" element={<ProtectedRoute><AdminLayout><Money /></AdminLayout></ProtectedRoute>} />
|
|
<Route path="/social" element={<ProtectedRoute><AdminLayout><SocialInsurance /></AdminLayout></ProtectedRoute>} />
|
|
<Route path="/termination" element={<ProtectedRoute><AdminLayout><Termination /></AdminLayout></ProtectedRoute>} />
|
|
<Route path="/ai-assistant" element={<ProtectedRoute><AdminLayout><AIAssistant /></AdminLayout></ProtectedRoute>} />
|
|
<Route path="/settings" element={<ProtectedRoute><AdminLayout><Settings /></AdminLayout></ProtectedRoute>} />
|
|
|
|
{/* 员工端 */}
|
|
<Route path="/portal/login" element={<PortalLayout><PortalLogin /></PortalLayout>} />
|
|
<Route path="/portal/payslip" element={<PortalLayout><Payslip /></PortalLayout>} />
|
|
<Route path="/portal/contract" element={<PortalLayout><MyContract /></PortalLayout>} />
|
|
<Route path="/portal/onboarding" element={<PortalLayout><Onboarding /></PortalLayout>} />
|
|
<Route path="/portal/contract-confirm" element={<PortalLayout><ContractConfirm /></PortalLayout>} />
|
|
|
|
{/* 兜底 */}
|
|
<Route path="*" element={<Navigate to="/" replace />} />
|
|
</Routes>
|
|
<Toaster position="top-center" richColors closeButton />
|
|
</>
|
|
)
|
|
}
|