diff --git a/apps/api/src/db/schema.ts b/apps/api/src/db/schema.ts index 3b25cd6..f875c7f 100644 --- a/apps/api/src/db/schema.ts +++ b/apps/api/src/db/schema.ts @@ -1431,6 +1431,7 @@ export const classLesson = pgTable( * 没有它。写入侧在 PUT /classroom/lesson 按 lessonLanguageSchema 校验过 */ language: text().$type(), + /** 这天第一次布置的老师,别的老师「改」也不换(和 createdAt 一样)。看板上写「HH:mm 谁 布置」 */ createdBy: integer("created_by").notNull(), /** * 这天第一次布置的时刻,之后「改」只动 updatedAt。清掉(删行)再布置算重新开始。 diff --git a/apps/api/src/routes/classroom.ts b/apps/api/src/routes/classroom.ts index 130af28..1840e0b 100644 --- a/apps/api/src/routes/classroom.ts +++ b/apps/api/src/routes/classroom.ts @@ -105,15 +105,21 @@ async function visibleProblems(ids: number[]) { return new Map(rows.map((row) => [row.id, row])) } -/** 老师给这个班今天布置的题(problem.id,按输入顺序)、选的语言和布置时刻;没布置为 null */ +/** + * 老师给这个班今天布置的题(problem.id,按输入顺序)、选的语言、布置时刻和布置的老师; + * 没布置为 null。老师写真名:老师之间认的是名字,用户名(lwp0201、little)认不出是谁 + */ async function lessonPlan(className: string, day: string) { const [row] = await db .select({ problemIds: schema.classLesson.problemIds, language: schema.classLesson.language, createdAt: schema.classLesson.createdAt, + createdBy: sql`coalesce(nullif(${schema.userProfile.realName}, ''), ${schema.user.username})`, }) .from(schema.classLesson) + .innerJoin(schema.user, eq(schema.user.id, schema.classLesson.createdBy)) + .leftJoin(schema.userProfile, eq(schema.userProfile.userId, schema.classLesson.createdBy)) .where(and(eq(schema.classLesson.className, className), eq(schema.classLesson.day, day))) .limit(1) return row?.problemIds.length ? row : null @@ -142,6 +148,7 @@ async function classLessonProblems(className: string, lookbackDays: number) { day: today, language: plan.language ?? null, assignedAt: plan.createdAt, + assignedBy: plan.createdBy, problems: planned.flatMap((id) => { const problem = problems.get(id) if (!problem) return [] @@ -174,6 +181,7 @@ async function classLessonProblems(className: string, lookbackDays: number) { // 推断出来的课不知道老师要的是哪种语言,不限 language: null, assignedAt: null, + assignedBy: null, problems: picked.flatMap((row) => { const problem = problems.get(row.problemId) return problem @@ -400,6 +408,7 @@ classroomRoutes.get("/classroom/board", requireTeacher, async (c) => { source: null, language: null, assignedAt: null, + assignedBy: null, lastLanguage: null, problems: [], students: [], @@ -603,6 +612,7 @@ classroomRoutes.get("/classroom/board", requireTeacher, async (c) => { source: lesson.source, language: lesson.language, assignedAt: lesson.assignedAt, + assignedBy: lesson.assignedBy, lastLanguage: last?.language ?? null, problems: lesson.problems.map((problem) => ({ problemId: problem.id, @@ -742,6 +752,7 @@ classroomRoutes.get("/classroom/today", requireTeacher, async (c) => { className, source: lesson.source, assignedAt: lesson.assignedAt, + assignedBy: lesson.assignedBy, problems: lesson.problems.map((problem) => ({ problemDisplayId: problem.displayId, title: problem.title, @@ -867,7 +878,8 @@ classroomRoutes.put("/classroom/lesson", requireTeacher, async (c) => { }) .onConflictDoUpdate({ target: [schema.classLesson.className, schema.classLesson.day], - set: { problemIds, language, createdBy: user.id, updatedAt: now }, + // 「改」不换布置的人,和 createdAt 一样认第一次 + set: { problemIds, language, updatedAt: now }, }) return success(c, null) }) diff --git a/apps/web/src/oj/classroom/board.vue b/apps/web/src/oj/classroom/board.vue index 999174c..f052213 100644 --- a/apps/web/src/oj/classroom/board.vue +++ b/apps/web/src/oj/classroom/board.vue @@ -465,7 +465,7 @@ function lastText(student: ClassBoardStudent) { {{ problem.problemDisplayId }} - {{ parseTime(board.assignedAt, "HH:mm") }} 布置 + {{ parseTime(board.assignedAt, "HH:mm") }} {{ board.assignedBy }} 布置 diff --git a/apps/web/src/oj/home/TeacherHome.vue b/apps/web/src/oj/home/TeacherHome.vue index 15becf0..f84ee37 100644 --- a/apps/web/src/oj/home/TeacherHome.vue +++ b/apps/web/src/oj/home/TeacherHome.vue @@ -53,7 +53,7 @@ function stateOf(row: ClassRow) { function metaOf(row: ClassRow) { const parts = [ row.source === "teacher" && row.assignedAt - ? `${parseTime(row.assignedAt, "HH:mm")} 布置了 ${row.problems.length} 道` + ? `${parseTime(row.assignedAt, "HH:mm")} ${row.assignedBy} 布置了 ${row.problems.length} 道` : `做了 ${row.problems.length} 道`, ] if (row.activeCount) parts.push(`${row.activeCount}/${row.rosterCount} 人交过`) diff --git a/packages/contract/src/classroom.ts b/packages/contract/src/classroom.ts index 7d7d2fa..a84d62e 100644 --- a/packages/contract/src/classroom.ts +++ b/packages/contract/src/classroom.ts @@ -172,6 +172,8 @@ export const classBoardSchema = z.object({ language: lessonLanguageSchema, /** 今天第一次布置的时刻,之后改题不变;推断出来的课为 null */ assignedAt: z.string().nullable(), + /** 第一次布置的老师(真名,没有真名用用户名);推断出来的课为 null */ + assignedBy: z.string().nullable(), /** 这个班最近一次布置选的语言(含今天),给语言下拉当默认值;从没选过为 null */ lastLanguage: lessonLanguageSchema, problems: z.array(classBoardProblemSchema), @@ -210,6 +212,8 @@ export const classTodaySchema = z.object({ source: z.enum(["teacher", "inferred"]).nullable(), /** 老师布置的时刻;推断出来的为 null */ assignedAt: z.string().nullable(), + /** 布置的老师;推断出来的为 null */ + assignedBy: z.string().nullable(), problems: z.array( z.object({ problemDisplayId: z.string(),