aegon-newepss 1.0.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/index.md +556 -0
- package/package.json +12 -0
package/index.md
ADDED
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
// excelExport.ts
|
|
2
|
+
import ExcelJS from "exceljs";
|
|
3
|
+
import type { CellValue, Worksheet, Row, Cell } from "exceljs";
|
|
4
|
+
|
|
5
|
+
export interface ExportOptions {
|
|
6
|
+
excelName?: string;
|
|
7
|
+
sheetName?: string;
|
|
8
|
+
dateColumnName?: string;
|
|
9
|
+
groupColumnName?: string;
|
|
10
|
+
columnsToMerge?: string[];
|
|
11
|
+
rightAlignedColumns?: string[];
|
|
12
|
+
centerAlignedColumns?: string[];
|
|
13
|
+
leftAlignedColumns?: string[];
|
|
14
|
+
// 已移除:sortColumns 相关配置
|
|
15
|
+
exportType?: 'single' | 'multi-sheet';
|
|
16
|
+
headerStyle?: {
|
|
17
|
+
font?: any;
|
|
18
|
+
fill?: any;
|
|
19
|
+
alignment?: any;
|
|
20
|
+
border?: any;
|
|
21
|
+
};
|
|
22
|
+
dataRowStyle?: {
|
|
23
|
+
font?: any;
|
|
24
|
+
alignment?: any;
|
|
25
|
+
border?: any;
|
|
26
|
+
};
|
|
27
|
+
columnWidthLimit?: number;
|
|
28
|
+
customFileName?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const getCellValueLength = (cellValue: CellValue | undefined | null): number => {
|
|
32
|
+
if (cellValue === null || cellValue === undefined) return 0;
|
|
33
|
+
let strValue = "";
|
|
34
|
+
if (typeof cellValue === "string") {
|
|
35
|
+
strValue = cellValue;
|
|
36
|
+
} else if (typeof cellValue === "number" || typeof cellValue === "boolean") {
|
|
37
|
+
strValue = cellValue.toString();
|
|
38
|
+
} else if (cellValue instanceof Date) {
|
|
39
|
+
strValue = cellValue.toISOString();
|
|
40
|
+
} else {
|
|
41
|
+
strValue = String(cellValue);
|
|
42
|
+
}
|
|
43
|
+
return strValue.length;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const isNumberValue = (value: any): boolean => {
|
|
47
|
+
if (value === null || value === undefined) return false;
|
|
48
|
+
if (typeof value === "number") return true;
|
|
49
|
+
if (typeof value !== "string") return false;
|
|
50
|
+
|
|
51
|
+
if (/[a-zA-Z\-_:]/.test(value)) return false;
|
|
52
|
+
|
|
53
|
+
const cleanedValue = value.replace(/[,$]/g, "").replace(/\s/g, "");
|
|
54
|
+
|
|
55
|
+
return /^-?\d+(\.\d+)?$/.test(cleanedValue);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const isCodeValue = (value: any): boolean => {
|
|
59
|
+
if (value === null || value === undefined) return false;
|
|
60
|
+
if (typeof value !== "string") return false;
|
|
61
|
+
|
|
62
|
+
return /^\d{3}-[A-Z]\d-\d{8}-\d{3}$/.test(value) ||
|
|
63
|
+
/^[A-Za-z0-9\-_.:]+$/.test(value);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const shouldLeftAlign = (cellValue: any, columnName?: string, leftAlignedColumns: string[] = []): boolean => {
|
|
67
|
+
if (columnName && leftAlignedColumns.includes(columnName)) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (isCodeValue(cellValue)) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (typeof cellValue === "string" && !isNumberValue(cellValue)) {
|
|
76
|
+
const strValue = cellValue.toString();
|
|
77
|
+
if (strValue.includes("/") || strValue.includes("-") || strValue.includes(":")) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return false;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const groupDataByDate = (data: string[][], dateColumnName: string = ""): Record<string, string[][]> => {
|
|
86
|
+
if (data.length <= 1 || !dateColumnName) return {};
|
|
87
|
+
const header: string[] = data[0] || [];
|
|
88
|
+
const dateGroups: Record<string, string[][]> = {};
|
|
89
|
+
|
|
90
|
+
if (!header || !Array.isArray(header)) {
|
|
91
|
+
dateGroups["全部数据"] = data;
|
|
92
|
+
return dateGroups;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const dateColumnIndex = header.indexOf(dateColumnName);
|
|
96
|
+
if (dateColumnIndex === -1) {
|
|
97
|
+
dateGroups["全部数据"] = data;
|
|
98
|
+
return dateGroups;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
for (let i = 1; i < data.length; i++) {
|
|
102
|
+
const row: string[] = data[i] || [];
|
|
103
|
+
const date = row[dateColumnIndex];
|
|
104
|
+
if (!date) continue;
|
|
105
|
+
|
|
106
|
+
if (!dateGroups[date]) {
|
|
107
|
+
dateGroups[date] = [header];
|
|
108
|
+
}
|
|
109
|
+
dateGroups[date].push(row);
|
|
110
|
+
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return dateGroups;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const configureWorksheetStyle = (
|
|
117
|
+
worksheet: Worksheet,
|
|
118
|
+
header: string[],
|
|
119
|
+
options: {
|
|
120
|
+
rightAlignedColumns?: string[];
|
|
121
|
+
centerAlignedColumns?: string[];
|
|
122
|
+
leftAlignedColumns?: string[];
|
|
123
|
+
headerStyle?: any;
|
|
124
|
+
dataRowStyle?: any;
|
|
125
|
+
columnWidthLimit?: number;
|
|
126
|
+
} = {}
|
|
127
|
+
): void => {
|
|
128
|
+
const {
|
|
129
|
+
rightAlignedColumns = [],
|
|
130
|
+
centerAlignedColumns = [],
|
|
131
|
+
leftAlignedColumns = [],
|
|
132
|
+
headerStyle = {},
|
|
133
|
+
dataRowStyle = {},
|
|
134
|
+
columnWidthLimit = 50
|
|
135
|
+
} = options;
|
|
136
|
+
|
|
137
|
+
if (!header || !Array.isArray(header)) return;
|
|
138
|
+
|
|
139
|
+
// 设置表头样式(修改:确保所有表头单元格都有边框)
|
|
140
|
+
const headerRow = worksheet.getRow(1);
|
|
141
|
+
if (headerRow) {
|
|
142
|
+
// 使用 eachCell 遍历所有有数据的表头单元格
|
|
143
|
+
headerRow.eachCell((cell: Cell) => {
|
|
144
|
+
cell.font = {
|
|
145
|
+
name: "Calibri",
|
|
146
|
+
size: 11,
|
|
147
|
+
bold: true,
|
|
148
|
+
color: { argb: "FF000000" },
|
|
149
|
+
...headerStyle.font
|
|
150
|
+
};
|
|
151
|
+
cell.fill = {
|
|
152
|
+
type: "pattern",
|
|
153
|
+
pattern: "solid",
|
|
154
|
+
fgColor: { argb: "FFFFFFFF" },
|
|
155
|
+
...headerStyle.fill
|
|
156
|
+
};
|
|
157
|
+
cell.alignment = {
|
|
158
|
+
vertical: "middle",
|
|
159
|
+
horizontal: "left",
|
|
160
|
+
wrapText: true,
|
|
161
|
+
...headerStyle.alignment
|
|
162
|
+
};
|
|
163
|
+
cell.border = {
|
|
164
|
+
top: { style: "thin", color: { argb: "FF000000" } },
|
|
165
|
+
left: { style: "thin", color: { argb: "FF000000" } },
|
|
166
|
+
bottom: { style: "thin", color: { argb: "FF000000" } },
|
|
167
|
+
right: { style: "thin", color: { argb: "FF000000" } },
|
|
168
|
+
...headerStyle.border
|
|
169
|
+
};
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// 确保所有列都有边框(包括空单元格)
|
|
173
|
+
for (let i = 1; i <= header.length; i++) {
|
|
174
|
+
const cell = headerRow.getCell(i);
|
|
175
|
+
if (!cell.border) {
|
|
176
|
+
cell.border = {
|
|
177
|
+
top: { style: "thin", color: { argb: "FF000000" } },
|
|
178
|
+
left: { style: "thin", color: { argb: "FF000000" } },
|
|
179
|
+
bottom: { style: "thin", color: { argb: "FF000000" } },
|
|
180
|
+
right: { style: "thin", color: { argb: "FF000000" } },
|
|
181
|
+
...headerStyle.border
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// 修改:遍历所有行和列,确保所有单元格都有边框
|
|
189
|
+
const totalRows = worksheet.rowCount;
|
|
190
|
+
const totalCols = header.length;
|
|
191
|
+
|
|
192
|
+
for (let rowIndex = 1; rowIndex <= totalRows; rowIndex++) {
|
|
193
|
+
const row = worksheet.getRow(rowIndex);
|
|
194
|
+
|
|
195
|
+
if (!row) continue;
|
|
196
|
+
|
|
197
|
+
for (let colIndex = 1; colIndex <= totalCols; colIndex++) {
|
|
198
|
+
const cell = row.getCell(colIndex);
|
|
199
|
+
|
|
200
|
+
// 跳过表头行(已经设置过)
|
|
201
|
+
if (rowIndex === 1) continue;
|
|
202
|
+
|
|
203
|
+
// 为所有单元格设置字体
|
|
204
|
+
cell.font = {
|
|
205
|
+
name: "Calibri",
|
|
206
|
+
size: 11,
|
|
207
|
+
color: { argb: "FF000000" },
|
|
208
|
+
...dataRowStyle.font
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const columnName = colIndex <= header.length ? header[colIndex - 1] : "";
|
|
212
|
+
|
|
213
|
+
// 设置对齐方式
|
|
214
|
+
let horizontalAlignment = "left";
|
|
215
|
+
|
|
216
|
+
if (columnName && centerAlignedColumns.includes(columnName)) {
|
|
217
|
+
horizontalAlignment = "center";
|
|
218
|
+
}
|
|
219
|
+
else if (columnName && rightAlignedColumns.includes(columnName)) {
|
|
220
|
+
horizontalAlignment = "right";
|
|
221
|
+
}
|
|
222
|
+
else if (columnName && leftAlignedColumns.includes(columnName)) {
|
|
223
|
+
horizontalAlignment = "left";
|
|
224
|
+
}
|
|
225
|
+
else if (shouldLeftAlign(cell.value, columnName, leftAlignedColumns)) {
|
|
226
|
+
horizontalAlignment = "left";
|
|
227
|
+
}
|
|
228
|
+
else if (isNumberValue(cell.value)) {
|
|
229
|
+
horizontalAlignment = "right";
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
horizontalAlignment = "left";
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
cell.alignment = {
|
|
236
|
+
vertical: "middle",
|
|
237
|
+
horizontal: horizontalAlignment,
|
|
238
|
+
wrapText: true,
|
|
239
|
+
...dataRowStyle.alignment
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// 确保所有数据单元格都有边框
|
|
243
|
+
cell.border = {
|
|
244
|
+
top: { style: "thin", color: { argb: "FF000000" } },
|
|
245
|
+
left: { style: "thin", color: { argb: "FF000000" } },
|
|
246
|
+
bottom: { style: "thin", color: { argb: "FF000000" } },
|
|
247
|
+
right: { style: "thin", color: { argb: "FF000000" } },
|
|
248
|
+
...dataRowStyle.border
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
// 修复:防止数值自动转换为科学计数法 - 对数值列设置文本格式
|
|
252
|
+
if (cell.value !== null && cell.value !== undefined) {
|
|
253
|
+
const cellStr = String(cell.value);
|
|
254
|
+
// 检查是否是纯数字(无字母和特殊字符,除了-、$、,)
|
|
255
|
+
if (isNumberValue(cellStr) && cellStr.length > 10) {
|
|
256
|
+
// 对于较长的数字字符串,设置为文本格式避免科学计数法
|
|
257
|
+
cell.numFmt = '@';
|
|
258
|
+
// 确保值为字符串格式,避免Excel自动转换
|
|
259
|
+
if (typeof cell.value === 'number') {
|
|
260
|
+
cell.value = String(cell.value);
|
|
261
|
+
} else if (typeof cell.value === 'string' && cell.value[0] !== "'") {
|
|
262
|
+
// 如果不是以单引号开头,添加单引号前缀确保Excel将其视为文本
|
|
263
|
+
cell.value = cell.value;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
worksheet.columns?.forEach((column) => {
|
|
272
|
+
let maxWidth = 10;
|
|
273
|
+
if (column.values && column.values.length > 0) {
|
|
274
|
+
maxWidth = column.values.reduce<number>((w: number, cellValue: CellValue) => {
|
|
275
|
+
const cellLength = getCellValueLength(cellValue);
|
|
276
|
+
return Math.max(w, cellLength);
|
|
277
|
+
}, 10);
|
|
278
|
+
}
|
|
279
|
+
column.width = Math.min(maxWidth + 2, columnWidthLimit);
|
|
280
|
+
});
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const groupDataByColumn = (data: any[][], groupColumnName: string = ""): any[] => {
|
|
284
|
+
const groups: any[] = [];
|
|
285
|
+
let currentGroup: any = null;
|
|
286
|
+
const groupColumnIndex = groupColumnName ? data[0]?.indexOf(groupColumnName) : 0;
|
|
287
|
+
|
|
288
|
+
data.forEach((row, index) => {
|
|
289
|
+
const groupValue = row[groupColumnIndex || 0];
|
|
290
|
+
if (!currentGroup || currentGroup.groupValue !== groupValue) {
|
|
291
|
+
if (currentGroup) {
|
|
292
|
+
currentGroup.endRow = index - 1;
|
|
293
|
+
groups.push(currentGroup);
|
|
294
|
+
}
|
|
295
|
+
currentGroup = {
|
|
296
|
+
groupValue,
|
|
297
|
+
startRow: index,
|
|
298
|
+
endRow: index,
|
|
299
|
+
rows: [row],
|
|
300
|
+
};
|
|
301
|
+
} else {
|
|
302
|
+
currentGroup.endRow = index;
|
|
303
|
+
currentGroup.rows.push(row);
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
if (currentGroup) {
|
|
308
|
+
groups.push(currentGroup);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return groups;
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
const mergeCellsByGroup = (
|
|
315
|
+
worksheet: Worksheet,
|
|
316
|
+
data: any[][],
|
|
317
|
+
columnsToMerge: string[],
|
|
318
|
+
headers: string[]
|
|
319
|
+
): void => {
|
|
320
|
+
if (!data || data.length === 0 || !columnsToMerge || columnsToMerge.length === 0) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const groups = groupDataByColumn(data);
|
|
325
|
+
const mergedRanges = new Set<string>();
|
|
326
|
+
|
|
327
|
+
groups.forEach((group) => {
|
|
328
|
+
if (group.startRow === group.endRow) return;
|
|
329
|
+
|
|
330
|
+
columnsToMerge.forEach((columnName) => {
|
|
331
|
+
const columnIndexes: number[] = [];
|
|
332
|
+
headers.forEach((header, index) => {
|
|
333
|
+
if (header === columnName) {
|
|
334
|
+
columnIndexes.push(index);
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
columnIndexes.forEach((columnIndex) => {
|
|
339
|
+
if (columnIndex === -1) return;
|
|
340
|
+
const startRow = group.startRow + 2;
|
|
341
|
+
const endRow = group.endRow + 2;
|
|
342
|
+
const rangeKey = `${startRow}-${endRow}-${columnIndex + 1}`;
|
|
343
|
+
|
|
344
|
+
if (mergedRanges.has(rangeKey)) return;
|
|
345
|
+
|
|
346
|
+
try {
|
|
347
|
+
worksheet.mergeCells(startRow, columnIndex + 1, endRow, columnIndex + 1);
|
|
348
|
+
mergedRanges.add(rangeKey);
|
|
349
|
+
|
|
350
|
+
let mergedValue = "";
|
|
351
|
+
if (group.rows && group.rows.length > 0) {
|
|
352
|
+
for (let i = 0; i < group.rows.length; i++) {
|
|
353
|
+
const rowData = group.rows[i];
|
|
354
|
+
if (rowData && rowData[columnIndex] !== undefined) {
|
|
355
|
+
const value = rowData[columnIndex];
|
|
356
|
+
if (
|
|
357
|
+
value !== null &&
|
|
358
|
+
value !== undefined &&
|
|
359
|
+
String(value).trim() !== ""
|
|
360
|
+
) {
|
|
361
|
+
mergedValue = String(value);
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const cell = worksheet.getCell(startRow, columnIndex + 1);
|
|
369
|
+
cell.value = mergedValue;
|
|
370
|
+
|
|
371
|
+
// 修复:如果合并的值是长数字,确保它不被转换为科学计数法
|
|
372
|
+
if (mergedValue && isNumberValue(mergedValue) && mergedValue.length > 10) {
|
|
373
|
+
cell.numFmt = '@';
|
|
374
|
+
}
|
|
375
|
+
} catch (error: any) {
|
|
376
|
+
console.warn(`合并单元格失败: ${error.message}`, {
|
|
377
|
+
startRow,
|
|
378
|
+
columnIndex: columnIndex + 1,
|
|
379
|
+
endRow,
|
|
380
|
+
columnName,
|
|
381
|
+
groupValue: group.groupValue,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
});
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
export const getDateRangeString = (data: string[][], dateColumnName: string = ""): string => {
|
|
391
|
+
if (data.length <= 1 || !dateColumnName) return "";
|
|
392
|
+
|
|
393
|
+
const header: string[] = data[0] || [];
|
|
394
|
+
const dateColumnIndex = header.indexOf(dateColumnName);
|
|
395
|
+
|
|
396
|
+
if (dateColumnIndex === -1) return "";
|
|
397
|
+
|
|
398
|
+
const dates: string[] = [];
|
|
399
|
+
for (let i = 1; i < data.length; i++) {
|
|
400
|
+
const row: string[] = data[i] || [];
|
|
401
|
+
const date = row[dateColumnIndex];
|
|
402
|
+
if (date && !dates.includes(date)) {
|
|
403
|
+
dates.push(date);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (dates.length === 0) return "";
|
|
408
|
+
dates.sort();
|
|
409
|
+
|
|
410
|
+
if (dates.length === 1) {
|
|
411
|
+
return dates[0] as any;
|
|
412
|
+
} else {
|
|
413
|
+
return `${dates[0]}~${dates[dates.length - 1]}`;
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
export const guiExportToExcel = async (
|
|
418
|
+
data: string[][],
|
|
419
|
+
options: ExportOptions = {}
|
|
420
|
+
): Promise<void> => {
|
|
421
|
+
const {
|
|
422
|
+
excelName = "", // 修改:默认值设置为空字符串
|
|
423
|
+
sheetName = "", // 修改:默认值设置为空字符串
|
|
424
|
+
dateColumnName = "",
|
|
425
|
+
groupColumnName = "",
|
|
426
|
+
columnsToMerge = [],
|
|
427
|
+
rightAlignedColumns = [],
|
|
428
|
+
centerAlignedColumns = [],
|
|
429
|
+
leftAlignedColumns = [],
|
|
430
|
+
// 已移除:sortColumns 相关配置
|
|
431
|
+
exportType = "single",
|
|
432
|
+
headerStyle = {},
|
|
433
|
+
dataRowStyle = {},
|
|
434
|
+
columnWidthLimit = 50,
|
|
435
|
+
customFileName = ""
|
|
436
|
+
} = options;
|
|
437
|
+
|
|
438
|
+
const workbook = new ExcelJS.Workbook();
|
|
439
|
+
|
|
440
|
+
// 处理数值格式,防止科学计数法 - 在处理前预处理数据
|
|
441
|
+
const finalData = data.map((row, rowIndex) => {
|
|
442
|
+
if (rowIndex === 0) return row; // 表头行不变
|
|
443
|
+
|
|
444
|
+
return row.map(cell => {
|
|
445
|
+
// 修复:检查是否是可能被转换为科学计数法的长数字
|
|
446
|
+
if (cell !== null && cell !== undefined) {
|
|
447
|
+
const cellStr = String(cell);
|
|
448
|
+
// 检查是否是纯数字(无字母和特殊字符,除了-、$、,)
|
|
449
|
+
if (isNumberValue(cellStr) && cellStr.length > 10) {
|
|
450
|
+
// 对于较长的数字,直接返回原值(不添加前缀)
|
|
451
|
+
// 在 configureWorksheetStyle 中会为这些单元格设置文本格式
|
|
452
|
+
return cellStr;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return cell;
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
if (exportType === "multi-sheet" && dateColumnName) {
|
|
461
|
+
const dateGroups = groupDataByDate(finalData, dateColumnName);
|
|
462
|
+
|
|
463
|
+
if (Object.keys(dateGroups).length === 0) {
|
|
464
|
+
const worksheet = workbook.addWorksheet(sheetName || "数据");
|
|
465
|
+
const header = finalData[0] || [];
|
|
466
|
+
worksheet.addRows(finalData.length > 0 ? finalData : [header]);
|
|
467
|
+
configureWorksheetStyle(worksheet, header, {
|
|
468
|
+
rightAlignedColumns,
|
|
469
|
+
centerAlignedColumns,
|
|
470
|
+
leftAlignedColumns,
|
|
471
|
+
headerStyle,
|
|
472
|
+
dataRowStyle,
|
|
473
|
+
columnWidthLimit
|
|
474
|
+
});
|
|
475
|
+
} else {
|
|
476
|
+
Object.keys(dateGroups).forEach((date) => {
|
|
477
|
+
const dateData = dateGroups[date] || [];
|
|
478
|
+
let sheetName = date;
|
|
479
|
+
if (sheetName === "全部数据") {
|
|
480
|
+
sheetName = "汇总";
|
|
481
|
+
} else {
|
|
482
|
+
sheetName = sheetName.replace(/[\/\\\*\?\[\]:]/g, "-");
|
|
483
|
+
if (sheetName.length > 31) {
|
|
484
|
+
sheetName = sheetName.substring(0, 31);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
const worksheet = workbook.addWorksheet(sheetName);
|
|
489
|
+
if (dateData.length > 0) {
|
|
490
|
+
worksheet.addRows(dateData);
|
|
491
|
+
const header = dateData[0] || [];
|
|
492
|
+
configureWorksheetStyle(worksheet, header, {
|
|
493
|
+
rightAlignedColumns,
|
|
494
|
+
centerAlignedColumns,
|
|
495
|
+
leftAlignedColumns,
|
|
496
|
+
headerStyle,
|
|
497
|
+
dataRowStyle,
|
|
498
|
+
columnWidthLimit
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
if (columnsToMerge.length > 0 && groupColumnName) {
|
|
502
|
+
const dataWithoutHeader = dateData.slice(1);
|
|
503
|
+
mergeCellsByGroup(worksheet, dataWithoutHeader, columnsToMerge, header);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
} else {
|
|
510
|
+
const worksheet = workbook.addWorksheet(sheetName || "数据");
|
|
511
|
+
const header = finalData[0] || [];
|
|
512
|
+
worksheet.addRows(finalData);
|
|
513
|
+
configureWorksheetStyle(worksheet, header, {
|
|
514
|
+
rightAlignedColumns,
|
|
515
|
+
centerAlignedColumns,
|
|
516
|
+
leftAlignedColumns,
|
|
517
|
+
headerStyle,
|
|
518
|
+
dataRowStyle,
|
|
519
|
+
columnWidthLimit
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
if (columnsToMerge.length > 0 && groupColumnName) {
|
|
523
|
+
const dataWithoutHeader = finalData.slice(1);
|
|
524
|
+
mergeCellsByGroup(worksheet, dataWithoutHeader, columnsToMerge, header);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
try {
|
|
530
|
+
const buffer = await workbook.xlsx.writeBuffer();
|
|
531
|
+
const blob = new Blob([buffer], {
|
|
532
|
+
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
533
|
+
});
|
|
534
|
+
const url = URL.createObjectURL(blob);
|
|
535
|
+
const a = document.createElement("a");
|
|
536
|
+
|
|
537
|
+
let fileName = customFileName || excelName;
|
|
538
|
+
if (exportType === "multi-sheet" && dateColumnName) {
|
|
539
|
+
const dateRange = getDateRangeString(finalData, dateColumnName);
|
|
540
|
+
if (dateRange) {
|
|
541
|
+
fileName = `${excelName}${excelName && dateRange ? '_' : ''}${dateRange}`;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
a.href = url;
|
|
546
|
+
a.download = `${fileName || "导出数据"}.xlsx`; // 添加默认文件名
|
|
547
|
+
document.body.appendChild(a);
|
|
548
|
+
a.click();
|
|
549
|
+
document.body.removeChild(a);
|
|
550
|
+
URL.revokeObjectURL(url);
|
|
551
|
+
return Promise.resolve();
|
|
552
|
+
|
|
553
|
+
} catch (error) {
|
|
554
|
+
return Promise.reject(error);
|
|
555
|
+
}
|
|
556
|
+
};
|
package/package.json
ADDED