@gx-design-vue/pro-table 0.2.0-alpha.8 → 0.2.0-alpha.9

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 (133) hide show
  1. package/dist/ProTable.d.ts +14 -492
  2. package/dist/ProTable.js +818 -518
  3. package/dist/components/ScrollBar/Bar.d.ts +81 -0
  4. package/dist/components/ScrollBar/Bar.js +84 -0
  5. package/dist/components/ScrollBar/Thumb.d.ts +52 -0
  6. package/dist/components/ScrollBar/{Thumb/index.js → Thumb.js} +67 -55
  7. package/dist/components/ScrollBar/context.d.ts +3 -4
  8. package/dist/components/ScrollBar/context.js +3 -3
  9. package/dist/components/ScrollBar/util.d.ts +6 -5
  10. package/dist/components/ScrollBar/util.js +1 -12
  11. package/dist/components/SearchForm/CollapseToggle.d.ts +55 -0
  12. package/dist/components/SearchForm/CollapseToggle.js +47 -0
  13. package/dist/components/SearchForm/FormItemContainer.d.ts +75 -0
  14. package/dist/components/SearchForm/FormItemContainer.js +225 -0
  15. package/dist/components/SearchForm/FormItemWrapper.d.ts +82 -0
  16. package/dist/components/SearchForm/FormItemWrapper.js +62 -0
  17. package/dist/components/SearchForm/SearchForm.d.ts +130 -0
  18. package/dist/components/SearchForm/SearchForm.js +319 -0
  19. package/dist/components/SearchForm/index.d.ts +2 -0
  20. package/dist/components/SearchForm/index.js +2 -0
  21. package/dist/components/Toolbar/FullscreenIcon.d.ts +26 -0
  22. package/dist/components/Toolbar/FullscreenIcon.js +22 -0
  23. package/dist/components/Toolbar/ListToolBar.d.ts +111 -0
  24. package/dist/components/Toolbar/ListToolBar.js +101 -0
  25. package/dist/components/Toolbar/index.d.ts +103 -0
  26. package/dist/components/Toolbar/index.js +101 -0
  27. package/dist/components/Toolbar/style.d.ts +8 -0
  28. package/dist/components/{ListToolBar → Toolbar}/style.js +32 -27
  29. package/dist/context/TableContext.d.ts +15 -27
  30. package/dist/context/TableContext.js +3 -3
  31. package/dist/hooks/index.d.ts +16 -0
  32. package/dist/hooks/index.js +16 -0
  33. package/dist/hooks/useBreakpoints.d.ts +13 -0
  34. package/dist/hooks/useBreakpoints.js +57 -0
  35. package/dist/hooks/useCellRender.d.ts +13 -0
  36. package/dist/hooks/useCellRender.js +28 -0
  37. package/dist/hooks/useColumnResize.d.ts +30 -0
  38. package/dist/hooks/useColumnResize.js +110 -0
  39. package/dist/hooks/useColumns.d.ts +35 -24
  40. package/dist/hooks/useColumns.js +89 -56
  41. package/dist/hooks/useFetchData.d.ts +40 -65
  42. package/dist/hooks/useFetchData.js +157 -172
  43. package/dist/hooks/useFitPage.d.ts +19 -0
  44. package/dist/hooks/useFitPage.js +90 -0
  45. package/dist/hooks/useKeepAliveReload.d.ts +21 -0
  46. package/dist/hooks/useKeepAliveReload.js +24 -0
  47. package/dist/hooks/useLoading.d.ts +18 -7
  48. package/dist/hooks/useLoading.js +26 -8
  49. package/dist/hooks/usePagination.d.ts +10 -7
  50. package/dist/hooks/usePagination.js +37 -26
  51. package/dist/hooks/useRequestOptions.d.ts +18 -0
  52. package/dist/hooks/useRequestOptions.js +39 -0
  53. package/dist/hooks/useRowSelection.d.ts +27 -15
  54. package/dist/hooks/useRowSelection.js +92 -77
  55. package/dist/hooks/useTable.d.ts +19 -77
  56. package/dist/hooks/useTable.js +66 -54
  57. package/dist/hooks/useTableForm.d.ts +15 -83
  58. package/dist/hooks/useTableForm.js +93 -57
  59. package/dist/hooks/useTableScroll.d.ts +33 -31
  60. package/dist/hooks/useTableScroll.js +71 -26
  61. package/dist/hooks/useTableSize.d.ts +17 -7
  62. package/dist/hooks/useTableSize.js +20 -6
  63. package/dist/index.d.ts +10 -7
  64. package/dist/index.js +9 -3
  65. package/dist/interface.d.ts +492 -0
  66. package/dist/pro-table.esm.js +3512 -3965
  67. package/dist/pro-table.js +1 -1
  68. package/dist/style/fit-page.d.ts +4 -2
  69. package/dist/style/fit-page.js +9 -3
  70. package/dist/style/index.d.ts +4 -6
  71. package/dist/style/index.js +24 -74
  72. package/dist/style/list.d.ts +4 -2
  73. package/dist/style/list.js +1 -10
  74. package/dist/style/resizable.d.ts +8 -0
  75. package/dist/style/resizable.js +18 -0
  76. package/dist/style/scroll.d.ts +4 -2
  77. package/dist/style/scroll.js +8 -6
  78. package/dist/style/search.d.ts +8 -0
  79. package/dist/{components/Form/style.js → style/search.js} +22 -8
  80. package/dist/theme/augment.d.ts +8 -0
  81. package/dist/theme/interface/components.d.ts +8 -0
  82. package/dist/utils/dateFormat.d.ts +9 -0
  83. package/dist/utils/dateFormat.js +29 -0
  84. package/dist/utils/formConstants.d.ts +9 -0
  85. package/dist/utils/formConstants.js +29 -0
  86. package/dist/utils/valueFormat.d.ts +9 -0
  87. package/dist/utils/valueFormat.js +27 -0
  88. package/package.json +10 -9
  89. package/dist/components/Form/components/RequestSelect.d.ts +0 -50
  90. package/dist/components/Form/components/RequestSelect.js +0 -56
  91. package/dist/components/Form/hooks/useForm.d.ts +0 -11
  92. package/dist/components/Form/hooks/useForm.js +0 -30
  93. package/dist/components/Form/index.d.ts +0 -32
  94. package/dist/components/Form/index.js +0 -504
  95. package/dist/components/Form/style.d.ts +0 -6
  96. package/dist/components/Form/utils/config.d.ts +0 -9
  97. package/dist/components/Form/utils/config.js +0 -29
  98. package/dist/components/Form/utils/dateFormat.d.ts +0 -22
  99. package/dist/components/Form/utils/dateFormat.js +0 -43
  100. package/dist/components/ListToolBar/index.d.ts +0 -59
  101. package/dist/components/ListToolBar/index.js +0 -123
  102. package/dist/components/ListToolBar/style.d.ts +0 -6
  103. package/dist/components/ScrollBar/Bar/index.d.ts +0 -49
  104. package/dist/components/ScrollBar/Bar/index.js +0 -68
  105. package/dist/components/ScrollBar/Bar/props.d.ts +0 -25
  106. package/dist/components/ScrollBar/Bar/props.js +0 -17
  107. package/dist/components/ScrollBar/Thumb/index.d.ts +0 -40
  108. package/dist/components/ScrollBar/Thumb/props.d.ts +0 -20
  109. package/dist/components/ScrollBar/Thumb/props.js +0 -17
  110. package/dist/components/TableCell/index.d.ts +0 -37
  111. package/dist/components/TableCell/index.js +0 -69
  112. package/dist/components/ToolBar/FullscreenIcon.d.ts +0 -7
  113. package/dist/components/ToolBar/FullscreenIcon.js +0 -11
  114. package/dist/components/ToolBar/index.d.ts +0 -34
  115. package/dist/components/ToolBar/index.js +0 -97
  116. package/dist/hooks/tryOnActivated.d.ts +0 -6
  117. package/dist/hooks/tryOnActivated.js +0 -12
  118. package/dist/hooks/useDebounceFn.d.ts +0 -8
  119. package/dist/hooks/useDebounceFn.js +0 -31
  120. package/dist/hooks/useScrollArea.d.ts +0 -24
  121. package/dist/hooks/useScrollArea.js +0 -102
  122. package/dist/props.d.ts +0 -340
  123. package/dist/props.js +0 -247
  124. package/dist/types/ColumnTypings.d.ts +0 -130
  125. package/dist/types/SlotsTypings.d.ts +0 -63
  126. package/dist/types/SlotsTypings.js +0 -12
  127. package/dist/types/TableTypings.d.ts +0 -359
  128. package/dist/types/index.d.ts +0 -9
  129. package/dist/utils/utils.d.ts +0 -10
  130. package/dist/utils/utils.js +0 -89
  131. /package/dist/{types/ColumnTypings.js → interface.js} +0 -0
  132. /package/dist/{types/TableTypings.js → theme/augment.js} +0 -0
  133. /package/dist/{types/index.js → theme/interface/components.js} +0 -0
