import { Alert, Button, Progress, Skeleton } from 'antd' import { ArrowRightOutlined, ReloadOutlined } from '@ant-design/icons' import { useQuery } from '@tanstack/react-query' import http from '../api/http' import { useAuthStore } from '../stores/auth' import StudentDashboardPage from './dashboard/StudentDashboardPage' import TeacherDashboardPage from './dashboard/TeacherDashboardPage' import './dashboard/role-dashboard.css' interface DashboardData { audience: { level: string title: string scopeName: string description: string } currentTerm?: { id: string name: string startDate: string endDate: string } counts: { students: number teachers: number courses: number teachingTasks: number publishedTeachingTasks: number scheduledTeachingTasks: number courseEnrollments: number gradeSheets: number publishedGradeSheets: number submittedGradeSheets: number openCourseSelectionRounds: number } pending: Record greeting: { title: string subtitle: string narrative: string } } const number = new Intl.NumberFormat('zh-CN') function percent(value: number, total: number) { return total > 0 ? Math.min(100, Math.round(value / total * 100)) : 0 } function formatDate(value?: string) { if (!value) return '待设置' const date = new Date(`${value.slice(0, 10)}T00:00:00`) return new Intl.DateTimeFormat('zh-CN', { month: 'long', day: 'numeric' }).format(date) } function AdminDashboardPage() { const query = useQuery({ queryKey: ['dashboard'], queryFn: async () => (await http.get('/dashboard')).data, }) if (query.isLoading) return
if (query.isError || !query.data) { return (
} onClick={() => void query.refetch()}>重新加载} />
) } const data = query.data const metrics = [ { label: '在籍学生', value: data.counts.students, hint: `${data.audience.scopeName}当前有效学籍` }, { label: '教师档案', value: data.counts.teachers, hint: '当前数据范围内的教师' }, { label: '本学期教学班', value: data.counts.teachingTasks, hint: `${data.counts.publishedTeachingTasks} 个已发布` }, { label: '有效选课', value: data.counts.courseEnrollments, hint: `${data.counts.openCourseSelectionRounds} 个批次开放中` }, ] const readiness = [ { label: '任务发布', value: data.counts.publishedTeachingTasks, total: data.counts.teachingTasks }, { label: '课表覆盖', value: data.counts.scheduledTeachingTasks, total: data.counts.publishedTeachingTasks }, { label: '成绩发布', value: data.counts.publishedGradeSheets, total: data.counts.gradeSheets }, ] const pending = Object.entries(data.pending).filter(([, value]) => value > 0) return (
React 迁移预览当前页面直接读取现有 `/api/dashboard`,业务数据未使用模拟值。
{data.audience.title}

{data.greeting.title}

{data.greeting.narrative || data.audience.description}

ACADEMIC TERM {data.currentTerm?.name ?? '尚未设置当前学期'} · {formatDate(data.currentTerm?.startDate)}—{formatDate(data.currentTerm?.endDate)}
{metrics.map((metric) => (
{metric.label}{number.format(metric.value)}{metric.hint}
))}

教学运行准备度

{readiness.map((item) => { const value = percent(item.value, item.total) return (
{item.label}{value}%
) })}

等待处理

{pending.reduce((sum, [, value]) => sum + value, 0)} 项
{pending.length === 0 ? : pending.slice(0, 6).map(([key, value]) => (
{key}{value}
))}
) } export default function DashboardPage() { const roles = useAuthStore((state) => state.user?.roles ?? []) const isStudent = roles.includes('Student') && !roles.some((role) => ['SuperAdmin', 'AcademicAdmin', 'CollegeAdmin', 'Counselor'].includes(role)) const isTeacher = roles.includes('Teacher') && !roles.some((role) => ['SuperAdmin', 'AcademicAdmin', 'CollegeAdmin', 'Counselor', 'Student'].includes(role)) if (isStudent) return if (isTeacher) return return }