feat(提交列表): 老师也能重新判题;列表能按班级、一次按几道题筛,还带「通过几个测试点」

- 重新判题从只放超管改成老师及以上:前端一直给老师亮着按钮,点了只会「权限不足」
- /submissions、/flowcharts 加 className(user.class_name 精确匹配),题号可以一次填几道
- 列表每行带 caseSummary,口径和详情一致,在库里数完只回两个数
- 新增 GET /classroom/lesson:提交列表「这节课」按钮用,班级和题的取法同课堂看板

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-09-29 11:08:49 +08:00
1 parent b76a35b5f2
commit ea480d5e0c
12 files changed
+151 -425

No files matched your search

+22 -2
View File
@@ -29,6 +29,7 @@ import {
isAdminRole,
matchedUsers,
asRecord,
parseDisplayIds,
queryInteger,
rounded,
stripClassPrefix,
@@ -178,12 +179,15 @@ flowchartRoutes.post("/flowcharts", requireAuth, async (c) => {
* 「查无此班」会变成「全站」。
*/
async function flowchartProblemFilter(displayId: string) {
// 和代码提交列表一样可以一次筛几道
const lowered = parseDisplayIds(displayId).map((id) => id.toLowerCase())
if (!lowered.length) return sql`false`
const problems = await db
.select({ id: schema.problem.id })
.from(schema.problem)
.where(
and(
sql`lower(${schema.problem.displayId}) = lower(${displayId})`,
inArray(sql`lower(${schema.problem.displayId})`, lowered),
// 流程图题都是公开题(快照里那 12 道 contest_id 全为空),
// 比赛题的 _id 撞号是常态,不该被筛进来
isNull(schema.problem.contestId),
@@ -197,6 +201,20 @@ async function flowchartProblemFilter(displayId: string) {
: sql`false`
}
/** 按班级(user.class_name)筛,口径同 submission-statistics.ts 的 classNameFilter */
async function flowchartClassFilter(className: string) {
const users = await db
.select({ id: schema.user.id })
.from(schema.user)
.where(eq(schema.user.className, className))
return users.length
? inArray(
schema.flowchartSubmission.userId,
users.map((row) => row.id),
)
: sql`false`
}
async function flowchartUserFilter(username: string) {
const ids = (await matchedUsers(username)).map((row) => row.id)
return ids.length ? inArray(schema.flowchartSubmission.userId, ids) : sql`false`
@@ -250,13 +268,15 @@ flowchartRoutes.get("/flowcharts", requireAuth, async (c) => {
return success(c, { results: [], total: 0 } satisfies FlowchartList)
}
// 「只看自己」盖过用户名;普通学生不填用户名时也只看自己
const className = c.req.query("className")?.trim()
const onlyMyself =
c.req.query("myself") === "1" || (!username && user.adminType === "Regular User")
c.req.query("myself") === "1" || (!username && !className && user.adminType === "Regular User")
const filters: Array<SQL | undefined> = []
filters.push(
...(await Promise.all([
displayId ? flowchartProblemFilter(displayId) : undefined,
!onlyMyself && username ? flowchartUserFilter(username) : undefined,
!onlyMyself && className ? flowchartClassFilter(className) : undefined,
])),
)
if (onlyMyself) filters.push(eq(schema.flowchartSubmission.userId, user.id))