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} + + +
+ )} +
+ ))} +
+ ); +}