"use client" import type { HomeworkAssignmentQuestionAnalytics } from "@/modules/homework/types" import { ScrollArea } from "@/shared/components/ui/scroll-area" const isRecord = (v: unknown): v is Record => typeof v === "object" && v !== null const getOptions = (content: unknown): Array<{ id: string; text: string }> => { if (!isRecord(content)) return [] const raw = content.options if (!Array.isArray(raw)) return [] const out: Array<{ id: string; text: string }> = [] for (const item of raw) { if (!isRecord(item)) continue const id = typeof item.id === "string" ? item.id : "" const text = typeof item.text === "string" ? item.text : "" if (!id || !text) continue out.push({ id, text }) } return out } const safeInlineJson = (v: unknown) => { try { const s = JSON.stringify(v) if (typeof s === "string" && s.length > 180) return `${s.slice(0, 180)}…` return s ?? String(v) } catch { return String(v) } } const formatAnswer = (answerContent: unknown, question: HomeworkAssignmentQuestionAnalytics | null) => { if (isRecord(answerContent) && "answer" in answerContent) answerContent = answerContent.answer if (answerContent === null || answerContent === undefined) return "未作答" const options = getOptions(question?.questionContent ?? null) const optionTextById = new Map(options.map((o) => [o.id, o.text] as const)) if (typeof answerContent === "boolean") return answerContent ? "True" : "False" if (typeof answerContent === "string") return optionTextById.get(answerContent) ?? answerContent if (Array.isArray(answerContent)) { const parts = answerContent .map((x) => (typeof x === "string" ? optionTextById.get(x) ?? x : x)) .map((x) => (typeof x === "string" ? x : safeInlineJson(x))) return parts.join(", ") } return safeInlineJson(answerContent) } const clamp01 = (v: number) => Math.max(0, Math.min(1, v)) function ErrorRatePieChart({ errorRate }: { errorRate: number }) { const pct = clamp01(errorRate) * 100 const r = 15.91549430918954 const dashA = pct const dashB = 100 - pct const showError = pct > 0 return ( {showError ? ( ) : null} {pct.toFixed(0)}% ) } export function HomeworkAssignmentQuestionErrorDetailPanel({ selected, gradedSampleCount, }: { selected: HomeworkAssignmentQuestionAnalytics | null gradedSampleCount: number }) { const wrongAnswers = selected?.wrongAnswers ?? [] const errorCount = selected?.errorCount ?? 0 const errorRate = selected?.errorRate ?? 0 return (
错题详情
{selected ? (
错误人数 {errorCount}
错误率 {(errorRate * 100).toFixed(1)}%
统计样本 {gradedSampleCount}
) : (
请选择左侧题目
)}
{!selected ? (
暂无数据
) : wrongAnswers.length === 0 ? (
暂无错误答案
) : (
错误答案列表(可滚动)
{wrongAnswers.map((item, idx) => (
{item.studentName}
{formatAnswer(item.answerContent, selected)}
))}
)}
) }