diff --git a/src/app/parent/dashboard.tsx b/src/app/parent/dashboard.tsx
index 3540b3c..ec9edbb 100644
--- a/src/app/parent/dashboard.tsx
+++ b/src/app/parent/dashboard.tsx
@@ -68,8 +68,6 @@ export type DevicesData = {
isCurrent: boolean;
}[];
};
-export type WeeklyRow = { childName: string; weekKey: string; score: number; passed: boolean };
-
// xuchao: 家庭管理数据——家庭名 + 家长成员 + 孩子成员
export type FamilyData = {
familyName: string;
@@ -93,14 +91,12 @@ export function ParentDashboard({
overview,
templates,
devices,
- weekly,
points,
family,
}: {
overview: OverviewData;
templates: TemplatesData;
devices: DevicesData;
- weekly: WeeklyRow[];
points: PointsData;
family: FamilyData;
}) {
@@ -161,17 +157,12 @@ export function ParentDashboard({
改标题/目标/课文,保存即生效
-
-
📝 每周检测成绩
-
- {weekly.length === 0 &&
暂无检测记录
}
- {weekly.map((w, i) => (
-
- {w.childName} · {w.weekKey} · {w.score} 分 {w.passed ? "✅" : "❌"}
-
- ))}
+
+
+
📝 每周检测成绩管理
+
改分数/达标,删除误生成记录
-
+
diff --git a/src/app/parent/page.tsx b/src/app/parent/page.tsx
index 1b3c1bb..5ea89ab 100644
--- a/src/app/parent/page.tsx
+++ b/src/app/parent/page.tsx
@@ -32,7 +32,6 @@ import {
type OverviewData,
type PointsData,
type TemplatesData,
- type WeeklyRow,
} from "./dashboard";
const SH = { timeZone: "Asia/Shanghai" } as const;
@@ -181,26 +180,6 @@ export default async function ParentPage() {
})),
};
- // ===== 周测成绩(课程管理) =====
- const weeklyRows = await db
- .select({
- childName: users.displayName,
- weekKey: weeklyTest.weekKey,
- score: weeklyTest.score,
- passed: weeklyTest.passed,
- })
- .from(weeklyTest)
- .innerJoin(users, eq(users.id, weeklyTest.childUserId))
- .where(eq(users.familyId, parent.familyId))
- .orderBy(desc(weeklyTest.takenAt))
- .limit(10);
- const weekly: WeeklyRow[] = weeklyRows.map((w) => ({
- childName: w.childName,
- weekKey: w.weekKey,
- score: w.score ?? 0,
- passed: w.passed,
- }));
-
// ===== 积分管理(规则 + 每孩子总积分/最近流水) =====
const rules = await listPointRules();
const pointsData: PointsData = { rules, kids: [] };
@@ -243,7 +222,6 @@ export default async function ParentPage() {
overview={overview}
templates={templates}
devices={devices}
- weekly={weekly}
points={pointsData}
family={family}
/>
diff --git a/src/app/parent/weekly-records/page.tsx b/src/app/parent/weekly-records/page.tsx
new file mode 100644
index 0000000..6778c8f
--- /dev/null
+++ b/src/app/parent/weekly-records/page.tsx
@@ -0,0 +1,56 @@
+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 { users, weeklyTest } from "@/db/schema";
+import { getSessionUser } from "@/lib/auth";
+import { WeeklyList } from "./weekly-list";
+
+// xuchao: 周测成绩管理——编辑分数/达标、删除误生成记录(不联动积分打卡)
+export default async function WeeklyRecordsPage() {
+ const parent = await getSessionUser();
+ if (!parent) redirect("/login");
+ if (parent.role !== "parent") redirect("/kid");
+
+ const rows = await db
+ .select({
+ id: weeklyTest.id,
+ childName: users.displayName,
+ weekKey: weeklyTest.weekKey,
+ score: weeklyTest.score,
+ passed: weeklyTest.passed,
+ takenAt: weeklyTest.takenAt,
+ })
+ .from(weeklyTest)
+ .innerJoin(users, eq(users.id, weeklyTest.childUserId))
+ .where(eq(users.familyId, parent.familyId))
+ .orderBy(desc(weeklyTest.takenAt))
+ .limit(100);
+
+ return (
+
+
+
+
+ ← 返回家长中心
+
+ 每周检测成绩管理
+ 最近 {rows.length} 条
+
+
+ 修改分数/达标状态或删除记录不会影响已发的积分与当日打卡。
+
+ ({
+ id: r.id,
+ childName: r.childName,
+ weekKey: r.weekKey,
+ score: r.score ?? 0,
+ passed: r.passed,
+ takenAt: r.takenAt.toLocaleDateString("zh-CN"),
+ }))}
+ />
+
+ );
+}
diff --git a/src/app/parent/weekly-records/weekly-list.tsx b/src/app/parent/weekly-records/weekly-list.tsx
new file mode 100644
index 0000000..4de1267
--- /dev/null
+++ b/src/app/parent/weekly-records/weekly-list.tsx
@@ -0,0 +1,124 @@
+"use client";
+
+import { useState, useTransition } from "react";
+import { useRouter } from "next/navigation";
+import { Check, Pencil, RotateCcw, 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 { deleteWeeklyRecord, updateWeeklyRecord } from "../actions";
+
+export type WeeklyRowItem = {
+ id: number;
+ childName: string;
+ weekKey: string;
+ score: number;
+ passed: boolean;
+ takenAt: string;
+};
+
+// xuchao: 周测成绩行内编辑(分数+达标开关)、删除;保存后刷新服务端列表
+export function WeeklyList({ rows }: { rows: WeeklyRowItem[] }) {
+ 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: WeeklyRowItem) => {
+ setEditingId(r.id);
+ setScore(String(r.score));
+ setPassed(r.passed);
+ setMsg("");
+ };
+
+ const save = () => {
+ if (editingId == null) return;
+ const s = Number(score);
+ const err = (t: string) => setMsg(t);
+ startTransition(async () => {
+ const r = await updateWeeklyRecord(editingId, s, passed);
+ if (r) err(r);
+ else {
+ setEditingId(null);
+ router.refresh();
+ }
+ });
+ };
+
+ const remove = (id: number, label: string) => {
+ if (!confirm(`确定删除「${label}」的这条周测记录?孩子可重新检测。`)) return;
+ startTransition(() => {
+ deleteWeeklyRecord(id).then(() => router.refresh());
+ });
+ };
+
+ return (
+
+ {rows.length === 0 && (
+
+ )}
+ {rows.map((r) => (
+
+ {editingId === r.id ? (
+
+
+ {r.childName} · {r.weekKey}
+
+
+
+ 分数
+ setScore(e.target.value)}
+ />
+
+
+ {msg &&
{msg}}
+
+
+
+
+
+
+ ) : (
+
+
{r.childName}
+
{r.weekKey}
+
+ {r.score} 分 {r.passed ? "✅" : "❌"}
+
+
{r.takenAt}
+
+
+
+ )}
+
+ ))}
+
+ );
+}