Ver Fonte

fix: 修复公式里的 <>符号问题

gwd há 1 semana atrás
pai
commit
68447b436b

+ 8 - 0
app/Services/ExamPdfExportService.php

@@ -2371,6 +2371,10 @@ class ExamPdfExportService
             // 1. 生成试卷PDF(不含答案)
             $examHtml = $this->renderCustomExamHtml($paper, $groupedQuestions, $student, $teacher, false);
             if ($examHtml) {
+                // 【修复】使用服务端 KaTeX 预渲染 LaTeX 公式
+                if ($this->katexRenderer) {
+                    $examHtml = $this->katexRenderer->renderHtml($examHtml);
+                }
                 $examPdf = $this->buildPdf($examHtml);
                 if ($examPdf) {
                     $examPath = "custom_exams/{$paper->paper_id}_exam.pdf";
@@ -2384,6 +2388,10 @@ class ExamPdfExportService
             if ($includeGrading) {
                 $gradingHtml = $this->renderCustomExamHtml($paper, $groupedQuestions, $student, $teacher, true);
                 if ($gradingHtml) {
+                    // 【修复】使用服务端 KaTeX 预渲染 LaTeX 公式
+                    if ($this->katexRenderer) {
+                        $gradingHtml = $this->katexRenderer->renderHtml($gradingHtml);
+                    }
                     $gradingPdf = $this->buildPdf($gradingHtml);
                     if ($gradingPdf) {
                         $gradingPath = "custom_exams/{$paper->paper_id}_grading.pdf";

+ 44 - 4
app/Services/MathFormulaProcessor.php

@@ -55,9 +55,10 @@ class MathFormulaProcessor
 
             case 'delimited':
                 // 已包含定界符的内容($...$, $$...$$, \(...\), \[...\])
-                // 直接返回,cleanInsideDelimiters() 已经清理了内部内容
+                // cleanInsideDelimiters() 已经清理了内部内容
                 // 渲染工作由客户端 KaTeX 或服务端 KatexRenderer 完成
-                return $content;
+                // 【关键修复】将定界符内的 < > 编码为 HTML 实体,避免被浏览器当作 HTML 标签处理
+                return self::encodeAngleBracketsInDelimiters($content);
 
             case 'plain_text':
             default:
@@ -158,6 +159,41 @@ class MathFormulaProcessor
         return $content;
     }
 
+    /**
+     * 【新增】将定界符内的 < > 编码为 HTML 实体
+     * 避免 LaTeX 公式中的 < > 被浏览器当作 HTML 标签处理
+     * 例如:$x<4$ 中的 <4 会被浏览器当作无效标签移除
+     */
+    private static function encodeAngleBracketsInDelimiters(string $content): string
+    {
+        $encodeInner = function (string $tex): string {
+            // 将 < 和 > 编码为 HTML 实体,KaTeX 会正确处理这些实体
+            return str_replace(['<', '>'], ['&lt;', '&gt;'], $tex);
+        };
+
+        // 1. 处理 $$...$$ 块级公式
+        $content = preg_replace_callback('/\$\$([\s\S]*?)\$\$/', function ($matches) use ($encodeInner) {
+            return '$$' . $encodeInner($matches[1]) . '$$';
+        }, $content);
+
+        // 2. 处理 $...$ 行内公式(避免与$$冲突)
+        $content = preg_replace_callback('/(?<!\$)\$([^$\n]+?)\$(?!\$)/', function ($matches) use ($encodeInner) {
+            return '$' . $encodeInner($matches[1]) . '$';
+        }, $content);
+
+        // 3. 处理 \(...\) 行内公式
+        $content = preg_replace_callback('/\\\\\(([\s\S]*?)\\\\\)/', function ($matches) use ($encodeInner) {
+            return '\\(' . $encodeInner($matches[1]) . '\\)';
+        }, $content);
+
+        // 4. 处理 \[...\] 块级公式
+        $content = preg_replace_callback('/\\\\\[([\s\S]*?)\\\\\]/', function ($matches) use ($encodeInner) {
+            return '\\[' . $encodeInner($matches[1]) . '\\]';
+        }, $content);
+
+        return $content;
+    }
+
     /**
      * 【新增】检查内容中是否包含任意定界符(不要求整个字符串被包裹)
      */
@@ -219,7 +255,9 @@ class MathFormulaProcessor
     private static function wrapPureMath(string $content): string
     {
         // 已经是纯数学格式,直接用 $ 包裹
-        return '$'.$content.'$';
+        // 【修复】编码 < > 避免被浏览器当作 HTML 标签
+        $encoded = str_replace(['<', '>'], ['&lt;', '&gt;'], $content);
+        return '$' . $encoded . '$';
     }
 
     /**
@@ -313,7 +351,9 @@ class MathFormulaProcessor
                     return $math;
                 }
 
-                return '$'.$math.'$';
+                // 【修复】编码 < > 避免被浏览器当作 HTML 标签
+                $encoded = str_replace(['<', '>'], ['&lt;', '&gt;'], $math);
+                return '$' . $encoded . '$';
             }
 
             return $matches[0];