total_questions(用于验证「智能补充」生效)接口:POST /api/intelligent-exams
请求体(JSON)- 以七年级下册为例:
{
"student_id": "1764913638",
"teacher_id": "1764913637",
"student_name": "张三",
"teacher_name": "李老师",
"grade": 7,
"assemble_type": 3,
"series_id": 1,
"semester_code": 2,
"chapter_id_list": [244, 248],
"total_questions": 20,
"difficulty_category": 1,
"paper_name": "七年级下册第1-2章测试"
}
说明:
semester_code: 2表示下学期;chapter_id_list: [244, 248]为教材textbook_id=2(七年级下册)的前 2 个章节节点 ID。
参数说明:
| 参数 | 必填 | 说明 |
|---|---|---|
| student_id | 是 | 学生ID |
| teacher_id | 是 | 教师ID |
| student_name | 是 | 学生姓名 |
| teacher_name | 是 | 教师姓名 |
| grade | 是 | 年级(如 7=初一) |
| assemble_type | 否 | 3=教材组卷,默认为 4(通用) |
| series_id | 教材组卷必填 | 教材系列ID |
| semester_code | 教材组卷必填 | 1=上册,2=下册(当前学期示例用 2) |
| chapter_id_list | 教材组卷推荐 | 章节节点ID 列表;不传则自动选该教材下有题目的章节 |
| total_questions | 否 | 题目数量,默认 20 |
| difficulty_category | 否 | 难度类别 1-4 |
| paper_name | 否 | 试卷名称 |
说明:API 通过 series_id + semester_code + grade 解析出 textbook_id。内部调用(如 Filament 页面)可直接传 textbook_id。
getSupplementaryQuestionsForGrade、排除学生已做过的题目、限制为前章节 等字样POST /api/intelligent-exams
→ IntelligentExamController::store()
→ 校验参数,resolveTextbookId(若用 series_id)
→ $params 传入 LearningAnalyticsService::generateIntelligentExam()
generateIntelligentExam($params)
→ $params['assemble_type'] = 3(教材组卷)
→ ExamTypeStrategy::buildParams($params, 3)
→ buildTextbookAssembleParams($params)
buildTextbookAssembleParams 主要逻辑:
chapter_id_list,若无则从教材下自动选有题目的章节kp_codes(知识点)getStudentAnsweredQuestionIds($studentId, $kpCodes)paper_questions 查学生试卷question_bank_id(对应 questions.id)exclude_question_ids 写入 paramsgrade 缺失,从 textbooks 表按 textbook_id 推断kp_codes、textbook_catalog_node_ids、exclude_question_ids、grade、textbook_idgenerateIntelligentExam 继续
→ 获取 kp_codes、exclude_question_ids 等
→ 若有错题优先获取错题
→ getQuestionsFromBank($kpCodes, ..., $excludeQuestionIds, $textbookCatalogNodeIds, $grade, $textbookId, ...)
主查询
kp_codes、grade、难度等筛选whereNotIn('id', $excludeQuestionIds),排除已做题目textbook_catalog_node_ids,再按章节节点筛选检查题目是否足够
count($selectedQuestions) < $totalNeeded 且 $grade !== null智能补充
getSupplementaryQuestionsForGrade(
$grade,
array_column($selectedQuestions, 'kp_code'), // 排除已选知识点
$deficit,
$difficultyCategory,
$textbookId,
$excludeQuestionIds, // ← 排除已做题目
$textbookCatalogNodeIds // ← 用于前章节限制
)
排除已做题目
if (!empty($excludeQuestionIds)) {
$query->whereNotIn('id', $excludeQuestionIds);
}
同年级同教材
getGradeKnowledgePoints($grade, $textbookId) 获取该教材知识点whereIn('kp_code', $gradeKpCodes)仅从前章节补充(未学章节不补)
$textbookId 和 $textbookCatalogNodeIdsgetEarlierChapterNodeIds($textbookId, $textbookCatalogNodeIds)max(sort_order),得到「前章节」节点 IDwhereIn('textbook_catalog_nodes_id', $allowedNodeIds)按难度、题型等筛选后返回补充题目
getQuestionsFromBank 返回
→ selectQuestionsByMastery():按掌握度、题型配比筛选
→ applyTypeAwareDifficultyDistribution():题型感知难度分布
→ 返回最终题目列表
| 能力 | 生效位置 | 实现方式 |
|---|---|---|
| 排除已做题目 | getStudentAnsweredQuestionIds |
从 paper_questions 取 question_bank_id,写入 exclude_question_ids |
| 主选题排除 | getQuestionsFromBank 主查询 |
whereNotIn('id', $excludeQuestionIds) |
| 补充时排除 | getSupplementaryQuestionsForGrade |
传入 excludeQuestionIds,whereNotIn('id', $excludeQuestionIds) |
| grade 推断 | buildTextbookAssembleParams |
无 grade 时从 textbooks 按 textbook_id 查 grade |
| 前章节限制 | getEarlierChapterNodeIds |
按 max(sort_order) 取前章节节点,whereIn('textbook_catalog_nodes_id', ...) |
在 storage/logs/laravel.log 中可看到类似日志:
ExamTypeStrategy: 教材组卷从教材推断 grade
ExamTypeStrategy: 获取学生已答题目 ... answered_count: N
getQuestionsFromBank: 指定知识点题目不足,尝试智能补充
getSupplementaryQuestionsForGrade: 开始智能补充 ... exclude_count: N, has_chapter_scope: true
getSupplementaryQuestionsForGrade: 应用排除筛选 (或 排除学生已做过的题目)
getSupplementaryQuestionsForGrade: 限制为前章节 ... allowed_node_count: M
getQuestionsFromBank: 智能补充完成 ... supplementary_count: K
paper_questions 中该学生的 question_bank_id,与本次组卷题目 ID,应无交集。textbook_catalog_nodes_id,其 sort_order 应 ≤ 选中章节的最大 sort_order。curl -X POST 'http://localhost/api/intelligent-exams' \
-H 'Content-Type: application/json' \
-d '{
"student_id": "1764913638",
"teacher_id": "1764913637",
"student_name": "张三",
"teacher_name": "李老师",
"grade": 7,
"assemble_type": 3,
"series_id": 1,
"semester_code": 2,
"chapter_id_list": [244, 248],
"total_questions": 20,
"paper_name": "七年级下册教材组卷验证测试"
}'
将 student_id、teacher_id 替换为环境中的真实数据。series_id=1, semester_code=2, grade=7 对应 七年级下册(textbook_id=2)。