feat(标签): 题目列表的标签分成「知识点」「主题」两组,新建的标签在后台标出待归类
Deploy / deploy (push) Canceled after 0s

- 迁移 0022:problem_tag 加 category(knowledge / theme)和 category_confirmed;
  存量 25 个题材、题集类标签归主题,其余归知识点,全部记为已确认
- 前台题目列表按两组显示标签,组内按题目数从多到少
- 后台标签管理:每行切换分类;出题时新建的标签默认知识点、标「待归类」并排在最前,
  页头提示待归类数量,可点「确认」保留默认;加分类筛选
- 新接口 PUT /admin/problem-tags/:id/category,设置分类即视为确认

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-09-27 20:38:43 +08:00
1 parent e1b6a9e9fa
commit d07459928d
12 files changed
+4226 -30

No files matched your search

+8
View File
@@ -12,6 +12,7 @@ import {
problemDifficultySchema,
sqlConfigSchema,
sqlDisplaySchema,
tagCategorySchema,
} from "./problem"
// 放这里而不是 roles.ts:roles.ts 要保持不 import zod,理由见那边的文件头
@@ -472,9 +473,16 @@ export const adminProblemSetProgressSchema = z.object({
export const adminTagSchema = z.object({
id: z.number().int(),
name: z.string(),
category: tagCategorySchema,
/** 分类有没有人确认过。出题时新建的标签是 false,默认先算知识点,等老师归类 */
categoryConfirmed: z.boolean(),
problemCount: z.number().int(),
})
export const setTagCategoryRequestSchema = z.object({
category: tagCategorySchema,
})
export const renameTagRequestSchema = z.object({
name: z.string().trim().min(1).max(64),
})
+9
View File
@@ -427,9 +427,17 @@ export const problemListItemSchema = z.object({
export const problemListSchema = paginatedSchema(problemListItemSchema)
/**
* 标签分两类:`knowledge` 是知识点(循环结构、字符串……),`theme` 是题目的
* 题材(LOL、周杰伦、哈利波特……)。两类原来混在一起,题目列表上四十多个标签
* 挤成一片,学生想按知识点找题得在一堆游戏名里挑。新标签默认算知识点。
*/
export const tagCategorySchema = z.enum(["knowledge", "theme"])
export const tagSchema = z.object({
id: z.number().int(),
name: z.string(),
category: tagCategorySchema,
problemCount: z.number().int().nonnegative(),
})
@@ -454,6 +462,7 @@ export type ProblemDifficulty = z.infer<typeof problemDifficultySchema>
export type ProblemListItem = z.infer<typeof problemListItemSchema>
export type ProblemList = z.infer<typeof problemListSchema>
export type Tag = z.infer<typeof tagSchema>
export type TagCategory = z.infer<typeof tagCategorySchema>
export type ProblemAuthor = z.infer<typeof problemAuthorSchema>
export type SqlConfig = z.infer<typeof sqlConfigSchema>
export type SqlDisplay = z.infer<typeof sqlDisplaySchema>