"use client"; import Link from "next/link"; import { useParams } from "next/navigation"; import { useCallback, useEffect, useMemo, useState, useTransition } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Checkbox } from "@/components/ui/checkbox"; import { Textarea } from "@/components/ui/textarea"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { enrollStudents, getCourseStudents, getTeacherCourseDetail, listAvailableStudents, } from "@/app/(protected)/dashboard/actions/teacher-courses"; import { createAssignment, listAssignableProblems, listCourseAssignments, } from "@/app/(protected)/dashboard/actions/teacher-assignments"; interface SelectableStudent { id: string; name: string | null; email: string; } interface SelectableProblem { id: string; displayId: number; difficulty: string; localizations: { content: string }[]; } export default function TeacherCourseDetailPage() { const params = useParams<{ courseId: string }>(); const courseId = params.courseId; const [error, setError] = useState(null); const [isPending, startTransition] = useTransition(); const [course, setCourse] = useState > | null>(null); const [students, setStudents] = useState>>([]); const [availableStudents, setAvailableStudents] = useState([]); const [assignments, setAssignments] = useState >>([]); const [problems, setProblems] = useState([]); const [selectedStudents, setSelectedStudents] = useState([]); const [assignmentTitle, setAssignmentTitle] = useState(""); const [assignmentDescription, setAssignmentDescription] = useState(""); const [assignmentDueAt, setAssignmentDueAt] = useState(""); const [selectedProblems, setSelectedProblems] = useState< Record >({}); const selectedProblemIds = useMemo( () => Object.keys(selectedProblems), [selectedProblems] ); const loadData = useCallback(async () => { try { const [courseData, studentsData, allStudents, assignmentData, problemData] = await Promise.all([ getTeacherCourseDetail(courseId), getCourseStudents(courseId), listAvailableStudents(), listCourseAssignments(courseId), listAssignableProblems(), ]); setCourse(courseData); setStudents(studentsData); setAvailableStudents(allStudents); setAssignments(assignmentData); setProblems(problemData); } catch (e) { setError(e instanceof Error ? e.message : "加载课程数据失败"); } }, [courseId]); useEffect(() => { loadData(); }, [loadData]); const handleEnrollStudents = () => { if (selectedStudents.length === 0) { return; } setError(null); startTransition(async () => { try { await enrollStudents(courseId, selectedStudents); setSelectedStudents([]); await loadData(); } catch (e) { setError(e instanceof Error ? e.message : "添加学生失败"); } }); }; const handleCreateAssignment = () => { if (!assignmentTitle.trim() || selectedProblemIds.length === 0) { return; } setError(null); startTransition(async () => { try { await createAssignment({ courseId, title: assignmentTitle, description: assignmentDescription, dueAt: assignmentDueAt || undefined, published: true, problems: selectedProblemIds.map((problemId, index) => ({ problemId, maxPoints: selectedProblems[problemId] ?? 100, order: index + 1, })), }); setAssignmentTitle(""); setAssignmentDescription(""); setAssignmentDueAt(""); setSelectedProblems({}); await loadData(); } catch (e) { setError(e instanceof Error ? e.message : "创建作业失败"); } }); }; const toggleStudent = (studentId: string, checked: boolean) => { setSelectedStudents((prev) => checked ? [...prev, studentId] : prev.filter((id) => id !== studentId) ); }; const toggleProblem = (problemId: string, checked: boolean) => { setSelectedProblems((prev) => { if (!checked) { const next = { ...prev }; delete next[problemId]; return next; } return { ...prev, [problemId]: prev[problemId] ?? 100 }; }); }; if (!course) { return
加载中...
; } return (
{course.title} {course.description || "暂无课程简介"} · 学生 {course._count.enrollments} 人 · 作业 {course._count.assignments} 个 学生管理 勾选学生后加入课程
{availableStudents.map((student) => ( ))}

已加入学生

{students.length === 0 ? (

暂无学生

) : ( students.map((item) => (

{item.user.name || "未命名"} ({item.user.email})

)) )}
创建作业 选择题目并设置每题分值 setAssignmentTitle(e.target.value)} placeholder="作业标题" />