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, calculateTotalWidth, calculateTotalHeight } from './utils/tableCalculations.js';
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
- return calculateColumnRenderInfos(processedColumns, containerWidth, manuallyResizedColumnKeys);
127
- }, [processedColumns, containerWidth, manuallyResizedColumnKeys]);
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
- pendingDeltaRef.current.deltaX += e.deltaY;
122
- pendingDeltaRef.current.deltaY += 0;
121
+ deltaX = e.deltaY;
122
+ deltaY = 0;
123
123
  }
124
124
  else {
125
125
  // 正常滚动逻辑
126
- pendingDeltaRef.current.deltaX += e.deltaX;
127
- pendingDeltaRef.current.deltaY += e.deltaY;
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 deltaX = pendingDeltaRef.current.deltaX;
136
- var deltaY = pendingDeltaRef.current.deltaY;
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 + deltaY));
144
- var newScrollLeft = Math.max(0, Math.min(maxScrollLeft, prev.scrollLeft + deltaX));
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 && typeof formattedValue === "number") {
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
- // maxScrollTop 需要考虑水平滚动条占用的空间
96
- // 当有水平滚动条时,数据可视区域减少了 scrollbarSize 的高度
97
- var maxScrollTop = Math.max(0, totalHeight -
98
- containerHeight +
99
- (needHorizontalScrollbar ? scrollbarSize : 0));
100
- // maxScrollLeft 需要考虑垂直滚动条占用的空间
101
- // 当有垂直滚动条时,数据可视区域减少了 scrollbarSize 的宽度
102
- var maxScrollLeft = Math.max(0, totalWidth - containerWidth + (needVerticalScrollbar ? scrollbarSize : 0));
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 -
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zmdms-webui",
3
- "version": "2.4.9",
3
+ "version": "2.5.0",
4
4
  "private": false,
5
5
  "main": "dist/index.es.js",
6
6
  "module": "dist/index.es.js",