"use client" import Link from "next/link" import { useTranslations } from "next-intl" import { Award, AlertTriangle, Lightbulb, FileText, History, ArrowRight } 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 { Tooltip, TooltipContent, TooltipTrigger } from "@/shared/components/ui/tooltip" import { EmptyState } from "@/shared/components/ui/empty-state" import { formatDate } from "@/shared/lib/utils" import { MasteryRadarChart } from "./mastery-radar-chart" import { getConfidenceLevel, confidenceBadgeVariant, type ConfidenceLevel, } from "./confidence-utils" import type { DiagnosticReportWithDetails, MasteryRadarPoint, StudentMasterySummary } from "../types" interface StudentDiagnosticViewProps { summary: StudentMasterySummary | null reports: DiagnosticReportWithDetails[] classAverageMastery?: MasteryRadarPoint[] /** * v3-P2-6: "练习"按钮的跳转基础路径。 * - 学生视角:默认 `/student/learning/assignments` * - 教师视角:传入 `/teacher/questions`(题目库支持 kp 查询参数筛选) * - 家长视角:传入 `null` 隐藏练习按钮(家长无练习入口) * 最终链接会附加 `?kp={knowledgePointId}` 实现个性化练习推荐。 */ practiceHrefBase?: string | null } export function StudentDiagnosticView({ summary, reports, classAverageMastery, practiceHrefBase = "/student/learning/assignments", }: StudentDiagnosticViewProps) { const t = useTranslations("diagnostic") 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") // v4-P1-3: 移除草稿回退逻辑,仅展示已发布报告 // 调用方(学生/家长页面)已传 status: "published" 过滤,此处双重保障 const latestReport = publishedReports[0] ?? null const statusLabel = (status: string): string => { if (status === "draft") return t("status.draft") if (status === "published") return t("status.published") if (status === "archived") return t("status.archived") return status } const typeLabel = (reportType: string): string => { if (reportType === "individual") return t("type.individual") if (reportType === "class") return t("type.class") if (reportType === "grade") return t("type.grade") return reportType } // v4-P3-7: 置信度标签与提示 const confidenceLabel = (level: ConfidenceLevel): string => { if (level === "high") return t("reportList.confidenceHigh") if (level === "medium") return t("reportList.confidenceMedium") if (level === "low") return t("reportList.confidenceLow") return t("reportList.confidenceInsufficient") } const confidenceHint = (level: ConfidenceLevel): string => { if (level === "high") return t("reportList.confidenceHighHint") if (level === "medium") return t("reportList.confidenceMediumHint") if (level === "low") return t("reportList.confidenceLowHint") return t("reportList.confidenceInsufficient") } return (
{/* 概览卡片 */}
{t("summary.student")}

{summary.studentName}

{t("summary.overallMastery")}

{summary.averageMastery.toFixed(1)}%

{t("summary.strengths")}

{summary.strengths.length}

{t("summary.weaknesses")}

{summary.weaknesses.length}

{/* 雷达图 */} {/* 强项 / 弱项 */}
{t("strengths.title")} {t("studentDiagnostic.strengthsDescription")} {summary.strengths.length === 0 ? (

{t("studentDiagnostic.noStrengths")}

) : (
    {summary.strengths.map((m) => (
  • {m.knowledgePointName} {m.masteryLevel.toFixed(1)}%
  • ))}
)}
{t("weaknesses.title")} {t("studentDiagnostic.weaknessesDescription")} {summary.weaknesses.length === 0 ? (

{t("studentDiagnostic.noWeaknesses")}

) : (
    {summary.weaknesses.map((m) => (
  • {m.knowledgePointName} {m.masteryLevel.toFixed(1)}%
    {practiceHrefBase ? ( ) : null}
  • ))}
)}
{/* 最新报告 / 建议 */} {latestReport ? ( {t("studentDiagnostic.diagnosticReportTitle")} {statusLabel(latestReport.status)} {(() => { const level = getConfidenceLevel(latestReport) return ( {confidenceLabel(level)} {confidenceHint(level)} ) })()} {t("studentDiagnostic.reportMeta", { period: latestReport.period ?? "-", score: latestReport.overallScore?.toFixed(1) ?? "-", })} {latestReport.summary ? (

{latestReport.summary}

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

{t("report.recommendations")}

    {latestReport.recommendations.map((rec, i) => (
  • • {rec}
  • ))}
) : null}
) : null} {/* 历史报告列表 */} {publishedReports.length > 1 ? ( {t("report.history")} {t("studentDiagnostic.historyDescription")}
{publishedReports.map((r) => (
{r.period ?? t("studentDiagnostic.untitledPeriod")} {typeLabel(r.reportType)}

{r.overallScore !== null ? t("studentDiagnostic.historyReportMeta", { date: formatDate(r.createdAt), score: r.overallScore.toFixed(1), }) : formatDate(r.createdAt)}

))}
) : null}
) }