zmdms-webui 2.3.7 → 2.3.8

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.
@@ -91,6 +91,7 @@ function CanvasTable(props) {
91
91
  columns: processedColumnsOld,
92
92
  rowSelection: rowSelection,
93
93
  onFilterChange: onFilterChange,
94
+ isAutoMerge: isAutoMerge,
94
95
  }), state = _y.state, setState = _y.setState, processedDataSource = _y.processedDataSource, handleFilterChange = _y.handleFilterChange, closeFilterPopover = _y.closeFilterPopover, autoGeneratedFilters = _y.autoGeneratedFilters;
95
96
  var order = useMemo(function () {
96
97
  return state.sortOrder && state.sortField
@@ -323,7 +324,7 @@ function CanvasTable(props) {
323
324
  // 渲染表格
324
325
  useTableRender(__assign(__assign({ canvasRef: canvasRef, processedDataSource: finalDataSource, columnRenderInfos: columnRenderInfos, columns: processedColumns, // 传递原始columns用于渲染多级表头
325
326
  state: state, scrollState: scrollState, rowSelection: rowSelection, containerWidth: containerWidth, containerHeight: containerHeight, headerHeight: calculatedHeaderHeight, baseHeaderHeight: headerHeight, // 传入原始基础高度用于计算每层高度
326
- rowHeight: rowHeight, bordered: bordered, striped: striped }, scrollbarMetrics), { getRowKey: getRowKey, resizeState: resizeState, getColumnWidth: getColumnWidth, RESIZE_HANDLE_WIDTH: RESIZE_HANDLE_WIDTH, mergeCellMap: mergeCellMap, hasSummaryRow: hasSummaryRow, fixedRowsCount: fixedRowsCount, fixedRowsConfig: fixedRowsConfig, summaryFixed: summaryFixed }));
327
+ rowHeight: rowHeight, bordered: bordered, striped: striped, headerAlign: headerAlign }, scrollbarMetrics), { getRowKey: getRowKey, resizeState: resizeState, getColumnWidth: getColumnWidth, RESIZE_HANDLE_WIDTH: RESIZE_HANDLE_WIDTH, mergeCellMap: mergeCellMap, hasSummaryRow: hasSummaryRow, fixedRowsCount: fixedRowsCount, fixedRowsConfig: fixedRowsConfig, summaryFixed: summaryFixed }));
327
328
  // 单元格覆盖层
328
329
  var cellOverlays = useTableCellOverlay({
329
330
  canvasRef: canvasRef,
@@ -458,7 +459,7 @@ function CanvasTable(props) {
458
459
  MozOsxFontSmoothing: "grayscale",
459
460
  textRendering: "optimizeLegibility",
460
461
  } }), dynamicKey ? (jsx(DynamicSetting, { parentDynamicKey: TABLE_DYNAMIC_KEY, dynamicKey: dynamicKey, defaultList: defaultDynamicList, onCurrentListChange: onCurrentListChange, ref: dynamicSettingRef, hiddenOperationIcon: true, isMore: true, isFixed: true, isDimensionDynamic: isDimensionDynamic })) : null, jsx(EmptyPlaceholder, { visible: finalDataSource.length === 0, text: emptyText, headerHeight: calculatedHeaderHeight }), jsx(HeaderOverlay, { overlays: headerOverlays }), jsx(CellOverlay, { overlays: cellOverlays }), filterPopoverElement, jsx(Tooltip, { visible: state.tooltip.visible, content: state.tooltip.content, position: state.tooltip.position }), jsx(BadgePopover, { visible: state.badgePopover.visible, content: state.badgePopover.content, position: state.badgePopover.position, popoverRef: badgePopoverRef }), menuId ? (jsx(CanvasTableMenu, { menuId: menuId, containerRef: containerRef, isFullscreenHandle: isFullscreenHandle, tableMenuRef: tableMenuRef, onCopy: handleCopy, onExport: function () {
461
- return exportExcel((exportExcelConfig === null || exportExcelConfig === void 0 ? void 0 : exportExcelConfig.fileName) || "表格数据.xlsx", __assign({}, exportExcelConfig));
462
+ return exportExcel((exportExcelConfig === null || exportExcelConfig === void 0 ? void 0 : exportExcelConfig.fileName) || "表格数据.xlsx", exportExcelConfig);
462
463
  } })) : null] })) })));
463
464
  }
464
465
 
@@ -1,5 +1,6 @@
1
1
  import { __assign } from '../../_virtual/_tslib.js';
2
2
  import { jsx, Fragment } from 'react/jsx-runtime';
3
+ import { TEXT_PADDING } from '../utils/constants.js';
3
4
 
4
5
  var CellOverlay = function (_a) {
5
6
  var overlays = _a.overlays;
@@ -27,9 +28,9 @@ var CellOverlay = function (_a) {
27
28
  })(), // 根据固定列和固定行设置 z-index
