feat(后台比赛): 比赛列表带上每场几道题、几人参加,按开始时间排,复制出来的旧比赛不再跑到最前面
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c59e31eeb2
commit
591c7bcab9
2 files changed
+38
-4
No files matched your search
@@ -5,7 +5,7 @@ import {
|
||||
type AdminContest,
|
||||
type AdminContestList,
|
||||
} from "@oj2/contract"
|
||||
import { and, count, desc, eq, ilike, inArray } from "drizzle-orm"
|
||||
import { and, count, countDistinct, desc, eq, ilike, inArray } from "drizzle-orm"
|
||||
import { Hono } from "hono"
|
||||
|
||||
import { requireTeacher, type AppEnv } from "../../auth/middleware"
|
||||
@@ -93,12 +93,39 @@ adminContestRoutes.get("/contests", requireTeacher, async (c) => {
|
||||
.innerJoin(schema.user, eq(schema.contest.createdById, schema.user.id))
|
||||
.leftJoin(schema.userProfile, eq(schema.userProfile.userId, schema.user.id))
|
||||
.where(where)
|
||||
.orderBy(desc(schema.contest.createTime))
|
||||
// 按开始时间:原来按创建时间,「复制一份」出来的旧比赛会排到最前面
|
||||
.orderBy(desc(schema.contest.startTime), desc(schema.contest.id))
|
||||
.limit(limit)
|
||||
.offset(offset),
|
||||
])
|
||||
const ids = rows.map((row) => row.contest.id)
|
||||
const [problemCounts, participantCounts] = ids.length
|
||||
? await Promise.all([
|
||||
db
|
||||
.select({ contestId: schema.problem.contestId, value: count() })
|
||||
.from(schema.problem)
|
||||
.where(inArray(schema.problem.contestId, ids))
|
||||
.groupBy(schema.problem.contestId),
|
||||
db
|
||||
.select({
|
||||
contestId: schema.submission.contestId,
|
||||
value: countDistinct(schema.submission.userId),
|
||||
})
|
||||
.from(schema.submission)
|
||||
.where(inArray(schema.submission.contestId, ids))
|
||||
.groupBy(schema.submission.contestId),
|
||||
])
|
||||
: [[], []]
|
||||
const problemsOf = new Map(problemCounts.map((row) => [row.contestId, row.value]))
|
||||
const peopleOf = new Map(participantCounts.map((row) => [row.contestId, row.value]))
|
||||
return success(c, {
|
||||
results: await Promise.all(rows.map(serialize)),
|
||||
results: await Promise.all(
|
||||
rows.map(async (row) => ({
|
||||
...(await serialize(row)),
|
||||
problemCount: problemsOf.get(row.contest.id) ?? 0,
|
||||
participantCount: peopleOf.get(row.contest.id) ?? 0,
|
||||
})),
|
||||
),
|
||||
total: totalRows[0]?.value ?? 0,
|
||||
} satisfies AdminContestList)
|
||||
})
|
||||
|
||||
@@ -394,7 +394,13 @@ export const adminContestSchema = z.object({
|
||||
contestType: z.enum(["Public", "Password Protected"]),
|
||||
})
|
||||
|
||||
export const adminContestListSchema = paginatedSchema(adminContestSchema)
|
||||
/** 后台比赛列表的一行:比赛本身,加几道题、几人参加(交过题的人数) */
|
||||
export const adminContestListItemSchema = adminContestSchema.extend({
|
||||
problemCount: z.number().int(),
|
||||
participantCount: z.number().int(),
|
||||
})
|
||||
|
||||
export const adminContestListSchema = paginatedSchema(adminContestListItemSchema)
|
||||
|
||||
export const createContestRequestSchema = z.object({
|
||||
title: z.string().trim().min(1).max(128),
|
||||
@@ -1008,6 +1014,7 @@ export type CreateProblemRequest = z.infer<typeof createProblemRequestSchema>
|
||||
|
||||
export type AdminContest = z.infer<typeof adminContestSchema>
|
||||
export type AdminContestList = z.infer<typeof adminContestListSchema>
|
||||
export type AdminContestListItem = z.infer<typeof adminContestListItemSchema>
|
||||
export type AdminUser = z.infer<typeof adminUserSchema>
|
||||
export type AdminUserList = z.infer<typeof adminUserListSchema>
|
||||
export type CheckUsernamesResponse = z.infer<typeof checkUsernamesResponseSchema>
|
||||
|
||||
Reference in new issue
Block a user