zmdms-webui 1.8.2 → 1.8.4

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.
@@ -0,0 +1,273 @@
1
+ import { __spreadArray, __assign } from '../_virtual/_tslib.js';
2
+ import { x as xlsx_minExports } from '../node_modules/xlsx-js-style/dist/xlsx.min.js';
3
+ import { useMergeKeys } from './hooks.js';
4
+ import { useMemo } from 'react';
5
+ import { useMemoizedFn } from 'ahooks';
6
+ import { MERGE_ROW_SPANS } from './constant.js';
7
+
8
+ /**
9
+ * 导出Excel,支持维度合并和小计
10
+ */
11
+ function exportToExcelWithMerge(records, columns, mergeKeys, summaryKeys, fileName, sheetName, columnHeaders) {
12
+ if (fileName === void 0) { fileName = "export.xlsx"; }
13
+ if (sheetName === void 0) { sheetName = "Sheet1"; }
14
+ if (!records || records.length === 0) {
15
+ throw new Error("没有数据可导出");
16
+ }
17
+ var processedData = records;
18
+ // 2. 准备Excel数据
19
+ var excelData = prepareExcelData(processedData, columns, columnHeaders);
20
+ // 3. 创建工作簿
21
+ var workbook = xlsx_minExports.utils.book_new();
22
+ // 4. 创建工作表
23
+ var worksheet = createWorksheetWithMerge(excelData, mergeKeys);
24
+ // 5. 添加样式(合计行高亮)
25
+ applyExcelStyles(worksheet, excelData.data, mergeKeys, summaryKeys, excelData.columns);
26
+ // 6. 添加工作表到工作簿
27
+ xlsx_minExports.utils.book_append_sheet(workbook, worksheet, sheetName);
28
+ // 7. 导出文件
29
+ xlsx_minExports.writeFile(workbook, fileName, { bookType: "xlsx" });
30
+ return {
31
+ totalRows: excelData.data.length,
32
+ summaryRows: excelData.data.filter(function (row) { return row.__is_summary__; }).length,
33
+ fileName: fileName,
34
+ };
35
+ }
36
+ /**
37
+ * 准备Excel数据
38
+ */
39
+ function prepareExcelData(processedData, columns, columnHeaders) {
40
+ // 过滤有效的列配置
41
+ var validColumns = columns.filter(function (item) {
42
+ return typeof item.dataIndex === "string" &&
43
+ typeof (item.dynamicTitle || item.title) === "string";
44
+ });
45
+ // 准备表头
46
+ var headers = validColumns.map(function (item) {
47
+ if (typeof item.dataIndex === "string") {
48
+ if (columnHeaders === null || columnHeaders === void 0 ? void 0 : columnHeaders[item.dataIndex]) {
49
+ return columnHeaders[item.dataIndex];
50
+ }
51
+ }
52
+ return (item.dynamicTitle || item.title);
53
+ });
54
+ return {
55
+ headers: headers,
56
+ data: processedData,
57
+ columns: validColumns,
58
+ };
59
+ }
60
+ /**
61
+ * 创建带合并单元格的工作表
62
+ */
63
+ function createWorksheetWithMerge(excelData, mergeKeys) {
64
+ var _a;
65
+ var headers = excelData.headers, data = excelData.data, columns = excelData.columns;
66
+ // 创建工作表数据(包含表头)
67
+ var worksheetData = __spreadArray([
68
+ headers
69
+ ], data.map(function (row) {
70
+ return columns.map(function (item) {
71
+ var value = row[item.dataIndex];
72
+ // 处理数值类型
73
+ if (typeof value === "number") {
74
+ return value;
75
+ }
76
+ // 处理字符串类型,避免空值
77
+ return value != null ? String(value) : "";
78
+ });
79
+ }), true);
80
+ // 创建工作表
81
+ var worksheet = xlsx_minExports.utils.aoa_to_sheet(worksheetData);
82
+ // 设置列宽
83
+ var columnWidths = columns.map(function (col) {
84
+ var _a;
85
+ return ({
86
+ wch: Math.max(15, ((_a = ((col.dynamicTitle || col.title))) === null || _a === void 0 ? void 0 : _a.length) * 2),
87
+ });
88
+ });
89
+ worksheet["!cols"] = columnWidths;
90
+ // 添加合并单元格
91
+ var merges = [];
92
+ if (mergeKeys && mergeKeys.length > 0) {
93
+ var _loop_1 = function (colIndex) {
94
+ var mergeKey = mergeKeys[colIndex];
95
+ var excelColIndex = columns.findIndex(function (item) { return item.dataIndex === mergeKey; });
96
+ if (excelColIndex === -1) {
97
+ return "continue";
98
+ }
99
+ for (var rowIndex = 0; rowIndex < data.length; rowIndex++) {
100
+ var rowData = data[rowIndex];
101
+ var spanCount = (_a = rowData[MERGE_ROW_SPANS]) === null || _a === void 0 ? void 0 : _a[mergeKey];
102
+ // 如果合并数量大于1,添加合并单元格
103
+ if (spanCount && spanCount > 1) {
104
+ var mergeRange = {
105
+ s: { r: rowIndex + 1, c: excelColIndex },
106
+ e: { r: rowIndex + spanCount, c: excelColIndex }, // 修复合并范围
107
+ };
108
+ merges.push(mergeRange);
109
+ }
110
+ }
111
+ };
112
+ // 处理每个合并字段
113
+ for (var colIndex = 0; colIndex < mergeKeys.length; colIndex++) {
114
+ _loop_1(colIndex);
115
+ }
116
+ }
117
+ worksheet["!merges"] = merges;
118
+ return worksheet;
119
+ }
120
+ /**
121
+ * 应用Excel样式 - 修复版本
122
+ */
123
+ function applyExcelStyles(worksheet, data, mergeKeys, summaryKeys, columns) {
124
+ var _a;
125
+ // 修复1:定义样式对象,确保格式正确
126
+ var headerStyle = {
127
+ font: { bold: true, color: { rgb: "FFFFFF" } },
128
+ fill: { patternType: "solid", fgColor: { rgb: "4F81BD" } },
129
+ alignment: { horizontal: "center", vertical: "center" },
130
+ border: {
131
+ top: { style: "thin", color: { rgb: "000000" } },
132
+ bottom: { style: "thin", color: { rgb: "000000" } },
133
+ left: { style: "thin", color: { rgb: "000000" } },
134
+ right: { style: "thin", color: { rgb: "000000" } },
135
+ },
136
+ };
137
+ var summaryStyle = {
138
+ font: { bold: true, color: { rgb: "000000" } },
139
+ fill: { patternType: "solid", fgColor: { rgb: "E6F3FF" } },
140
+ alignment: { horizontal: "center", vertical: "center" },
141
+ border: {
142
+ top: { style: "thin", color: { rgb: "000000" } },
143
+ bottom: { style: "thin", color: { rgb: "000000" } },
144
+ left: { style: "thin", color: { rgb: "000000" } },
145
+ right: { style: "thin", color: { rgb: "000000" } },
146
+ },
147
+ };
148
+ var normalStyle = {
149
+ alignment: { horizontal: "center", vertical: "center" },
150
+ border: {
151
+ top: { style: "thin", color: { rgb: "000000" } },
152
+ bottom: { style: "thin", color: { rgb: "000000" } },
153
+ left: { style: "thin", color: { rgb: "000000" } },
154
+ right: { style: "thin", color: { rgb: "000000" } },
155
+ },
156
+ };
157
+ // 修复2:获取工作表范围,添加默认范围处理
158
+ var range;
159
+ try {
160
+ range = xlsx_minExports.utils.decode_range(worksheet["!ref"] || "A1");
161
+ }
162
+ catch (e) {
163
+ // 如果没有!ref,手动计算范围
164
+ var maxCol = columns ? columns.length - 1 : 0;
165
+ var maxRow = data.length; // +1 for header, but 0-indexed
166
+ range = { s: { r: 0, c: 0 }, e: { r: maxRow, c: maxCol } };
167
+ }
168
+ // 修复3:应用表头样式,确保单元格存在
169
+ for (var col = range.s.c; col <= range.e.c; col++) {
170
+ var cellAddress = xlsx_minExports.utils.encode_cell({ r: 0, c: col });
171
+ // 确保单元格存在
172
+ if (!worksheet[cellAddress]) {
173
+ worksheet[cellAddress] = { v: "", t: "s" };
174
+ }
175
+ // 应用样式
176
+ worksheet[cellAddress].s = headerStyle;
177
+ }
178
+ // 修复4:应用数据行样式
179
+ for (var rowIndex = 0; rowIndex < data.length; rowIndex++) {
180
+ var rowData = data[rowIndex];
181
+ var isSubtotal = rowData.__is_summary__;
182
+ for (var col = range.s.c; col <= range.e.c; col++) {
183
+ var cellAddress = xlsx_minExports.utils.encode_cell({ r: rowIndex + 1, c: col });
184
+ // 确保单元格存在
185
+ if (!worksheet[cellAddress]) {
186
+ worksheet[cellAddress] = { v: "", t: "s" };
187
+ }
188
+ // 应用对应的样式,并根据列配置的对齐方式覆盖水平对齐
189
+ var baseStyle = isSubtotal ? summaryStyle : normalStyle;
190
+ var columnAlign = columns && Array.isArray(columns)
191
+ ? (_a = columns[col]) === null || _a === void 0 ? void 0 : _a.align
192
+ : undefined;
193
+ if (columnAlign === "left" ||
194
+ columnAlign === "right" ||
195
+ columnAlign === "center") {
196
+ worksheet[cellAddress].s = __assign(__assign({}, baseStyle), { alignment: __assign(__assign({}, baseStyle.alignment), { horizontal: columnAlign }) });
197
+ }
198
+ else {
199
+ worksheet[cellAddress].s = baseStyle;
200
+ }
201
+ }
202
+ }
203
+ // 修复5:设置数值列的格式,确保数值类型正确处理
204
+ if (summaryKeys && summaryKeys.length > 0 && columns) {
205
+ for (var rowIndex = 0; rowIndex < data.length; rowIndex++) {
206
+ var rowData = data[rowIndex];
207
+ var _loop_2 = function (summaryKey) {
208
+ var colIndex = columns.findIndex(function (col) { return col.dataIndex === summaryKey; });
209
+ if (colIndex === -1)
210
+ return "continue";
211
+ var cellAddress = xlsx_minExports.utils.encode_cell({
212
+ r: rowIndex + 1,
213
+ c: colIndex,
214
+ });
215
+ var cellValue = rowData[summaryKey];
216
+ // 确保单元格存在并且值是数字
217
+ if (worksheet[cellAddress] &&
218
+ (typeof cellValue === "number" || !isNaN(Number(cellValue)))) {
219
+ // 确保单元格值是数字类型
220
+ worksheet[cellAddress].v = Number(cellValue);
221
+ worksheet[cellAddress].t = "n"; // 明确设置为数字类型
222
+ // 应用数字格式
223
+ worksheet[cellAddress].z = "#,##0.00"; // 千分位分隔符,保留两位小数
224
+ }
225
+ };
226
+ for (var _i = 0, summaryKeys_1 = summaryKeys; _i < summaryKeys_1.length; _i++) {
227
+ var summaryKey = summaryKeys_1[_i];
228
+ _loop_2(summaryKey);
229
+ }
230
+ }
231
+ }
232
+ // 修复6:确保工作表引用正确
233
+ if (!worksheet["!ref"]) {
234
+ var lastCol = Math.max(0, ((columns === null || columns === void 0 ? void 0 : columns.length) || 1) - 1);
235
+ var lastRow = data.length; // header + data rows
236
+ worksheet["!ref"] = xlsx_minExports.utils.encode_range({
237
+ s: { r: 0, c: 0 },
238
+ e: { r: lastRow, c: lastCol },
239
+ });
240
+ }
241
+ }
242
+ /**
243
+ * 导出Excel的简化版本(只提供必要参数)
244
+ */
245
+ function exportToExcelSimple(records, config) {
246
+ return exportToExcelWithMerge(records, config.columns || [], config.mergeKeys, config.summaryKeys || [], config.fileName || "export.xlsx", config.sheetName || "Sheet1", config.columnHeaders);
247
+ }
248
+ /**
249
+ * excel导出
250
+ */
251
+ function useExcelExport(records, config) {
252
+ var columns = config.columns, fileName = config.fileName, isAutoMerge = config.isAutoMerge, columnHeaders = config.columnHeaders;
253
+ // 计算需要合并的字段key集合
254
+ var mergeKeys = useMergeKeys(columns, isAutoMerge);
255
+ // 需要合计的字段
256
+ var summaryKeys = useMemo(function () {
257
+ return columns
258
+ .filter(function (item) { return item.isSummary; })
259
+ .map(function (item) { return item.dataIndex; });
260
+ }, [columns]);
261
+ var exportFunction = useMemoizedFn(function () {
262
+ exportToExcelSimple(records, {
263
+ columns: columns,
264
+ mergeKeys: mergeKeys,
265
+ summaryKeys: summaryKeys,
266
+ fileName: fileName,
267
+ columnHeaders: columnHeaders,
268
+ });
269
+ });
270
+ return exportFunction;
271
+ }
272
+
273
+ export { exportToExcelSimple, exportToExcelWithMerge, useExcelExport };
@@ -337,7 +337,7 @@ var useMergeKeys = function (columns, isAutoMerge) {
337
337
  if (isAutoMerge) {
338
338
  return Array.from(new Set(columns
339
339
  .filter(function (item) { return item.isMerge && item.key !== MERGE_INDEX; })
340
- .map(function (item) { return item.mergeKey || item.key; })));
340
+ .map(function (item) { return (item.mergeKey || item.key); })));
341
341
  }
