zmdms-webui 2.6.2 → 2.6.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.
@@ -13,6 +13,7 @@ import HeaderOverlay from './components/HeaderOverlay.js';
13
13
  import { useContextMenu as Fe } from '../node_modules/react-contexify/dist/index.js';
14
14
  import { useTableState } from './hooks/useTableState.js';
15
15
  import { useTableSelection } from './hooks/useTableSelection.js';
16
+ import { useExpandable } from './hooks/useExpandable.js';
16
17
  import { useTableRender } from './hooks/useTableRender.js';
17
18
  import { useTableInteraction } from './hooks/useTableInteraction.js';
18
19
  import { useScrollbarMetrics, useTableScroll, useScrollReset } from './hooks/useScroll.js';
@@ -39,7 +40,8 @@ import { getTableColumns } from '../table/utils.js';
39
40
  import DynamicSetting from '../dynamicsetting/dynamicSetting.js';
40
41
 
41
42
  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, 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, _u = props.maxHeight, maxHeight = _u === void 0 ? 3000 : _u;
43
+ var _a;
44
+ var _b = props.dataSource, dataSource = _b === void 0 ? [] : _b, _c = props.columns, columns = _c === void 0 ? [] : _c, _d = props.rowKey, rowKey = _d === void 0 ? "id" : _d, _e = props.height, height = _e === void 0 ? 600 : _e, width = props.width, _f = props.rowHeight, rowHeight = _f === void 0 ? 36 : _f, _g = props.headerHeight, headerHeight = _g === void 0 ? 36 : _g, rowSelection = props.rowSelection, onSortChange = props.onSortChange, onFilterChange = props.onFilterChange, onScroll = props.onScroll, onRowClick = props.onRowClick, onColumnResize = props.onColumnResize, _h = props.bordered, bordered = _h === void 0 ? true : _h, _j = props.striped, striped = _j === void 0 ? false : _j, _k = props.emptyText, emptyText = _k === void 0 ? "暂无数据" : _k, style = props.style, className = props.className, _l = props.loading, loading = _l === void 0 ? false : _l, _m = props.isContextMenu, isContextMenu = _m === void 0 ? true : _m, isFullscreenHandle = props.isFullscreenHandle, mode = props.mode, dynamicKey = props.dynamicKey, dynamicVersion = props.dynamicVersion, customDynamicListHandle = props.customDynamicListHandle, isDimensionDynamic = props.isDimensionDynamic, dimensionCustomSumKeys = props.dimensionCustomSumKeys, isAutoMerge = props.isAutoMerge, _o = props.isIndexMerge, isIndexMerge = _o === void 0 ? true : _o, _p = props.isSelectionMerge, isSelectionMerge = _p === void 0 ? false : _p, _q = props.renderMode, renderMode = _q === void 0 ? "object" : _q, fixedRowsCount = props.fixedRowsCount, fixedRowsConfig = props.fixedRowsConfig, _r = props.summaryFixed, summaryFixed = _r === void 0 ? false : _r, _s = props.isAutoScrollY, isAutoScrollY = _s === void 0 ? false : _s, _t = props.autoScrollYMarginBottom, autoScrollYMarginBottom = _t === void 0 ? 65 : _t, canvasTableId = props.canvasTableId, headerWrap = props.headerWrap, _u = props.headerAlign, headerAlign = _u === void 0 ? "center" : _u, tableRefHandle = props.tableRefHandle, exportExcelConfig = props.exportExcelConfig, _v = props.maxHeight, maxHeight = _v === void 0 ? 3000 : _v, expandable = props.expandable;
43
45
  var actualMode = "mode" in props ? mode : "index";
44
46
  var canvasRef = useRef(null);
45
47
  var containerRef = useRef(null);
@@ -62,17 +64,17 @@ function CanvasTable(props) {
62
64
  return String((_a = record[rowKey]) !== null && _a !== void 0 ? _a : index);
63
65
  }, [rowKey]);
64
66
  // 动态列配置
65
- var _v = useDynamicListByColumns(columns, {
67
+ var _w = useDynamicListByColumns(columns, {
66
68
  dynamicKey: dynamicKey,
67
69
  dynamicVersion: dynamicVersion,
68
70
  customDynamicListHandle: customDynamicListHandle,
69
- }), defaultDynamicList = _v.defaultDynamicList, currentDynamicList = _v.currentDynamicList, onCurrentListChange = _v.onCurrentListChange, dynamicSettingRef = _v.dynamicSettingRef;
71
+ }), defaultDynamicList = _w.defaultDynamicList, currentDynamicList = _w.currentDynamicList, onCurrentListChange = _w.onCurrentListChange, dynamicSettingRef = _w.dynamicSettingRef;
70
72
  // 根据动态列配置处理columns
