工作内容 - 新增 /teacher/questions 页面,支持 Suspense/空状态/加载态 - 题库 CRUD Server Actions:创建/更新/递归删除子题,变更后 revalidatePath - getQuestions 支持 q/type/difficulty/knowledgePointId 筛选与分页返回 meta - UI:表格列/筛选器/创建编辑弹窗,content JSON 兼容组卷 - 更新中文设计文档:docs/design/004_question_bank_implementation.md
4.4 KiB
4.4 KiB
题库模块实现
1. 概述
题库模块(src/modules/questions)是教师管理考试资源的核心组件,提供完整的 CRUD 能力,并支持搜索/筛选等常用管理能力。
状态:已实现
日期:2025-12-23
作者:前端高级工程师
2. 架构与技术栈
2.1 垂直切片(Vertical Slice)架构
遵循项目的架构规范,所有与题库相关的逻辑都收敛在 src/modules/questions 下:
components/:UI 组件(表格、弹窗、筛选器)actions.ts:Server Actions(数据变更)data-access.ts:数据库查询逻辑schema.ts:Zod 校验 Schematypes.ts:TypeScript 类型定义
2.2 关键技术
- 数据表格:
@tanstack/react-table(高性能表格渲染) - 状态管理:
nuqs(基于 URL Query 的筛选/搜索状态) - 表单:
react-hook-form+zod+shadcn/ui表单组件 - 校验:Zod 提供严格的服务端/客户端校验
3. 组件设计
3.1 QuestionDataTable(question-data-table.tsx)
- 能力:分页、排序、行选择
- 性能:尽可能采用与
React.memo兼容的写法(useReactTable本身不做 memo) - 响应式:移动端优先;复杂列支持横向滚动
3.2 QuestionColumns(question-columns.tsx)
用于增强单元格展示的自定义渲染:
- 题型 Badge:不同题型的颜色/样式区分(单选、多选等)
- 难度展示:难度标签 + 数值
- 行操作:下拉菜单(编辑、删除、查看详情、复制 ID)
3.3 创建/编辑弹窗(create-question-dialog.tsx)
创建与编辑共用同一个弹窗组件:
- 动态字段:根据题型显示/隐藏“选项”区域
- 选项编辑:支持添加/删除选项(选择题)
- 交互反馈:提交中 Loading 状态
3.4 筛选器(question-filters.tsx)
- URL 同步:搜索、题型、难度等筛选条件与 URL 参数保持同步
- 无 Debounce(当前):搜索输入每次变更都会更新 URL
- 服务端筛选:在服务端组件中通过
getQuestions执行筛选查询
4. 实现细节
4.1 数据流
- 读取:
page.tsx(Server Component)根据searchParams拉取数据 - 写入:客户端组件调用 Server Actions ->
revalidatePath-> UI 更新 - 筛选:用户操作 -> 更新 URL -> 服务端组件重新渲染 -> 返回新数据
4.2 类型安全
共享的 Question 类型用于保证前后端一致:
export interface Question {
id: string
content: unknown
type: QuestionType
difficulty: number
// ... 关联字段
}
4.3 UI/UX 规范
- 空状态:无数据时展示
EmptyState - 加载态:表格加载使用 Skeleton
- 反馈:
Sonnertoast 展示成功/失败提示 - 确认弹窗:删除等破坏性操作使用
AlertDialog
5. 后续计划
- 接入真实数据库(替换 Mock Data)
- 为题目内容引入富文本编辑器(Slate.js / Tiptap)
- 增加“批量导入”能力
- 增加知识点“标签”管理能力
6. 实现更新(2025-12-30)
6.1 教师路由与加载态
- 实现
/teacher/questions页面(Suspense + 空状态) - 新增路由级加载 UI:
/teacher/questions/loading.tsx
6.2 Content JSON 约定
为与考试组卷/预览组件保持一致,questions.content 采用最小 JSON 结构:
type ChoiceOption = {
id: string
text: string
isCorrect?: boolean
}
type QuestionContent = {
text: string
options?: ChoiceOption[]
}
6.3 数据访问层(getQuestions)
- 新增服务端筛选:
q(content LIKE)、type、difficulty、knowledgePointId - 默认仅返回根题(
parentId IS NULL),除非显式按ids查询 - 返回
{ data, meta }(包含分页统计),并为 UI 映射关联数据
6.4 Server Actions(CRUD)
createNestedQuestion支持 FormData(字段json)与递归subQuestionsupdateQuestionAction更新题目与知识点关联deleteQuestionAction递归删除子题- 所有变更都会对
/teacher/questions做缓存再验证
6.5 UI 集成
CreateQuestionDialog提交QuestionContentJSON,并支持选择题正确答案勾选QuestionActions在编辑/删除后刷新列表- 表格内容预览优先展示
content.text
6.6 校验
npm run lint:0 errors(仓库其他位置仍存在 warnings)npm run typecheck:通过