342
342
  return undefined;
343
343
  }, [isAutoMerge, columns]);
@@ -469,7 +469,6 @@ function useMergeAddAndDel(_a) {
469
469
  if (isAutoMerge) {
470
470
  return __assign(__assign({}, addAndDelProps), { onCell: function (record) {
471
471
  var _a;
472
- console.log(record, firstMergeKey, "record");
473
472
  return {
474
473
  rowSpan: (_a = record === null || record === void 0 ? void 0 : record[MERGE_ROW_SPANS]) === null || _a === void 0 ? void 0 : _a[firstMergeKey],
475
474
  };
@@ -480,4 +479,4 @@ function useMergeAddAndDel(_a) {
480
479
  return [newRowSelection, newAddAndDelProps];
481
480
  }
482
481
 
483
- export { useAddAndDelChange, useAutoMerge, useCalcScrollY, useCustomSort, useEditChange, useMergeAddAndDel, useMoveRowChange, useScuRfresh };
482
+ export { useAddAndDelChange, useAutoMerge, useCalcScrollY, useCustomSort, useEditChange, useMergeAddAndDel, useMergeKeys, useMoveRowChange, useScuRfresh };
@@ -274,6 +274,10 @@ interface ITableRefHandel {
274
274
  * 重置
275
275
  */
276
276
  onResetDynamicList?: () => void;
277
+ /**
278
+ * 导出excel
279
+ */
280
+ exportExcel?: () => void;
277
281
  }
278
282
  interface ITableProps<RecordType> extends Omit<TableProps<RecordType>, "columns"> {
279
283
  /**
@@ -22,6 +22,7 @@ import { HTML5Backend } from '../node_modules/react-dnd-html5-backend/dist/index
22
22
  import { VList, scrollTo } from '../node_modules/virtuallist-antd/dist/index.es.js';
23
23
  import useTableValidate, { tableValidate } from './useTableValidate.js';
24
24
  import TitleDirectionColumn from './components/TitleDirectionColumn.js';
25
+ import { useExcelExport } from './excel.js';
25
26
  import DynamicSetting from '../dynamicsetting/dynamicSetting.js';
26
27
  import { DndProvider } from '../node_modules/react-dnd/dist/core/DndProvider.js';
27
28
 
@@ -241,6 +242,12 @@ var Table = function (props) {
241
242
  }
242
243
  return undefined;
243
244
  }, [differences]);
245
+ // 导出excel
246
+ var exportExcel = useExcelExport(newDataSource, {
247
+ columns: newColumns,
248
+ isAutoMerge: isAutoMerge,
249
+ fileName: "导出.xlsx",
250
+ });
244
251
  // 暴露给外部一些方法
245
252
  useImperativeHandle(tableRefHandle, function () {
246
253
  return {
@@ -293,6 +300,7 @@ var Table = function (props) {
293
300
  var _a, _b;
294
301
  (_b = (_a = dynamicSettingRef.current) === null || _a === void 0 ? void 0 : _a.updateList) === null || _b === void 0 ? void 0 : _b.call(_a, list);
295
302
  },
303
+ exportExcel: exportExcel,
296
304
  };
297
305
  });
298
306
  // 表格
@@ -456,7 +456,9 @@ function flattenRecordsOptimized(records, mergeKeys, dimensionSummaryKeys, summa
456
456
  return records;
457
457
  }
458
458
  // 0. 首先根据维度字段对数据进行排序
459
- var result = sortByDimensions(__spreadArray([], records, true), mergeKeys);
459
+ var result = (dimensionSummaryKeys === null || dimensionSummaryKeys === void 0 ? void 0 : dimensionSummaryKeys.length) > 0
460
+ ? sortByDimensions(__spreadArray([], records, true), mergeKeys)
461
+ : __spreadArray([], records, true);
460
462
  // 1. 首先插入维度合计行
461
463
  if (dimensionSummaryKeys &&
462
464
  dimensionSummaryKeys.length > 0 &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zmdms-webui",
3
- "version": "1.8.2",
3
+ "version": "1.8.4",
4
4
  "private": false,
5
5
  "main": "dist/index.es.js",
6
6
  "module": "dist/index.es.js",
@@ -9,6 +9,8 @@
9
9
  "type": "module",
10
10
  "license": "MIT",
11
11
  "peerDependencies": {
12
+ "@tanstack/react-query": ">=5",
13
+ "@tanstack/react-query-devtools": ">=5",
12
14
  "ahooks": ">=3.7.8",
13
15
  "antd": ">=4.24.8",
14
16
  "dayjs": ">=1.11.7",
@@ -20,9 +22,7 @@
20
22
  "react-dom": ">=16.8.0",
21
23
  "react-resizable": "^3.0.5",
22
24
  "react-router-dom": ">=6",
23
- "zmdms-utils": ">=0.0.1",
24
- "@tanstack/react-query": ">=5",
25
- "@tanstack/react-query-devtools": ">=5"
25
+ "zmdms-utils": ">=0.0.1"
26
26
  },
27
27
  "sideEffects": [
28
28
  "dist/es/**/style/*",
@@ -144,6 +144,8 @@
144
144
  "react-dnd": "^16.0.1",
145
145
  "react-dnd-html5-backend": "^16.0.1",
146
146
  "screenfull": "^6.0.2",
147
- "virtuallist-antd": "^0.8.0-beta.1"
147
+ "virtuallist-antd": "^0.8.0-beta.1",
148
+ "xlsx": "^0.18.5",
149
+ "xlsx-js-style": "^1.2.0"
148
150
  }
149
151
  }