diff --git a/src/app/parent/dashboard.tsx b/src/app/parent/dashboard.tsx
index ec9edbb..b94708e 100644
--- a/src/app/parent/dashboard.tsx
+++ b/src/app/parent/dashboard.tsx
@@ -163,6 +163,12 @@ export function ParentDashboard({
改分数/达标,删除误生成记录
+
+
+
📄 考试记录管理
+
改考试成绩/达标,删除误生成记录
+
+
diff --git a/src/app/parent/exam-records/exam-list.tsx b/src/app/parent/exam-records/exam-list.tsx
new file mode 100644
index 0000000..5d84dfe
--- /dev/null
+++ b/src/app/parent/exam-records/exam-list.tsx
@@ -0,0 +1,125 @@
+"use client";
+
+import { useState, useTransition } from "react";
+import { useRouter } from "next/navigation";
+import { Check, Pencil, Trash2, X } from "lucide-react";
+import { Button } from "@/components/ui/button";
+import { Checkbox } from "@/components/ui/checkbox";
+import { Input } from "@/components/ui/input";
+import { cn } from "@/lib/utils";
+import { deleteExamRecord, updateExamRecord } from "../actions";
+
+export type ExamRowItem = {
+ id: number;
+ childName: string;
+ paperTitle: string;
+ score: number;
+ passed: boolean;
+ takenAt: string;
+};
+
+// xuchao: 考试记录行内编辑(分数+达标开关)、删除;保存后刷新服务端列表
+export function ExamList({ rows }: { rows: ExamRowItem[] }) {
+ const router = useRouter();
+ const [editingId, setEditingId] = useState(null);
+ const [score, setScore] = useState("");
+ const [passed, setPassed] = useState(false);
+ const [msg, setMsg] = useState("");
+ const [pending, startTransition] = useTransition();
+
+ const startEdit = (r: ExamRowItem) => {
+ setEditingId(r.id);
+ setScore(String(r.score));
+ setPassed(r.passed);
+ setMsg("");
+ };
+
+ const save = () => {
+ if (editingId == null) return;
+ const s = Number(score);
+ startTransition(async () => {
+ const r = await updateExamRecord(editingId, s, passed);
+ if (r) setMsg(r);
+ else {
+ setEditingId(null);
+ router.refresh();
+ }
+ });
+ };
+
+ const remove = (id: number, label: string) => {
+ if (!confirm(`确定删除「${label}」这条考试记录?孩子可重新考试。`)) return;
+ startTransition(() => {
+ deleteExamRecord(id).then(() => router.refresh());
+ });
+ };
+
+ return (
+
+ {rows.length === 0 && (
+
+ )}
+ {rows.map((r) => (
+
+ {editingId === r.id ? (
+
+
+ {r.childName} · {r.paperTitle}
+
+
+
+ 分数
+ setScore(e.target.value)}
+ />
+
+
+ {msg &&
{msg}}
+
+
+
+
+
+
+ ) : (
+
+
{r.childName}
+
+ {r.paperTitle}
+
+
+ {r.score} 分 {r.passed ? "✅" : "❌"}
+
+
{r.takenAt}
+
+
+
+ )}
+
+ ))}
+
+ );
+}
diff --git a/src/app/parent/exam-records/page.tsx b/src/app/parent/exam-records/page.tsx
new file mode 100644
index 0000000..a4dac52
--- /dev/null
+++ b/src/app/parent/exam-records/page.tsx
@@ -0,0 +1,57 @@
+import Link from "next/link";
+import { redirect } from "next/navigation";
+import { desc, eq } from "drizzle-orm";
+import { BackgroundBlobs } from "@/components/background-blobs";
+import { db } from "@/db";
+import { examPapers, examRecords, users } from "@/db/schema";
+import { getSessionUser } from "@/lib/auth";
+import { ExamList } from "./exam-list";
+
+// xuchao: 考试成绩记录管理——编辑分数/达标、删除记录(卷已删时标题显示占位)
+export default async function ExamRecordsPage() {
+ const parent = await getSessionUser();
+ if (!parent) redirect("/login");
+ if (parent.role !== "parent") redirect("/kid");
+
+ const rows = await db
+ .select({
+ id: examRecords.id,
+ childName: users.displayName,
+ paperTitle: examPapers.title,
+ score: examRecords.score,
+ passed: examRecords.passed,
+ takenAt: examRecords.takenAt,
+ })
+ .from(examRecords)
+ .innerJoin(users, eq(users.id, examRecords.childUserId))
+ .leftJoin(examPapers, eq(examPapers.paperId, examRecords.paperId))
+ .where(eq(users.familyId, parent.familyId))
+ .orderBy(desc(examRecords.takenAt))
+ .limit(100);
+
+ return (
+
+
+
+
+ ← 返回家长中心
+
+ 考试记录管理
+ 最近 {rows.length} 条
+
+
+ 修改分数/达标状态或删除记录不会影响已发的积分与当日打卡;删除后孩子可重新考试。
+
+ ({
+ id: r.id,
+ childName: r.childName,
+ paperTitle: r.paperTitle ?? "已删试卷",
+ score: r.score ?? 0,
+ passed: r.passed,
+ takenAt: r.takenAt.toLocaleDateString("zh-CN"),
+ }))}
+ />
+
+ );
+}