d79e3baa34
- 面包屑导航组件,集成至TopNav header - 侧边栏菜单分组间距增大,分组间分隔线 - 制度公示员工阅读签收:PolicyReadRecord模型、portal路由、管理端阅读统计 - 修复Policies.tsx民主程序推进bug(字段名/API路径/参数) - 用工文本模板变量名英文转中文显示 - 通知类型TYPE_LABELS补全(RISK_ALERT/SOCIAL_INS/OVERTIME_ALERT/PAYSLIP_READY) - 通知示例数据补充 - h2标题统一为text-sm font-medium - 新增run.md
121 lines
6.6 KiB
TypeScript
121 lines
6.6 KiB
TypeScript
import { lazy, Suspense, useState } 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 SidebarNav from './components/layout/SidebarNav'
|
|
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 Evidence = lazy(() => import('./pages/Evidence'))
|
|
const Policies = lazy(() => import('./pages/Policies'))
|
|
const Attendance = lazy(() => import('./pages/Attendance'))
|
|
const Templates = lazy(() => import('./pages/Templates'))
|
|
const AuditLog = lazy(() => import('./pages/AuditLog'))
|
|
const Notifications = lazy(() => import('./pages/Notifications'))
|
|
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'))
|
|
const MyPolicies = lazy(() => import('./pages/portal/MyPolicies'))
|
|
const MedicalPeriodCalculator = lazy(() => import('./pages/tools/MedicalPeriodCalculator'))
|
|
const HealthCheck = lazy(() => import('./pages/tools/HealthCheck'))
|
|
const AnnualValueReport = lazy(() => import('./pages/tools/AnnualValueReport'))
|
|
|
|
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 }) {
|
|
const [sidebarOpen, setSidebarOpen] = useState(false)
|
|
return (
|
|
<div className="flex min-h-screen bg-[#f8f9fb]">
|
|
<SidebarNav mobileOpen={sidebarOpen} onClose={() => setSidebarOpen(false)} />
|
|
<div className="flex-1 flex flex-col min-w-0">
|
|
<TopNav onMenuClick={() => setSidebarOpen(true)} />
|
|
<main className="flex-1 py-6 pb-20 md:pb-6">
|
|
<PageContainer>
|
|
<Suspense fallback={<SkeletonPage />}>{children}</Suspense>
|
|
</PageContainer>
|
|
</main>
|
|
<MobileTabBar />
|
|
<OnboardingGuide />
|
|
</div>
|
|
</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="/evidence" element={<ProtectedRoute><AdminLayout><Evidence /></AdminLayout></ProtectedRoute>} />
|
|
<Route path="/policies" element={<ProtectedRoute><AdminLayout><Policies /></AdminLayout></ProtectedRoute>} />
|
|
<Route path="/attendance" element={<ProtectedRoute><AdminLayout><Attendance /></AdminLayout></ProtectedRoute>} />
|
|
<Route path="/templates" element={<ProtectedRoute><AdminLayout><Templates /></AdminLayout></ProtectedRoute>} />
|
|
<Route path="/audit" element={<ProtectedRoute><AdminLayout><AuditLog /></AdminLayout></ProtectedRoute>} />
|
|
<Route path="/notifications" element={<ProtectedRoute><AdminLayout><Notifications /></AdminLayout></ProtectedRoute>} />
|
|
<Route path="/tools/medical-period" element={<ProtectedRoute><AdminLayout><MedicalPeriodCalculator /></AdminLayout></ProtectedRoute>} />
|
|
<Route path="/tools/health-check" element={<ProtectedRoute><AdminLayout><HealthCheck /></AdminLayout></ProtectedRoute>} />
|
|
<Route path="/tools/annual-value" element={<ProtectedRoute><AdminLayout><AnnualValueReport /></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="/portal/policies" element={<PortalLayout><MyPolicies /></PortalLayout>} />
|
|
|
|
{/* 兜底 */}
|
|
<Route path="*" element={<Navigate to="/" replace />} />
|
|
</Routes>
|
|
<Toaster position="top-center" richColors closeButton />
|
|
</>
|
|
)
|
|
}
|