"use client" import { useState, useTransition } from "react" import { useRouter } from "next/navigation" import { useTranslations } from "next-intl" import { Zap } from "lucide-react" import { toast } from "sonner" import { Button } from "@/shared/components/ui/button" import { Badge } from "@/shared/components/ui/badge" import { Checkbox } from "@/shared/components/ui/checkbox" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/shared/components/ui/table" import { formatDate } from "@/shared/lib/utils" import { batchAutoGradeSubmissionsAction } from "../actions" import type { HomeworkSubmissionListItem } from "../types" interface HomeworkBatchGradingViewProps { submissions: HomeworkSubmissionListItem[] } /** * V3-7: 批量批改视图 * * 教师在提交列表页可勾选多份提交,一键自动批改所有客观题。 * 对标智学网的批量批改功能。 */ export function HomeworkBatchGradingView({ submissions }: HomeworkBatchGradingViewProps) { const t = useTranslations("examHomework") const router = useRouter() const [selectedIds, setSelectedIds] = useState>(new Set()) const [isPending, startTransition] = useTransition() const selectableSubmissions = submissions.filter( (s) => s.status === "submitted" ) const allSelectableSelected = selectableSubmissions.length > 0 && selectableSubmissions.every((s) => selectedIds.has(s.id)) const toggleSelectAll = () => { if (allSelectableSelected) { setSelectedIds(new Set()) } else { setSelectedIds(new Set(selectableSubmissions.map((s) => s.id))) } } const toggleSelect = (id: string) => { setSelectedIds((prev) => { const next = new Set(prev) if (next.has(id)) { next.delete(id) } else { next.add(id) } return next }) } const handleBatchAutoGrade = () => { if (selectedIds.size === 0) { toast.error(t("homework.grade.batchSelectAtLeastOne")) return } startTransition(async () => { const formData = new FormData() formData.set("submissionIds", JSON.stringify(Array.from(selectedIds))) const result = await batchAutoGradeSubmissionsAction(null, formData) if (result.success) { toast.success(result.message) setSelectedIds(new Set()) router.refresh() } else { toast.error(result.message || t("homework.grade.batchFailed")) } }) } return (
{selectedIds.size > 0 && (
{t("homework.grade.batchSelected", { count: selectedIds.size })}
)}
{t("homework.grade.student")} {t("homework.grade.status")} {t("homework.grade.submitted")} {t("homework.grade.score")} {t("homework.grade.action")} {submissions.map((s) => { const isSelectable = s.status === "submitted" const isSelected = selectedIds.has(s.id) return ( {isSelectable ? ( toggleSelect(s.id)} aria-label={t("homework.grade.selectRow")} /> ) : ( )} {s.studentName} {s.status} {s.isLate ? {t("homework.grade.late")} : null} {s.submittedAt ? formatDate(s.submittedAt) : "-"} {typeof s.score === "number" ? s.score : "-"} {t("homework.grade.title")} ) })}
) }