新增数学思维自学板块与考试板块(9模块154课+初一上5套真实试卷客观题)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jacobxu666
2026-08-06 08:00:46 +08:00
co-authored by Claude Opus 4.8
parent 3473ecbf2b
commit bc53e2b2a5
38 changed files with 3393 additions and 10 deletions
+61
View File
@@ -0,0 +1,61 @@
// xuchao: 数学每周检测——从已点亮数学课的题池 seeded 抽 10 题
import { and, eq } from "drizzle-orm";
import { db } from "@/db";
import { mathPoints, mathProgress, mathWeeklyTest } from "@/db/schema";
import { extractQuiz, type QuizQ } from "@/lib/quiz-parse";
import { todayStr, weekKey } from "@/lib/dates";
export const currentMathWeekKey = () => weekKey(todayStr());
// xuchao: 确定性随机(同 seed 每次得到相同组卷,渲染与判分一致)
function hashStr(s: string): number {
let h = 5381;
for (let i = 0; i < s.length; i++) h = ((h << 5) + h + s.charCodeAt(i)) >>> 0;
return h >>> 0;
}
function mulberry32(a: number) {
return () => {
a |= 0;
a = (a + 0x6d2b79f5) | 0;
let t = Math.imul(a ^ (a >>> 15), 1 | a);
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
function seededSample<T>(arr: T[], seed: string, n: number): T[] {
const rnd = mulberry32(hashStr(seed));
const pool = [...arr];
for (let i = pool.length - 1; i > 0; i--) {
const j = Math.floor(rnd() * (i + 1));
[pool[i], pool[j]] = [pool[j], pool[i]];
}
return pool.slice(0, n);
}
// xuchao: 从已点亮数学课组卷;题池不足 5 题时用计算模块兜底
export async function buildMathWeeklyQuestions(childId: number, wk: string): Promise<QuizQ[]> {
const lit = await db
.select({ pointId: mathProgress.pointId })
.from(mathProgress)
.where(and(eq(mathProgress.childUserId, childId), eq(mathProgress.passed, true)));
const litIds = new Set(lit.map((r) => r.pointId));
const all = await db.select().from(mathPoints);
let pool: QuizQ[] = [];
for (const p of all) {
if (litIds.has(p.pointId)) pool.push(...extractQuiz(p.md));
}
if (pool.length < 5) {
for (const p of all) if (p.module === "calc") pool.push(...extractQuiz(p.md));
}
return seededSample(pool, `${childId}:math:${wk}`, 10);
}
export async function getMathWeeklyRecord(childId: number, wk: string) {
const [row] = await db
.select()
.from(mathWeeklyTest)
.where(and(eq(mathWeeklyTest.childUserId, childId), eq(mathWeeklyTest.weekKey, wk)))
.limit(1);
return row ?? null;
}