"use client" import { useState } from "react" import { useRouter } from "next/navigation" import { toast } from "sonner" import { Award, AlertTriangle, Lightbulb, FileText, TrendingUp } from "lucide-react" import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/shared/components/ui/card" import { Badge } from "@/shared/components/ui/badge" import { Button } from "@/shared/components/ui/button" import { Input } from "@/shared/components/ui/input" import { Label } from "@/shared/components/ui/label" import { EmptyState } from "@/shared/components/ui/empty-state" import { usePermission } from "@/shared/hooks" import { Permissions } from "@/shared/types/permissions" import { MasteryRadarChart } from "./mastery-radar-chart" import { generateStudentReportAction } from "../actions" import type { DiagnosticReportWithDetails, MasteryRadarPoint, StudentMasterySummary } from "../types" interface StudentDiagnosticViewProps { summary: StudentMasterySummary | null reports: DiagnosticReportWithDetails[] classAverageMastery?: MasteryRadarPoint[] } export function StudentDiagnosticView({ summary, reports, classAverageMastery }: StudentDiagnosticViewProps) { const router = useRouter() const { hasPermission } = usePermission() const canManage = hasPermission(Permissions.DIAGNOSTIC_MANAGE) const [period, setPeriod] = useState(new Date().toISOString().slice(0, 7)) const [isGenerating, setIsGenerating] = useState(false) const handleGenerate = async () => { if (!summary) return setIsGenerating(true) const formData = new FormData() formData.set("studentId", summary.studentId) formData.set("period", period) const result = await generateStudentReportAction(null, formData) setIsGenerating(false) if (result.success) { toast.success(result.message) router.refresh() } else { toast.error(result.message || "Failed to generate report") } } if (!summary) { return ( ) } const radarData: MasteryRadarPoint[] = summary.allMastery.map((m) => { const classAvg = classAverageMastery?.find((c) => c.knowledgePoint === m.knowledgePointName) return { knowledgePoint: m.knowledgePointName, student: Math.round(m.masteryLevel * 100) / 100, classAverage: classAvg?.classAverage, } }) const publishedReports = reports.filter((r) => r.status === "published") const latestReport = publishedReports[0] ?? reports[0] ?? null return (
{/* 概览卡片 */}
Student

{summary.studentName}

Overall Mastery

{summary.averageMastery.toFixed(1)}%

Strengths

{summary.strengths.length}

Weaknesses

{summary.weaknesses.length}

{/* 雷达图 */} {/* 强项 / 弱项 */}
Strengths (≥80%) Knowledge points with high mastery. {summary.strengths.length === 0 ? (

No strengths identified yet.

) : (
    {summary.strengths.map((m) => (
  • {m.knowledgePointName} {m.masteryLevel.toFixed(1)}%
  • ))}
)}
Weaknesses (<60%) Knowledge points needing attention. {summary.weaknesses.length === 0 ? (

No weaknesses identified.

) : (
    {summary.weaknesses.map((m) => (
  • {m.knowledgePointName} {m.masteryLevel.toFixed(1)}%
  • ))}
)}
{/* 生成报告 */} {canManage ? ( Generate Diagnostic Report Generate an AI-analyzed diagnostic report for this student.
setPeriod(e.target.value)} className="w-[180px]" />
) : null} {/* 最新报告 / 建议 */} {latestReport ? ( Diagnostic Report {latestReport.status} Period: {latestReport.period ?? "-"} · Overall: {latestReport.overallScore?.toFixed(1) ?? "-"}% {latestReport.summary ? (

{latestReport.summary}

) : null} {latestReport.recommendations && latestReport.recommendations.length > 0 ? (

Recommendations

    {latestReport.recommendations.map((rec, i) => (
  • • {rec}
  • ))}
) : null}
) : null}
) }