|
|
@@ -30,7 +30,12 @@ class ExamTypeStrategy
|
|
|
|
|
|
/**
|
|
|
* 根据组卷类型构建参数
|
|
|
- * assembleType: 0-新摸底, 8-智能组卷, 2-知识点组卷, 3-教材组卷, 4-通用, 5-错题本, 9-原摸底
|
|
|
+ * assembleType: 0-章节摸底, 1-智能组卷, 2-知识点组卷, 3-教材组卷, 4-通用, 5-错题本, 8-智能组卷(新), 9-原摸底
|
|
|
+ *
|
|
|
+ * 映射规则(前端不改,后端动态处理):
|
|
|
+ * - 0, 9(摸底)→ 章节摸底(新逻辑)
|
|
|
+ * - 1, 8(智能组卷)→ 按知识点顺序学习(新逻辑)
|
|
|
+ * - 2, 3, 4, 5 → 保持原有逻辑不变
|
|
|
*/
|
|
|
public function buildParams(array $baseParams, int $assembleType): array
|
|
|
{
|
|
|
@@ -39,15 +44,25 @@ class ExamTypeStrategy
|
|
|
'base_params_keys' => array_keys($baseParams)
|
|
|
]);
|
|
|
|
|
|
- return match($assembleType) {
|
|
|
- 0 => $this->applyDifficultyDistribution($this->buildInitialDiagnosticParams($baseParams)), // 新摸底
|
|
|
- 1 => $this->applyDifficultyDistribution($this->buildIntelligentAssembleParams($baseParams)), // 智能组卷(旧参数兼容)
|
|
|
- 2 => $this->applyDifficultyDistribution($this->buildKnowledgePointAssembleParams($baseParams)), // 知识点组卷
|
|
|
- 3 => $this->applyDifficultyDistribution($this->buildTextbookAssembleParams($baseParams)), // 教材组卷
|
|
|
- 4 => $this->applyDifficultyDistribution($this->buildGeneralParams($baseParams)), // 通用
|
|
|
- 5 => $this->applyDifficultyDistribution($this->buildMistakeParams($baseParams)), // 追练
|
|
|
- 8 => $this->applyDifficultyDistribution($this->buildIntelligentAssembleParams($baseParams)), // 智能组卷
|
|
|
- 9 => $this->applyDifficultyDistribution($this->buildDiagnosticParams($baseParams)), // 原摸底
|
|
|
+ // 映射 assembleType 到实际处理逻辑
|
|
|
+ $actualType = match($assembleType) {
|
|
|
+ 0, 9 => 'chapter_diagnostic', // 摸底 → 章节摸底(新逻辑)
|
|
|
+ 1, 8 => 'chapter_intelligent', // 智能组卷 → 按知识点顺序学习(新逻辑)
|
|
|
+ default => $assembleType // 其他保持不变
|
|
|
+ };
|
|
|
+
|
|
|
+ Log::info('ExamTypeStrategy: assembleType 映射', [
|
|
|
+ 'original' => $assembleType,
|
|
|
+ 'actual' => $actualType,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return match($actualType) {
|
|
|
+ 'chapter_diagnostic' => $this->applyDifficultyDistribution($this->buildChapterDiagnosticParams($baseParams)), // 章节摸底(新)
|
|
|
+ 'chapter_intelligent' => $this->applyDifficultyDistribution($this->buildChapterIntelligentParams($baseParams)), // 按知识点顺序学习(新)
|
|
|
+ 2 => $this->applyDifficultyDistribution($this->buildKnowledgePointAssembleParams($baseParams)), // 知识点组卷(不动)
|
|
|
+ 3 => $this->applyDifficultyDistribution($this->buildTextbookAssembleParams($baseParams)), // 教材组卷(不动)
|
|
|
+ 4 => $this->applyDifficultyDistribution($this->buildGeneralParams($baseParams)), // 通用(不动)
|
|
|
+ 5 => $this->applyDifficultyDistribution($this->buildMistakeParams($baseParams)), // 追练(不动)
|
|
|
default => $this->applyDifficultyDistribution($this->buildGeneralParams($baseParams))
|
|
|
};
|
|
|
}
|
|
|
@@ -1677,4 +1692,187 @@ class ExamTypeStrategy
|
|
|
return [];
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ // ========== 以下是新增的章节摸底和智能组卷方法 ==========
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 章节摸底(新逻辑)
|
|
|
+ * - 找第一个未摸底的章节
|
|
|
+ * - 用该章节的知识点出题(不扩展子知识点)
|
|
|
+ * - 过滤掉没有题目的知识点
|
|
|
+ * - 保存时记录 diagnostic_chapter_id
|
|
|
+ */
|
|
|
+ private function buildChapterDiagnosticParams(array $params): array
|
|
|
+ {
|
|
|
+ $diagnosticService = app(DiagnosticChapterService::class);
|
|
|
+ $textbookId = $params['textbook_id'] ?? null;
|
|
|
+ $studentId = (int) ($params['student_id'] ?? 0);
|
|
|
+ $grade = $params['grade'] ?? null;
|
|
|
+ $totalQuestions = $params['total_questions'] ?? 20;
|
|
|
+
|
|
|
+ Log::info('ExamTypeStrategy: 构建章节摸底参数', [
|
|
|
+ 'textbook_id' => $textbookId,
|
|
|
+ 'student_id' => $studentId,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ if (!$textbookId) {
|
|
|
+ Log::warning('ExamTypeStrategy: 章节摸底需要 textbook_id 参数');
|
|
|
+ return $this->buildGeneralParams($params);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 找第一个未摸底的章节
|
|
|
+ $chapterInfo = $diagnosticService->getFirstUndiagnosedChapter((int) $textbookId, $studentId);
|
|
|
+
|
|
|
+ if (empty($chapterInfo) || empty($chapterInfo['kp_codes'])) {
|
|
|
+ Log::warning('ExamTypeStrategy: 章节摸底未找到有效章节', [
|
|
|
+ 'textbook_id' => $textbookId,
|
|
|
+ 'student_id' => $studentId,
|
|
|
+ ]);
|
|
|
+ return $this->buildGeneralParams($params);
|
|
|
+ }
|
|
|
+
|
|
|
+ Log::info('ExamTypeStrategy: 章节摸底参数构建完成', [
|
|
|
+ 'textbook_id' => $textbookId,
|
|
|
+ 'chapter_id' => $chapterInfo['chapter_id'],
|
|
|
+ 'chapter_name' => $chapterInfo['chapter_name'] ?? '',
|
|
|
+ 'section_count' => count($chapterInfo['section_ids'] ?? []),
|
|
|
+ 'kp_count' => count($chapterInfo['kp_codes']),
|
|
|
+ 'total_questions' => $totalQuestions,
|
|
|
+ 'is_restart' => $chapterInfo['is_restart'] ?? false,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ $enhanced = array_merge($params, [
|
|
|
+ 'kp_code_list' => $chapterInfo['kp_codes'],
|
|
|
+ 'chapter_id_list' => $chapterInfo['section_ids'],
|
|
|
+ 'diagnostic_chapter_id' => $chapterInfo['chapter_id'], // 记录摸底的章节ID
|
|
|
+ 'textbook_id' => $textbookId,
|
|
|
+ 'grade' => $grade,
|
|
|
+ 'paper_name' => $params['paper_name'] ?? ('章节摸底_' . ($chapterInfo['chapter_name'] ?? '') . '_' . now()->format('Ymd_His')),
|
|
|
+ 'assembleType' => 0, // 确保 paper_type 记录为摸底
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return $this->buildKnowledgePointAssembleParams($enhanced);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 按知识点顺序学习(新逻辑)
|
|
|
+ * - 找当前应该学习的章节(有未达标知识点的章节)
|
|
|
+ * - 如果该章节未摸底,返回摸底参数
|
|
|
+ * - 按顺序找未达标的知识点,最多2个
|
|
|
+ * - 如果都达标,进入下一章摸底
|
|
|
+ */
|
|
|
+ private function buildChapterIntelligentParams(array $params): array
|
|
|
+ {
|
|
|
+ $diagnosticService = app(DiagnosticChapterService::class);
|
|
|
+ $textbookId = $params['textbook_id'] ?? null;
|
|
|
+ $studentId = (int) ($params['student_id'] ?? 0);
|
|
|
+ $grade = $params['grade'] ?? null;
|
|
|
+ $totalQuestions = $params['total_questions'] ?? 20;
|
|
|
+
|
|
|
+ Log::info('ExamTypeStrategy: 构建按知识点顺序学习参数', [
|
|
|
+ 'textbook_id' => $textbookId,
|
|
|
+ 'student_id' => $studentId,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ if (!$textbookId) {
|
|
|
+ Log::warning('ExamTypeStrategy: 智能组卷需要 textbook_id 参数');
|
|
|
+ return $this->buildGeneralParams($params);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取当前应该学习的章节
|
|
|
+ $chapterInfo = $diagnosticService->getCurrentLearningChapter((int) $textbookId, $studentId, 0.9);
|
|
|
+
|
|
|
+ // 情况1: 所有章节都达标,从第一章重新开始摸底
|
|
|
+ if (empty($chapterInfo)) {
|
|
|
+ Log::info('ExamTypeStrategy: 所有章节都达标,从第一章重新开始摸底');
|
|
|
+ return $this->buildChapterDiagnosticParams($params);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 情况2: 当前章节未摸底,需要先摸底
|
|
|
+ if (!($chapterInfo['has_diagnostic'] ?? false)) {
|
|
|
+ Log::info('ExamTypeStrategy: 当前章节未摸底,先进行摸底', [
|
|
|
+ 'chapter_id' => $chapterInfo['chapter_id'],
|
|
|
+ ]);
|
|
|
+ return $this->buildChapterDiagnosticParams($params);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 情况3: 已摸底,按顺序找未达标的知识点
|
|
|
+ $unmasteredKpCodes = $diagnosticService->getUnmasteredKpCodesInOrder(
|
|
|
+ $studentId,
|
|
|
+ $chapterInfo['kp_codes'],
|
|
|
+ 0.9, // 阈值
|
|
|
+ 2, // 最多2个知识点
|
|
|
+ $totalQuestions
|
|
|
+ );
|
|
|
+
|
|
|
+ // 情况4: 当前章节所有知识点都达标,进入下一章摸底
|
|
|
+ if (empty($unmasteredKpCodes)) {
|
|
|
+ Log::info('ExamTypeStrategy: 当前章节所有知识点都达标,进入下一章', [
|
|
|
+ 'current_chapter_id' => $chapterInfo['chapter_id'],
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // 获取下一章
|
|
|
+ $nextChapter = $diagnosticService->getNextChapter((int) $textbookId, $chapterInfo['chapter_id']);
|
|
|
+
|
|
|
+ if ($nextChapter) {
|
|
|
+ // 检查下一章是否已摸底
|
|
|
+ $hasNextDiagnostic = $diagnosticService->hasChapterDiagnostic($studentId, $nextChapter['chapter_id']);
|
|
|
+
|
|
|
+ if (!$hasNextDiagnostic) {
|
|
|
+ Log::info('ExamTypeStrategy: 下一章未摸底,进行摸底', [
|
|
|
+ 'next_chapter_id' => $nextChapter['chapter_id'],
|
|
|
+ ]);
|
|
|
+ // 直接设置下一章的参数,不递归调用
|
|
|
+ $enhanced = array_merge($params, [
|
|
|
+ 'kp_code_list' => $nextChapter['kp_codes'],
|
|
|
+ 'chapter_id_list' => $nextChapter['section_ids'],
|
|
|
+ 'diagnostic_chapter_id' => $nextChapter['chapter_id'],
|
|
|
+ 'textbook_id' => $textbookId,
|
|
|
+ 'grade' => $grade,
|
|
|
+ 'paper_name' => $params['paper_name'] ?? ('章节摸底_' . ($nextChapter['chapter_name'] ?? '') . '_' . now()->format('Ymd_His')),
|
|
|
+ 'assembleType' => 0,
|
|
|
+ ]);
|
|
|
+ return $this->buildKnowledgePointAssembleParams($enhanced);
|
|
|
+ } else {
|
|
|
+ // 下一章已摸底,找下一章的未达标知识点
|
|
|
+ $nextUnmasteredKpCodes = $diagnosticService->getUnmasteredKpCodesInOrder(
|
|
|
+ $studentId,
|
|
|
+ $nextChapter['kp_codes'],
|
|
|
+ 0.9,
|
|
|
+ 2,
|
|
|
+ $totalQuestions
|
|
|
+ );
|
|
|
+
|
|
|
+ if (!empty($nextUnmasteredKpCodes)) {
|
|
|
+ $unmasteredKpCodes = $nextUnmasteredKpCodes;
|
|
|
+ $chapterInfo = $nextChapter;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果没有下一章或下一章也都达标,从头开始
|
|
|
+ if (empty($unmasteredKpCodes)) {
|
|
|
+ Log::info('ExamTypeStrategy: 所有章节都学完,从第一章重新开始');
|
|
|
+ return $this->buildChapterDiagnosticParams($params);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Log::info('ExamTypeStrategy: 按知识点顺序学习参数构建完成', [
|
|
|
+ 'textbook_id' => $textbookId,
|
|
|
+ 'chapter_id' => $chapterInfo['chapter_id'],
|
|
|
+ 'kp_codes' => $unmasteredKpCodes,
|
|
|
+ 'kp_count' => count($unmasteredKpCodes),
|
|
|
+ 'total_questions' => $totalQuestions,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ $enhanced = array_merge($params, [
|
|
|
+ 'kp_code_list' => $unmasteredKpCodes,
|
|
|
+ 'textbook_id' => $textbookId,
|
|
|
+ 'grade' => $grade,
|
|
|
+ 'paper_name' => $params['paper_name'] ?? ('智能学习_' . now()->format('Ymd_His')),
|
|
|
+ 'assembleType' => 1, // paper_type 记录为智能组卷
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return $this->buildKnowledgePointAssembleParams($enhanced);
|
|
|
+ }
|
|
|
}
|