zmdms-webui 2.2.9 → 2.3.1

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.
Files changed (73) hide show
  1. package/dist/es/canvastable/canvasTable.js +367 -0
  2. package/dist/es/canvastable/components/BadgePopover.js +27 -0
  3. package/dist/es/canvastable/components/CanvasTableMenu.js +74 -0
  4. package/dist/es/canvastable/components/CellOverlay.js +49 -0
  5. package/dist/es/canvastable/components/ColumnDynamic.js +12 -0
  6. package/dist/es/canvastable/components/EmptyPlaceholder.js +20 -0
  7. package/dist/es/canvastable/components/FilterPopover.js +274 -0
  8. package/dist/es/canvastable/components/HeaderOverlay.js +22 -0
  9. package/dist/es/canvastable/components/Tooltip.js +27 -0
  10. package/dist/es/canvastable/hooks/useClickOutside.js +30 -0
  11. package/dist/es/canvastable/hooks/useColumnResize.js +130 -0
  12. package/dist/es/canvastable/hooks/useContainerSize.js +40 -0
  13. package/dist/es/canvastable/hooks/useCopyToClipboard.js +150 -0
  14. package/dist/es/canvastable/hooks/useHeaderHeight.js +103 -0
  15. package/dist/es/canvastable/hooks/useMergeCells.js +111 -0
  16. package/dist/es/canvastable/hooks/useOverlays.js +364 -0
  17. package/dist/es/canvastable/hooks/usePopovers.js +93 -0
  18. package/dist/es/canvastable/hooks/useProcessedColumns.js +94 -0
  19. package/dist/es/canvastable/hooks/useScroll.js +251 -0
  20. package/dist/es/canvastable/hooks/useSummaryRow.js +81 -0
  21. package/dist/es/canvastable/hooks/useTableInteraction.js +804 -0
  22. package/dist/es/canvastable/hooks/useTableRender.js +1289 -0
  23. package/dist/es/canvastable/hooks/useTableSelection.js +57 -0
  24. package/dist/es/canvastable/hooks/useTableState.js +218 -0
  25. package/dist/es/canvastable/index.js +5 -0
  26. package/dist/es/canvastable/utils/canvasDrawHelpers.js +156 -0
  27. package/dist/es/canvastable/utils/cellHelpers.js +121 -0
  28. package/dist/es/canvastable/utils/columnHelpers.js +67 -0
  29. package/dist/es/canvastable/utils/constants.js +42 -0
  30. package/dist/es/canvastable/utils/formatHelpers.js +60 -0
  31. package/dist/es/canvastable/utils/interactionHelpers.js +176 -0
  32. package/dist/es/canvastable/utils/multiHeaderHelpers.js +82 -0
  33. package/dist/es/canvastable/utils/tableCalculations.js +100 -0
  34. package/dist/es/form/form.js +1 -0
  35. package/dist/index.dark.css +1 -1
  36. package/dist/index.default.css +1 -1
  37. package/dist/index.es.css +1 -1
  38. package/dist/less/components/CanvasTable/style/index.less +106 -0
  39. package/dist/less/components/Form/style/index.less +6 -1
  40. package/package.json +1 -1
  41. package/dist/es/cascader/index.css +0 -1
  42. package/dist/es/collapse/index.css +0 -1
  43. package/dist/es/container/index.css +0 -1
  44. package/dist/es/datepicker/index.css +0 -1
  45. package/dist/es/descriptions/index.css +0 -1
  46. package/dist/es/detaillist/index.css +0 -1
  47. package/dist/es/differences/index.css +0 -1
  48. package/dist/es/dynamicsetting/index.css +0 -1
  49. package/dist/es/electronsignatures/index.css +0 -1
  50. package/dist/es/footer/index.css +0 -1
  51. package/dist/es/form/index.css +0 -1
  52. package/dist/es/formitem/index.css +0 -1
  53. package/dist/es/input/index.css +0 -1
  54. package/dist/es/inputnumber/index.css +0 -1
  55. package/dist/es/leftcontent/index.css +0 -1
  56. package/dist/es/message/index.css +0 -1
  57. package/dist/es/microloading/index.css +0 -1
  58. package/dist/es/modal/index.css +0 -1
  59. package/dist/es/notauthpage/index.css +0 -0
  60. package/dist/es/notroutepage/index.css +0 -0
  61. package/dist/es/pagination/index.css +0 -1
  62. package/dist/es/placeholder/index.css +0 -1
  63. package/dist/es/print/index.css +0 -1
  64. package/dist/es/select/index.css +0 -1
  65. package/dist/es/table/index.css +0 -1
  66. package/dist/es/tabs/index.css +0 -1
  67. package/dist/es/tag/index.css +0 -1
  68. package/dist/es/title/index.css +0 -1
  69. package/dist/es/tree/index.css +0 -1
  70. package/dist/es/treeselect/index.css +0 -1
  71. package/dist/es/uploadlist/index.css +0 -1
  72. package/dist/es/watermark/index.css +0 -1
  73. package/dist/es/zttransfer/index.css +0 -1
