feat: 集成KaTeX库支持LaTeX数学公式渲染

This commit is contained in:
lixinran 2025-09-10 15:53:16 +08:00
parent b5c56d4946
commit 682744e4b8
9 changed files with 14653 additions and 25 deletions

Binary file not shown.

View File

@ -1,71 +1,77 @@
{
"hash": "1229e8fa",
"browserHash": "5c2510fa",
"hash": "76772e52",
"browserHash": "b5df73c3",
"optimized": {
"axios": {
"src": "../../axios/index.js",
"file": "axios.js",
"fileHash": "c14dff39",
"fileHash": "d5a6fb13",
"needsInterop": false
},
"mammoth": {
"src": "../../mammoth/lib/index.js",
"file": "mammoth.js",
"fileHash": "9331e90f",
"fileHash": "8e0b13e7",
"needsInterop": true
},
"marked": {
"src": "../../marked/lib/marked.esm.js",
"file": "marked.js",
"fileHash": "d9459e29",
"fileHash": "330cfdd3",
"needsInterop": false
},
"pdfjs-dist": {
"src": "../../pdfjs-dist/build/pdf.mjs",
"file": "pdfjs-dist.js",
"fileHash": "4db246e9",
"fileHash": "63546997",
"needsInterop": false
},
"prismjs": {
"src": "../../prismjs/prism.js",
"file": "prismjs.js",
"fileHash": "e122bdaf",
"fileHash": "3730e60a",
"needsInterop": true
},
"prismjs/components/prism-css": {
"src": "../../prismjs/components/prism-css.js",
"file": "prismjs_components_prism-css.js",
"fileHash": "b1805788",
"fileHash": "b5dc8638",
"needsInterop": true
},
"prismjs/components/prism-javascript": {
"src": "../../prismjs/components/prism-javascript.js",
"file": "prismjs_components_prism-javascript.js",
"fileHash": "c034dce0",
"fileHash": "a3fb501c",
"needsInterop": true
},
"prismjs/components/prism-json": {
"src": "../../prismjs/components/prism-json.js",
"file": "prismjs_components_prism-json.js",
"fileHash": "1379480f",
"fileHash": "2d44f86b",
"needsInterop": true
},
"prismjs/components/prism-python": {
"src": "../../prismjs/components/prism-python.js",
"file": "prismjs_components_prism-python.js",
"fileHash": "fa615091",
"fileHash": "ca5259af",
"needsInterop": true
},
"prismjs/components/prism-sql": {
"src": "../../prismjs/components/prism-sql.js",
"file": "prismjs_components_prism-sql.js",
"fileHash": "31352c1e",
"fileHash": "4a89443c",
"needsInterop": true
},
"vue": {
"src": "../../vue/dist/vue.runtime.esm-bundler.js",
"file": "vue.js",
"fileHash": "7f03e6bd",
"fileHash": "a7d38f14",
"needsInterop": false
},
"katex": {
"src": "../../katex/dist/katex.mjs",
"file": "katex.js",
"fileHash": "d08a8bdf",
"needsInterop": false
}
},

14541
frontend/node_modules/.vite/deps/katex.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

7
frontend/node_modules/.vite/deps/katex.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -9,6 +9,7 @@
"version": "1.0.0",
"dependencies": {
"axios": "^1.5.0",
"katex": "^0.16.22",
"mammoth": "^1.10.0",
"marked": "^16.2.1",
"markmap-lib": "^0.18.12",

View File

@ -9,6 +9,7 @@
},
"dependencies": {
"axios": "^1.5.0",
"katex": "^0.16.22",
"mammoth": "^1.10.0",
"marked": "^16.2.1",
"markmap-lib": "^0.18.12",

View File

@ -710,6 +710,28 @@ Level 4 标题用 #####
// Markdown
const formatMarkdownToText = (markdown) => {
//
if (markdown.includes('|') && markdown.includes('-')) {
const lines = markdown.split('\n');
let hasTableRow = false;
let hasSeparator = false;
for (const line of lines) {
const trimmedLine = line.trim();
if (trimmedLine.includes('|') && trimmedLine.split('|').length >= 3) {
hasTableRow = true;
}
if (trimmedLine.includes('|') && trimmedLine.includes('-') && /^[\s\|\-\:]+$/.test(trimmedLine)) {
hasSeparator = true;
}
}
if (hasTableRow && hasSeparator) {
console.log('🚫 formatMarkdownToText: 检测到表格内容,跳过转换');
return markdown; //
}
}
return markdown
//
.replace(/^### (.*$)/gim, '📋 $1') //

View File

@ -3340,9 +3340,9 @@ const updateMindMapRealtime = async (data, title) => {
maxScale: 5,
minScale: 0.1,
markdown: (text, nodeObj) => {
console.log('🔍 实时更新 Mind Elixir markdown函数被调用:', text.substring(0, 100) + '...');
// markdown
if (text.includes('|') || text.includes('**') || text.includes('`') || text.includes('#')) {
// console.log('🔍 Mind Elixir markdown:', text.substring(0, 100) + '...');
// markdown
if (text.includes('|') || text.includes('**') || text.includes('`') || text.includes('#') || text.includes('$')) {
console.log('🎨 实时更新 检测到markdown内容开始渲染:', text.substring(0, 100) + '...');
const result = smartRenderNodeContent(text);
console.log('🎨 实时更新 渲染结果:', result.substring(0, 200) + '...');

View File

@ -6,11 +6,13 @@
import { marked } from 'marked';
import Prism from 'prismjs';
import katex from 'katex';
import 'prismjs/components/prism-javascript';
import 'prismjs/components/prism-css';
import 'prismjs/components/prism-json';
import 'prismjs/components/prism-python';
import 'prismjs/components/prism-sql';
import 'katex/dist/katex.min.css';
// 配置marked选项
marked.setOptions({
@ -52,9 +54,39 @@ export const renderMarkdownToHTML = (markdown) => {
*/
const preprocessMarkdown = (markdown) => {
return markdown
// 处理数学公式(如果需要的话)
.replace(/\$\$(.*?)\$\$/g, '<div class="math-block">$$$1$$</div>')
.replace(/\$(.*?)\$/g, '<span class="math-inline">$$1$</span>');
// 处理块级数学公式($$...$$
.replace(/\$\$([\s\S]*?)\$\$/g, (match, formula) => {
try {
const rendered = katex.renderToString(formula.trim(), {
displayMode: true,
throwOnError: false
});
return `<div class="math-block">${rendered}</div>`;
} catch (error) {
console.warn('数学公式渲染失败:', error);
return `<div class="math-error">数学公式错误: ${formula}</div>`;
}
})
// 处理行内数学公式($...$),但避免匹配单个$符号
.replace(/\$([^$\n]+?)\$/g, (match, formula) => {
// 检查是否包含LaTeX命令或数学符号
if (formula.includes('\\') || formula.includes('{') || formula.includes('}') ||
formula.includes('^') || formula.includes('_') || formula.includes('=') ||
formula.includes('+') || formula.includes('-') || formula.includes('*') ||
formula.includes('/') || formula.includes('(') || formula.includes(')')) {
try {
const rendered = katex.renderToString(formula.trim(), {
displayMode: false,
throwOnError: false
});
return `<span class="math-inline">${rendered}</span>`;
} catch (error) {
console.warn('数学公式渲染失败:', error);
return `<span class="math-error">数学公式错误: ${formula}</span>`;
}
}
return match; // 如果不包含数学符号,保持原样
});
};
/**
@ -67,10 +99,7 @@ const postprocessHTML = (html) => {
// 为表格添加样式类
.replace(/<table>/g, '<table class="markdown-table">')
// 为代码块添加样式类
.replace(/<pre><code/g, '<pre class="markdown-code"><code')
// 为数学公式添加样式类
.replace(/<div class="math-block">/g, '<div class="math-block markdown-math">')
.replace(/<span class="math-inline">/g, '<span class="math-inline markdown-math">');
.replace(/<pre><code/g, '<pre class="markdown-code"><code');
// 创建临时DOM元素来处理语法高亮
const tempDiv = document.createElement('div');
@ -320,8 +349,27 @@ const addMarkdownStyles = (container) => {
font-style: italic;
}
.markdown-math {
font-family: 'Times New Roman', serif;
.math-block {
text-align: center;
margin: 4px 0;
padding: 4px;
background: #f8f9fa;
border-radius: 4px;
}
.math-inline {
display: inline;
margin: 0 2px;
}
.math-error {
color: #dc3545;
background: #f8d7da;
border: 1px solid #f5c6cb;
padding: 2px 4px;
border-radius: 3px;
font-size: 10px;
font-family: monospace;
}
.markdown-error {
@ -400,6 +448,8 @@ export const hasMarkdownSyntax = (content) => {
/^\s*\d+\.\s+/m, // 有序列表
/\[.*?\]\(.*?\)/, // 链接
/!\[.*?\]\(.*?\)/, // 图片
/\$\$.*?\$\$/, // 块级数学公式
/\$.*?\$/, // 行内数学公式
];
return markdownPatterns.some(pattern => pattern.test(content));