zmdms-webui 2.4.9 → 2.5.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.
|
@@ -28,7 +28,7 @@ import { useProcessedColumns } from './hooks/useProcessedColumns.js';
|
|
|
28
28
|
import { useSummaryRow } from './hooks/useSummaryRow.js';
|
|
29
29
|
import { useCanvasTableAutoHeight } from './hooks/useAutoHeight.js';
|
|
30
30
|
import { SCROLLBAR_SIZE } from './utils/constants.js';
|
|
31
|
-
import { calculateColumnRenderInfos,
|
|
31
|
+
import { calculateColumnRenderInfos, calculateTotalHeight, calculateTotalWidth } from './utils/tableCalculations.js';
|
|
32
32
|
import 'zmdms-utils';
|
|
33
33
|
import 'dayjs';
|
|
34
34
|
import { TABLE_DYNAMIC_KEY } from '../table/constant.js';
|
|
@@ -122,9 +122,31 @@ function CanvasTable(props) {
|
|
|
122
122
|
var containerHeight = containerSize.height;
|
|
123
123
|
// 计算列的渲染信息(使用容器宽度进行自适应填充)
|
|
124
124
|
// 手动调整过宽度的列不参与自动宽度分配
|
|
125
|
+
// 注意:需要先预判是否会有垂直滚动条,如果有则预留滚动条宽度
|
|
125
126
|
var columnRenderInfos = useMemo(function () {
|
|
126
|
-
|
|
127
|
-
|
|
127
|
+
// 第一步:先用原始列宽计算,判断是否需要垂直滚动条
|
|
128
|
+
calculateColumnRenderInfos(processedColumns, undefined, // 不进行自适应填充
|
|
129
|
+
manuallyResizedColumnKeys);
|
|
130
|
+
// 计算原始总高度
|
|
131
|
+
var tempTotalHeight = calculateTotalHeight(headerHeight, // 使用基础表头高度做粗略判断
|
|
132
|
+
finalDataSource.length, rowHeight);
|
|
133
|
+
// 判断是否需要垂直滚动条
|
|
134
|
+
var needVerticalScrollbar = tempTotalHeight > containerHeight;
|
|
135
|
+
// 第二步:计算实际可用宽度(如果需要垂直滚动条,减去滚动条宽度)
|
|
136
|
+
var availableWidth = needVerticalScrollbar
|
|
137
|
+
? containerWidth - SCROLLBAR_SIZE
|
|
138
|
+
: containerWidth;
|
|
139
|
+
// 第三步:使用可用宽度进行自适应填充
|
|
140
|
+
return calculateColumnRenderInfos(processedColumns, availableWidth, manuallyResizedColumnKeys);
|
|
141
|
+
}, [
|
|
142
|
+
processedColumns,
|
|
143
|
+
containerWidth,
|
|
144
|
+
containerHeight,
|
|
145
|
+
headerHeight,
|
|
146
|
+
finalDataSource.length,
|
|
147
|
+
rowHeight,
|
|
148
|
+
manuallyResizedColumnKeys,
|
|
149
|
+
]);
|
|
128
150
|
// 计算表头动态高度(支持wrap换行)
|
|
129
151
|
// 注意:必须在 columnRenderInfos 计算之后,以便使用实际的列宽
|
|
130
152
|
var calculatedHeaderHeight = useHeaderHeight({
|
|
@@ -111,37 +111,88 @@ var useTableScroll = function (params) {
|
|
|
111
111
|
// 允许过滤弹框内部滚动
|
|
112
112
|
return;
|
|
113
113
|
}
|
|
114
|
-
e.preventDefault();
|
|
115
|
-
e.stopPropagation();
|
|
116
114
|
// 当鼠标在容器内任何位置(包括CellOverlay)时都能滚动
|
|
117
115
|
// 累积滚动增量
|
|
118
116
|
// 支持 Shift + 鼠标滚轮进行水平滚动
|
|
117
|
+
var deltaX = 0;
|
|
118
|
+
var deltaY = 0;
|
|
119
119
|
if (e.shiftKey) {
|
|
120
120
|
// 按住 Shift 键时,将垂直滚动转换为水平滚动
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
deltaX = e.deltaY;
|
|
122
|
+
deltaY = 0;
|
|
123
123
|
}
|
|
124
124
|
else {
|
|
125
125
|
// 正常滚动逻辑
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
deltaX = e.deltaX;
|
|
127
|
+
deltaY = e.deltaY;
|
|
128
|
+
}
|
|
129
|
+
// 检查是否需要支持父元素滚动
|
|
130
|
+
// 1. 如果没有滚动条(maxScrollTop 和 maxScrollLeft 都为 0)
|
|
131
|
+
// 2. 或者已经滚动到底部且继续向下滚动
|
|
132
|
+
// 3. 或者已经滚动到顶部且继续向上滚动
|
|
133
|
+
var hasNoVerticalScrollbar = maxScrollTop <= 0;
|
|
134
|
+
var hasNoHorizontalScrollbar = maxScrollLeft <= 0;
|
|
135
|
+
var isAtBottom = Math.abs(scrollState.scrollTop - maxScrollTop) < 1;
|
|
136
|
+
var isAtTop = scrollState.scrollTop <= 0;
|
|
137
|
+
var isAtRight = Math.abs(scrollState.scrollLeft - maxScrollLeft) < 1;
|
|
138
|
+
var isAtLeft = scrollState.scrollLeft <= 0;
|
|
139
|
+
var shouldAllowParentScroll = false;
|
|
140
|
+
// 垂直滚动检查
|
|
141
|
+
if (deltaY !== 0) {
|
|
142
|
+
if (hasNoVerticalScrollbar) {
|
|
143
|
+
// 没有垂直滚动条,允许父元素滚动
|
|
144
|
+
shouldAllowParentScroll = true;
|
|
145
|
+
}
|
|
146
|
+
else if (deltaY > 0 && isAtBottom) {
|
|
147
|
+
// 向下滚动且已在底部,允许父元素滚动
|
|
148
|
+
shouldAllowParentScroll = true;
|
|
149
|
+
}
|
|
150
|
+
else if (deltaY < 0 && isAtTop) {
|
|
151
|
+
// 向上滚动且已在顶部,允许父元素滚动
|
|
152
|
+
shouldAllowParentScroll = true;
|
|
153
|
+
}
|
|
128
154
|
}
|
|
155
|
+
// 水平滚动检查
|
|
156
|
+
if (deltaX !== 0) {
|
|
157
|
+
if (hasNoHorizontalScrollbar) {
|
|
158
|
+
// 没有水平滚动条,允许父元素滚动
|
|
159
|
+
shouldAllowParentScroll = true;
|
|
160
|
+
}
|
|
161
|
+
else if (deltaX > 0 && isAtRight) {
|
|
162
|
+
// 向右滚动且已在右边界,允许父元素滚动
|
|
163
|
+
shouldAllowParentScroll = true;
|
|
164
|
+
}
|
|
165
|
+
else if (deltaX < 0 && isAtLeft) {
|
|
166
|
+
// 向左滚动且已在左边界,允许父元素滚动
|
|
167
|
+
shouldAllowParentScroll = true;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// 如果需要支持父元素滚动,不阻止默认行为
|
|
171
|
+
if (shouldAllowParentScroll) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
// 阻止默认行为和事件冒泡
|
|
175
|
+
e.preventDefault();
|
|
176
|
+
e.stopPropagation();
|
|
177
|
+
// 累积滚动增量
|
|
178
|
+
pendingDeltaRef.current.deltaX += deltaX;
|
|
179
|
+
pendingDeltaRef.current.deltaY += deltaY;
|
|
129
180
|
// 如果已经有pending的动画帧,不需要再次请求
|
|
130
181
|
if (rafIdRef.current !== null) {
|
|
131
182
|
return;
|
|
132
183
|
}
|
|
133
184
|
// 使用 requestAnimationFrame 节流更新
|
|
134
185
|
rafIdRef.current = requestAnimationFrame(function () {
|
|
135
|
-
var
|
|
136
|
-
var
|
|
186
|
+
var accumulatedDeltaX = pendingDeltaRef.current.deltaX;
|
|
187
|
+
var accumulatedDeltaY = pendingDeltaRef.current.deltaY;
|
|
137
188
|
// 重置累积的增量
|
|
138
189
|
pendingDeltaRef.current.deltaX = 0;
|
|
139
190
|
pendingDeltaRef.current.deltaY = 0;
|
|
140
191
|
rafIdRef.current = null;
|
|
141
192
|
// 批量更新状态
|
|
142
193
|
setScrollState(function (prev) {
|
|
143
|
-
var newScrollTop = Math.max(0, Math.min(maxScrollTop, prev.scrollTop +
|
|
144
|
-
var newScrollLeft = Math.max(0, Math.min(maxScrollLeft, prev.scrollLeft +
|
|
194
|
+
var newScrollTop = Math.max(0, Math.min(maxScrollTop, prev.scrollTop + accumulatedDeltaY));
|
|
195
|
+
var newScrollLeft = Math.max(0, Math.min(maxScrollLeft, prev.scrollLeft + accumulatedDeltaX));
|
|
145
196
|
if (newScrollTop !== prev.scrollTop ||
|
|
146
197
|
newScrollLeft !== prev.scrollLeft) {
|
|
147
198
|
onScroll === null || onScroll === void 0 ? void 0 : onScroll(newScrollLeft, newScrollTop);
|
|
@@ -162,7 +213,7 @@ var useTableScroll = function (params) {
|
|
|
162
213
|
rafIdRef.current = null;
|
|
163
214
|
}
|
|
164
215
|
};
|
|
165
|
-
}, [containerRef, maxScrollTop, maxScrollLeft, onScroll, setScrollState]);
|
|
216
|
+
}, [containerRef, maxScrollTop, maxScrollLeft, onScroll, setScrollState, scrollState.scrollTop, scrollState.scrollLeft]);
|
|
166
217
|
// 全局鼠标事件处理(拖拽滚动条)
|
|
167
218
|
useEffect(function () {
|
|
168
219
|
var handleGlobalMouseUp = function () {
|
|
@@ -30,7 +30,7 @@ var formatCellValue = function (value, column, noEmptyText) {
|
|
|
30
30
|
formattedValue = formatDate(formattedValue, column.dateFormat);
|
|
31
31
|
}
|
|
32
32
|
// 数值精度
|
|
33
|
-
if (column.precision !== undefined
|
|
33
|
+
if (column.precision !== undefined) {
|
|
34
34
|
formattedValue = exactRound(formattedValue, column.precision);
|
|
35
35
|
}
|
|
36
36
|
// 千分符
|
|
@@ -88,18 +88,26 @@ var calculateTotalHeight = function (headerHeight, dataLength, rowHeight) {
|
|
|
88
88
|
*/
|
|
89
89
|
var calculateScrollbarMetrics = function (params) {
|
|
90
90
|
var containerWidth = params.containerWidth, containerHeight = params.containerHeight, totalWidth = params.totalWidth, totalHeight = params.totalHeight, headerHeight = params.headerHeight, scrollbarSize = params.scrollbarSize, minScrollbarSize = params.minScrollbarSize, scrollTop = params.scrollTop, scrollLeft = params.scrollLeft;
|
|
91
|
-
//
|
|
91
|
+
// 计算实际可用的内容区域尺寸
|
|
92
|
+
// 注意:需要先确定是否需要滚动条,这里采用两次判断的方式
|
|
93
|
+
// 第一次判断:基于原始容器尺寸
|
|
92
94
|
var needVerticalScrollbar = totalHeight > containerHeight;
|
|
93
95
|
var needHorizontalScrollbar = totalWidth > containerWidth;
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
96
|
+
// 第二次判断:考虑滚动条互相影响
|
|
97
|
+
// 如果有垂直滚动条,可用宽度会减少,可能导致需要水平滚动条
|
|
98
|
+
if (needVerticalScrollbar && !needHorizontalScrollbar) {
|
|
99
|
+
needHorizontalScrollbar = totalWidth > containerWidth - scrollbarSize;
|
|
100
|
+
}
|
|
101
|
+
// 如果有水平滚动条,可用高度会减少,可能导致需要垂直滚动条
|
|
102
|
+
if (needHorizontalScrollbar && !needVerticalScrollbar) {
|
|
103
|
+
needVerticalScrollbar = totalHeight > containerHeight - scrollbarSize;
|
|
104
|
+
}
|
|
105
|
+
// 计算实际可用的内容区域尺寸(减去滚动条占用的空间)
|
|
106
|
+
var availableWidth = containerWidth - (needVerticalScrollbar ? scrollbarSize : 0);
|
|
107
|
+
var availableHeight = containerHeight - (needHorizontalScrollbar ? scrollbarSize : 0);
|
|
108
|
+
// 计算可滚动的最大值(基于实际可用空间)
|
|
109
|
+
var maxScrollTop = Math.max(0, totalHeight - availableHeight);
|
|
110
|
+
var maxScrollLeft = Math.max(0, totalWidth - availableWidth);
|
|
103
111
|
// 计算数据区域高度(不包括表头和水平滚动条)
|
|
104
112
|
var dataAreaHeight = containerHeight -
|
|
105
113
|
headerHeight -
|