@@ -0,0 +1,57 @@
1
+ import { __assign } from '../../_virtual/_tslib.js';
2
+ import { useRef } from 'react';
3
+ import { useMemoizedFn } from 'ahooks';
4
+
5
+ /**
6
+ * 单元格框选管理 Hook
7
+ */
8
+ var useTableSelection = function (params) {
9
+ var setState = params.setState;
10
+ // 框选起始位置
11
+ var selectionStartRef = useRef(null);
12
+ // 开始框选
13
+ var startSelection = useMemoizedFn(function (cell) {
14
+ selectionStartRef.current = cell;
15
+ setState(function (prev) { return (__assign(__assign({}, prev), { isSelecting: true, cellSelection: {
16
+ startRow: cell.row,
17
+ endRow: cell.row,
18
+ startCol: cell.col,
19
+ endCol: cell.col,
20
+ } })); });
21
+ });
22
+ // 更新框选区域
23
+ var updateSelection = useMemoizedFn(function (cell) {
24
+ if (!selectionStartRef.current)
25
+ return;
26
+ setState(function (prev) { return (__assign(__assign({}, prev), { cellSelection: {
27
+ startRow: selectionStartRef.current.row,
28
+ startCol: selectionStartRef.current.col,
29
+ endRow: cell.row,
30
+ endCol: cell.col,
31
+ } })); });
32
+ });
33
+ // 扩展选区(Shift+点击)
34
+ var extendSelection = useMemoizedFn(function (cell) {
35
+ setState(function (prev) { return (__assign(__assign({}, prev), { cellSelection: __assign(__assign({}, prev.cellSelection), { endRow: cell.row, endCol: cell.col }) })); });
36
+ });
37
+ // 结束框选
38
+ var endSelection = useMemoizedFn(function () {
39
+ setState(function (prev) { return (__assign(__assign({}, prev), { isSelecting: false })); });
40
+ selectionStartRef.current = null;
41
+ });
42
+ // 清除选区
43
+ var clearSelection = useMemoizedFn(function () {
44
+ setState(function (prev) { return (__assign(__assign({}, prev), { cellSelection: null, isSelecting: false })); });
45
+ selectionStartRef.current = null;
46
+ });
47
+ return {
48
+ selectionStartRef: selectionStartRef,
49
+ startSelection: startSelection,
50
+ updateSelection: updateSelection,
51
+ extendSelection: extendSelection,
52
+ endSelection: endSelection,
53
+ clearSelection: clearSelection,
54
+ };
55
+ };
56
+
57
+ export { useTableSelection };
@@ -0,0 +1,218 @@
1
+ import { __assign, __spreadArray } from '../../_virtual/_tslib.js';
2
+ import { useState, useEffect, useMemo } from 'react';
3
+ import { useMemoizedFn } from 'ahooks';
4
+ import 'dayjs';
5
+ import { getAllLeafColumns, findColumnByKey } from '../utils/columnHelpers.js';
6
+
7
+ /**
8
+ * 表格状态管理 Hook
9
+ */
10
+ var useTableState = function (params) {
11
+ var dataSource = params.dataSource, columns = params.columns, rowSelection = params.rowSelection, onFilterChange = params.onFilterChange;
12
+ // 表格状态
13
+ var _a = useState({
14
+ sortField: null,
15
+ sortOrder: null,
16
+ filters: {},
17
+ selectedRowKeys: (rowSelection === null || rowSelection === void 0 ? void 0 : rowSelection.selectedRowKeys) || [],
18
+ hoverRowIndex: null,
19
+ filterPopover: {
20
+ visible: false,
21
+ columnKey: null,
22
+ position: { x: 0, y: 0 },
23
+ },
24
+ cellSelection: null,
25
+ isSelecting: false,
26
+ tooltip: {
27
+ visible: false,
28
+ content: "",
29
+ position: { x: 0, y: 0 },
30
+ cellInfo: null,
31
+ },
32
+ badgePopover: {
33
+ visible: false,
34
+ content: "",
35
+ position: { x: 0, y: 0 },
36
+ },
37
+ }), state = _a[0], setState = _a[1];
38
+ // 同步外部选中状态
39
+ useEffect(function () {
40
+ if (rowSelection === null || rowSelection === void 0 ? void 0 : rowSelection.selectedRowKeys) {
41
+ setState(function (prev) { return (__assign(__assign({}, prev), { selectedRowKeys: rowSelection.selectedRowKeys || [] })); });
42
+ }
43
+ }, [rowSelection === null || rowSelection === void 0 ? void 0 : rowSelection.selectedRowKeys]);
44
+ // 自动生成筛选选项(基于数据的唯一值)
45
+ var autoGeneratedFilters = useMemo(function () {
46
+ var filtersMap = {};
47
+ // 如果没有数据,直接返回空对象
48
+ if (dataSource.length === 0) {
49
+ return filtersMap;
50
+ }
51
+ // 获取所有叶子列(包括多级表头中的嵌套列)
52
+ var leafColumns = getAllLeafColumns(columns);
53
+ leafColumns.forEach(function (column) {
54
+ // 如果列已经有有效的filters或未开启filter,跳过
55
+ if ((column.filters && column.filters.length > 0) ||
56
+ column.isFilter === false ||
57
+ column.key === "__selection__") {
58
+ return;
59
+ }
60
+ var dataIndex = column.dataIndex || column.key;
61
+ var uniqueValues = new Set();
62
+ dataSource.forEach(function (record) {
63
+ var value = record[dataIndex];
64
+ if (value !== null && value !== undefined && value !== "") {
65
+ uniqueValues.add(value);
66
+ }
67
+ });
68
+ if (uniqueValues.size > 0) {
69
+ filtersMap[column.key] = Array.from(uniqueValues)
70
+ .map(function (value) { return ({
71
+ text: String(value),
72
+ value: value,
73
+ }); })
74
+ .slice(0, 50);
75
+ }
76
+ });
77
+ return filtersMap;
78
+ }, [dataSource, columns]);
79
+ // 判断是否为数值筛选
80
+ var isNumberFilter = function (value) {
81
+ return (value &&
82
+ typeof value === "object" &&
83
+ "operator" in value &&
84
+ "value" in value);
85
+ };
86
+ // 判断是否为模糊查询
87
+ var isFuzzyFilter = function (value) {
88
+ return value && typeof value === "object" && "__fuzzy__" in value;
89
+ };
90
+ // 应用数值筛选
91
+ var applyNumberFilter = function (recordValue, filterValue) {
92
+ var numValue = parseFloat(recordValue);
93
+ if (isNaN(numValue))
94
+ return false;
95
+ var operator = filterValue.operator, value = filterValue.value;
96
+ switch (operator) {
97
+ case "=":
98
+ return numValue === value;
99
+ case "!=":
100
+ return numValue !== value;
101
+ case ">":
102
+ return numValue > value;
103
+ case "<":
104
+ return numValue < value;
105
+ case ">=":
106
+ return numValue >= value;
107
+ case "<=":
108
+ return numValue <= value;
109
+ default:
110
+ return false;
111
+ }
112
+ };
113
+ // 过滤和排序后的数据
114
+ var processedDataSource = useMemo(function () {
115
+ var data = __spreadArray([], dataSource, true);
116
+ // 应用过滤
117
+ Object.keys(state.filters).forEach(function (key) {
118
+ var filterValues = state.filters[key];
119
+ if (filterValues && filterValues.length > 0) {
120
+ var column_1 = findColumnByKey(columns, key);
121
+ var dataIndex_1 = (column_1 === null || column_1 === void 0 ? void 0 : column_1.dataIndex) || key;
122
+ if (column_1 === null || column_1 === void 0 ? void 0 : column_1.onFilter) {
123
+ // 使用自定义过滤方法
124
+ data = data.filter(function (record) {
125
+ return filterValues.some(function (value) { return column_1.onFilter(value, record); });
126
+ });
127
+ }
128
+ else {
129
+ // 检查是否为数值筛选
130
+ var firstValue = filterValues[0];
131
+ if (isNumberFilter(firstValue)) {
132
+ // 数值筛选逻辑
133
+ // 如果有多个条件(区间筛选),需要同时满足所有条件(且关系)
134
+ // 如果只有一个条件(单值筛选),满足该条件即可
135
+ data = data.filter(function (record) {
136
+ return filterValues.every(function (filterValue) {
137
+ return applyNumberFilter(record[dataIndex_1], filterValue);
138
+ });
139
+ });
140
+ }
141
+ else if (isFuzzyFilter(firstValue)) {
142
+ // 模糊查询逻辑
143
+ var searchText_1 = firstValue.text.toLowerCase();
144
+ data = data.filter(function (record) {
145
+ var recordValue = String(record[dataIndex_1] || "");
146
+ return recordValue.toLowerCase().includes(searchText_1);
147
+ });
148
+ }
149
+ else {
150
+ // 使用默认过滤方法(精确匹配)
151
+ data = data.filter(function (record) {
152
+ return filterValues.includes(record[dataIndex_1]);
153
+ });
154
+ }
155
+ }
156
+ }
157
+ });
158
+ // 应用排序
159
+ if (state.sortField && state.sortOrder) {
160
+ var column_2 = findColumnByKey(columns, state.sortField);
161
+ if (column_2 && column_2.isOrder !== false) {
162
+ var sortFn_1 = typeof column_2.sorter === "function"
163
+ ? column_2.sorter
164
+ : function (a, b) {
165
+ var dataIndex = column_2.dataIndex || column_2.key;
166
+ var aVal = a[dataIndex];
167
+ var bVal = b[dataIndex];
168
+ // 默认排序逻辑
169
+ if (aVal === bVal)
170
+ return 0;
171
+ if (aVal === null || aVal === undefined)
172
+ return 1;
173
+ if (bVal === null || bVal === undefined)
174
+ return -1;
175
+ // 数字排序
176
+ if (typeof aVal === "number" && typeof bVal === "number") {
177
+ return aVal - bVal;
178
+ }
179
+ // 字符串排序
180
+ return String(aVal).localeCompare(String(bVal));
181
+ };
182
+ data.sort(function (a, b) {
183
+ var result = sortFn_1(a, b);
184
+ return state.sortOrder === "ascend" ? result : -result;
185
+ });
186
+ }
187
+ }
188
+ return data;
189
+ }, [dataSource, columns, state.filters, state.sortField, state.sortOrder]);
190
+ // 处理过滤变化
191
+ var handleFilterChange = useMemoizedFn(function (columnKey, values) {
192
+ var _a;
193
+ setState(function (prev) {
194
+ var _a;
195
+ return (__assign(__assign({}, prev), { filters: __assign(__assign({}, prev.filters), (_a = {}, _a[columnKey] = values, _a)) }));
196
+ });
197
+ var newFilters = __assign(__assign({}, state.filters), (_a = {}, _a[columnKey] = values, _a));
198
+ onFilterChange === null || onFilterChange === void 0 ? void 0 : onFilterChange(newFilters);
199
+ });
200
+ // 关闭过滤弹窗
201
+ var closeFilterPopover = useMemoizedFn(function () {
202
+ setState(function (prev) { return (__assign(__assign({}, prev), { filterPopover: {
203
+ visible: false,
204
+ columnKey: null,
205
+ position: { x: 0, y: 0 },
206
+ } })); });
207
+ });
208
+ return {
209
+ state: state,
210
+ setState: setState,
211
+ processedDataSource: processedDataSource,
212
+ handleFilterChange: handleFilterChange,
213
+ closeFilterPopover: closeFilterPopover,
214
+ autoGeneratedFilters: autoGeneratedFilters,
215
+ };
216
+ };
217
+
218
+ export { useTableState };
@@ -0,0 +1,5 @@
1
+ import CanvasTable from './canvasTable.js';
2
+
3
+
4
+
5
+ export { CanvasTable as default };
@@ -0,0 +1,156 @@
1
+ import { COLORS, CHECKBOX_SIZE, SORT_ICON_SIZE } from './constants.js';
2
+
3
+ /**
4
+ * Canvas 绘制辅助函数
5
+ */
6
+ /**
7
+ * 绘制复选框
8
+ */
9
+ var drawCheckbox = function (ctx, x, y, checked, disabled, indeterminate) {
10
+ if (indeterminate === void 0) { indeterminate = false; }
11
+ var size = CHECKBOX_SIZE;
12
+ var centerX = x;
13
+ var centerY = y;
14
+ // 绘制边框
15
+ if (disabled) {
16
+ // 禁用状态:灰色边框和背景
17
+ ctx.strokeStyle = COLORS.checkboxDisabled;
18
+ ctx.fillStyle = checked || indeterminate ? "#f5f5f5" : COLORS.white;
19
+ }
20
+ else if (checked || indeterminate) {
21
+ // 选中或部分选中状态
22
+ ctx.strokeStyle = COLORS.primary;
23
+ ctx.fillStyle = COLORS.primary;
24
+ }
25
+ else {
26
+ // 正常未选中状态
27
+ ctx.strokeStyle = COLORS.checkboxBorder;
28
+ ctx.fillStyle = COLORS.white;
29
+ }
30
+ ctx.lineWidth = 1;
31
+ ctx.beginPath();
32
+ ctx.rect(centerX - size / 2, centerY - size / 2, size, size);
33
+ ctx.fill();
34
+ ctx.stroke();
35
+ // 绘制勾选标记或部分选中标记
36
+ if (indeterminate) {
37
+ // 部分选中状态:绘制横线
38
+ ctx.strokeStyle = disabled ? COLORS.checkboxDisabled : COLORS.white;
39
+ ctx.lineWidth = 2;
40
+ ctx.beginPath();
41
+ ctx.moveTo(centerX - 4, centerY);
42
+ ctx.lineTo(centerX + 4, centerY);
43
+ ctx.stroke();
44
+ }
45
+ else if (checked) {
46
+ // 完全选中状态:绘制勾选标记
47
+ ctx.strokeStyle = disabled ? COLORS.checkboxDisabled : COLORS.white;
48
+ ctx.lineWidth = 2;
49
+ ctx.beginPath();
50
+ ctx.moveTo(centerX - 4, centerY);
51
+ ctx.lineTo(centerX - 1, centerY + 3);
52
+ ctx.lineTo(centerX + 4, centerY - 4);
53
+ ctx.stroke();
54
+ }
55
+ };
56
+ /**
57
+ * 绘制排序图标
58
+ */
59
+ var drawSortIcon = function (ctx, x, y, order) {
60
+ var size = SORT_ICON_SIZE;
61
+ var gap = 4; // 上下箭头间距
62
+ // 向上箭头(居中绘制)
63
+ ctx.fillStyle = order === "ascend" ? COLORS.primary : COLORS.scrollbarThumb;
64
+ ctx.beginPath();
65
+ ctx.moveTo(x, y - gap / 2 - size); // 顶点
66
+ ctx.lineTo(x - size / 2, y - gap / 2); // 左下角
67
+ ctx.lineTo(x + size / 2, y - gap / 2); // 右下角
68
+ ctx.closePath();
69
+ ctx.fill();
70
+ // 向下箭头(居中绘制)
71
+ ctx.fillStyle = order === "descend" ? COLORS.primary : COLORS.scrollbarThumb;
72
+ ctx.beginPath();
73
+ ctx.moveTo(x, y + gap / 2 + size); // 底点
74
+ ctx.lineTo(x - size / 2, y + gap / 2); // 左上角
75
+ ctx.lineTo(x + size / 2, y + gap / 2); // 右上角
76
+ ctx.closePath();
77
+ ctx.fill();
78
+ };
79
+ /**
80
+ * 绘制过滤图标(放大镜)
81
+ */
82
+ var drawFilterIcon = function (ctx, x, y, active) {
83
+ ctx.strokeStyle = active ? COLORS.primary : COLORS.scrollbarThumb;
84
+ ctx.fillStyle = active ? COLORS.primary : COLORS.scrollbarThumb;
85
+ ctx.lineWidth = 1.5;
86
+ // 绘制圆形(放大镜的镜面)
87
+ var radius = 4;
88
+ ctx.beginPath();
89
+ ctx.arc(x - 1, y - 1, radius, 0, Math.PI * 2);
90
+ ctx.stroke();
91
+ // 绘制手柄(放大镜的柄)
92
+ ctx.lineWidth = 2;
93
+ ctx.beginPath();
94
+ ctx.moveTo(x + 2, y + 2);
95
+ ctx.lineTo(x + 5, y + 5);
96
+ ctx.stroke();
97
+ };
98
+ /**
99
+ * 文本截断
100
+ */
101
+ var truncateText = function (ctx, text, maxWidth) {
102
+ var width = ctx.measureText(text).width;
103
+ if (width <= maxWidth)
104
+ return text;
105
+ var truncated = text;
106
+ while (ctx.measureText(truncated + "...").width > maxWidth &&
107
+ truncated.length > 0) {
108
+ truncated = truncated.slice(0, -1);
109
+ }
110
+ return truncated + "...";
111
+ };
112
+ /**
113
+ * 检查文本是否被截断
114
+ */
115
+ var isTextTruncated = function (ctx, text, maxWidth) {
116
+ var width = ctx.measureText(text).width;
117
+ return width > maxWidth;
118
+ };
119
+ /**
120
+ * 文本换行
121
+ */
122
+ var wrapText = function (ctx, text, maxWidth) {
123
+ // 首先按照 \n 分割文本
124
+ var paragraphs = text.split("\n");
125
+ var allLines = [];
126
+ // 对每个段落进行自动换行处理
127
+ for (var _i = 0, paragraphs_1 = paragraphs; _i < paragraphs_1.length; _i++) {
128
+ var paragraph = paragraphs_1[_i];
129
+ if (paragraph === "") {
130
+ // 空行也要保留
131
+ allLines.push("");
132
+ continue;
133
+ }
134
+ var words = paragraph.split("");
135
+ var currentLine = "";
136
+ for (var _a = 0, words_1 = words; _a < words_1.length; _a++) {
137
+ var char = words_1[_a];
138
+ var testLine = currentLine + char;
139
+ var metrics = ctx.measureText(testLine);
140
+ var testWidth = metrics.width;
141
+ if (testWidth > maxWidth && currentLine.length > 0) {
142
+ allLines.push(currentLine);
143
+ currentLine = char;
144
+ }
145
+ else {
146
+ currentLine = testLine;
147
+ }
148
+ }
149
+ if (currentLine.length > 0) {
150
+ allLines.push(currentLine);
151
+ }
152
+ }
153
+ return allLines;
154
+ };
155
+
156
+ export { drawCheckbox, drawFilterIcon, drawSortIcon, isTextTruncated, truncateText, wrapText };
@@ -0,0 +1,121 @@
1
+ /**
2
+ * 单元格相关辅助函数
3
+ */
4
+ /**
5
+ * 获取鼠标位置对应的单元格
6
+ */
7
+ var getCellFromMousePosition = function (params) {
8
+ var x = params.x, y = params.y, headerHeight = params.headerHeight, rowHeight = params.rowHeight, scrollTop = params.scrollTop, scrollLeft = params.scrollLeft, columnRenderInfos = params.columnRenderInfos, dataLength = params.dataLength, _a = params.fixedTopRowsCount, fixedTopRowsCount = _a === void 0 ? 0 : _a, _b = params.fixedBottomRowsCount, fixedBottomRowsCount = _b === void 0 ? 0 : _b, _c = params.hasSummaryRow, hasSummaryRow = _c === void 0 ? false : _c, _d = params.fixedSummaryRow, fixedSummaryRow = _d === void 0 ? false : _d, _e = params.displayHeight, displayHeight = _e === void 0 ? 0 : _e, _f = params.needHorizontalScrollbar, needHorizontalScrollbar = _f === void 0 ? false : _f, _g = params.scrollbarSize, scrollbarSize = _g === void 0 ? 12 : _g;
9
+ // 判断是否在表头区域(row=-1表示表头)
10
+ var rowIndex;
11
+ if (y < headerHeight) {
12
+ rowIndex = -1; // 表头行
13
+ }
14
+ else {
15
+ // 检查是否在固定顶部行区域
16
+ var fixedTopAreaEnd = headerHeight + fixedTopRowsCount * rowHeight;
17
+ if (y < fixedTopAreaEnd) {
18
+ // 在固定顶部行区域
19
+ var relativeY = y - headerHeight;
20
+ rowIndex = Math.floor(relativeY / rowHeight);
21
+ if (rowIndex < 0 || rowIndex >= fixedTopRowsCount)
22
+ return null;
23
+ return findColumn(x, scrollLeft, columnRenderInfos, rowIndex);
24
+ }
25
+ // 检查是否在固定合计行区域
26
+ if (fixedSummaryRow && hasSummaryRow && displayHeight > 0) {
27
+ var summaryRowY = displayHeight -
28
+ (needHorizontalScrollbar ? scrollbarSize : 0) -
29
+ rowHeight;
30
+ if (y >= summaryRowY) {
31
+ // 在固定合计行区域
32
+ rowIndex = dataLength - 1; // 合计行是最后一行
33
+ return findColumn(x, scrollLeft, columnRenderInfos, rowIndex);
34
+ }
35
+ }
36
+ // 检查是否在固定底部行区域
37
+ if (fixedBottomRowsCount > 0 && displayHeight > 0) {
38
+ var fixedSummaryHeight = fixedSummaryRow && hasSummaryRow ? rowHeight : 0;
39
+ var fixedBottomAreaStart = displayHeight -
40
+ (needHorizontalScrollbar ? scrollbarSize : 0) -
41
+ fixedSummaryHeight -
42
+ fixedBottomRowsCount * rowHeight;
43
+ if (y >= fixedBottomAreaStart &&
44
+ y <
45
+ displayHeight -
46
+ (needHorizontalScrollbar ? scrollbarSize : 0) -
47
+ fixedSummaryHeight) {
48
+ // 在固定底部行区域
49
+ var relativeY = y - fixedBottomAreaStart;
50
+ var relativeIndex = Math.floor(relativeY / rowHeight);
51
+ var bottomRowsStartIndex = dataLength -
52
+ fixedBottomRowsCount -
53
+ (fixedSummaryRow && hasSummaryRow ? 1 : 0);
54
+ rowIndex = bottomRowsStartIndex + relativeIndex;
55
+ if (rowIndex < 0 || rowIndex >= dataLength)
56
+ return null;
57
+ return findColumn(x, scrollLeft, columnRenderInfos, rowIndex);
58
+ }
59
+ }
60
+ // 在可滚动区域
61
+ var adjustedY = y - fixedTopAreaEnd + scrollTop;
62
+ rowIndex = Math.floor(adjustedY / rowHeight) + fixedTopRowsCount;
63
+ if (rowIndex < fixedTopRowsCount || rowIndex >= dataLength)
64
+ return null;
65
+ // 如果有固定底部行或合计行,需要排除它们
66
+ var maxScrollableRow = dataLength -
67
+ fixedBottomRowsCount -
68
+ (fixedSummaryRow && hasSummaryRow ? 1 : 0);
69
+ if (rowIndex >= maxScrollableRow) {
70
+ // 超出可滚动区域,可能在滚动条或空白区域
71
+ return null;
72
+ }
73
+ }
74
+ return findColumn(x, scrollLeft, columnRenderInfos, rowIndex);
75
+ };
76
+ /**
77
+ * 根据x坐标查找列索引
78
+ */
79
+ function findColumn(x, scrollLeft, columnRenderInfos, rowIndex) {
80
+ // 优先查找fixed列(因为fixed列在上层,会遮挡下层的非fixed列)
81
+ for (var i = 0; i < columnRenderInfos.length; i++) {
82
+ var info = columnRenderInfos[i];
83
+ if (info.fixed) {
84
+ var fixedLeft = info.fixedLeft, width = info.width;
85
+ var drawX = fixedLeft;
86
+ if (x >= drawX && x < drawX + width) {
87
+ return { row: rowIndex, col: i };
88
+ }
89
+ }
90
+ }
91
+ // 如果不在fixed列上,再查找非fixed列
92
+ for (var i = 0; i < columnRenderInfos.length; i++) {
93
+ var info = columnRenderInfos[i];
94
+ if (!info.fixed) {
95
+ var width = info.width;
96
+ var drawX = info.x - scrollLeft;
97
+ if (x >= drawX && x < drawX + width) {
98
+ return { row: rowIndex, col: i };
99
+ }
100
+ }
101
+ }
102
+ return null;
103
+ }
104
+ /**
105
+ * 提取单元格文本(处理 render 函数)
106
+ */
107
+ var extractCellText = function (params) {
108
+ var cellValue = params.cellValue, record = params.record, rowIndex = params.rowIndex, renderFn = params.renderFn;
109
+ if (renderFn) {
110
+ var rendered = renderFn(cellValue, record, rowIndex);
111
+ // 如果 render 返回的是字符串或数字,直接使用
112
+ if (typeof rendered === "string" || typeof rendered === "number") {
113
+ return String(rendered);
114
+ }
115
+ // 如果是 React 元素或其他对象,使用原始值
116
+ return String(cellValue !== null && cellValue !== void 0 ? cellValue : "");
117
+ }
118
+ return String(cellValue !== null && cellValue !== void 0 ? cellValue : "");
119
+ };
120
+
121
+ export { extractCellText, getCellFromMousePosition };
@@ -0,0 +1,67 @@
1
+ import { __assign } from '../../_virtual/_tslib.js';
2
+
3
+ /**
4
+ * 列相关的辅助函数
5
+ */
6
+ /**
7
+ * 递归查找列(支持多级表头)
8
+ */
9
+ var findColumnByKey = function (columns, key) {
10
+ for (var _i = 0, columns_1 = columns; _i < columns_1.length; _i++) {
11
+ var col = columns_1[_i];
12
+ if (col.key === key) {
13
+ return col;
14
+ }
15
+ if (col.children && col.children.length > 0) {
16
+ var found = findColumnByKey(col.children, key);
17
+ if (found) {
18
+ return found;
19
+ }
20
+ }
21
+ }
22
+ return undefined;
23
+ };
24
+ /**
25
+ * 递归处理列的render函数(转换为统一的调用格式)
26
+ */
27
+ var processColumnRender = function (column, renderMode) {
28
+ if (renderMode === void 0) { renderMode = "object"; }
29
+ var processedColumn = __assign({}, column);
30
+ // 处理当前列的render函数
31
+ if (column.render) {
32
+ var render_1 = column.render;
33
+ processedColumn.render = function (text, record, index) {
34
+ if (renderMode === "object") {
35
+ return render_1({ value: text, record: record, index: index });
36
+ }
37
+ return render_1 === null || render_1 === void 0 ? void 0 : render_1(text, record, index);
38
+ };
39
+ }
40
+ // 递归处理children
41
+ if (column.children && Array.isArray(column.children)) {
42
+ processedColumn.children = column.children.map(function (child) {
43
+ return processColumnRender(child, renderMode);
44
+ });
45
+ }
46
+ return processedColumn;
47
+ };
48
+ /**
49
+ * 获取所有叶子列(支持多级表头)
50
+ */
51
+ var getAllLeafColumns = function (columns) {
52
+ var leafColumns = [];
53
+ var walk = function (nodes) {
54
+ nodes.forEach(function (node) {
55
+ if (Array.isArray(node.children) && node.children.length > 0) {
56
+ walk(node.children);
57
+ }
58
+ else {
59
+ leafColumns.push(node);
60
+ }
61
+ });
62
+ };
63
+ walk(columns);
64
+ return leafColumns;
65
+ };
66
+
67
+ export { findColumnByKey, getAllLeafColumns, processColumnRender };
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Canvas 表格常量配置
3
+ */
4
+ // 滚动条配置
5
+ var SCROLLBAR_SIZE = 12; // 滚动条宽度
6
+ var SCROLLBAR_PADDING = 2; // 滚动条内边距
7
+ // 最小滚动条尺寸
8
+ var MIN_SCROLLBAR_SIZE = 30;
9
+ var DEFAULT_COLUMN_WIDTH = 120;
10
+ var DEFAULT_SELECTION_COLUMN_WIDTH = 60;
11
+ // 样式常量
12
+ var COLORS = {
13
+ // 背景色
14
+ white: "#ffffff",
15
+ headerBg: "rgb(239, 245, 254)",
16
+ stripedBg: "#fafafa",
17
+ selectedBg: "#e6f7ff",
18
+ hoverBg: "rgb(239, 245, 254)",
19
+ selectionBg: "rgba(24, 144, 255, 0.1)",
20
+ // 文本色
21
+ text: "rgba(0, 0, 0, 0.85)",
22
+ emptyText: "rgba(0, 0, 0, 0.25)",
23
+ // 边框色
24
+ border: "rgb(222, 233, 246)",
25
+ // 主题色
26
+ primary: "#1890ff",
27
+ // 滚动条
28
+ scrollbarTrack: "#f0f0f0",
29
+ scrollbarThumb: "#bfbfbf",
30
+ scrollbarThumbActive: "#999",
31
+ // checkbox
32
+ checkboxBorder: "#d9d9d9",
33
+ checkboxDisabled: "#d9d9d9",
34
+ };
35
+ // 字体配置
36
+ var FONT_FAMILY = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto';
37
+ var FONT_SIZE = 14;
38
+ // 图标尺寸
39
+ var CHECKBOX_SIZE = 16;
40
+ var SORT_ICON_SIZE = 6;
41
+
42
+ export { CHECKBOX_SIZE, COLORS, DEFAULT_COLUMN_WIDTH, DEFAULT_SELECTION_COLUMN_WIDTH, FONT_FAMILY, FONT_SIZE, MIN_SCROLLBAR_SIZE, SCROLLBAR_PADDING, SCROLLBAR_SIZE, SORT_ICON_SIZE };