Files
TurboHR/frontend/src/pages/Money.tsx
T
selfrelease 5196d7c80a fix: portal端token过期后自动跳转登录页,避免显示空数据
- portalAxios 401 响应拦截器:清除 token 并跳转 /portal/login
- PortalLayoutWrapper:检查 token 是否存在,不存在则跳转登录页
- 排除 /portal/login 和 /portal/auto-login 页面避免重复跳转

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-17 15:06:46 +08:00

59 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState, Suspense } from 'react'
import { useSearchParams } from 'react-router-dom'
import { Layers, Wallet, LayoutTemplate, Receipt, Loader2 } from 'lucide-react'
import PageGuide from '../components/ui/PageGuide'
import { lazyRetry } from '../lib/lazyRetry'
const BatchManager = lazyRetry(() => import('./money/BatchTab').then(m => ({ default: m.BatchManager })))
const TemplateManager = lazyRetry(() => import('./money/TemplateTab').then(m => ({ default: m.TemplateManager })))
const PayslipManager = lazyRetry(() => import('./money/PayslipTab').then(m => ({ default: m.PayslipManager })))
type Tab = 'batch' | 'template' | 'payslip'
export default function Money() {
const [searchParams] = useSearchParams()
const initialEmployeeId = searchParams.get('employeeId') || ''
const initialTab = (searchParams.get('tab') as Tab) || (initialEmployeeId ? 'payslip' : 'batch')
const [tab, setTab] = useState<Tab>(initialTab)
const tabs: { key: Tab; label: string; icon: React.ReactNode }[] = [
{ key: 'batch', label: '发薪批次', icon: <Layers className="w-4 h-4" /> },
{ key: 'template', label: '薪酬模版', icon: <LayoutTemplate className="w-4 h-4" /> },
{ key: 'payslip', label: '工资条管理', icon: <Receipt className="w-4 h-4" /> },
]
return (
<div className="space-y-4">
<PageGuide> </PageGuide>
<div className="flex items-center gap-2">
<Wallet className="w-5 h-5 text-primary" />
<div>
<h1 className="text-base font-semibold"></h1>
<p className="mt-1 text-sm text-gray-500"></p>
</div>
</div>
<div className="flex gap-1 border-b overflow-x-auto">
{tabs.map((t) => (
<button
key={t.key}
onClick={() => setTab(t.key)}
className={`flex items-center gap-1.5 px-4 py-2 text-sm font-medium border-b-2 transition-colors whitespace-nowrap ${
tab === t.key ? 'border-primary text-primary' : 'border-transparent text-gray-500 hover:text-gray-700'
}`}
>
{t.icon}
{t.label}
</button>
))}
</div>
<Suspense fallback={<div className="flex items-center justify-center py-12"><Loader2 className="w-5 h-5 animate-spin text-gray-400" /></div>}>
{tab === 'batch' && <BatchManager />}
{tab === 'template' && <TemplateManager />}
{tab === 'payslip' && <PayslipManager filterEmployeeId={initialEmployeeId} />}
</Suspense>
</div>
)
}