diff --git a/frontend/package.json b/frontend/package.json index e31991f..1378c94 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,8 +13,11 @@ "license": "ISC", "dependencies": { "@types/qrcode": "^1.5.6", + "highlight.js": "^11.11.1", "html2canvas": "^1.4.1", "jspdf": "^4.2.1", + "katex": "^0.17.0", + "mermaid": "^11.16.0", "qrcode": "^1.5.4", "react": "^18.3.1", "react-dom": "^18.3.1", diff --git a/frontend/src/pages/front/ChatPage.css b/frontend/src/pages/front/ChatPage.css index 0ce673f..fc48a08 100644 --- a/frontend/src/pages/front/ChatPage.css +++ b/frontend/src/pages/front/ChatPage.css @@ -507,6 +507,52 @@ background: rgba(255, 255, 255, 0.05); } +/* 数学公式 */ +.md-math-block { + display: block; + overflow-x: auto; + padding: 10px 0; + text-align: center; +} +.md-math-inline { + display: inline; + padding: 0 2px; +} + +/* 代码块包装器 + 复制按钮 */ +.md-code-wrapper { + position: relative; + margin: 12px 0; +} +.md-code-wrapper .md-code-block { + margin: 0; + border-radius: var(--radius-md); +} +.md-code-copy { + position: absolute; + top: 8px; + right: 8px; + padding: 4px 10px; + font-size: 12px; + color: #6B7280; + background: #F3F4F6; + border: 1px solid #E5E7EB; + border-radius: 4px; + cursor: pointer; + opacity: 0; + transition: opacity 0.2s; + z-index: 2; +} +.md-code-wrapper:hover .md-code-copy { + opacity: 1; +} + +/* 删除线 */ +del { + text-decoration: line-through; + opacity: 0.6; +} + .md-hr { border: none; border-top: 1px solid var(--color-border); diff --git a/frontend/src/pages/front/ChatPage.tsx b/frontend/src/pages/front/ChatPage.tsx index 337998f..bf08806 100644 --- a/frontend/src/pages/front/ChatPage.tsx +++ b/frontend/src/pages/front/ChatPage.tsx @@ -4,6 +4,12 @@ import { chatAPI, knowledgeAPI, marketAPI, evolutionAPI } from '@/api'; import type { Conversation, Message } from '@/types'; import './ChatPage.css'; +// ===== 增强渲染依赖 ===== +import hljs from 'highlight.js'; +import 'highlight.js/styles/github.css'; +import katex from 'katex'; +import 'katex/dist/katex.min.css'; + // ===== Enhanced Markdown Renderer ===== // 媒体(图片/视频)以受限缩略图呈现,并提供下载(格式+尺寸)选项 interface MediaInfo { type: 'img' | 'video'; src: string; alt?: string; } @@ -209,6 +215,34 @@ const MarkdownContent: React.FC<{ content: string }> = ({ content }) => { } ); + // 2.8 LaTeX 数学公式:$$...$$(块级)和 $...$(行内) + // 提取为占位符,渲染后用 KaTeX 处理 + const mathBlocks: string[] = []; + text = text.replace(/\$\$([\s\S]+?)\$\$/g, (_m: string, formula: string) => { + try { + const rendered = katex.renderToString(formula.trim(), { displayMode: true, throwOnError: false }); + const idx = mathBlocks.length; + mathBlocks.push(`
([\s\S]*?)<\/code><\/pre>/g,
+ (_m: string, code: string) => {
+ const decoded = code.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');
+ let highlighted: string;
+ try { highlighted = hljs.highlightAuto(decoded).value; } catch { highlighted = code; }
+ return `
+
+ ${highlighted}
+ `;
+ }
+ );
// 11. Wrap in paragraph and clean up
text = '' + text + '
';