paper-burner/tests/test-table-fix-visual-compa...

397 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>表格修复前后对比</title>
<script src="https://cdn.jsdelivr.net/npm/markdown-it@13.0.1/dist/markdown-it.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/marked@4.0.0/marked.min.js"></script>
<script src="js/processing/markdown_processor_ast.js"></script>
<style>
body {
font-family: 'Microsoft YaHei', Arial, sans-serif;
max-width: 1600px;
margin: 20px auto;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
h1 {
text-align: center;
color: white;
font-size: 36px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
margin-bottom: 30px;
}
.comparison-container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin: 20px 0;
}
.panel {
background: white;
border-radius: 12px;
padding: 25px;
box-shadow: 0 8px 16px rgba(0,0,0,0.2);
}
.panel-header {
text-align: center;
font-size: 24px;
font-weight: bold;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
}
.before .panel-header {
background: linear-gradient(135deg, #ff6b6b, #ee5a6f);
color: white;
}
.after .panel-header {
background: linear-gradient(135deg, #51cf66, #37b24d);
color: white;
}
.result-box {
border: 3px solid #dee2e6;
padding: 20px;
border-radius: 8px;
background: #f8f9fa;
margin: 15px 0;
min-height: 200px;
}
.before .result-box {
border-color: #ff6b6b;
}
.after .result-box {
border-color: #51cf66;
}
.result-box table {
width: 100%;
border-collapse: collapse;
margin: 10px 0;
background: white;
}
.result-box th, .result-box td {
border: 1px solid #dee2e6;
padding: 10px;
text-align: left;
}
.result-box th {
background: linear-gradient(135deg, #4c6ef5, #364fc7);
color: white;
font-weight: bold;
}
.result-box tr:nth-child(even) {
background: #f8f9fa;
}
.result-box tr:hover {
background: #e7f5ff;
}
.badge {
display: inline-block;
padding: 8px 16px;
border-radius: 20px;
font-weight: bold;
margin: 10px 5px;
font-size: 14px;
}
.badge-error {
background: #ffe3e3;
color: #c92a2a;
}
.badge-success {
background: #d3f9d8;
color: #2b8a3e;
}
.code-display {
background: #2c3e50;
color: #ecf0f1;
padding: 15px;
border-radius: 8px;
font-family: 'Courier New', monospace;
font-size: 12px;
white-space: pre-wrap;
word-break: break-all;
margin: 15px 0;
max-height: 300px;
overflow-y: auto;
}
.fix-layer {
background: #e7f5ff;
border-left: 4px solid #339af0;
padding: 15px;
margin: 15px 0;
border-radius: 4px;
}
.fix-layer h4 {
color: #1971c2;
margin-top: 0;
}
.fix-layer code {
background: #f1f3f5;
padding: 2px 6px;
border-radius: 3px;
font-family: 'Courier New', monospace;
color: #d9480f;
}
.test-case {
background: white;
border-radius: 12px;
padding: 25px;
margin: 20px 0;
box-shadow: 0 8px 16px rgba(0,0,0,0.2);
}
.test-case h2 {
color: #495057;
border-bottom: 3px solid #dee2e6;
padding-bottom: 10px;
margin-bottom: 20px;
}
.source-markdown {
background: #fff3bf;
border: 2px dashed #fcc419;
padding: 15px;
margin: 15px 0;
border-radius: 8px;
font-family: 'Courier New', monospace;
font-size: 11px;
white-space: pre-wrap;
word-break: break-all;
}
.arrow-down {
text-align: center;
font-size: 48px;
color: white;
margin: 20px 0;
animation: bounce 2s infinite;
}
@keyframes bounce {
0%, 20%, 50%, 80%, 100% {
transform: translateY(0);
}
40% {
transform: translateY(-10px);
}
60% {
transform: translateY(-5px);
}
}
</style>
</head>
<body>
<h1>🔍 表格渲染修复:前后对比</h1>
<div id="output"></div>
<script>
const output = document.getElementById('output');
// 测试表格数据
const compressedTable = `| | | | 五分位数 (Quintiles) | | | |---|---|---|---|---|---|---| | | 1 | 2 | 3 | 4 | 5 | 5-1 | | 市场 (Market) | 0.145*** | 0.200** | 0.061* | 0.136* | 0.106*** | -0.039 | | | (2.774) | (2.441) | (1.938) | (1.689) | (2.703) | (-0.930) | | 规模 (Size) | 0.107** | 0.329* | 0.147** | 0.206** | 0.059*** | 0.047 | | | (2.163) | (1.800) | (2.223) | (2.452) | (3.150) | (1.090) |`;
// ==================== 测试案例 1: Block #31 压缩表格 ====================
const testCase1 = document.createElement('div');
testCase1.className = 'test-case';
testCase1.innerHTML = `
<h2>📊 测试案例Block #31 压缩表格</h2>
<div class="source-markdown"><strong>源 Markdown:</strong><br>${compressedTable.substring(0, 200)}...</div>
`;
output.appendChild(testCase1);
const comparison1 = document.createElement('div');
comparison1.className = 'comparison-container';
// ========== 修复前 ==========
const beforePanel = document.createElement('div');
beforePanel.className = 'panel before';
beforePanel.innerHTML = `
<div class="panel-header">❌ 修复前</div>
<div class="badge badge-error">渲染为 &lt;p&gt; 标签</div>
<div class="badge badge-error">被 sub-block 分割</div>
<div class="badge badge-error">压缩表格未修复</div>
<h3>HTML 结构:</h3>
<div class="code-display">&lt;p data-block-index="31"&gt;
&lt;span class="sub-block" data-sub-block-id="31.0"&gt;
| | | | 五分位数 (Quintiles) | | |
&lt;/span&gt;
&lt;span class="sub-block" data-sub-block-id="31.1"&gt;
|---|---|---|---|---|---|---|
&lt;/span&gt;
&lt;span class="sub-block" data-sub-block-id="31.2"&gt;
| | 1 | 2 | 3 | 4 | 5 | 5-1 |
&lt;/span&gt;
...
&lt;/p&gt;</div>
<h3>浏览器显示:</h3>
<div class="result-box">
<p>| | | | 五分位数 (Quintiles) | | | |---|---|---|---|---|---|---| | | 1 | 2 | 3 | 4 | 5 | 5-1 | | 市场 (Market) | 0.145*** | 0.200** | 0.061* | 0.136* | 0.106*** | -0.039 |</p>
</div>
`;
comparison1.appendChild(beforePanel);
// ========== 修复后 ==========
const afterPanel = document.createElement('div');
afterPanel.className = 'panel after';
// 实际渲染表格
let renderedTable = '';
if (typeof MarkdownProcessorAST !== 'undefined' && MarkdownProcessorAST.render) {
renderedTable = MarkdownProcessorAST.render(compressedTable, {});
} else {
const md = markdownit({ html: true });
renderedTable = md.render(compressedTable);
}
const isTable = renderedTable.trim().startsWith('<table');
afterPanel.innerHTML = `
<div class="panel-header">✅ 修复后</div>
<div class="badge badge-success">渲染为 &lt;table&gt; 标签</div>
<div class="badge badge-success">保持表格完整性</div>
<div class="badge badge-success">压缩表格自动修复</div>
<h3>HTML 结构:</h3>
<div class="code-display">${renderedTable.substring(0, 400).replace(/</g, '&lt;').replace(/>/g, '&gt;')}...</div>
<h3>浏览器显示:</h3>
<div class="result-box">
${renderedTable}
</div>
`;
comparison1.appendChild(afterPanel);
output.appendChild(comparison1);
// ==================== 三层修复机制说明 ====================
const arrow = document.createElement('div');
arrow.className = 'arrow-down';
arrow.innerHTML = '⬇️';
output.appendChild(arrow);
const mechanismSection = document.createElement('div');
mechanismSection.className = 'test-case';
mechanismSection.innerHTML = `
<h2>🛡️ 三层修复机制详解</h2>
<div class="fix-layer">
<h4>🔍 第一层Token 类型检测与强制转换</h4>
<p><strong>问题:</strong><code>marked.lexer()</code> 错误地将表格标记为 paragraph token</p>
<p><strong>解决:</strong>在 <code>renderBatch</code> 中检测表格语法,强制修改 token 类型</p>
<div class="code-display">const hasTableSyntax = /\\|(:?-+:?\\|)+/.test(tokenRaw);
if (tokens[i].type === 'paragraph' && hasTableSyntax) {
console.log('[renderBatch] 检测到 paragraph token 包含表格语法');
tokens[i].type = 'table'; // 强制改为 table 类型
}</div>
</div>
<div class="fix-layer">
<h4>⚙️ 第二层:优先使用 AST 渲染器</h4>
<p><strong>优势:</strong>AST 渲染器支持压缩表格自动修复</p>
<div class="code-display">if (typeof MarkdownProcessorAST !== 'undefined') {
htmlStr = MarkdownProcessorAST.render(tokenRaw, data.images);
// ✓ 自动修复压缩表格
// ✓ 支持表格中的公式
// ✓ 完整的 Markdown 语法支持
}</div>
</div>
<div class="fix-layer">
<h4>🔄 第三层:后验检查与重新渲染</h4>
<p><strong>兜底保护:</strong>如果前两层失败,从 &lt;p&gt; 标签中提取并重新渲染</p>
<div class="code-display">if (hasTableSyntax && htmlStr.trim().startsWith('&lt;p')) {
console.warn('[renderBatch] 渲染后仍然是 &lt;p&gt;,重新渲染');
// 提取 &lt;p&gt; 中的 Markdown 文本
const tableMarkdown = pElement.textContent;
// 重新渲染为表格
htmlStr = MarkdownProcessorAST.render(tableMarkdown);
console.log('[renderBatch] 重新渲染表格成功');
}</div>
</div>
`;
output.appendChild(mechanismSection);
// ==================== 简单测试案例 ====================
const arrow2 = document.createElement('div');
arrow2.className = 'arrow-down';
arrow2.innerHTML = '⬇️';
output.appendChild(arrow2);
const simpleTest = document.createElement('div');
simpleTest.className = 'test-case';
const simpleTable = `| Header A | Header B | Header C |
|----------|----------|----------|
| Data 1 | Data 2 | Data 3 |
| Data 4 | Data 5 | Data 6 |`;
let simpleRendered = '';
if (typeof MarkdownProcessorAST !== 'undefined' && MarkdownProcessorAST.render) {
simpleRendered = MarkdownProcessorAST.render(simpleTable, {});
}
simpleTest.innerHTML = `
<h2>📋 测试案例:普通多行表格</h2>
<div class="source-markdown"><strong>源 Markdown:</strong><br>${simpleTable}</div>
<h3>渲染结果:</h3>
<div class="result-box after">
${simpleRendered}
</div>
<div class="badge badge-success">✓ 正确渲染为 &lt;table&gt;</div>
`;
output.appendChild(simpleTest);
// ==================== 验证清单 ====================
const checklistSection = document.createElement('div');
checklistSection.className = 'test-case';
checklistSection.innerHTML = `
<h2>✅ 验证清单</h2>
<div style="font-size: 16px; line-height: 2;">
<div>✓ <strong>压缩表格</strong>:单行表格自动展开为多行格式</div>
<div>✓ <strong>表格完整性</strong>:不被 sub-block 分割</div>
<div>✓ <strong>正确渲染</strong>:显示为 &lt;table&gt; 元素而非 &lt;p&gt;</div>
<div>✓ <strong>样式显示</strong>:带有边框、表头背景色</div>
<div>✓ <strong>公式支持</strong>:表格内的公式正确渲染</div>
<div>✓ <strong>性能优化</strong>:批量渲染,不阻塞 UI</div>
</div>
<h3 style="margin-top: 30px;">🚀 下一步操作</h3>
<ol style="font-size: 16px; line-height: 2;">
<li>在实际应用中按 <code style="background:#f1f3f5;padding:2px 8px;border-radius:3px;">Ctrl + Shift + R</code> 清除缓存并刷新</li>
<li>打开浏览器开发者工具F12查看控制台日志</li>
<li>检查 Block #31 是否正确渲染为表格</li>
<li>验证表格中的公式和特殊符号显示正常</li>
</ol>
`;
output.appendChild(checklistSection);
</script>
</body>
</html>