原来只有 `apps/web` 在 Prettier 下(配置在 `apps/web/.prettierrc.toml`、脚本在 web 的 package.json),后端和契约从来没格式化过 —— 手写在 100 列上下,`db/schema.ts` 还是 drizzle-kit pull 留下的 tab 缩进。两套口径分叉久了,跨端改一处就得记着「这边 什么风格」。 - 配置搬到根目录 `.prettierrc.toml`,内容不变(`semi=false`,其余全默认, printWidth 80 —— 和前端已有的格式一致,不另立一套宽度); - 脚本统一成根目录 `bun run fmt`,覆盖 `apps/*/src`、`apps/web/tests` 和两个构建 配置;web 自己那份 `fmt` 和重复的 prettier 依赖删掉; - `.prettierignore` 挡掉两类不该碰的:drizzle-kit 生成的 `src/db/meta/` 结构快照 (它是 db:generate 的比对输入,只该由 drizzle-kit 写)、unplugin 每次 dev 都会 重写的 `auto-imports.d.ts` / `components.d.ts`; - 全量跑了一遍。纯格式,无行为改动:api typecheck / check:routes / check:ast、 前端 type-check 全过,起 api 打了接口确认正常。前端这 39 个文件的小改动是 prettier 版本漂移(类型断言的换行口径变了),不是新配置带来的。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,11 @@
|
||||
import { z } from "zod"
|
||||
|
||||
export const achievementRaritySchema = z.enum(["bronze", "silver", "gold", "platinum"])
|
||||
export const achievementRaritySchema = z.enum([
|
||||
"bronze",
|
||||
"silver",
|
||||
"gold",
|
||||
"platinum",
|
||||
])
|
||||
|
||||
export const achievementSchema = z.object({
|
||||
id: z.number().int(),
|
||||
@@ -66,6 +71,8 @@ export type PendingAchievement = z.infer<typeof pendingAchievementSchema>
|
||||
export type AchievementSummary = z.infer<typeof achievementSummarySchema>
|
||||
export type AchievementRarity = z.infer<typeof achievementRaritySchema>
|
||||
export type AchievementRarityStat = z.infer<typeof achievementRarityStatSchema>
|
||||
export type AchievementNotification = z.infer<typeof achievementNotificationSchema>
|
||||
export type AchievementNotification = z.infer<
|
||||
typeof achievementNotificationSchema
|
||||
>
|
||||
|
||||
export type MarkAchievementsRead = z.infer<typeof markAchievementsReadSchema>
|
||||
|
||||
@@ -98,7 +98,9 @@ export const createTutorialRequestSchema = z.object({
|
||||
})
|
||||
|
||||
export const updateTutorialRequestSchema = createTutorialRequestSchema
|
||||
export const setTutorialVisibilityRequestSchema = z.object({ isPublic: z.boolean() })
|
||||
export const setTutorialVisibilityRequestSchema = z.object({
|
||||
isPublic: z.boolean(),
|
||||
})
|
||||
|
||||
export const exerciseTypeSchema = z.enum([
|
||||
"mcq",
|
||||
@@ -151,8 +153,12 @@ export const adminAiReportSchema = z.object({
|
||||
analysis: z.string(),
|
||||
})
|
||||
|
||||
export const adminAiReportListSchema = paginatedSchema(adminAiReportListItemSchema)
|
||||
export const toggleAiReportPinResponseSchema = z.object({ isPinned: z.boolean() })
|
||||
export const adminAiReportListSchema = paginatedSchema(
|
||||
adminAiReportListItemSchema,
|
||||
)
|
||||
export const toggleAiReportPinResponseSchema = z.object({
|
||||
isPinned: z.boolean(),
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------- 成就
|
||||
|
||||
@@ -233,12 +239,16 @@ export const updateUserRequestSchema = z.object({
|
||||
|
||||
/** 导入用户:每行 [用户名, 密码, 邮箱, 真名],与前端粘贴的 Excel 列序一致 */
|
||||
export const importUsersRequestSchema = z.object({
|
||||
users: z.array(z.tuple([
|
||||
z.string().trim().min(1).max(32),
|
||||
z.string().min(1),
|
||||
z.string(),
|
||||
z.string(),
|
||||
])).min(1),
|
||||
users: z
|
||||
.array(
|
||||
z.tuple([
|
||||
z.string().trim().min(1).max(32),
|
||||
z.string().min(1),
|
||||
z.string(),
|
||||
z.string(),
|
||||
]),
|
||||
)
|
||||
.min(1),
|
||||
})
|
||||
|
||||
export const deleteUsersRequestSchema = z.object({
|
||||
@@ -282,7 +292,9 @@ export const judgeServerListSchema = z.object({
|
||||
servers: z.array(judgeServerSchema),
|
||||
})
|
||||
|
||||
export const updateJudgeServerRequestSchema = z.object({ isDisabled: z.boolean() })
|
||||
export const updateJudgeServerRequestSchema = z.object({
|
||||
isDisabled: z.boolean(),
|
||||
})
|
||||
|
||||
export const orphanTestCaseSchema = z.object({
|
||||
id: z.string(),
|
||||
@@ -365,7 +377,11 @@ export const updateAcmHelperRequestSchema = z.object({
|
||||
|
||||
export const problemSetDifficultySchema = z.enum(["Easy", "Medium", "Hard"])
|
||||
export const problemSetStatusSchema = z.enum(["draft", "active", "archived"])
|
||||
export const badgeConditionTypeSchema = z.enum(["all_problems", "problem_count", "score"])
|
||||
export const badgeConditionTypeSchema = z.enum([
|
||||
"all_problems",
|
||||
"problem_count",
|
||||
"score",
|
||||
])
|
||||
|
||||
export const adminProblemSetSchema = z.object({
|
||||
id: z.number().int(),
|
||||
@@ -395,7 +411,9 @@ export const createProblemSetRequestSchema = z.object({
|
||||
})
|
||||
|
||||
export const updateProblemSetRequestSchema = createProblemSetRequestSchema
|
||||
export const updateProblemSetStatusRequestSchema = z.object({ status: problemSetStatusSchema })
|
||||
export const updateProblemSetStatusRequestSchema = z.object({
|
||||
status: problemSetStatusSchema,
|
||||
})
|
||||
|
||||
export const adminProblemSetProblemSchema = z.object({
|
||||
id: z.number().int(),
|
||||
@@ -446,7 +464,8 @@ export const createProblemSetBadgeRequestSchema = z.object({
|
||||
conditionValue: z.number().int().default(0),
|
||||
})
|
||||
|
||||
export const updateProblemSetBadgeRequestSchema = createProblemSetBadgeRequestSchema
|
||||
export const updateProblemSetBadgeRequestSchema =
|
||||
createProblemSetBadgeRequestSchema
|
||||
|
||||
export const adminProblemSetProgressSchema = z.object({
|
||||
id: z.number().int(),
|
||||
@@ -470,7 +489,9 @@ export const adminTagSchema = z.object({
|
||||
problemCount: z.number().int(),
|
||||
})
|
||||
|
||||
export const renameTagRequestSchema = z.object({ name: z.string().trim().min(1).max(64) })
|
||||
export const renameTagRequestSchema = z.object({
|
||||
name: z.string().trim().min(1).max(64),
|
||||
})
|
||||
|
||||
export const renameTagResponseSchema = z.object({
|
||||
/** 改名撞上已有标签时视为合并:题目关系转移过去、原标签删除 */
|
||||
@@ -597,8 +618,15 @@ export const learnTutorialProgressListSchema = z.object({
|
||||
results: z.array(learnTutorialProgressSchema),
|
||||
})
|
||||
|
||||
export const generateFlowchartRequestSchema = z.object({ python: z.string().min(1).max(64 * 1024) })
|
||||
export const generateFlowchartResponseSchema = z.object({ flowchart: z.string() })
|
||||
export const generateFlowchartRequestSchema = z.object({
|
||||
python: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(64 * 1024),
|
||||
})
|
||||
export const generateFlowchartResponseSchema = z.object({
|
||||
flowchart: z.string(),
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------- 题目管理
|
||||
|
||||
@@ -621,7 +649,9 @@ export const adminProblemListItemSchema = z.object({
|
||||
.nullable(),
|
||||
})
|
||||
|
||||
export const adminProblemListSchema = paginatedSchema(adminProblemListItemSchema)
|
||||
export const adminProblemListSchema = paginatedSchema(
|
||||
adminProblemListItemSchema,
|
||||
)
|
||||
|
||||
/**
|
||||
* 题面样例 / 标准答案 / 测试点分值。这三个旧后端都是逐字段校验的
|
||||
@@ -656,7 +686,6 @@ export const problemTestCaseScoreSchema = z.object({
|
||||
score: z.coerce.number().int().min(0),
|
||||
})
|
||||
|
||||
|
||||
/** 后台题目详情:包含 oj 侧永不下发的 answers / testCase* / astRules */
|
||||
export const adminProblemSchema = z.object({
|
||||
id: z.number().int(),
|
||||
@@ -720,9 +749,16 @@ export const createProblemRequestSchema = z.object({
|
||||
inputDescription: z.string(),
|
||||
outputDescription: z.string(),
|
||||
samples: z.array(problemSampleSchema),
|
||||
testCaseId: z.string().regex(/^[a-zA-Z0-9]+$/).max(32),
|
||||
testCaseId: z
|
||||
.string()
|
||||
.regex(/^[a-zA-Z0-9]+$/)
|
||||
.max(32),
|
||||
testCaseScore: z.array(problemTestCaseScoreSchema),
|
||||
timeLimit: z.number().int().min(1).max(1000 * 60),
|
||||
timeLimit: z
|
||||
.number()
|
||||
.int()
|
||||
.min(1)
|
||||
.max(1000 * 60),
|
||||
memoryLimit: z.number().int().min(1).max(1024),
|
||||
// 收窄到语言联合而不是裸 string[]:`problem.languages` 列上挂着
|
||||
// `$type<ProblemLanguage[]>()`,那个断言得有人兑现 —— 闸就设在这里(写入侧)。
|
||||
@@ -782,13 +818,22 @@ export const sqlTestCaseScriptSchema = z.object({
|
||||
})
|
||||
|
||||
export const sqlPreviewRequestSchema = z.object({
|
||||
initSql: z.string().min(1).max(1024 * 1024),
|
||||
refSql: z.string().min(1).max(1024 * 1024),
|
||||
initSql: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(1024 * 1024),
|
||||
refSql: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(1024 * 1024),
|
||||
mode: z.enum(["query", "modify"]),
|
||||
})
|
||||
|
||||
export const generateSqlTestCaseRequestSchema = z.object({
|
||||
refSql: z.string().min(1).max(64 * 1024),
|
||||
refSql: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(64 * 1024),
|
||||
mode: z.enum(["query", "modify"]),
|
||||
})
|
||||
|
||||
@@ -818,72 +863,132 @@ export type AdminAiReport = z.infer<typeof adminAiReportSchema>
|
||||
export type AdminAiReportList = z.infer<typeof adminAiReportListSchema>
|
||||
export type StuckProblem = z.infer<typeof stuckProblemSchema>
|
||||
export type LearnStudentProgress = z.infer<typeof learnStudentProgressSchema>
|
||||
export type LearnStudentProgressList = z.infer<typeof learnStudentProgressListSchema>
|
||||
export type LearnStudentProgressList = z.infer<
|
||||
typeof learnStudentProgressListSchema
|
||||
>
|
||||
export type LearnTutorialProgress = z.infer<typeof learnTutorialProgressSchema>
|
||||
export type LearnTutorialProgressList = z.infer<typeof learnTutorialProgressListSchema>
|
||||
export type LearnTutorialProgressList = z.infer<
|
||||
typeof learnTutorialProgressListSchema
|
||||
>
|
||||
export type LearnExerciseProgress = z.infer<typeof learnExerciseProgressSchema>
|
||||
export type LearnExerciseProgressList = z.infer<typeof learnExerciseProgressListSchema>
|
||||
export type LearnExerciseProgressList = z.infer<
|
||||
typeof learnExerciseProgressListSchema
|
||||
>
|
||||
export type LearnExerciseAttempt = z.infer<typeof learnExerciseAttemptSchema>
|
||||
export type AcTrend = z.infer<typeof acTrendSchema>
|
||||
|
||||
export type AdminTag = z.infer<typeof adminTagSchema>
|
||||
export type RenameTagResponse = z.infer<typeof renameTagResponseSchema>
|
||||
export type BatchProblemTagResponse = z.infer<typeof batchProblemTagResponseSchema>
|
||||
export type BatchProblemTagResponse = z.infer<
|
||||
typeof batchProblemTagResponseSchema
|
||||
>
|
||||
export type SqlTestCaseScript = z.infer<typeof sqlTestCaseScriptSchema>
|
||||
export type GenerateSqlTestCaseResponse = z.infer<typeof generateSqlTestCaseResponseSchema>
|
||||
export type AdminProblemSetProgress = z.infer<typeof adminProblemSetProgressSchema>
|
||||
export type GenerateSqlTestCaseResponse = z.infer<
|
||||
typeof generateSqlTestCaseResponseSchema
|
||||
>
|
||||
export type AdminProblemSetProgress = z.infer<
|
||||
typeof adminProblemSetProgressSchema
|
||||
>
|
||||
|
||||
export type AdminAnnouncementList = z.infer<typeof adminAnnouncementListSchema>
|
||||
export type CreateAnnouncementRequest = z.infer<typeof createAnnouncementRequestSchema>
|
||||
export type UpdateAnnouncementRequest = z.infer<typeof updateAnnouncementRequestSchema>
|
||||
export type CreateAnnouncementRequest = z.infer<
|
||||
typeof createAnnouncementRequestSchema
|
||||
>
|
||||
export type UpdateAnnouncementRequest = z.infer<
|
||||
typeof updateAnnouncementRequestSchema
|
||||
>
|
||||
export type TutorialType = z.infer<typeof tutorialTypeSchema>
|
||||
export type AdminTutorial = z.infer<typeof adminTutorialSchema>
|
||||
export type AdminTutorialListItem = z.infer<typeof adminTutorialListItemSchema>
|
||||
export type AdminTutorialGroups = z.infer<typeof adminTutorialGroupsSchema>
|
||||
export type CreateTutorialRequest = z.infer<typeof createTutorialRequestSchema>
|
||||
export type UpdateTutorialRequest = z.infer<typeof updateTutorialRequestSchema>
|
||||
export type SetTutorialVisibilityRequest = z.infer<typeof setTutorialVisibilityRequestSchema>
|
||||
export type SetTutorialVisibilityRequest = z.infer<
|
||||
typeof setTutorialVisibilityRequestSchema
|
||||
>
|
||||
export type ExerciseType = z.infer<typeof exerciseTypeSchema>
|
||||
export type AdminExercise = z.infer<typeof adminExerciseSchema>
|
||||
export type CreateExerciseRequest = z.infer<typeof createExerciseRequestSchema>
|
||||
export type UpdateExerciseRequest = z.infer<typeof updateExerciseRequestSchema>
|
||||
export type ToggleAiReportPinResponse = z.infer<typeof toggleAiReportPinResponseSchema>
|
||||
export type ToggleAiReportPinResponse = z.infer<
|
||||
typeof toggleAiReportPinResponseSchema
|
||||
>
|
||||
export type AchievementOperator = z.infer<typeof achievementOperatorSchema>
|
||||
export type CreateAchievementRequest = z.infer<typeof createAchievementRequestSchema>
|
||||
export type UpdateAchievementRequest = z.infer<typeof updateAchievementRequestSchema>
|
||||
export type CreateAchievementRequest = z.infer<
|
||||
typeof createAchievementRequestSchema
|
||||
>
|
||||
export type UpdateAchievementRequest = z.infer<
|
||||
typeof updateAchievementRequestSchema
|
||||
>
|
||||
export type UpdateUserRequest = z.infer<typeof updateUserRequestSchema>
|
||||
export type ImportUsersRequest = z.infer<typeof importUsersRequestSchema>
|
||||
export type DeleteUsersRequest = z.infer<typeof deleteUsersRequestSchema>
|
||||
export type ResetPasswordResponse = z.infer<typeof resetPasswordResponseSchema>
|
||||
export type UpdateWebsiteConfigRequest = z.infer<typeof updateWebsiteConfigRequestSchema>
|
||||
export type UpdateJudgeServerRequest = z.infer<typeof updateJudgeServerRequestSchema>
|
||||
export type UpdateWebsiteConfigRequest = z.infer<
|
||||
typeof updateWebsiteConfigRequestSchema
|
||||
>
|
||||
export type UpdateJudgeServerRequest = z.infer<
|
||||
typeof updateJudgeServerRequestSchema
|
||||
>
|
||||
export type UploadImageResponse = z.infer<typeof uploadImageResponseSchema>
|
||||
export type CreateContestRequest = z.infer<typeof createContestRequestSchema>
|
||||
export type UpdateContestRequest = z.infer<typeof updateContestRequestSchema>
|
||||
export type UpdateAcmHelperRequest = z.infer<typeof updateAcmHelperRequestSchema>
|
||||
export type UpdateAcmHelperRequest = z.infer<
|
||||
typeof updateAcmHelperRequestSchema
|
||||
>
|
||||
export type ProblemSetDifficulty = z.infer<typeof problemSetDifficultySchema>
|
||||
export type ProblemSetStatus = z.infer<typeof problemSetStatusSchema>
|
||||
export type BadgeConditionType = z.infer<typeof badgeConditionTypeSchema>
|
||||
export type AdminProblemSet = z.infer<typeof adminProblemSetSchema>
|
||||
export type AdminProblemSetList = z.infer<typeof adminProblemSetListSchema>
|
||||
export type CreateProblemSetRequest = z.infer<typeof createProblemSetRequestSchema>
|
||||
export type UpdateProblemSetRequest = z.infer<typeof updateProblemSetRequestSchema>
|
||||
export type UpdateProblemSetStatusRequest = z.infer<typeof updateProblemSetStatusRequestSchema>
|
||||
export type AdminProblemSetProblem = z.infer<typeof adminProblemSetProblemSchema>
|
||||
export type AddProblemToSetRequest = z.infer<typeof addProblemToSetRequestSchema>
|
||||
export type UpdateProblemInSetRequest = z.infer<typeof updateProblemInSetRequestSchema>
|
||||
export type CreateProblemSetRequest = z.infer<
|
||||
typeof createProblemSetRequestSchema
|
||||
>
|
||||
export type UpdateProblemSetRequest = z.infer<
|
||||
typeof updateProblemSetRequestSchema
|
||||
>
|
||||
export type UpdateProblemSetStatusRequest = z.infer<
|
||||
typeof updateProblemSetStatusRequestSchema
|
||||
>
|
||||
export type AdminProblemSetProblem = z.infer<
|
||||
typeof adminProblemSetProblemSchema
|
||||
>
|
||||
export type AddProblemToSetRequest = z.infer<
|
||||
typeof addProblemToSetRequestSchema
|
||||
>
|
||||
export type UpdateProblemInSetRequest = z.infer<
|
||||
typeof updateProblemInSetRequestSchema
|
||||
>
|
||||
export type AdminProblemSetBadge = z.infer<typeof adminProblemSetBadgeSchema>
|
||||
export type CreateProblemSetBadgeRequest = z.infer<typeof createProblemSetBadgeRequestSchema>
|
||||
export type UpdateProblemSetBadgeRequest = z.infer<typeof updateProblemSetBadgeRequestSchema>
|
||||
export type CreateProblemSetBadgeRequest = z.infer<
|
||||
typeof createProblemSetBadgeRequestSchema
|
||||
>
|
||||
export type UpdateProblemSetBadgeRequest = z.infer<
|
||||
typeof updateProblemSetBadgeRequestSchema
|
||||
>
|
||||
export type RenameTagRequest = z.infer<typeof renameTagRequestSchema>
|
||||
export type BatchProblemTagRequest = z.infer<typeof batchProblemTagRequestSchema>
|
||||
export type BatchProblemTagRequest = z.infer<
|
||||
typeof batchProblemTagRequestSchema
|
||||
>
|
||||
export type AcTrendYear = z.infer<typeof acTrendYearSchema>
|
||||
export type GenerateFlowchartRequest = z.infer<typeof generateFlowchartRequestSchema>
|
||||
export type GenerateFlowchartResponse = z.infer<typeof generateFlowchartResponseSchema>
|
||||
export type GenerateFlowchartRequest = z.infer<
|
||||
typeof generateFlowchartRequestSchema
|
||||
>
|
||||
export type GenerateFlowchartResponse = z.infer<
|
||||
typeof generateFlowchartResponseSchema
|
||||
>
|
||||
export type UpdateProblemRequest = z.infer<typeof updateProblemRequestSchema>
|
||||
export type MakeProblemPublicRequest = z.infer<typeof makeProblemPublicRequestSchema>
|
||||
export type AddContestProblemRequest = z.infer<typeof addContestProblemRequestSchema>
|
||||
export type MakeProblemPublicRequest = z.infer<
|
||||
typeof makeProblemPublicRequestSchema
|
||||
>
|
||||
export type AddContestProblemRequest = z.infer<
|
||||
typeof addContestProblemRequestSchema
|
||||
>
|
||||
export type TestCaseEntry = z.infer<typeof testCaseEntrySchema>
|
||||
export type UploadTestCaseResponse = z.infer<typeof uploadTestCaseResponseSchema>
|
||||
export type UploadTestCaseResponse = z.infer<
|
||||
typeof uploadTestCaseResponseSchema
|
||||
>
|
||||
export type SqlPreviewRequest = z.infer<typeof sqlPreviewRequestSchema>
|
||||
export type GenerateSqlTestCaseRequest = z.infer<typeof generateSqlTestCaseRequestSchema>
|
||||
export type GenerateSqlTestCaseRequest = z.infer<
|
||||
typeof generateSqlTestCaseRequestSchema
|
||||
>
|
||||
|
||||
@@ -81,10 +81,12 @@ export const aiDetailSchema = z.object({
|
||||
* 判完的失败提交按状态码分组,多的在前。状态码是落库的值,
|
||||
* 前端用 utils/constants 的 JUDGE_STATUS 翻成中文,两边必须一致。
|
||||
*/
|
||||
errors: z.array(z.object({
|
||||
result: z.number().int(),
|
||||
count: z.number().int(),
|
||||
})),
|
||||
errors: z.array(
|
||||
z.object({
|
||||
result: z.number().int(),
|
||||
count: z.number().int(),
|
||||
}),
|
||||
),
|
||||
/**
|
||||
* solved 里的 rank/acCount 是在哪个范围里排的。班里只有一个人时后端会回退到全服,
|
||||
* 前端不能只看 className 有没有值就写「班级排名」。
|
||||
@@ -180,4 +182,6 @@ export type LoginSummary = z.infer<typeof loginSummarySchema>
|
||||
export type AiAnalysisRequest = z.infer<typeof aiAnalysisRequestSchema>
|
||||
export type AiHintRequest = z.infer<typeof aiHintRequestSchema>
|
||||
export type ClassAnalysisRequest = z.infer<typeof classAnalysisRequestSchema>
|
||||
export type ClassPkAnalysisRequest = z.infer<typeof classPkAnalysisRequestSchema>
|
||||
export type ClassPkAnalysisRequest = z.infer<
|
||||
typeof classPkAnalysisRequestSchema
|
||||
>
|
||||
|
||||
@@ -66,7 +66,11 @@ export const classComparisonResponseSchema = z.object({
|
||||
export type ClassRankItem = z.infer<typeof classRankItemSchema>
|
||||
export type ClassUserRank = z.infer<typeof classUserRankSchema>
|
||||
export type ClassComparison = z.infer<typeof classComparisonSchema>
|
||||
export type ClassComparisonResponse = z.infer<typeof classComparisonResponseSchema>
|
||||
export type ClassComparisonResponse = z.infer<
|
||||
typeof classComparisonResponseSchema
|
||||
>
|
||||
|
||||
export type ClassUserRankItem = z.infer<typeof classUserRankItemSchema>
|
||||
export type ClassComparisonRequest = z.infer<typeof classComparisonRequestSchema>
|
||||
export type ClassComparisonRequest = z.infer<
|
||||
typeof classComparisonRequestSchema
|
||||
>
|
||||
|
||||
@@ -41,7 +41,10 @@ export const messageListSchema = paginatedSchema(messageSchema)
|
||||
export const createMessageRequestSchema = z.object({
|
||||
recipientId: z.number().int().positive(),
|
||||
submissionId: z.string().min(1),
|
||||
message: z.string().min(1).max(1024 * 1024),
|
||||
message: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(1024 * 1024),
|
||||
})
|
||||
|
||||
export const reactionKeySchema = z.enum([
|
||||
@@ -54,7 +57,10 @@ export const reactionKeySchema = z.enum([
|
||||
"want_explain",
|
||||
])
|
||||
|
||||
export const reactionCountsSchema = z.record(reactionKeySchema, z.number().int())
|
||||
export const reactionCountsSchema = z.record(
|
||||
reactionKeySchema,
|
||||
z.number().int(),
|
||||
)
|
||||
export const reactionStateSchema = z.object({
|
||||
mine: reactionKeySchema.nullable(),
|
||||
counts: reactionCountsSchema.nullable(),
|
||||
@@ -130,13 +136,36 @@ export const exerciseAttemptRequestSchema = z.object({
|
||||
* 也不会让历史数据把学生端打不开。
|
||||
*/
|
||||
export const exerciseDataByType: Record<string, z.ZodType> = {
|
||||
mcq: z.object({ question: z.string(), options: z.array(z.string()), answer: z.array(z.number()) }),
|
||||
mcq: z.object({
|
||||
question: z.string(),
|
||||
options: z.array(z.string()),
|
||||
answer: z.array(z.number()),
|
||||
}),
|
||||
sort: z.object({ question: z.string(), lines: z.array(z.string()) }),
|
||||
fill: z.object({ question: z.string(), code: z.string() }),
|
||||
match: z.object({ question: z.string(), left: z.array(z.string()), right: z.array(z.string()), answer: z.array(z.number()) }),
|
||||
predict: z.object({ question: z.string(), code: z.string(), answer: z.array(z.string()) }),
|
||||
debug: z.object({ question: z.string(), lines: z.array(z.string()), answer: z.array(z.number()), explanation: z.string().optional() }),
|
||||
group: z.object({ question: z.string(), buckets: z.array(z.string()), items: z.array(z.string()), answer: z.array(z.number()) }),
|
||||
match: z.object({
|
||||
question: z.string(),
|
||||
left: z.array(z.string()),
|
||||
right: z.array(z.string()),
|
||||
answer: z.array(z.number()),
|
||||
}),
|
||||
predict: z.object({
|
||||
question: z.string(),
|
||||
code: z.string(),
|
||||
answer: z.array(z.string()),
|
||||
}),
|
||||
debug: z.object({
|
||||
question: z.string(),
|
||||
lines: z.array(z.string()),
|
||||
answer: z.array(z.number()),
|
||||
explanation: z.string().optional(),
|
||||
}),
|
||||
group: z.object({
|
||||
question: z.string(),
|
||||
buckets: z.array(z.string()),
|
||||
items: z.array(z.string()),
|
||||
answer: z.array(z.number()),
|
||||
}),
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,7 +196,9 @@ export type Tutorial = z.infer<typeof tutorialSchema>
|
||||
export type Exercise = z.infer<typeof exerciseSchema>
|
||||
export type TutorialProgress = z.infer<typeof tutorialProgressSchema>
|
||||
export type TutorialProgressPing = z.infer<typeof tutorialProgressPingSchema>
|
||||
export type ExerciseAttemptRequest = z.infer<typeof exerciseAttemptRequestSchema>
|
||||
export type ExerciseAttemptRequest = z.infer<
|
||||
typeof exerciseAttemptRequestSchema
|
||||
>
|
||||
|
||||
/**
|
||||
* 「已读」的门槛:累计停留满 3 分钟才算读过这一课。
|
||||
|
||||
@@ -27,7 +27,9 @@ export const contestPasswordRequestSchema = z.object({
|
||||
})
|
||||
|
||||
export const contestAccessSchema = z.object({ access: z.boolean() })
|
||||
export const contestProblemsSchema = z.array(z.union([problemListItemSchema, problemDetailSchema]))
|
||||
export const contestProblemsSchema = z.array(
|
||||
z.union([problemListItemSchema, problemDetailSchema]),
|
||||
)
|
||||
|
||||
/**
|
||||
* `acm_contest_rank.submission_info` 的 JSONB 原文。
|
||||
@@ -69,5 +71,7 @@ export type ContestAccess = z.infer<typeof contestAccessSchema>
|
||||
export type ContestSubmissionInfo = z.infer<typeof contestSubmissionInfoSchema>
|
||||
|
||||
export type ContestStatus = z.infer<typeof contestStatusSchema>
|
||||
export type ContestPasswordRequest = z.infer<typeof contestPasswordRequestSchema>
|
||||
export type ContestPasswordRequest = z.infer<
|
||||
typeof contestPasswordRequestSchema
|
||||
>
|
||||
export type ContestProblems = z.infer<typeof contestProblemsSchema>
|
||||
|
||||
@@ -2,14 +2,24 @@ import { z } from "zod"
|
||||
|
||||
import { paginatedSchema } from "./common"
|
||||
|
||||
export const flowchartStatusSchema = z.union([z.literal(0), z.literal(1), z.literal(2), z.literal(3)])
|
||||
export const flowchartStatusSchema = z.union([
|
||||
z.literal(0),
|
||||
z.literal(1),
|
||||
z.literal(2),
|
||||
z.literal(3),
|
||||
])
|
||||
|
||||
export const createFlowchartRequestSchema = z.object({
|
||||
problemId: z.number().int().positive(),
|
||||
mermaidCode: z.string().trim().min(1).max(50_000).refine(
|
||||
(value) => value.split("\n").filter((line) => line.trim()).length <= 200,
|
||||
"Flowchart is too complex",
|
||||
),
|
||||
mermaidCode: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1)
|
||||
.max(50_000)
|
||||
.refine(
|
||||
(value) => value.split("\n").filter((line) => line.trim()).length <= 200,
|
||||
"Flowchart is too complex",
|
||||
),
|
||||
flowchartData: z.record(z.string(), z.unknown()).default({}),
|
||||
})
|
||||
|
||||
@@ -49,9 +59,19 @@ export const flowchartListItemSchema = z.object({
|
||||
})
|
||||
|
||||
export const flowchartListSchema = paginatedSchema(flowchartListItemSchema)
|
||||
export const createFlowchartResponseSchema = z.object({ submissionId: z.string(), status: z.literal("pending") })
|
||||
export const flowchartCurrentSchema = z.object({ count: z.number().int(), score: z.number(), grade: z.string() })
|
||||
export const flowchartDetailSchema = z.object({ submission: flowchartSubmissionSchema.nullable(), count: z.number().int() })
|
||||
export const createFlowchartResponseSchema = z.object({
|
||||
submissionId: z.string(),
|
||||
status: z.literal("pending"),
|
||||
})
|
||||
export const flowchartCurrentSchema = z.object({
|
||||
count: z.number().int(),
|
||||
score: z.number(),
|
||||
grade: z.string(),
|
||||
})
|
||||
export const flowchartDetailSchema = z.object({
|
||||
submission: flowchartSubmissionSchema.nullable(),
|
||||
count: z.number().int(),
|
||||
})
|
||||
|
||||
export const flowchartStatisticsSchema = z.object({
|
||||
totalCount: z.number().int(),
|
||||
@@ -94,7 +114,11 @@ export type FlowchartListItem = z.infer<typeof flowchartListItemSchema>
|
||||
export type FlowchartList = z.infer<typeof flowchartListSchema>
|
||||
export type FlowchartCurrent = z.infer<typeof flowchartCurrentSchema>
|
||||
export type FlowchartDetail = z.infer<typeof flowchartDetailSchema>
|
||||
export type CreateFlowchartResponse = z.infer<typeof createFlowchartResponseSchema>
|
||||
export type CreateFlowchartRequest = z.infer<typeof createFlowchartRequestSchema>
|
||||
export type CreateFlowchartResponse = z.infer<
|
||||
typeof createFlowchartResponseSchema
|
||||
>
|
||||
export type CreateFlowchartRequest = z.infer<
|
||||
typeof createFlowchartRequestSchema
|
||||
>
|
||||
|
||||
export type FlowchartStatus = z.infer<typeof flowchartStatusSchema>
|
||||
|
||||
@@ -38,6 +38,5 @@ export const problemLanguageSchema = z.enum([
|
||||
"Flowchart",
|
||||
])
|
||||
|
||||
|
||||
export type JudgeLanguage = z.infer<typeof judgeLanguageSchema>
|
||||
export type ProblemLanguage = z.infer<typeof problemLanguageSchema>
|
||||
|
||||
@@ -148,7 +148,10 @@ const C_NODE_TARGETS = {
|
||||
include: { label: "#include 指令", node: "preproc_include" },
|
||||
} satisfies Record<string, AstNodeTarget>
|
||||
|
||||
export const AST_NODE_TARGETS_BY_LANGUAGE: Record<string, Record<string, AstNodeTarget>> = {
|
||||
export const AST_NODE_TARGETS_BY_LANGUAGE: Record<
|
||||
string,
|
||||
Record<string, AstNodeTarget>
|
||||
> = {
|
||||
C: C_NODE_TARGETS,
|
||||
/**
|
||||
* tree-sitter-cpp 继承 tree-sitter-c 的语法,C 那 14 条在 C++ 树里逐个实测通用,
|
||||
@@ -225,24 +228,62 @@ export const AST_NODE_TARGETS_BY_LANGUAGE: Record<string, Record<string, AstNode
|
||||
* 恒等的条目(`+`、`==` …)写全是因为这张表同时是后台下拉的选项来源。
|
||||
*/
|
||||
const C_OPERATOR_TARGETS = {
|
||||
"+": "+", "-": "-", "*": "*", "/": "/", "%": "%",
|
||||
"+=": "+=", "-=": "-=", "*=": "*=", "/=": "/=", "%=": "%=",
|
||||
"++": "++", "--": "--",
|
||||
"==": "==", "!=": "!=", ">": ">", ">=": ">=", "<": "<", "<=": "<=",
|
||||
and: "&&", or: "||", not: "!",
|
||||
"&": "&", "|": "|",
|
||||
"+": "+",
|
||||
"-": "-",
|
||||
"*": "*",
|
||||
"/": "/",
|
||||
"%": "%",
|
||||
"+=": "+=",
|
||||
"-=": "-=",
|
||||
"*=": "*=",
|
||||
"/=": "/=",
|
||||
"%=": "%=",
|
||||
"++": "++",
|
||||
"--": "--",
|
||||
"==": "==",
|
||||
"!=": "!=",
|
||||
">": ">",
|
||||
">=": ">=",
|
||||
"<": "<",
|
||||
"<=": "<=",
|
||||
and: "&&",
|
||||
or: "||",
|
||||
not: "!",
|
||||
"&": "&",
|
||||
"|": "|",
|
||||
}
|
||||
|
||||
export const AST_OPERATOR_TARGETS_BY_LANGUAGE: Record<string, Record<string, string>> = {
|
||||
export const AST_OPERATOR_TARGETS_BY_LANGUAGE: Record<
|
||||
string,
|
||||
Record<string, string>
|
||||
> = {
|
||||
C: C_OPERATOR_TARGETS,
|
||||
// `<<` / `>>` 对 C++ 主要是 cout/cin 的流运算符(位移是同一个 token)
|
||||
"C++": { ...C_OPERATOR_TARGETS, "<<": "<<", ">>": ">>" },
|
||||
Python3: {
|
||||
"+": "+", "-": "-", "*": "*", "/": "/", "//": "//", "%": "%", "**": "**",
|
||||
"+=": "+=", "-=": "-=", "*=": "*=", "/=": "/=", "%=": "%=",
|
||||
"==": "==", "!=": "!=", ">": ">", ">=": ">=", "<": "<", "<=": "<=",
|
||||
and: "and", or: "or", not: "not",
|
||||
"&": "&", "|": "|",
|
||||
"+": "+",
|
||||
"-": "-",
|
||||
"*": "*",
|
||||
"/": "/",
|
||||
"//": "//",
|
||||
"%": "%",
|
||||
"**": "**",
|
||||
"+=": "+=",
|
||||
"-=": "-=",
|
||||
"*=": "*=",
|
||||
"/=": "/=",
|
||||
"%=": "%=",
|
||||
"==": "==",
|
||||
"!=": "!=",
|
||||
">": ">",
|
||||
">=": ">=",
|
||||
"<": "<",
|
||||
"<=": "<=",
|
||||
and: "and",
|
||||
or: "or",
|
||||
not: "not",
|
||||
"&": "&",
|
||||
"|": "|",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -254,11 +295,12 @@ export const AST_OPERATOR_TARGETS_BY_LANGUAGE: Record<string, Record<string, str
|
||||
export const AST_SUPPORTED_LANGUAGES = Object.keys(AST_NODE_TARGETS_BY_LANGUAGE)
|
||||
|
||||
/** 全语言的节点中文名并集,只给拿不到语言的场合做回落。有语言一律走 astNodeLabel() */
|
||||
export const AST_NODE_TARGET_LABELS: Record<string, string> = Object.fromEntries(
|
||||
Object.values(AST_NODE_TARGETS_BY_LANGUAGE).flatMap((table) =>
|
||||
Object.entries(table).map(([target, entry]) => [target, entry.label]),
|
||||
),
|
||||
)
|
||||
export const AST_NODE_TARGET_LABELS: Record<string, string> =
|
||||
Object.fromEntries(
|
||||
Object.values(AST_NODE_TARGETS_BY_LANGUAGE).flatMap((table) =>
|
||||
Object.entries(table).map(([target, entry]) => [target, entry.label]),
|
||||
),
|
||||
)
|
||||
|
||||
export function astNodeLabel(target: string, language?: string): string {
|
||||
const table = language ? AST_NODE_TARGETS_BY_LANGUAGE[language] : undefined
|
||||
@@ -279,7 +321,11 @@ export function astTargetNodeType(target: string, language: string): string {
|
||||
}
|
||||
|
||||
export function astOperatorLabel(target: string, language?: string): string {
|
||||
return (language ? AST_OPERATOR_TARGETS_BY_LANGUAGE[language]?.[target] : undefined) ?? target
|
||||
return (
|
||||
(language
|
||||
? AST_OPERATOR_TARGETS_BY_LANGUAGE[language]?.[target]
|
||||
: undefined) ?? target
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -297,7 +343,9 @@ export function astRuleIsMeaningful(rule: {
|
||||
max?: number
|
||||
}): boolean {
|
||||
if (!rule.engine.startsWith("count")) return true
|
||||
return rule.exact !== undefined || rule.min !== undefined || rule.max !== undefined
|
||||
return (
|
||||
rule.exact !== undefined || rule.min !== undefined || rule.max !== undefined
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -71,7 +71,6 @@ export const joinProblemSetRequestSchema = z.object({
|
||||
problemSetId: z.number().int().positive(),
|
||||
})
|
||||
|
||||
|
||||
export const completedProblemSchema = z.object({
|
||||
id: z.number().int(),
|
||||
_id: z.string(),
|
||||
@@ -92,7 +91,9 @@ export const problemSetProgressSchema = z.object({
|
||||
completedProblems: z.array(completedProblemSchema),
|
||||
})
|
||||
|
||||
export const problemSetProgressListSchema = paginatedSchema(problemSetProgressSchema).extend({
|
||||
export const problemSetProgressListSchema = paginatedSchema(
|
||||
problemSetProgressSchema,
|
||||
).extend({
|
||||
statistics: z.object({
|
||||
total: z.number().int(),
|
||||
completed: z.number().int(),
|
||||
@@ -114,9 +115,13 @@ export type ProblemSetList = z.infer<typeof problemSetListSchema>
|
||||
export type ProblemSetBadge = z.infer<typeof problemSetBadgeSchema>
|
||||
export type ProblemSetProblem = z.infer<typeof problemSetProblemSchema>
|
||||
export type ProblemSetProgress = z.infer<typeof problemSetProgressSchema>
|
||||
export type ProblemSetProgressList = z.infer<typeof problemSetProgressListSchema>
|
||||
export type ProblemSetProgressList = z.infer<
|
||||
typeof problemSetProgressListSchema
|
||||
>
|
||||
export type UserBadge = z.infer<typeof userBadgeSchema>
|
||||
export type CompletedProblem = z.infer<typeof completedProblemSchema>
|
||||
|
||||
export type ProblemSetUserProgressSummary = z.infer<typeof problemSetUserProgressSummarySchema>
|
||||
export type ProblemSetUserProgressSummary = z.infer<
|
||||
typeof problemSetUserProgressSummarySchema
|
||||
>
|
||||
export type JoinProblemSetRequest = z.infer<typeof joinProblemSetRequestSchema>
|
||||
|
||||
@@ -33,23 +33,35 @@ export const problemPermissionSchema = z.enum(PROBLEM_PERMISSIONS)
|
||||
*/
|
||||
|
||||
/** 能进后台的三种 */
|
||||
export const ADMIN_ROLES: readonly AdminType[] = ["Student Admin", "Teacher Admin", "Super Admin"]
|
||||
export const ADMIN_ROLES: readonly AdminType[] = [
|
||||
"Student Admin",
|
||||
"Teacher Admin",
|
||||
"Super Admin",
|
||||
]
|
||||
|
||||
/** 老师及以上 */
|
||||
export const TEACHER_ROLES: readonly AdminType[] = ["Teacher Admin", "Super Admin"]
|
||||
export const TEACHER_ROLES: readonly AdminType[] = [
|
||||
"Teacher Admin",
|
||||
"Super Admin",
|
||||
]
|
||||
|
||||
/**
|
||||
* 学生口径:排行榜、班级榜、比赛榜、自学统计都只算这两种,教师和超管不入榜。
|
||||
* 注意 Student Admin 算学生 —— 他要参赛、要上榜,只是多了个后台入口。
|
||||
*/
|
||||
export const STUDENT_ROLES: readonly AdminType[] = ["Regular User", "Student Admin"]
|
||||
export const STUDENT_ROLES: readonly AdminType[] = [
|
||||
"Regular User",
|
||||
"Student Admin",
|
||||
]
|
||||
|
||||
/**
|
||||
* 把库里读出来的裸字符串收成联合类型。**认不出来的一律降成最低权限**,
|
||||
* 不抛错:脏数据不该让人登不上,但更不该让人凭一个拼错的角色名拿到权限。
|
||||
*/
|
||||
export function toAdminType(value: string): AdminType {
|
||||
return (ADMIN_TYPES as readonly string[]).includes(value) ? (value as AdminType) : "Regular User"
|
||||
return (ADMIN_TYPES as readonly string[]).includes(value)
|
||||
? (value as AdminType)
|
||||
: "Regular User"
|
||||
}
|
||||
|
||||
export function toProblemPermission(value: string): ProblemPermission {
|
||||
|
||||
@@ -81,14 +81,16 @@ export const statisticInfoSchema = z.looseObject({
|
||||
err_info: z.string().optional(),
|
||||
time_cost: z.number().optional(),
|
||||
memory_cost: z.number().optional(),
|
||||
ast_results: z.array(
|
||||
z.object({
|
||||
description: z.string(),
|
||||
passed: z.boolean(),
|
||||
/** count_* 规则实际数到的次数,判题机只在这两个引擎上写 */
|
||||
actual: z.number().optional(),
|
||||
}),
|
||||
).optional(),
|
||||
ast_results: z
|
||||
.array(
|
||||
z.object({
|
||||
description: z.string(),
|
||||
passed: z.boolean(),
|
||||
/** count_* 规则实际数到的次数,判题机只在这两个引擎上写 */
|
||||
actual: z.number().optional(),
|
||||
}),
|
||||
)
|
||||
.optional(),
|
||||
})
|
||||
|
||||
export const createSubmissionRequestSchema = z.object({
|
||||
@@ -100,7 +102,10 @@ export const createSubmissionRequestSchema = z.object({
|
||||
* 学生看到的是「系统错误」而不是「语言不对」。
|
||||
*/
|
||||
language: problemLanguageSchema,
|
||||
code: z.string().min(1).max(1024 * 1024),
|
||||
code: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(1024 * 1024),
|
||||
contestId: z.number().int().positive().optional(),
|
||||
/**
|
||||
* 来源题单。学生从 `/problemset/:id/problem/:pid` 那个入口提交时前端带上,
|
||||
@@ -146,10 +151,12 @@ export const submissionDetailSchema = z.object({
|
||||
* SQL 题(`judge/run.ts` 遇到被杀的测试点会 break,total 偏小)、没有逐点结果
|
||||
* (待判、编译失败)。
|
||||
*/
|
||||
caseSummary: z.object({
|
||||
passed: z.number().int(),
|
||||
total: z.number().int(),
|
||||
}).nullable(),
|
||||
caseSummary: z
|
||||
.object({
|
||||
passed: z.number().int(),
|
||||
total: z.number().int(),
|
||||
})
|
||||
.nullable(),
|
||||
})
|
||||
|
||||
/**
|
||||
@@ -164,7 +171,13 @@ export const embeddedSubmissionSchema = submissionDetailSchema
|
||||
// problemDisplayId 也要去掉:下面的 problem 就是它,同一个值留两份,
|
||||
// 而路由只填了 problem —— 这里漏 omit 的那阵子,凡是收到过站内信的人
|
||||
// 打开消息页都是 500(parse 抛在缺失的 problemDisplayId 上,列表为空时才碰巧不炸)。
|
||||
.omit({ info: true, contestId: true, problemId: true, problemDisplayId: true, caseSummary: true })
|
||||
.omit({
|
||||
info: true,
|
||||
contestId: true,
|
||||
problemId: true,
|
||||
problemDisplayId: true,
|
||||
caseSummary: true,
|
||||
})
|
||||
// 旧 SubmissionSafeModelSerializer 里 problem 是
|
||||
// `SlugRelatedField(slug_field="_id")`,即**展示用题号**而非数字主键。
|
||||
// 站内信页面拿它拼 `/problem/<题号>` 链接,给数字 id 会拼出打不开的地址。
|
||||
@@ -407,7 +420,9 @@ export type AttemptedStudent = z.infer<typeof attemptedStudentSchema>
|
||||
export type SubmissionListItem = z.infer<typeof submissionListItemSchema>
|
||||
export type SubmissionList = z.infer<typeof submissionListSchema>
|
||||
export type EmbeddedSubmission = z.infer<typeof embeddedSubmissionSchema>
|
||||
export type CreateSubmissionResponse = z.infer<typeof createSubmissionResponseSchema>
|
||||
export type CreateSubmissionResponse = z.infer<
|
||||
typeof createSubmissionResponseSchema
|
||||
>
|
||||
export type FormatCodeResponse = z.infer<typeof formatCodeResponseSchema>
|
||||
|
||||
export type FormatCodeRequest = z.infer<typeof formatCodeRequestSchema>
|
||||
|
||||
Reference in New Issue
Block a user