feat(teacher): 题库模块(QuestionBank)

工作内容

- 新增 /teacher/questions 页面,支持 Suspense/空状态/加载态

- 题库 CRUD Server Actions:创建/更新/递归删除子题,变更后 revalidatePath

- getQuestions 支持 q/type/difficulty/knowledgePointId 筛选与分页返回 meta

- UI:表格列/筛选器/创建编辑弹窗,content JSON 兼容组卷

- 更新中文设计文档:docs/design/004_question_bank_implementation.md
This commit is contained in:
SpecialX
2025-12-30 19:04:22 +08:00
parent f7ff018490
commit f8e39f518d
12 changed files with 680 additions and 325 deletions

View File

@@ -1,87 +1,132 @@
# Question Bank Module Implementation
# 题库模块实现
## 1. Overview
The Question Bank module (`src/modules/questions`) is a core component for teachers to manage their examination resources. It implements a comprehensive CRUD interface with advanced filtering and batch operations.
## 1. 概述
题库模块(`src/modules/questions`)是教师管理考试资源的核心组件,提供完整的 CRUD 能力,并支持搜索/筛选等常用管理能力。
**Status**: IMPLEMENTED
**Date**: 2025-12-23
**Author**: Senior Frontend Engineer
**状态**:已实现
**日期**2025-12-23
**作者**:前端高级工程师
---
## 2. Architecture & Tech Stack
## 2. 架构与技术栈
### 2.1 Vertical Slice Architecture
Following the project's architectural guidelines, all question-related logic is encapsulated within `src/modules/questions`:
- `components/`: UI components (Data Table, Dialogs, Filters)
- `actions.ts`: Server Actions for data mutation
- `data-access.ts`: Database query logic
- `schema.ts`: Zod schemas for validation
- `types.ts`: TypeScript interfaces
### 2.1 垂直切片(Vertical Slice)架构
遵循项目的架构规范,所有与题库相关的逻辑都收敛在 `src/modules/questions` 下:
- `components/`UI 组件(表格、弹窗、筛选器)
- `actions.ts`Server Actions(数据变更)
- `data-access.ts`:数据库查询逻辑
- `schema.ts`Zod 校验 Schema
- `types.ts`TypeScript 类型定义
### 2.2 Key Technologies
- **Data Grid**: `@tanstack/react-table` for high-performance rendering.
- **State Management**: `nuqs` for URL-based state (filters, search).
- **Forms**: `react-hook-form` + `zod` + `shadcn/ui` form components.
- **Validation**: Strict server-side and client-side validation using Zod schemas.
### 2.2 关键技术
- **数据表格**`@tanstack/react-table`(高性能表格渲染)
- **状态管理**`nuqs`(基于 URL Query 的筛选/搜索状态)
- **表单**`react-hook-form` + `zod` + `shadcn/ui` 表单组件
- **校验**Zod 提供严格的服务端/客户端校验
---
## 3. Component Design
## 3. 组件设计
### 3.1 QuestionDataTable (`question-data-table.tsx`)
- **Features**: Pagination, Sorting, Row Selection.
- **Performance**: Uses `React.memo` compatible patterns where possible (though `useReactTable` itself is not memoized).
- **Responsiveness**: Mobile-first design with horizontal scroll for complex columns.
### 3.1 QuestionDataTable`question-data-table.tsx`
- **能力**:分页、排序、行选择
- **性能**:尽可能采用与 `React.memo` 兼容的写法(`useReactTable` 本身不做 memo
- **响应式**:移动端优先;复杂列支持横向滚动
### 3.2 QuestionColumns (`question-columns.tsx`)
Custom cell renderers for rich data display:
- **Type Badge**: Color-coded badges for different question types (Single Choice, Multiple Choice, etc.).
- **Difficulty**: Visual indicator with color (Green -> Red) and numerical value.
- **Actions**: Dropdown menu for Edit, Delete, View Details, and Copy ID.
### 3.2 QuestionColumns`question-columns.tsx`
用于增强单元格展示的自定义渲染:
- **题型 Badge**:不同题型的颜色/样式区分(单选、多选等)
- **难度展示**:难度标签 + 数值
- **行操作**:下拉菜单(编辑、删除、查看详情、复制 ID
### 3.3 Create/Edit Dialog (`create-question-dialog.tsx`)
A unified dialog component for both creating and editing questions.
- **Dynamic Fields**: Shows/hides "Options" field based on question type.
- **Interactive Options**: Allows adding/removing/reordering options for choice questions.
- **Optimistic UI**: Shows loading states during submission.
### 3.3 创建/编辑弹窗(`create-question-dialog.tsx`
创建与编辑共用同一个弹窗组件:
- **动态字段**:根据题型显示/隐藏“选项”区域
- **选项编辑**:支持添加/删除选项(选择题)
- **交互反馈**:提交中 Loading 状态
### 3.4 Filters (`question-filters.tsx`)
- **URL Sync**: All filter states (Search, Type, Difficulty) are synced to URL parameters.
- **Debounce**: Search input uses debounce to prevent excessive requests.
- **Server Filtering**: Filtering logic is executed on the server side (currently simulated in `page.tsx`, ready for DB integration).
### 3.4 筛选器(`question-filters.tsx`
- **URL 同步**:搜索、题型、难度等筛选条件与 URL 参数保持同步
- **Debounce(当前)**:搜索输入每次变更都会更新 URL
- **服务端筛选**:在服务端组件中通过 `getQuestions` 执行筛选查询
---
## 4. Implementation Details
## 4. 实现细节
### 4.1 Data Flow
1. **Read**: `page.tsx` (Server Component) fetches data based on `searchParams`.
2. **Write**: Client components invoke Server Actions (simulated) -> Revalidate Path -> UI Updates.
3. **Filter**: User interaction -> Update URL -> Server Component Re-render -> New Data.
### 4.1 数据流
1. **读取**`page.tsx`Server Component)根据 `searchParams` 拉取数据
2. **写入**:客户端组件调用 Server Actions -> `revalidatePath` -> UI 更新
3. **筛选**:用户操作 -> 更新 URL -> 服务端组件重新渲染 -> 返回新数据
### 4.2 类型安全
共享的 `Question` 类型用于保证前后端一致:
### 4.2 Type Safety
A shared `Question` interface ensures consistency across the stack:
```typescript
export interface Question {
id: string;
content: any; // Rich text structure
type: QuestionType;
difficulty: number;
// ... relations
id: string
content: unknown
type: QuestionType
difficulty: number
// ... 关联字段
}
```
### 4.3 UI/UX Standards
- **Empty States**: Custom `EmptyState` component when no data matches.
- **Loading States**: Skeleton screens for table loading.
- **Feedback**: `Sonner` toasts for success/error notifications.
- **Confirmation**: `AlertDialog` for destructive actions (Delete).
### 4.3 UI/UX 规范
- **空状态**:无数据时展示 `EmptyState`
- **加载态**:表格加载使用 Skeleton
- **反馈**`Sonner` toast 展示成功/失败提示
- **确认弹窗**:删除等破坏性操作使用 `AlertDialog`
---
## 5. Next Steps
- [ ] Integrate with real Database (replace Mock Data).
- [ ] Implement Rich Text Editor (Slate.js / Tiptap) for question content.
- [ ] Add "Batch Import" functionality.
- [ ] Implement "Tags" management for Knowledge Points.
## 5. 后续计划
- [x] 接入真实数据库(替换 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 结构:
```typescript
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 ActionsCRUD
- `createNestedQuestion` 支持 FormData字段 `json`)与递归 `subQuestions`
- `updateQuestionAction` 更新题目与知识点关联
- `deleteQuestionAction` 递归删除子题
- 所有变更都会对 `/teacher/questions` 做缓存再验证
### 6.5 UI 集成
- `CreateQuestionDialog` 提交 `QuestionContent` JSON并支持选择题正确答案勾选
- `QuestionActions` 在编辑/删除后刷新列表
- 表格内容预览优先展示 `content.text`
### 6.6 校验
- `npm run lint`0 errors仓库其他位置仍存在 warnings
- `npm run typecheck`:通过