Просмотр исходного кода

fix(knowledge-explanation): fill paper_info fields and align exam_content stats

Populate difficulty_category from task data, grading_code, statistics,
question metadata labels; sync papers row; add callback stats payload.

Co-authored-by: Cursor <cursoragent@cursor.com>
yemeishu 5 дней назад
Родитель
Сommit
a03f395786
1 измененных файлов с 104 добавлено и 20 удалено
  1. 104 20
      app/Jobs/GenerateKnowledgeExplanationPdfJob.php

+ 104 - 20
app/Jobs/GenerateKnowledgeExplanationPdfJob.php

@@ -57,7 +57,16 @@ class GenerateKnowledgeExplanationPdfJob implements ShouldQueue
                 'pdf_url' => $pdfUrl,
                 'generated_at' => now(),
             ]);
-            $this->syncPaperRecord($record, $pdfUrl);
+
+            $taskSnapshot = $taskManager->getTaskStatus($this->taskId);
+            $taskData = is_array($taskSnapshot) && isset($taskSnapshot['data']) && is_array($taskSnapshot['data'])
+                ? $taskSnapshot['data']
+                : [];
+
+            $examContent = $this->buildKnowledgeExamContent($record, $pdfUrl, $taskData);
+            $this->syncPaperRecord($record, $pdfUrl, $examContent);
+
+            $difficultyCategoryForStats = (int) ($examContent['paper_info']['difficulty_category'] ?? 2);
 
             $taskManager->markTaskCompleted($this->taskId, [
                 'paper_id' => $this->knowledgeId,
@@ -65,7 +74,12 @@ class GenerateKnowledgeExplanationPdfJob implements ShouldQueue
                 'pdfs' => [
                     'all_pdf' => $pdfUrl,
                 ],
-                'exam_content' => $this->buildKnowledgeExamContent($record, $pdfUrl),
+                'exam_content' => $examContent,
+                'stats' => [
+                    'difficulty_category' => $difficultyCategoryForStats,
+                    'total_selected' => count($examContent['questions'] ?? []),
+                    'difficulty_distribution_applied' => true,
+                ],
             ]);
             $taskManager->sendCallback($this->taskId);
         } catch (\Throwable $e) {
@@ -89,7 +103,7 @@ class GenerateKnowledgeExplanationPdfJob implements ShouldQueue
         app(TaskManager::class)->markTaskFailed($this->taskId, $exception->getMessage());
     }
 
-    private function syncPaperRecord(KnowledgeExplanation $record, string $pdfUrl): void
+    private function syncPaperRecord(KnowledgeExplanation $record, string $pdfUrl, array $examContent): void
     {
         $paperId = (string) ($record->knowledge_id ?? '');
         if ($paperId === '') {
@@ -101,6 +115,10 @@ class GenerateKnowledgeExplanationPdfJob implements ShouldQueue
             $displayCode = $paperId;
         }
 
+        $paperInfo = $examContent['paper_info'] ?? [];
+        $totalQuestions = (int) ($paperInfo['total_questions'] ?? 0);
+        $difficultyCategory = $paperInfo['difficulty_category'] ?? null;
+
         Paper::query()->updateOrCreate(
             ['paper_id' => $paperId],
             [
@@ -113,10 +131,12 @@ class GenerateKnowledgeExplanationPdfJob implements ShouldQueue
                 ],
                 'paper_name' => '知识点讲解_' . $displayCode,
                 'paper_type' => 22,
-                'total_questions' => 0,
+                'total_questions' => $totalQuestions,
                 'total_score' => 100,
                 'status' => 'completed',
-                'difficulty_category' => null,
+                'difficulty_category' => $difficultyCategory !== null && $difficultyCategory !== ''
+                    ? (string) $difficultyCategory
+                    : null,
                 'exam_pdf_url' => $pdfUrl,
                 'grading_pdf_url' => null,
                 'all_pdf_url' => $pdfUrl,
@@ -125,7 +145,7 @@ class GenerateKnowledgeExplanationPdfJob implements ShouldQueue
         );
     }
 
-    private function buildKnowledgeExamContent(KnowledgeExplanation $record, string $pdfUrl): array
+    private function buildKnowledgeExamContent(KnowledgeExplanation $record, string $pdfUrl, array $taskData = []): array
     {
         $paperId = (string) ($record->knowledge_id ?? '');
         $displayCode = (string) preg_replace('/^(paper_|knowledge_)/', '', $paperId);
@@ -133,6 +153,11 @@ class GenerateKnowledgeExplanationPdfJob implements ShouldQueue
             $displayCode = $paperId;
         }
         $kpCodes = is_array($record->kp_codes) ? array_values($record->kp_codes) : [];
+        $difficultyCategoryRaw = $taskData['difficulty_category'] ?? null;
+        $difficultyCategoryStr = $difficultyCategoryRaw !== null && $difficultyCategoryRaw !== ''
+            ? (string) $difficultyCategoryRaw
+            : '2';
+
         $questions = $this->buildKnowledgeQuestions(100);
         $knowledgeDistribution = [];
         foreach ($kpCodes as $kpCode) {
@@ -146,6 +171,35 @@ class GenerateKnowledgeExplanationPdfJob implements ShouldQueue
             $knowledgeDistribution[$kp] = (int) ($knowledgeDistribution[$kp] ?? 0) + 1;
         }
 
