2968484d2d
- Money.tsx (2260行→54行): 拆分为 money/ 子目录4个组件, React.lazy二级分割 - AIAssistant.tsx (2038行→63行): 拆分为 ai-assistant/ 子目录6个组件, React.lazy二级分割 - xlsx改为动态导入, OvertimeTab从345KB降至12.7KB - api-services.ts: 请求参数 any→Record<string,unknown> - 移除前端3处console.log残留 - 后端console替换为pino logger - 前后端未使用import/变量清理 - Zod schema验证: termination/platform/special-status/work-process - 新增 leave.routes.ts, acceptance-test.routes.ts - UI组件: PageGuide, QueryError, Stepper
64 lines
2.8 KiB
TypeScript
64 lines
2.8 KiB
TypeScript
import { useState, lazy, Suspense } from 'react'
|
||
import { Bot, FileSearch, Scale, Sparkles, BookOpen, TrendingUp, Loader2 } from 'lucide-react'
|
||
|
||
const ChatTab = lazy(() => import('./ai-assistant/ChatTab').then(m => ({ default: m.ChatTab })))
|
||
const PredictTab = lazy(() => import('./ai-assistant/PredictTab').then(m => ({ default: m.PredictTab })))
|
||
const ReviewTab = lazy(() => import('./ai-assistant/ReviewTab').then(m => ({ default: m.ReviewTab })))
|
||
const CaseTab = lazy(() => import('./ai-assistant/CaseTab').then(m => ({ default: m.CaseTab })))
|
||
const KnowledgeTab = lazy(() => import('./ai-assistant/KnowledgeTab').then(m => ({ default: m.KnowledgeTab })))
|
||
const HRReportTab = lazy(() => import('./ai-assistant/HRReportTab').then(m => ({ default: m.HRReportTab })))
|
||
|
||
type Tab = 'chat' | 'predict' | 'review' | 'case' | 'knowledge' | 'hr-report'
|
||
|
||
export default function AIAssistant() {
|
||
const [tab, setTab] = useState<Tab>('chat')
|
||
|
||
const tabs: { key: Tab; label: string; icon: typeof Bot }[] = [
|
||
{ key: 'chat', label: '智能问答', icon: Bot },
|
||
{ key: 'predict', label: '风险预测', icon: Sparkles },
|
||
{ key: 'review', label: '合同审查', icon: FileSearch },
|
||
{ key: 'case', label: '案例匹配', icon: Scale },
|
||
{ key: 'hr-report', label: '人力报告', icon: TrendingUp },
|
||
{ key: 'knowledge', label: '知识库', icon: BookOpen },
|
||
]
|
||
|
||
return (
|
||
<div className="space-y-4">
|
||
<div className="flex items-center gap-2">
|
||
<Bot className="h-5 w-5 text-primary" />
|
||
<div>
|
||
<h1 className="text-base font-semibold">AI 合规顾问</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) => {
|
||
const Icon = t.icon
|
||
return (
|
||
<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'
|
||
}`}
|
||
>
|
||
<Icon className="w-4 h-4" />
|
||
{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 === 'chat' && <ChatTab />}
|
||
{tab === 'predict' && <PredictTab />}
|
||
{tab === 'review' && <ReviewTab />}
|
||
{tab === 'case' && <CaseTab />}
|
||
{tab === 'hr-report' && <HRReportTab />}
|
||
{tab === 'knowledge' && <KnowledgeTab />}
|
||
</Suspense>
|
||
</div>
|
||
)
|
||
}
|