Kaynağa Gözat

fix: optimize analysis path and refine report rendering

yemeishu 2 hafta önce
ebeveyn
işleme
63fd2c1378

+ 111 - 47
app/Services/ExamAnswerAnalysisService.php

@@ -778,23 +778,19 @@ class ExamAnswerAnalysisService
         }
 
         // 【公司要求】【核心】使用MasteryCalculator计算每个知识点的掌握度
+        // 性能优化:批量读取历史 + 批量upsert,避免逐知识点查询与写入
+        $baseDifficulty = $examBaseDifficulty ?? 2;
+        $batchMasteryResults = $this->masteryCalculator->calculateMasteryLevelsBatch(
+            $studentId ?? '',
+            $knowledgeAttempts,
+            $baseDifficulty
+        );
         $masteryVector = [];
         foreach ($knowledgeAttempts as $kpId => $data) {
-            $attempts = $data['attempts'];
-
-            // 如果没有学案基准难度,使用默认值2(提分)
-            $baseDifficulty = $examBaseDifficulty ?? 2;
-
-            // 【公司要求】调用MasteryCalculator的核心算法(传入学案基准难度)
-            // 该算法包含:难度映射、权重计算、数值更新(newMastery = oldMastery + change)
-            $masteryResult = $this->masteryCalculator->calculateMasteryLevel(
-                $studentId ?? '', // 传递学生ID,用于保存掌握度到数据库
-                $kpId,
-                $attempts,
-                $baseDifficulty
-            );
-
-            // 【公司要求】只保留核心掌握度数据
+            $masteryResult = $batchMasteryResults[$kpId] ?? null;
+            if ($masteryResult === null) {
+                continue;
+            }
             $masteryVector[$kpId] = [
                 'kp_id' => $kpId,
                 'mastery' => $masteryResult['mastery'],
@@ -1617,11 +1613,47 @@ class ExamAnswerAnalysisService
         $now = now();
         $updated = 0;
 
+        $questionIds = [];
+        foreach ($examData['questions'] as $question) {
+            $questionId = $question['question_id'] ?? $question['question_bank_id'] ?? null;
+            if (!empty($questionId)) {
+                $questionIds[] = (string) $questionId;
+            }
+        }
+        $questionIds = array_values(array_unique($questionIds));
+        if (empty($questionIds)) {
+            return;
+        }
+
+        $paperQuestionRows = DB::connection('mysql')->table('paper_questions')
+            ->where('paper_id', $paperId)
+            ->where(function ($q) use ($questionIds) {
+                $q->whereIn('question_bank_id', $questionIds)
+                    ->orWhereIn('question_id', $questionIds);
+            })
+            ->get(['id', 'question_bank_id', 'question_id']);
+
+        $rowIdsByQuestionId = [];
+        foreach ($paperQuestionRows as $row) {
+            if (!empty($row->question_bank_id)) {
+                $rowIdsByQuestionId[(string) $row->question_bank_id][] = (int) $row->id;
+            }
+            if (!empty($row->question_id)) {
+                $rowIdsByQuestionId[(string) $row->question_id][] = (int) $row->id;
+            }
+        }
+
+        $updateRowsById = [];
         foreach ($examData['questions'] as $question) {
             $questionId = $question['question_id'] ?? $question['question_bank_id'] ?? null;
             if (empty($questionId)) {
                 continue;
             }
+            $questionId = (string) $questionId;
+            $targetRowIds = $rowIdsByQuestionId[$questionId] ?? [];
+            if (empty($targetRowIds)) {
+                continue;
+            }
 
             $isCorrectArray = $question['is_correct'] ?? [];
             if (!is_array($isCorrectArray)) {
@@ -1629,37 +1661,67 @@ class ExamAnswerAnalysisService
             }
             $totalSteps = count($isCorrectArray);
             $correctSteps = array_sum(array_map(fn ($v) => (int) $v === 1 ? 1 : 0, $isCorrectArray));
-            $scoreRatio = $totalSteps > 0 ? ($correctSteps / $totalSteps) : null;
-            $isFullyCorrect = $totalSteps > 0 ? ($correctSteps === $totalSteps) : null;
+            $scoreRatio = $totalSteps > 0 ? round($correctSteps / $totalSteps, 4) : null;
+            $isFullyCorrect = $totalSteps > 0 ? ($correctSteps === $totalSteps ? 1 : 0) : null;
             $scoreObtained = $question['score_obtained'] ?? null;
 
-            $query = DB::connection('mysql')->table('paper_questions')
-                ->where('paper_id', $paperId)
-                ->where(function ($q) use ($questionId) {
-                    $q->where('question_bank_id', $questionId)
-                        ->orWhere('question_id', $questionId);
-                });
-
-            $payload = [
-                'graded_at' => $now,
-            ];
-            if ($isFullyCorrect !== null) {
-                $payload['is_correct'] = $isFullyCorrect ? 1 : 0;
-            }
-            if ($scoreRatio !== null) {
-                $payload['score_ratio'] = round($scoreRatio, 4);
-            }
-            if ($scoreObtained !== null) {
-                $payload['score_obtained'] = $scoreObtained;
-            }
-            if (array_key_exists('student_answer', $question)) {
-                $payload['student_answer'] = $question['student_answer'];
+            foreach ($targetRowIds as $rowId) {
+                $payload = [
+                    'id' => $rowId,
+                    'graded_at' => $now,
+                ];
+                if ($isFullyCorrect !== null) {
+                    $payload['is_correct'] = $isFullyCorrect;
+                }
+                if ($scoreRatio !== null) {
+                    $payload['score_ratio'] = $scoreRatio;
+                }
+                if ($scoreObtained !== null) {
+                    $payload['score_obtained'] = $scoreObtained;
+                }
+                if (array_key_exists('student_answer', $question)) {
+                    $payload['student_answer'] = $question['student_answer'];
+                }
+                if (array_key_exists('teacher_comment', $question)) {
+                    $payload['teacher_comment'] = $question['teacher_comment'];
+                }
+                $updateRowsById[$rowId] = $payload;
             }
-            if (array_key_exists('teacher_comment', $question)) {
-                $payload['teacher_comment'] = $question['teacher_comment'];
+        }
+
+        if (!empty($updateRowsById)) {
+            $updateRows = array_values($updateRowsById);
+            $fields = ['graded_at', 'is_correct', 'score_ratio', 'score_obtained', 'student_answer', 'teacher_comment'];
+            $cases = [];
+            $bindings = [];
+
+            foreach ($fields as $field) {
+                $caseSql = "`{$field}` = CASE `id`";
+                $hasValue = false;
+                foreach ($updateRows as $row) {
+                    if (!array_key_exists($field, $row)) {
+                        continue;
+                    }
+                    $hasValue = true;
+                    $caseSql .= ' WHEN ? THEN ?';
+                    $bindings[] = $row['id'];
+                    $bindings[] = $row[$field];
+                }
+                $caseSql .= " ELSE `{$field}` END";
+                if ($hasValue) {
+                    $cases[] = $caseSql;
+                }
             }
 
-            $updated += $query->update($payload);
+            if (!empty($cases)) {
+                $ids = array_column($updateRows, 'id');
+                $idPlaceholders = implode(',', array_fill(0, count($ids), '?'));
+                $sql = 'UPDATE `paper_questions` SET '.implode(', ', $cases)." WHERE `id` IN ({$idPlaceholders})";
+                foreach ($ids as $id) {
+                    $bindings[] = $id;
+                }
+                $updated = DB::connection('mysql')->update($sql, $bindings);
+            }
         }
 
         if ($updated > 0) {
@@ -2125,12 +2187,14 @@ class ExamAnswerAnalysisService
                 );
             }
 
-            Log::debug('自动计算分数', [
-                'question_id' => $questionId,
-                'default_score' => $question['score'],
-                'score_obtained' => $question['score_obtained'],
-                'is_correct' => $question['is_correct'] ?? [],
-            ]);
+            if (config('app.debug')) {
+                Log::debug('自动计算分数', [
+                    'question_id' => $questionId,
+                    'default_score' => $question['score'],
+                    'score_obtained' => $question['score_obtained'],
+                    'is_correct' => $question['is_correct'] ?? [],
+                ]);
+            }
         }
 
         return $questions;

+ 141 - 49
app/Services/MasteryCalculator.php

@@ -91,6 +91,84 @@ class MasteryCalculator
         return $masteryData;
     }
 
+    /**
+     * 批量计算并落库知识点掌握度(性能优化:批量读历史 + 批量upsert)
+     *
+     * @param  string  $studentId
+     * @param  array<string, array{attempts: array}>  $knowledgeAttempts
+     * @param  int  $examBaseDifficulty
+     * @return array<string, array>
+     */
+    public function calculateMasteryLevelsBatch(string $studentId, array $knowledgeAttempts, int $examBaseDifficulty): array
+    {
+        if (empty($knowledgeAttempts)) {
+            return [];
+        }
+
+        $kpCodes = array_keys($knowledgeAttempts);
+        $historyRows = DB::table('student_knowledge_mastery')
+            ->where('student_id', $studentId)
+            ->whereIn('kp_code', $kpCodes)
+            ->get(['kp_code', 'mastery_level', 'total_attempts', 'correct_attempts'])
+            ->keyBy('kp_code');
+
+        $now = now();
+        $upsertRows = [];
+        $results = [];
+
+        foreach ($knowledgeAttempts as $kpCode => $data) {
+            $attempts = $data['attempts'] ?? [];
+            if (empty($attempts)) {
+                continue;
+            }
+
+            $historyMastery = $historyRows->get($kpCode);
+            $oldMastery = (float) ($historyMastery->mastery_level ?? 0.0);
+            $historyTotalAttempts = (int) ($historyMastery->total_attempts ?? 0);
+            $historyCorrectAttempts = (int) ($historyMastery->correct_attempts ?? 0);
+
+            $computed = $this->computeMasteryChange($attempts, $examBaseDifficulty, false);
+            $newMastery = max(0.0, min(1.0, $oldMastery + $computed['total_change']));
+            $newMastery = round($newMastery, 4);
+
+            $upsertRows[] = [
+                'student_id' => $studentId,
+                'kp_code' => $kpCode,
+                'mastery_level' => $newMastery,
+                'direct_mastery_level' => $newMastery,
+                'confidence_level' => 0.0,
+                'total_attempts' => $historyTotalAttempts + $computed['total_attempts'],
+                'correct_attempts' => $historyCorrectAttempts + $computed['correct_attempts'],
+                'mastery_trend' => 'stable',
+                'last_mastery_update' => $now,
+                'updated_at' => $now,
+            ];
+
+            $results[$kpCode] = [
+                'mastery' => $newMastery,
+                'total_attempts' => $computed['total_attempts'],
+                'correct_attempts' => $computed['correct_attempts'],
+                'accuracy_rate' => $computed['accuracy_rate'],
+                'old_mastery' => $oldMastery,
+                'change' => round($computed['total_change'], 4),
+                'details' => [
+                    'exam_base_difficulty' => $examBaseDifficulty,
+                    'total_change' => round($computed['total_change'], 4),
+                ],
+            ];
+        }
+
+        if (!empty($upsertRows)) {
+            DB::table('student_knowledge_mastery')->upsert(
+                $upsertRows,
+                ['student_id', 'kp_code'],
+                ['mastery_level', 'direct_mastery_level', 'confidence_level', 'total_attempts', 'correct_attempts', 'mastery_trend', 'last_mastery_update', 'updated_at']
+            );
+        }
+
+        return $results;
+    }
+
     /**
      * 获取难度等级名称
      */
@@ -119,54 +197,10 @@ class MasteryCalculator
 
         $oldMastery = $historyMastery->mastery_level ?? 0.0; // 默认 0.0
 
-        // 统计正确和错误次数
-        $totalAttempts = count($attempts);
-        $correctAttempts = 0;
-        $incorrectAttempts = 0;
-        foreach ($attempts as $attempt) {
-            if (boolval($attempt['is_correct'] ?? false)) {
-                $correctAttempts++;
-            } else {
-                $incorrectAttempts++;
-            }
-        }
-        $accuracyRate = $totalAttempts > 0 ? ($correctAttempts / $totalAttempts) : 0.0;
-
-        // 计算每次答题的权重变化
-        $totalChange = 0.0;
-
-        foreach ($attempts as $attempt) {
-            $isCorrect = boolval($attempt['is_correct'] ?? false);
-            $questionDifficulty = floatval($attempt['question_difficulty'] ?? 0.6);
-
-            // 难度映射:将0.0-1.0的浮点数难度映射为 1-4 等级
-            $questionLevel = $this->mapDifficultyToLevel($questionDifficulty);
-
-            // 根据难度关系计算权重变化
-            $change = $this->calculateWeightByDifficultyRelation($questionLevel, $examBaseDifficulty, $isCorrect);
-
-            // 0基础保护:当次正确率偏低时,限制正向增益,避免“错很多但掌握度持续贴近100%”
-            if (
-                $examBaseDifficulty === 0
-                && $accuracyRate < self::BASE_ZERO_GAIN_GUARD_CORRECT_RATE
-                && $change > 0
-            ) {
-                $change = round($change * 0.5, 4);
-            }
-
-            $totalChange += $change;
-
-        Log::debug('掌握度变化计算', [
-                'question_id' => $attempt['question_id'] ?? '',
-                'question_difficulty' => $questionDifficulty,
-                'question_level' => $questionLevel,
-                'exam_base_difficulty' => $examBaseDifficulty,
-                'is_correct' => $isCorrect,
-                'change' => $change,
-                'running_total' => $totalChange,
-                'accuracy_rate' => round($accuracyRate, 4),
-            ]);
-        }
+        $computed = $this->computeMasteryChange($attempts, $examBaseDifficulty, config('app.debug'));
+        $totalAttempts = $computed['total_attempts'];
+        $correctAttempts = $computed['correct_attempts'];
+        $totalChange = $computed['total_change'];
 
         // 【公司要求】数值更新:newMastery = oldMastery + change
         $newMastery = $oldMastery + $totalChange;
@@ -196,7 +230,7 @@ class MasteryCalculator
             'mastery' => round($newMastery, 4),
             'total_attempts' => $totalAttempts,
             'correct_attempts' => $correctAttempts,
-            'accuracy_rate' => round(($correctAttempts / $totalAttempts) * 100, 2),
+            'accuracy_rate' => $computed['accuracy_rate'],
             'old_mastery' => $oldMastery,
             'change' => round($totalChange, 4),
             'details' => [
@@ -206,6 +240,64 @@ class MasteryCalculator
         ];
     }
 
