Files
2026-05-12 12:24:11 +08:00

11 KiB
Raw Permalink Blame History

考试模块exam

证据来源:[SRC-FEAT-01] [SRC-FEAT-02] [SRC-SQL-01] [SRC-API-01] [SRC-CODE-01module/exam/]


1. 模块定位

  • 模块目标:管理从出题到考试全链路:题目→试卷→考试→作答记录,支持在线作答、自动判分、成绩排名。
  • 解决问题:替代纸质考试,提升出卷效率(自动组卷),实现客观题自动判分,并对考试行为(时间窗口、次数限制、超时交卷)进行严格管控。

2. 功能清单

[SRC-FEAT-01模块三/四/五] [SRC-API-014.4 在线考试接口]

功能名称 功能描述 输入 输出 依赖模块
题目分类管理 按分类管理题目,多级目录,按部门隔离 QuestionCategoryDTO QuestionCategoryVO system
题目 CRUD 创建/修改/删除题目,支持单选/多选/判断三种题型,必须填写解析 QuestionDTOtype, content, options, answer, analysis QuestionVO -
题目状态管理 草稿→发布→下架,下架前检查引用 questionId, action - -
手动组卷 讲师从题库手动选题,配置每题分值 PaperDTOtitle, questions[] PaperVO -
自动组卷 按规则单选X题+多选Y题+判断Z题随机抽题 AutoPaperDTO规则配置 PaperVO -
试卷配置 设置总分、各题分值、考试时长、及格分 PaperDTO PaperVO -
试卷预览 组卷后预览试卷效果(随机题目顺序) paperId 完整试卷预览 -
试卷状态管理 草稿→发布→下架 paperId, action - -
创建考试 选择试卷,设置考试名称、时间窗口、最大次数 ExamQueryDTO + ExamTarget ExamVO -
指定考试对象 指定部门/小组/个人参加考试 exam_id, target_type, target_id[] - system
发布考试 将考试状态从 NOT_STARTED 转为 IN_PROGRESS时间到自动 examId - -
学员-我的考试列表 查询分配给当前学员的考试(在时间窗口内) - PageResult<ExamVO + 我的记录> auth
学员-开始考试 校验资格,创建 exam_record返回试题 examId 试题 + 时长 + recordId -
学员-断点续考 恢复进行中的考试记录,返回已保存答案 examId 试题 + 已保存答案 + 剩余时间 -
学员-保存答案 每30秒自动保存答案增量保存 recordId, answers(JSON) - -
学员-提交试卷 自动判分,保存成绩,返回排名+解析 recordId, answers(JSON) 成绩 + 排名 + 答案解析 -
超时自动交卷 定时任务每分钟扫描超时记录,系统代提交 @Scheduled - -
查看考试结果 查看某次考试的详细成绩和答案解析 recordId ExamResultVO -
成绩/排名查询 讲师查看某考试的所有学员成绩 examId PageResult<成绩列表> -

3. 核心逻辑

3.1 业务规则

[SRC-FEAT-014.3 考试规则] [SRC-API-015.2/5.3]

题型规则

  • 单选题SINGLE=0options 为 JSON 数组answer 为单字母A/B/C/D
  • 多选题MULTIPLE=1answer 为多字母组合(如"AB"/"BCD"),按字母排序存储
  • 判断题JUDGE=2options 为空answer 为"T"(正确)或"F"(错误)
  • 每道题必须填写 analysis(答案解析),否则不允许发布

考试时间窗口

  • 只有在 exam.start_time ≤ NOW() ≤ exam.end_time 时,学员才能进入考试
  • 考试到期后,exam.status 自动(或手动)变为 ENDED

次数限制

  • 达到 max_attempts 后,学员不可再次开始考试
  • 历史成绩取最高分作为最终成绩
  • 每次考试创建 exam_record.attempt_no = 历史次数 + 1

