feat(成就): 下架三个拿不到的成就、理顺稀有度和图标;接口多给本班几人有和「本班」卡片
- 0032:下架六边形战士(判题机只剩 3 种语言)、坚持三天/一周(按天算基本拿不到); 不撞南墙改白银、屡败屡战改黄金;百发百中换 💯、屡败屡战换 💪,不再和别的撞图标; 代码行数只算做对的、空行不算,并按新口径重算所有人;已经拿到的一个不收回 - 奖杯收藏家只数上架的成就(判题结算、补发重算、0032 存量一起改) - GET /achievements:每个成就带全站几人有、本班几人有;看自己时带「本班」(最近拿到、成就最多前五、自己第几); 隐藏成就同一串拿到一档就整串亮出来;连续几周给「现在连着几周」而不是历史最长 - 删掉只有旧成就页在用的 /achievements/summary Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
689d40b116
commit
85108df9d8
9 files changed
+4220
-213
No files matched your search
@@ -15,13 +15,41 @@ export const achievementSchema = z.object({
|
||||
unlocked: z.boolean(),
|
||||
unlockTime: z.string().nullable(),
|
||||
backfilled: z.boolean(),
|
||||
/** 连续几周那一串给的是「现在连着几周」,不是历史最长 —— 要拿下一档得从现在数起 */
|
||||
progress: z.number().nullable(),
|
||||
unlockRate: z.number(),
|
||||
/** 全站几人有 */
|
||||
holders: z.number().int(),
|
||||
/** 本班(被看的人的班)几人有;没有班级是 null */
|
||||
classHolders: z.number().int().nullable(),
|
||||
})
|
||||
|
||||
/** 「本班」那张卡:只在看自己、而且有班级时给 */
|
||||
export const achievementClassBoardSchema = z.object({
|
||||
className: z.string(),
|
||||
/** 本班最近拿到的(补发的不算),新的在前 */
|
||||
recent: z.array(
|
||||
z.object({
|
||||
username: z.string(),
|
||||
achievementId: z.number().int(),
|
||||
unlockTime: z.string(),
|
||||
}),
|
||||
),
|
||||
/** 本班成就最多的前几名;一样多的名次相同,先拿到的排前面 */
|
||||
most: z.array(
|
||||
z.object({
|
||||
username: z.string(),
|
||||
count: z.number().int(),
|
||||
rank: z.number().int(),
|
||||
}),
|
||||
),
|
||||
/** 自己不在 most 里时的名次;不计入排名的人是 null */
|
||||
me: z.object({ rank: z.number().int(), count: z.number().int() }).nullable(),
|
||||
})
|
||||
|
||||
export const achievementListSchema = z.object({
|
||||
username: z.string(),
|
||||
achievements: z.array(achievementSchema),
|
||||
classBoard: achievementClassBoardSchema.nullable(),
|
||||
})
|
||||
|
||||
export const pendingAchievementSchema = z.object({
|
||||
@@ -32,13 +60,6 @@ export const pendingAchievementSchema = z.object({
|
||||
rarity: achievementRaritySchema,
|
||||
})
|
||||
|
||||
export const achievementRarityStatSchema = z.object({
|
||||
rarity: achievementRaritySchema,
|
||||
label: z.string(),
|
||||
total: z.number().int(),
|
||||
unlocked: z.number().int(),
|
||||
})
|
||||
|
||||
/**
|
||||
* WebSocket 推来的解锁通知。比 `/achievements/pending` 多一个 `kind` ——
|
||||
* 题单奖章和成就来自两张表、id 会重叠,前端靠它区分(见 events.ts 的 publishAchievementNotification)。
|
||||
@@ -47,15 +68,6 @@ export const achievementNotificationSchema = pendingAchievementSchema.extend({
|
||||
kind: z.enum(["achievement", "badge"]),
|
||||
})
|
||||
|
||||
export const achievementSummarySchema = z.object({
|
||||
username: z.string(),
|
||||
total: z.number().int(),
|
||||
unlocked: z.number().int(),
|
||||
percent: z.number(),
|
||||
rarity: z.array(achievementRarityStatSchema),
|
||||
recent: z.array(pendingAchievementSchema),
|
||||
})
|
||||
|
||||
export const markAchievementsReadSchema = z.object({
|
||||
ids: z.array(z.number().int()),
|
||||
})
|
||||
@@ -63,9 +75,8 @@ export const markAchievementsReadSchema = z.object({
|
||||
export type Achievement = z.infer<typeof achievementSchema>
|
||||
export type AchievementList = z.infer<typeof achievementListSchema>
|
||||
export type PendingAchievement = z.infer<typeof pendingAchievementSchema>
|
||||
export type AchievementSummary = z.infer<typeof achievementSummarySchema>
|
||||
export type AchievementClassBoard = z.infer<typeof achievementClassBoardSchema>
|
||||
export type AchievementRarity = z.infer<typeof achievementRaritySchema>
|
||||
export type AchievementRarityStat = z.infer<typeof achievementRarityStatSchema>
|
||||
export type AchievementNotification = z.infer<typeof achievementNotificationSchema>
|
||||
|
||||
export type MarkAchievementsRead = z.infer<typeof markAchievementsReadSchema>
|
||||
Reference in new issue
Block a user