// 考试列表页面(家长查看子女考试) // 依据:02-architecture-design.md §3.1 路由结构 // 路由:/parent/exams // 对标 student-portal /my-exams(家长只读视角) "use client"; import Link from "next/link"; import { useChildExams } from "@/hooks/useChildExams"; import { useChildSwitcher } from "@/hooks/useChildSwitcher"; import { formatDate, cn } from "@/lib/utils"; import type { ExamListItem, ExamStatus } from "@/types"; const STATUS_GROUPS: Array<{ key: ExamStatus; label: string; description: string; }> = [ { key: "in_progress", label: "进行中", description: "子女正在作答" }, { key: "not_started", label: "未开始", description: "等待开考" }, { key: "submitted", label: "已提交", description: "等待批改" }, { key: "graded", label: "已批改", description: "可查看成绩" }, { key: "expired", label: "已结束", description: "考试已结束" }, ]; const STATUS_BADGE_STYLES: Record = { not_started: "text-ink-muted", in_progress: "text-warning", submitted: "text-ink-muted", graded: "text-success", expired: "text-ink-muted", }; const STATUS_LABELS: Record = { not_started: "未开始", in_progress: "进行中", submitted: "已提交", graded: "已批改", expired: "已结束", }; function formatDuration(seconds: number): string { return `${Math.round(seconds / 60)} 分钟`; } export default function ExamsPage(): JSX.Element { const { currentChild } = useChildSwitcher(); const { exams, loading, error } = useChildExams(); if (loading) { return (
); } if (error) { return (
加载失败:{error.message}
); } const grouped = STATUS_GROUPS.map((g) => ({ ...g, items: exams.filter((e) => e.status === g.key), })); return (

{currentChild?.name}的考试

{exams.length === 0 ? (

暂无考试安排

) : (
{grouped.map((group) => group.items.length > 0 ? (

{group.label}

{group.items.length} 场 · {group.description}
    {group.items.map((exam) => (
  • ))}
) : null, )}
)}
); } function ExamCard({ exam }: { exam: ExamListItem }): JSX.Element { const isResult = exam.status === "submitted" || exam.status === "graded"; const linkHref = isResult ? `/parent/exams/${exam.id}/result` : null; const inner = (

{exam.subject}

{exam.name}

{STATUS_LABELS[exam.status]}
开考时间
{formatDate(exam.startsAt)}
截止时间
{formatDate(exam.expiresAt)}
时长
{formatDuration(exam.durationSeconds)}
题量
{exam.questionCount} 题
满分
{exam.totalScore} 分
{linkHref &&

查看结果 →

}
); if (!linkHref) return inner; return ( {inner} ); }