diff --git a/app.js b/app.js
index 5261fed..6b40786 100644
--- a/app.js
+++ b/app.js
@@ -673,6 +673,7 @@ function generateTable() {
theme: document.getElementById('tableTheme').value,
fontSize: parseInt(document.getElementById('tableFontSize').value) || 14,
stripeRows: document.getElementById('stripeRows').checked,
+ borderStyle: document.getElementById('borderStyle').value,
pixelRatio: 2
};
diff --git a/index.html b/index.html
index 6a7eec2..5406976 100644
--- a/index.html
+++ b/index.html
@@ -151,6 +151,22 @@ C, 20, 30, 40
+
+
+
+
+
diff --git a/server.js b/server.js
index 027328e..6089e65 100644
--- a/server.js
+++ b/server.js
@@ -655,7 +655,8 @@ function generateTableImage(params) {
borderWidth = 1,
stripeRows = true,
pixelRatio = 2,
- maxWidth = 1200
+ maxWidth = 1200,
+ borderStyle = 'all' // all, none, no-outer, no-horizontal, no-vertical, no-inner, no-inner-horizontal, no-inner-vertical, outer-only, header-only
} = params;
const tableData = parseTableData(data);
@@ -763,35 +764,50 @@ function generateTableImage(params) {
ctx.strokeStyle = themeConfig.borderColor;
ctx.lineWidth = borderWidth;
- // 外边框(向内偏移半个线宽,确保边框完全在画布内)
- const offset = borderWidth / 2;
- ctx.strokeRect(offset, startY + offset, finalWidth - borderWidth, tableHeight - borderWidth);
+ // 边框样式控制
+ const drawOuter = !['none', 'no-outer', 'no-inner', 'no-inner-horizontal', 'no-inner-vertical', 'header-only'].includes(borderStyle);
+ const drawHorizontal = !['none', 'no-horizontal', 'no-inner', 'no-inner-horizontal', 'outer-only', 'header-only'].includes(borderStyle);
+ const drawVertical = !['none', 'no-vertical', 'no-inner', 'no-inner-vertical', 'outer-only'].includes(borderStyle);
+ const drawHeaderLine = !['none', 'no-horizontal', 'no-inner', 'no-inner-horizontal'].includes(borderStyle);
- // 横线
- ctx.beginPath();
- ctx.moveTo(0, startY + headerHeight);
- ctx.lineTo(finalWidth, startY + headerHeight);
- ctx.stroke();
+ // 外边框
+ if (drawOuter) {
+ const offset = borderWidth / 2;
+ ctx.strokeRect(offset, startY + offset, finalWidth - borderWidth, tableHeight - borderWidth);
+ }
- rows.forEach((_, rowIdx) => {
- const y = startY + headerHeight + (rowIdx + 1) * rowHeight;
+ // 表头分隔线(横线)
+ if (drawHeaderLine) {
ctx.beginPath();
- ctx.moveTo(0, y);
- ctx.lineTo(finalWidth, y);
+ ctx.moveTo(0, startY + headerHeight);
+ ctx.lineTo(finalWidth, startY + headerHeight);
ctx.stroke();
- });
+ }
+
+ // 数据行横线
+ if (drawHorizontal) {
+ rows.forEach((_, rowIdx) => {
+ const y = startY + headerHeight + (rowIdx + 1) * rowHeight;
+ ctx.beginPath();
+ ctx.moveTo(0, y);
+ ctx.lineTo(finalWidth, y);
+ ctx.stroke();
+ });
+ }
// 竖线
- x = 0;
- colWidths.forEach((width, i) => {
- if (i > 0) {
- ctx.beginPath();
- ctx.moveTo(x, startY);
- ctx.lineTo(x, startY + tableHeight);
- ctx.stroke();
- }
- x += width;
- });
+ if (drawVertical) {
+ x = 0;
+ colWidths.forEach((width, i) => {
+ if (i > 0) {
+ ctx.beginPath();
+ ctx.moveTo(x, startY);
+ ctx.lineTo(x, startY + tableHeight);
+ ctx.stroke();
+ }
+ x += width;
+ });
+ }
return canvas;
}
@@ -833,7 +849,8 @@ app.get('/api/table', (req, res) => {
borderWidth: parseInt(req.query.borderWidth) || 1,
stripeRows: req.query.stripeRows !== 'false',
pixelRatio: parseInt(req.query.pixelRatio) || 2,
- maxWidth: parseInt(req.query.maxWidth) || 1200
+ maxWidth: parseInt(req.query.maxWidth) || 1200,
+ borderStyle: req.query.borderStyle || 'all'
};
if (!params.data) {
@@ -951,7 +968,8 @@ app.get('/api/docs', (req, res) => {
borderWidth: { type: 'number', default: 1, description: '边框宽度' },
stripeRows: { type: 'boolean', default: true, description: '是否斑马纹' },
pixelRatio: { type: 'number', default: 2, description: '像素倍率(清晰度)' },
- maxWidth: { type: 'number', default: 1200, description: '最大宽度(px)' }
+ maxWidth: { type: 'number', default: 1200, description: '最大宽度(px)' },
+ borderStyle: { type: 'string', default: 'all', options: ['all', 'none', 'no-outer', 'no-horizontal', 'no-vertical', 'no-inner', 'no-inner-horizontal', 'no-inner-vertical', 'outer-only', 'header-only'], description: '边框样式' }
},
returns: 'image/png',
example: {