第二期:企业信任风 UI + 打卡科目分类 + 英语语法学习模块

- 全站按 Corporate Trust 设计规范重做:靛蓝/紫罗兰渐变、Plus Jakarta Sans
  自托管字体、带色阴影、卡片悬浮、氛围光斑
- 打卡任务增加科目分类(语文/数学/英语/运动/其他),孩子端按科目分组
- 英语语法自学模块:线性解锁课程 + 课后/周/月测验引擎,测验达标
  自动联动当日英语打卡;家长概览显示语法进度
- 课程内容:A1→B1 完整大纲,9 周 54 课 + 9 周测 + 2 月测,讲解/例句/
  练习/测验均原创,仅参考两份语法书的主题编排

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
jacobxu666
2026-08-03 01:20:04 +08:00
co-authored by Claude Opus 4.8
parent b08f6649be
commit 6ed4d5a61e
45 changed files with 5824 additions and 92 deletions
+39
View File
@@ -0,0 +1,39 @@
"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;
}