import { useEffect, useMemo, useState } from "react"; import { BarChart3, Building2, Check, TrendingUp, Users } from "lucide-react"; import { motion } from "motion/react"; import { completeDashboardTodo, getDashboardHome, type DashboardActivity, type DashboardHome, type DashboardStat, type DashboardTodo } from "@/lib/auth"; const DASHBOARD_PREVIEW_COUNT = 5; const DASHBOARD_HISTORY_PREVIEW_COUNT = 3; const baseStats = [ { name: "本月新增商机", metricKey: "monthlyOpportunities", icon: TrendingUp, color: "text-emerald-600 dark:text-emerald-400", bg: "bg-emerald-100 dark:bg-emerald-500/20" }, { name: "已推送OMS项目", metricKey: "pushedOmsProjects", icon: Users, color: "text-blue-600 dark:text-blue-400", bg: "bg-blue-100 dark:bg-blue-500/20" }, { name: "本月新增渠道", metricKey: "monthlyChannels", icon: Building2, color: "text-violet-600 dark:text-violet-400", bg: "bg-violet-100 dark:bg-violet-500/20" }, { name: "本月打卡次数", metricKey: "monthlyCheckins", icon: BarChart3, color: "text-amber-600 dark:text-amber-400", bg: "bg-amber-100 dark:bg-amber-500/20" }, ] as const; export default function Dashboard() { const [home, setHome] = useState({}); const [loading, setLoading] = useState(true); const [showAllActivities, setShowAllActivities] = useState(false); const [showAllHistoryTodos, setShowAllHistoryTodos] = useState(false); const [historyExpanded, setHistoryExpanded] = useState(false); const [completingTodoId, setCompletingTodoId] = useState(null); useEffect(() => { let cancelled = false; async function loadDashboard() { try { const data = await getDashboardHome(); if (!cancelled) { setHome(data ?? {}); } } catch { if (!cancelled) { setHome({}); } } finally { if (!cancelled) { setLoading(false); } } } void loadDashboard(); return () => { cancelled = true; }; }, []); useEffect(() => { setShowAllActivities(false); setShowAllHistoryTodos(false); setHistoryExpanded(false); }, [home.activities, home.todos]); const statMap = new Map((home.stats ?? []).map((item: DashboardStat) => [item.metricKey, item.value])); const stats = baseStats.map((stat) => ({ ...stat, value: statMap.get(stat.metricKey), })); const pendingTodos = useMemo( () => (home.todos ?? []).filter((item) => item.status !== "done"), [home.todos], ); const historyTodos = useMemo( () => (home.todos ?? []).filter((item) => item.status === "done"), [home.todos], ); const visibleHistoryTodos = showAllHistoryTodos ? historyTodos : historyTodos.slice(0, DASHBOARD_HISTORY_PREVIEW_COUNT); const activities = (home.activities?.length ? home.activities : [{ id: 0, title: "无", content: "无", timeText: "无" }]) as DashboardActivity[]; const visibleActivities = showAllActivities ? activities : activities.slice(0, DASHBOARD_PREVIEW_COUNT); const hasMoreActivities = activities.length > DASHBOARD_PREVIEW_COUNT && activities[0]?.id !== 0; const hasMoreHistoryTodos = historyTodos.length > DASHBOARD_HISTORY_PREVIEW_COUNT; const handleCompleteTodo = async (todoId: string) => { if (!todoId || completingTodoId === todoId) { return; } setCompletingTodoId(todoId); try { await completeDashboardTodo(todoId); setHome((current) => ({ ...current, todos: (current.todos ?? []).map((item) => ( item.id === todoId ? { ...item, status: "done", updatedAt: new Date().toISOString() } : item )), })); } catch { // Keep current UI state when completion fails silently. } finally { setCompletingTodoId(null); } }; return (

工作台

欢迎回来,{home.realName || "无"}。今天是你入职的第 {home.onboardingDays ?? 0} 天。

{loading ? ( ) : (
{stats.map((stat, i) => (

{stat.name}

{stat.value ?? 0}

))}

待办事项

共 {pendingTodos.length + historyTodos.length} 条
待办 {pendingTodos.length} 条未完成
{pendingTodos.length ? (
    {pendingTodos.map((task: DashboardTodo) => (
  • {getTodoDisplayTitle(task)}

  • ))}
) : (
暂无未完成待办
)}
{historyExpanded ? ( historyTodos.length ? ( <>
    {visibleHistoryTodos.map((task: DashboardTodo) => (
  • {getTodoDisplayTitle(task)}

  • ))}
{hasMoreHistoryTodos ? ( ) : null} ) : (
暂无历史待办
) ) : null}

最新动态

{visibleActivities.map((news: DashboardActivity, i: number) => (

{news.title || "无"}

{news.content || "无"}

{news.timeText || "无"}

))}
{hasMoreActivities && !showAllActivities ? ( ) : null}
)}
); } function DashboardSkeleton() { return (
{[0, 1, 2, 3].map((item) => (
))}
{[0, 1].map((item) => (
))}
{[0, 1, 2].map((item) => (
))}
); } function getTodoDisplayTitle(task: DashboardTodo) { const title = task.title?.trim(); if (!title) { return "无"; } if (task.bizType === "report" && title.startsWith("明日工作计划:")) { return title.slice("明日工作计划:".length).trim() || "明日工作计划"; } return title; }