chih.yikuan
Redesign ClassLens v2: 3-step exam analysis workflow
bc45e54
Raw
History Blame Contribute Delete
5.36 kB
interface DataViewerProps {
parsedData: Record<string, unknown[]>;
}
export function DataViewer({ parsedData }: DataViewerProps) {
const questions = parsedData.questions?.[0] as { structured_data: { questions: Array<{ number: number; text: string; type: string; options: string[] | null; points: number | null }> } } | undefined;
const studentAnswers = parsedData.student_answers?.[0] as { structured_data: { students: Array<{ name: string; id: string; answers: Array<{ question_number: number; answer: string }> }> } } | undefined;
const teacherAnswers = parsedData.teacher_answers?.[0] as { structured_data: { answers: Array<{ question_number: number; correct_answer: string; explanation: string | null }> } } | undefined;
return (
<div className="space-y-6">
{/* Questions */}
{questions && (
<div className="card p-6">
<h3 className="font-display text-lg font-semibold text-[var(--color-text)] mb-4">
📝 考試題目 ({questions.structured_data.questions?.length || 0} 題)
</h3>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-[var(--color-border)]">
<th className="text-left py-2 px-3 text-[var(--color-text-muted)]">#</th>
<th className="text-left py-2 px-3 text-[var(--color-text-muted)]">題目</th>
<th className="text-left py-2 px-3 text-[var(--color-text-muted)]">類型</th>
<th className="text-left py-2 px-3 text-[var(--color-text-muted)]">分數</th>
</tr>
</thead>
<tbody>
{questions.structured_data.questions?.map((q) => (
<tr key={q.number} className="border-b border-[var(--color-border)]/50">
<td className="py-2 px-3 text-[var(--color-primary)] font-bold">{q.number}</td>
<td className="py-2 px-3 text-[var(--color-text)]">
<p>{q.text}</p>
{q.options && (
<div className="mt-1 text-xs text-[var(--color-text-muted)]">
{q.options.join(" | ")}
</div>
)}
</td>
<td className="py-2 px-3">
<span className="badge badge-success">{q.type}</span>
</td>
<td className="py-2 px-3 text-[var(--color-text-muted)]">{q.points ?? "-"}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{/* Student Answers */}
{studentAnswers && (
<div className="card p-6">
<h3 className="font-display text-lg font-semibold text-[var(--color-text)] mb-4">
👨‍🎓 學生答案 ({studentAnswers.structured_data.students?.length || 0} 位學生)
</h3>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-[var(--color-border)]">
<th className="text-left py-2 px-3 text-[var(--color-text-muted)]">學生</th>
{questions?.structured_data.questions?.map((q) => (
<th key={q.number} className="text-center py-2 px-3 text-[var(--color-text-muted)]">Q{q.number}</th>
))}
</tr>
</thead>
<tbody>
{studentAnswers.structured_data.students?.map((s) => (
<tr key={s.name || s.id} className="border-b border-[var(--color-border)]/50">
<td className="py-2 px-3 text-[var(--color-text)] font-medium">{s.name || s.id}</td>
{(questions?.structured_data.questions || s.answers)?.map((_, i) => {
const ans = s.answers?.find((a) => a.question_number === i + 1);
return (
<td key={i} className="text-center py-2 px-3 text-[var(--color-text-muted)]">
{ans?.answer ?? "-"}
</td>
);
})}
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{/* Teacher Answers */}
{teacherAnswers && (
<div className="card p-6">
<h3 className="font-display text-lg font-semibold text-[var(--color-text)] mb-4">
✅ 標準答案
</h3>
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3">
{teacherAnswers.structured_data.answers?.map((a) => (
<div key={a.question_number} className="bg-[var(--color-background)] rounded-lg p-3">
<span className="text-xs text-[var(--color-text-muted)]">Q{a.question_number}</span>
<p className="text-[var(--color-success)] font-semibold">{a.correct_answer}</p>
</div>
))}
</div>
</div>
)}
{!questions && !studentAnswers && !teacherAnswers && (
<div className="text-center py-12 text-[var(--color-text-muted)]">
尚未有解析資料
</div>
)}
</div>
);
}