refactor(契约): 展示题号统一叫 problemDisplayId,题单 id 统一叫 problemSetId
Deploy / deploy (push) Canceled after 0s
Deploy / deploy (push) Canceled after 0s
前后端同时改,部署前开着的旧页面要刷新一次(题号列会是空的、提交筛选会失效)。 - 挂在非题目对象上的展示题号,原来叫 problem(字符串)或 displayId,统一成 problemDisplayId:提交列表、流程图列表、统计的 lastFailure / items / 今日最热题、站内信里的提交、后台题单的题目列表。别处的 problem 都是对象 或数字 id,这几处是字符串,最容易看错 - 列表筛选的 query 参数 ?problemId= 实际传的是展示题号,改成 ?problemDisplayId=(提交列表、流程图列表、三个统计接口) - 契约里 problemsetId / problemSetId、problemset / problemSet 两种拼法并存, 统一成 problemSetId / problemSet,和 ProblemSet* 类型名、problem-sets 路径、前端路由参数一致。drizzle 的列键跟表名走,没动 - aiDetail.user(用户名字符串,而契约里别的 user 都是对象)→ username。 ai_analysis.data 里存的历史快照仍是 user,没有代码读回它 - 后台题单题目表的列是按字符串键 'displayId' 取的,类型检查抓不到,一并改 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5ae830a7f9
commit
9412ba3cf6
24 files changed
+80
-82
No files matched your search
@@ -421,9 +421,9 @@ export const updateProblemSetStatusRequestSchema = z.object({
|
||||
|
||||
export const adminProblemSetProblemSchema = z.object({
|
||||
id: z.number().int(),
|
||||
problemsetId: z.number().int(),
|
||||
problemSetId: z.number().int(),
|
||||
problemId: z.number().int(),
|
||||
displayId: z.string(),
|
||||
problemDisplayId: z.string(),
|
||||
title: z.string(),
|
||||
difficulty: z.string(),
|
||||
order: z.number().int(),
|
||||
@@ -450,7 +450,7 @@ export const updateProblemInSetRequestSchema = z.object({
|
||||
|
||||
export const adminProblemSetBadgeSchema = z.object({
|
||||
id: z.number().int(),
|
||||
problemsetId: z.number().int(),
|
||||
problemSetId: z.number().int(),
|
||||
name: z.string(),
|
||||
description: z.string(),
|
||||
icon: z.string(),
|
||||
|
||||
@@ -59,7 +59,7 @@ export const activityBucketSchema = z.object({
|
||||
})
|
||||
|
||||
export const aiDetailSchema = z.object({
|
||||
user: z.string(),
|
||||
username: z.string(),
|
||||
className: z.string().nullable(),
|
||||
start: z.string(),
|
||||
end: z.string(),
|
||||
|
||||
@@ -45,7 +45,7 @@ export const flowchartSubmissionSchema = z.object({
|
||||
export const flowchartListItemSchema = z.object({
|
||||
id: z.string(),
|
||||
username: z.string(),
|
||||
problem: z.string(),
|
||||
problemDisplayId: z.string(),
|
||||
problemTitle: z.string(),
|
||||
status: flowchartStatusSchema,
|
||||
createTime: z.string(),
|
||||
|
||||
@@ -13,7 +13,7 @@ export const problemSetUserProgressSummarySchema = z.object({
|
||||
|
||||
export const problemSetBadgeSchema = z.object({
|
||||
id: z.number().int(),
|
||||
problemsetId: z.number().int(),
|
||||
problemSetId: z.number().int(),
|
||||
name: z.string(),
|
||||
description: z.string(),
|
||||
icon: z.string(),
|
||||
@@ -58,7 +58,7 @@ export const problemSetProblemItemSchema = z.object({
|
||||
|
||||
export const problemSetProblemSchema = z.object({
|
||||
id: z.number().int(),
|
||||
problemsetId: z.number().int(),
|
||||
problemSetId: z.number().int(),
|
||||
problem: problemSetProblemItemSchema,
|
||||
order: z.number().int(),
|
||||
isRequired: z.boolean(),
|
||||
@@ -79,7 +79,7 @@ export const completedProblemSchema = z.object({
|
||||
|
||||
export const problemSetProgressSchema = z.object({
|
||||
id: z.number().int(),
|
||||
problemsetId: z.number().int(),
|
||||
problemSetId: z.number().int(),
|
||||
user: sampleUserSchema,
|
||||
joinTime: z.string(),
|
||||
completeTime: z.string().nullable(),
|
||||
@@ -107,7 +107,7 @@ export const userBadgeSchema = z.object({
|
||||
userId: z.number().int(),
|
||||
badge: problemSetBadgeSchema,
|
||||
earnedTime: z.string(),
|
||||
problemset: z.object({ id: z.number().int(), title: z.string() }),
|
||||
problemSet: z.object({ id: z.number().int(), title: z.string() }),
|
||||
})
|
||||
|
||||
export type ProblemSet = z.infer<typeof problemSetSchema>
|
||||
|
||||
@@ -191,20 +191,14 @@ export const submissionDetailSchema = z.object({
|
||||
* 将来有人「顺手」把空值改成真值就不会变成泄露,因为这里压根没有这些字段。
|
||||
*/
|
||||
export const embeddedSubmissionSchema = submissionDetailSchema
|
||||
// problemDisplayId 也要去掉:下面的 problem 就是它,同一个值留两份,
|
||||
// 而路由只填了 problem —— 这里漏 omit 的那阵子,凡是收到过站内信的人
|
||||
// 打开消息页都是 500(parse 抛在缺失的 problemDisplayId 上,列表为空时才碰巧不炸)。
|
||||
// 留下 problemDisplayId(展示用题号)而不是数字主键:站内信页面拿它拼
|
||||
// `/problem/<题号>` 链接,给数字 id 会拼出打不开的地址。
|
||||
.omit({
|
||||
info: true,
|
||||
contestId: true,
|
||||
problemId: true,
|
||||
problemDisplayId: true,
|
||||
caseSummary: true,
|
||||
})
|
||||
// 旧 SubmissionSafeModelSerializer 里 problem 是
|
||||
// `SlugRelatedField(slug_field="_id")`,即**展示用题号**而非数字主键。
|
||||
// 站内信页面拿它拼 `/problem/<题号>` 链接,给数字 id 会拼出打不开的地址。
|
||||
.extend({ problem: z.string() })
|
||||
|
||||
/**
|
||||
* 判题进度推送。**只带前端真正要用的东西**:靠 submissionId 认领、靠 result /
|
||||
@@ -224,7 +218,7 @@ export const submissionUpdateSchema = z.object({
|
||||
|
||||
export const submissionListItemSchema = z.object({
|
||||
id: z.string(),
|
||||
problem: z.string(),
|
||||
problemDisplayId: z.string(),
|
||||
problemTitle: z.string(),
|
||||
showLink: z.boolean(),
|
||||
createTime: z.string(),
|
||||
@@ -277,7 +271,7 @@ export const attemptedStudentSchema = unacceptedStudentSchema.extend({
|
||||
.object({
|
||||
id: z.string(),
|
||||
/** 题目的展示编号,用来告诉老师错在哪道题 */
|
||||
problem: z.string(),
|
||||
problemDisplayId: z.string(),
|
||||
result: judgeStatusSchema,
|
||||
error: z.string().nullable(),
|
||||
})
|
||||
@@ -325,7 +319,7 @@ export const submissionStatisticsItemsSchema = z.object({
|
||||
* 展开某个学生时列出他这段时间的提交。**带上题目**:一节课里学生往往在好几道题
|
||||
* 之间来回跳,一串只有编号的按钮看不出他卡在哪一道 —— 前端按题目分组展示。
|
||||
*
|
||||
* 字段名沿用 submissionListItemSchema 的口径:`problem` 是展示用题号(problem._id),
|
||||
* 字段名沿用 submissionListItemSchema 的口径:`problemDisplayId` 是展示用题号(problem._id),
|
||||
* `problemTitle` 是标题。
|
||||
*/
|
||||
items: z.array(
|
||||
@@ -333,7 +327,7 @@ export const submissionStatisticsItemsSchema = z.object({
|
||||
id: z.string(),
|
||||
result: judgeStatusSchema,
|
||||
createTime: z.string(),
|
||||
problem: z.string(),
|
||||
problemDisplayId: z.string(),
|
||||
problemTitle: z.string(),
|
||||
}),
|
||||
),
|
||||
@@ -405,7 +399,7 @@ export const todaySubmissionStatisticsSchema = z.object({
|
||||
*/
|
||||
problems: z.array(
|
||||
z.object({
|
||||
problem: z.string(),
|
||||
problemDisplayId: z.string(),
|
||||
problemTitle: z.string(),
|
||||
count: z.number().int(),
|
||||
acceptedCount: z.number().int(),
|
||||
|
||||
Reference in new issue
Block a user