export-to-exceljs-util 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +8 -210
- package/package.json +1 -1
- package/utils/index.js +198 -0
package/index.js
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
import { saveAs } from "file-saver";
|
2
|
-
import { retainTitleAndKey } from './utils/index.js'
|
3
2
|
import DefaultExport from "./defaultExport.js";
|
3
|
+
import { workerUrl, retainTitleAndKey } from "./utils/index";
|
4
4
|
|
5
|
-
class
|
5
|
+
class ExcelExporter1 {
|
6
6
|
constructor(columns, data, filename = "导出数据.xlsx", describe = []) {
|
7
7
|
this.columns = columns;
|
8
8
|
this.data = data;
|
@@ -22,217 +22,15 @@ class ExcelExporter {
|
|
22
22
|
}
|
23
23
|
}
|
24
24
|
|
25
|
-
// Web Worker 脚本代码存储在变量 workerScript 中
|
26
25
|
async exportLargeDataSet() {
|
27
|
-
const workerScript = `
|
28
|
-
importScripts("https://cdn.bootcdn.net/ajax/libs/exceljs/4.4.0/exceljs.min.js");
|
29
|
-
const fontStyle = {
|
30
|
-
name: "Arial",
|
31
|
-
size: 10,
|
32
|
-
bold: true, // 设置文字加粗
|
33
|
-
color: { argb: "FF000000" },
|
34
|
-
};
|
35
|
-
const alignmentStyle = (vertical = "middle", horizontal = "center") => {
|
36
|
-
return {
|
37
|
-
vertical,
|
38
|
-
horizontal,
|
39
|
-
};
|
40
|
-
};
|
41
|
-
|
42
|
-
const borderStyle = {
|
43
|
-
top: { style: "thin" },
|
44
|
-
left: { style: "thin" },
|
45
|
-
bottom: { style: "thin" },
|
46
|
-
right: { style: "thin" },
|
47
|
-
};
|
48
|
-
|
49
|
-
function generateHeaders(
|
50
|
-
worksheet,
|
51
|
-
columns,
|
52
|
-
rowIndex = 1,
|
53
|
-
colIndexStart = 1,
|
54
|
-
maxDepth = null
|
55
|
-
) {
|
56
|
-
let maxRowIndex = rowIndex;
|
57
|
-
let colIndex = colIndexStart;
|
58
|
-
|
59
|
-
// 计算整个表头的最大深度(用于单级表头行合并)
|
60
|
-
if (maxDepth === null) {
|
61
|
-
maxDepth = getMaxDepth(columns);
|
62
|
-
}
|
63
|
-
|
64
|
-
columns.forEach((column) => {
|
65
|
-
const currentRowIndex = rowIndex;
|
66
|
-
const currentColIndex = colIndex;
|
67
|
-
|
68
|
-
// 计算列的跨度和行的跨度
|
69
|
-
const colSpan = getColSpan(column);
|
70
|
-
const rowSpan = getRowSpan(column, maxDepth - rowIndex + 1);
|
71
|
-
|
72
|
-
// 设置表头单元格值并应用样式
|
73
|
-
const cell = worksheet.getCell(currentRowIndex, currentColIndex);
|
74
|
-
cell.value = column.title;
|
75
|
-
cell.alignment = alignmentStyle();
|
76
|
-
cell.border = borderStyle;
|
77
|
-
cell.font = fontStyle;
|
78
|
-
cell.fill = {
|
79
|
-
type: "pattern",
|
80
|
-
pattern: "solid",
|
81
|
-
fgColor: { argb: "87CEEB" },
|
82
|
-
};
|
83
|
-
|
84
|
-
// 合并单元格处理
|
85
|
-
if (colSpan > 1) {
|
86
|
-
worksheet.mergeCells(
|
87
|
-
currentRowIndex,
|
88
|
-
currentColIndex,
|
89
|
-
currentRowIndex,
|
90
|
-
currentColIndex + colSpan - 1
|
91
|
-
);
|
92
|
-
}
|
93
|
-
|
94
|
-
// 处理跨行合并的情况
|
95
|
-
if (rowSpan > 1) {
|
96
|
-
worksheet.mergeCells(
|
97
|
-
currentRowIndex,
|
98
|
-
currentColIndex,
|
99
|
-
currentRowIndex + rowSpan - 1,
|
100
|
-
currentColIndex
|
101
|
-
);
|
102
|
-
}
|
103
|
-
|
104
|
-
// 处理子列
|
105
|
-
if (column.children && column.children.length > 0) {
|
106
|
-
const childMaxRowIndex = generateHeaders(
|
107
|
-
worksheet,
|
108
|
-
column.children,
|
109
|
-
currentRowIndex + 1,
|
110
|
-
currentColIndex,
|
111
|
-
maxDepth
|
112
|
-
);
|
113
|
-
maxRowIndex = Math.max(maxRowIndex, childMaxRowIndex);
|
114
|
-
} else {
|
115
|
-
maxRowIndex = Math.max(maxRowIndex, currentRowIndex + rowSpan - 1);
|
116
|
-
}
|
117
|
-
|
118
|
-
colIndex += colSpan;
|
119
|
-
});
|
120
|
-
|
121
|
-
return maxRowIndex;
|
122
|
-
}
|
123
|
-
|
124
|
-
function getColSpan(column) {
|
125
|
-
if (!column.children || column.children.length === 0) {
|
126
|
-
return 1;
|
127
|
-
}
|
128
|
-
return column.children.reduce((sum, child) => sum + getColSpan(child), 0);
|
129
|
-
}
|
130
|
-
|
131
|
-
function getRowSpan(column, remainingDepth) {
|
132
|
-
if (!column.children || column.children.length === 0) {
|
133
|
-
return remainingDepth;
|
134
|
-
}
|
135
|
-
return 1;
|
136
|
-
}
|
137
|
-
|
138
|
-
function getMaxDepth(columns) {
|
139
|
-
return columns.reduce((max, column) => {
|
140
|
-
const depth = column.children ? 1 + getMaxDepth(column.children) : 1;
|
141
|
-
return Math.max(max, depth);
|
142
|
-
}, 1);
|
143
|
-
}
|
144
|
-
|
145
|
-
function fillData(worksheet, data, columns) {
|
146
|
-
data.forEach((rowData) => {
|
147
|
-
const row = worksheet.addRow(
|
148
|
-
columns.flatMap((col) => extractValues(rowData, col))
|
149
|
-
);
|
150
|
-
row.eachCell((cell) => {
|
151
|
-
cell.alignment = alignmentStyle();
|
152
|
-
});
|
153
|
-
});
|
154
|
-
}
|
155
|
-
|
156
|
-
function autoFitColumns(worksheet) {
|
157
|
-
worksheet.columns.forEach((column) => {
|
158
|
-
let maxLength = 0;
|
159
|
-
column.eachCell({ includeEmpty: true }, (cell) => {
|
160
|
-
const columnLength = cell.value ? cell.value.toString().length : 10;
|
161
|
-
if (columnLength > maxLength) {
|
162
|
-
maxLength = columnLength;
|
163
|
-
}
|
164
|
-
});
|
165
|
-
column.width = maxLength < 10 ? maxLength + 5 : maxLength;
|
166
|
-
});
|
167
|
-
}
|
168
|
-
|
169
|
-
function generateDescribe(worksheet, describe, data) {
|
170
|
-
if (describe) {
|
171
|
-
console.log('describe',describe);
|
172
|
-
// 定义开始的位置
|
173
|
-
const startCell = data.length + 7;
|
174
|
-
const endCell = startCell + 9;
|
175
|
-
|
176
|
-
// 合并单元格的范围
|
177
|
-
const mergeStart = 'A' + startCell;
|
178
|
-
const mergeEnd = 'E' + endCell;
|
179
|
-
worksheet.mergeCells(mergeStart + ':' + mergeEnd);
|
180
|
-
|
181
|
-
// 在表格底部加上文字解释
|
182
|
-
let combinedText = describe
|
183
|
-
const mergedCells = [
|
184
|
-
'A' + startCell,
|
185
|
-
'B' + startCell,
|
186
|
-
'C' + startCell,
|
187
|
-
'D' + startCell,
|
188
|
-
'E' + startCell,
|
189
|
-
];
|
190
|
-
|
191
|
-
// 设置每个合并单元格的自动换行属性
|
192
|
-
mergedCells.forEach(function(cell) {
|
193
|
-
const currentCell = worksheet.getCell(cell);
|
194
|
-
currentCell.value = combinedText;
|
195
|
-
currentCell.font = fontStyle;
|
196
|
-
currentCell.alignment = {
|
197
|
-
vertical: "top",
|
198
|
-
horizontal: "left",
|
199
|
-
wrapText: true // 设置自动换行
|
200
|
-
};
|
201
|
-
});
|
202
|
-
worksheet.getCell(mergeStart).border = borderStyle;
|
203
|
-
}
|
204
|
-
}
|
205
|
-
|
206
|
-
function extractValues(rowData, column) {
|
207
|
-
if (column.children && column.children.length > 0) {
|
208
|
-
return column.children.flatMap((child) => extractValues(rowData, child));
|
209
|
-
} else {
|
210
|
-
return [rowData[column.key]];
|
211
|
-
}
|
212
|
-
}
|
213
|
-
self.onmessage = async function (e) {
|
214
|
-
const { data, columns, describe, filename } = e.data;
|
215
|
-
const workbook = new ExcelJS.Workbook();
|
216
|
-
const worksheet = workbook.addWorksheet("Sheet1");
|
217
|
-
generateHeaders(worksheet, columns);
|
218
|
-
fillData(worksheet, data, columns);
|
219
|
-
generateDescribe(worksheet, describe, data);
|
220
|
-
const buffer = await workbook.xlsx.writeBuffer();
|
221
|
-
self.postMessage({ buffer, filename });
|
222
|
-
};`;
|
223
|
-
|
224
|
-
// 创建 Blob 对象
|
225
|
-
const blob = new Blob([workerScript], { type: "text/javascript" });
|
226
|
-
|
227
|
-
// 创建指向 Blob 的 URL
|
228
|
-
const workerUrl = URL.createObjectURL(blob);
|
229
26
|
|
230
27
|
// 创建 Web Worker 实例
|
231
28
|
const writeBufferWorker = new Worker(workerUrl);
|
232
29
|
|
233
|
-
//
|
234
|
-
|
30
|
+
// 格式化数组数据
|
235
31
|
const formatColumns = retainTitleAndKey(this.columns);
|
32
|
+
|
33
|
+
// 发送数据到 Web Worker
|
236
34
|
writeBufferWorker.postMessage({
|
237
35
|
columns: formatColumns,
|
238
36
|
data: this.data,
|
@@ -240,14 +38,14 @@ class ExcelExporter {
|
|
240
38
|
filename: this.filename,
|
241
39
|
});
|
242
40
|
|
41
|
+
// 监听 Web Worker 的消息
|
243
42
|
writeBufferWorker.onmessage = (e) => {
|
244
43
|
const { buffer, filename } = e.data;
|
245
44
|
const blob = new Blob([buffer], { type: "application/octet-stream" });
|
45
|
+
// 下载文件
|
246
46
|
saveAs(blob, filename);
|
247
|
-
|
248
47
|
// 释放对象 URL
|
249
48
|
URL.revokeObjectURL(workerUrl);
|
250
|
-
|
251
49
|
// 终止 Web Worker
|
252
50
|
writeBufferWorker.terminate();
|
253
51
|
};
|
@@ -268,4 +66,4 @@ class ExcelExporter {
|
|
268
66
|
}
|
269
67
|
}
|
270
68
|
|
271
|
-
export default
|
69
|
+
export default ExcelExporter1;
|
package/package.json
CHANGED
package/utils/index.js
CHANGED
@@ -21,3 +21,201 @@ export function retainTitleAndKey(items) {
|
|
21
21
|
return item;
|
22
22
|
});
|
23
23
|
}
|
24
|
+
|
25
|
+
function getworkerUrl() {
|
26
|
+
const workerScript = `
|
27
|
+
importScripts("https://cdn.bootcdn.net/ajax/libs/exceljs/4.4.0/exceljs.min.js");
|
28
|
+
const fontStyle = {
|
29
|
+
name: "Arial",
|
30
|
+
size: 10,
|
31
|
+
bold: true, // 设置文字加粗
|
32
|
+
color: { argb: "FF000000" },
|
33
|
+
};
|
34
|
+
const alignmentStyle = (vertical = "middle", horizontal = "center") => {
|
35
|
+
return {
|
36
|
+
vertical,
|
37
|
+
horizontal,
|
38
|
+
};
|
39
|
+
};
|
40
|
+
|
41
|
+
const borderStyle = {
|
42
|
+
top: { style: "thin" },
|
43
|
+
left: { style: "thin" },
|
44
|
+
bottom: { style: "thin" },
|
45
|
+
right: { style: "thin" },
|
46
|
+
};
|
47
|
+
|
48
|
+
function generateHeaders(worksheet, columns, rowIndex = 1, colIndexStart = 1, maxDepth = null) {
|
49
|
+
let maxRowIndex = rowIndex;
|
50
|
+
let colIndex = colIndexStart;
|
51
|
+
|
52
|
+
// 计算整个表头的最大深度(用于单级表头行合并)
|
53
|
+
if (maxDepth === null) {
|
54
|
+
maxDepth = getMaxDepth(columns);
|
55
|
+
}
|
56
|
+
|
57
|
+
columns.forEach((column) => {
|
58
|
+
const currentRowIndex = rowIndex;
|
59
|
+
const currentColIndex = colIndex;
|
60
|
+
|
61
|
+
// 计算列的跨度和行的跨度
|
62
|
+
const colSpan = getColSpan(column);
|
63
|
+
const rowSpan = getRowSpan(column, maxDepth - rowIndex + 1);
|
64
|
+
|
65
|
+
// 设置表头单元格值并应用样式
|
66
|
+
const cell = worksheet.getCell(currentRowIndex, currentColIndex);
|
67
|
+
cell.value = column.title;
|
68
|
+
cell.alignment = alignmentStyle();
|
69
|
+
cell.border = borderStyle;
|
70
|
+
cell.font = fontStyle;
|
71
|
+
cell.fill = {
|
72
|
+
type: "pattern",
|
73
|
+
pattern: "solid",
|
74
|
+
fgColor: { argb: "87CEEB" },
|
75
|
+
};
|
76
|
+
|
77
|
+
// 合并单元格处理
|
78
|
+
if (colSpan > 1) {
|
79
|
+
worksheet.mergeCells(
|
80
|
+
currentRowIndex,
|
81
|
+
currentColIndex,
|
82
|
+
currentRowIndex,
|
83
|
+
currentColIndex + colSpan - 1
|
84
|
+
);
|
85
|
+
}
|
86
|
+
|
87
|
+
// 处理跨行合并的情况
|
88
|
+
if (rowSpan > 1) {
|
89
|
+
worksheet.mergeCells(
|
90
|
+
currentRowIndex,
|
91
|
+
currentColIndex,
|
92
|
+
currentRowIndex + rowSpan - 1,
|
93
|
+
currentColIndex
|
94
|
+
);
|
95
|
+
}
|
96
|
+
|
97
|
+
// 处理子列
|
98
|
+
if (column.children && column.children.length > 0) {
|
99
|
+
const childMaxRowIndex = generateHeaders(
|
100
|
+
worksheet,
|
101
|
+
column.children,
|
102
|
+
currentRowIndex + 1,
|
103
|
+
currentColIndex,
|
104
|
+
maxDepth
|
105
|
+
);
|
106
|
+
maxRowIndex = Math.max(maxRowIndex, childMaxRowIndex);
|
107
|
+
} else {
|
108
|
+
maxRowIndex = Math.max(maxRowIndex, currentRowIndex + rowSpan - 1);
|
109
|
+
}
|
110
|
+
|
111
|
+
colIndex += colSpan;
|
112
|
+
});
|
113
|
+
|
114
|
+
return maxRowIndex;
|
115
|
+
}
|
116
|
+
|
117
|
+
function getColSpan(column) {
|
118
|
+
if (!column.children || column.children.length === 0) {
|
119
|
+
return 1;
|
120
|
+
}
|
121
|
+
return column.children.reduce((sum, child) => sum + getColSpan(child), 0);
|
122
|
+
}
|
123
|
+
|
124
|
+
function getRowSpan(column, remainingDepth) {
|
125
|
+
if (!column.children || column.children.length === 0) {
|
126
|
+
return remainingDepth;
|
127
|
+
}
|
128
|
+
return 1;
|
129
|
+
}
|
130
|
+
|
131
|
+
function getMaxDepth(columns) {
|
132
|
+
return columns.reduce((max, column) => {
|
133
|
+
const depth = column.children ? 1 + getMaxDepth(column.children) : 1;
|
134
|
+
return Math.max(max, depth);
|
135
|
+
}, 1);
|
136
|
+
}
|
137
|
+
|
138
|
+
function fillData(worksheet, data, columns) {
|
139
|
+
const rows = data.map((rowData) =>
|
140
|
+
columns.flatMap((col) => extractValues(rowData, col))
|
141
|
+
);
|
142
|
+
worksheet.addRows(rows);
|
143
|
+
}
|
144
|
+
|
145
|
+
function autoFitColumns(worksheet) {
|
146
|
+
worksheet.columns.forEach((column) => {
|
147
|
+
let maxLength = 0;
|
148
|
+
column.eachCell({ includeEmpty: true }, (cell) => {
|
149
|
+
const columnLength = cell.value ? cell.value.toString().length : 10;
|
150
|
+
if (columnLength > maxLength) {
|
151
|
+
maxLength = columnLength;
|
152
|
+
}
|
153
|
+
});
|
154
|
+
column.width = maxLength < 10 ? maxLength + 5 : maxLength;
|
155
|
+
});
|
156
|
+
}
|
157
|
+
|
158
|
+
function generateDescribe(worksheet, describe, data) {
|
159
|
+
if (describe) {
|
160
|
+
console.log('describe',describe);
|
161
|
+
// 定义开始的位置
|
162
|
+
const startCell = data.length + 7;
|
163
|
+
const endCell = startCell + 9;
|
164
|
+
|
165
|
+
// 合并单元格的范围
|
166
|
+
const mergeStart = 'A' + startCell;
|
167
|
+
const mergeEnd = 'E' + endCell;
|
168
|
+
worksheet.mergeCells(mergeStart + ':' + mergeEnd);
|
169
|
+
|
170
|
+
// 在表格底部加上文字解释
|
171
|
+
let combinedText = describe.join('\\n');
|
172
|
+
const mergedCells = [
|
173
|
+
'A' + startCell,
|
174
|
+
'B' + startCell,
|
175
|
+
'C' + startCell,
|
176
|
+
'D' + startCell,
|
177
|
+
'E' + startCell,
|
178
|
+
];
|
179
|
+
|
180
|
+
// 设置每个合并单元格的自动换行属性
|
181
|
+
mergedCells.forEach(function(cell) {
|
182
|
+
const currentCell = worksheet.getCell(cell);
|
183
|
+
currentCell.value = combinedText;
|
184
|
+
currentCell.font = fontStyle;
|
185
|
+
currentCell.alignment = {
|
186
|
+
vertical: "top",
|
187
|
+
horizontal: "left",
|
188
|
+
wrapText: true // 设置自动换行
|
189
|
+
};
|
190
|
+
});
|
191
|
+
worksheet.getCell(mergeStart).border = borderStyle;
|
192
|
+
}
|
193
|
+
}
|
194
|
+
|
195
|
+
function extractValues(rowData, column) {
|
196
|
+
if (column.children && column.children.length > 0) {
|
197
|
+
return column.children.flatMap((child) => extractValues(rowData, child));
|
198
|
+
} else {
|
199
|
+
return [rowData[column.key]];
|
200
|
+
}
|
201
|
+
}
|
202
|
+
self.onmessage = async function (e) {
|
203
|
+
const { data, columns, describe, filename } = e.data;
|
204
|
+
const workbook = new ExcelJS.Workbook();
|
205
|
+
const worksheet = workbook.addWorksheet("Sheet1");
|
206
|
+
generateHeaders(worksheet, columns);
|
207
|
+
fillData(worksheet, data, columns);
|
208
|
+
generateDescribe(worksheet, describe, data);
|
209
|
+
const buffer = await workbook.xlsx.writeBuffer();
|
210
|
+
self.postMessage({ buffer, filename });
|
211
|
+
const endTime = performance.now();
|
212
|
+
};`;
|
213
|
+
|
214
|
+
// 创建 Blob 对象
|
215
|
+
const blob = new Blob([workerScript], { type: "text/javascript" });
|
216
|
+
|
217
|
+
// 创建指向 Blob 的 URL
|
218
|
+
return URL.createObjectURL(blob);
|
219
|
+
}
|
220
|
+
|
221
|
+
export const workerUrl = getworkerUrl();
|