export-to-exceljs-util 1.0.8 → 1.1.0

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/defaultExport.js CHANGED
@@ -20,7 +20,7 @@ const borderStyle = {
20
20
  right: { style: "thin" },
21
21
  };
22
22
  export default class DefaultExport {
23
- constructor(columns, data, filename = "export.xlsx", describe='') {
23
+ constructor(columns, data, filename = "export.xlsx", describe = "") {
24
24
  this.columns = columns;
25
25
  this.data = data;
26
26
  this.filename = filename;
@@ -180,19 +180,33 @@ export default class DefaultExport {
180
180
 
181
181
  generateDescribe(worksheet) {
182
182
  if (this.describe) {
183
- // 定义开始的位置
184
- const startCell = this.data.length + 7;
185
- const endCell = startCell + 9;
186
- worksheet.mergeCells(`A${startCell}:E${endCell}`);
183
+ // 定义开始和结束单元格的位置
184
+ let startCell = this.data.length + 7;
185
+ let endCell = 0;
187
186
 
188
187
  // 在表格底部加上文字解释
189
188
  let combinedText = this.describe;
189
+
190
+ // 合并单元格处理,根据描述信息的类型
191
+ if (typeof this.describe === "string") {
192
+ endCell = startCell + 10;
193
+ } else if (Array.isArray(this.describe)) {
194
+ endCell = startCell + this.describe.length;
195
+ combinedText = this.describe.join("\n");
196
+ } else {
197
+ endCell = startCell;
198
+ }
199
+ worksheet.mergeCells(`A${startCell}:H${endCell}`);
200
+
190
201
  const mergedCells = [
191
202
  `A${startCell}`,
192
203
  `B${startCell}`,
193
204
  `C${startCell}`,
194
205
  `D${startCell}`,
195
206
  `E${startCell}`,
207
+ `F${startCell}`,
208
+ `G${startCell}`,
209
+ `H${startCell}`,
196
210
  ];
197
211
 
198
212
  // 设置每个合并单元格的自动换行属性
package/index.js CHANGED
@@ -1,8 +1,7 @@
1
1
  import { saveAs } from "file-saver";
2
2
  import DefaultExport from "./defaultExport.js";
3
- import { workerUrl, retainTitleAndKey } from "./utils/index";
4
-
5
- class ExcelExporter1 {
3
+ import { workerScript, retainTitleAndKey } from "./utils/index";
4
+ class ExcelExporter {
6
5
  constructor(columns, data, filename = "导出数据.xlsx", describe = []) {
7
6
  this.columns = columns;
8
7
  this.data = data;
@@ -10,27 +9,28 @@ class ExcelExporter1 {
10
9
  this.describe = describe;
11
10
  }
12
11
 
13
- async exportToExcel() {
14
- try {
15
- if (this.data.length > 10000) {
16
- await this.exportLargeDataSet();
17
- } else {
18
- await this.exportSmallDataSet();
19
- }
20
- } catch (error) {
21
- console.error("Export failed:", error);
12
+ exportToExcel() {
13
+ if (this.data.length > 10000) {
14
+ this.exportLargeDataSet();
15
+ } else {
16
+ this.exportSmallDataSet();
22
17
  }
23
18
  }
24
19
 
25
- async exportLargeDataSet() {
20
+ exportLargeDataSet() {
21
+ // 创建 Blob 对象
22
+ const blob = new Blob([workerScript()], { type: "text/javascript" });
23
+
24
+ // 创建指向 Blob 的 URL
25
+ const workerUrl = URL.createObjectURL(blob);
26
26
 
27
27
  // 创建 Web Worker 实例
28
28
  const writeBufferWorker = new Worker(workerUrl);
29
29
 
30
- // 格式化数组数据
30
+ // 处理数据格式,保留标题和键
31
31
  const formatColumns = retainTitleAndKey(this.columns);
32
32
 
33
- // 发送数据到 Web Worker
33
+ // Web Worker 实例发送数据
34
34
  writeBufferWorker.postMessage({
35
35
  columns: formatColumns,
36
36
  data: this.data,
@@ -38,24 +38,28 @@ class ExcelExporter1 {
38
38
  filename: this.filename,
39
39
  });
40
40
 
41
- // 监听 Web Worker 的消息
41
+ // 监听 Web Worker 实例的消息
42
42
  writeBufferWorker.onmessage = (e) => {
43
+ // 下载文件
43
44
  const { buffer, filename } = e.data;
44
45
  const blob = new Blob([buffer], { type: "application/octet-stream" });
45
- // 下载文件
46
46
  saveAs(blob, filename);
47
+
47
48
  // 释放对象 URL
48
49
  URL.revokeObjectURL(workerUrl);
50
+
49
51
  // 终止 Web Worker
50
52
  writeBufferWorker.terminate();
51
53
  };
52
54
 
53
55
  writeBufferWorker.onerror = (error) => {
54
56
  console.error("Worker error:", error);
57
+ URL.revokeObjectURL(workerUrl);
58
+ writeBufferWorker.terminate();
55
59
  };
56
60
  }
57
61
 
58
- async exportSmallDataSet() {
62
+ exportSmallDataSet() {
59
63
  const defaultExport = new DefaultExport(
60
64
  this.columns,
61
65
  this.data,
@@ -66,4 +70,4 @@ class ExcelExporter1 {
66
70
  }
67
71
  }
68
72
 
69
- export default ExcelExporter1;
73
+ export default ExcelExporter;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "export-to-exceljs-util",
3
- "version": "1.0.8",
3
+ "version": "1.1.0",
4
4
  "description": "使用exceljs导出excel文件",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/utils/index.js CHANGED
@@ -1,220 +1,222 @@
1
1
  export function retainTitleAndKey(items) {
2
- return items.map((item) => {
3
- // 如果项目是一个数组,递归调用这个函数
4
- if (Array.isArray(item)) {
5
- return retainTitleAndKey(item);
6
- }
7
- // 如果项目是一个对象,处理 title, key 和 children 属性
8
- if (typeof item === "object" && item !== null) {
9
- // 创建一个新对象,只包含 title 和 key 属性
10
- let newItem = {
11
- title: item.title,
12
- key: item.key,
13
- };
14
- // 如果存在 children 属性,递归处理它
15
- if (item.children && Array.isArray(item.children)) {
16
- newItem.children = retainTitleAndKey(item.children);
2
+ return items.map((item) => {
3
+ // 如果项目是一个数组,递归调用这个函数
4
+ if (Array.isArray(item)) {
5
+ return retainTitleAndKey(item);
17
6
  }
18
- return newItem;
19
- }
20
- // 如果项目既不是数组也不是对象,直接返回它
21
- return item;
22
- });
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;
7
+ // 如果项目是一个对象,处理 title, key 和 children 属性
8
+ if (typeof item === "object" && item !== null) {
9
+ // 创建一个新对象,只包含 title 和 key 属性
10
+ let newItem = {
11
+ title: item.title,
12
+ key: item.key,
13
+ };
14
+ // 如果存在 children 属性,递归处理它
15
+ if (item.children && Array.isArray(item.children)) {
16
+ newItem.children = retainTitleAndKey(item.children);
17
+ }
18
+ return newItem;
115
19
  }
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) {
20
+ // 如果项目既不是数组也不是对象,直接返回它
21
+ return item;
22
+ });
23
+ }
24
+
25
+ export function workerScript() {
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
159
  if (describe) {
160
- // 定义开始的位置
161
- const startCell = data.length + 7;
162
- const endCell = startCell + 9;
163
-
164
- // 合并单元格的范围
165
- const mergeStart = 'A' + startCell;
166
- const mergeEnd = 'E' + endCell;
167
- worksheet.mergeCells(mergeStart + ':' + mergeEnd);
168
-
160
+ // 定义开始和结束单元格的位置
161
+ let startCell = data.length + 7;
162
+ let endCell = 0;
169
163
  // 在表格底部加上文字解释
170
164
  let combinedText = describe;
165
+ if (typeof describe === "string") {
166
+ endCell = startCell + 10;
167
+ } else if (Array.isArray(describe)) {
168
+ endCell = startCell + describe.length;
169
+ combinedText = describe.join("\\n");
170
+ } else {
171
+ endCell = startCell;
172
+ }
173
+ // 合并单元格的范围
174
+ const mergeStart = 'A' + startCell;
175
+ const mergeEnd = 'H' + endCell;
176
+ worksheet.mergeCells(mergeStart+':'+mergeEnd);
171
177
  const mergedCells = [
172
- 'A' + startCell,
173
- 'B' + startCell,
174
- 'C' + startCell,
175
- 'D' + startCell,
176
- 'E' + startCell,
178
+ 'A' + startCell,
179
+ 'B' + startCell,
180
+ 'C' + startCell,
181
+ 'D' + startCell,
182
+ 'E' + startCell,
183
+ 'F' + startCell,
184
+ 'G' + startCell,
185
+ 'H' + startCell
177
186
  ];
178
-
179
187
  // 设置每个合并单元格的自动换行属性
180
188
  mergedCells.forEach(function(cell) {
181
- const currentCell = worksheet.getCell(cell);
182
- currentCell.value = combinedText;
183
- currentCell.font = fontStyle;
184
- currentCell.alignment = {
185
- vertical: "top",
186
- horizontal: "left",
187
- wrapText: true // 设置自动换行
188
- };
189
+ const currentCell = worksheet.getCell(cell);
190
+ currentCell.value = combinedText;
191
+ currentCell.font = fontStyle;
192
+ currentCell.alignment = {
193
+ vertical: "top",
194
+ horizontal: "left",
195
+ wrapText: true // 设置自动换行
196
+ };
189
197
  });
190
198
  worksheet.getCell(mergeStart).border = borderStyle;
191
199
  }
192
- }
193
-
194
- function extractValues(rowData, column) {
195
- if (column.children && column.children.length > 0) {
196
- return column.children.flatMap((child) => extractValues(rowData, child));
197
- } else {
198
- return [rowData[column.key]];
199
- }
200
- }
201
- self.onmessage = async function (e) {
202
- const { data, columns, describe, filename } = e.data;
203
- const workbook = new ExcelJS.Workbook();
204
- const worksheet = workbook.addWorksheet("Sheet1");
205
- generateHeaders(worksheet, columns);
206
- fillData(worksheet, data, columns);
207
- generateDescribe(worksheet, describe, data);
208
- const buffer = await workbook.xlsx.writeBuffer();
209
- self.postMessage({ buffer, filename });
210
- const endTime = performance.now();
211
- };`;
212
-
213
- // 创建 Blob 对象
214
- const blob = new Blob([workerScript], { type: "text/javascript" });
215
-
216
- // 创建指向 Blob 的 URL
217
- return URL.createObjectURL(blob);
218
- }
219
-
220
- export const workerUrl = getworkerUrl();
200
+ }
201
+
202
+ function extractValues(rowData, column) {
203
+ if (column.children && column.children.length > 0) {
204
+ return column.children.flatMap((child) => extractValues(rowData, child));
205
+ } else {
206
+ return [rowData[column.key]];
207
+ }
208
+ }
209
+ self.onmessage = async function (e) {
210
+ const { data, columns, describe, filename } = e.data;
211
+ const workbook = new ExcelJS.Workbook();
212
+ const worksheet = workbook.addWorksheet("Sheet1");
213
+ generateHeaders(worksheet, columns);
214
+ fillData(worksheet, data, columns);
215
+ generateDescribe(worksheet, describe, data);
216
+ const buffer = await workbook.xlsx.writeBuffer();
217
+ self.postMessage({ buffer, filename });
218
+ const endTime = performance.now();
219
+ };`;
220
+ return workerScript
221
+ }
222
+