feat(提交列表): 今日提交数旁加「统计」按钮,弹框给今天的提交统计
筛到今天之后标签旁边出现「统计」,弹框里是全站今天的提交概况:总提交 / 正确 / 判题中 / 正确率 / 参与人数,外加按钟点的 24 格分布、按语言、按判题结果,以及 今天最热的 10 道题。 新接口 GET /submissions/today-statistics,公开、只出聚合数,口径和那颗标签一致 (东八区今天 + 非比赛提交): - 钟点分桶走 time.ts 的 localTime()。`extract(hour from create_time)` 按会话时区 算,容器是 UTC,整张分布图会左移 8 小时; - 正确率的分母摘掉未判完的条数,正确数含 AST_CHECK_FAILED; - 热门题只算 visible 的题目 —— 这个接口不需要登录,不能拿它探未发布题目的标题; 「提交列表对学生全开」关掉时这张表整个不下发,跟提交列表同一个开关(数字照给, 否则标签说 21、弹框说 0)。 前端组件异步加载,不进本路由的关键路径;小时分布是纯 CSS 柱状图,没有引 chart.js。 柱子和基线取 useThemeVars(),深浅色都跟着走,「现在」那一格是基线上一段主色刻度。 流程图那档不给这颗按钮 —— 流程图提交在另一张表、只有 AI 评级没有判题状态。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -331,6 +331,52 @@ export const submissionStatisticsSchema = z.object({
|
||||
dataAttempted: z.array(attemptedStudentSchema),
|
||||
})
|
||||
|
||||
/**
|
||||
* 提交列表那颗「今日提交数」标签点开之后的统计弹框(GET /submissions/today-statistics)。
|
||||
*
|
||||
* **公开接口,只下发聚合数** —— 没有用户名、没有代码、没有隐藏题目的标题,学生和
|
||||
* 匿名访客看到的和教师一样。教师那套按班级/按题号钻取的口径在
|
||||
* `submissionStatisticsSchema`,两者不是一回事,别把这个当它的简版去加字段。
|
||||
*
|
||||
* 口径跟着那颗标签走:**东八区今天、非比赛提交、不分语言**(语言分布就是
|
||||
* `languages` 这张表本身)。
|
||||
*/
|
||||
export const todaySubmissionStatisticsSchema = z.object({
|
||||
total: z.number().int(),
|
||||
/** 通过的条数,含 AST_CHECK_FAILED(那也是答案对了) */
|
||||
accepted: z.number().int(),
|
||||
/**
|
||||
* 还没判完的条数(PENDING / JUDGING)。`total` 把它算在内,`correctRate` 的分母
|
||||
* 不算 —— 全班同时交卷的那几秒,分母涨了分子没涨,正确率会凭空掉一截。
|
||||
*/
|
||||
judging: z.number().int(),
|
||||
correctRate: z.number(),
|
||||
/** 今天交过东西的人数,按 user_id 去重 */
|
||||
userCount: z.number().int(),
|
||||
/** 按东八区钟点分的 24 个桶,**下标就是钟点**,没有提交的钟点是 0 */
|
||||
hours: z.array(z.number().int()).length(24),
|
||||
/** 按语言,提交数倒序。零提交的语言不在表里 */
|
||||
languages: z.array(
|
||||
z.object({ language: problemLanguageSchema, count: z.number().int() }),
|
||||
),
|
||||
/** 按判题结果,条数倒序 */
|
||||
results: z.array(
|
||||
z.object({ result: judgeStatusSchema, count: z.number().int() }),
|
||||
),
|
||||
/**
|
||||
* 今天最热的几道题,提交数倒序,最多 10 道。
|
||||
* **只含公开可见的题目** —— 这个接口不需要登录,不能拿它探未发布题目的标题。
|
||||
*/
|
||||
problems: z.array(
|
||||
z.object({
|
||||
problem: z.string(),
|
||||
problemTitle: z.string(),
|
||||
count: z.number().int(),
|
||||
acceptedCount: z.number().int(),
|
||||
}),
|
||||
),
|
||||
})
|
||||
|
||||
export const formatCodeRequestSchema = z.object({
|
||||
code: z.string().max(1024 * 1024),
|
||||
language: z.enum(["python", "c", "cpp", "sql"]),
|
||||
@@ -346,6 +392,9 @@ export type CreateSubmissionRequest = z.infer<
|
||||
export type SubmissionDetail = z.infer<typeof submissionDetailSchema>
|
||||
export type SubmissionUpdate = z.infer<typeof submissionUpdateSchema>
|
||||
export type SubmissionStatistics = z.infer<typeof submissionStatisticsSchema>
|
||||
export type TodaySubmissionStatistics = z.infer<
|
||||
typeof todaySubmissionStatisticsSchema
|
||||
>
|
||||
export type SubmissionStatisticsUser = z.infer<
|
||||
typeof submissionStatisticsUserSchema
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user