> ⚠️ **已归档文档**
> 本文档记录的是 2025-12-23 题库模块的实现细节。
> 当前实现已演进，最新架构与组件清单详见 [004 架构影响地图](../architecture/004_architecture_impact_map.md) 的 questions 模块章节。
> 保留用于历史参考，不再维护。

---

# 题库模块实现

## 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 校验 Schema
- `types.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 数据流
1. **读取**：`page.tsx`（Server Component）根据 `searchParams` 拉取数据
2. **写入**：客户端组件调用 Server Actions -> `revalidatePath` -> UI 更新
3. **筛选**：用户操作 -> 更新 URL -> 服务端组件重新渲染 -> 返回新数据

### 4.2 类型安全
共享的 `Question` 类型用于保证前后端一致：

```typescript
export interface Question {
  id: string
  content: unknown
  type: QuestionType
  difficulty: number
  // ... 关联字段
}
```

### 4.3 UI/UX 规范
- **空状态**：无数据时展示 `EmptyState`
- **加载态**：表格加载使用 Skeleton
- **反馈**：`Sonner` toast 展示成功/失败提示
- **确认弹窗**：删除等破坏性操作使用 `AlertDialog`

---

## 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 Actions（CRUD）
- `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`：通过

---

## 7. 实现更新（2026-03-03）

### 7.1 登录态与权限校验
- 题库创建/更新/知识点加载统一使用会话身份；缺失会话时回退到首个教师账号以保持演示可用。
- 主要修改：
  - [actions.ts](file:///e:/Desktop/CICD/src/modules/questions/actions.ts)

### 7.2 弹窗稳定性
- Create Question 弹窗在打开时仅在默认知识点变化时更新，避免重复 setState 造成循环更新。
- 主要修改：
  - [create-question-dialog.tsx](file:///e:/Desktop/CICD/src/modules/questions/components/create-question-dialog.tsx)

### 7.3 校验
- `npm run lint`：通过
- `npm run typecheck`：通过