自动判分规则

  • 仅客观题(单选/多选/判断)自动判分
  • 单选/判断:答案完全匹配得满分
  • 多选:全部选项匹配(顺序无关)得满分;部分正确得 0 分V1 不分项给分)
  • 总分 = 各题得分之和

超时自动交卷

  • @Scheduled(cron="0 */1 * * * ?") 每分钟扫描
  • 查询:ex_exam_record.status=IN_PROGRESSstart_time + paper.duration 分钟 < NOW()
  • 使用乐观锁(version 字段)防止与用户主动交卷并发冲突 [SRC-API-015.2]

排名计算

  • 计算时机:用户交卷后立即计算本次提交对应的排名
  • 统计范围:同一 exam_id 下,所有 status=SUBMITTED 记录,取每用户最高分
  • 排名规则:DENSE_RANK() OVER (ORDER BY MAX(score) DESC, MIN(submit_time) ASC)(同分按提交时间早排前)[SRC-API-015.3]

题目顺序

  • 自动组卷时,返回给学员的题目顺序随机打乱(前端处理或后端随机返回)

3.2 校验逻辑

校验项 规则 失败响应
题目 analysis 必填 发布时 analysis 不可为空 400请填写答案解析后再发布
开始考试-时间窗口 NOW() 在 [start_time, end_time] 范围内 400考试尚未开始 / 考试已结束
开始考试-次数限制 已有考试记录数 < max_attempts 400已达到最大考试次数
开始考试-状态 exam.status = IN_PROGRESS1 400状态不符
开始考试-进行中记录 若已有 IN_PROGRESS 记录,返回续考而非新建 自动转入断点续考流程
答案格式 多选题答案字母需排序后匹配 自动处理,不返回错误
超时交卷并发 乐观锁冲突时(用户已提交),忽略定时任务提交 静默忽略 OptimisticLockException
试卷引用保护 已被考试引用的试卷下架前需确认警告 400 + 警告 + 引用考试数量
题目引用保护 已被试卷引用的题目下架前需确认警告 400 + 警告 + 引用试卷数量

3.3 状态流转

内容状态(题目/试卷)

stateDiagram-v2
    [*] --> DRAFT : 创建
    DRAFT --> PUBLISHED : 发布(题目需有 analysis
    PUBLISHED --> OFFLINE : 下架(引用保护确认)
    OFFLINE --> PUBLISHED : 重新上架
    DRAFT --> [*] : 逻辑删除

考试状态

stateDiagram-v2
    [*] --> NOT_STARTED : 创建考试start_time 未到)
    NOT_STARTED --> IN_PROGRESS : 到达 start_time自动或手动
    IN_PROGRESS --> ENDED : 到达 end_time自动或手动结束
    ENDED --> [*] : 逻辑删除

考试记录状态

stateDiagram-v2
    [*] --> IN_PROGRESS : 学员点击"开始考试"创建记录
    IN_PROGRESS --> SUBMITTED : 学员交卷submit_source=USER
    IN_PROGRESS --> SUBMITTED : 定时任务超时submit_source=SYSTEM_TIMEOUT
    SUBMITTED --> [*] : 永久保留

4. 数据结构

[SRC-SQL-01三、考试模块]

4.1 涉及数据表7张

ex_question_category:题目分类(同知识库分类结构,按 department_id 隔离)

ex_question

