zmdms-webui 2.4.0 → 2.4.2
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.
|
@@ -39,7 +39,8 @@ import { getTableColumns } from '../table/utils.js';
|
|
|
39
39
|
import DynamicSetting from '../dynamicsetting/dynamicSetting.js';
|
|
40
40
|
|
|
41
41
|
function CanvasTable(props) {
|
|
42
|
-
var _a = props.dataSource, dataSource = _a === void 0 ? [] : _a, _b = props.columns, columns = _b === void 0 ? [] : _b, _c = props.rowKey, rowKey = _c === void 0 ? "id" : _c, _d = props.height, height = _d === void 0 ? 600 : _d, width = props.width, _e = props.rowHeight, rowHeight = _e === void 0 ? 36 : _e, _f = props.headerHeight, headerHeight = _f === void 0 ? 36 : _f, rowSelection = props.rowSelection, onSortChange = props.onSortChange, onFilterChange = props.onFilterChange, onScroll = props.onScroll, onRowClick = props.onRowClick, onColumnResize = props.onColumnResize, _g = props.bordered, bordered = _g === void 0 ? true : _g, _h = props.striped, striped = _h === void 0 ? false : _h, _j = props.emptyText, emptyText = _j === void 0 ? "暂无数据" : _j, style = props.style, className = props.className, _k = props.loading, loading = _k === void 0 ? false : _k, _l = props.isContextMenu, isContextMenu = _l === void 0 ? true : _l, isFullscreenHandle = props.isFullscreenHandle,
|
|
42
|
+
var _a = props.dataSource, dataSource = _a === void 0 ? [] : _a, _b = props.columns, columns = _b === void 0 ? [] : _b, _c = props.rowKey, rowKey = _c === void 0 ? "id" : _c, _d = props.height, height = _d === void 0 ? 600 : _d, width = props.width, _e = props.rowHeight, rowHeight = _e === void 0 ? 36 : _e, _f = props.headerHeight, headerHeight = _f === void 0 ? 36 : _f, rowSelection = props.rowSelection, onSortChange = props.onSortChange, onFilterChange = props.onFilterChange, onScroll = props.onScroll, onRowClick = props.onRowClick, onColumnResize = props.onColumnResize, _g = props.bordered, bordered = _g === void 0 ? true : _g, _h = props.striped, striped = _h === void 0 ? false : _h, _j = props.emptyText, emptyText = _j === void 0 ? "暂无数据" : _j, style = props.style, className = props.className, _k = props.loading, loading = _k === void 0 ? false : _k, _l = props.isContextMenu, isContextMenu = _l === void 0 ? true : _l, isFullscreenHandle = props.isFullscreenHandle, mode = props.mode, dynamicKey = props.dynamicKey, dynamicVersion = props.dynamicVersion, customDynamicListHandle = props.customDynamicListHandle, isDimensionDynamic = props.isDimensionDynamic, dimensionCustomSumKeys = props.dimensionCustomSumKeys, isAutoMerge = props.isAutoMerge, _m = props.isIndexMerge, isIndexMerge = _m === void 0 ? true : _m, _o = props.isSelectionMerge, isSelectionMerge = _o === void 0 ? false : _o, _p = props.renderMode, renderMode = _p === void 0 ? "object" : _p, fixedRowsCount = props.fixedRowsCount, fixedRowsConfig = props.fixedRowsConfig, _q = props.summaryFixed, summaryFixed = _q === void 0 ? false : _q, _r = props.isAutoScrollY, isAutoScrollY = _r === void 0 ? false : _r, _s = props.autoScrollYMarginBottom, autoScrollYMarginBottom = _s === void 0 ? 65 : _s, canvasTableId = props.canvasTableId, headerWrap = props.headerWrap, _t = props.headerAlign, headerAlign = _t === void 0 ? "center" : _t, tableRefHandle = props.tableRefHandle, exportExcelConfig = props.exportExcelConfig;
|
|
43
|
+
var actualMode = "mode" in props ? mode : "index";
|
|
43
44
|
var canvasRef = useRef(null);
|
|
44
45
|
var containerRef = useRef(null);
|
|
45
46
|
var filterPopoverRef = useRef(null);
|
|
@@ -61,22 +62,22 @@ function CanvasTable(props) {
|
|
|
61
62
|
return String((_a = record[rowKey]) !== null && _a !== void 0 ? _a : index);
|
|
62
63
|
}, [rowKey]);
|
|
63
64
|
// 动态列配置
|
|
64
|
-
var
|
|
65
|
+
var _u = useDynamicListByColumns(columns, {
|
|
65
66
|
dynamicKey: dynamicKey,
|
|
66
67
|
dynamicVersion: dynamicVersion,
|
|
67
68
|
customDynamicListHandle: customDynamicListHandle,
|
|
68
|
-
}), defaultDynamicList =
|
|
69
|
+
}), defaultDynamicList = _u.defaultDynamicList, currentDynamicList = _u.currentDynamicList, onCurrentListChange = _u.onCurrentListChange, dynamicSettingRef = _u.dynamicSettingRef;
|
|
69
70
|
// 根据动态列配置处理columns
|
|
70
71
|
var dynamicColumns = useMemo(function () { return getTableColumns(columns, currentDynamicList); }, [columns, currentDynamicList]).columns;
|
|
71
72
|
// 内部列宽状态(未开启动态配置时使用)
|
|
72
|
-
var
|
|
73
|
+
var _v = useState({}), internalColumnWidths = _v[0], setInternalColumnWidths = _v[1];
|
|
73
74
|
// 跟踪用户手动调整过宽度的列(用于排除自动宽度分配)
|
|
74
|
-
var
|
|
75
|
+
var _w = useState(new Set()), manuallyResizedColumnKeys = _w[0], setManuallyResizedColumnKeys = _w[1];
|
|
75
76
|
// 处理选中框列、序号列等
|
|
76
77
|
var processedColumnsOld = useProcessedColumns({
|
|
77
78
|
columns: columns,
|
|
78
79
|
dynamicColumns: dynamicColumns,
|
|
79
|
-
mode:
|
|
80
|
+
mode: actualMode,
|
|
80
81
|
rowSelection: rowSelection,
|
|
81
82
|
internalColumnWidths: internalColumnWidths,
|
|
82
83
|
dynamicKey: dynamicKey,
|
|
@@ -86,29 +87,29 @@ function CanvasTable(props) {
|
|
|
86
87
|
headerAlign: headerAlign,
|
|
87
88
|
});
|
|
88
89
|
// 表格状态管理
|
|
89
|
-
var
|
|
90
|
+
var _x = useTableState({
|
|
90
91
|
dataSource: dataSource,
|
|
91
92
|
columns: processedColumnsOld,
|
|
92
93
|
rowSelection: rowSelection,
|
|
93
94
|
onFilterChange: onFilterChange,
|
|
94
95
|
isAutoMerge: isAutoMerge,
|
|
95
|
-
}), state =
|
|
96
|
+
}), state = _x.state, setState = _x.setState, processedDataSource = _x.processedDataSource, handleFilterChange = _x.handleFilterChange, closeFilterPopover = _x.closeFilterPopover, autoGeneratedFilters = _x.autoGeneratedFilters;
|
|
96
97
|
var order = useMemo(function () {
|
|
97
98
|
return state.sortOrder && state.sortField
|
|
98
99
|
? { field: state.sortField, order: state.sortOrder }
|
|
99
100
|
: undefined;
|
|
100
101
|
}, [state.sortOrder, state.sortField]);
|
|
101
|
-
var
|
|
102
|
+
var _y = useAutoMerge(processedDataSource, processedColumnsOld, {
|
|
102
103
|
isAutoMerge: isAutoMerge,
|
|
103
104
|
isDimensionDynamic: isDimensionDynamic,
|
|
104
105
|
order: order,
|
|
105
106
|
dimensionCustomSumKeys: dimensionCustomSumKeys,
|
|
106
|
-
}), newDataSource =
|
|
107
|
+
}), newDataSource = _y[0], processedColumns = _y[1];
|
|
107
108
|
// 生成合计行和最终数据源
|
|
108
|
-
var
|
|
109
|
+
var _z = useSummaryRow({
|
|
109
110
|
columns: processedColumns,
|
|
110
111
|
dataSource: newDataSource,
|
|
111
|
-
}), finalDataSource =
|
|
112
|
+
}), finalDataSource = _z.finalDataSource, hasSummaryRow = _z.hasSummaryRow;
|
|
112
113
|
// 自动高度计算(需要在容器尺寸计算之前)
|
|
113
114
|
var autoHeight = useCanvasTableAutoHeight(isAutoScrollY, autoScrollYMarginBottom, canvasTableId);
|
|
114
115
|
// 监听容器尺寸变化(提前计算,用于列宽自适应)
|
|
@@ -144,7 +145,7 @@ function CanvasTable(props) {
|
|
|
144
145
|
return calculateTotalHeight(calculatedHeaderHeight, finalDataSource.length, rowHeight);
|
|
145
146
|
}, [calculatedHeaderHeight, finalDataSource.length, rowHeight]);
|
|
146
147
|
// 计算滚动条指标
|
|
147
|
-
var
|
|
148
|
+
var _0 = useScrollbarMetrics({
|
|
148
149
|
containerWidth: containerWidth,
|
|
149
150
|
containerHeight: containerHeight,
|
|
150
151
|
totalWidth: totalWidth,
|
|
@@ -152,14 +153,14 @@ function CanvasTable(props) {
|
|
|
152
153
|
headerHeight: calculatedHeaderHeight,
|
|
153
154
|
scrollTop: 0,
|
|
154
155
|
scrollLeft: 0,
|
|
155
|
-
}), maxScrollTop =
|
|
156
|
+
}), maxScrollTop = _0.maxScrollTop, maxScrollLeft = _0.maxScrollLeft;
|
|
156
157
|
// 滚动管理(使用预先计算的maxScrollTop和maxScrollLeft)
|
|
157
|
-
var
|
|
158
|
+
var _1 = useTableScroll({
|
|
158
159
|
containerRef: containerRef,
|
|
159
160
|
maxScrollTop: maxScrollTop,
|
|
160
161
|
maxScrollLeft: maxScrollLeft,
|
|
161
162
|
onScroll: onScroll,
|
|
162
|
-
}), scrollState =
|
|
163
|
+
}), scrollState = _1.scrollState, setScrollState = _1.setScrollState;
|
|
163
164
|
// 数据变化时重置滚动位置(筛选、排序、数据源更新等操作后)
|
|
164
165
|
useScrollReset({
|
|
165
166
|
dataSourceLength: dataSource.length,
|
|
@@ -180,12 +181,12 @@ function CanvasTable(props) {
|
|
|
180
181
|
scrollLeft: scrollState.scrollLeft,
|
|
181
182
|
}).actualMetrics;
|
|
182
183
|
// 单元格框选
|
|
183
|
-
var
|
|
184
|
+
var _2 = useTableSelection({
|
|
184
185
|
state: state,
|
|
185
186
|
setState: setState,
|
|
186
187
|
}),
|
|
187
188
|
// selectionStartRef,
|
|
188
|
-
startSelection =
|
|
189
|
+
startSelection = _2.startSelection, updateSelection = _2.updateSelection, extendSelection = _2.extendSelection;
|
|
189
190
|
// 处理列宽调整
|
|
190
191
|
var handleColumnResize = useCallback(function (columnKey, newWidth) {
|
|
191
192
|
var _a;
|
|
@@ -240,13 +241,13 @@ function CanvasTable(props) {
|
|
|
240
241
|
onCurrentListChange,
|
|
241
242
|
]);
|
|
242
243
|
// 列宽调整
|
|
243
|
-
var
|
|
244
|
+
var _3 = useColumnResize({
|
|
244
245
|
columnRenderInfos: columnRenderInfos,
|
|
245
246
|
containerWidth: containerWidth,
|
|
246
247
|
headerHeight: calculatedHeaderHeight,
|
|
247
248
|
scrollLeft: scrollState.scrollLeft,
|
|
248
249
|
onColumnResize: handleColumnResize,
|
|
249
|
-
}), resizeState =
|
|
250
|
+
}), resizeState = _3.resizeState, checkResizeHandle = _3.checkResizeHandle, startResize = _3.startResize, updateResize = _3.updateResize, endResize = _3.endResize, setHoverResizeColumn = _3.setHoverResizeColumn, getColumnWidth = _3.getColumnWidth, RESIZE_HANDLE_WIDTH = _3.RESIZE_HANDLE_WIDTH;
|
|
250
251
|
// 复制到剪贴板
|
|
251
252
|
var getSelectedCellsText = useCopyToClipboard({
|
|
252
253
|
cellSelection: state.cellSelection,
|
|
@@ -274,7 +275,7 @@ function CanvasTable(props) {
|
|
|
274
275
|
summaryConfig: [],
|
|
275
276
|
});
|
|
276
277
|
// 交互事件处理(使用baseScrollbarMetrics的maxScrollTop/maxScrollLeft以保持稳定)
|
|
277
|
-
var
|
|
278
|
+
var _4 = useTableInteraction({
|
|
278
279
|
state: state,
|
|
279
280
|
setState: setState,
|
|
280
281
|
scrollState: scrollState,
|
|
@@ -289,6 +290,7 @@ function CanvasTable(props) {
|
|
|
289
290
|
containerHeight: containerHeight,
|
|
290
291
|
scrollbarSize: SCROLLBAR_SIZE,
|
|
291
292
|
canvasRef: canvasRef,
|
|
293
|
+
containerRef: containerRef,
|
|
292
294
|
totalHeight: totalHeight,
|
|
293
295
|
totalWidth: totalWidth,
|
|
294
296
|
// 使用scrollbarMetrics的显示相关属性(需要随滚动更新)
|
|
@@ -320,7 +322,7 @@ function CanvasTable(props) {
|
|
|
320
322
|
fixedRowsCount: fixedRowsCount,
|
|
321
323
|
fixedRowsConfig: fixedRowsConfig,
|
|
322
324
|
summaryFixed: summaryFixed,
|
|
323
|
-
}), handleCanvasMouseDown =
|
|
325
|
+
}), handleCanvasMouseDown = _4.handleCanvasMouseDown, handleCanvasMouseMove = _4.handleCanvasMouseMove, handleCanvasMouseUp = _4.handleCanvasMouseUp, handleCanvasMouseLeave = _4.handleCanvasMouseLeave, handleCanvasContextMenu = _4.handleCanvasContextMenu;
|
|
324
326
|
// 渲染表格
|
|
325
327
|
useTableRender(__assign(__assign({ canvasRef: canvasRef, processedDataSource: finalDataSource, columnRenderInfos: columnRenderInfos, columns: processedColumns, // 传递原始columns用于渲染多级表头
|
|
326
328
|
state: state, scrollState: scrollState, rowSelection: rowSelection, containerWidth: containerWidth, containerHeight: containerHeight, headerHeight: calculatedHeaderHeight, baseHeaderHeight: headerHeight, // 传入原始基础高度用于计算每层高度
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { __assign } from '../../_virtual/_tslib.js';
|
|
2
|
-
import { useMemo, useState, useRef, useEffect } from 'react';
|
|
2
|
+
import { useMemo, useState, useRef, useEffect, useCallback } from 'react';
|
|
3
3
|
import { SCROLLBAR_SIZE, MIN_SCROLLBAR_SIZE } from '../utils/constants.js';
|
|
4
4
|
import { calculateScrollbarMetrics } from '../utils/tableCalculations.js';
|
|
5
5
|
import 'zmdms-utils';
|
|
@@ -115,8 +115,17 @@ var useTableScroll = function (params) {
|
|
|
115
115
|
e.stopPropagation();
|
|
116
116
|
// 当鼠标在容器内任何位置(包括CellOverlay)时都能滚动
|
|
117
117
|
// 累积滚动增量
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
// 支持 Shift + 鼠标滚轮进行水平滚动
|
|
119
|
+
if (e.shiftKey) {
|
|
120
|
+
// 按住 Shift 键时,将垂直滚动转换为水平滚动
|
|
121
|
+
pendingDeltaRef.current.deltaX += e.deltaY;
|
|
122
|
+
pendingDeltaRef.current.deltaY += 0;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
// 正常滚动逻辑
|
|
126
|
+
pendingDeltaRef.current.deltaX += e.deltaX;
|
|
127
|
+
pendingDeltaRef.current.deltaY += e.deltaY;
|
|
128
|
+
}
|
|
120
129
|
// 如果已经有pending的动画帧,不需要再次请求
|
|
121
130
|
if (rafIdRef.current !== null) {
|
|
122
131
|
return;
|
|
@@ -178,7 +187,239 @@ var useTableScroll = function (params) {
|
|
|
178
187
|
setScrollState: setScrollState,
|
|
179
188
|
};
|
|
180
189
|
};
|
|
181
|
-
|
|
190
|
+
var useSelectionBoundaryScroll = function (params) {
|
|
191
|
+
var containerRef = params.containerRef, isSelecting = params.isSelecting,
|
|
192
|
+
// scrollState,
|
|
193
|
+
setScrollState = params.setScrollState, maxScrollTop = params.maxScrollTop, maxScrollLeft = params.maxScrollLeft, onScroll = params.onScroll, getCellFromPosition = params.getCellFromPosition, updateSelection = params.updateSelection, columnRenderInfos = params.columnRenderInfos;
|
|
194
|
+
var scrollRafRef = useRef(null);
|
|
195
|
+
var currentMousePosRef = useRef(null);
|
|
196
|
+
var lastCellRef = useRef(null);
|
|
197
|
+
var scrollVelocityRef = useRef({
|
|
198
|
+
deltaX: 0,
|
|
199
|
+
deltaY: 0,
|
|
200
|
+
});
|
|
201
|
+
// 状态更新去抖:避免频繁的状态更新
|
|
202
|
+
var stateUpdateRafRef = useRef(null);
|
|
203
|
+
var pendingStateUpdateRef = useRef(null);
|
|
204
|
+
// 缓存当前的滚动状态,避免频繁读取
|
|
205
|
+
var currentScrollStateRef = useRef({ scrollLeft: 0, scrollTop: 0 });
|
|
206
|
+
// 使用 ref 保存最新的函数引用,避免闭包问题
|
|
207
|
+
var setScrollStateRef = useRef(setScrollState);
|
|
208
|
+
var onScrollRef = useRef(onScroll);
|
|
209
|
+
var getCellFromPositionRef = useRef(getCellFromPosition);
|
|
210
|
+
var updateSelectionRef = useRef(updateSelection);
|
|
211
|
+
var columnRenderInfosRef = useRef(columnRenderInfos);
|
|
212
|
+
// 更新 ref 中的函数引用
|
|
213
|
+
useEffect(function () {
|
|
214
|
+
setScrollStateRef.current = setScrollState;
|
|
215
|
+
onScrollRef.current = onScroll;
|
|
216
|
+
getCellFromPositionRef.current = getCellFromPosition;
|
|
217
|
+
updateSelectionRef.current = updateSelection;
|
|
218
|
+
columnRenderInfosRef.current = columnRenderInfos;
|
|
219
|
+
});
|
|
220
|
+
// 同步当前滚动状态到 ref
|
|
221
|
+
useEffect(function () {
|
|
222
|
+
// 通过 setScrollState 的返回值来获取当前状态(不触发状态更新)
|
|
223
|
+
var currentState;
|
|
224
|
+
setScrollStateRef.current(function (prev) {
|
|
225
|
+
currentState = prev;
|
|
226
|
+
return prev; // 不修改状态,只读取
|
|
227
|
+
});
|
|
228
|
+
if (currentState) {
|
|
229
|
+
currentScrollStateRef.current = {
|
|
230
|
+
scrollLeft: currentState.scrollLeft,
|
|
231
|
+
scrollTop: currentState.scrollTop,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
var SCROLL_BOUNDARY_SIZE = 50; // 触发滚动的边界距离
|
|
236
|
+
var SCROLL_SPEED = 6; // 每次滚动的距离(进一步降低以减少频率)
|
|
237
|
+
// 防抖:避免鼠标移动时过度频繁地触发边界检测
|
|
238
|
+
var boundaryCheckThrottleRef = useRef(0);
|
|
239
|
+
// 批量状态更新函数:减少重新渲染次数
|
|
240
|
+
var batchUpdateScrollState = useCallback(function (newScrollLeft, newScrollTop) {
|
|
241
|
+
// 立即更新缓存状态
|
|
242
|
+
currentScrollStateRef.current = {
|
|
243
|
+
scrollLeft: newScrollLeft,
|
|
244
|
+
scrollTop: newScrollTop,
|
|
245
|
+
};
|
|
246
|
+
// 保存待更新的状态
|
|
247
|
+
pendingStateUpdateRef.current = {
|
|
248
|
+
scrollLeft: newScrollLeft,
|
|
249
|
+
scrollTop: newScrollTop,
|
|
250
|
+
};
|
|
251
|
+
// 如果已经有待处理的更新,直接返回
|
|
252
|
+
if (stateUpdateRafRef.current !== null) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
// 延迟到下一个渲染周期批量更新
|
|
256
|
+
stateUpdateRafRef.current = requestAnimationFrame(function () {
|
|
257
|
+
var pendingUpdate = pendingStateUpdateRef.current;
|
|
258
|
+
if (pendingUpdate) {
|
|
259
|
+
setScrollStateRef.current(function (prev) {
|
|
260
|
+
if (prev.scrollLeft !== pendingUpdate.scrollLeft ||
|
|
261
|
+
prev.scrollTop !== pendingUpdate.scrollTop) {
|
|
262
|
+
// 延迟调用 onScroll 回调,避免阻塞滚动
|
|
263
|
+
setTimeout(function () {
|
|
264
|
+
var _a;
|
|
265
|
+
(_a = onScrollRef.current) === null || _a === void 0 ? void 0 : _a.call(onScrollRef, pendingUpdate.scrollLeft, pendingUpdate.scrollTop);
|
|
266
|
+
}, 0);
|
|
267
|
+
return __assign(__assign({}, prev), { scrollLeft: pendingUpdate.scrollLeft, scrollTop: pendingUpdate.scrollTop });
|
|
268
|
+
}
|
|
269
|
+
return prev;
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
// 清理状态
|
|
273
|
+
stateUpdateRafRef.current = null;
|
|
274
|
+
pendingStateUpdateRef.current = null;
|
|
275
|
+
});
|
|
276
|
+
}, []);
|
|
277
|
+
// 检查边界滚动
|
|
278
|
+
var checkBoundaryScroll = useCallback(function (mouseX, mouseY) {
|
|
279
|
+
if (!containerRef.current || !isSelecting)
|
|
280
|
+
return;
|
|
281
|
+
// 节流:限制边界检测频率(每16ms最多执行一次,约60fps)
|
|
282
|
+
var now = performance.now();
|
|
283
|
+
if (now - boundaryCheckThrottleRef.current < 16) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
boundaryCheckThrottleRef.current = now;
|
|
287
|
+
var rect = containerRef.current.getBoundingClientRect();
|
|
288
|
+
var containerWidth = rect.width;
|
|
289
|
+
var containerHeight = rect.height;
|
|
290
|
+
var scrollDeltaX = 0;
|
|
291
|
+
var scrollDeltaY = 0;
|
|
292
|
+
// 检查水平边界
|
|
293
|
+
if (mouseX < SCROLL_BOUNDARY_SIZE) {
|
|
294
|
+
// 接近左边界,向左滚动
|
|
295
|
+
scrollDeltaX = -SCROLL_SPEED;
|
|
296
|
+
}
|
|
297
|
+
else if (mouseX > containerWidth - SCROLL_BOUNDARY_SIZE) {
|
|
298
|
+
// 接近右边界,向右滚动
|
|
299
|
+
scrollDeltaX = SCROLL_SPEED;
|
|
300
|
+
}
|
|
301
|
+
// 检查垂直边界
|
|
302
|
+
if (mouseY < SCROLL_BOUNDARY_SIZE) {
|
|
303
|
+
// 接近顶部边界,向上滚动
|
|
304
|
+
scrollDeltaY = -SCROLL_SPEED;
|
|
305
|
+
}
|
|
306
|
+
else if (mouseY > containerHeight - SCROLL_BOUNDARY_SIZE) {
|
|
307
|
+
// 接近底部边界,向下滚动
|
|
308
|
+
scrollDeltaY = SCROLL_SPEED;
|
|
309
|
+
}
|
|
310
|
+
// 保存当前鼠标位置和滚动速度
|
|
311
|
+
currentMousePosRef.current = { x: mouseX, y: mouseY };
|
|
312
|
+
scrollVelocityRef.current = {
|
|
313
|
+
deltaX: scrollDeltaX,
|
|
314
|
+
deltaY: scrollDeltaY,
|
|
315
|
+
};
|
|
316
|
+
// 如果需要滚动
|
|
317
|
+
if (scrollDeltaX !== 0 || scrollDeltaY !== 0) {
|
|
318
|
+
// 清除之前的动画帧
|
|
319
|
+
if (scrollRafRef.current) {
|
|
320
|
+
cancelAnimationFrame(scrollRafRef.current);
|
|
321
|
+
}
|
|
322
|
+
// 开始持续滚动(优化版本)
|
|
323
|
+
var performScroll_1 = function () {
|
|
324
|
+
var _a;
|
|
325
|
+
var velocity = scrollVelocityRef.current;
|
|
326
|
+
if (velocity.deltaX === 0 && velocity.deltaY === 0) {
|
|
327
|
+
return; // 停止滚动
|
|
328
|
+
}
|
|
329
|
+
// 获取当前滚动状态(从缓存中读取,避免触发状态更新)
|
|
330
|
+
var currentState = currentScrollStateRef.current;
|
|
331
|
+
var newScrollLeft = Math.max(0, Math.min(maxScrollLeft, currentState.scrollLeft + velocity.deltaX));
|
|
332
|
+
var newScrollTop = Math.max(0, Math.min(maxScrollTop, currentState.scrollTop + velocity.deltaY));
|
|
333
|
+
// 只有在位置真正发生变化时才更新
|
|
334
|
+
if (newScrollLeft !== currentState.scrollLeft ||
|
|
335
|
+
newScrollTop !== currentState.scrollTop) {
|
|
336
|
+
// 使用批量更新机制
|
|
337
|
+
batchUpdateScrollState(newScrollLeft, newScrollTop);
|
|
338
|
+
// 优化的框选更新:减少不必要的计算
|
|
339
|
+
if (getCellFromPositionRef.current &&
|
|
340
|
+
updateSelectionRef.current &&
|
|
341
|
+
columnRenderInfosRef.current &&
|
|
342
|
+
currentMousePosRef.current) {
|
|
343
|
+
var _b = currentMousePosRef.current, x = _b.x, y = _b.y;
|
|
344
|
+
// 添加位置计算的缓存,避免重复计算
|
|
345
|
+
try {
|
|
346
|
+
var cell = getCellFromPositionRef.current(x, y);
|
|
347
|
+
// 只有当单元格位置发生变化时才更新框选
|
|
348
|
+
if (cell &&
|
|
349
|
+
(!lastCellRef.current ||
|
|
350
|
+
lastCellRef.current.row !== cell.row ||
|
|
351
|
+
lastCellRef.current.col !== cell.col)) {
|
|
352
|
+
var isSelectionColumn = ((_a = columnRenderInfosRef.current[cell.col]) === null || _a === void 0 ? void 0 : _a.column.key) ===
|
|
353
|
+
"__selection__";
|
|
354
|
+
if (!isSelectionColumn) {
|
|
355
|
+
updateSelectionRef.current(cell);
|
|
356
|
+
lastCellRef.current = cell;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
catch (error) {
|
|
361
|
+
// 如果计算单元格位置出错,静默处理,不影响滚动
|
|
362
|
+
console.warn("Cell position calculation error during boundary scroll:", error);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
// 继续滚动
|
|
367
|
+
scrollRafRef.current = requestAnimationFrame(performScroll_1);
|
|
368
|
+
};
|
|
369
|
+
scrollRafRef.current = requestAnimationFrame(performScroll_1);
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
// 停止滚动
|
|
373
|
+
if (scrollRafRef.current) {
|
|
374
|
+
cancelAnimationFrame(scrollRafRef.current);
|
|
375
|
+
scrollRafRef.current = null;
|
|
376
|
+
}
|
|
377
|
+
scrollVelocityRef.current = { deltaX: 0, deltaY: 0 };
|
|
378
|
+
}
|
|
379
|
+
}, [
|
|
380
|
+
containerRef,
|
|
381
|
+
isSelecting,
|
|
382
|
+
maxScrollTop,
|
|
383
|
+
maxScrollLeft,
|
|
384
|
+
batchUpdateScrollState,
|
|
385
|
+
]);
|
|
386
|
+
// 停止边界滚动
|
|
387
|
+
var stopBoundaryScroll = useCallback(function () {
|
|
388
|
+
if (scrollRafRef.current) {
|
|
389
|
+
cancelAnimationFrame(scrollRafRef.current);
|
|
390
|
+
scrollRafRef.current = null;
|
|
391
|
+
}
|
|
392
|
+
if (stateUpdateRafRef.current) {
|
|
393
|
+
cancelAnimationFrame(stateUpdateRafRef.current);
|
|
394
|
+
stateUpdateRafRef.current = null;
|
|
395
|
+
}
|
|
396
|
+
scrollVelocityRef.current = { deltaX: 0, deltaY: 0 };
|
|
397
|
+
pendingStateUpdateRef.current = null;
|
|
398
|
+
lastCellRef.current = null; // 重置缓存的单元格位置
|
|
399
|
+
}, []);
|
|
400
|
+
// 当框选结束时停止滚动
|
|
401
|
+
useEffect(function () {
|
|
402
|
+
if (!isSelecting) {
|
|
403
|
+
stopBoundaryScroll();
|
|
404
|
+
}
|
|
405
|
+
}, [isSelecting, stopBoundaryScroll]);
|
|
406
|
+
// 组件卸载时清理动画帧
|
|
407
|
+
useEffect(function () {
|
|
408
|
+
return function () {
|
|
409
|
+
if (scrollRafRef.current) {
|
|
410
|
+
cancelAnimationFrame(scrollRafRef.current);
|
|
411
|
+
}
|
|
412
|
+
if (stateUpdateRafRef.current) {
|
|
413
|
+
cancelAnimationFrame(stateUpdateRafRef.current);
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
}, []);
|
|
417
|
+
return {
|
|
418
|
+
checkBoundaryScroll: checkBoundaryScroll,
|
|
419
|
+
stopBoundaryScroll: stopBoundaryScroll,
|
|
420
|
+
};
|
|
421
|
+
};
|
|
422
|
+
// ==================== Hook 4: 滚动位置重置 ====================
|
|
182
423
|
/**
|
|
183
424
|
* 滚动位置重置 Hook
|
|
184
425
|
*
|
|
@@ -236,4 +477,4 @@ var useScrollReset = function (params) {
|
|
|
236
477
|
]);
|
|
237
478
|
};
|
|
238
479
|
|
|
239
|
-
export { useScrollReset, useScrollbarMetrics, useTableScroll };
|
|
480
|
+
export { useScrollReset, useScrollbarMetrics, useSelectionBoundaryScroll, useTableScroll };
|
|
@@ -22,6 +22,8 @@ var useSummaryRow = function (params) {
|
|
|
22
22
|
if (!hasSummary)
|
|
23
23
|
return null;
|
|
24
24
|
var summaryRecord = {};
|
|
25
|
+
// 原始值,为转为千分符的
|
|
26
|
+
var summaryOriginalValues = {};
|
|
25
27
|
// 找到第一个列(包括序号列、选择框列)
|
|
26
28
|
var firstColIndex = leafColumns.length > 0 ? 0 : -1;
|
|
27
29
|
leafColumns.forEach(function (column, colIndex) {
|
|
@@ -43,9 +45,11 @@ var useSummaryRow = function (params) {
|
|
|
43
45
|
calculatedSum = sum_1;
|
|
44
46
|
// 应用格式化(仅在没有自定义回调或回调返回数值时)
|
|
45
47
|
var formattedSum = calculatedSum;
|
|
48
|
+
summaryOriginalValues[dataIndex] = calculatedSum;
|
|
46
49
|
if (typeof calculatedSum === "number") {
|
|
47
50
|
if (column.precision !== undefined) {
|
|
48
51
|
formattedSum = exactRound(calculatedSum, column.precision);
|
|
52
|
+
summaryOriginalValues[dataIndex] = calculatedSum;
|
|
49
53
|
}
|
|
50
54
|
if (column.thousand) {
|
|
51
55
|
formattedSum = addThousedSeparator(formattedSum);
|
|
@@ -64,7 +68,7 @@ var useSummaryRow = function (params) {
|
|
|
64
68
|
leafColumns.forEach(function (column) {
|
|
65
69
|
if (column.totalCalcCallback) {
|
|
66
70
|
var dataIndex = column.dataIndex || column.key;
|
|
67
|
-
summaryRecord[dataIndex] = column.totalCalcCallback(
|
|
71
|
+
summaryRecord[dataIndex] = column.totalCalcCallback(summaryOriginalValues[dataIndex], summaryOriginalValues);
|
|
68
72
|
}
|
|
69
73
|
});
|
|
70
74
|
summaryRecord[IS_SUMMARY] = true;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { __assign, __spreadArray } from '../../_virtual/_tslib.js';
|
|
2
2
|
import { useRef, useEffect } from 'react';
|
|
3
3
|
import { useMemoizedFn } from 'ahooks';
|
|
4
|
+
import { useSelectionBoundaryScroll } from './useScroll.js';
|
|
4
5
|
import { FONT_SIZE, FONT_FAMILY } from '../utils/constants.js';
|
|
5
6
|
import { isTextTruncated } from '../utils/canvasDrawHelpers.js';
|
|
6
7
|
import { getMaxDepth, flattenHeaders, getLeafColumns } from '../utils/multiHeaderHelpers.js';
|
|
@@ -13,7 +14,7 @@ import { calculateSelectionState, toggleSelectAll, handleSortClick, calculateIco
|
|
|
13
14
|
* 表格交互事件处理 Hook
|
|
14
15
|
*/
|
|
15
16
|
var useTableInteraction = function (params) {
|
|
16
|
-
var state = params.state, setState = params.setState, scrollState = params.scrollState, setScrollState = params.setScrollState, processedDataSource = params.processedDataSource, columnRenderInfos = params.columnRenderInfos, _a = params.columns, columns = _a === void 0 ? [] : _a, rowSelection = params.rowSelection, rowHeight = params.rowHeight, headerHeight = params.headerHeight, containerWidth = params.containerWidth, containerHeight = params.containerHeight, scrollbarSize = params.scrollbarSize, canvasRef = params.canvasRef, needVerticalScrollbar = params.needVerticalScrollbar, needHorizontalScrollbar = params.needHorizontalScrollbar, verticalScrollbarTop = params.verticalScrollbarTop, verticalScrollbarHeight = params.verticalScrollbarHeight, horizontalScrollbarLeft = params.horizontalScrollbarLeft, horizontalScrollbarWidth = params.horizontalScrollbarWidth, maxScrollTop = params.maxScrollTop, maxScrollLeft = params.maxScrollLeft, totalHeight = params.totalHeight, totalWidth = params.totalWidth, dataAreaHeight = params.dataAreaHeight, onSortChange = params.onSortChange, onRowClick = params.onRowClick, getRowKey = params.getRowKey, startSelection = params.startSelection, updateSelection = params.updateSelection, extendSelection = params.extendSelection, checkResizeHandle = params.checkResizeHandle, startResize = params.startResize, updateResize = params.updateResize, endResize = params.endResize, setHoverResizeColumn = params.setHoverResizeColumn, resizeState = params.resizeState, _b = params.hasSummaryRow, hasSummaryRow = _b === void 0 ? false : _b, mergeCellMap = params.mergeCellMap, menuShow = params.menuShow, fixedRowsCount = params.fixedRowsCount, fixedRowsConfig = params.fixedRowsConfig, summaryFixed = params.summaryFixed;
|
|
17
|
+
var state = params.state, setState = params.setState, scrollState = params.scrollState, setScrollState = params.setScrollState, processedDataSource = params.processedDataSource, columnRenderInfos = params.columnRenderInfos, _a = params.columns, columns = _a === void 0 ? [] : _a, rowSelection = params.rowSelection, rowHeight = params.rowHeight, headerHeight = params.headerHeight, containerWidth = params.containerWidth, containerHeight = params.containerHeight, scrollbarSize = params.scrollbarSize, canvasRef = params.canvasRef, containerRef = params.containerRef, needVerticalScrollbar = params.needVerticalScrollbar, needHorizontalScrollbar = params.needHorizontalScrollbar, verticalScrollbarTop = params.verticalScrollbarTop, verticalScrollbarHeight = params.verticalScrollbarHeight, horizontalScrollbarLeft = params.horizontalScrollbarLeft, horizontalScrollbarWidth = params.horizontalScrollbarWidth, maxScrollTop = params.maxScrollTop, maxScrollLeft = params.maxScrollLeft, totalHeight = params.totalHeight, totalWidth = params.totalWidth, dataAreaHeight = params.dataAreaHeight, onSortChange = params.onSortChange, onRowClick = params.onRowClick, getRowKey = params.getRowKey, startSelection = params.startSelection, updateSelection = params.updateSelection, extendSelection = params.extendSelection, checkResizeHandle = params.checkResizeHandle, startResize = params.startResize, updateResize = params.updateResize, endResize = params.endResize, setHoverResizeColumn = params.setHoverResizeColumn, resizeState = params.resizeState, _b = params.hasSummaryRow, hasSummaryRow = _b === void 0 ? false : _b, mergeCellMap = params.mergeCellMap, menuShow = params.menuShow, fixedRowsCount = params.fixedRowsCount, fixedRowsConfig = params.fixedRowsConfig, summaryFixed = params.summaryFixed;
|
|
17
18
|
// 获取鼠标位置对应的单元格
|
|
18
19
|
var getCellFromPosition = useMemoizedFn(function (x, y) {
|
|
19
20
|
var fixedTopRowsCount = (fixedRowsConfig === null || fixedRowsConfig === void 0 ? void 0 : fixedRowsConfig.topCount) || fixedRowsCount || 0;
|
|
@@ -464,6 +465,8 @@ var useTableInteraction = function (params) {
|
|
|
464
465
|
updateSelection(cell);
|
|
465
466
|
}
|
|
466
467
|
}
|
|
468
|
+
// 检查边界滚动 - 当鼠标接近容器边界时自动滚动
|
|
469
|
+
checkBoundaryScroll(x, y);
|
|
467
470
|
return;
|
|
468
471
|
}
|
|
469
472
|
// 检测列宽调整手柄hover状态
|
|
@@ -612,6 +615,8 @@ var useTableInteraction = function (params) {
|
|
|
612
615
|
// 结束框选
|
|
613
616
|
if (state.isSelecting) {
|
|
614
617
|
setState(function (prev) { return (__assign(__assign({}, prev), { isSelecting: false })); });
|
|
618
|
+
// 停止边界滚动
|
|
619
|
+
stopBoundaryScroll();
|
|
615
620
|
}
|
|
616
621
|
});
|
|
617
622
|
// 检查目标元素是否是Canvas内部渲染的元素
|
|
@@ -808,6 +813,8 @@ var useTableInteraction = function (params) {
|
|
|
808
813
|
// 结束框选
|
|
809
814
|
if (currentState.isSelecting) {
|
|
810
815
|
setState(function (prev) { return (__assign(__assign({}, prev), { isSelecting: false })); });
|
|
816
|
+
// 停止边界滚动
|
|
817
|
+
stopBoundaryScroll();
|
|
811
818
|
}
|
|
812
819
|
setScrollState(function (prev) { return (__assign(__assign({}, prev), { isDraggingVertical: false, isDraggingHorizontal: false })); });
|
|
813
820
|
};
|
|
@@ -828,6 +835,21 @@ var useTableInteraction = function (params) {
|
|
|
828
835
|
// updateResize, endResize, handleVerticalScrollDrag, handleHorizontalScrollDrag,
|
|
829
836
|
// updateSelection, setState, getCellFromPosition, columnRenderInfos,
|
|
830
837
|
]);
|
|
838
|
+
// 边界滚动Hook - 用于框选时的自动滚动
|
|
839
|
+
var _c = useSelectionBoundaryScroll({
|
|
840
|
+
containerRef: containerRef,
|
|
841
|
+
isSelecting: state.isSelecting,
|
|
842
|
+
scrollState: scrollState,
|
|
843
|
+
setScrollState: setScrollState,
|
|
844
|
+
maxScrollTop: maxScrollTop,
|
|
845
|
+
maxScrollLeft: maxScrollLeft,
|
|
846
|
+
onScroll: function (scrollLeft, scrollTop) {
|
|
847
|
+
// 边界滚动时的回调,可以在这里添加额外的逻辑
|
|
848
|
+
},
|
|
849
|
+
getCellFromPosition: getCellFromPosition,
|
|
850
|
+
updateSelection: updateSelection,
|
|
851
|
+
columnRenderInfos: columnRenderInfos,
|
|
852
|
+
}), checkBoundaryScroll = _c.checkBoundaryScroll, stopBoundaryScroll = _c.stopBoundaryScroll;
|
|
831
853
|
return {
|
|
832
854
|
handleCanvasMouseDown: handleCanvasMouseDown,
|
|
833
855
|
handleCanvasMouseMove: handleCanvasMouseMove,
|