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) <noreply@anthropic.com>
This commit is contained in:
@@ -343,9 +343,11 @@ const ReactTableTooltip = ({ content }: { content: string }) => {
|
||||
const textRef = useRef<HTMLDivElement>(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 <div>{content}</div>;
|
||||
return (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-full border-collapse border border-gray-300">
|
||||
<tbody>
|
||||
{rows.map((row, rowIndex) => (
|
||||
<tr key={`row-${rowIndex}`}>
|
||||
{row.map((cell, cellIndex) => (
|
||||
<td
|
||||
key={`cell-${rowIndex}-${cellIndex}`}
|
||||
className="px-2 py-1 border border-gray-300 text-xs text-left"
|
||||
>
|
||||
{cell || ' '}
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Pipe表格渲染错误:', error);
|
||||
return <div>{content}</div>;
|
||||
}
|
||||
};
|
||||
|
||||
// 渲染React表格(tab分隔)
|
||||
const renderReactTable = (text: string) => {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user