소스 검색

fix(exam): 指定章节摸底优先按传入列表处理

指定 chapter_id_list 时按传入节点映射并顺序选章,避免因教材映射不一致回退默认摸底章节。

Made-with: Cursor
yemeishu 1 개월 전
부모
커밋
41421b8b66
1개의 변경된 파일35개의 추가작업 그리고 25개의 파일을 삭제
  1. 35 25
      app/Services/DiagnosticChapterService.php

+ 35 - 25
app/Services/DiagnosticChapterService.php

@@ -313,37 +313,37 @@ class DiagnosticChapterService
      */
     public function getFirstUndiagnosedChapter(int $textbookId, int $studentId, ?array $targetChapterIds = null): ?array
     {
-        $query = TextbookCatalog::query()
-            ->where('textbook_id', $textbookId)
-            ->where('node_type', 'chapter');
-
         $targetChapterIds = is_array($targetChapterIds)
             ? array_values(array_unique(array_filter(array_map('intval', $targetChapterIds), fn ($id) => $id > 0)))
             : [];
 
-        // 兜底:允许传入 section/subsection 节点,自动映射到所属 chapter 节点
+        // 只要传了 chapter_id_list(非空),就以传入参数为准;
+        // 仅当未传或为空时,才走教材默认章节逻辑。
         if (!empty($targetChapterIds)) {
-            $targetChapterIds = $this->normalizeToChapterIds($textbookId, $targetChapterIds);
-        }
+            // 兜底:允许传入 section/subsection,自动向上映射到 chapter
+            $targetChapterIds = $this->normalizeToChapterIds($targetChapterIds);
+            if (empty($targetChapterIds)) {
+                Log::warning('DiagnosticChapterService: 指定章节参数无可解析chapter,终止指定章节摸底', [
+                    'textbook_id' => $textbookId,
+                    'student_id' => $studentId,
+                ]);
 
-        $useTargetChapters = !empty($targetChapterIds);
-        if ($useTargetChapters) {
-            $query->whereIn('id', $targetChapterIds);
-        }
+                return null;
+            }
 
-        $chapters = $query
-            ->orderBy('sort_order')
-            ->orderBy('display_no')
-            ->orderBy('id')
-            ->get();
+            // 保持传入顺序遍历,不使用教材排序字段重排
+            $chapterMap = TextbookCatalog::query()
+                ->whereIn('id', $targetChapterIds)
+                ->where('node_type', 'chapter')
+                ->get()
+                ->keyBy('id');
 
-        if ($chapters->isEmpty()) {
-            return null;
-        }
+            foreach ($targetChapterIds as $chapterId) {
+                $chapter = $chapterMap->get($chapterId);
+                if (!$chapter) {
+                    continue;
+                }
 
-        // 用户指定章节:按顺序找“有题知识点”的章节,不判断是否已摸底(允许重复摸底)
-        if ($useTargetChapters) {
-            foreach ($chapters as $chapter) {
                 $chapterData = $this->getChapterKnowledgePointsSimple($chapter->id);
                 $kpCodesWithQuestions = $this->filterKpCodesWithQuestions($chapterData['kp_codes']);
 
@@ -377,6 +377,18 @@ class DiagnosticChapterService
             return null;
         }
 
+        $chapters = TextbookCatalog::query()
+            ->where('textbook_id', $textbookId)
+            ->where('node_type', 'chapter')
+            ->orderBy('sort_order')
+            ->orderBy('display_no')
+            ->orderBy('id')
+            ->get();
+
+        if ($chapters->isEmpty()) {
+            return null;
+        }
+
         foreach ($chapters as $chapter) {
             // 检查是否已摸底
             if (!$this->hasChapterDiagnostic($studentId, $chapter->id)) {
@@ -434,7 +446,7 @@ class DiagnosticChapterService
      * @param array<int> $nodeIds
      * @return array<int>
      */
-    private function normalizeToChapterIds(int $textbookId, array $nodeIds): array
+    private function normalizeToChapterIds(array $nodeIds): array
     {
         if (empty($nodeIds)) {
             return [];
@@ -453,7 +465,6 @@ class DiagnosticChapterService
             while ($currentId > 0 && $guard++ < 10) {
                 $node = TextbookCatalog::query()
                     ->where('id', $currentId)
-                    ->where('textbook_id', $textbookId)
                     ->first(['id', 'parent_id', 'node_type']);
 
                 if (!$node) {
@@ -474,7 +485,6 @@ class DiagnosticChapterService
 
         if (count($chapterIds) !== count($nodeIds)) {
             Log::info('DiagnosticChapterService: 章节参数已自动映射到chapter节点', [
-                'textbook_id' => $textbookId,
                 'input_ids' => $nodeIds,
                 'resolved_chapter_ids' => $chapterIds,
             ]);