字段 类型 说明
id BIGINT 主键
type TINYINT 0-单选 / 1-多选 / 2-判断
content TEXT NOT NULL 题干
options JSON 选项数组(判断题为 NULL
answer VARCHAR(50) NOT NULL 正确答案(单选/判断单字母,多选合并字母)
analysis TEXT 答案解析(发布前必填)
category_id BIGINT 所属分类
department_id BIGINT NOT NULL 部门隔离键
status TINYINT 0-草稿 / 1-发布 / 2-下架
creator_id BIGINT NOT NULL 创建人

ex_paper

字段 类型 说明
id BIGINT 主键
title VARCHAR(200) NOT NULL 试卷标题
total_score INT DEFAULT 100 总分
duration INT DEFAULT 60 考试时长(分钟)
pass_score INT DEFAULT 60 及格分
department_id BIGINT NOT NULL 部门隔离键
status TINYINT 0-草稿 / 1-发布 / 2-下架

ex_paper_question

字段 类型 说明
paper_id BIGINT NOT NULL 试卷ID
question_id BIGINT NOT NULL 题目ID
score INT DEFAULT 5 该题分值
sort_order INT 排序(大题号顺序)

ex_exam

字段 类型 说明
id BIGINT 主键
title VARCHAR(200) NOT NULL 考试标题
paper_id BIGINT NOT NULL 关联试卷
start_time / end_time DATETIME 时间窗口
max_attempts INT DEFAULT 1 最大考试次数
department_id BIGINT NOT NULL 部门隔离键
status TINYINT 0-未开始 / 1-进行中 / 2-已结束

ex_exam_target

字段 类型 说明
exam_id BIGINT NOT NULL 考试ID
target_type TINYINT 0-部门 / 1-小组 / 2-个人
target_id BIGINT NOT NULL 对应 dept/group/user 的ID

ex_exam_record(含 V1.0.1 扩展字段)

字段 类型 说明
id BIGINT 主键
exam_id BIGINT NOT NULL 考试ID
user_id BIGINT NOT NULL 学员ID
attempt_no INT NOT NULL 第几次考试
score INT 得分
passed TINYINT 0-未通过 / 1-通过
start_time DATETIME NOT NULL 开始时间
submit_time DATETIME 提交时间
answers JSON 答题详情
status VARCHAR(20) IN_PROGRESS / SUBMITTED
last_save_time DATETIME 最后保存时间
version INT DEFAULT 0 乐观锁版本号
submit_source VARCHAR(20) USER / SYSTEM_TIMEOUT

4.2 数据关联

  • ex_paper_question.paper_idex_paper.id
  • ex_paper_question.question_idex_question.id
  • ex_exam.paper_idex_paper.id
  • ex_exam_target 多态关联target_type=0 → sys_department.id=1 → sys_group.id=2 → sys_user.id
  • ex_exam_record.exam_idex_exam.iduser_idsys_user.id

5. 对外接口

[SRC-API-014.4]

API 名称 方法 路径 权限
题目分类 CRUD GET/POST/PUT/DELETE /api/exam/question-category/** LECTURER/ADMIN
题目 CRUD GET/POST/PUT/DELETE /api/exam/question/** LECTURER/ADMIN
试卷 CRUD + 自动组卷 GET/POST/PUT/DELETE /api/exam/paper/** + /api/exam/paper/auto LECTURER/ADMIN
考试 CRUD GET/POST/PUT/DELETE /api/exam/** LECTURER/ADMIN
我的考试列表 GET /api/student/exam STUDENT
考试详情 GET /api/student/exam/{id} STUDENT
开始考试 POST /api/student/exam/{id}/start STUDENT
断点续考 GET /api/student/exam/{id}/continue STUDENT
保存答案 POST /api/student/exam/{id}/save STUDENT
提交试卷 POST /api/student/exam/{id}/submit STUDENT
查看考试结果 GET /api/student/exam/record/{recordId} STUDENT

6. 异常与边界处理

场景 处理方式
学员在时间窗口外访问考试 400 + 明确提示是"未开始"还是"已结束"
次数用完后再次开始 400已达最大考试次数如有异议请联系讲师
交卷时 exam_record 已是 SUBMITTED并发/重复提交) 乐观锁冲突或状态判断,幂等返回已有成绩,不重复判分
定时任务超时提交时用户同时提交 乐观锁 version 冲突,定时任务忽略,用户提交成功
试卷总分与题目分值之和不一致 [ASSUMPTION] PRD 未明确,建议前端组卷时实时计算并提示差额
自动组卷时题库数量不足 400题库中相应题型数量不足请手动添加题目或降低要求
学员中途关闭浏览器 answers 按最后一次 save 记录恢复,重新进入走断点续考流程