+    /**
+     * 计算一次掌握度变化,不落库。
+     *
+     * @param  array  $attempts
+     * @param  int  $examBaseDifficulty
+     * @param  bool  $enableDebug
+     * @return array{total_attempts:int,correct_attempts:int,accuracy_rate:float,total_change:float}
+     */
+    private function computeMasteryChange(array $attempts, int $examBaseDifficulty, bool $enableDebug = false): array
+    {
+        $totalAttempts = count($attempts);
+        $correctAttempts = 0;
+        foreach ($attempts as $attempt) {
+            if (boolval($attempt['is_correct'] ?? false)) {
+                $correctAttempts++;
+            }
+        }
+        $accuracyRateRatio = $totalAttempts > 0 ? ($correctAttempts / $totalAttempts) : 0.0;
+
+        $totalChange = 0.0;
+        foreach ($attempts as $attempt) {
+            $isCorrect = boolval($attempt['is_correct'] ?? false);
+            $questionDifficulty = floatval($attempt['question_difficulty'] ?? 0.6);
+            $questionLevel = $this->mapDifficultyToLevel($questionDifficulty);
+            $change = $this->calculateWeightByDifficultyRelation($questionLevel, $examBaseDifficulty, $isCorrect);
+
+            if (
+                $examBaseDifficulty === 0
+                && $accuracyRateRatio < self::BASE_ZERO_GAIN_GUARD_CORRECT_RATE
+                && $change > 0
+            ) {
+                $change = round($change * 0.5, 4);
+            }
+
+            $totalChange += $change;
+
+            if ($enableDebug) {
+                Log::debug('掌握度变化计算', [
+                    'question_id' => $attempt['question_id'] ?? '',
+                    'question_difficulty' => $questionDifficulty,
+                    'question_level' => $questionLevel,
+                    'exam_base_difficulty' => $examBaseDifficulty,
+                    'is_correct' => $isCorrect,
+                    'change' => $change,
+                    'running_total' => $totalChange,
+                    'accuracy_rate' => round($accuracyRateRatio, 4),
+                ]);
+            }
+        }
+
+        return [
+            'total_attempts' => $totalAttempts,
+            'correct_attempts' => $correctAttempts,
+            'accuracy_rate' => $totalAttempts > 0 ? round(($correctAttempts / $totalAttempts) * 100, 2) : 0.0,
+            'total_change' => $totalChange,
+        ];
+    }
+
     /**
      * 【公司要求】难度映射:将题目中0.0-1.0的浮点数难度映射为0-4等级
      *

+ 63 - 32
resources/views/exam-analysis/pdf-report.blade.php

@@ -107,11 +107,11 @@
             word-break: break-all;
             line-height: 1.45;
         }
-        .tree-line.hit { font-weight: 700; color: #1d4ed8; }
+        .tree-line.hit { font-weight: 700; color: #1f2937; }
         .tree-line-badge { display: inline-block; margin-left: 6px; padding: 1px 5px; border-radius: 999px; font-size: 10px; border: 1px solid transparent; }
         .tree-line-badge.high { background: #ecfdf3; color: #15803d; border-color: #86efac; }
         .tree-line-badge.mid { background: #fffbeb; color: #b45309; border-color: #fcd34d; }
-        .tree-line-badge.low { background: #fef2f2; color: #b91c1c; border-color: #fca5a5; }
+        .tree-line-badge.low { background: #f8fafc; color: #475569; border-color: #cbd5e1; }
         .tree-line-badge.miss { background: #f3f4f6; color: #6b7280; border-color: #d1d5db; }
         .detail-card {
             border: 1px solid #e2e8f0;
@@ -184,12 +184,15 @@
         .detail-change-down { color: #dc2626; font-weight: 700; }
         .aggregate-tip { font-size: 11px; color: #475569; margin-top: 6px; }
         .question-card { border:1px solid #e5e7eb; border-radius:8px; padding:6px 9px; margin-bottom:5px; background:#fff; page-break-inside: auto; break-inside: auto; }
-        .question-block { margin-bottom: 5px; padding: 5px; border-radius: 4px; }
+        .question-block { margin-bottom: 5px; padding: 5px; border-radius: 4px; page-break-inside: auto; break-inside: auto; }
         .solution-content {
-            display: inline-block;
+            display: block;
             line-height: 1.75;
             white-space: normal;
             word-break: break-word;
+            overflow-wrap: anywhere;
+            page-break-inside: auto;
+            break-inside: auto;
         }
     </style>
 </head>
@@ -217,19 +220,61 @@
     <div class="card">
         <div class="section-title">本次命中子知识点掌握度</div>
         @php
-            // 【修复】过滤掉K-GENERAL等通用知识点,只显示有值的知识点
+            // 先收集“本次命中”子知识点(用于区分:已作答0分 vs 未学习0分)
+            $hitChildMeta = [];
+            foreach (($parent_mastery_levels ?? []) as $pData) {
+                foreach (($pData['children_all'] ?? []) as $child) {
+                    if (empty($child['is_hit'])) {
+                        continue;
+                    }
+                    $kpCode = (string) ($child['kp_code'] ?? '');
+                    if ($kpCode === '') {
+                        continue;
+                    }
+                    $hitChildMeta[$kpCode] = [
+                        'kp_code' => $kpCode,
+                        'kp_name' => $child['kp_name'] ?? $kpCode,
+                        'mastery_level' => floatval($child['mastery_level'] ?? 0),
+                        'is_hit' => true,
+                    ];
+                }
+            }
+
+            // 过滤掉K-GENERAL等通用知识点:
+            // - 掌握度>0 的正常显示
+            // - 命中且0分(已作答)也显示,避免被误判为“未学习”
             $filteredMasteryItems = [];
+            $filteredMasteryByCode = [];
             if (!empty($mastery['items'])) {
                 foreach ($mastery['items'] as $item) {
                     $kpCode = $item['kp_code'] ?? '';
                     $masteryLevel = $item['mastery_level'] ?? 0;
+                    $isHit = isset($hitChildMeta[$kpCode]);
 
-                    // 过滤条件:不是通用知识点,且掌握度>0
-                    if (!in_array($kpCode, ['K-GENERAL', 'GENERAL', 'DEFAULT']) && $masteryLevel > 0) {
+                    if (!in_array($kpCode, ['K-GENERAL', 'GENERAL', 'DEFAULT']) && ($masteryLevel > 0 || $isHit)) {
+                        $item['is_hit'] = $isHit;
                         $filteredMasteryItems[] = $item;
+                        $filteredMasteryByCode[$kpCode] = true;
                     }
                 }
             }
+
+            // 补齐:如果命中子知识点没有出现在 mastery.items 中,也补一条0分记录用于展示和建议
+            foreach ($hitChildMeta as $kpCode => $meta) {
+                if (isset($filteredMasteryByCode[$kpCode])) {
+                    continue;
+                }
+                if (in_array($kpCode, ['K-GENERAL', 'GENERAL', 'DEFAULT'])) {
+                    continue;
+                }
+                $filteredMasteryItems[] = [
+                    'kp_code' => $kpCode,
+                    'kp_name' => $meta['kp_name'],
+                    'mastery_level' => $meta['mastery_level'],
+                    'mastery_change' => null,
+                    'is_hit' => true,
+                ];
+            }
         @endphp
 
         @if(!empty($filteredMasteryItems))
@@ -238,6 +283,7 @@
                     $pct = min(100, max(0, ($item['mastery_level'] ?? 0) * 100));
                     $barColor = $pct >= 80 ? '#10b981' : ($pct >= 60 ? '#f59e0b' : '#ef4444');
                     $delta = $item['mastery_change'] ?? null;
+                    $isHitItem = !empty($item['is_hit']);
                     // 只有当有变化值时才显示变化信息
                     $changeText = '';
                     if ($delta !== null && $delta !== '' && abs($delta) > 0.001) {
@@ -258,7 +304,7 @@
                 </div>
             @endforeach
         @else
-            <div class="muted">暂无有效掌握度数据(已过滤通用知识点和零值)</div>
+            <div class="muted">暂无有效掌握度数据(已过滤通用知识点)</div>
         @endif
     </div>
 
@@ -313,7 +359,7 @@
                                                     └─ {{ $child['kp_name'] }}
                                                     <span class="tree-line-badge {{ $badgeClass }}">{{ $badgeText }}</span>
                                                     @if($isHit)
-                                                        <span class="tree-line-badge high">本次命中</span>
+                                                        <span class="tree-line-badge miss">本次命中</span>
                                                     @endif
                                                 </div>
                                             @endforeach
@@ -353,7 +399,7 @@
                                             @endif
                                         </div>
                                         <div class="detail-meta">
-                                            子节点总数 {{ $childCount }} 个,本次命中 {{ $hitCount }} 个,命中均值 {{ $hitAvg !== null ? number_format(floatval($hitAvg) * 100, 1) . '%' : '-' }}
+                                            子节点总数 {{ $childCount }} 个,本次命中 {{ $hitCount }} 个,命中均值 {{ $hitAvg !== null ? number_format(floatval($hitAvg) * 100, 1) . '%' : '-' }}(命中表示本次覆盖,不等于已掌握)
                                         </div>
                                     </div>
                                 </td>
@@ -565,21 +611,16 @@
                 }
 
                 // 判分状态显示逻辑
-                $showStatus = false;
                 $statusText = '';
                 $statusColor = '';
-                if (!empty($studentAnswer)) {
-                    // 学生有答题,显示判分结果
-                    $showStatus = true;
-                    if ($isCorrect === 1) {
-                        $statusText = '正确';
-                        $statusColor = '#10b981';
-                    } elseif ($isCorrect === 0) {
-                        $statusText = '错误';
-                        $statusColor = '#ef4444';
-                    }
+                if ($isCorrect === 1) {
+                    $statusText = '正确';
+                    $statusColor = '#10b981';
+                } elseif ($isCorrect === 0) {
+                    $statusText = '错误';
+                    $statusColor = '#ef4444';
                 }
-                // 没答题的不显示状态
+                $showStatus = $statusText !== '';
 
                 $insight = $insightMap[$q['question_number']] ?? ($insightMap[$q['display_number'] ?? null] ?? []);
                 // 【修复】得分显示:答错显示实际得分,答对显示满分
@@ -654,16 +695,6 @@
                     @endif
                 </div>
 
-                {{-- 【新增】学生答案显示(如果有) --}}
-                @if(!empty($studentAnswer))
-                    <div class="question-block" style="background:#fef2f2; border-left:3px solid #ef4444;">
-                        <div style="font-weight:600; font-size:12px; color:#111827; margin-bottom:3px;">学生答案</div>
-                        <div class="math-content" style="font-size:12px; line-height:1.5; color:#374151;">
-                            {!! nl2br(e($studentAnswer)) !!}
-                        </div>
-                    </div>
-                @endif
-
                 <div class="math-content" style="margin-bottom:6px; font-size:12px;">{!! $questionText !!}</div>
 
                 {{-- 【修复】正确答案显示 --}}