feat: 新增表格图片生成功能

- 新增 POST/GET /api/table 接口
- 支持5种主题风格、自定义字体大小、斑马纹等
- 前端新增图表/表格模式切换
- 完美支持中文内容显示(Noto Sans CJK SC)
- 更新 API 文档和 README
This commit is contained in:
2026-07-17 12:40:47 +08:00
parent 02212e9ef7
commit e2f9892a2a
5 changed files with 657 additions and 14 deletions
+113
View File
@@ -3,6 +3,8 @@ let chartInstance = null;
let parsedData = null;
let seriesColors = [];
let seriesOrder = [];
let currentMode = 'chart'; // 'chart' or 'table'
let tableImageBlob = null;
// ===== 预设颜色方案 =====
const colorPalettes = {
@@ -605,3 +607,114 @@ function exportChart(format) {
svgChart.dispose();
}
}
// ===== 模式切换 =====
function switchMode(mode) {
currentMode = mode;
// 更新按钮状态
document.getElementById('btnChartMode').classList.toggle('active', mode === 'chart');
document.getElementById('btnTableMode').classList.toggle('active', mode === 'table');
// 显示/隐藏配置区
document.getElementById('chartConfigSection').style.display = mode === 'chart' ? 'block' : 'none';
document.getElementById('tableConfigSection').style.display = mode === 'table' ? 'block' : 'none';
document.getElementById('seriesConfigSection').style.display = mode === 'chart' ? 'block' : 'none';
document.getElementById('splitConfigSection').style.display = mode === 'chart' ? 'block' : 'none';
// 更新生成按钮
const btnGenerate = document.getElementById('btnGenerate');
btnGenerate.textContent = mode === 'chart' ? '🎨 生成图表' : '📋 生成表格';
// 更新导出按钮
const btnExportSvg = document.getElementById('btnExportSvg');
btnExportSvg.style.display = mode === 'chart' ? 'inline-flex' : 'none';
// 重新生成
generate();
}
// ===== 统一生成入口 =====
function generate() {
if (currentMode === 'chart') {
generateChart();
} else {
generateTable();
}
}
// ===== 更新字体大小显示 =====
function updateFontSize() {
const val = document.getElementById('tableFontSize').value;
document.getElementById('fontSizeValue').textContent = val;
}
// ===== 生成表格 =====
function generateTable() {
const rawText = document.getElementById('dataInput').value;
if (!rawText.trim()) {
alert('请输入数据');
return;
}
const params = {
data: rawText,
title: document.getElementById('tableTitle').value,
theme: document.getElementById('tableTheme').value,
fontSize: parseInt(document.getElementById('tableFontSize').value) || 14,
stripeRows: document.getElementById('stripeRows').checked,
pixelRatio: 2
};
const chartArea = document.getElementById('chartArea');
chartArea.innerHTML = '<div class="placeholder"><p>⏳</p><p>正在生成表格...</p></div>';
fetch('/api/table', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(params)
})
.then(res => {
if (!res.ok) throw new Error('表格生成失败');
return res.blob();
})
.then(blob => {
tableImageBlob = blob;
const url = URL.createObjectURL(blob);
chartArea.innerHTML = `<div class="table-preview"><img src="${url}" alt="表格预览"></div>`;
})
.catch(err => {
chartArea.innerHTML = `<div class="placeholder"><p>❌</p><p>${err.message}</p></div>`;
});
}
// ===== 更新表格(配置变更时) =====
function updateTable() {
if (currentMode === 'table' && document.getElementById('dataInput').value.trim()) {
generateTable();
}
}
// ===== 统一导出图片 =====
function exportImage(format) {
if (currentMode === 'chart') {
exportChart(format);
} else {
exportTable(format);
}
}
// ===== 导出表格 =====
function exportTable(format) {
if (!tableImageBlob) {
alert('请先生成表格');
return;
}
const url = URL.createObjectURL(tableImageBlob);
const a = document.createElement('a');
a.href = url;
a.download = 'table.png';
a.click();
URL.revokeObjectURL(url);
}