+        $typeDistribution = ['choice' => 0, 'fill' => 0, 'answer' => 0];
+        foreach ($questions as $q) {
+            $t = (string) ($q['question_type'] ?? 'answer');
+            if ($t === 'choice') {
+                $typeDistribution['choice']++;
+            } elseif ($t === 'fill') {
+                $typeDistribution['fill']++;
+            } else {
+                $typeDistribution['answer']++;
+            }
+        }
+
+        $difficultyDistribution = [];
+        $difficultySum = 0.0;
+        $difficultyCount = 0;
+        foreach ($questions as $q) {
+            $dl = $q['metadata']['difficulty_label'] ?? '';
+            if ($dl !== '') {
+                $difficultyDistribution[$dl] = ($difficultyDistribution[$dl] ?? 0) + 1;
+            }
+            if (isset($q['difficulty']) && is_numeric($q['difficulty'])) {
+                $difficultySum += (float) $q['difficulty'];
+                $difficultyCount++;
+            }
+        }
+
+        $averageDifficulty = $difficultyCount > 0 ? $difficultySum / $difficultyCount : null;
+        $totalEstimatedTime = count($questions) * 300;
+
         return [
             'paper_info' => [
                 'paper_id' => $paperId,
@@ -154,25 +208,21 @@ class GenerateKnowledgeExplanationPdfJob implements ShouldQueue
                 'teacher_id' => (string) ($record->teacher_id ?? ''),
                 'total_questions' => count($questions),
                 'total_score' => 100,
-                'difficulty_category' => null,
+                'difficulty_category' => $difficultyCategoryStr,
                 'created_at' => optional($record->created_at)->toISOString(),
                 'updated_at' => optional($record->updated_at)->toISOString(),
                 'exam_code' => $displayCode,
-                'grading_code' => null,
+                'grading_code' => $displayCode,
                 'paper_id_num' => $displayCode,
             ],
             'questions' => $questions,
             'knowledge_points' => $kpCodes,
             'statistics' => [
-                'type_distribution' => [
-                    'choice' => 0,
-                    'fill' => 0,
-                    'answer' => count($questions),
-                ],
-                'difficulty_distribution' => [],
+                'type_distribution' => $typeDistribution,
+                'difficulty_distribution' => $difficultyDistribution,
                 'knowledge_point_distribution' => $knowledgeDistribution,
-                'average_difficulty' => null,
-                'total_estimated_time' => 0,
+                'average_difficulty' => $averageDifficulty,
+                'total_estimated_time' => $totalEstimatedTime,
             ],
             'pdfs' => [
                 'all_pdf' => $pdfUrl,
@@ -191,26 +241,35 @@ class GenerateKnowledgeExplanationPdfJob implements ShouldQueue
             $cases = is_array($point['cases'] ?? null) ? $point['cases'] : [];
             foreach ($cases as $case) {
                 $questionId = (int) ($case['question_id'] ?? 0);
+                $qType = (string) ($case['question_type'] ?? 'answer');
+                $solutionText = (string) ($case['solution'] ?? '');
+                $difficultyVal = isset($case['difficulty']) && is_numeric($case['difficulty']) ? (float) $case['difficulty'] : null;
                 $questions[] = [
                     'question_number' => $seq++,
                     'question_id' => $questionId > 0 ? (string) $questionId : '',
                     'question_bank_id' => $questionId > 0 ? $questionId : null,
-                    'question_type' => (string) ($case['question_type'] ?? 'answer'),
+                    'question_type' => $qType,
                     'knowledge_point' => $kpCode,
                     'knowledge_point_name' => $kpName,
-                    'difficulty' => isset($case['difficulty']) && is_numeric($case['difficulty']) ? (float) $case['difficulty'] : null,
+                    'difficulty' => $difficultyVal,
                     'score' => 0,
-                    'estimated_time' => null,
+                    'estimated_time' => 300,
                     'stem' => (string) ($case['stem'] ?? ''),
                     'options' => is_array($case['options'] ?? null) ? $case['options'] : [],
                     'correct_answer' => (string) ($case['answer'] ?? ''),
-                    'solution' => (string) ($case['solution'] ?? ''),
+                    'solution' => $solutionText,
                     'metadata' => [
                         'source_type' => (string) ($case['source_type'] ?? ''),
                         'source_label' => (string) ($case['source_label'] ?? ''),
                         'is_wrong_case' => (bool) ($case['is_wrong_case'] ?? false),
                         'child_kp_code' => $case['child_kp_code'] ?? null,
                         'child_kp_name' => $case['child_kp_name'] ?? null,
+                        'has_solution' => $solutionText !== '',
+                        'is_choice' => $qType === 'choice',
+                        'is_fill' => $qType === 'fill',
+                        'is_answer' => $qType === 'answer',
+                        'difficulty_label' => $this->difficultyLabelForPayload($difficultyVal),
+                        'question_type_label' => $this->questionTypeLabelForPayload($qType),
                     ],
                 ];
             }
@@ -236,4 +295,29 @@ class GenerateKnowledgeExplanationPdfJob implements ShouldQueue
 
         return $questions;
     }
+
+    private function questionTypeLabelForPayload(?string $type): string
+    {
+        return match ($type) {
+            'choice' => '选择题',
+            'fill' => '填空题',
+            'answer' => '解答题',
+            default => '未知题型',
+        };
+    }
+
+    private function difficultyLabelForPayload(?float $difficulty): string
+    {
+        if ($difficulty === null) {
+            return '未知';
+        }
+        if ($difficulty <= 0.4) {
+            return '基础';
+        }
+        if ($difficulty <= 0.7) {
+            return '中等';
+        }
+
+        return '拔高';
+    }
 }