From 93b8673363b3e1af3a0de154ed0b14f9c2e30e5f Mon Sep 17 00:00:00 2001 From: wren Date: Mon, 23 Mar 2026 19:30:44 +0800 Subject: [PATCH] fix(ui): handle single-line markdown tables and pipe-delimited tables - parseMarkdownTable now handles tables stored as single line by counting columns from separator row and grouping cells accordingly - Added isPipeTable detection for pipe-delimited data without header (e.g., "1 | name | qty\n2 | name | qty") - Added renderPipeTable for headerless pipe tables Co-Authored-By: Claude Opus 4.6 (1M context) --- app/components/reviews/ReviewPointsList.tsx | 83 ++++++++++++++++++--- 1 file changed, 72 insertions(+), 11 deletions(-) diff --git a/app/components/reviews/ReviewPointsList.tsx b/app/components/reviews/ReviewPointsList.tsx index b11feba..c3c2428 100644 --- a/app/components/reviews/ReviewPointsList.tsx +++ b/app/components/reviews/ReviewPointsList.tsx @@ -343,9 +343,11 @@ const ReactTableTooltip = ({ content }: { content: string }) => { const textRef = useRef(null); const isTabTable = content.includes('\t') && content.includes('\n'); - // 检测 markdown 表格:至少有 | 分隔符和分隔行 |---| + // 检测 markdown 表格:有 |---| 分隔行,或 pipe 分隔 + 换行(无表头的 pipe 表格) const isMdTable = content.includes('|') && /\|[-\s:]+\|/.test(content); - const isTableLike = isTabTable || isMdTable; + const isPipeTable = !isMdTable && content.includes('|') && content.includes('\n') + && content.split('\n').filter(l => l.includes('|')).length >= 2; + const isTableLike = isTabTable || isMdTable || isPipeTable; useEffect(() => { const checkTextOverflow = () => { @@ -359,6 +361,8 @@ const ReactTableTooltip = ({ content }: { content: string }) => { // 预渲染内容并缓存 if (isMdTable) { setRenderedContent(renderMarkdownTable(content)); + } else if (isPipeTable) { + setRenderedContent(renderPipeTable(content)); } else if (isTabTable) { setRenderedContent(renderReactTable(content)); } else { @@ -378,17 +382,41 @@ const ReactTableTooltip = ({ content }: { content: string }) => { return rows; }; - // 解析 markdown 表格 + // 解析 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); + + // 多行格式:有多行且包含分隔行 + if (lines.length > 2) { + 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); + } + if (rows.length > 1) return rows; + } + + // 单行格式:整个表格在一行内,通过分隔行 |---|---| 来拆分 + const sepMatch = text.match(/\|[\s-:]+(?:\|[\s-:]+)+\|/); + if (!sepMatch) return []; + + const colCount = (sepMatch[0].match(/---/g) || []).length; + if (colCount === 0) return []; + + const sepIdx = text.indexOf(sepMatch[0]); + const headerPart = text.substring(0, sepIdx); + const bodyPart = text.substring(sepIdx + sepMatch[0].length); + + // 解析 header + const headerCells = headerPart.split('|').map(c => c.trim()).filter(c => c); + // 解析 body:按 | 分割后每 colCount 个cell为一行 + const bodyCells = bodyPart.split('|').map(c => c.trim()).filter(c => c); + const rows: string[][] = [headerCells]; + for (let i = 0; i < bodyCells.length; i += colCount) { + const row = bodyCells.slice(i, i + colCount); + if (row.length > 0) rows.push(row); } return rows; }; @@ -437,6 +465,39 @@ const ReactTableTooltip = ({ content }: { content: string }) => { } }; + // 渲染 pipe 分隔表格(无表头,如 "1 | 名称 | 项 | 1\n2 | ...") + const renderPipeTable = (text: string) => { + try { + const rows = text.split('\n') + .filter(l => l.trim() && l.includes('|')) + .map(line => line.split('|').map(c => c.trim())); + if (rows.length === 0) return
{content}
; + return ( +
+ + + {rows.map((row, rowIndex) => ( + + {row.map((cell, cellIndex) => ( + + ))} + + ))} + +
+ {cell || ' '} +
+
+ ); + } catch (error) { + console.error('Pipe表格渲染错误:', error); + return
{content}
; + } + }; + // 渲染React表格(tab分隔) const renderReactTable = (text: string) => { try {