# 考试工作流-最终版

**版本：** v2.0  
**状态：** ✅ 已完成并验证  
**最后更新：** 2025-10-12

---

## 一、功能概述

### 考试页面
- **URL**：`http://localhost:3001/trainee/exam?courseId=1`
- **流程**：三轮考试（正式考试 + 两次错题重考）
- **试题生成**：动态调用Dify工作流，预计1-3分钟

### 支持的题型
1. 单选题 - 点击立即判断
2. 多选题 - 点击提交判断
3. 判断题 - 点击立即判断
4. 填空题 - AI语义判断
5. 问答题 - AI语义判断

---

## 二、Dify工作流配置

### 工作流1：试题生成器

**API配置：**
```
URL: http://dify.ireborn.com.cn/v1/workflows/run
Token: app-tDlrmXyS9NtWCShsOx5FH49L
User: kaopeilian
Mode: streaming
```

**输入参数：**
```json
{
  "course_id": 1,
  "position_id": 3,
  "single_choice_count": 4,
  "multiple_choice_count": 2,
  "true_false_count": 1,
  "fill_blank_count": 2,
  "essay_count": 1,
  "difficulty_level": 3
}
```

**第二、三轮增加：**
```json
{
  "mistake_records": "[{\"question_id\":null,\"knowledge_point_id\":456,...}]"
}
```

⚠️ **重要**：第一轮不传`mistake_records`参数，第二三轮传入JSON字符串格式

### 工作流2：答案判断器

**API配置：**
```
URL: http://dify.ireborn.com.cn/v1/workflows/run
Token: app-FvMdrvbRBz547DVZEorgO1WT
User: kaopeilian
Mode: streaming
```

**输入参数：**
```json
{
  "question": "题目内容",
  "correct_answer": "正确答案",
  "user_answer": "用户答案",
  "analysis": "答案解析"
}
```

**返回字段：** `result` 或 `is_correct`（值为"正确"/"错误"或true/false）

---

## 三、后端API接口

### 接口列表

| 接口 | 方法 | 功能 |
|------|------|------|
| `/api/v1/exams/generate` | POST | 生成试题 |
| `/api/v1/exams/judge-answer` | POST | 判断主观题答案 |
| `/api/v1/exams/record-mistake` | POST | 记录错题 |
| `/api/v1/exams/mistakes` | GET | 获取错题记录 |

**文件位置：** `kaopeilian-backend/app/api/v1/exam.py`

### 关键实现

**获取岗位ID：**
```python
# 从用户岗位分配信息中自动获取
position_member = await db.execute(
    select(PositionMember).where(
        PositionMember.user_id == current_user.id,
        PositionMember.is_deleted == False
    )
)
position_id = position_member.position_id if position_member else 1
```

**创建Exam记录：**
```python
exam = Exam(
    user_id=current_user.id,
    course_id=request.course_id,
    exam_name=f"课程{request.course_id}考试",
    status="started"
)
await db.commit()
return exam.id  # 使用真实自增ID
```

---

## 四、前端实现要点

### 数据格式转换

**Dify格式 → 前端格式：**
```typescript
{
  type: "single_choice" → "single",
  topic.title → title,
  topic.options → options[],
  correct → correctAnswer,
  analysis → explanation,
  knowledge_point_id → parseInt()
}
```

### 三轮考试流程

```typescript
// 第一轮：不传mistake_records
await generateExam({
  course_id: 1,
  // 不包含 mistake_records
})

// 第二、三轮：传入上一轮错题
const mistakes = await getMistakes(lastExamId)
await generateExam({
  course_id: 1,
  mistake_records: JSON.stringify(mistakes.data.data.mistakes)
})
```

---

## 五、关键配置

### HTTP超时设置

```typescript
// 前端
generateExam: timeout 300000  // 5分钟
judgeAnswer: timeout 60000    // 1分钟

// 后端
httpx.AsyncClient(timeout=300.0)  // 试题生成
httpx.AsyncClient(timeout=60.0)   // 答案判断
```

### 数据库表

**exam_mistakes表：**
- user_id, exam_id（必填）
- question_id, knowledge_point_id（可空）
- question_content, correct_answer, user_answer

---

## 六、重要经验

### FastAPI路由顺序
```python
# ✅ 正确顺序
@router.get("/mistakes")      # 具体路由在前
@router.get("/{exam_id}")     # 动态路由在后
```

### ResponseModel使用
```python
# ✅ 统一使用ResponseModel
@router.get("/mistakes", response_model=ResponseModel[GetMistakesResponse])
async def get_mistakes(...):
    return ResponseModel(code=200, data=GetMistakesResponse(...))
```

### 数据库ID生成
- ❌ 不使用时间戳（13位数字超出INT范围）
- ✅ 使用数据库自增ID

### Axios响应访问
```typescript
// ✅ 正确路径
response.data.code
response.data.data.result
response.data.data.exam_id
```

---

## 七、测试账号

- **用户名：** admin
- **密码：** admin123
- **测试课程：** courseId=1

---

**文档维护：** AI助手  
**最后验证：** 2025-10-12（三轮考试流程验证成功）

