feat(课堂看板): 看板接口给没做对的格子带上今天最后一次提交,按错法归堆、点开讲错误要用
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
754a9d7caf
commit
0a4f528c44
3 files changed
+62
-1
No files matched your search
@@ -9,6 +9,7 @@ import {
|
||||
type ClassActivityProblem,
|
||||
type LastVisit,
|
||||
type LessonLanguage,
|
||||
type StatisticInfo,
|
||||
FLOWCHART_PASS_GRADES,
|
||||
} from "@oj2/contract"
|
||||
import { and, asc, desc, eq, gte, inArray, isNotNull, isNull, lt, sql } from "drizzle-orm"
|
||||
@@ -558,7 +559,7 @@ classroomRoutes.get("/classroom/board", requireTeacher, async (c) => {
|
||||
// 「来了几次」代码和流程图合起来数:那天只画了流程图的也算来过,和 recentDays 同一个口径
|
||||
const recentActivity = activityRows({ since: windowStart, users: userIds })
|
||||
const localDay = sql<string>`to_char(${localTime(recentActivity.createTime)}, 'YYYY-MM-DD')`
|
||||
const [cells, lastSubmits, lastDrawn, attendance, drawn] = await Promise.all([
|
||||
const [cells, lastSubmits, lastDrawn, attendance, drawn, latests] = await Promise.all([
|
||||
ids.length && userIds.length
|
||||
? db
|
||||
.select({
|
||||
@@ -650,7 +651,42 @@ classroomRoutes.get("/classroom/board", requireTeacher, async (c) => {
|
||||
)
|
||||
.groupBy(schema.flowchartSubmission.userId, schema.flowchartSubmission.problemId)
|
||||
: [],
|
||||
/**
|
||||
* 每人每题今天最后一次代码提交:没做对的格子靠它点开讲错误、按错法归堆。
|
||||
* 范围和 cells 一样(非比赛、布置的语言),只多一个「今天」
|
||||
*/
|
||||
ids.length && userIds.length
|
||||
? db
|
||||
.selectDistinctOn([schema.submission.userId, schema.submission.problemId], {
|
||||
userId: schema.submission.userId,
|
||||
problemId: schema.submission.problemId,
|
||||
id: schema.submission.id,
|
||||
result: schema.submission.result,
|
||||
runtimeError: sql<
|
||||
StatisticInfo["runtime_error"] | null
|
||||
>`${schema.submission.statisticInfo}->'runtime_error'`,
|
||||
sampleCheck: sql<
|
||||
StatisticInfo["sample_check"] | null
|
||||
>`${schema.submission.statisticInfo}->'sample_check'`,
|
||||
})
|
||||
.from(schema.submission)
|
||||
.where(
|
||||
and(
|
||||
isNull(schema.submission.contestId),
|
||||
inArray(schema.submission.userId, userIds),
|
||||
inArray(schema.submission.problemId, ids),
|
||||
gte(schema.submission.createTime, start),
|
||||
lessonLanguageFilter(lesson.language),
|
||||
),
|
||||
)
|
||||
.orderBy(
|
||||
schema.submission.userId,
|
||||
schema.submission.problemId,
|
||||
desc(schema.submission.createTime),
|
||||
)
|
||||
: [],
|
||||
])
|
||||
const latestByKey = new Map(latests.map((row) => [`${row.userId}:${row.problemId}`, row]))
|
||||
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]))
|
||||
@@ -689,12 +725,21 @@ classroomRoutes.get("/classroom/board", requireTeacher, async (c) => {
|
||||
const cell = cellByKey.get(key)
|
||||
const flow = drawnByKey.get(key)
|
||||
const acceptedAt = earliest(cell?.firstAcceptedAt, flow?.firstPassedAt)
|
||||
const latest = acceptedAt ? undefined : latestByKey.get(key)
|
||||
return {
|
||||
status: !cell && !flow ? "none" : acceptedAt ? "accepted" : "tried",
|
||||
attempts: (cell?.attempts ?? 0) + (flow?.attempts ?? 0),
|
||||
codeAttempts: cell?.attempts ?? 0,
|
||||
flowchartAttempts: flow?.attempts ?? 0,
|
||||
acceptedAt,
|
||||
latest: latest
|
||||
? {
|
||||
submissionId: latest.id,
|
||||
result: latest.result,
|
||||
runtimeError: latest.runtimeError ?? undefined,
|
||||
sampleCheck: latest.sampleCheck ?? undefined,
|
||||
}
|
||||
: null,
|
||||
}
|
||||
}),
|
||||
lastSubmitAt: lastByUser.get(student.userId) ?? null,
|
||||
|
||||
File renamed without changes.
@@ -2,6 +2,7 @@ import { z } from "zod"
|
||||
|
||||
import { judgeStatusSchema } from "./judge-status"
|
||||
import { lessonLanguageSchema as lessonLanguageValueSchema } from "./language"
|
||||
import { statisticInfoSchema } from "./submission"
|
||||
|
||||
/**
|
||||
* 「班里在做」:同班同一天有好几个人做的题,基本就是老师在课上点名的那几道。
|
||||
@@ -105,6 +106,21 @@ export const classBoardCellSchema = z.object({
|
||||
flowchartAttempts: z.number().int(),
|
||||
/** 第一次通过的时刻;今天之前通过的,前端显示成「之前」 */
|
||||
acceptedAt: z.string().nullable(),
|
||||
/**
|
||||
* 还没做对时,今天最后一次**代码**提交:点格子打开它讲错误,题卡片下面按错法归堆。
|
||||
* 做对了、今天没交代码(只画了流程图)的为 null。
|
||||
*
|
||||
* 只带归类要用的那几样(runtime_error / sample_check 和提交里存的同一份),
|
||||
* 不带代码和原始报错 —— 一班四五十人,真要看代码的时候按 submissionId 再拉
|
||||
*/
|
||||
latest: z
|
||||
.object({
|
||||
submissionId: z.string(),
|
||||
result: judgeStatusSchema,
|
||||
runtimeError: statisticInfoSchema.shape.runtime_error,
|
||||
sampleCheck: statisticInfoSchema.shape.sample_check,
|
||||
})
|
||||
.nullable(),
|
||||
})
|
||||
|
||||
export const classBoardStudentSchema = z.object({
|
||||
|
||||
Reference in new issue
Block a user