家长端课程管理:可见语法检测明细+孩子错题本+跟读录音

- 语法检测:列出孩子每课检测的标题/分数/是否通过
- 错题本:展示孩子错题(题干/孩子答案/正确答案),含单词与语法错题
- 跟读录音:已有,保持可回放

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
jacobxu666
2026-08-05 20:42:17 +08:00
co-authored by Claude Opus 4.8
parent 2bbf349e0c
commit 44e58f48a6
2 changed files with 103 additions and 1 deletions
+39
View File
@@ -55,6 +55,15 @@ export type DevicesData = {
};
export type WeeklyRow = { childName: string; weekKey: string; score: number; passed: boolean };
export type RecordingRow = { childName: string; word: string; url: string; at: string };
export type GrammarTestRow = { childName: string; title: string; score: number; passed: boolean; at: string };
export type WrongItemRow = {
childName: string;
stem: string;
userAnswer: string;
correctAnswer: string;
sourceTitle: string;
mastered: boolean;
};
const tabCls = "data-[state=active]:bg-white data-[state=active]:text-indigo-600 data-[state=active]:shadow-soft";
@@ -74,12 +83,16 @@ export function ParentDashboard({
devices,
weekly,
recordings,
grammarTests,
wrongItems,
}: {
overview: OverviewData;
templates: TemplatesData;
devices: DevicesData;
weekly: WeeklyRow[];
recordings: RecordingRow[];
grammarTests: GrammarTestRow[];
wrongItems: WrongItemRow[];
}) {
return (
<main className="relative mx-auto max-w-3xl space-y-5 p-4 pb-10">
@@ -146,6 +159,32 @@ export function ParentDashboard({
))}
</div>
</div>
<div className="rounded-xl border border-slate-100 bg-white p-4 shadow-soft">
<p className="font-bold text-slate-900">📘 英语语法检测</p>
<div className="mt-2 space-y-1">
{grammarTests.length === 0 && <p className="text-xs text-muted-foreground">暂无检测记录</p>}
{grammarTests.map((g, i) => (
<p key={i} className="truncate text-xs text-slate-600">
{g.childName} · {g.title} · {g.score} 分 {g.passed ? "✅" : "❌"}
</p>
))}
</div>
</div>
<div className="rounded-xl border border-slate-100 bg-white p-4 shadow-soft">
<p className="font-bold text-slate-900">📒 孩子错题本</p>
<div className="mt-2 space-y-2">
{wrongItems.length === 0 && <p className="text-xs text-muted-foreground">暂无错题</p>}
{wrongItems.map((w, i) => (
<div key={i} className="rounded-lg bg-slate-50 p-2 text-xs">
<p className="font-medium text-slate-800">
{w.childName} · {w.stem}
</p>
<p className="mt-0.5 text-rose-600">答:{w.userAnswer || "未作答"}</p>
<p className="text-emerald-700">正:{w.correctAnswer}</p>
</div>
))}
</div>
</div>
</div>
</Section>
+64 -1
View File
@@ -190,7 +190,70 @@ export default async function ParentPage() {
at: dstr(r.createdAt),
}));
// ===== 英语语法检测明细 =====
const grammarRows = await db
.select({
childName: users.displayName,
title: grammarPoints.title,
score: grammarProgress.score,
passed: grammarProgress.passed,
completedAt: grammarProgress.completedAt,
})
.from(grammarProgress)
.innerJoin(users, eq(users.id, grammarProgress.childUserId))
.innerJoin(grammarPoints, eq(grammarPoints.pointId, grammarProgress.pointId))
.where(eq(users.familyId, parent.familyId))
.orderBy(desc(grammarProgress.completedAt))
.limit(20);
const grammarTests = grammarRows.map((g) => ({
childName: g.childName,
title: g.title,
score: g.score ?? 0,
passed: g.passed,
at: g.completedAt ? dstr(g.completedAt) : "",
}));
// ===== 孩子错题数据 =====
const wrongRows = await db
.select({
childName: users.displayName,
question: wrongBook.question,
userAnswer: wrongBook.userAnswer,
correctAnswer: wrongBook.correctAnswer,
sourceTitle: wrongBook.sourceTitle,
mastered: wrongBook.mastered,
})
.from(wrongBook)
.innerJoin(users, eq(users.id, wrongBook.childUserId))
.where(eq(users.familyId, parent.familyId))
.orderBy(desc(wrongBook.createdAt))
.limit(30);
const wrongItems = wrongRows.map((w) => {
let stem = "";
try {
stem = (JSON.parse(w.question) as { stem?: string }).stem ?? "";
} catch {
stem = "";
}
return {
childName: w.childName,
stem,
userAnswer: w.userAnswer ?? "",
correctAnswer: w.correctAnswer ?? "",
sourceTitle: w.sourceTitle ?? "",
mastered: w.mastered,
};
});
return (
<ParentDashboard overview={overview} templates={templates} devices={devices} weekly={weekly} recordings={recordings} />
<ParentDashboard
overview={overview}
templates={templates}
devices={devices}
weekly={weekly}
recordings={recordings}
grammarTests={grammarTests}
wrongItems={wrongItems}
/>
);
}