feat(课堂): 老师的课堂看板——布置这节课的题、看全班谁还没开始谁卡住了,布置的题直接出现在学生首页
2025 秋平均每节课有 14 个平时在用的学生一道都没交(三分之一),交了 3 次以上还没过的 平均不到 1 个;而老师原来只能一道题一道题打开统计弹窗看。 - 新表 class_lesson(迁移 0023,仅建表):一个班一天一行,存老师布置的 problem.id 与顺序; day 存东八区日历日文本,created_by CASCADE - GET /classroom/board:这个班今天的题 × 全班学生(通过与否不限今天、今天交了几次、 最后提交时间);不给班级时猜最近两小时提交人数最多的班,不记老师上次选的 - PUT /classroom/lesson:按展示题号布置,对不上的题号点名拒绝,空数组 = 清掉 - /me/class-activity 优先返回老师布置的题(source = teacher),否则照旧推断 - 前端 /classroom:没交过的名单置顶,按 没交过 → 卡住 → 在做 → 做完 排序,15 秒刷新; 投影模式只显示每题完成人数、不出名字;用户菜单给老师加入口 - 学生首页:老师布置的标题写「今天老师布置的题」,没人交时不显示 0/0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7e964fdbdd
commit
80106eaa04
12 files changed
+4992
-69
No files matched your search
@@ -81,15 +81,65 @@ export const classActivityProblemSchema = z.object({
|
||||
export const classActivitySchema = z.object({
|
||||
className: z.string().nullable(),
|
||||
day: z.string().nullable(),
|
||||
/** teacher = 老师在课堂看板里布置的;inferred = 从同班提交记录推断的 */
|
||||
source: z.enum(["teacher", "inferred"]).nullable(),
|
||||
problems: z.array(classActivityProblemSchema),
|
||||
})
|
||||
|
||||
/** 课堂看板里老师布置这节课的题:按输入顺序给展示题号,最多 20 道,空数组 = 清掉 */
|
||||
export const classLessonRequestSchema = z.object({
|
||||
className: z.string().trim().min(1),
|
||||
problemDisplayIds: z.array(z.string().trim().min(1)).max(20),
|
||||
})
|
||||
|
||||
export const classBoardProblemSchema = z.object({
|
||||
problemId: z.number().int(),
|
||||
problemDisplayId: z.string(),
|
||||
title: z.string(),
|
||||
})
|
||||
|
||||
export const classBoardCellSchema = z.object({
|
||||
/** accepted 看的是题库里(不含比赛)有没有通过过,不限今天 —— 以前做过的也算做完 */
|
||||
status: z.enum(["accepted", "tried", "none"]),
|
||||
/** 今天在这道题上交了几次 */
|
||||
attempts: z.number().int(),
|
||||
/** 第一次通过的时刻;今天之前通过的,前端显示成「之前」 */
|
||||
acceptedAt: z.string().nullable(),
|
||||
})
|
||||
|
||||
export const classBoardStudentSchema = z.object({
|
||||
userId: z.number().int(),
|
||||
username: z.string(),
|
||||
realName: z.string().nullable(),
|
||||
/** 和 problems 同序 */
|
||||
cells: z.array(classBoardCellSchema),
|
||||
/** 今天最后一次提交(任何题),没交过为 null */
|
||||
lastSubmitAt: z.string().nullable(),
|
||||
})
|
||||
|
||||
/**
|
||||
* 课堂看板:一个班、今天、这节课的几道题 × 全班学生。
|
||||
* className 为 null = 没指定班级、最近两小时也没有哪个班在交(没法猜)。
|
||||
*/
|
||||
export const classBoardSchema = z.object({
|
||||
className: z.string().nullable(),
|
||||
day: z.string(),
|
||||
source: z.enum(["teacher", "inferred"]).nullable(),
|
||||
problems: z.array(classBoardProblemSchema),
|
||||
students: z.array(classBoardStudentSchema),
|
||||
})
|
||||
|
||||
export type ClassRankItem = z.infer<typeof classRankItemSchema>
|
||||
export type ClassUserRank = z.infer<typeof classUserRankSchema>
|
||||
export type ClassComparison = z.infer<typeof classComparisonSchema>
|
||||
export type ClassComparisonResponse = z.infer<typeof classComparisonResponseSchema>
|
||||
|
||||
export type ClassActivity = z.infer<typeof classActivitySchema>
|
||||
export type ClassLessonRequest = z.infer<typeof classLessonRequestSchema>
|
||||
export type ClassBoard = z.infer<typeof classBoardSchema>
|
||||
export type ClassBoardProblem = z.infer<typeof classBoardProblemSchema>
|
||||
export type ClassBoardStudent = z.infer<typeof classBoardStudentSchema>
|
||||
export type ClassBoardCell = z.infer<typeof classBoardCellSchema>
|
||||
export type ClassActivityProblem = z.infer<typeof classActivityProblemSchema>
|
||||
|
||||
export type ClassUserRankItem = z.infer<typeof classUserRankItemSchema>
|
||||
|
||||
Reference in new issue
Block a user