"use client"; import { useState, useEffect, useCallback, useRef } from "react"; import { motion } from "motion/react"; import { FileText, AlertTriangle, CheckCircle, TrendingUp, Clock, ArrowRight, Loader2, Sparkles, Send, MessageSquare, Receipt, BarChart3, Upload, } from "lucide-react"; import { Card, CardContent } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { useRouter } from "next/navigation"; import { api } from "@/lib/api/client"; import ENDPOINTS from "@/lib/api/endpoints"; interface TaskStats { monthly_tasks: number; pending_exceptions: number; completed_tasks: number; match_rate: number; current_period: string; } interface Task { id: number; period: string; status: string; total_employees: number; matched_count: number; exception_count: number; created_at: string; completed_at: string | null; } const statusLabels: Record = { PENDING: { label: "待处理", color: "bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300" }, PROCESSING: { label: "处理中", color: "bg-blue-100 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300" }, MAPPING_COMPLETED: { label: "映射完成", color: "bg-amber-100 text-amber-700 dark:bg-amber-900/50 dark:text-amber-300" }, COMPLETED: { label: "已完成", color: "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/50 dark:text-emerald-300" }, FAILED: { label: "失败", color: "bg-red-100 text-red-700 dark:bg-red-900/50 dark:text-red-300" }, }; const container = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { staggerChildren: 0.08, delayChildren: 0.1, }, }, }; const item = { hidden: { opacity: 0, y: 12 }, show: { opacity: 1, y: 0, transition: { duration: 0.4, ease: [0.16, 1, 0.3, 1] as const, }, }, }; interface SuggestedQuestions { questions: string[]; } interface QAResponse { answer: string; data_points: string[]; } export default function DashboardPage() { const router = useRouter(); const [stats, setStats] = useState(null); const [recentTasks, setRecentTasks] = useState([]); const [loading, setLoading] = useState(true); const [questions, setQuestions] = useState([]); const [askLoading, setAskLoading] = useState(false); const [customQuestion, setCustomQuestion] = useState(""); const [chatHistory, setChatHistory] = useState<{ q: string; a: string }[]>([]); const chatEndRef = useRef(null); const loadDashboardData = useCallback(async () => { setLoading(true); try { // 并行获取统计数据和任务列表 const [statsRes, tasksRes] = await Promise.all([ api.get(ENDPOINTS.TASK.STATS), api.get<{ items: Task[] }>(ENDPOINTS.TASK.LIST, { params: { page: 1, page_size: 5 } }), ]); setStats(statsRes.data); setRecentTasks(tasksRes.data.items || []); } catch (error) { console.error("加载数据失败:", error); } finally { setLoading(false); } }, []); const loadQuestions = useCallback(async () => { try { const res = await api.get(`/api/qa/suggested-questions`, { params: { task_id: 1, context: "" }, }); setQuestions(res.data.questions || []); } catch (error) { // 静默处理 } }, []); useEffect(() => { loadDashboardData(); loadQuestions(); }, [loadDashboardData, loadQuestions]); useEffect(() => { chatEndRef.current?.scrollIntoView({ behavior: "smooth" }); }, [chatHistory]); async function askQuestion(question: string) { if (!question) return; setAskLoading(true); try { const res = await api.post(`/api/qa/ask`, { task_id: recentTasks[0]?.id || 1, question, context: "", }); setChatHistory([...chatHistory, { q: question, a: res.data.answer }]); } catch (error) { setChatHistory([...chatHistory, { q: question, a: "暂时无法回答该问题,请稍后重试。" }]); } finally { setAskLoading(false); } } const formatPeriod = (period: string) => { const [year, month] = period.split("-"); return `${year}年${parseInt(month)}月`; }; return (
{/* Header */}

AI 工作台

智能驱动的工资对账与成本分析平台

{loading ? (
) : ( <> {/* Stats Grid */}

本月任务

{stats?.monthly_tasks ?? 0}

{stats?.current_period ? formatPeriod(stats.current_period) : "-"}

待处理异常

{stats?.pending_exceptions ?? 0}

需要人工处理

已完成

{stats?.completed_tasks ?? 0}

本月累计

匹配率

{stats?.match_rate ?? 0}%

本月平均
{/* AI Chat + Recent Tasks */}
{/* AI Chat Panel */}

AI 助手

基于真实数据回答您的问题

{/* Chat History */}
{chatHistory.length === 0 && !askLoading && (

向 AI 助手提问,获取基于对账数据的即时分析

)} {chatHistory.map((chat, i) => (

{chat.q}

{chat.a}

))} {askLoading && (
正在思考...
)}
{/* Suggested Questions */} {chatHistory.length === 0 && questions.length > 0 && (
{questions.slice(0, 4).map((q, i) => ( ))}
)} {/* Input */}
setCustomQuestion(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter" && customQuestion) { askQuestion(customQuestion); setCustomQuestion(""); } }} className="flex-1 h-10 px-3 rounded-lg border border-input bg-background text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" />
{/* Recent Tasks */}

最近任务

{recentTasks.length === 0 ? (

暂无对账任务

) : (
{recentTasks.map((task) => (
router.push(`/tasks/${task.id}/result`)} >
{formatPeriod(task.period)} {statusLabels[task.status]?.label || task.status}

{task.total_employees} 人 · {task.matched_count} 匹配 · {task.exception_count} 异常

))}
)}
{/* Quick Actions */}

快捷操作

router.push("/tasks/new")} >

新建对账任务

上传工资表、社保表进行对账

router.push("/exceptions")} >

查看异常

处理待解决的异常记录

router.push("/analysis")} >

成本分析

多维度人工成本分析

router.push("/vouchers")} >

凭证管理

生成和导出会计凭证

router.push("/settings/rules")} >

对账规则

配置对账规则和映射关系

)}
); }