From d0124b012151202a90d02697aadcc1f1163eccbd Mon Sep 17 00:00:00 2001 From: wren Date: Mon, 23 Mar 2026 19:19:53 +0800 Subject: [PATCH] feat(ui): support markdown table rendering in evaluation field values ReactTableTooltip now detects and renders markdown tables (| delimited) in addition to existing tab-delimited tables. Table content is rendered directly as an HTML table instead of showing raw markdown text. Co-Authored-By: Claude Opus 4.6 (1M context) --- app/components/reviews/ReviewPointsList.tsx | 101 +++++++++++++++++--- 1 file changed, 87 insertions(+), 14 deletions(-) diff --git a/app/components/reviews/ReviewPointsList.tsx b/app/components/reviews/ReviewPointsList.tsx index 69b5937..b11feba 100644 --- a/app/components/reviews/ReviewPointsList.tsx +++ b/app/components/reviews/ReviewPointsList.tsx @@ -341,9 +341,12 @@ const ReactTableTooltip = ({ content }: { content: string }) => { const [showTooltip, setShowTooltip] = useState(false); const [renderedContent, setRenderedContent] = useState(null); const textRef = useRef(null); - - const isTableLike = content.includes('\t') && content.includes('\n'); - + + const isTabTable = content.includes('\t') && content.includes('\n'); + // 检测 markdown 表格:至少有 | 分隔符和分隔行 |---| + const isMdTable = content.includes('|') && /\|[-\s:]+\|/.test(content); + const isTableLike = isTabTable || isMdTable; + useEffect(() => { const checkTextOverflow = () => { const element = textRef.current; @@ -352,33 +355,94 @@ const ReactTableTooltip = ({ content }: { content: string }) => { setShowTooltip(isTableLike || element.scrollHeight > element.clientHeight); } }; - + // 预渲染内容并缓存 - if (isTableLike) { + if (isMdTable) { + setRenderedContent(renderMarkdownTable(content)); + } else if (isTabTable) { setRenderedContent(renderReactTable(content)); } else { setRenderedContent(content); } - + requestAnimationFrame(checkTextOverflow); window.addEventListener('resize', checkTextOverflow); return () => { window.removeEventListener('resize', checkTextOverflow); }; }, [content, isTableLike]); - - // 解析表格数据 + + // 解析表格数据(tab分隔) const parseTableData = (text: string) => { const rows = text.split('\n').map(row => row.split('\t')); return rows; }; - - // 渲染React表格 + + // 解析 markdown 表格 + const parseMarkdownTable = (text: string): string[][] => { + const lines = text.split('\n').filter(l => l.trim()); + const rows: string[][] = []; + for (const line of lines) { + // 跳过分隔行 |---|---| + if (/^\s*\|[-\s:]+\|/.test(line)) continue; + const cells = line.split('|') + .map(c => c.trim()) + .filter((_, i, arr) => i > 0 && i < arr.length); // 去掉首尾空元素 + if (cells.length > 0) rows.push(cells); + } + return rows; + }; + + // 渲染 markdown 表格 + const renderMarkdownTable = (text: string) => { + try { + const tableData = parseMarkdownTable(text); + if (tableData.length === 0) return content; + + return ( +
+ + + + {tableData[0].map((cell, cellIndex) => ( + + ))} + + + + {tableData.slice(1).map((row, rowIndex) => ( + + {row.map((cell, cellIndex) => ( + + ))} + + ))} + +
+ {cell || ' '} +
+ {cell || ' '} +
+
+ ); + } catch (error) { + console.error('Markdown表格渲染错误:', error); + return
{content}
; + } + }; + + // 渲染React表格(tab分隔) const renderReactTable = (text: string) => { try { const tableData = parseTableData(text); const hasHeader = tableData.length > 0; - + return (
@@ -386,7 +450,7 @@ const ReactTableTooltip = ({ content }: { content: string }) => { {tableData[0].map((cell, cellIndex) => ( - {row.map((cell, cellIndex) => ( -
@@ -400,7 +464,7 @@ const ReactTableTooltip = ({ content }: { content: string }) => { {tableData.slice(1).map((row, rowIndex) => (
@@ -421,10 +485,19 @@ const ReactTableTooltip = ({ content }: { content: string }) => { + // 表格内容直接渲染表格组件,非表格内容保持原有行为 + if (isTableLike) { + return ( +
+ {renderedContent} +
+ ); + } + return (
{showTooltip ? ( -