- 全站按 Corporate Trust 设计规范重做:靛蓝/紫罗兰渐变、Plus Jakarta Sans 自托管字体、带色阴影、卡片悬浮、氛围光斑 - 打卡任务增加科目分类(语文/数学/英语/运动/其他),孩子端按科目分组 - 英语语法自学模块:线性解锁课程 + 课后/周/月测验引擎,测验达标 自动联动当日英语打卡;家长概览显示语法进度 - 课程内容:A1→B1 完整大纲,9 周 54 课 + 9 周测 + 2 月测,讲解/例句/ 练习/测验均原创,仅参考两份语法书的主题编排 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
40 lines
1.3 KiB
TypeScript
40 lines
1.3 KiB
TypeScript
"use server";
|
|
|
|
import { revalidatePath } from "next/cache";
|
|
import { getSessionUser } from "@/lib/auth";
|
|
import { entryBySeq } from "@/content/grammar";
|
|
import { completeSeq, grade, isUnlocked, passedSet } from "@/lib/grammar";
|
|
|
|
export type QuizResult =
|
|
| {
|
|
score: number;
|
|
passed: boolean;
|
|
correct: number;
|
|
total: number;
|
|
detail: boolean[];
|
|
}
|
|
| { error: string };
|
|
|
|
// 提交测验:服务端按标准答案计分(防篡改),达标即记进度并联动英语打卡
|
|
export async function submitQuiz(_prev: QuizResult | null, formData: FormData): Promise<QuizResult> {
|
|
const user = await getSessionUser();
|
|
if (!user || user.role !== "child") return { error: "会话无效,请重新激活设备" };
|
|
|
|
const seq = Number(formData.get("seq"));
|
|
const entry = entryBySeq(seq);
|
|
if (!entry) return { error: "课程不存在" };
|
|
|
|
const passed = await passedSet(user.id);
|
|
if (!isUnlocked(seq, passed)) return { error: "请先完成前面的课程" };
|
|
|
|
const answers = entry.quiz.map((_, i) => Number(formData.get(`a${i}`)));
|
|
const g = grade(entry.quiz, answers);
|
|
|
|
await completeSeq(user.id, seq, g.score, g.passed);
|
|
revalidatePath("/learn");
|
|
revalidatePath(`/learn/${seq}`);
|
|
revalidatePath("/kid");
|
|
revalidatePath("/parent");
|
|
return g;
|
|
}
|