@gx-design-vue/pro-table 0.2.0-alpha.2 → 0.2.0-alpha.21
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.
- package/dist/ProTable.d.ts +14 -493
- package/dist/ProTable.js +902 -511
- package/dist/components/Drag/Handle.d.ts +90 -0
- package/dist/components/Drag/Handle.js +64 -0
- package/dist/components/Drag/Tbody.d.ts +17 -0
- package/dist/components/Drag/Tbody.js +27 -0
- package/dist/components/EllipsisText/index.d.ts +50 -0
- package/dist/components/EllipsisText/index.js +65 -0
- package/dist/components/ScrollBar/Bar.d.ts +79 -0
- package/dist/components/ScrollBar/Bar.js +84 -0
- package/dist/components/ScrollBar/Thumb.d.ts +50 -0
- package/dist/components/ScrollBar/{Thumb/index.js → Thumb.js} +67 -58
- package/dist/components/ScrollBar/context.d.ts +3 -4
- package/dist/components/ScrollBar/context.js +3 -5
- package/dist/components/ScrollBar/util.d.ts +6 -5
- package/dist/components/ScrollBar/util.js +1 -14
- package/dist/components/SearchForm/CollapseToggle.d.ts +53 -0
- package/dist/components/SearchForm/CollapseToggle.js +47 -0
- package/dist/components/SearchForm/FormItemContainer.d.ts +73 -0
- package/dist/components/SearchForm/FormItemContainer.js +225 -0
- package/dist/components/SearchForm/FormItemWrapper.d.ts +80 -0
- package/dist/components/SearchForm/FormItemWrapper.js +62 -0
- package/dist/components/SearchForm/SearchForm.d.ts +128 -0
- package/dist/components/SearchForm/SearchForm.js +319 -0
- package/dist/components/SearchForm/index.d.ts +2 -0
- package/dist/components/SearchForm/index.js +2 -0
- package/dist/components/Toolbar/FullscreenIcon.d.ts +24 -0
- package/dist/components/Toolbar/FullscreenIcon.js +22 -0
- package/dist/components/Toolbar/ListToolBar.d.ts +109 -0
- package/dist/components/Toolbar/ListToolBar.js +101 -0
- package/dist/components/Toolbar/index.d.ts +101 -0
- package/dist/components/Toolbar/index.js +101 -0
- package/dist/components/Toolbar/style.d.ts +8 -0
- package/dist/components/{ListToolBar → Toolbar}/style.js +32 -27
- package/dist/context/TableContext.d.ts +15 -27
- package/dist/context/TableContext.js +3 -5
- package/dist/hooks/index.d.ts +19 -0
- package/dist/hooks/index.js +19 -0
- package/dist/hooks/useAutoScroll.d.ts +32 -0
- package/dist/hooks/useAutoScroll.js +127 -0
- package/dist/hooks/useBreakpoints.d.ts +13 -0
- package/dist/hooks/useBreakpoints.js +65 -0
- package/dist/hooks/useCellRender.d.ts +13 -0
- package/dist/hooks/useCellRender.js +40 -0
- package/dist/hooks/useColumnResize.d.ts +29 -0
- package/dist/hooks/useColumnResize.js +112 -0
- package/dist/hooks/useColumns.d.ts +35 -24
- package/dist/hooks/useColumns.js +89 -58
- package/dist/hooks/useDragHandleColumn.d.ts +26 -0
- package/dist/hooks/useDragHandleColumn.js +52 -0
- package/dist/hooks/useEllipsis.d.ts +20 -0
- package/dist/hooks/useEllipsis.js +51 -0
- package/dist/hooks/useFetchData.d.ts +42 -65
- package/dist/hooks/useFetchData.js +160 -176
- package/dist/hooks/useFitPage.d.ts +19 -0
- package/dist/hooks/useFitPage.js +90 -0
- package/dist/hooks/useKeepAliveReload.d.ts +21 -0
- package/dist/hooks/useKeepAliveReload.js +24 -0
- package/dist/hooks/useLoading.d.ts +18 -7
- package/dist/hooks/useLoading.js +27 -11
- package/dist/hooks/usePagination.d.ts +10 -7
- package/dist/hooks/usePagination.js +38 -29
- package/dist/hooks/useRequestOptions.d.ts +18 -0
- package/dist/hooks/useRequestOptions.js +39 -0
- package/dist/hooks/useRowDrag.d.ts +42 -0
- package/dist/hooks/useRowDrag.js +268 -0
- package/dist/hooks/useRowSelection.d.ts +27 -15
- package/dist/hooks/useRowSelection.js +93 -80
- package/dist/hooks/useTable.d.ts +35 -77
- package/dist/hooks/useTable.js +76 -49
- package/dist/hooks/useTableForm.d.ts +17 -82
- package/dist/hooks/useTableForm.js +137 -52
- package/dist/hooks/useTableScroll.d.ts +33 -31
- package/dist/hooks/useTableScroll.js +71 -28
- package/dist/hooks/useTableSize.d.ts +17 -7
- package/dist/hooks/useTableSize.js +21 -9
- package/dist/index.d.ts +11 -7
- package/dist/index.js +10 -4
- package/dist/interface.d.ts +537 -0
- package/dist/interface.js +1 -0
- package/dist/pro-table.esm.js +8897 -4012
- package/dist/pro-table.js +4 -1
- package/dist/style/ellipsis.d.ts +13 -0
- package/dist/style/ellipsis.js +16 -0
- package/dist/style/fit-page.d.ts +4 -2
- package/dist/style/fit-page.js +10 -5
- package/dist/style/index.d.ts +3 -7
- package/dist/style/index.js +38 -76
- package/dist/style/list.d.ts +4 -2
- package/dist/style/list.js +2 -12
- package/dist/style/resizable.d.ts +8 -0
- package/dist/style/resizable.js +18 -0
- package/dist/style/row-drag.d.ts +8 -0
- package/dist/style/row-drag.js +44 -0
- package/dist/style/scroll.d.ts +4 -2
- package/dist/style/scroll.js +9 -9
- package/dist/style/search.d.ts +8 -0
- package/dist/{components/Form/style.js → style/search.js} +22 -9
- package/dist/theme/augment.d.ts +8 -0
- package/dist/theme/augment.js +1 -0
- package/dist/theme/interface/components.d.ts +8 -0
- package/dist/theme/interface/components.js +1 -0
- package/dist/utils/arrayMove.d.ts +9 -0
- package/dist/utils/arrayMove.js +15 -0
- package/dist/utils/dateFormat.d.ts +9 -0
- package/dist/utils/dateFormat.js +29 -0
- package/dist/utils/ellipsis.d.ts +19 -0
- package/dist/utils/ellipsis.js +30 -0
- package/dist/utils/flipAnimate.d.ts +25 -0
- package/dist/utils/flipAnimate.js +40 -0
- package/dist/utils/formConstants.d.ts +9 -0
- package/dist/utils/formConstants.js +29 -0
- package/dist/utils/valueFormat.d.ts +9 -0
- package/dist/utils/valueFormat.js +27 -0
- package/package.json +23 -11
- package/dist/components/Form/components/RequestSelect.d.ts +0 -50
- package/dist/components/Form/components/RequestSelect.js +0 -58
- package/dist/components/Form/hooks/useForm.d.ts +0 -11
- package/dist/components/Form/hooks/useForm.js +0 -32
- package/dist/components/Form/index.d.ts +0 -33
- package/dist/components/Form/index.js +0 -479
- package/dist/components/Form/style.d.ts +0 -6
- package/dist/components/Form/utils/config.d.ts +0 -9
- package/dist/components/Form/utils/config.js +0 -30
- package/dist/components/Form/utils/dateFormat.d.ts +0 -22
- package/dist/components/Form/utils/dateFormat.js +0 -45
- package/dist/components/ListToolBar/index.d.ts +0 -60
- package/dist/components/ListToolBar/index.js +0 -123
- package/dist/components/ListToolBar/style.d.ts +0 -6
- package/dist/components/ScrollBar/Bar/index.d.ts +0 -49
- package/dist/components/ScrollBar/Bar/index.js +0 -71
- package/dist/components/ScrollBar/Bar/props.d.ts +0 -25
- package/dist/components/ScrollBar/Bar/props.js +0 -18
- package/dist/components/ScrollBar/Thumb/index.d.ts +0 -40
- package/dist/components/ScrollBar/Thumb/props.d.ts +0 -20
- package/dist/components/ScrollBar/Thumb/props.js +0 -18
- package/dist/components/TableCell/index.d.ts +0 -37
- package/dist/components/TableCell/index.js +0 -72
- package/dist/components/ToolBar/FullscreenIcon.d.ts +0 -7
- package/dist/components/ToolBar/FullscreenIcon.js +0 -14
- package/dist/components/ToolBar/index.d.ts +0 -34
- package/dist/components/ToolBar/index.js +0 -100
- package/dist/hooks/tryOnActivated.d.ts +0 -6
- package/dist/hooks/tryOnActivated.js +0 -14
- package/dist/hooks/useDebounceFn.d.ts +0 -8
- package/dist/hooks/useDebounceFn.js +0 -34
- package/dist/hooks/useScrollArea.d.ts +0 -24
- package/dist/hooks/useScrollArea.js +0 -104
- package/dist/props.d.ts +0 -340
- package/dist/props.js +0 -251
- package/dist/types/ColumnTypings.d.ts +0 -129
- package/dist/types/ColumnTypings.js +0 -1
- package/dist/types/SlotsTypings.d.ts +0 -63
- package/dist/types/SlotsTypings.js +0 -13
- package/dist/types/TableTypings.d.ts +0 -359
- package/dist/types/TableTypings.js +0 -1
- package/dist/types/index.d.ts +0 -9
- package/dist/types/index.js +0 -1
- package/dist/utils/utils.d.ts +0 -10
- package/dist/utils/utils.js +0 -91
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { arrayMove } from "../utils/arrayMove.js";
|
|
2
|
+
import { flipAnimate } from "../utils/flipAnimate.js";
|
|
3
|
+
import { useAutoScroll } from "./useAutoScroll.js";
|
|
4
|
+
import { nextTick, ref } from "vue";
|
|
5
|
+
import { useEventListener } from "@vueuse/core";
|
|
6
|
+
//#region src/hooks/useRowDrag.ts
|
|
7
|
+
/** 移动阈值(px),超过才视为拖拽,避免误触影响点击 */
|
|
8
|
+
const DRAG_THRESHOLD = 3;
|
|
9
|
+
const SCROLL_RESTORE_FRAMES = 2;
|
|
10
|
+
const DISPLACEMENT_DURATION = 160;
|
|
11
|
+
const DISPLACEMENT_EASING = "cubic-bezier(0.2, 0, 0, 1)";
|
|
12
|
+
const DRAGGING_Z_INDEX = "1000";
|
|
13
|
+
function isFromDragHandle(target) {
|
|
14
|
+
const el = target;
|
|
15
|
+
if (!el || typeof el.closest !== "function") return false;
|
|
16
|
+
const handle = el.closest("[data-drag-handle]");
|
|
17
|
+
if (!handle) return false;
|
|
18
|
+
return handle.getAttribute("data-drag-disabled") !== "true";
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 表格行拖拽排序 —— 精简复刻 `useTabDrag` 的垂直版本。
|
|
22
|
+
*
|
|
23
|
+
* - 仅从把手列(`[data-drag-handle]`)发起拖拽,单元格交互不受影响
|
|
24
|
+
* - 移动阈值(3px)区分点击与拖拽
|
|
25
|
+
* - 拖拽行 `transform: translateY(delta)` 跟随指针
|
|
26
|
+
* - 同列表其他行按虚拟插入位置实时 `translate` 让位(CSS translate 属性 + WAAPI)
|
|
27
|
+
* - drop 锚点用最近中心法(被拖行中心 Y 与全量各行中心比距离取最近者;含自身,半身位即换位)
|
|
28
|
+
* - 松手 → onSortEnd(仅 emit 排序结果,由使用方回写数据源)→ nextTick 用 flipAnimate 平滑归位
|
|
29
|
+
* - 拖拽结束后捕获抑制下一次 click
|
|
30
|
+
* - 指针接近滚动容器上下边缘时自动滚动(垂直版 detectScrollIntent)
|
|
31
|
+
*/
|
|
32
|
+
function useRowDrag(options) {
|
|
33
|
+
const { tbodyEl, scrollEl, dataSource, rowKey, rowDraggable, onSortEnd } = options;
|
|
34
|
+
const isDragging = ref(false);
|
|
35
|
+
const draggingRowKey = ref("");
|
|
36
|
+
let dragStartClientY = 0;
|
|
37
|
+
let dragStartScrollTop = 0;
|
|
38
|
+
let dragPointerOffsetY = 0;
|
|
39
|
+
let pointerClientY = 0;
|
|
40
|
+
let dragEl = null;
|
|
41
|
+
let rowRects = [];
|
|
42
|
+
let pendingKey = "";
|
|
43
|
+
let pendingStartY = 0;
|
|
44
|
+
let pendingRecord = null;
|
|
45
|
+
const { scroll: scrollOnDragMove, start: startAutoScroll, stop: stopAutoScroll } = useAutoScroll(scrollEl, () => pointerClientY, { onScroll: updateDragPosition });
|
|
46
|
+
function queryRowEl(key) {
|
|
47
|
+
return tbodyEl.value?.querySelector(`tr[data-row-key="${key}"]`) ?? null;
|
|
48
|
+
}
|
|
49
|
+
function recordRowRects() {
|
|
50
|
+
rowRects = [];
|
|
51
|
+
const data = dataSource.value;
|
|
52
|
+
for (const record of data) {
|
|
53
|
+
const key = record?.[rowKey.value];
|
|
54
|
+
if (key == null) continue;
|
|
55
|
+
const el = queryRowEl(key);
|
|
56
|
+
if (!el) continue;
|
|
57
|
+
const rect = el.getBoundingClientRect();
|
|
58
|
+
rowRects.push({
|
|
59
|
+
el,
|
|
60
|
+
key,
|
|
61
|
+
top: rect.top,
|
|
62
|
+
height: rect.height,
|
|
63
|
+
translate: 0
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function getCurrentScrollOffset() {
|
|
68
|
+
return (scrollEl.value?.scrollTop ?? 0) - dragStartScrollTop;
|
|
69
|
+
}
|
|
70
|
+
function getVisualPointerY() {
|
|
71
|
+
return pointerClientY + getCurrentScrollOffset();
|
|
72
|
+
}
|
|
73
|
+
function getDragCenterY() {
|
|
74
|
+
const dragRect = rowRects.find((r) => r.key === draggingRowKey.value);
|
|
75
|
+
if (!dragRect) return getVisualPointerY();
|
|
76
|
+
return getVisualPointerY() - dragPointerOffsetY + dragRect.height / 2;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 计算拖拽行应去的目标索引(最近中心法,对齐 dnd-kit `closestCenter`)。
|
|
80
|
+
*
|
|
81
|
+
* 在全量行(含拖拽行自身)里找离拖拽行视觉中心最近的行,返回其索引作为
|
|
82
|
+
* `arrayMove(data, fromIdx, 返回值)` 的 to。返回值的几何意义即"拖拽行想占据的位置":
|
|
83
|
+
* - 最近行是自己(fromIdx) → from===to,不移动
|
|
84
|
+
* - 最近行在下方 → 向下移动占据其位置
|
|
85
|
+
* - 最近行在上方 → 向上移动占据其位置
|
|
86
|
+
*
|
|
87
|
+
* 关键:拖拽行自身必须参与比较,否则切换阈值会从「半个身位」退化成「一个身位」——
|
|
88
|
+
* 缺少起始参考点后,需要整行越过下一行中心才会换位(表现为完全覆盖才触发);
|
|
89
|
+
* 含自身时切换点落在相邻两行中心的中点,即拖动半个行高即换位。
|
|
90
|
+
*/
|
|
91
|
+
function computeTargetIdx(dragCenterY) {
|
|
92
|
+
const fromIdx = rowRects.findIndex((r) => r.key === draggingRowKey.value);
|
|
93
|
+
if (fromIdx < 0) return -1;
|
|
94
|
+
let nearestIdx = fromIdx;
|
|
95
|
+
let nearestDist = Infinity;
|
|
96
|
+
for (let i = 0; i < rowRects.length; i++) {
|
|
97
|
+
const center = rowRects[i].top + rowRects[i].height / 2;
|
|
98
|
+
const dist = Math.abs(dragCenterY - center);
|
|
99
|
+
if (dist < nearestDist) {
|
|
100
|
+
nearestDist = dist;
|
|
101
|
+
nearestIdx = i;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return nearestIdx;
|
|
105
|
+
}
|
|
106
|
+
/** 同区间其他行实时让位 */
|
|
107
|
+
function applyDisplacement(targetIdx) {
|
|
108
|
+
const fromIdx = rowRects.findIndex((r) => r.key === draggingRowKey.value);
|
|
109
|
+
if (fromIdx < 0) return;
|
|
110
|
+
const dragHeight = rowRects.find((r) => r.key === draggingRowKey.value)?.height ?? 0;
|
|
111
|
+
for (let i = 0; i < rowRects.length; i++) {
|
|
112
|
+
const rect = rowRects[i];
|
|
113
|
+
if (rect.key === draggingRowKey.value) continue;
|
|
114
|
+
let translate = 0;
|
|
115
|
+
if (fromIdx < targetIdx && i > fromIdx && i <= targetIdx) translate = -dragHeight;
|
|
116
|
+
else if (fromIdx > targetIdx && i >= targetIdx && i < fromIdx) translate = dragHeight;
|
|
117
|
+
applyRowTranslate(rect, translate);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function applyRowTranslate(rect, nextTranslate) {
|
|
121
|
+
const prevTranslate = rect.translate;
|
|
122
|
+
if (prevTranslate === nextTranslate) return;
|
|
123
|
+
rect.animation?.cancel();
|
|
124
|
+
rect.translate = nextTranslate;
|
|
125
|
+
rect.el.style.translate = nextTranslate ? `0px ${nextTranslate}px` : "";
|
|
126
|
+
if (typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches || typeof rect.el.animate !== "function") return;
|
|
127
|
+
rect.animation = rect.el.animate({ translate: [`0px ${prevTranslate}px`, `0px ${nextTranslate}px`] }, {
|
|
128
|
+
duration: DISPLACEMENT_DURATION,
|
|
129
|
+
easing: DISPLACEMENT_EASING
|
|
130
|
+
});
|
|
131
|
+
const clear = () => {
|
|
132
|
+
rect.animation = void 0;
|
|
133
|
+
};
|
|
134
|
+
rect.animation.addEventListener("finish", clear, { once: true });
|
|
135
|
+
rect.animation.addEventListener("cancel", clear, { once: true });
|
|
136
|
+
}
|
|
137
|
+
function updateDragPosition() {
|
|
138
|
+
if (!isDragging.value) return;
|
|
139
|
+
if (dragEl) dragEl.style.transform = `translateY(${getVisualPointerY() - dragStartClientY}px)`;
|
|
140
|
+
applyDisplacement(computeTargetIdx(getDragCenterY()));
|
|
141
|
+
}
|
|
142
|
+
function clearInlineStyles(rects = rowRects, activeDragEl = dragEl) {
|
|
143
|
+
for (const rect of rects) {
|
|
144
|
+
rect.animation?.cancel();
|
|
145
|
+
rect.animation = void 0;
|
|
146
|
+
rect.translate = 0;
|
|
147
|
+
rect.el.style.translate = "";
|
|
148
|
+
rect.el.style.zIndex = "";
|
|
149
|
+
}
|
|
150
|
+
if (activeDragEl) {
|
|
151
|
+
activeDragEl.style.transform = "";
|
|
152
|
+
activeDragEl.classList.remove("row-dragging");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function restoreScrollTop(scrollTop, frames = SCROLL_RESTORE_FRAMES) {
|
|
156
|
+
const el = scrollEl.value;
|
|
157
|
+
if (!el) return;
|
|
158
|
+
el.scrollTop = scrollTop;
|
|
159
|
+
if (frames <= 0 || typeof requestAnimationFrame === "undefined") return;
|
|
160
|
+
requestAnimationFrame(() => restoreScrollTop(scrollTop, frames - 1));
|
|
161
|
+
}
|
|
162
|
+
function beginDrag(clientY) {
|
|
163
|
+
isDragging.value = true;
|
|
164
|
+
dragStartClientY = clientY;
|
|
165
|
+
dragStartScrollTop = scrollEl.value?.scrollTop ?? 0;
|
|
166
|
+
pointerClientY = clientY;
|
|
167
|
+
dragEl = queryRowEl(draggingRowKey.value);
|
|
168
|
+
recordRowRects();
|
|
169
|
+
const dragRect = rowRects.find((r) => r.key === draggingRowKey.value);
|
|
170
|
+
dragPointerOffsetY = dragRect ? clientY - dragRect.top : 0;
|
|
171
|
+
if (dragEl) {
|
|
172
|
+
dragEl.classList.add("row-dragging");
|
|
173
|
+
dragEl.style.zIndex = DRAGGING_Z_INDEX;
|
|
174
|
+
}
|
|
175
|
+
startAutoScroll();
|
|
176
|
+
}
|
|
177
|
+
/** 捕获阶段抑制拖拽结束后的下一次 click */
|
|
178
|
+
function suppressNextClick() {
|
|
179
|
+
const target = dragEl;
|
|
180
|
+
if (!target) return;
|
|
181
|
+
const suppress = (event) => {
|
|
182
|
+
event.stopPropagation();
|
|
183
|
+
event.preventDefault();
|
|
184
|
+
target.removeEventListener("click", suppress, true);
|
|
185
|
+
};
|
|
186
|
+
target.addEventListener("click", suppress, {
|
|
187
|
+
capture: true,
|
|
188
|
+
once: true
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
function handleMousedown(event, record) {
|
|
192
|
+
if (event.button !== 0) return;
|
|
193
|
+
if (!isFromDragHandle(event.target)) return;
|
|
194
|
+
const cfg = rowDraggable.value;
|
|
195
|
+
if (!cfg) return;
|
|
196
|
+
if ((typeof cfg === "object" ? cfg : {}).disabled?.(record)) return;
|
|
197
|
+
event.preventDefault();
|
|
198
|
+
const key = record?.[rowKey.value];
|
|
199
|
+
pendingKey = key;
|
|
200
|
+
pendingStartY = event.clientY;
|
|
201
|
+
pendingRecord = record;
|
|
202
|
+
draggingRowKey.value = key;
|
|
203
|
+
}
|
|
204
|
+
function handleMousemove(event) {
|
|
205
|
+
if (!isDragging.value) {
|
|
206
|
+
if (!pendingKey) return;
|
|
207
|
+
if (Math.abs(event.clientY - pendingStartY) < DRAG_THRESHOLD) return;
|
|
208
|
+
beginDrag(pendingStartY);
|
|
209
|
+
}
|
|
210
|
+
pointerClientY = event.clientY;
|
|
211
|
+
updateDragPosition();
|
|
212
|
+
scrollOnDragMove();
|
|
213
|
+
}
|
|
214
|
+
function endDrag() {
|
|
215
|
+
const targetIdx = computeTargetIdx(getDragCenterY());
|
|
216
|
+
const fromIdx = rowRects.findIndex((r) => r.key === draggingRowKey.value);
|
|
217
|
+
const data = dataSource.value;
|
|
218
|
+
const prevRects = /* @__PURE__ */ new Map();
|
|
219
|
+
for (const { key, el } of rowRects) prevRects.set(key, el.getBoundingClientRect());
|
|
220
|
+
stopAutoScroll();
|
|
221
|
+
const currentRowRects = rowRects;
|
|
222
|
+
const currentDragEl = dragEl;
|
|
223
|
+
const currentScrollTop = scrollEl.value?.scrollTop ?? 0;
|
|
224
|
+
const record = pendingRecord;
|
|
225
|
+
if (targetIdx >= 0 && targetIdx !== fromIdx && targetIdx < data.length) {
|
|
226
|
+
const newData = arrayMove(data, fromIdx, targetIdx);
|
|
227
|
+
onSortEnd?.(fromIdx, targetIdx, newData, record);
|
|
228
|
+
nextTick(() => {
|
|
229
|
+
restoreScrollTop(currentScrollTop);
|
|
230
|
+
clearInlineStyles(currentRowRects, currentDragEl);
|
|
231
|
+
flipAnimate(data.map((r) => ({
|
|
232
|
+
key: r[rowKey.value],
|
|
233
|
+
el: queryRowEl(r[rowKey.value])
|
|
234
|
+
})).filter((entry) => Boolean(entry.el)), prevRects);
|
|
235
|
+
restoreScrollTop(currentScrollTop);
|
|
236
|
+
});
|
|
237
|
+
} else clearInlineStyles();
|
|
238
|
+
suppressNextClick();
|
|
239
|
+
isDragging.value = false;
|
|
240
|
+
draggingRowKey.value = "";
|
|
241
|
+
dragEl = null;
|
|
242
|
+
rowRects = [];
|
|
243
|
+
dragPointerOffsetY = 0;
|
|
244
|
+
pendingKey = "";
|
|
245
|
+
pendingRecord = null;
|
|
246
|
+
}
|
|
247
|
+
function handleMouseup() {
|
|
248
|
+
if (isDragging.value) endDrag();
|
|
249
|
+
else if (pendingKey) {
|
|
250
|
+
pendingKey = "";
|
|
251
|
+
draggingRowKey.value = "";
|
|
252
|
+
pendingRecord = null;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
const documentTarget = typeof document === "undefined" ? void 0 : document;
|
|
256
|
+
useEventListener(documentTarget, "mousemove", handleMousemove);
|
|
257
|
+
useEventListener(documentTarget, "mouseup", handleMouseup);
|
|
258
|
+
function getRowProps(record, _index) {
|
|
259
|
+
return { onMousedown: (event) => handleMousedown(event, record) };
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
isDragging,
|
|
263
|
+
draggingRowKey,
|
|
264
|
+
getRowProps
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
//#endregion
|
|
268
|
+
export { useRowDrag };
|
|
@@ -1,19 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Ref } from "vue";
|
|
1
|
+
import { ComputedRef } from "vue";
|
|
3
2
|
import { RecordType } from "@gx-design-vue/pro-utils";
|
|
4
|
-
import {
|
|
5
|
-
import { Key } from "ant-design-vue/es/vc-table/interface";
|
|
3
|
+
import { Key, TableRowSelection } from "antdv-next/dist/table/interface";
|
|
6
4
|
|
|
7
5
|
//#region src/hooks/useRowSelection.d.ts
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
6
|
+
interface UseRowSelectionOptions<T = RecordType> {
|
|
7
|
+
rowKey: ComputedRef<string>;
|
|
8
|
+
rowSelection: ComputedRef<TableRowSelection<T> | undefined>;
|
|
9
|
+
dataSource: ComputedRef<T[]>;
|
|
10
|
+
}
|
|
11
|
+
interface UseRowSelectionReturn<T = RecordType> {
|
|
12
|
+
selectedRowKeys: ComputedRef<Key[]>;
|
|
13
|
+
selectedItems: ComputedRef<T[]>;
|
|
14
|
+
mergedRowSelection: ComputedRef<TableRowSelection<T> | undefined>;
|
|
15
|
+
select: (record: T, selected: boolean) => void;
|
|
16
|
+
selectAll: (records: T[], selected: boolean) => void;
|
|
17
|
+
remove: (keys: Key[]) => void;
|
|
18
|
+
clear: () => void;
|
|
19
|
+
sync: () => void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 行选择状态管理。内部使用 reactive Map 作为唯一数据源,
|
|
23
|
+
* selectedRowKeys / selectedItems 均从 Map 派生,保证 keys 与 items 永远同步。
|
|
24
|
+
*
|
|
25
|
+
* antdv-next 已废弃 onSelectAll / onSelectInvert / onSelectNone,
|
|
26
|
+
* 所有选中变化统一通过 onChange 回调,因此 mergedRowSelection 只拦截 onChange,
|
|
27
|
+
* 不拦截 onSelect / onSelectAll。
|
|
28
|
+
*/
|
|
29
|
+
declare function useRowSelection<T = RecordType>(options: UseRowSelectionOptions<T>): UseRowSelectionReturn<T>;
|
|
18
30
|
//#endregion
|
|
19
|
-
export { useRowSelection };
|
|
31
|
+
export { UseRowSelectionOptions, UseRowSelectionReturn, useRowSelection };
|
|
@@ -1,89 +1,102 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { arrayUnique, cloneDeep } from "@gx-design-vue/pro-utils";
|
|
3
|
-
|
|
1
|
+
import { computed, onScopeDispose, reactive, watch } from "vue";
|
|
4
2
|
//#region src/hooks/useRowSelection.ts
|
|
5
|
-
function
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
selectedKeys.value = [record[rowKey.value]];
|
|
27
|
-
selectedItems.value = [record];
|
|
3
|
+
function getKey(record, rowKey) {
|
|
4
|
+
return record[rowKey];
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* 行选择状态管理。内部使用 reactive Map 作为唯一数据源,
|
|
8
|
+
* selectedRowKeys / selectedItems 均从 Map 派生,保证 keys 与 items 永远同步。
|
|
9
|
+
*
|
|
10
|
+
* antdv-next 已废弃 onSelectAll / onSelectInvert / onSelectNone,
|
|
11
|
+
* 所有选中变化统一通过 onChange 回调,因此 mergedRowSelection 只拦截 onChange,
|
|
12
|
+
* 不拦截 onSelect / onSelectAll。
|
|
13
|
+
*/
|
|
14
|
+
function useRowSelection(options) {
|
|
15
|
+
const selectedMap = reactive(/* @__PURE__ */ new Map());
|
|
16
|
+
const stopWatch = watch(() => options.rowSelection.value?.selectedRowKeys, (keys) => {
|
|
17
|
+
if (!keys) return;
|
|
18
|
+
const newMap = /* @__PURE__ */ new Map();
|
|
19
|
+
const currentDataSource = options.dataSource.value;
|
|
20
|
+
for (const key of keys) {
|
|
21
|
+
const existing = selectedMap.get(key);
|
|
22
|
+
const matched = currentDataSource.find((record) => getKey(record, options.rowKey.value) === key);
|
|
23
|
+
newMap.set(key, matched ?? existing);
|
|
28
24
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
selectedMap.clear();
|
|
26
|
+
for (const [key, item] of newMap) selectedMap.set(key, item);
|
|
27
|
+
}, { immediate: true });
|
|
28
|
+
onScopeDispose(() => stopWatch());
|
|
29
|
+
const selectedRowKeys = computed(() => Array.from(selectedMap.keys()));
|
|
30
|
+
const selectedItems = computed(() => Array.from(selectedMap.values()).filter((item) => item != null));
|
|
31
|
+
function emitChange(type) {
|
|
32
|
+
options.rowSelection.value?.onChange?.(selectedRowKeys.value, selectedItems.value, { type });
|
|
33
|
+
}
|
|
34
|
+
function select(record, selected) {
|
|
35
|
+
const key = getKey(record, options.rowKey.value);
|
|
36
|
+
const selectionType = options.rowSelection.value?.type ?? "checkbox";
|
|
37
|
+
if (selected) if (selectionType === "radio") {
|
|
38
|
+
selectedMap.clear();
|
|
39
|
+
selectedMap.set(key, record);
|
|
40
|
+
} else selectedMap.set(key, record);
|
|
41
|
+
else selectedMap.delete(key);
|
|
42
|
+
emitChange(selected ? selectionType === "radio" ? "single" : "multiple" : "none");
|
|
43
|
+
}
|
|
44
|
+
function selectAll(records, selected) {
|
|
45
|
+
if (selected) for (const record of records) selectedMap.set(getKey(record, options.rowKey.value), record);
|
|
46
|
+
else for (const record of records) selectedMap.delete(getKey(record, options.rowKey.value));
|
|
47
|
+
emitChange(selected ? "all" : "none");
|
|
48
|
+
}
|
|
49
|
+
function remove(keys) {
|
|
50
|
+
for (const key of keys) selectedMap.delete(key);
|
|
51
|
+
emitChange("none");
|
|
52
|
+
}
|
|
53
|
+
function clear() {
|
|
54
|
+
selectedMap.clear();
|
|
55
|
+
emitChange("none");
|
|
56
|
+
}
|
|
57
|
+
/** 从当前 dataSource 补全 Map 中 value 为空的条目(分页切换后调用) */
|
|
58
|
+
function sync() {
|
|
59
|
+
const currentDataSource = options.dataSource.value;
|
|
60
|
+
const rowKeyField = options.rowKey.value;
|
|
61
|
+
for (const [key, item] of selectedMap) if (item == null) {
|
|
62
|
+
const matched = currentDataSource.find((record) => getKey(record, rowKeyField) === key);
|
|
63
|
+
if (matched) selectedMap.set(key, matched);
|
|
32
64
|
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return item;
|
|
46
|
-
});
|
|
47
|
-
else changeRows.map((item) => {
|
|
48
|
-
if (selectedKeys.value.includes(item?.[rowKey.value])) {
|
|
49
|
-
selectedKeys.value = selectedKeys.value.filter((el) => el !== item[rowKey.value]);
|
|
50
|
-
selectedItems.value = selectedItems.value.filter((el) => el[rowKey.value] !== item[rowKey.value]);
|
|
51
|
-
}
|
|
52
|
-
return item;
|
|
53
|
-
});
|
|
54
|
-
};
|
|
55
|
-
const removeRowKeys = (keys) => {
|
|
56
|
-
selectedKeys.value = selectedKeys.value.filter((el) => !keys.includes(el));
|
|
57
|
-
selectedItems.value = selectedItems.value.filter((el) => !keys.includes(el?.[rowKey.value || ""]));
|
|
58
|
-
changeRowKey();
|
|
59
|
-
};
|
|
60
|
-
const syncSelectedRows = (dataList) => {
|
|
61
|
-
if (rowKey.value) {
|
|
62
|
-
if (selectedKeys.value.length !== selectedItems.value.length) {
|
|
63
|
-
const itemsKeys = selectedItems.value.map((item) => item[rowKey.value]);
|
|
64
|
-
const notIncludes = selectedKeys.value.filter((item) => !itemsKeys.includes(item));
|
|
65
|
-
dataList.forEach((item) => {
|
|
66
|
-
if (notIncludes.includes(item[rowKey.value])) selectedItems.value.push(cloneDeep(item));
|
|
67
|
-
});
|
|
68
|
-
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 处理 antdv Table 的 onChange 回调。
|
|
68
|
+
* antd 传入的 rows 只包含当前页数据,需与已有 Map 合并以保留跨页选中项。
|
|
69
|
+
*/
|
|
70
|
+
function handleAntdChange(keys, rows, info) {
|
|
71
|
+
const rowKeyField = options.rowKey.value;
|
|
72
|
+
const newMap = /* @__PURE__ */ new Map();
|
|
73
|
+
for (const key of keys) {
|
|
74
|
+
const fromRows = rows.find((record) => getKey(record, rowKeyField) === key);
|
|
75
|
+
const existing = selectedMap.get(key);
|
|
76
|
+
newMap.set(key, fromRows ?? existing);
|
|
69
77
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
changeRowKey();
|
|
75
|
-
};
|
|
78
|
+
selectedMap.clear();
|
|
79
|
+
for (const [key, item] of newMap) selectedMap.set(key, item);
|
|
80
|
+
options.rowSelection.value?.onChange?.(selectedRowKeys.value, selectedItems.value, info);
|
|
81
|
+
}
|
|
76
82
|
return {
|
|
77
|
-
|
|
83
|
+
selectedRowKeys,
|
|
78
84
|
selectedItems,
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
mergedRowSelection: computed(() => {
|
|
86
|
+
const rowSelectionConfig = options.rowSelection.value;
|
|
87
|
+
if (!rowSelectionConfig) return void 0;
|
|
88
|
+
return {
|
|
89
|
+
...rowSelectionConfig,
|
|
90
|
+
selectedRowKeys: selectedRowKeys.value,
|
|
91
|
+
onChange: handleAntdChange
|
|
92
|
+
};
|
|
93
|
+
}),
|
|
94
|
+
select,
|
|
95
|
+
selectAll,
|
|
96
|
+
remove,
|
|
97
|
+
clear,
|
|
98
|
+
sync
|
|
85
99
|
};
|
|
86
100
|
}
|
|
87
|
-
|
|
88
101
|
//#endregion
|
|
89
|
-
export { useRowSelection };
|
|
102
|
+
export { useRowSelection };
|
package/dist/hooks/useTable.d.ts
CHANGED
|
@@ -1,90 +1,48 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ProCoreActionType, ProCoreFormType, ProTableProps, ProTableRef, ProTableRowSelection, RequestConfig, RequestFunction } from "../types/TableTypings.js";
|
|
3
|
-
import { BaseTableProps } from "../props.js";
|
|
1
|
+
import { PageState, ProCoreActionType, ProCoreFormType, ProSearchMap, ProTablePaginationConfig, ProTableProps, ProTableRef, RequestFunction, RowSelectionActions } from "../interface.js";
|
|
4
2
|
import { ComputedRef, MaybeRef, Reactive, Ref } from "vue";
|
|
5
|
-
import {
|
|
3
|
+
import { FilterValue, SorterResult, TableCurrentDataSource } from "antdv-next/dist/table/interface";
|
|
6
4
|
|
|
7
5
|
//#region src/hooks/useTable.d.ts
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
rowKey?: keyof T;
|
|
15
|
-
title?: (data: T[]) => any;
|
|
16
|
-
footer?: (data: T[]) => any;
|
|
17
|
-
postData?: (data: T[]) => any;
|
|
18
|
-
rowExpandable?: (record: T) => boolean;
|
|
19
|
-
transformCellText?: (opt: {
|
|
20
|
-
text: any;
|
|
21
|
-
column: ProColumnType<T, R>;
|
|
22
|
-
record: any;
|
|
23
|
-
index: number;
|
|
24
|
-
}) => any;
|
|
25
|
-
expandIcon?: (props: {
|
|
26
|
-
prefixCls: string;
|
|
27
|
-
expanded: boolean;
|
|
28
|
-
record: T;
|
|
29
|
-
expandable: boolean;
|
|
30
|
-
onExpand: (record: T, event: MouseEvent) => void;
|
|
31
|
-
}) => any;
|
|
32
|
-
customRow?: (data: T, index?: number, column?: ProColumnType<T, R>) => any;
|
|
33
|
-
customHeaderRow?: (data: T, index?: number, column?: ProColumnType<T, R>) => any;
|
|
34
|
-
expandedRowRender: (opt: {
|
|
35
|
-
record: T;
|
|
36
|
-
index: number;
|
|
37
|
-
indent: number;
|
|
38
|
-
expanded: boolean;
|
|
39
|
-
}) => any;
|
|
40
|
-
rowClassName?: string | ((record: T, index: number, indent: number) => string);
|
|
41
|
-
onReset?: (params?: Partial<R>) => void;
|
|
42
|
-
onReload?: (params?: Partial<R>) => void;
|
|
43
|
-
onSubmit?: (params?: Partial<R>) => void;
|
|
44
|
-
onExpand?: (expanded: boolean, record: T) => void;
|
|
45
|
-
onResizeColumn?: (w: number, col: ProColumnType<T, R>) => void;
|
|
46
|
-
onBeforeSearchSubmit?: RequestFunction<T, R>;
|
|
47
|
-
};
|
|
48
|
-
type BaseTableState<T extends object = RecordType, R extends object = RecordType> = Omit<ProTableProps<T, R>, 'request'>;
|
|
49
|
-
interface UseTableReturn<T extends object = RecordType, R extends object = RecordType> {
|
|
50
|
-
/** @name loading 状态,可以直接进行修改 */
|
|
6
|
+
interface UseTableOptions<T = any, R = any> {
|
|
7
|
+
state?: MaybeRef<Partial<ProTableProps<T, R>>> | Reactive<Partial<ProTableProps<T, R>>>;
|
|
8
|
+
request?: RequestFunction<T, R>;
|
|
9
|
+
}
|
|
10
|
+
interface UseTableReturn<T = any, R = any> {
|
|
11
|
+
/** loading 状态,可直接赋值 */
|
|
51
12
|
loading: Ref<boolean>;
|
|
52
|
-
/**
|
|
13
|
+
/** 只读表格数据 */
|
|
53
14
|
dataSource: ComputedRef<T[]>;
|
|
54
|
-
/**
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
|
|
62
|
-
/**
|
|
15
|
+
/** 表格请求参数(含分页 + 表单搜索参数) */
|
|
16
|
+
requestSearch: ComputedRef<Partial<R> & Partial<PageState>>;
|
|
17
|
+
/** 表格行选择 keys */
|
|
18
|
+
selectedKeys: ComputedRef<(string | number)[]>;
|
|
19
|
+
/** 表格行选择 rows */
|
|
20
|
+
selectedItems: ComputedRef<T[]>;
|
|
21
|
+
/** 表格行选择操作 */
|
|
22
|
+
rowsSelection: RowSelectionActions<T>;
|
|
23
|
+
/** action 表格实例 */
|
|
24
|
+
actionRef: ComputedRef<ProCoreActionType<T, R>>;
|
|
25
|
+
/** form 查询表单实例 */
|
|
26
|
+
formRef: ComputedRef<ProCoreFormType<R>>;
|
|
27
|
+
/** 主动刷新 */
|
|
63
28
|
reload: ProCoreActionType<T, R>['reload'];
|
|
64
|
-
/**
|
|
29
|
+
/** 更新表格数据 */
|
|
65
30
|
setTableDataList: ProCoreActionType<T, R>['setTableDataList'];
|
|
66
|
-
/**
|
|
31
|
+
/** 更新表格行数据 */
|
|
67
32
|
operateTableDataRow: ProCoreActionType<T, R>['operateTableDataRow'];
|
|
68
|
-
/**
|
|
69
|
-
setPageInfo:
|
|
70
|
-
/**
|
|
33
|
+
/** 设置翻页、排序、筛选并刷新 */
|
|
34
|
+
setPageInfo: (pagination: ProTablePaginationConfig, filters?: Record<string, FilterValue | null>, sorter?: SorterResult | SorterResult[], extra?: TableCurrentDataSource) => void;
|
|
35
|
+
/** 设置翻页 */
|
|
71
36
|
setPagination: ProCoreActionType<T, R>['setPagination'];
|
|
72
|
-
/**
|
|
37
|
+
/** 刷新并清空表单,重置为第一页 */
|
|
73
38
|
reloadAndReset: ProCoreActionType<T, R>['reloadAndReset'];
|
|
74
|
-
/**
|
|
39
|
+
/** 改变 loading 状态 */
|
|
75
40
|
setLoading: ProCoreActionType<T, R>['setLoading'];
|
|
76
|
-
/**
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
|
|
80
|
-
/** @name 表格参数,用于传递给ProTable组件使用,可以对其进行修改 */
|
|
81
|
-
tableState: Reactive<ProTableState<T, R>>;
|
|
82
|
-
/** @name 更新表格参数 SearchMap,key为SearchMap唯一字段,value是更新的参数,会merge */
|
|
83
|
-
updateSearchMap: (key: keyof R | keyof T, value: Partial<ProSearchMap<any>>) => void;
|
|
41
|
+
/** 表格参数,传递给 ProTable 组件 */
|
|
42
|
+
tableState: Reactive<Partial<ProTableProps<T, R>>>;
|
|
43
|
+
/** 更新 searchMap 中指定字段的配置 */
|
|
44
|
+
updateSearchMap: (key: keyof T | keyof R, value: Partial<ProSearchMap<any>>) => void;
|
|
84
45
|
}
|
|
85
|
-
declare function useTable<T
|
|
86
|
-
state?: MaybeRef<BaseTableState<T, R>> | Reactive<BaseTableState<T, R>> | ComputedRef<BaseTableState<T, R>>;
|
|
87
|
-
request?: RequestFunction<T, R>;
|
|
88
|
-
}): UseTableReturn<T, R>;
|
|
46
|
+
declare function useTable<T = any, R = any>(tableRef: Ref<ProTableRef<T, R> | undefined>, options?: UseTableOptions<T, R>): UseTableReturn<T, R>;
|
|
89
47
|
//#endregion
|
|
90
|
-
export {
|
|
48
|
+
export { UseTableOptions, UseTableReturn, useTable };
|