@@ -1,49 +1,78 @@
1
- import useDebounceFn from "./useDebounceFn.js";
2
- import { computed, onActivated, onDeactivated, onMounted, onUnmounted, ref, toRaw, unref, watch } from "vue";
3
- import { cloneDeep, deepMerge, getRandomNumber, getSortIndex, handleCurrentPage, isArray, isDeepEqualReact, isFunction, isObject, runFunction } from "@gx-design-vue/pro-utils";
4
- import { omit } from "es-toolkit";
1
+ import { computed, onActivated, onDeactivated, onUnmounted, ref, toRaw, watch } from "vue";
2
+ import { getRandomNumber, getSortIndex, handleCurrentPage, isArray, isFunction, isObject, merge } from "@gx-design-vue/pro-utils";
3
+ import { useDebounceFn } from "@vueuse/core";
5
4
  //#region src/hooks/useFetchData.ts
6
- function useConfigFetchData(props) {
7
- const rowKey = computed(() => props.rowKey);
8
- const polling = computed(() => props.polling);
9
- const debounceTime = computed(() => props.debounceTime);
10
- const dataSource = computed(() => props.dataSource);
11
- const autoRequest = computed(() => props.autoRequest);
12
- return {
13
- rowKey,
14
- polling,
15
- request: props.request,
16
- postData: props.postData,
17
- debounceTime,
18
- dataSource,
19
- autoRequest
20
- };
21
- }
22
- function useFetchData({ rowKey, autoRequest, polling, request, postData, dataSource, waitRequest, debounceTime }, { params, columns, setLoading, setColumns, removeRowKeys, syncSelectedRows, defaultFormSearch, setPagination, pageInfo, paginationInfo, onRequestError, onBeforeSearchSubmit, hasCustomRender }, emit) {
23
- const updateKey = ref("");
24
- const umountRef = ref(false);
25
- const pollingLoading = ref(false);
5
+ const EMPTY_ARRAY = [];
6
+ /**
7
+ * 核心请求引擎。
8
+ * 负责数据请求调度、分页状态、轮询、AbortController 中断、
9
+ * loading 管理、数据转换、行操作、排序/筛选变更。
10
+ *
11
+ * 调度模型:所有请求入口(run/reload/handleTableChange/params 变化等)
12
+ * 统一进入 dispatchFetch → debouncedFetch → fetchList。
13
+ * 通过 requestId + AbortController 双重保证旧响应不回写。
14
+ */
15
+ function useFetchData(config, action) {
16
+ const { rowKey, polling, pollingTime, request, postData, dataSource, immediate, waitRequest, autoRequest, debounceTime, params, defaultFormSearch, onLoadingChange, onRequestError, onBeforeSearchSubmit } = config;
17
+ const { pageInfo, paginationInfo, setPagination, setLoading, setColumns, removeRowKeys, syncSelectedRows, columns } = action;
26
18
  const tableDataList = ref([]);
27
- const pollingSetTimeRef = ref();
28
- const abortRef = ref(null);
29
- const requestFinally = (clear = false) => {
30
- if (umountRef.value || clear) setLoading(false);
31
- setPollingLoading(false);
32
- };
33
- const fetchList = async (props = {}) => {
34
- const { pagination = {}, filters = {}, sorter = {}, removeKeys = [], isPolling = false, extra } = props;
19
+ const unmounted = ref(false);
20
+ const pollingTimer = ref(null);
21
+ const abortController = ref(null);
22
+ const requestId = ref("");
23
+ /** 通知外部 loading 状态变化(通过 onLoadingChange 回调) */
24
+ function notifyLoading(loadingState) {
25
+ if (onLoadingChange) onLoadingChange(loadingState);
26
+ }
27
+ function clearPollingTimer() {
28
+ if (pollingTimer.value != null) {
29
+ clearTimeout(pollingTimer.value);
30
+ pollingTimer.value = null;
31
+ }
32
+ }
33
+ function stopPolling() {
34
+ clearPollingTimer();
35
+ }
36
+ function schedulePolling(fetchParams) {
37
+ if (unmounted.value || !polling.value) return;
38
+ const interval = Math.max(pollingTime.value || 2e3, 2e3);
39
+ clearPollingTimer();
40
+ pollingTimer.value = setTimeout(() => {
41
+ dispatchFetch({
42
+ ...fetchParams,
43
+ isPolling: true
44
+ });
45
+ }, interval);
46
+ }
47
+ function abortCurrent() {
48
+ abortController.value?.abort();
49
+ abortController.value = null;
50
+ }
51
+ /** 写入表格数据并同步 sortIndex,无 request 时同步 dataSource total */
52
+ function setTableDataList(list) {
53
+ tableDataList.value = getSortIndex(list, toRaw(pageInfo));
54
+ if (!request || !isFunction(request)) {
55
+ const total = list.length || 0;
56
+ if (total !== pageInfo.total) setPagination({ total });
57
+ }
58
+ }
59
+ /** 执行单次请求,处理参数合并、AbortController、轮询调度、错误处理 */
60
+ async function fetchList(fetchParams = {}) {
61
+ const { pagination: fetchPagination = {}, filters = {}, sorter = {}, removeKeys = [], isPolling = false, extra } = fetchParams;
35
62
  if (!request || !isFunction(request)) return dataSource.value || [];
36
- if (!isPolling) setLoading(true);
37
- else setPollingLoading(true);
38
- if (pagination && Object.keys(pagination).length) setPagination(pagination);
63
+ if (!isPolling) {
64
+ setLoading(true);
65
+ notifyLoading(true);
66
+ }
67
+ if (fetchPagination && Object.keys(fetchPagination).length) setPagination(fetchPagination);
39
68
  try {
40
69
  if (removeKeys.length) removeRowKeys(removeKeys);
41
- const sorterList = isObject(sorter) ? Object.keys(sorter).length ? [sorter] : [] : sorter;
42
- setColumns(unref(columns).map((item) => {
43
- const row = sorterList.find((el) => (el?.columnKey || el?.field) === item.dataIndex);
70
+ const sorterList = isObject(sorter) && Object.keys(sorter).length ? [sorter] : isArray(sorter) ? sorter : [];
71
+ if (setColumns && columns) setColumns(columns.value.map((columnItem) => {
72
+ const matchedSorter = sorterList.find((sorterItem) => (sorterItem?.columnKey || sorterItem?.field) === columnItem.dataIndex);
44
73
  return {
45
- ...item,
46
- sortOrder: row?.order
74
+ ...columnItem,
75
+ sortOrder: matchedSorter?.order
47
76
  };
48
77
  }));
49
78
  let actionParams = {
@@ -51,9 +80,9 @@ function useFetchData({ rowKey, autoRequest, polling, request, postData, dataSou
51
80
  pageSize: pageInfo.pageSize,
52
81
  current: handleCurrentPage(toRaw(pageInfo), removeKeys.length)
53
82
  },
54
- ...unref(defaultFormSearch),
55
- ...unref(params),
56
- ...props.params || {}
83
+ ...toRaw(defaultFormSearch.value),
84
+ ...toRaw(params.value),
85
+ ...fetchParams.params || {}
57
86
  };
58
87
  if (onBeforeSearchSubmit && isFunction(onBeforeSearchSubmit)) actionParams = await onBeforeSearchSubmit({
59
88
  params: actionParams,
@@ -61,98 +90,66 @@ function useFetchData({ rowKey, autoRequest, polling, request, postData, dataSou
61
90
  filter: filters,
62
91
  extra
63
92
  });
64
- let responseData = [];
65
- const requestKey = `table_request_${getRandomNumber().uuid(10)}`;
66
- updateKey.value = requestKey;
67
- const response = await request?.({
68
- params: cloneDeep(toRaw(actionParams)),
93
+ const currentRequestId = `table_request_${getRandomNumber().uuid(10)}`;
94
+ requestId.value = currentRequestId;
95
+ const controller = new AbortController();
96
+ abortController.value = controller;
97
+ const response = await request({
98
+ params: { ...actionParams },
69
99
  sorter: sorterList,
70
100
  filter: filters,
71
- extra
101
+ extra,
102
+ signal: controller.signal
72
103
  });
73
- if (updateKey.value !== requestKey) return [];
104
+ if (requestId.value !== currentRequestId || controller.signal.aborted) return [];
74
105
  if (response) {
75
106
  const { success = true, data = [] } = response;
76
107
  if (!success) return [];
77
- responseData = typeof postData === "function" ? await postData?.(data) : data;
78
- syncSelectedRows(responseData);
79
- const total = response.total || responseData?.length || 0;
108
+ const responseData = typeof postData === "function" ? postData(data) : data;
109
+ const total = response.total || responseData.length || 0;
80
110
  if (total !== pageInfo.total) setPagination({ total });
81
- const preTableDataList = unref(tableDataList).map((item) => omit(item, ["sortIndex"]));
82
- if (!isDeepEqualReact(responseData, preTableDataList)) {
83
- setTableDataList(responseData);
84
- return responseData;
85
- }
86
- return unref(tableDataList);
87
- } else return [];
111
+ setTableDataList(responseData);
112
+ syncSelectedRows(responseData);
113
+ schedulePolling(fetchParams);
114
+ return responseData;
115
+ }
116
+ return [];
88
117
  } catch (e) {
89
- if (onRequestError === void 0) throw new Error(e);
90
- if (tableDataList.value === void 0) setTableDataList([]);
91
- onRequestError(e);
118
+ if (e.name === "AbortError") return [];
119
+ if (onRequestError) {
120
+ if (tableDataList.value === void 0) setTableDataList([]);
121
+ onRequestError(e);
122
+ return [];
123
+ }
124
+ throw e;
92
125
  } finally {
93
- requestFinally(true);
94
- }
95
- return [];
96
- };
97
- const fetchListDebounce = useDebounceFn(async (props = {}) => {
98
- if (pollingSetTimeRef.value) clearTimeout(pollingSetTimeRef.value);
99
- if (!request) return;
100
- const abort = new AbortController();
101
- abortRef.value = abort;
102
- try {
103
- const msg = await Promise.race([fetchList(props), new Promise((_, reject) => {
104
- abortRef.value?.signal?.addEventListener?.("abort", () => {
105
- reject("aborted");
106
- fetchListDebounce.cancel();
107
- requestFinally();
108
- });
109
- })]);
110
- if (abort.signal.aborted) return;
111
- const needPolling = runFunction(polling.value, msg);
112
- if (needPolling && !umountRef.value) pollingSetTimeRef.value = setTimeout(() => {
113
- fetchListDebounce.run({
114
- ...props,
115
- isPolling: needPolling
116
- });
117
- }, Math.max(needPolling, 2e3));
118
- return msg;
119
- } catch (error) {
120
- if (error === "aborted") return;
121
- throw error;
126
+ if (!isPolling) {
127
+ setLoading(false);
128
+ notifyLoading(false);
129
+ }
122
130
  }
123
- }, debounceTime.value || 30);
124
- const abortFetch = () => {
125
- abortRef.value?.abort();
126
- fetchListDebounce.cancel();
127
- requestFinally();
128
- };
129
- onMounted(() => {
130
- umountRef.value = false;
131
- });
131
+ }
132
+ const debouncedFetch = useDebounceFn((fetchParams) => fetchList(fetchParams), () => debounceTime.value ?? 10);
133
+ /** 统一请求调度入口:先 abort 上一个请求,再 debounce 执行 */
134
+ function dispatchFetch(fetchParams = {}) {
135
+ abortCurrent();
136
+ debouncedFetch(fetchParams);
137
+ }
132
138
  onActivated(() => {
133
- umountRef.value = false;
139
+ unmounted.value = false;
134
140
  });
135
141
  onUnmounted(() => {
136
- abortFetch();
137
- umountRef.value = true;
138
- clearTimeout(pollingSetTimeRef.value);
142
+ unmounted.value = true;
143
+ abortCurrent();
144
+ stopPolling();
139
145
  });
140
146
  onDeactivated(() => {
141
- abortFetch();
142
- umountRef.value = true;
143
- clearTimeout(pollingSetTimeRef.value);
147
+ unmounted.value = true;
148
+ abortCurrent();
149
+ stopPolling();
144
150
  });
145
- watch(() => polling.value, () => {
146
- if (waitRequest.value) return;
147
- if (!polling.value) clearTimeout(pollingSetTimeRef.value);
148
- else fetchListDebounce.run({ isPolling: true });
149
- }, { immediate: true });
150
- watch(() => waitRequest.value, () => {
151
- if (waitRequest.value) setLoading(true);
152
- else fetchListDebounce.run({ isPolling: false });
153
- }, { immediate: true });
154
- watch(() => dataSource.value, () => {
155
- if (dataSource.value) setTableDataList(dataSource.value || []);
151
+ watch(() => dataSource.value, (source) => {
152
+ if (source && !isFunction(request)) setTableDataList(source);
156
153
  }, {
157
154
  deep: true,
158
155
  immediate: true
@@ -161,59 +158,40 @@ function useFetchData({ rowKey, autoRequest, polling, request, postData, dataSou
161
158
  if (waitRequest.value) return;
162
159
  if (autoRequest.value) {
163
160
  setPagination({ current: 1 });
164
- fetchRunData();
161
+ dispatchFetch({ isPolling: false });
165
162
  }
166
- }, {
167
- deep: true,
168
- immediate: true
169
- });
170
- watch(() => defaultFormSearch.value, (val, old) => {
163
+ }, { deep: true });
164
+ watch(() => defaultFormSearch.value, (current, previous) => {
171
165
  if (waitRequest.value) return;
172
- if (!isDeepEqualReact(val, old)) {
166
+ if (current !== previous) {
173
167
  setPagination({ current: 1 });
174
- fetchRunData();
168
+ dispatchFetch({ isPolling: false });
175
169
  }
176
- }, {
177
- deep: true,
178
- immediate: true
170
+ }, { deep: true });
171
+ watch(() => polling.value, () => {
172
+ if (waitRequest.value) return;
173
+ if (!polling.value) stopPolling();
174
+ else dispatchFetch({ isPolling: true });
179
175
  });
180
- function fetchRunData() {
181
- if (request) {
182
- if (!polling.value) {
183
- abortFetch();
184
- fetchListDebounce.run({ isPolling: false });
185
- }
186
- } else setTableDataList(dataSource.value || []);
187
- }
188
- const getDataSourceRef = computed(() => {
189
- if (hasCustomRender.value) return unref(tableDataList);
190
- const viewColumns = columns.value.filter((column) => column.show || column.show === void 0);
191
- if (!unref(tableDataList) || !viewColumns || viewColumns.length === 0) return [];
192
- return unref(tableDataList);
176
+ watch(() => waitRequest.value, (waiting) => {
177
+ if (waiting) {
178
+ setLoading(true);
179
+ notifyLoading(true);
180
+ } else if (immediate.value) dispatchFetch({ isPolling: false });
193
181
  });
194
- const isTreeDataRef = computed(() => unref(tableDataList).some((item) => isArray(item.children) && item.children.length > 0));
195
- function setPollingLoading(loading) {
196
- pollingLoading.value = loading;
197
- }
198
- function handleTableChange(pagination, filters = {}, sorter = {}, extra) {
199
- abortFetch();
200
- fetchListDebounce.run({
201
- pagination,
182
+ if (!waitRequest.value && immediate.value) dispatchFetch({ isPolling: false });
183
+ const isTreeDataRef = computed(() => tableDataList.value.some((item) => isArray(item.children) && item.children.length > 0));
184
+ function handleTableChange(paginationConfig, filters = {}, sorter = {}, extra) {
185
+ dispatchFetch({
186
+ pagination: paginationConfig,
202
187
  filters,
203
188
  sorter,
204
189
  extra,
205
190
  isPolling: false
206
191
  });
207
192
  }
208
- function setTableDataList(list) {
209
- const newData = getSortIndex(cloneDeep(list), toRaw(pageInfo));
210
- tableDataList.value = newData;
211
- if (!request || !isFunction(request)) {
212
- const total = newData.length || 0;
213
- if (total !== pageInfo.total) setPagination({ total });
214
- }
215
- }
216
- const operateTableDataRow = (props) => {
193
+ /** 对表格数据行执行增删改操作(update/push/unshift/delete) */
194
+ function operateTableDataRow(props) {
217
195
  const { key, row, value, type = "update" } = props;
218
196
  const dataIndex = key ?? rowKey.value;
219
197
  const recordValue = row?.[dataIndex] ?? value;
@@ -221,7 +199,7 @@ function useFetchData({ rowKey, autoRequest, polling, request, postData, dataSou
221
199
  switch (type) {
222
200
  case "update":
223
201
  if (dataIndex && recordValue && row) tableDataList.value = tableDataList.value.map((item) => {
224
- if (recordValue === item[dataIndex]) return deepMerge(item, row);
202
+ if (recordValue === item[dataIndex]) return merge({}, item, row);
225
203
  return item;
226
204
  });
227
205
  break;
@@ -235,22 +213,29 @@ function useFetchData({ rowKey, autoRequest, polling, request, postData, dataSou
235
213
  if (dataIndex) tableDataList.value = tableDataList.value.filter((item) => value !== item[dataIndex]);
236
214
  break;
237
215
  }
238
- };
216
+ }
217
+ /** 手动触发请求,waitRequest=true 时跳过 */
218
+ function run(info) {
219
+ if (waitRequest.value) return;
220
+ if (request) dispatchFetch({
221
+ ...info,
222
+ isPolling: false
223
+ });
224
+ else setTableDataList(dataSource.value || []);
225
+ }
226
+ /** reload 是 run 的别名 */
227
+ function reload(info) {
228
+ run(info);
229
+ }
239
230
  return {
240
- dataSource: getDataSourceRef,
231
+ dataSource: computed(() => tableDataList.value.length ? tableDataList.value : EMPTY_ARRAY),
241
232
  isTreeDataRef,
242
233
  setTableDataList,
243
234
  operateTableDataRow,
244
235
  handleTableChange,
245
- run: async (info) => {
246
- if (waitRequest.value) return;
247
- if (request) await fetchListDebounce.run({
248
- ...info,
249
- isPolling: false
250
- });
251
- else emit("reload");
252
- }
236
+ run,
237
+ reload
253
238
  };
254
239
  }
255
240
  //#endregion
256
- export { useConfigFetchData, useFetchData };
241
+ export { useFetchData };
@@ -0,0 +1,19 @@
1
+ import { BarExpose } from "../components/ScrollBar/Bar.js";
2
+ import { ComputedRef, Ref } from "vue";
3
+
4
+ //#region src/hooks/useFitPage.d.ts
5
+ interface UseFitPageOptions {
6
+ fitPage: ComputedRef<boolean>;
7
+ cardEl: Ref<HTMLElement | undefined>;
8
+ prefixCls: ComputedRef<string>;
9
+ }
10
+ interface UseFitPageReturn {
11
+ scrollY: ComputedRef<number>;
12
+ overflowHidden: ComputedRef<boolean>;
13
+ fullPageClass: ComputedRef<string>;
14
+ scrollEl: Ref<HTMLElement | undefined>;
15
+ barRef: Ref<BarExpose | undefined>;
16
+ }
17
+ declare function useFitPage(options: UseFitPageOptions): UseFitPageReturn;
18
+ //#endregion
19
+ export { UseFitPageOptions, UseFitPageReturn, useFitPage };
@@ -0,0 +1,90 @@
1
+ import { useProvideScrollBarContext } from "../components/ScrollBar/context.js";
2
+ import { computed, ref, watchEffect } from "vue";
3
+ import { useElementSize, useMutationObserver, useResizeObserver, useScroll } from "@vueuse/core";
4
+ import { onMountedOrActivated } from "@gx-design-vue/pro-hooks";
5
+ //#region src/hooks/useFitPage.ts
6
+ function queryChildElements(card, prefixCls, targets) {
7
+ targets.toolbarEl.value = card.querySelector(`.${prefixCls}-list-toolbar`) ?? void 0;
8
+ targets.headerEl.value = card.querySelector(".ant-table-header") ?? void 0;
9
+ targets.pageEl.value = card.querySelector(".ant-table-pagination") ?? void 0;
10
+ targets.scrollEl.value = card.querySelector(".ant-table-body") ?? void 0;
11
+ targets.bodyInnerEl.value = card.querySelector(".ant-table-body > table") ?? void 0;
12
+ }
13
+ function getElementBlockMargin(el) {
14
+ if (!el) return 0;
15
+ const style = getComputedStyle(el);
16
+ return (Number.parseFloat(style.marginTop) || 0) + (Number.parseFloat(style.marginBottom) || 0);
17
+ }
18
+ function useFitPage(options) {
19
+ const { fitPage, cardEl, prefixCls } = options;
20
+ const barRef = ref();
21
+ const toolbarEl = ref();
22
+ const headerEl = ref();
23
+ const pageEl = ref();
24
+ const scrollEl = ref();
25
+ const bodyInnerEl = ref();
26
+ const childRefs = {
27
+ toolbarEl,
28
+ headerEl,
29
+ pageEl,
30
+ scrollEl,
31
+ bodyInnerEl
32
+ };
33
+ const { height: cardHeight } = useElementSize(cardEl);
34
+ const { height: toolbarHeight } = useElementSize(toolbarEl);
35
+ const { height: headerHeight } = useElementSize(headerEl);
36
+ const { height: pageHeight } = useElementSize(pageEl);
37
+ const { height: bodyContentHeight } = useElementSize(bodyInnerEl);
38
+ useMutationObserver(cardEl, () => {
39
+ if (cardEl.value) queryChildElements(cardEl.value, prefixCls.value, childRefs);
40
+ }, {
41
+ childList: true,
42
+ subtree: true
43
+ });
44
+ onMountedOrActivated(() => {
45
+ if (cardEl.value) queryChildElements(cardEl.value, prefixCls.value, childRefs);
46
+ });
47
+ const toolbarMargin = computed(() => getElementBlockMargin(toolbarEl.value));
48
+ const pageMargin = computed(() => {
49
+ return getElementBlockMargin(pageEl.value);
50
+ });
51
+ const scrollY = computed(() => {
52
+ if (!cardEl.value || !fitPage.value) return 0;
53
+ const tableHeight = cardHeight.value - toolbarHeight.value - toolbarMargin.value - headerHeight.value - pageHeight.value - pageMargin.value;
54
+ return Math.max(0, tableHeight);
55
+ });
56
+ const overflowHidden = computed(() => {
57
+ if (!scrollY.value || !fitPage.value) return false;
58
+ return bodyContentHeight.value <= scrollY.value;
59
+ });
60
+ const fullPageClass = computed(() => {
61
+ return fitPage.value ? `${prefixCls.value}-full-page` : "";
62
+ });
63
+ watchEffect(() => {
64
+ if (!scrollEl.value) return;
65
+ if (fitPage.value && scrollY.value > 0) scrollEl.value.style.height = `${scrollY.value}px`;
66
+ else scrollEl.value.style.height = "";
67
+ });
68
+ useScroll(scrollEl, { onScroll: () => {
69
+ if (scrollEl.value) barRef.value?.handleScroll(scrollEl.value);
70
+ } });
71
+ useResizeObserver(scrollEl, () => {
72
+ barRef.value?.update();
73
+ });
74
+ useProvideScrollBarContext({
75
+ className: `${prefixCls.value}-scroll`,
76
+ tableHeaderHeight: headerHeight,
77
+ tableScrollYHeight: scrollY,
78
+ scrollbarElement: cardEl,
79
+ wrapElement: scrollEl
80
+ });
81
+ return {
82
+ scrollY,
83
+ overflowHidden,
84
+ fullPageClass,
85
+ scrollEl,
86
+ barRef
87
+ };
88
+ }
89
+ //#endregion
90
+ export { useFitPage };
@@ -0,0 +1,21 @@
1
+ import { ComputedRef, Ref } from "vue";
2
+
3
+ //#region src/hooks/useKeepAliveReload.d.ts
4
+ interface UseKeepAliveReloadOptions {
5
+ enabled: ComputedRef<boolean>;
6
+ reload: () => void;
7
+ }
8
+ interface UseKeepAliveReloadReturn {
9
+ hasActivated: Ref<boolean>;
10
+ }
11
+ /**
12
+ * 安全的 onActivated 包装:无组件实例时直接执行回调。
13
+ */
14
+ declare function tryOnActivated(callback: () => void): void;
15
+ /**
16
+ * Keep-alive 页面重新进入时触发数据请求。
17
+ * 首次激活仅标记状态,后续激活且 enabled 为 true 时调用 reload。
18
+ */
19
+ declare function useKeepAliveReload(options: UseKeepAliveReloadOptions): UseKeepAliveReloadReturn;
20
+ //#endregion
21
+ export { UseKeepAliveReloadOptions, UseKeepAliveReloadReturn, tryOnActivated, useKeepAliveReload };
@@ -0,0 +1,24 @@
1
+ import { getCurrentInstance, nextTick, onActivated, ref } from "vue";
2
+ //#region src/hooks/useKeepAliveReload.ts
3
+ /**
4
+ * 安全的 onActivated 包装:无组件实例时直接执行回调。
5
+ */
6
+ function tryOnActivated(callback) {
7
+ if (getCurrentInstance()) onActivated(callback);
8
+ else nextTick(callback);
9
+ }
10
+ /**
11
+ * Keep-alive 页面重新进入时触发数据请求。
12
+ * 首次激活仅标记状态,后续激活且 enabled 为 true 时调用 reload。
13
+ */
14
+ function useKeepAliveReload(options) {
15
+ const hasActivated = ref(false);
16
+ tryOnActivated(() => {
17
+ if (hasActivated.value) {
18
+ if (options.enabled.value) options.reload();
19
+ } else hasActivated.value = true;
20
+ });
21
+ return { hasActivated };
22
+ }
23
+ //#endregion
24
+ export { tryOnActivated, useKeepAliveReload };
@@ -1,10 +1,21 @@
1
- import { BaseTableProps } from "../props.js";
2
- import { Ref } from "vue";
1
+ import { ComputedRef, Ref } from "vue";
3
2
 
4
3
  //#region src/hooks/useLoading.d.ts
5
- declare function useLoading(options: {
6
- loading: Ref<BaseTableProps['loading']>;
7
- onChange: (value: BaseTableProps['loading']) => void;
8
- }): [Ref<boolean>, (value: boolean) => void];
4
+ interface UseLoadingOptions {
5
+ loading: ComputedRef<boolean | {
6
+ spinning?: boolean;
7
+ } | undefined>;
8
+ onChange?: (loading: boolean) => void;
9
+ }
10
+ interface UseLoadingReturn {
11
+ loading: Ref<boolean>;
12
+ setLoading: (value: boolean) => void;
13
+ }
14
+ /**
15
+ * Table loading 状态管理。
16
+ * 支持 boolean 和 SpinProps 对象两种 loading prop 形式,
17
+ * 内部始终维护 boolean 状态,外部 prop 变化时自动同步。
18
+ */
19
+ declare function useLoading(options: UseLoadingOptions): UseLoadingReturn;
9
20
  //#endregion
10
- export { useLoading };
21
+ export { UseLoadingOptions, UseLoadingReturn, useLoading };
@@ -1,18 +1,36 @@
1
1
  import { ref, watch } from "vue";
2
2
  import { isBoolean, isObject } from "@gx-design-vue/pro-utils";
3
3
  //#region src/hooks/useLoading.ts
4
+ /** 从 boolean 或 SpinProps 对象中提取 spinning 状态 */
5
+ function toSpinning(value, fallback = false) {
6
+ if (isBoolean(value)) return value;
7
+ if (isObject(value)) return value.spinning ?? fallback;
8
+ return fallback;
9
+ }
10
+ /**
11
+ * Table loading 状态管理。
12
+ * 支持 boolean 和 SpinProps 对象两种 loading prop 形式,
13
+ * 内部始终维护 boolean 状态,外部 prop 变化时自动同步。
14
+ */
4
15
  function useLoading(options) {
5
- const loading = ref(getStatus(options.loading.value));
6
- watch(() => options.loading.value, (val) => {
7
- loading.value = getStatus(val, loading.value);
16
+ const loading = ref(toSpinning(options.loading.value));
17
+ watch(() => options.loading.value, (propValue) => {
18
+ const next = toSpinning(propValue, loading.value);
19
+ if (next !== loading.value) {
20
+ loading.value = next;
21
+ options.onChange?.(next);
22
+ }
8
23
  });
9
- function getStatus(value, defaultValue = false) {
10
- return isBoolean(value) ? value : isObject(value) ? value?.spinning ?? defaultValue : defaultValue;
11
- }
12
24
  function setLoading(value) {
13
- loading.value = value;
25
+ if (loading.value !== value) {
26
+ loading.value = value;
27
+ options.onChange?.(value);
28
+ }
14
29
  }
15
- return [loading, setLoading];
30
+ return {
31
+ loading,
32
+ setLoading
33
+ };
16
34
  }
17
35
  //#endregion
18
36
  export { useLoading };
@@ -1,18 +1,21 @@
1
- import { PageItemRender } from "../types/SlotsTypings.js";
2
- import { PageState, ProTablePagination, ProTableProps } from "../types/TableTypings.js";
1
+ import { PageState, ProTablePagination, ProTablePaginationConfig } from "../interface.js";
3
2
  import { Ref } from "vue";
4
3
 
5
4
  //#region src/hooks/usePagination.d.ts
5
+ /**
6
+ * 分页状态管理。
7
+ * 合并用户分页配置与默认值,分离 UI 分页展示与请求分页参数。
8
+ * setPagination 只同步 current/pageSize/total 到 requestPagination,避免 UI 字段污染请求参数。
9
+ */
6
10
  declare function usePagination({
7
- pagination,
8
- pageItemRender
11
+ pagination
9
12
  }: {
10
- pagination: Ref<ProTableProps['pagination']>;
11
- pageItemRender: PageItemRender;
13
+ pagination: Ref<ProTablePagination | undefined>;
12
14
  }): {
13
15
  paginationInfo: Ref<ProTablePagination | false>;
16
+ paginationAlign: Ref<'start' | 'center' | 'end'>;
14
17
  requestPagination: PageState;
15
- setPagination: (info: Partial<ProTablePagination>) => void;
18
+ setPagination: (info: Partial<ProTablePaginationConfig>) => void;
16
19
  };
17
20
  //#endregion
18
21
  export { usePagination };