新增数学思维自学板块与考试板块(9模块154课+初一上5套真实试卷客观题)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
3473ecbf2b
commit
bc53e2b2a5
@@ -0,0 +1,77 @@
|
||||
"use server";
|
||||
|
||||
// xuchao: 数学每周检测判分(同英语 takeWeekly,打卡联动数学)
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { and, eq, sql } from "drizzle-orm";
|
||||
import { getSessionUser } from "@/lib/auth";
|
||||
import { gradeAnswers, type AnswerValue } from "@/lib/grammar";
|
||||
import { buildMathWeeklyQuestions, currentMathWeekKey, getMathWeeklyRecord } from "@/lib/math-weekly";
|
||||
import { recordWrong } from "@/lib/wrongbook";
|
||||
import { db } from "@/db";
|
||||
import { taskInstances, mathWeeklyTest } from "@/db/schema";
|
||||
import { todayStr } from "@/lib/dates";
|
||||
|
||||
export type MathWeeklyResult =
|
||||
| { score: number; passed: boolean; correct: number; total: number; detail: boolean[] }
|
||||
| { error: string };
|
||||
|
||||
// 提交数学每周检测:判分、记录、错题入库、达标关联当日数学打卡
|
||||
export async function takeMathWeekly(answers: AnswerValue[]): Promise<MathWeeklyResult> {
|
||||
const user = await getSessionUser();
|
||||
if (!user || user.role !== "child") return { error: "会话无效,请重新激活设备" };
|
||||
const wk = currentMathWeekKey();
|
||||
const existing = await getMathWeeklyRecord(user.id, wk);
|
||||
if (existing) return { error: "本周已完成数学检测,下周再来。" };
|
||||
|
||||
const questions = await buildMathWeeklyQuestions(user.id, wk);
|
||||
if (questions.length === 0) return { error: "暂无可组卷的题目,先学几课吧。" };
|
||||
|
||||
const g = gradeAnswers(questions, answers);
|
||||
questions.forEach((q, i) => {
|
||||
if (!g.detail[i]) void recordWrong(user.id, "mweekly", wk, `数学周检测 ${wk}`, q, answers[i]);
|
||||
});
|
||||
|
||||
await db
|
||||
.insert(mathWeeklyTest)
|
||||
.values({
|
||||
childUserId: user.id,
|
||||
weekKey: wk,
|
||||
score: g.score,
|
||||
correct: g.correct,
|
||||
total: g.total,
|
||||
passed: g.passed,
|
||||
questions: JSON.stringify(questions),
|
||||
})
|
||||
.onDuplicateKeyUpdate({ set: { score: g.score, correct: g.correct, total: g.total, passed: g.passed } });
|
||||
|
||||
// 达标关联当日数学打卡
|
||||
if (g.passed) {
|
||||
const today = todayStr();
|
||||
const title = `数学周检测 · ${wk}`;
|
||||
const [ex] = await db
|
||||
.select({ id: taskInstances.id, status: taskInstances.status })
|
||||
.from(taskInstances)
|
||||
.where(and(eq(taskInstances.childUserId, user.id), eq(taskInstances.date, today), eq(taskInstances.title, title)))
|
||||
.limit(1);
|
||||
if (ex) {
|
||||
if (ex.status !== "done")
|
||||
await db.update(taskInstances).set({ status: "done", doneAt: sql`CURRENT_TIMESTAMP` }).where(eq(taskInstances.id, ex.id));
|
||||
} else {
|
||||
await db.insert(taskInstances).values({
|
||||
childUserId: user.id,
|
||||
date: today,
|
||||
title,
|
||||
subject: "math",
|
||||
status: "done",
|
||||
doneAt: new Date(),
|
||||
sortOrder: 95,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
revalidatePath("/math/weekly");
|
||||
revalidatePath("/kid");
|
||||
revalidatePath("/parent");
|
||||
revalidatePath("/wrongbook");
|
||||
return g;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// xuchao: 数学每周检测页(结构同英语 /weekly)
|
||||
import Link from "next/link";
|
||||
import { redirect } from "next/navigation";
|
||||
import { BackgroundBlobs } from "@/components/background-blobs";
|
||||
import { getSessionUser } from "@/lib/auth";
|
||||
import { buildMathWeeklyQuestions, currentMathWeekKey, getMathWeeklyRecord } from "@/lib/math-weekly";
|
||||
import { QuizBlock } from "@/app/learn/quiz-block";
|
||||
import { takeMathWeekly } from "./actions";
|
||||
|
||||
export default async function MathWeeklyPage() {
|
||||
const user = await getSessionUser();
|
||||
if (!user) redirect("/join");
|
||||
if (user.role !== "child") redirect("/parent");
|
||||
|
||||
const wk = currentMathWeekKey();
|
||||
const record = await getMathWeeklyRecord(user.id, wk);
|
||||
const questions = record ? [] : await buildMathWeeklyQuestions(user.id, wk);
|
||||
|
||||
return (
|
||||
<main className="relative mx-auto max-w-2xl space-y-5 p-4 pb-12">
|
||||
<BackgroundBlobs />
|
||||
<header className="flex items-center justify-between">
|
||||
<Link href="/math" className="text-sm font-medium text-orange-600">
|
||||
← 返回数学
|
||||
</Link>
|
||||
<h1 className="text-xl font-extrabold text-slate-900">数学每周检测</h1>
|
||||
<span className="text-xs text-muted-foreground">{wk}</span>
|
||||
</header>
|
||||
<p className="rounded-lg border-l-4 border-orange-400 bg-orange-50 px-3 py-2 text-sm text-orange-800">
|
||||
从你已点亮的数学课里抽 10 题,判断这周的掌握情况;达标自动计入今日数学打卡,错题进错题本。
|
||||
</p>
|
||||
|
||||
{record ? (
|
||||
<div
|
||||
className={
|
||||
record.passed
|
||||
? "rounded-2xl bg-gradient-to-r from-emerald-500 to-emerald-600 p-6 text-center text-white shadow-btn"
|
||||
: "rounded-2xl bg-gradient-to-r from-rose-500 to-rose-600 p-6 text-center text-white shadow-btn"
|
||||
}
|
||||
>
|
||||
<p className="text-4xl font-extrabold">{record.score} 分</p>
|
||||
<p className="mt-1 text-sm opacity-90">
|
||||
答对 {record.correct} / {record.total} · {record.passed ? "本周掌握良好 🎉" : "看看错题本,下周再战"}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<QuizBlock
|
||||
pointId=""
|
||||
questions={questions}
|
||||
submitter={takeMathWeekly}
|
||||
title="数学周检测"
|
||||
subtitle="10 题,做完提交;每题有解说,达标计入今日数学打卡。"
|
||||
passText="周检测达标 🎉 已计入今日数学打卡"
|
||||
backHref="/math"
|
||||
backLabel="返回数学地图"
|
||||
/>
|
||||
)}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user