71
73
  var dynamicColumns = useMemo(function () { return getTableColumns(columns, currentDynamicList); }, [columns, currentDynamicList]).columns;
72
74
  // 内部列宽状态(未开启动态配置时使用)
73
- var _w = useState({}), internalColumnWidths = _w[0], setInternalColumnWidths = _w[1];
75
+ var _x = useState({}), internalColumnWidths = _x[0], setInternalColumnWidths = _x[1];
74
76
  // 跟踪用户手动调整过宽度的列(用于排除自动宽度分配)
75
- var _x = useState(new Set()), manuallyResizedColumnKeys = _x[0], setManuallyResizedColumnKeys = _x[1];
77
+ var _y = useState(new Set()), manuallyResizedColumnKeys = _y[0], setManuallyResizedColumnKeys = _y[1];
76
78
  // 处理选中框列、序号列等
77
79
  var processedColumnsOld = useProcessedColumns({
78
80
  columns: columns,
@@ -87,33 +89,46 @@ function CanvasTable(props) {
87
89
  headerAlign: headerAlign,
88
90
  });
89
91
  // 表格状态管理
90
- var _y = useTableState({
92
+ var _z = useTableState({
91
93
  dataSource: dataSource,
92
94
  columns: processedColumnsOld,
93
95
  rowSelection: rowSelection,
94
96
  onFilterChange: onFilterChange,
95
97
  isAutoMerge: isAutoMerge,
96
- }), state = _y.state, setState = _y.setState, processedDataSource = _y.processedDataSource, handleFilterChange = _y.handleFilterChange, closeFilterPopover = _y.closeFilterPopover, autoGeneratedFilters = _y.autoGeneratedFilters;
98
+ }), state = _z.state, setState = _z.setState, processedDataSource = _z.processedDataSource, handleFilterChange = _z.handleFilterChange, closeFilterPopover = _z.closeFilterPopover, autoGeneratedFilters = _z.autoGeneratedFilters;
99
+ // 树形展开管理
100
+ var _0 = useExpandable({
101
+ dataSource: dataSource,
102
+ expandable: expandable,
103
+ rowKey: rowKey,
104
+ }), expandedKeys = _0.expandedKeys, flattenedData = _0.flattenedData, toggleExpand = _0.toggleExpand, expandRow = _0.expandRow, collapseRow = _0.collapseRow, setExpandedRowKeys = _0.setExpandedRowKeys, hasExpandable = _0.hasExpandable;
97
105
  var order = useMemo(function () {
98
106
  return state.sortOrder && state.sortField
99
107
  ? { field: state.sortField, order: state.sortOrder }
100
108
  : undefined;
101
109
  }, [state.sortOrder, state.sortField]);
102
- var _z = useAutoMerge(processedDataSource, processedColumnsOld, {
110
+ var _1 = useAutoMerge(processedDataSource, processedColumnsOld, {
103
111
  isAutoMerge: isAutoMerge,
104
112
  isDimensionDynamic: isDimensionDynamic,
105
113
  order: order,
106
114
  dimensionCustomSumKeys: dimensionCustomSumKeys,
107
- }), newDataSource = _z[0], processedColumns = _z[1];
115
+ }), newDataSource = _1[0], processedColumns = _1[1];
116
+ // 如果开启了树形展开,使用扁平化后的数据源
117
+ var expandedDataSource = useMemo(function () {
118
+ if (hasExpandable) {
119
+ return flattenedData.map(function (item) { return item.record; });
120
+ }
121
+ return newDataSource;
122
+ }, [hasExpandable, flattenedData, newDataSource]);
108
123
  // 生成合计行和最终数据源
109
- var _0 = useSummaryRow({
124
+ var _2 = useSummaryRow({
110
125
  columns: processedColumns,
111
- dataSource: newDataSource,
112
- }), finalDataSource = _0.finalDataSource, hasSummaryRow = _0.hasSummaryRow;
126
+ dataSource: expandedDataSource,
127
+ }), finalDataSource = _2.finalDataSource, hasSummaryRow = _2.hasSummaryRow;
113
128
  // 用于存储计算后的表头高度(用于自动高度的精确计算)
114
- var _1 = useState(undefined), preciseHeaderHeight = _1[0], setPreciseHeaderHeight = _1[1];
129
+ var _3 = useState(undefined), preciseHeaderHeight = _3[0], setPreciseHeaderHeight = _3[1];
115
130
  // 用于存储是否需要横向滚动条(用于自动高度的精确计算)
116
- var _2 = useState(false), needHorizontalScrollbar = _2[0], setNeedHorizontalScrollbar = _2[1];
131
+ var _4 = useState(false), needHorizontalScrollbar = _4[0], setNeedHorizontalScrollbar = _4[1];
117
132
  // 自动高度计算(需要在容器尺寸计算之前)
118
133
  var autoHeight = useCanvasTableAutoHeight(isAutoScrollY, autoScrollYMarginBottom, canvasTableId, finalDataSource.length, // 数据行数(用于 content 模式)
119
134
  headerHeight, // 表头基础高度(用于 content 模式的初始计算)
@@ -180,7 +195,7 @@ function CanvasTable(props) {
180
195
  return calculateTotalHeight(calculatedHeaderHeight, finalDataSource.length, rowHeight);
181
196
  }, [calculatedHeaderHeight, finalDataSource.length, rowHeight]);
182
197
  // 计算滚动条指标
183
- var _3 = useScrollbarMetrics({
198
+ var _5 = useScrollbarMetrics({
184
199
  containerWidth: containerWidth,
185
200
  containerHeight: containerHeight,
186
201
  totalWidth: totalWidth,
@@ -188,14 +203,14 @@ function CanvasTable(props) {
188
203
  headerHeight: calculatedHeaderHeight,
189
204
  scrollTop: 0,
190
205
  scrollLeft: 0,
191
- }), maxScrollTop = _3.maxScrollTop, maxScrollLeft = _3.maxScrollLeft;
206
+ }), maxScrollTop = _5.maxScrollTop, maxScrollLeft = _5.maxScrollLeft;
192
207
  // 滚动管理(使用预先计算的maxScrollTop和maxScrollLeft)
193
- var _4 = useTableScroll({
208
+ var _6 = useTableScroll({
194
209
  containerRef: containerRef,
195
210
  maxScrollTop: maxScrollTop,
196
211
  maxScrollLeft: maxScrollLeft,
197
212
  onScroll: onScroll,
198
- }), scrollState = _4.scrollState, setScrollState = _4.setScrollState;
213
+ }), scrollState = _6.scrollState, setScrollState = _6.setScrollState;
199
214
  // 使用 ref 保存最新的滚动位置,确保在组件卸载过程中仍能访问
200
215
  var scrollPositionRef = useRef({ x: 0, y: 0 });
201
216
  useEffect(function () {
@@ -213,6 +228,10 @@ function CanvasTable(props) {
213
228
  sortOrder: state.sortOrder,
214
229
  setScrollState: setScrollState,
215
230
  });
231
+ // 容器尺寸变化时重置滚动位置
232
+ useEffect(function () {
233
+ setScrollState(function (prev) { return (__assign(__assign({}, prev), { scrollLeft: 0, scrollTop: 0 })); });
234
+ }, [containerWidth, containerHeight, setScrollState]);
216
235
  // 使用实际滚动位置重新计算滚动条的显示位置
217
236
  var scrollbarMetrics = useScrollbarMetrics({
218
237
  containerWidth: containerWidth,
@@ -235,12 +254,12 @@ function CanvasTable(props) {
235
254
  needHorizontalScrollbar,
236
255
  ]);
237
256
  // 单元格框选
238
- var _5 = useTableSelection({
257
+ var _7 = useTableSelection({
239
258
  state: state,
240
259
  setState: setState,
241
260
  }),
242
261
  // selectionStartRef,
243
- startSelection = _5.startSelection, updateSelection = _5.updateSelection, extendSelection = _5.extendSelection;
262
+ startSelection = _7.startSelection, updateSelection = _7.updateSelection, extendSelection = _7.extendSelection;
244
263
  // 处理列宽调整
245
264
  var handleColumnResize = useCallback(function (columnKey, newWidth) {
246
265
  var _a;
@@ -295,20 +314,20 @@ function CanvasTable(props) {
295
314
  onCurrentListChange,
296
315
  ]);
297
316
  // 列宽调整
298
- var _6 = useColumnResize({
317
+ var _8 = useColumnResize({
299
318
  columnRenderInfos: columnRenderInfos,
300
319
  containerWidth: containerWidth,
301
320
  headerHeight: calculatedHeaderHeight,
302
321
  scrollLeft: scrollState.scrollLeft,
303
322
  onColumnResize: handleColumnResize,
304
- }), resizeState = _6.resizeState, checkResizeHandle = _6.checkResizeHandle, startResize = _6.startResize, updateResize = _6.updateResize, endResize = _6.endResize, setHoverResizeColumn = _6.setHoverResizeColumn, getColumnWidth = _6.getColumnWidth, RESIZE_HANDLE_WIDTH = _6.RESIZE_HANDLE_WIDTH;
323
+ }), resizeState = _8.resizeState, checkResizeHandle = _8.checkResizeHandle, startResize = _8.startResize, updateResize = _8.updateResize, endResize = _8.endResize, setHoverResizeColumn = _8.setHoverResizeColumn, getColumnWidth = _8.getColumnWidth, RESIZE_HANDLE_WIDTH = _8.RESIZE_HANDLE_WIDTH;
305
324
  // 复制到剪贴板
306
- var _7 = useCopyToClipboard({
325
+ var _9 = useCopyToClipboard({
307
326
  cellSelection: state.cellSelection,
308
327
  processedDataSource: finalDataSource,
309
328
  columns: processedColumns,
310
329
  containerRef: containerRef,
311
- }), getSelectedCellsText = _7.getSelectedCellsText, copyToClipboard = _7.copyToClipboard;
330
+ }), getSelectedCellsText = _9.getSelectedCellsText, copyToClipboard = _9.copyToClipboard;
312
331
  // 处理右键菜单的复制操作
313
332
  var handleCopy = useCallback(function () {
314
333
  var text = getSelectedCellsText();
@@ -325,9 +344,10 @@ function CanvasTable(props) {
325
344
  columns: exportColumns,
326
345
  isAutoMerge: isAutoMerge,
327
346
  summaryConfig: (exportExcelConfig === null || exportExcelConfig === void 0 ? void 0 : exportExcelConfig.isExportNoSummary) ? undefined : [],
347
+ childrenColumnName: (_a = props.expandable) === null || _a === void 0 ? void 0 : _a.childrenColumnName,
328
348
  });
329
349
  // 交互事件处理(使用baseScrollbarMetrics的maxScrollTop/maxScrollLeft以保持稳定)
330
- var _8 = useTableInteraction({
350
+ var _10 = useTableInteraction({
331
351
  state: state,
332
352
  setState: setState,
333
353
  scrollState: scrollState,
@@ -335,6 +355,8 @@ function CanvasTable(props) {
335
355
  processedDataSource: finalDataSource,
336
356
  columnRenderInfos: columnRenderInfos,
337
357
  columns: processedColumns,
358
+ expandable: expandable,
359
+ flattenedData: flattenedData,
338
360
  rowSelection: rowSelection,
339
361
  rowHeight: rowHeight,
340
362
  headerHeight: calculatedHeaderHeight,
@@ -359,6 +381,7 @@ function CanvasTable(props) {
359
381
  onSortChange: onSortChange,
360
382
  onRowClick: onRowClick,
361
383
  getRowKey: getRowKey,
384
+ onExpand: toggleExpand,
362
385
  startSelection: startSelection,
363
386
  updateSelection: updateSelection,
364
387
  extendSelection: extendSelection,
@@ -374,11 +397,11 @@ function CanvasTable(props) {
374
397
  fixedRowsCount: fixedRowsCount,
375
398
  fixedRowsConfig: fixedRowsConfig,
376
399
  summaryFixed: summaryFixed,
377
- }), handleCanvasMouseDown = _8.handleCanvasMouseDown, handleCanvasMouseMove = _8.handleCanvasMouseMove, handleCanvasMouseUp = _8.handleCanvasMouseUp, handleCanvasMouseLeave = _8.handleCanvasMouseLeave, handleCanvasContextMenu = _8.handleCanvasContextMenu;
400
+ }), handleCanvasMouseDown = _10.handleCanvasMouseDown, handleCanvasMouseMove = _10.handleCanvasMouseMove, handleCanvasMouseUp = _10.handleCanvasMouseUp, handleCanvasMouseLeave = _10.handleCanvasMouseLeave, handleCanvasContextMenu = _10.handleCanvasContextMenu;
378
401
  // 渲染表格
379
402
  useTableRender(__assign(__assign({ canvasRef: canvasRef, processedDataSource: finalDataSource, columnRenderInfos: columnRenderInfos, columns: processedColumns, // 传递原始columns用于渲染多级表头
380
403
  state: state, scrollState: scrollState, rowSelection: rowSelection, containerWidth: containerWidth, containerHeight: containerHeight, headerHeight: calculatedHeaderHeight, baseHeaderHeight: headerHeight, // 传入原始基础高度用于计算每层高度
381
- 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 }));
404
+ 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, expandable: expandable, flattenedData: flattenedData }));
382
405
  // 单元格覆盖层
383
406
  var cellOverlays = useTableCellOverlay({
384
407
  canvasRef: canvasRef,
@@ -469,6 +492,26 @@ function CanvasTable(props) {
469
492
  setSelectedRowKeys: function (keys) {
470
493
  setState(function (prev) { return (__assign(__assign({}, prev), { selectedRowKeys: keys })); });
471
494
  },
495
+ /** 获取展开的keys */
496
+ getExpandedRowKeys: function () {
497
+ return Array.from(expandedKeys);
498
+ },
499
+ /** 设置展开的keys */
500
+ setExpandedRowKeys: function (keys) {
501
+ setExpandedRowKeys(keys);
502
+ },
503
+ /** 展开指定行 */
504
+ expandRow: function (key) {
505
+ expandRow(key);
506
+ },
507
+ /** 收起指定行 */
508
+ collapseRow: function (key) {
509
+ collapseRow(key);
510
+ },
511
+ /** 切换指定行展开状态 */
512
+ toggleExpandRow: function (key) {
513
+ toggleExpand(key);
514
+ },
472
515
  /** 滚动到指定位置 */
473
516
  scrollTo: function (params) {
474
517
  setScrollState(function (prev) { return (__assign(__assign({}, prev), { scrollLeft: params.x !== undefined ? params.x : prev.scrollLeft, scrollTop: params.y !== undefined ? params.y : prev.scrollTop })); });
@@ -510,6 +553,11 @@ function CanvasTable(props) {
510
553
  state.filters,
511
554
  setState,
512
555
  setScrollState,
556
+ expandedKeys,
557
+ setExpandedRowKeys,
558
+ expandRow,
559
+ collapseRow,
560
+ toggleExpand,
513
561
  ]);
514
562
  return (jsx(Spin, __assign({ spinning: loading }, { children: jsxs("div", __assign({ ref: containerRef, id: canvasTableId, className: "canvas-table-container ".concat(className || ""), tabIndex: 0, style: __assign(__assign({}, style), { position: "relative", width: width || "100%", height: containerHeight, overflow: "hidden", touchAction: "none", outline: "none" }) }, { children: [jsx("canvas", { ref: canvasRef, onMouseDown: handleCanvasMouseDown, onMouseMove: handleCanvasMouseMove, onMouseUp: handleCanvasMouseUp, onMouseLeave: handleCanvasMouseLeave, onContextMenu: handleCanvasContextMenu, style: {
515
563
  display: "block",
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Badge 渲染�?
3
+ * 负责绘制单元格角标(三角形标记,类似Excel批注�?
4
+ */
5
+ var BadgeRenderer = /** @class */ (function () {
6
+ function BadgeRenderer() {
7
+ this.context = null;
8
+ }
9
+ BadgeRenderer.prototype.setContext = function (context) {
10
+ this.context = context;
11
+ };
12
+ /**
13
+ * 绘制角标
14
+ */
15
+ BadgeRenderer.prototype.render = function (badge, cellX, cellY, cellWidth, cellHeight) {
16
+ if (!this.context) {
17
+ throw new Error("BadgeRenderer: Context not set");
18
+ }
19
+ var ctx = this.context.ctx;
20
+ var triangleSize = 12; // 三角形边�?
21
+ var position = badge.position || "top-right";
22
+ var color = badge.color || "#ff4d4f";
23
+ ctx.fillStyle = color;
24
+ ctx.beginPath();
25
+ // 根据位置绘制不同方向的三角形
26
+ switch (position) {
27
+ case "top-left":
28
+ // 左上角三角形
29
+ ctx.moveTo(cellX, cellY);
30
+ ctx.lineTo(cellX + triangleSize, cellY);
31
+ ctx.lineTo(cellX, cellY + triangleSize);
32
+ break;
33
+ case "top-right":
34
+ // 右上角三角形(默认)
35
+ ctx.moveTo(cellX + cellWidth, cellY);
36
+ ctx.lineTo(cellX + cellWidth - triangleSize, cellY);
37
+ ctx.lineTo(cellX + cellWidth, cellY + triangleSize);
38
+ break;
39
+ case "bottom-left":
40
+ // 左下角三角形
41
+ ctx.moveTo(cellX, cellY + cellHeight);
42
+ ctx.lineTo(cellX, cellY + cellHeight - triangleSize);
43
+ ctx.lineTo(cellX + triangleSize, cellY + cellHeight);
44
+ break;
45
+ case "bottom-right":
46
+ // 右下角三角形
47
+ ctx.moveTo(cellX + cellWidth, cellY + cellHeight);
48
+ ctx.lineTo(cellX + cellWidth, cellY + cellHeight - triangleSize);
49
+ ctx.lineTo(cellX + cellWidth - triangleSize, cellY + cellHeight);
50
+ break;
51
+ }
52
+ ctx.closePath();
53
+ ctx.fill();
54
+ };
55
+ return BadgeRenderer;
56
+ }());
57
+
58
+ export { BadgeRenderer };
@@ -0,0 +1,229 @@
1
+ import { COLORS, SCROLLBAR_SIZE } from '../../utils/constants.js';
2
+ import 'zmdms-utils';
3
+ import 'dayjs';
4
+ import '../../../_virtual/_tslib.js';
5
+ import { calculateFixedColumnsRightEdge } from '../../utils/renderHelpers.js';
6
+
7
+ /**
8
+ * 边框渲染�?
9
+ * 负责渲染表格的所有边框(数据行、固定行、表头)
10
+ */
11
+ var BorderRenderer = /** @class */ (function () {
12
+ function BorderRenderer() {
13
+ this.context = null;
14
+ }
15
+ BorderRenderer.prototype.setContext = function (context) {
16
+ this.context = context;
17
+ };
18
+ /**
19
+ * 渲染数据行边�?
20
+ */
21
+ BorderRenderer.prototype.renderDataBorders = function (startRow, endRow, onlyFixed) {
22
+ if (onlyFixed === void 0) { onlyFixed = false; }
23
+ if (!this.context || !this.context.bordered)
24
+ return;
25
+ var _a = this.context, ctx = _a.ctx, processedDataSource = _a.processedDataSource, headerHeight = _a.headerHeight, rowHeight = _a.rowHeight, scrollState = _a.scrollState, displayWidth = _a.displayWidth, displayHeight = _a.displayHeight, needHorizontalScrollbar = _a.needHorizontalScrollbar, fixedRowsCount = _a.fixedRowsCount, fixedRowsConfig = _a.fixedRowsConfig, summaryFixed = _a.summaryFixed, hasSummaryRow = _a.hasSummaryRow, columnRenderInfos = _a.columnRenderInfos, getColumnWidth = _a.getColumnWidth, mergeCellMap = _a.mergeCellMap;
26
+ ctx.strokeStyle = COLORS.border;
27
+ ctx.lineWidth = 1;
28
+ var dataRowCount = processedDataSource.length;
29
+ // 计算固定行占用的高度
30
+ var fixedTopRowsCount = fixedRowsCount || (fixedRowsConfig === null || fixedRowsConfig === void 0 ? void 0 : fixedRowsConfig.topCount) || 0;
31
+ var fixedBottomRowsCount = (fixedRowsConfig === null || fixedRowsConfig === void 0 ? void 0 : fixedRowsConfig.bottomCount) || 0;
32
+ var fixedSummaryHeight = summaryFixed && hasSummaryRow ? rowHeight : 0;
33
+ var fixedBottomHeight = fixedBottomRowsCount * rowHeight;
34
+ // 计算可滚动数据行的数�?
35
+ var scrollableDataRowCount = dataRowCount -
36
+ fixedTopRowsCount -
37
+ fixedBottomRowsCount -
38
+ (summaryFixed && hasSummaryRow ? 1 : 0);
39
+ // 计算实际数据区域的底部位�?
40
+ var dataBottomY = Math.min(headerHeight +
41
+ fixedTopRowsCount * rowHeight +
42
+ scrollableDataRowCount * rowHeight -
43
+ scrollState.scrollTop, displayHeight -
44
+ (needHorizontalScrollbar ? SCROLLBAR_SIZE : 0) -
45
+ fixedBottomHeight -
46
+ fixedSummaryHeight);
47
+ // 绘制垂直边框
48
+ columnRenderInfos.forEach(function (info, colIndex) {
49
+ var x = info.x, width = info.width, fixed = info.fixed, fixedLeft = info.fixedLeft;
50
+ if (onlyFixed && !fixed)
51
+ return;
52
+ if (!onlyFixed && fixed)
53
+ return;
54
+ var actualWidth = getColumnWidth ? getColumnWidth(colIndex) : width;
55
+ var drawX = fixed
56
+ ? fixedLeft + actualWidth
57
+ : x + actualWidth - scrollState.scrollLeft;
58
+ if (drawX >= 0 && drawX <= displayWidth) {
59
+ ctx.beginPath();
60
+ ctx.moveTo(drawX, headerHeight);
61
+ ctx.lineTo(drawX, dataBottomY);
62
+ ctx.stroke();
63
+ }
64
+ });
65
+ // 绘制水平边框
66
+ var maxRow = Math.min(endRow, dataRowCount, fixedTopRowsCount + scrollableDataRowCount);
67
+ var _loop_1 = function (i) {
68
+ var y = headerHeight +
69
+ fixedTopRowsCount * rowHeight +
70
+ (i - fixedTopRowsCount) * rowHeight -
71
+ scrollState.scrollTop;
72
+ if (y >= headerHeight + fixedTopRowsCount * rowHeight &&
73
+ y <= dataBottomY) {
74
+ // 分段绘制,只绘制当前范围的边�?
75
+ columnRenderInfos.forEach(function (info, colIndex) {
76
+ if (onlyFixed && !info.fixed)
77
+ return;
78
+ if (!onlyFixed && info.fixed)
79
+ return;
80
+ var mergeCellKey = "".concat(i, "-").concat(colIndex);
81
+ var mergeInfo = mergeCellMap === null || mergeCellMap === void 0 ? void 0 : mergeCellMap.get(mergeCellKey);
82
+ // 只有被合并的单元格(skip=true)才跳过绘制上边�?
83
+ if (mergeInfo && mergeInfo.skip) {
84
+ return;
85
+ }
86
+ var x = info.x, width = info.width, fixed = info.fixed, fixedLeft = info.fixedLeft;
87
+ var actualWidth = getColumnWidth ? getColumnWidth(colIndex) : width;
88
+ var drawX = fixed ? fixedLeft : x - scrollState.scrollLeft;
89
+ if (!fixed && (drawX + actualWidth < 0 || drawX > displayWidth)) {
90
+ return;
91
+ }
92
+ ctx.beginPath();
93
+ ctx.moveTo(Math.max(drawX, 0), y);
94
+ ctx.lineTo(Math.min(drawX + actualWidth, displayWidth), y);
95
+ ctx.stroke();
96
+ });
97
+ }
98
+ };
99
+ for (var i = startRow; i <= maxRow; i++) {
100
+ _loop_1(i);
101
+ }
102
+ // 为合并单元格绘制底部边框
103
+ if (mergeCellMap && mergeCellMap.size > 0) {
104
+ mergeCellMap.forEach(function (mergeInfo) {
105
+ if (!mergeInfo.skip && mergeInfo.rowSpan > 1) {
106
+ var rowIndex = mergeInfo.rowIndex, colIndex = mergeInfo.colIndex, rowSpan = mergeInfo.rowSpan;
107
+ if (rowIndex >= startRow && rowIndex <= maxRow) {
108
+ var columnInfo = columnRenderInfos[colIndex];
109
+ if (!columnInfo)
110
+ return;
111
+ if (onlyFixed && !columnInfo.fixed)
112
+ return;
113
+ if (!onlyFixed && columnInfo.fixed)
114
+ return;
115
+ var x = columnInfo.x, width = columnInfo.width, fixed = columnInfo.fixed, fixedLeft = columnInfo.fixedLeft;
116
+ var actualWidth = getColumnWidth
117
+ ? getColumnWidth(colIndex)
118
+ : width;
119
+ var drawX = fixed ? fixedLeft : x - scrollState.scrollLeft;
120
+ var bottomY = headerHeight +
121
+ fixedTopRowsCount * rowHeight +
122
+ (rowIndex + rowSpan - fixedTopRowsCount) * rowHeight -
123
+ scrollState.scrollTop;
124
+ if (bottomY >= headerHeight + fixedTopRowsCount * rowHeight &&
125
+ bottomY <= dataBottomY) {
126
+ ctx.beginPath();
127
+ ctx.moveTo(drawX, bottomY);
128
+ ctx.lineTo(drawX + actualWidth, bottomY);
129
+ ctx.stroke();
130
+ }
131
+ }
132
+ }
133
+ });
134
+ }
135
+ };
136
+ /**
137
+ * 渲染固定行边框(通用�?
138
+ */
139
+ BorderRenderer.prototype.renderFixedRowBorders = function (rowCount, startYCalculator, onlyFixed, borderType) {
140
+ var _this = this;
141
+ if (onlyFixed === void 0) { onlyFixed = false; }
142
+ if (borderType === void 0) { borderType = "normal"; }
143
+ if (!this.context || !this.context.bordered)
144
+ return;
145
+ var _a = this.context, ctx = _a.ctx, columnRenderInfos = _a.columnRenderInfos, scrollState = _a.scrollState, displayWidth = _a.displayWidth, getColumnWidth = _a.getColumnWidth;
146
+ ctx.save();
147
+ ctx.strokeStyle = COLORS.border;
148
+ ctx.lineWidth = borderType === "summary" ? 2 : 1;
149
+ var startY = startYCalculator();
150
+ // 计算固定列的右边�?
151
+ var fixedColumnsRightEdge = 0;
152
+ if (onlyFixed) {
153
+ fixedColumnsRightEdge = calculateFixedColumnsRightEdge(columnRenderInfos, getColumnWidth);
154
+ }
155
+ // 绘制水平边框
156
+ for (var i = 0; i <= rowCount; i++) {
157
+ var y = startY + i * this.context.rowHeight;
158
+ ctx.beginPath();
159
+ if (onlyFixed) {
160
+ ctx.moveTo(0, y);
161
+ ctx.lineTo(fixedColumnsRightEdge, y);
162
+ }
163
+ else {
164
+ ctx.moveTo(0, y);
165
+ ctx.lineTo(displayWidth, y);
166
+ }
167
+ ctx.stroke();
168
+ }
169
+ // 绘制垂直边框
170
+ ctx.lineWidth = 1;
171
+ columnRenderInfos.forEach(function (info, colIndex) {
172
+ var _a;
173
+ var x = info.x, width = info.width, fixed = info.fixed, fixedLeft = info.fixedLeft;
174
+ if (onlyFixed && !fixed)
175
+ return;
176
+ if (!onlyFixed && fixed)
177
+ return;
178
+ var actualWidth = getColumnWidth ? getColumnWidth(colIndex) : width;
179
+ var drawX = fixed
180
+ ? fixedLeft + actualWidth
181
+ : x + actualWidth - scrollState.scrollLeft;
182
+ if (drawX >= 0 && drawX <= displayWidth) {
183
+ ctx.beginPath();
184
+ ctx.moveTo(drawX, startY);
185
+ ctx.lineTo(drawX, startY + rowCount * (((_a = _this.context) === null || _a === void 0 ? void 0 : _a.rowHeight) || 0));
186
+ ctx.stroke();
187
+ }
188
+ });
189
+ ctx.restore();
190
+ };
191
+ /**
192
+ * 渲染固定顶部行边�?
193
+ */
194
+ BorderRenderer.prototype.renderFixedTopBorders = function (rowCount, onlyFixed) {
195
+ var _this = this;
196
+ if (onlyFixed === void 0) { onlyFixed = false; }
197
+ if (!this.context)
198
+ return;
199
+ this.renderFixedRowBorders(rowCount, function () { return _this.context.headerHeight; }, onlyFixed, "normal");
200
+ };
201
+ /**
202
+ * 渲染固定底部行边�?
203
+ */
204
+ BorderRenderer.prototype.renderFixedBottomBorders = function (rowCount, onlyFixed) {
205
+ if (onlyFixed === void 0) { onlyFixed = false; }
206
+ if (!this.context)
207
+ return;
208
+ var _a = this.context, displayHeight = _a.displayHeight, needHorizontalScrollbar = _a.needHorizontalScrollbar, summaryFixed = _a.summaryFixed, hasSummaryRow = _a.hasSummaryRow, rowHeight = _a.rowHeight;
209
+ this.renderFixedRowBorders(rowCount, function () {
210
+ var fixedSummaryHeight = summaryFixed && hasSummaryRow ? rowHeight : 0;
211
+ return (displayHeight -
212
+ (needHorizontalScrollbar ? SCROLLBAR_SIZE : 0) -
213
+ fixedSummaryHeight -
214
+ rowCount * rowHeight);
215
+ }, onlyFixed, "normal");
216
+ };
217
+ /**
218
+ * 渲染固定合计行边�?
219
+ */
220
+ BorderRenderer.prototype.renderFixedSummaryBorder = function (fixedY, onlyFixed) {
221
+ if (onlyFixed === void 0) { onlyFixed = false; }
222
+ if (!this.context)
223
+ return;
224
+ this.renderFixedRowBorders(1, function () { return fixedY; }, onlyFixed, "summary");
225
+ };
226
+ return BorderRenderer;
227
+ }());
228
+
229
+ export { BorderRenderer };