新增积分系统:打卡/测试达标赚积分,纯累计可配置
- point_rule 规则表 + point_log 流水表(0008 迁移),唯一键防刷:同一事件首次达标才发放,重复静默返回 0 - 打卡分值随任务设置(模板/实例 points 字段,默认 10);测试类 6 种事件按规则表取值,各有默认分(单词 20/数学课 15/语法点 15/周测 50×2/考试通过 100) - 发放埋点 6 处:打卡、单词检测、数学课、语法知识点、英语/数学周测、考试通过;周测达标联动打卡实例不重复计分 - 孩子端:/kid 总积分徽章,新增 /points 积分页(总积分+流水),测验结果页即时显示「+N 积分」,周测结果页刷新后从流水取回已发积分 - 家长端:功能管理新增「积分管理」Section(规则分值配置+每孩子总积分/最近流水);任务管理内联编辑任务分值 - 修复:drizzle 将 mysql2 重复键错误包进 cause,沿错误链识别 ER_DUP_ENTRY Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
841f937b8e
commit
7a11a89031
@@ -10,9 +10,10 @@ import { recordWrong } from "@/lib/wrongbook";
|
||||
import { db } from "@/db";
|
||||
import { taskInstances, mathWeeklyTest } from "@/db/schema";
|
||||
import { todayStr } from "@/lib/dates";
|
||||
import { awardRulePoints } from "@/lib/points";
|
||||
|
||||
export type MathWeeklyResult =
|
||||
| { score: number; passed: boolean; correct: number; total: number; detail: boolean[] }
|
||||
| { score: number; passed: boolean; correct: number; total: number; detail: boolean[]; pointsEarned: number }
|
||||
| { error: string };
|
||||
|
||||
// 提交数学每周检测:判分、记录、错题入库、达标关联当日数学打卡
|
||||
@@ -44,8 +45,10 @@ export async function takeMathWeekly(answers: AnswerValue[]): Promise<MathWeekly
|
||||
})
|
||||
.onDuplicateKeyUpdate({ set: { score: g.score, correct: g.correct, total: g.total, passed: g.passed } });
|
||||
|
||||
// 达标关联当日数学打卡
|
||||
// 达标关联当日数学打卡,并发积分(首次达标才发)
|
||||
let pointsEarned = 0;
|
||||
if (g.passed) {
|
||||
pointsEarned = await awardRulePoints(user.id, "math_weekly", `week-${wk}`, `数学周检测 ${wk}`);
|
||||
const today = todayStr();
|
||||
const title = `数学周检测 · ${wk}`;
|
||||
const [ex] = await db
|
||||
@@ -73,5 +76,6 @@ export async function takeMathWeekly(answers: AnswerValue[]): Promise<MathWeekly
|
||||
revalidatePath("/kid");
|
||||
revalidatePath("/parent");
|
||||
revalidatePath("/wrongbook");
|
||||
return g;
|
||||
revalidatePath("/points");
|
||||
return { ...g, pointsEarned };
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ 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 { getAwardedPoints } from "@/lib/points";
|
||||
import { QuizBlock } from "@/app/learn/quiz-block";
|
||||
import { takeMathWeekly } from "./actions";
|
||||
|
||||
@@ -15,6 +16,8 @@ export default async function MathWeeklyPage() {
|
||||
const wk = currentMathWeekKey();
|
||||
const record = await getMathWeeklyRecord(user.id, wk);
|
||||
const questions = record ? [] : await buildMathWeeklyQuestions(user.id, wk);
|
||||
// xuchao: 已有记录时从流水取回本周达标的积分,结果页刷新后仍显示
|
||||
const awarded = record?.passed ? await getAwardedPoints(user.id, "math_weekly", `week-${wk}`) : 0;
|
||||
|
||||
return (
|
||||
<main className="relative mx-auto max-w-2xl space-y-5 p-4 pb-12">
|
||||
@@ -42,6 +45,7 @@ export default async function MathWeeklyPage() {
|
||||
<p className="mt-1 text-sm opacity-90">
|
||||
答对 {record.correct} / {record.total} · {record.passed ? "本周掌握良好 🎉" : "看看错题本,下周再战"}
|
||||
</p>
|
||||
{record.passed && awarded > 0 && <p className="mt-1 text-base font-extrabold">🪙 +{awarded} 积分</p>}
|
||||
</div>
|
||||
) : (
|
||||
<QuizBlock
|
||||
|
||||
Reference in New Issue
Block a user