yemeishu пре 1 недеља
родитељ
комит
cfebf52cce
2 измењених фајлова са 107 додато и 4 уклоњено
  1. 97 2
      app/Services/ExamTypeStrategy.php
  2. 10 2
      app/Services/LearningAnalyticsService.php

+ 97 - 2
app/Services/ExamTypeStrategy.php

@@ -374,8 +374,24 @@ class ExamTypeStrategy
             'question_ids' => array_slice($paperQuestionIds, 0, 10) // 只记录前10个
         ]);
 
-        // 获取卷子题目知识点(直接从 paper_questions.knowledge_point)
-        $paperKnowledgePoints = $this->getKnowledgePointsFromPaperQuestions($paperIds);
+        // 优先从错题记录获取知识点;若无错题则回退到卷子题目知识点
+        $paperKnowledgePoints = $this->getMistakeKnowledgePointsFromPapers($studentId, $paperIds);
+        $useMistakeKnowledgePoints = ! empty($paperKnowledgePoints);
+        if (! $useMistakeKnowledgePoints) {
+            // 获取卷子题目知识点(直接从 paper_questions.knowledge_point)
+            $paperKnowledgePoints = $this->getKnowledgePointsFromPaperQuestions($paperIds);
+        }
+
+        // 排除错题本已有题目,避免重复出现
+        $excludeQuestionIds = $this->getMistakeQuestionIdsFromPapers($studentId, $paperIds);
+
+        Log::info('ExamTypeStrategy: 追练知识点来源', [
+            'student_id' => $studentId,
+            'paper_ids' => $paperIds,
+            'use_mistake_kp' => $useMistakeKnowledgePoints,
+            'kp_count' => count($paperKnowledgePoints),
+            'exclude_count' => count($excludeQuestionIds),
+        ]);
 
         if (empty($paperKnowledgePoints)) {
             Log::warning('ExamTypeStrategy: 卷子题目未找到知识点,无法生成错题本', [
@@ -416,6 +432,8 @@ class ExamTypeStrategy
             'difficulty_category' => $difficultyCategory,
             'is_mistake_exam' => true,
             'is_paper_based_mistake' => true, // 标记是基于卷子的错题本
+            'mistake_kp_source' => $useMistakeKnowledgePoints,
+            'exclude_question_ids' => $excludeQuestionIds,
             'source_paper_question_count' => $questionCount,
             'knowledge_points_count' => count($paperKnowledgePoints),
             'max_questions_limit' => $maxQuestions,
@@ -441,6 +459,83 @@ class ExamTypeStrategy
         return $this->buildKnowledgePointAssembleParams($enhanced);
     }
 
+    /**
+     * 从错题记录中获取知识点列表(按学生+卷子)
+     */
+    private function getMistakeKnowledgePointsFromPapers(?string $studentId, array $paperIds): array
+    {
+        if (empty($studentId) || empty($paperIds)) {
+            return [];
+        }
+
+        try {
+            $records = \App\Models\MistakeRecord::query()
+                ->where('student_id', $studentId)
+                ->whereIn('paper_id', $paperIds)
+                ->get(['kp_ids']);
+
+            $kpCodes = [];
+            foreach ($records as $record) {
+                $kpIds = $record->kp_ids;
+                if (empty($kpIds)) {
+                    continue;
+                }
+
+                if (is_string($kpIds)) {
+                    $decoded = json_decode($kpIds, true);
+                    if (is_array($decoded)) {
+                        $kpIds = $decoded;
+                    }
+                }
+
+                if (is_array($kpIds)) {
+                    foreach ($kpIds as $kpId) {
+                        if (! empty($kpId)) {
+                            $kpCodes[$kpId] = true;
+                        }
+                    }
+                }
+            }
+
+            return array_values(array_keys($kpCodes));
+        } catch (\Exception $e) {
+            Log::warning('ExamTypeStrategy: 获取错题知识点失败,回退旧逻辑', [
+                'student_id' => $studentId,
+                'paper_ids' => $paperIds,
+                'error' => $e->getMessage(),
+            ]);
+            return [];
+        }
+    }
+
+    /**
+     * 从错题记录中获取题目ID列表(用于排除已出现的错题)
+     */
+    private function getMistakeQuestionIdsFromPapers(?string $studentId, array $paperIds): array
+    {
+        if (empty($studentId) || empty($paperIds)) {
+            return [];
+        }
+
+        try {
+            return \App\Models\MistakeRecord::query()
+                ->where('student_id', $studentId)
+                ->whereIn('paper_id', $paperIds)
+                ->pluck('question_id')
+                ->filter()
+                ->unique()
+                ->values()
+                ->toArray();
+        } catch (\Exception $e) {
+            Log::warning('ExamTypeStrategy: 获取错题题目ID失败,忽略排除', [
+                'student_id' => $studentId,
+                'paper_ids' => $paperIds,
+                'error' => $e->getMessage(),
+            ]);
+            return [];
+        }
+    }
+
     /**
      * 专项练习:针对特定技能或知识点练习
      */

+ 10 - 2
app/Services/LearningAnalyticsService.php

@@ -1386,15 +1386,17 @@ class LearningAnalyticsService
 
             // 【修改】错题本类型严格按错题组卷,不补充题目
             if ($isMistakeBook) {
+                $mistakeKpSource = (bool) ($params['mistake_kp_source'] ?? false);
                 // 记录错题本组卷信息
                 Log::info('LearningAnalyticsService: 错题本严格按错题组卷,不补充题目', [
                     'mistake_count' => count($priorityQuestions),
                     'assemble_type' => $assembleType,
+                    'mistake_kp_source' => $mistakeKpSource,
                     'action' => '只使用学生错题,不从原卷子补充'
                 ]);
 
                 // 如果完全没有错题,回退到知识点/题库组卷
-                if (!$hasMistakePriority) {
+                if (!$hasMistakePriority && !$mistakeKpSource) {
                     Log::warning('LearningAnalyticsService: 错题本无错题', [
                         'student_id' => $studentId,
                         'paper_ids' => $params['paper_ids'] ?? []
@@ -1403,6 +1405,11 @@ class LearningAnalyticsService
                         'assemble_type' => $assembleType,
                         'action' => 'fallback_to_kp_or_bank'
                     ]);
+                } elseif (!$hasMistakePriority && $mistakeKpSource) {
+                    Log::info('LearningAnalyticsService: 错题本使用错题知识点组卷', [
+                        'assemble_type' => $assembleType,
+                        'action' => 'use_mistake_kp_codes'
+                    ]);
                 }
             }
 
@@ -1437,6 +1444,7 @@ class LearningAnalyticsService
                     ]);
 
                     // 【修复超纲问题】传入 grade 和 textbook_id,用于智能补充时限制范围
+                    $excludeQuestionIds = $params['exclude_question_ids'] ?? [];
                     $additionalQuestions = $this->getQuestionsFromBank(
                         $kpCodes,
                         $skills,
@@ -1444,7 +1452,7 @@ class LearningAnalyticsService
                         $questionTypeRatio,
                         $poolLimit,
                         [],
-                        [],
+                        $excludeQuestionIds,
                         $questionCategory,
                         $textbookCatalogNodeIds,
                         $grade ? (int) $grade : null,  // 年级