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,150 @@
1
+ import { useEffect } from 'react';
2
+ import { useMemoizedFn } from 'ahooks';
3
+ import { getLeafColumns } from '../utils/multiHeaderHelpers.js';
4
+ import { extractCellText } from '../utils/cellHelpers.js';
5
+ import { formatCellValue } from '../utils/formatHelpers.js';
6
+ import '../../_virtual/_tslib.js';
7
+
8
+ /**
9
+ * 复制到剪贴板 Hook
10
+ */
11
+ var useCopyToClipboard = function (params) {
12
+ var cellSelection = params.cellSelection, processedDataSource = params.processedDataSource, columns = params.columns, containerRef = params.containerRef;
13
+ // 获取叶子列(用于实际数据渲染和复制的列)
14
+ var leafColumns = getLeafColumns(columns);
15
+ // 获取选中单元格的文本数据
16
+ var getSelectedCellsText = useMemoizedFn(function () {
17
+ if (!cellSelection)
18
+ return "";
19
+ var startRow = cellSelection.startRow, endRow = cellSelection.endRow, startCol = cellSelection.startCol, endCol = cellSelection.endCol;
20
+ var minRow = Math.min(startRow, endRow);
21
+ var maxRow = Math.max(startRow, endRow);
22
+ var minCol = Math.min(startCol, endCol);
23
+ var maxCol = Math.max(startCol, endCol);
24
+ var rows = [];
25
+ for (var row = minRow; row <= maxRow; row++) {
26
+ var cells = [];
27
+ for (var col = minCol; col <= maxCol; col++) {
28
+ // 使用叶子列而不是原始列数组
29
+ var column = leafColumns[col];
30
+ if (!column)
31
+ continue;
32
+ // 跳过选择框列和序号列
33
+ if (column.key === "__selection__" || column.key === "__index__")
34
+ continue;
35
+ var text = void 0;
36
+ // row=-1 表示表头
37
+ if (row === -1) {
38
+ // 复制表头标题
39
+ if (column.dynamicTitle) {
40
+ text = column.dynamicTitle;
41
+ }
42
+ else {
43
+ text = typeof column.title === "string" ? column.title : column.key;
44
+ }
45
+ }
46
+ else {
47
+ // 复制数据行
48
+ var rowData = processedDataSource[row];
49
+ if (!rowData)
50
+ continue;
51
+ var cellValue = column.dataIndex
52
+ ? rowData[column.dataIndex]
53
+ : "";
54
+ // 优先使用 getCopyValue
55
+ if (column.getCopyValue) {
56
+ text = column.getCopyValue(cellValue, rowData, row);
57
+ }
58
+ else if (column.render) {
59
+ // 如果有自定义 render 函数,先尝试提取文本
60
+ var extractedText = extractCellText({
61
+ cellValue: cellValue,
62
+ record: rowData,
63
+ rowIndex: row,
64
+ renderFn: column.render,
65
+ });
66
+ // 如果 render 返回的是 React 元素(extractCellText 返回原始值)
67
+ // 且列配置了格式化选项,则应用格式化
68
+ var hasFormatConfig = !!(column.dateFormat ||
69
+ column.precision !== undefined ||
70
+ column.thousand);
71
+ if (hasFormatConfig && extractedText === String(cellValue !== null && cellValue !== void 0 ? cellValue : "")) {
72
+ // render 返回的是原始值,应用格式化
73
+ text = formatCellValue(cellValue, column);
74
+ }
75
+ else {
76
+ // render 返回的是已处理的字符串,直接使用
77
+ text = extractedText;
78
+ }
79
+ }
80
+ else {
81
+ // 没有自定义 render,直接使用格式化后的值(支持日期、精度、千分符等)
82
+ text = formatCellValue(cellValue, column);
83
+ }
84
+ }
85
+ cells.push(text);
86
+ }
87
+ if (cells.length > 0) {
88
+ rows.push(cells.join("\t"));
89
+ }
90
+ }
91
+ return rows.join("\n");
92
+ });
93
+ // 处理复制事件
94
+ var handleCopy = useMemoizedFn(function (e) {
95
+ var _a;
96
+ if (!cellSelection)
97
+ return;
98
+ var text = getSelectedCellsText();
99
+ if (text) {
100
+ e.preventDefault();
101
+ (_a = e.clipboardData) === null || _a === void 0 ? void 0 : _a.setData("text/plain", text);
102
+ }
103
+ });
104
+ // 监听复制事件
105
+ useEffect(function () {
106
+ var container = containerRef.current;
107
+ if (!container)
108
+ return;
109
+ container.addEventListener("copy", handleCopy);
110
+ return function () {
111
+ container.removeEventListener("copy", handleCopy);
112
+ };
113
+ }, [handleCopy, containerRef]);
114
+ // 监听键盘事件(Ctrl+C / Cmd+C)- 只在表格容器内部处理
115
+ useEffect(function () {
116
+ var container = containerRef.current;
117
+ if (!container)
118
+ return;
119
+ var handleKeyDown = function (e) {
120
+ // 检查是否为复制快捷键且有选中的单元格
121
+ if ((e.ctrlKey || e.metaKey) && e.key === "c" && cellSelection) {
122
+ // 检查当前焦点是否在表格容器内,或者事件目标是否在表格容器内
123
+ var isInContainer = container.contains(document.activeElement) ||
124
+ container.contains(e.target);
125
+ if (isInContainer) {
126
+ e.preventDefault(); // 阻止默认复制行为
127
+ var text = getSelectedCellsText();
128
+ if (text && navigator.clipboard) {
129
+ navigator.clipboard.writeText(text).catch(function (err) {
130
+ console.error("Failed to copy:", err);
131
+ });
132
+ }
133
+ }
134
+ }
135
+ };
136
+ // 监听容器的keydown事件,而不是全局window事件
137
+ container.addEventListener("keydown", handleKeyDown);
138
+ // 同时也监听全局事件,但会检查焦点位置
139
+ document.addEventListener("keydown", handleKeyDown);
140
+ return function () {
141
+ container.removeEventListener("keydown", handleKeyDown);
142
+ document.removeEventListener("keydown", handleKeyDown);
143
+ };
144
+ }, [cellSelection, getSelectedCellsText, containerRef]);
145
+ return {
146
+ getSelectedCellsText: getSelectedCellsText,
147
+ };
148
+ };
149
+
150
+ export { useCopyToClipboard };
@@ -0,0 +1,103 @@
1
+ import { __spreadArray } from '../../_virtual/_tslib.js';
2
+ import { useState, useEffect } from 'react';
3
+ import { getMaxDepth } from '../utils/multiHeaderHelpers.js';
4
+
5
+ var FONT_SIZE = 14;
6
+ var FONT_FAMILY = "Arial, sans-serif";
7
+ var LINE_HEIGHT = 20;
8
+ var FILTER_ICON_WIDTH = 15;
9
+ var SORT_ICON_WIDTH = 15;
10
+ var ICON_SPACING = 4;
11
+ var TEXT_PADDING = 16;
12
+ /**
13
+ * 计算文本在给定宽度下需要的行数
14
+ */
15
+ var calculateTextLines = function (ctx, text, maxWidth) {
16
+ var lines = text.split("\n");
17
+ var totalLines = 0;
18
+ for (var _i = 0, lines_1 = lines; _i < lines_1.length; _i++) {
19
+ var line = lines_1[_i];
20
+ if (line === "") {
21
+ totalLines += 1;
22
+ continue;
23
+ }
24
+ var currentLine = "";
25
+ var lineCount = 0;
26
+ var chars = line.split("");
27
+ for (var _a = 0, chars_1 = chars; _a < chars_1.length; _a++) {
28
+ var char = chars_1[_a];
29
+ var testLine = currentLine + char;
30
+ var metrics = ctx.measureText(testLine);
31
+ if (metrics.width > maxWidth && currentLine.length > 0) {
32
+ lineCount += 1;
33
+ currentLine = char;
34
+ }
35
+ else {
36
+ currentLine = testLine;
37
+ }
38
+ }
39
+ if (currentLine.length > 0) {
40
+ lineCount += 1;
41
+ }
42
+ totalLines += lineCount;
43
+ }
44
+ return totalLines;
45
+ };
46
+ /**
47
+ * 计算单个列标题需要的行数
48
+ */
49
+ var calculateColumnLines = function (ctx, column) {
50
+ if (!column.wrap || !column.title) {
51
+ return 1;
52
+ }
53
+ var titleText = String(column.title);
54
+ var columnWidth = column.width || 100;
55
+ // 计算图标占用的宽度
56
+ var hasOrder = column.isOrder !== false;
57
+ var hasFilter = column.isFilter !== false;
58
+ var iconsWidth = 0;
59
+ if (hasFilter)
60
+ iconsWidth += FILTER_ICON_WIDTH;
61
+ if (hasOrder) {
62
+ iconsWidth += SORT_ICON_WIDTH;
63
+ if (hasFilter)
64
+ iconsWidth += ICON_SPACING;
65
+ }
66
+ // 计算文本可用宽度
67
+ var textMaxWidth = columnWidth - TEXT_PADDING - iconsWidth;
68
+ return calculateTextLines(ctx, titleText, textMaxWidth);
69
+ };
70
+ /**
71
+ * Hook: 计算表头动态高度
72
+ * 支持多级表头
73
+ */
74
+ var useHeaderHeight = function (params) {
75
+ var columns = params.columns, headerHeight = params.headerHeight;
76
+ var _a = useState(headerHeight), calculatedHeight = _a[0], setCalculatedHeight = _a[1];
77
+ useEffect(function () {
78
+ var calculateHeight = function () {
79
+ // 获取多级表头的最大深度
80
+ var maxDepth = getMaxDepth(columns);
81
+ // 如果是多级表头,每层使用基础表头高度
82
+ if (maxDepth > 1) {
83
+ return headerHeight * maxDepth;
84
+ }
85
+ // 单层表头,考虑文本换行
86
+ var tempCanvas = document.createElement("canvas");
87
+ var ctx = tempCanvas.getContext("2d");
88
+ if (!ctx)
89
+ return headerHeight;
90
+ ctx.font = "".concat(FONT_SIZE, "px ").concat(FONT_FAMILY);
91
+ // 计算所有列需要的最大行数
92
+ var maxLines = Math.max.apply(Math, __spreadArray([1], columns.map(function (column) { return calculateColumnLines(ctx, column); }), false));
93
+ // 基础高度 + (额外行数 * 行高)
94
+ return maxLines > 1
95
+ ? headerHeight + (maxLines - 1) * LINE_HEIGHT
96
+ : headerHeight;
97
+ };
98
+ setCalculatedHeight(calculateHeight());
99
+ }, [columns, headerHeight]);
100
+ return calculatedHeight;
101
+ };
102
+
103
+ export { useHeaderHeight };
@@ -0,0 +1,111 @@
1
+ import { useMemo } from 'react';
2
+
3
+ /**
4
+ * 合并单元格管理 Hook
5
+ * 根据 processedColumns 的 onCell 和 finalDataSource 里面的 rowSpan 来判断合并
6
+ * 通过 isIndexMerge 和 isSelectionMerge 判断是否合并序号和勾选框
7
+ */
8
+ /**
9
+ * 根据 onCell 返回的 rowSpan 和 colSpan 计算合并单元格信息
10
+ */
11
+ var calculateMergeCellsFromOnCell = function (dataSource, columns, options) {
12
+ if (options === void 0) { options = {}; }
13
+ var _a = options.isIndexMerge, isIndexMerge = _a === void 0 ? true : _a, _b = options.isSelectionMerge, isSelectionMerge = _b === void 0 ? false : _b;
14
+ var mergeCellMap = new Map();
15
+ // 遍历所有数据行
16
+ dataSource.forEach(function (record, rowIndex) {
17
+ // 遍历所有列
18
+ columns.forEach(function (column, colIndex) {
19
+ var _a, _b;
20
+ // 特殊列处理:序号列和勾选框列
21
+ var isIndexColumn = column.key === "__index__";
22
+ var isSelectionColumn = column.key === "__selection__";
23
+ // 如果是序号列但不参与合并,或者是勾选框列但不参与合并,则跳过
24
+ if ((isIndexColumn && !isIndexMerge) ||
25
+ (isSelectionColumn && !isSelectionMerge)) {
26
+ return;
27
+ }
28
+ // 获取单元格属性
29
+ var cellProps = {};
30
+ // 对于序号列和勾选框列,如果允许合并,需要基于第一个业务列的合并信息
31
+ if (isIndexColumn || isSelectionColumn) {
32
+ // 找到第一个有 onCell 的业务列
33
+ var referenceColumn = columns.find(function (col) {
34
+ return col.onCell && col.key !== "__index__" && col.key !== "__selection__";
35
+ });
36
+ if (referenceColumn === null || referenceColumn === void 0 ? void 0 : referenceColumn.onCell) {
37
+ cellProps = referenceColumn.onCell(record, rowIndex) || {};
38
+ }
39
+ }
40
+ else if (column.onCell) {
41
+ // 业务列直接调用 onCell
42
+ cellProps = column.onCell(record, rowIndex) || {};
43
+ }
44
+ var rowSpan = (_a = cellProps.rowSpan) !== null && _a !== void 0 ? _a : 1;
45
+ var colSpan = (_b = cellProps.colSpan) !== null && _b !== void 0 ? _b : 1;
46
+ // 处理 rowSpan 或 colSpan 为 0 的情况(表示该单元格被合并)
47
+ if (rowSpan === 0 || colSpan === 0) {
48
+ // 标记为被合并的单元格
49
+ var key = "".concat(rowIndex, "-").concat(colIndex);
50
+ mergeCellMap.set(key, {
51
+ rowIndex: rowIndex,
52
+ colIndex: colIndex,
53
+ rowSpan: 0,
54
+ colSpan: 0,
55
+ skip: true,
56
+ });
57
+ return;
58
+ }
59
+ // 处理合并单元格(rowSpan > 1 或 colSpan > 1)
60
+ if (rowSpan > 1 || colSpan > 1) {
61
+ // 设置主单元格信息
62
+ var key = "".concat(rowIndex, "-").concat(colIndex);
63
+ mergeCellMap.set(key, {
64
+ rowIndex: rowIndex,
65
+ colIndex: colIndex,
66
+ rowSpan: rowSpan,
67
+ colSpan: colSpan,
68
+ skip: false,
69
+ });
70
+ // 标记被合并的单元格区域
71
+ for (var r = 0; r < rowSpan; r++) {
72
+ for (var c = 0; c < colSpan; c++) {
73
+ // 跳过主单元格自身
74
+ if (r === 0 && c === 0)
75
+ continue;
76
+ var mergedRowIndex = rowIndex + r;
77
+ var mergedColIndex = colIndex + c;
78
+ // 确保不越界
79
+ if (mergedRowIndex < dataSource.length &&
80
+ mergedColIndex < columns.length) {
81
+ var skipKey = "".concat(mergedRowIndex, "-").concat(mergedColIndex);
82
+ mergeCellMap.set(skipKey, {
83
+ rowIndex: mergedRowIndex,
84
+ colIndex: mergedColIndex,
85
+ rowSpan: 0,
86
+ colSpan: 0,
87
+ skip: true,
88
+ });
89
+ }
90
+ }
91
+ }
92
+ }
93
+ });
94
+ });
95
+ return mergeCellMap;
96
+ };
97
+ /**
98
+ * 合并单元格 Hook
99
+ */
100
+ var useMergeCells = function (params) {
101
+ var dataSource = params.dataSource, columns = params.columns, _a = params.isIndexMerge, isIndexMerge = _a === void 0 ? true : _a, _b = params.isSelectionMerge, isSelectionMerge = _b === void 0 ? false : _b;
102
+ var mergeCellMap = useMemo(function () {
103
+ return calculateMergeCellsFromOnCell(dataSource, columns, {
104
+ isIndexMerge: isIndexMerge,
105
+ isSelectionMerge: isSelectionMerge,
106
+ });
107
+ }, [dataSource, columns, isIndexMerge, isSelectionMerge]);
108
+ return { mergeCellMap: mergeCellMap };
109
+ };
110
+
111
+ export { useMergeCells };