feat(阶段3): oj 侧端点铺开(基线提交,未经评审)

由外部 agent (Codex) 在本会话额度中断期间完成。原样提交作为基线,
后续修复单独成 commit,便于区分与回退。

覆盖 oj 侧 65 个端点,新增 9 组路由(account/achievement/ai/classroom/
content/contest/flowchart/problemset/site)与对应 Zod 契约。

已核验:tsc --noEmit 退出码 0;API 可启动;/api/problems 返回真实数据;
judge 与 flowchart worker 均 ready。
未核验:权限边界与数据泄露,评审进行中。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-07 01:25:36 -06:00
parent ec274419c3
commit 8c00cdc947
52 changed files with 4273 additions and 300 deletions

View File

@@ -0,0 +1,96 @@
import { z } from "zod"
export const durationDataSchema = z.object({
unit: z.string(),
index: z.number().int(),
start: z.string(),
end: z.string(),
grade: z.string(),
problemCount: z.number().int(),
submissionCount: z.number().int(),
})
export const solvedProblemSchema = z.object({
problem: z.object({
title: z.string(),
displayId: z.string(),
contestTitle: z.string(),
contestId: z.number().int().nullable(),
}),
acTime: z.string(),
rank: z.number().int().nullable(),
acCount: z.number().int(),
grade: z.string(),
periodRank: z.number().int().nullable(),
periodAcCount: z.number().int(),
difficulty: z.string(),
})
export const flowchartSummarySchema = z.object({
problemId: z.string(),
problemTitle: z.string(),
submissionCount: z.number().int(),
bestScore: z.number(),
bestGrade: z.string(),
latestSubmissionTime: z.string(),
avgScore: z.number(),
})
export const aiDetailSchema = z.object({
user: z.string(),
className: z.string().nullable(),
start: z.string(),
end: z.string(),
solved: z.array(solvedProblemSchema),
flowcharts: z.array(flowchartSummarySchema),
grade: z.string(),
tags: z.record(z.string(), z.number().int()),
difficulty: z.record(z.string(), z.number().int()),
contestCount: z.number().int(),
})
export const aiAnalysisRequestSchema = z.object({
details: z.unknown(),
duration: z.unknown(),
})
export const aiHintRequestSchema = z.object({ submissionId: z.string().min(1) })
export const classAnalysisRequestSchema = z.object({
comparison: z.record(z.string(), z.unknown()),
})
export const classPkAnalysisRequestSchema = z.object({
comparisons: z.array(z.record(z.string(), z.unknown())).min(2),
timeRangeLabel: z.string().default("全部时间"),
})
export const heatmapItemSchema = z.object({
timestamp: z.number(),
value: z.number().int(),
})
export const aiAnalysisRecordSchema = z.object({
id: z.number().int(),
provider: z.string(),
model: z.string(),
data: z.record(z.string(), z.unknown()),
analysis: z.string(),
createTime: z.string(),
isPinned: z.boolean(),
username: z.string().optional(),
})
export const loginSummarySchema = z.object({
summary: z.object({
start: z.string(),
end: z.string(),
newProblemCount: z.number().int(),
submissionCount: z.number().int(),
acceptedCount: z.number().int(),
solvedCount: z.number().int(),
flowchartSubmissionCount: z.number().int(),
}),
analysis: z.string(),
analysisError: z.string().optional(),
})