28
29
  } }, { children: jsx("div", __assign({ className: "canvas-table-cell-content", style: {
29
30
  position: "absolute",
30
- left: -overlay.offsetLeft + 16,
31
+ left: -overlay.offsetLeft + TEXT_PADDING,
31
32
  top: -overlay.offsetTop,
32
- width: overlay.originalWidth - 32,
33
+ width: overlay.originalWidth - TEXT_PADDING * 2,
33
34
  height: overlay.originalHeight,
34
35
  display: "flex",
35
36
  alignItems: "center",
@@ -8,7 +8,7 @@ import 'react/jsx-runtime';
8
8
  import 'zmdms-utils';
9
9
  import '../../node_modules/exceljs/dist/exceljs.min.js';
10
10
  import 'dayjs';
11
- import { COLORS, FONT_WEIGHT, FONT_SIZE, FONT_FAMILY, SCROLLBAR_SIZE, SCROLLBAR_PADDING } from '../utils/constants.js';
11
+ import { COLORS, FONT_WEIGHT, FONT_SIZE, FONT_FAMILY, TEXT_PADDING, SCROLLBAR_SIZE, SCROLLBAR_PADDING } from '../utils/constants.js';
12
12
  import { drawCheckbox, wrapText, truncateText, drawFilterIcon, drawSortIcon } from '../utils/canvasDrawHelpers.js';
13
13
  import { getMaxDepth, flattenHeaders, calculateLayerHeights, getLeafColumns } from '../utils/multiHeaderHelpers.js';
14
14
  import { extractCellText } from '../utils/cellHelpers.js';
@@ -19,7 +19,7 @@ import { calculateSelectionState, calculateIconArea } from '../utils/interaction
19
19
  * 表格渲染 Hook
20
20
  */
21
21
  var useTableRender = function (params) {
22
- var canvasRef = params.canvasRef, processedDataSource = params.processedDataSource, columnRenderInfos = params.columnRenderInfos, columns = params.columns, state = params.state, scrollState = params.scrollState, rowSelection = params.rowSelection, containerWidth = params.containerWidth, containerHeight = params.containerHeight, headerHeight = params.headerHeight, baseHeaderHeight = params.baseHeaderHeight, rowHeight = params.rowHeight, bordered = params.bordered, striped = params.striped, needVerticalScrollbar = params.needVerticalScrollbar, needHorizontalScrollbar = params.needHorizontalScrollbar, verticalScrollbarTop = params.verticalScrollbarTop, verticalScrollbarHeight = params.verticalScrollbarHeight, horizontalScrollbarLeft = params.horizontalScrollbarLeft, horizontalScrollbarWidth = params.horizontalScrollbarWidth, getRowKey = params.getRowKey, resizeState = params.resizeState, getColumnWidth = params.getColumnWidth, _a = params.RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_WIDTH = _a === void 0 ? 8 : _a, mergeCellMap = params.mergeCellMap, _b = params.hasSummaryRow, hasSummaryRow = _b === void 0 ? false : _b, fixedRowsCount = params.fixedRowsCount, fixedRowsConfig = params.fixedRowsConfig, _c = params.summaryFixed, summaryFixed = _c === void 0 ? false : _c;
22
+ var canvasRef = params.canvasRef, processedDataSource = params.processedDataSource, columnRenderInfos = params.columnRenderInfos, columns = params.columns, state = params.state, scrollState = params.scrollState, rowSelection = params.rowSelection, containerWidth = params.containerWidth, containerHeight = params.containerHeight, headerHeight = params.headerHeight, baseHeaderHeight = params.baseHeaderHeight, rowHeight = params.rowHeight, bordered = params.bordered, striped = params.striped, _a = params.headerAlign, headerAlign = _a === void 0 ? "center" : _a, needVerticalScrollbar = params.needVerticalScrollbar, needHorizontalScrollbar = params.needHorizontalScrollbar, verticalScrollbarTop = params.verticalScrollbarTop, verticalScrollbarHeight = params.verticalScrollbarHeight, horizontalScrollbarLeft = params.horizontalScrollbarLeft, horizontalScrollbarWidth = params.horizontalScrollbarWidth, getRowKey = params.getRowKey, resizeState = params.resizeState, getColumnWidth = params.getColumnWidth, _b = params.RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_WIDTH = _b === void 0 ? 8 : _b, mergeCellMap = params.mergeCellMap, _c = params.hasSummaryRow, hasSummaryRow = _c === void 0 ? false : _c, fixedRowsCount = params.fixedRowsCount, fixedRowsConfig = params.fixedRowsConfig, _d = params.summaryFixed, summaryFixed = _d === void 0 ? false : _d;
23
23
  // 判断是否是多级表头
24
24
  var maxDepth = useMemo(function () { return getMaxDepth(columns); }, [columns]);
25
25
  var isMultiHeader = maxDepth > 1;
@@ -27,13 +27,13 @@ var useTableRender = function (params) {
27
27
  var flattenedHeaderRows = useMemo(function () { return (isMultiHeader ? flattenHeaders(columns) : []); }, [columns, isMultiHeader]);
28
28
  // 计算多级表头每一层的高度(考虑换行)
29
29
  // 使用 baseHeaderHeight 或默认计算出的基础高度
30
- var _d = useMemo(function () {
30
+ var _e = useMemo(function () {
31
31
  var maxDepth = getMaxDepth(columns);
32
32
  // 如果提供了 baseHeaderHeight,使用它;否则根据 headerHeight 和深度计算
33
33
  var baseHeight = baseHeaderHeight ||
34
34
  (maxDepth > 1 ? Math.floor(headerHeight / maxDepth) : headerHeight);
35
35
  return calculateLayerHeights(columns, baseHeight, columnRenderInfos);
36
- }, [columns, headerHeight, baseHeaderHeight, columnRenderInfos]), layerHeights = _d.layerHeights, layerStartY = _d.layerStartY;
36
+ }, [columns, headerHeight, baseHeaderHeight, columnRenderInfos]), layerHeights = _e.layerHeights, layerStartY = _e.layerStartY;
37
37
  var dpr = window.devicePixelRatio || 1;
38
38
  // ==================== 通用辅助函数 ====================
39
39
  /**
@@ -141,8 +141,8 @@ var useTableRender = function (params) {
141
141
  else {
142
142
  // 计算图标占用的宽度
143
143
  var iconArea = calculateIconArea(column, width);
144
- // 确定表头对齐方式,优先使用列的 headerAlign,其次是 align,最后是默认值
145
- var headerAlign = column.headerAlign || column.align || "center";
144
+ // 确定表头对齐方式,优先使用列的 headerAlign,其次是全局 headerAlign
145
+ var columnHeaderAlign = column.headerAlign || headerAlign;
146
146
  // 绘制文本(如果 title 是 React 元素,跳过Canvas渲染,在覆盖层中渲染)
147
147
  if (!isValidElement(column.title)) {
148
148
  var titleText = String(column.title || "");
@@ -150,39 +150,39 @@ var useTableRender = function (params) {
150
150
  var textX_1;
151
151
  var textMaxWidth = void 0;
152
152
  if (iconArea.iconsWidth > 0) {
153
- // 有图标时,根据headerAlign调整文本位置和最大宽度
154
- if (headerAlign === "right") {
153
+ // 有图标时,根据columnHeaderAlign调整文本位置和最大宽度
154
+ if (columnHeaderAlign === "right") {
155
155
  ctx.textAlign = "right";
156
- textX_1 = drawX + width - 5 - iconArea.iconsWidth;
157
- textMaxWidth = width - 10 - iconArea.iconsWidth;
156
+ textX_1 = drawX + width - TEXT_PADDING - iconArea.iconsWidth;
157
+ textMaxWidth = width - TEXT_PADDING * 2 - iconArea.iconsWidth;
158
158
  }
159
- else if (headerAlign === "center") {
159
+ else if (columnHeaderAlign === "center") {
160
160
  ctx.textAlign = "center";
161
161
  textX_1 = drawX + (width - iconArea.iconsWidth) / 2;
162
- textMaxWidth = width - 10 - iconArea.iconsWidth;
162
+ textMaxWidth = width - TEXT_PADDING * 2 - iconArea.iconsWidth;
163
163
  }
164
164
  else {
165
165
  ctx.textAlign = "left";
166
- textX_1 = drawX + 5;
167
- textMaxWidth = width - 5 - iconArea.iconsWidth;
166
+ textX_1 = drawX + TEXT_PADDING;
167
+ textMaxWidth = width - TEXT_PADDING - iconArea.iconsWidth;
168
168
  }
169
169
  }
170
170
  else {
171
- // 没有图标时,根据headerAlign设置对齐方式
172
- if (headerAlign === "left") {
171
+ // 没有图标时,根据columnHeaderAlign设置对齐方式
172
+ if (columnHeaderAlign === "left") {
173
173
  ctx.textAlign = "left";
174
- textX_1 = drawX + 5;
175
- textMaxWidth = width - 10;
174
+ textX_1 = drawX + TEXT_PADDING;
175
+ textMaxWidth = width - TEXT_PADDING * 2;
176
176
  }
177
- else if (headerAlign === "right") {
177
+ else if (columnHeaderAlign === "right") {
178
178
  ctx.textAlign = "right";
179
- textX_1 = drawX + width - 5;
180
- textMaxWidth = width - 10;
179
+ textX_1 = drawX + width - TEXT_PADDING;
180
+ textMaxWidth = width - TEXT_PADDING * 2;
181
181
  }
182
182
  else {
183
183
  ctx.textAlign = "center";
184
184
  textX_1 = drawX + width / 2;
185
- textMaxWidth = width - 10;
185
+ textMaxWidth = width - TEXT_PADDING * 2;
186
186
  }
187
187
  }
188
188
  // 根据 ellipsis 和 wrap 属性处理文本
@@ -325,27 +325,27 @@ var useTableRender = function (params) {
325
325
  var iconArea = shouldShowIcons
326
326
  ? calculateIconArea(column, width)
327
327
  : { hasOrder: false, hasFilter: false, iconsWidth: 0 };
328
- // 确定表头对齐方式,优先使用列的 headerAlign,其次是 align,最后是默认值
329
- var headerAlign = column.headerAlign || column.align || "center";
328
+ // 确定表头对齐方式,优先使用列的 headerAlign,其次是全局 headerAlign
329
+ var columnHeaderAlign = column.headerAlign || headerAlign;
330
330
  // 如果是最末级且有图标,需要调整对齐方式
331
331
  if (isLastLevel && iconArea.iconsWidth > 0) {
332
- // 有图标时,根据headerAlign调整文本位置和最大宽度
332
+ // 有图标时,根据columnHeaderAlign调整文本位置和最大宽度
333
333
  var textX_2;
334
334
  var textMaxWidth = void 0;
335
- if (headerAlign === "right") {
335
+ if (columnHeaderAlign === "right") {
336
336
  ctx.textAlign = "right";
337
- textX_2 = drawX + width - 5 - iconArea.iconsWidth;
338
- textMaxWidth = width - 10 - iconArea.iconsWidth;
337
+ textX_2 = drawX + width - TEXT_PADDING - iconArea.iconsWidth;
338
+ textMaxWidth = width - TEXT_PADDING * 2 - iconArea.iconsWidth;
339
339
  }
340
- else if (headerAlign === "center") {
340
+ else if (columnHeaderAlign === "center") {
341
341
  ctx.textAlign = "center";
342
342
  textX_2 = drawX + (width - iconArea.iconsWidth) / 2;
343
- textMaxWidth = width - 10 - iconArea.iconsWidth;
343
+ textMaxWidth = width - TEXT_PADDING * 2 - iconArea.iconsWidth;
344
344
  }
345
345
  else {
346
346
  ctx.textAlign = "left";
347
- textX_2 = drawX + 5;
348
- textMaxWidth = width - 5 - iconArea.iconsWidth;
347
+ textX_2 = drawX + TEXT_PADDING;
348
+ textMaxWidth = width - TEXT_PADDING - iconArea.iconsWidth;
349
349
  }
350
350
  // 根据 wrap 属性处理文本
351
351
  if (column.wrap) {
@@ -364,15 +364,15 @@ var useTableRender = function (params) {
364
364
  }
365
365
  }
366
366
  else {
367
- // 没有图标时,根据headerAlign设置对齐方式
367
+ // 没有图标时,根据columnHeaderAlign设置对齐方式
368
368
  var textX_3;
369
- if (headerAlign === "left") {
369
+ if (columnHeaderAlign === "left") {
370
370
  ctx.textAlign = "left";
371
- textX_3 = drawX + 5;
371
+ textX_3 = drawX + TEXT_PADDING;
372
372
  }
373
- else if (headerAlign === "right") {
373
+ else if (columnHeaderAlign === "right") {
374
374
  ctx.textAlign = "right";
375
- textX_3 = drawX + width - 5;
375
+ textX_3 = drawX + width - TEXT_PADDING;
376
376
  }
377
377
  else {
378
378
  ctx.textAlign = "center";
@@ -381,7 +381,7 @@ var useTableRender = function (params) {
381
381
  // 根据 wrap 属性处理文本
382
382
  if (column.wrap) {
383
383
  // 换行显示(支持\n和自动换行)
384
- var lines = wrapText(ctx, titleText, width - 10); // 左右各5px
384
+ var lines = wrapText(ctx, titleText, width - TEXT_PADDING * 2); // 左右各TEXT_PADDING
385
385
  var lineHeight_3 = FONT_SIZE + 5; // 字体大小 + 行间距5px
386
386
  var startY_3 = textY - ((lines.length - 1) * lineHeight_3) / 2;
387
387
  lines.forEach(function (line, index) {
@@ -390,7 +390,7 @@ var useTableRender = function (params) {
390
390
  });
391
391
  }
392
392
  else {
393
- var truncated = truncateText(ctx, titleText, width - 10); // 左右各5px
393
+ var truncated = truncateText(ctx, titleText, width - TEXT_PADDING * 2); // 左右各TEXT_PADDING
394
394
  ctx.fillText(truncated, textX_3, textY);
395
395
  }
396
396
  }
@@ -672,20 +672,20 @@ var useTableRender = function (params) {
672
672
  : "".concat(FONT_WEIGHT, " ").concat(FONT_SIZE, "px ").concat(FONT_FAMILY);
673
673
  ctx.textBaseline = "middle";
674
674
  var align = column.align || "left";
675
- var textX_4 = drawX + 5;
675
+ var textX_4 = drawX + TEXT_PADDING;
676
676
  if (align === "center") {
677
677
  ctx.textAlign = "center";
678
678
  textX_4 = drawX + width / 2;
679
679
  }
680
680
  else if (align === "right") {
681
681
  ctx.textAlign = "right";
682
- textX_4 = drawX + width - 5;
682
+ textX_4 = drawX + width - TEXT_PADDING;
683
683
  }
684
684
  else {
685
685
  ctx.textAlign = "left";
686
686
  }
687
687
  // 处理文本显示(ellipsis 或 wrap)
688
- var maxWidth = width - 10; // 左右各5px
688
+ var maxWidth = width - TEXT_PADDING * 2; // 左右各TEXT_PADDING
689
689
  var ellipsis = column.ellipsis !== false; // 默认为true
690
690
  var wrap = column.wrap === true; // 默认为false
691
691
  if (wrap) {
@@ -9,7 +9,7 @@ import { getAllLeafColumns, findColumnByKey } from '../utils/columnHelpers.js';
9
9
  * 表格状态管理 Hook
10
10
  */
11
11
  var useTableState = function (params) {
12
- var dataSource = params.dataSource, columns = params.columns, rowSelection = params.rowSelection, onFilterChange = params.onFilterChange;
12
+ var dataSource = params.dataSource, columns = params.columns, rowSelection = params.rowSelection, onFilterChange = params.onFilterChange, isAutoMerge = params.isAutoMerge;
13
13
  // 表格状态
14
14
  var _a = useState({
15
15
  sortField: null,
@@ -157,7 +157,7 @@ var useTableState = function (params) {
157
157
  }
158
158
  });
159
159
  // 应用排序
160
- if (state.sortField && state.sortOrder) {
160
+ if (state.sortField && state.sortOrder && !isAutoMerge) {
161
161
  var column_2 = findColumnByKey(columns, state.sortField);
162
162
  if (column_2 && column_2.isOrder !== false) {
163
163
  var sortFn_1 = typeof column_2.sorter === "function"
@@ -187,7 +187,14 @@ var useTableState = function (params) {
187
187
  }
188
188
  }
189
189
  return data;
190
- }, [dataSource, columns, state.filters, state.sortField, state.sortOrder]);
190
+ }, [
191
+ dataSource,
192
+ columns,
193
+ state.filters,
194
+ state.sortField,
195
+ state.sortOrder,
196
+ isAutoMerge,
197
+ ]);
191
198
  // 处理过滤变化
192
199
  var handleFilterChange = useMemoizedFn(function (columnKey, values) {
193
200
  var _a;
@@ -405,7 +405,7 @@ interface ICanvasTableProps<RecordType = any> {
405
405
  /**
406
406
  * 表格ref句柄,用于暴露表格的一些方法
407
407
  */
408
- tableRefHandle?: React__default.Ref<ICanvasTableRefHandle>;
408
+ tableRefHandle?: React__default.Ref<ICanvasTableRefHandle | undefined>;
409
409
  /**
410
410
  * 导出excel的一些配置
411
411
  */
@@ -104,26 +104,43 @@ var toggleSelectAll = function (dataSource, isAllSelected, getRowKey, getCheckbo
104
104
  };
105
105
  /**
106
106
  * 处理排序点击
107
+ * 优化后的逻辑:
108
+ * - 点击上箭头:升序 → 降序 → 取消排序 → 升序...(循环)
109
+ * - 点击下箭头:降序 → 升序 → 取消排序 → 降序...(循环)
107
110
  */
108
111
  var handleSortClick = function (clickedUpper, currentSortField, currentSortOrder, columnKey) {
109
112
  var newOrder = null;
113
+ // 判断当前列是否已经是排序列
114
+ var isCurrentColumn = currentSortField === columnKey;
110
115
  if (clickedUpper) {
111
- // 点击上箭头:升序
112
- if (currentSortField === columnKey && currentSortOrder === "ascend") {
113
- newOrder = null; // 取消排序
114
- }
115
- else {
116
+ // 点击上箭头的循环逻辑:升序 → 降序 → 取消排序
117
+ if (!isCurrentColumn || currentSortOrder === null) {
118
+ // 没有排序或不是当前列,设置为升序
116
119
  newOrder = "ascend";
117
120
  }
121
+ else if (currentSortOrder === "ascend") {
122
+ // 已经是升序,切换到降序
123
+ newOrder = "descend";
124
+ }
125
+ else if (currentSortOrder === "descend") {
126
+ // 已经是降序,取消排序
127
+ newOrder = null;
128
+ }
118
129
  }
119
130
  else {
120
- // 点击下箭头:降序
121
- if (currentSortField === columnKey && currentSortOrder === "descend") {
122
- newOrder = null; // 取消排序
123
- }
124
- else {
131
+ // 点击下箭头的循环逻辑:降序 → 升序 → 取消排序
132
+ if (!isCurrentColumn || currentSortOrder === null) {
133
+ // 没有排序或不是当前列,设置为降序
125
134
  newOrder = "descend";
126
135
  }
136
+ else if (currentSortOrder === "descend") {
137
+ // 已经是降序,切换到升序
138
+ newOrder = "ascend";
139
+ }
140
+ else if (currentSortOrder === "ascend") {
141
+ // 已经是升序,取消排序
142
+ newOrder = null;
143
+ }
127
144
  }
128
145
  return {
129
146
  sortField: newOrder ? columnKey : null,
@@ -423,7 +423,8 @@ function useAutoMerge(dataSource, columns, _a) {
423
423
  if (!mergeKeys)
424
424
  return dataSource;
425
425
  else {
426
- var newDataSource_2 = flattenRecordsOptimized(__spreadArray([], (dataSource || []), true), mergeKeys, dimensionSummaryKeys, summaryKeys, isDimensionDynamic, order, dimensionCustomSumKeys);
426
+ var newDataSource_2 = flattenRecordsOptimized(__spreadArray([], (dataSource || []), true), mergeKeys, dimensionSummaryKeys, summaryKeys, isDimensionDynamic, order, dimensionCustomSumKeys, columns // 添加 columns 参数,支持自定义排序
427
+ );
427
428
  return newDataSource_2;
428
429
  }
429
430
  }
@@ -436,6 +437,7 @@ function useAutoMerge(dataSource, columns, _a) {
436
437
  isDimensionDynamic,
437
438
  order,
438
439
  dimensionCustomSumKeys,
440
+ columns, // 添加 columns 依赖
439
441
  ]);
440
442
  var newColumns = useMemo(function () {
441
443
  var _columns = columns;
@@ -449,7 +449,7 @@ function startColumnInsertTableData(options) {
449
449
  * @param summaryKeys 合计字段
450
450
  * @param isDimensionDynamic 维度合并
451
451
  */
452
- function flattenRecordsOptimized(records, mergeKeys, dimensionSummaryKeys, summaryKeys, isDimensionDynamic, order, dimensionCustomSumKeys) {
452
+ function flattenRecordsOptimized(records, mergeKeys, dimensionSummaryKeys, summaryKeys, isDimensionDynamic, order, dimensionCustomSumKeys, columns) {
453
453
  var _a;
454
454
  if (!records ||
455
455
  records.length === 0 ||
@@ -461,7 +461,7 @@ function flattenRecordsOptimized(records, mergeKeys, dimensionSummaryKeys, summa
461
461
  var result = [];
462
462
  // 如果order没有排序方向,但isDimensionDynamic为true,则按维度字段排序
463
463
  if (isDimensionDynamic) {
464
- result = sortByDimensions(__spreadArray([], records, true), mergeKeys);
464
+ result = sortByDimensions(__spreadArray([], records, true), mergeKeys, undefined, columns);
465
465
  }
466
466
  // 否则保持原样
467
467
  else {
@@ -478,6 +478,7 @@ function flattenRecordsOptimized(records, mergeKeys, dimensionSummaryKeys, summa
478
478
  // 开启自定义维度后因为最后一个维度字段会合并为一行,所以可以不排序最后一个维度字段
479
479
  mergeKeys: isDimensionDynamic ? mergeKeys.slice(0, -1) : mergeKeys,
480
480
  order: order,
481
+ columns: columns,
481
482
  });
482
483
  // 2. 首先插入维度合计行
483
484
  if (dimensionSummaryKeys &&
@@ -579,10 +580,10 @@ function flattenRecordsOptimized(records, mergeKeys, dimensionSummaryKeys, summa
579
580
  return result;
580
581
  }
581
582
  function sortRecords(_a) {
582
- var records = _a.records, mergeKeys = _a.mergeKeys, order = _a.order;
583
+ var records = _a.records, mergeKeys = _a.mergeKeys, order = _a.order, columns = _a.columns;
583
584
  var result = [];
584
585
  if (order && order.order) {
585
- result = sortByDimensions(__spreadArray([], records, true), mergeKeys, order);
586
+ result = sortByDimensions(__spreadArray([], records, true), mergeKeys, order, columns);
586
587
  }
587
588
  // 否则保持原样
588
589
  else {
@@ -597,92 +598,145 @@ function sortRecords(_a) {
597
598
  * @param dimensionKeys 维度字段
598
599
  * @param order 排序配置
599
600
  */
600
- function sortByDimensions(records, dimensionKeys, order) {
601
- return records.sort(function (a, b) {
602
- // 如果有排序配置且有排序方向
603
- if (order && order.order && order.field) {
604
- var field = order.field, sortOrder = order.order;
605
- // 找到排序字段在维度字段中的位置
606
- var sortFieldIndex = dimensionKeys.indexOf(field);
607
- if (sortFieldIndex !== -1) {
608
- // 先按维度字段排序到排序字段之前的字段
609
- for (var i = 0; i < sortFieldIndex; i++) {
610
- var key = dimensionKeys[i];
611
- var valueA_1 = a[key] || "";
612
- var valueB_1 = b[key] || "";
613
- // 字符串比较
614
- if (valueA_1 < valueB_1)
615
- return -1;
616
- if (valueA_1 > valueB_1)
617
- return 1;
618
- // 如果当前字段相等,继续比较下一个字段
619
- }
620
- // 按排序字段进行排序
621
- var valueA = a[field] || "";
622
- var valueB = b[field] || "";
623
- var compareResult = 0;
624
- if (valueA < valueB)
625
- compareResult = -1;
626
- else if (valueA > valueB)
627
- compareResult = 1;
628
- if (compareResult !== 0) {
629
- return sortOrder === "ascend" ? compareResult : -compareResult;
601
+ function sortByDimensions(records, dimensionKeys, order, columns) {
602
+ // 根据字段名查找对应的列配置
603
+ var findColumnByKey = function (field) {
604
+ if (!columns)
605
+ return null;
606
+ var findInColumns = function (cols) {
607
+ for (var _i = 0, cols_1 = cols; _i < cols_1.length; _i++) {
608
+ var col = cols_1[_i];
609
+ if (col.key === field || col.dataIndex === field) {
610
+ return col;
630
611
  }
631
- // 如果排序字段相等,继续按后面的维度字段排序
632
- for (var i = sortFieldIndex + 1; i < dimensionKeys.length; i++) {
633
- var key = dimensionKeys[i];
634
- var valueA_2 = a[key] || "";
635
- var valueB_2 = b[key] || "";
636
- // 字符串比较
637
- if (valueA_2 < valueB_2)
638
- return -1;
639
- if (valueA_2 > valueB_2)
640
- return 1;
641
- // 如果当前字段相等,继续比较下一个字段
612
+ // 如果有子列,递归查找
613
+ if (col.children && Array.isArray(col.children)) {
614
+ var found = findInColumns(col.children);
615
+ if (found)
616
+ return found;
642
617
  }
643
618
  }
619
+ return null;
620
+ };
621
+ return findInColumns(columns);
622
+ };
623
+ // 通用排序比较函数
624
+ var compareValues = function (valueA, valueB, order, recordA, recordB, field) {
625
+ // 处理 null/undefined
626
+ if (valueA === valueB)
627
+ return 0;
628
+ if (valueA === null || valueA === undefined)
629
+ return 1;
630
+ if (valueB === null || valueB === undefined)
631
+ return -1;
632
+ var compareResult = 0;
633
+ // 如果提供了字段名,尝试获取自定义排序函数
634
+ if (field && recordA && recordB) {
635
+ var column = findColumnByKey(field);
636
+ if (column && typeof column.sorter === "function") {
637
+ // 使用列配置中的自定义排序函数
638
+ compareResult = column.sorter(recordA, recordB);
639
+ }
644
640
  else {
645
- // 如果排序字段不在维度字段中,按原逻辑排序维度字段
646
- for (var i = 0; i < dimensionKeys.length; i++) {
647
- var key = dimensionKeys[i];
648
- var valueA_3 = a[key] || "";
649
- var valueB_3 = b[key] || "";
650
- // 字符串比较
651
- if (valueA_3 < valueB_3)
652
- return -1;
653
- if (valueA_3 > valueB_3)
654
- return 1;
655
- // 如果当前字段相等,继续比较下一个字段
656
- }
657
- // 最后按排序字段排序
658
- var valueA = a[field] || "";
659
- var valueB = b[field] || "";
660
- var compareResult = 0;
661
- if (valueA < valueB)
662
- compareResult = -1;
663
- else if (valueA > valueB)
664
- compareResult = 1;
665
- if (compareResult !== 0) {
666
- return sortOrder === "ascend" ? compareResult : -compareResult;
667
- }
641
+ // 使用默认排序逻辑
642
+ compareResult = getDefaultCompareResult(valueA, valueB);
668
643
  }
669
644
  }
670
645
  else {
671
- // 没有排序配置,按原逻辑排序
672
- for (var i = 0; i < dimensionKeys.length; i++) {
673
- var key = dimensionKeys[i];
674
- var valueA = a[key] || "";
675
- var valueB = b[key] || "";
676
- // 字符串比较
677
- if (valueA < valueB)
678
- return -1;
679
- if (valueA > valueB)
680
- return 1;
681
- // 如果当前字段相等,继续比较下一个字段
646
+ // 使用默认排序逻辑
647
+ compareResult = getDefaultCompareResult(valueA, valueB);
648
+ }
649
+ return compareResult !== 0
650
+ ? order === "ascend"
651
+ ? compareResult
652
+ : -compareResult
653
+ : 0;
654
+ };
655
+ // 默认排序比较逻辑
656
+ var getDefaultCompareResult = function (valueA, valueB) {
657
+ // 数字比较
658
+ if (typeof valueA === "number" && typeof valueB === "number") {
659
+ return valueA - valueB;
660
+ }
661
+ // 字符串比较(使用 localeCompare 支持中文等)
662
+ else {
663
+ return String(valueA).localeCompare(String(valueB), "zh-CN", {
664
+ numeric: true,
665
+ sensitivity: "base", // 忽略大小写和重音符号
666
+ });
667
+ }
668
+ };
669
+ // 通用的分层分组函数
670
+ var groupByDimensionsHierarchical = function (data, dimensions, currentDimensionIndex, sortConfig) {
671
+ if (currentDimensionIndex === void 0) { currentDimensionIndex = 0; }
672
+ if (currentDimensionIndex >= dimensions.length) {
673
+ // 到达叶子节点,如果排序字段不是维度字段,在这里排序
674
+ if (sortConfig && !dimensions.includes(sortConfig.field)) {
675
+ return data.sort(function (a, b) {
676
+ var valueA = a[sortConfig.field];
677
+ var valueB = b[sortConfig.field];
678
+ return compareValues(valueA, valueB, sortConfig.order, a, b, sortConfig.field);
679
+ });
680
+ }
681
+ else {
682
+ // 无排序配置或排序字段是维度字段,直接返回
683
+ return data;
682
684
  }
683
685
  }
684
- return 0; // 所有字段都相等
685
- });
686
+ var currentDimension = dimensions[currentDimensionIndex];
687
+ // 按当前维度分组,同时记录原始值用于排序
688
+ var groupData = new Map();
689
+ var groupOrder = []; // 记录分组出现的顺序
690
+ data.forEach(function (item) {
691
+ var value = item[currentDimension];
692
+ var key = String(value || "");
693
+ if (!groupData.has(key)) {
694
+ groupData.set(key, { items: [], originalValue: value });
695
+ groupOrder.push(key); // 记录第一次出现的顺序
696
+ }
697
+ groupData.get(key).items.push(item);
698
+ });
699
+ // 如果当前维度是排序字段,对分组的key进行排序
700
+ var finalGroupOrder = groupOrder;
701
+ if (sortConfig && sortConfig.field === currentDimension) {
702
+ finalGroupOrder = __spreadArray([], groupOrder, true).sort(function (keyA, keyB) {
703
+ // 使用保存的原始值进行比较
704
+ var valueA = groupData.get(keyA).originalValue;
705
+ var valueB = groupData.get(keyB).originalValue;
706
+ // 获取对应的记录用于自定义排序
707
+ var recordA = groupData.get(keyA).items[0];
708
+ var recordB = groupData.get(keyB).items[0];
709
+ return compareValues(valueA, valueB, sortConfig.order, recordA, recordB, sortConfig.field);
710
+ });
711
+ }
712
+ // 递归处理每个分组的子维度,并按排序后的顺序合并结果
713
+ var result = [];
714
+ for (var _i = 0, finalGroupOrder_1 = finalGroupOrder; _i < finalGroupOrder_1.length; _i++) {
715
+ var groupKey = finalGroupOrder_1[_i];
716
+ var group = groupData.get(groupKey);
717
+ var sortedGroupData = groupByDimensionsHierarchical(group.items, dimensions, currentDimensionIndex + 1, sortConfig);
718
+ result.push.apply(result, sortedGroupData);
719
+ }
720
+ return result;
721
+ };
722
+ // 根据是否有排序配置调用分组函数
723
+ var sortConfig;
724
+ if (order && order.order && order.field) {
725
+ // 如果有明确的排序配置,使用它
726
+ sortConfig = { field: order.field, order: order.order };
727
+ }
728
+ else {
729
+ // 如果没有明确排序,检查维度字段是否有自定义sorter,优先使用第一个有sorter的字段
730
+ for (var _i = 0, dimensionKeys_1 = dimensionKeys; _i < dimensionKeys_1.length; _i++) {
731
+ var dimensionKey = dimensionKeys_1[_i];
732
+ var column = findColumnByKey(dimensionKey);
733
+ if (column && typeof column.sorter === "function") {
734
+ sortConfig = { field: dimensionKey, order: "ascend" };
735
+ break; // 找到第一个有sorter的字段就使用,按维度顺序优先
736
+ }
737
+ }
738
+ }
739
+ return groupByDimensionsHierarchical(records, dimensionKeys, 0, sortConfig);
686
740
  }
687
741
  /**
688
742
  * 插入维度合计行
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zmdms-webui",
3
- "version": "2.3.7",
3
+ "version": "2.3.8",
4
4
  "private": false,
5
5
  "main": "dist/index.es.js",
6
6
  "module": "dist/index.es.js",