Files
pj0235-eai_agentplatform/docs/04_Backend/BE02_Exam_Module.md
T
eaiadmin 4e8817d768 init: 数字员工平台初始代码
包含前端(Vue3 + VueFlow 画布)、后端(Go)、文档体系。
- 工作台画布:节点拖放、连线模式、右键菜单、AI 助手
- 后端:连接器 API、专员种子数据
- 导航:左侧导航、工坊、市场、控制台
2026-08-18 20:19:58 +08:00

4.3 KiB
Raw Blame History

BE02 — 考试模块设计

版本:V1.1 | 参考:pj006-zhilianyuan2 exam/routes.py + exam/service.py


1. 模块职责

  • 题库管理(管理员 CRUD)
  • 考试配置/组卷(管理员设置)
  • 学员端考试(开始/答题/交卷/判分)
  • 考试记录与回溯

2. 考试流程

管理员端:
  录入题目 → 配置考试(名称/类型/题量/总分/合格线/时长/随机)
  
员工端:
  考试列表 → 查看封面/说明 → 开始考试 → 答题 → 交卷
                  ↓                        ↓
           自测:即时显示对错+答案    正式考:存档(得分/明细/是否通过)

3. 数据表关系

question(题库)← exam_paper(考试配置,通过 domain+question_count 抽题)
                                                ↓
                                          exam_record(每次交卷的记录)

4. 题库 API

# 管理员 — 题目 CRUD
GET    /api/exam/questions?domain=company&status=active    # 题目列表
POST   /api/exam/questions                                  # 新增题目
PUT    /api/exam/questions/{id}                             # 编辑题目
DELETE /api/exam/questions/{id}                             # 停用题目

# 管理员 — 考试配置
GET    /api/exam/papers                                     # 考试配置列表
POST   /api/exam/papers                                     # 创建考试
PUT    /api/exam/papers/{id}                                # 编辑考试
DELETE /api/exam/papers/{id}                                # 停用考试

5. 学员端考试 API

GET    /api/exam/list                                       # 我的考试列表
GET    /api/exam/cover?id={paperId}                         # 考试封面/说明
POST   /api/exam/start                                      # 开始考试 → 下发题目
POST   /api/exam/submit                                     # 交卷判分
GET    /api/exam/record                                     # 我的考试记录
GET    /api/exam/record/{recordId}                          # 考试记录详情

6. 判分逻辑(参考 zhilianyuan2 _is_correct)

# services/exam_service.py

def _is_correct(qtype: str, correct: list, user: any) -> bool:
    """确定性判分"""
    if qtype == "multiple":           # 多选题:集合相等
        return sorted(correct) == sorted(user) if user else False
    elif qtype == "judge":            # 判断题:值相等
        return str(correct).lower() == str(user).lower()
    else:                              # 单选题:值相等
        return correct == user

def grade_paper(questions: list, answers: dict) -> dict:
    """批卷:逐题比对 → 统计得分/正确数"""
    correct_count = 0
    total = len(questions)
    score_per_question = 100 / total if total else 0
    details = []
    
    for q in questions:
        user_ans = answers.get(str(q["id"]))
        is_correct = _is_correct(q["type"], q["answer"], user_ans)
        if is_correct:
            correct_count += 1
        details.append({
            "question_id": q["id"],
            "is_correct": is_correct,
            "user_answer": user_ans,
            "correct_answer": q["answer"],
        })
    
    score = round(score_per_question * correct_count)
    return {
        "score": score,
        "correct_count": correct_count,
        "wrong_count": total - correct_count,
        "passed": score >= paper.pass_score,
        "details": details,
    }

7. 自测 vs 正式考区别

维度 自测 (self_test) 正式考 (formal)
次数限制 不限 按配置(通常 1 次)
即时反馈 每题显示对错+答案 交卷后显示成绩
成绩存档 不存 永久保存到 exam_record
答题明细 不存 JSON 持久化

8. 考试记录设计

// exam_record.detail_json 示例
{
  "questions": [
    {
      "question_id": 1,
      "stem": "博昇的主营业务包括?",
      "type": "single",
      "user_answer": "D",
      "correct_answer": "D",
      "is_correct": true,
      "explanation": "博昇双主营业务为资本咨询与AI产业落地"
    }
  ],
  "time_spent_sec": 1200
}

9. 权限

  • 员工: 仅查看自己的考试记录
  • 管理员: 查看全部考试记录(/api/system/exam-records)