From 923516ad368a7ce6165460caa89ab0bfafb6815d Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Tue, 29 Sep 2026 19:02:33 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E8=AF=BE=E5=A0=82=E7=9C=8B=E6=9D=BF):=20?= =?UTF-8?q?=E8=BF=99=E8=8A=82=E8=AF=BE=E6=95=B4=E7=8F=AD=E5=9C=A8=E7=94=BB?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E5=9B=BE=E6=97=B6=EF=BC=8C=E7=82=B9=E6=A0=BC?= =?UTF-8?q?=E5=AD=90=E3=80=81=E7=82=B9=E5=90=8D=E5=AD=97=E8=BF=9B=E5=88=B0?= =?UTF-8?q?=E7=9A=84=E6=98=AF=E4=B8=80=E7=89=87=E7=A9=BA=E7=9A=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=8F=90=E4=BA=A4=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 看板格子的次数原来是代码和流程图加在一起的,链接却总是去代码那边;名字链接看的「今天交过」 还把比赛提交算了进去。现在格子分开给代码 / 流程图次数、学生分开给今天交过代码 / 画过流程图, 只画了流程图的跳到提交列表的「流程图」那边。 Co-Authored-By: Claude Opus 5.5 --- apps/api/src/routes/classroom.ts | 12 +++++++++++ apps/web/src/oj/classroom/board.vue | 32 ++++++++++++++++++++++------- packages/contract/src/classroom.ts | 14 ++++++++++++- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/apps/api/src/routes/classroom.ts b/apps/api/src/routes/classroom.ts index 3f59ae2..f0de915 100644 --- a/apps/api/src/routes/classroom.ts +++ b/apps/api/src/routes/classroom.ts @@ -560,6 +560,10 @@ classroomRoutes.get("/classroom/board", requireTeacher, async (c) => { .select({ userId: schema.submission.userId, lastAt: sql`max(${schema.submission.createTime})`, + // 非比赛的最后一次,给「点名字跳提交列表」判断用(列表只列非比赛的) + lastPublicAt: sql< + string | null + >`max(${schema.submission.createTime}) filter (where ${isNull(schema.submission.contestId)})`, }) .from(schema.submission) .where( @@ -625,6 +629,10 @@ classroomRoutes.get("/classroom/board", requireTeacher, async (c) => { const cellByKey = new Map(cells.map((row) => [`${row.userId}:${row.problemId}`, row])) const drawnByKey = new Map(drawn.map((row) => [`${row.userId}:${row.problemId}`, row])) const lastByUser = new Map(lastSubmits.map((row) => [row.userId, row.lastAt])) + const codeTodayUsers = new Set( + lastSubmits.filter((row) => row.lastPublicAt).map((row) => row.userId), + ) + const drawnTodayUsers = new Set(lastDrawn.map((row) => row.userId)) for (const row of lastDrawn) { const known = lastByUser.get(row.userId) if (!known || Date.parse(row.lastAt) > Date.parse(known)) lastByUser.set(row.userId, row.lastAt) @@ -656,10 +664,14 @@ classroomRoutes.get("/classroom/board", requireTeacher, async (c) => { return { status: !cell && !flow ? "none" : acceptedAt ? "accepted" : "tried", attempts: (cell?.attempts ?? 0) + (flow?.attempts ?? 0), + codeAttempts: cell?.attempts ?? 0, + flowchartAttempts: flow?.attempts ?? 0, acceptedAt, } }), lastSubmitAt: lastByUser.get(student.userId) ?? null, + codeToday: codeTodayUsers.has(student.userId), + drawnToday: drawnTodayUsers.has(student.userId), recentAttended: attendedByUser.get(student.userId) ?? 0, }) satisfies ClassBoardStudent, ), diff --git a/apps/web/src/oj/classroom/board.vue b/apps/web/src/oj/classroom/board.vue index 7767c7a..490385a 100644 --- a/apps/web/src/oj/classroom/board.vue +++ b/apps/web/src/oj/classroom/board.vue @@ -224,16 +224,24 @@ const GROUP_LABEL: Record< const router = useRouter() /** - * 点格子 / 名字到提交列表看他今天交的代码。新标签打开:看板多半正投在屏幕上,别把它顶掉。 - * 用户名按整名匹配(学号互相包含是常态,ks24a1 会混进 ks24a10) + * 点格子 / 名字到提交列表看他今天交的。新标签打开:看板多半正投在屏幕上,别把它顶掉。 + * 用户名按整名匹配(学号互相包含是常态,ks24a1 会混进 ks24a10)。 + * + * 今天只画了流程图、没写代码的,跳到列表的「流程图」那边 —— 不然这节课整班在画流程图时, + * 点进去是一片「没有符合条件的提交」 */ -function submissionsHref(student: ClassBoardStudent, problemDisplayId?: string) { +function submissionsHref( + student: ClassBoardStudent, + problemDisplayId: string | undefined, + flowchart: boolean, +) { return router.resolve({ name: "submissions", query: { username: student.username, exactUsername: "1", today: "1", + ...(flowchart ? { language: "Flowchart" } : {}), ...(problemDisplayId ? { problem: problemDisplayId } : {}), }, }).href @@ -401,9 +409,9 @@ function submissionsHref(student: ClassBoardStudent, problemDisplayId?: string) @@ -432,9 +440,19 @@ function submissionsHref(student: ClassBoardStudent, problemDisplayId?: string) {{ cellText(cell) }} diff --git a/packages/contract/src/classroom.ts b/packages/contract/src/classroom.ts index cc6757c..4c8f597 100644 --- a/packages/contract/src/classroom.ts +++ b/packages/contract/src/classroom.ts @@ -101,8 +101,14 @@ export const classBoardProblemSchema = z.object({ export const classBoardCellSchema = z.object({ /** accepted 看的是题库里(不含比赛)有没有通过过,不限今天 —— 以前做过的也算做完 */ status: z.enum(["accepted", "tried", "none"]), - /** 今天在这道题上交了几次 */ + /** 今天在这道题上交了几次(代码 + 流程图) */ attempts: z.number().int(), + /** + * 上面那个数拆开:代码几次、流程图几次。点格子要知道该跳到提交列表的哪一边 —— + * 这节课整班在画流程图时,跳到代码那边是一片空 + */ + codeAttempts: z.number().int(), + flowchartAttempts: z.number().int(), /** 第一次通过的时刻;今天之前通过的,前端显示成「之前」 */ acceptedAt: z.string().nullable(), }) @@ -115,6 +121,12 @@ export const classBoardStudentSchema = z.object({ cells: z.array(classBoardCellSchema), /** 今天最后一次提交(任何题),没交过为 null */ lastSubmitAt: z.string().nullable(), + /** + * 今天交过**非比赛**的代码 / 画过流程图没有。点名字跳提交列表用:lastSubmitAt 把比赛提交 + * 也算进去了,而提交列表只列非比赛的,只看它会跳到一个空列表 + */ + codeToday: z.boolean(), + drawnToday: z.boolean(), /** 最近几节课(不含今天,个数见 ClassBoard.recentLessons)里交过题的有几节 */ recentAttended: z.number().int(), })