Files
OJ2/packages/contract/src/problemset.ts
T
xuyue d25b5dbe6d
Deploy / deploy (push) Canceled after 0s
update
2026-09-27 19:36:28 +08:00

122 lines
4.0 KiB
TypeScript

import { z } from "zod"
import { paginatedSchema, sampleUserSchema } from "./common"
import { maskedProblemDifficultySchema } from "./problem"
export const problemSetUserProgressSummarySchema = z.object({
isJoined: z.boolean(),
progressPercentage: z.number(),
completedCount: z.number().int(),
totalCount: z.number().int(),
isCompleted: z.boolean(),
})
export const problemSetBadgeSchema = z.object({
id: z.number().int(),
problemSetId: z.number().int(),
name: z.string(),
description: z.string(),
icon: z.string(),
conditionType: z.enum(["all_problems", "problem_count", "score"]),
conditionValue: z.number().int(),
isEarned: z.boolean().optional(),
})
export const problemSetSchema = z.object({
id: z.number().int(),
title: z.string(),
description: z.string(),
createdBy: sampleUserSchema,
createTime: z.string(),
lastUpdateTime: z.string().optional(),
difficulty: z.enum(["Easy", "Medium", "Hard"]),
status: z.enum(["active", "archived", "draft"]),
endTime: z.string().nullable(),
visible: z.boolean(),
problemsCount: z.number().int(),
completedCount: z.number().int().optional(),
userProgress: problemSetUserProgressSummarySchema,
badges: z.array(problemSetBadgeSchema).optional(),
})
export const problemSetListSchema = paginatedSchema(problemSetSchema)
/**
* 题单页的题目卡片只渲染题号、标题、难度,所以只下发这三样(外加题目主键)。
*
* 以前这里复用 problemListItemSchema,代价是服务端每次都要多 join 一次 user +
* user_profile 凑 createdBy、再多查一次标签表凑 tags,而 tags / submissionNumber /
* acceptedNumber / createdBy / flowchart / hasAstRules / myStatus 在题单页一个都不渲染
* —— myStatus 甚至是写死的 null。
*/
export const problemSetProblemItemSchema = z.object({
id: z.number().int(),
_id: z.string(),
title: z.string(),
difficulty: maskedProblemDifficultySchema,
})
export const problemSetProblemSchema = z.object({
id: z.number().int(),
problemSetId: z.number().int(),
problem: problemSetProblemItemSchema,
order: z.number().int(),
isRequired: z.boolean(),
score: z.number().int(),
hint: z.string().nullable(),
isCompleted: z.boolean(),
})
export const joinProblemSetRequestSchema = z.object({
problemSetId: z.number().int().positive(),
})
export const completedProblemSchema = z.object({
id: z.number().int(),
_id: z.string(),
title: z.string(),
})
export const problemSetProgressSchema = z.object({
id: z.number().int(),
problemSetId: z.number().int(),
user: sampleUserSchema,
joinTime: z.string(),
completeTime: z.string().nullable(),
isCompleted: z.boolean(),
progressPercentage: z.number(),
completedProblemsCount: z.number().int(),
totalProblemsCount: z.number().int(),
totalScore: z.number().int(),
completedProblems: z.array(completedProblemSchema),
})
export const problemSetProgressListSchema = paginatedSchema(problemSetProgressSchema).extend({
statistics: z.object({
total: z.number().int(),
completed: z.number().int(),
avgProgress: z.number(),
}),
problems: z.array(completedProblemSchema),
})
export const userBadgeSchema = z.object({
id: z.number().int(),
userId: z.number().int(),
badge: problemSetBadgeSchema,
earnedTime: z.string(),
problemSet: z.object({ id: z.number().int(), title: z.string() }),
})
export type ProblemSet = z.infer<typeof problemSetSchema>
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 UserBadge = z.infer<typeof userBadgeSchema>
export type CompletedProblem = z.infer<typeof completedProblemSchema>
export type ProblemSetUserProgressSummary = z.infer<typeof problemSetUserProgressSummarySchema>
export type JoinProblemSetRequest = z.infer<typeof joinProblemSetRequestSchema>