@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,52 @@
|
|
|
1
|
+
import { DragHandle } from "../components/Drag/Handle.js";
|
|
2
|
+
import { computed, createVNode } from "vue";
|
|
3
|
+
import { createUUIDFactory } from "@gx-design-vue/pro-utils";
|
|
4
|
+
//#region src/hooks/useDragHandleColumn.tsx
|
|
5
|
+
/** 把手列内部标记 key */
|
|
6
|
+
const DRAG_HANDLE_COLUMN_KEY = "__drag_handle__";
|
|
7
|
+
/**
|
|
8
|
+
* 创建行拖拽把手列配置。
|
|
9
|
+
*
|
|
10
|
+
* 把手列固定在最前面(比 indexColumn 序号列更靠前),包含 DragHandle 组件。
|
|
11
|
+
* 通过 `disabled(record)` 判断每行是否禁用拖拽。
|
|
12
|
+
*/
|
|
13
|
+
function createDragHandleColumn(options, prefixCls, cssVarCls) {
|
|
14
|
+
return {
|
|
15
|
+
key: DRAG_HANDLE_COLUMN_KEY,
|
|
16
|
+
dataIndex: DRAG_HANDLE_COLUMN_KEY,
|
|
17
|
+
title: "排序",
|
|
18
|
+
width: options.width ?? 40,
|
|
19
|
+
align: options.align ?? "center",
|
|
20
|
+
fixed: options.fixed ?? "start",
|
|
21
|
+
uuid: createUUIDFactory().uuid(15),
|
|
22
|
+
render: (_value, record, index) => {
|
|
23
|
+
const disabled = options.disabled?.(record) ?? false;
|
|
24
|
+
return createVNode(DragHandle, {
|
|
25
|
+
"handleRender": options.handleRender,
|
|
26
|
+
"record": record,
|
|
27
|
+
"index": index,
|
|
28
|
+
"disabled": disabled,
|
|
29
|
+
"cssVarCls": cssVarCls,
|
|
30
|
+
"prefixCls": prefixCls
|
|
31
|
+
}, null);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 在列首注入行拖拽把手列。
|
|
37
|
+
*
|
|
38
|
+
* 纯函数实现(对标 `applyIndexColumn`),在 `useColumns` 的 `cacheColumns` computed 中、
|
|
39
|
+
* `applyIndexColumn` 之前调用,确保把手列比序号列更靠前。
|
|
40
|
+
*/
|
|
41
|
+
function applyDragHandleColumn(columns, rowDraggable, prefixCls, cssVarCls) {
|
|
42
|
+
if (!rowDraggable || columns.length === 0) return columns;
|
|
43
|
+
if (columns.some((column) => column.dataIndex === "__drag_handle__")) return columns;
|
|
44
|
+
return [createDragHandleColumn(typeof rowDraggable === "object" ? rowDraggable : {}, prefixCls, cssVarCls), ...columns];
|
|
45
|
+
}
|
|
46
|
+
function useDragHandleColumn(options) {
|
|
47
|
+
return { dragColumns: computed(() => {
|
|
48
|
+
return applyDragHandleColumn(options.columns.value, options.rowDraggable.value, options.prefixCls.value, options.cssVarCls.value);
|
|
49
|
+
}) };
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { DRAG_HANDLE_COLUMN_KEY, applyDragHandleColumn, useDragHandleColumn };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Ref } from "vue";
|
|
2
|
+
|
|
3
|
+
//#region src/hooks/useEllipsis.d.ts
|
|
4
|
+
interface UseEllipsisReturn {
|
|
5
|
+
/** 当前文本在给定宽度/行数下是否溢出 */
|
|
6
|
+
isOverflow: Ref<boolean>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 基于 @chenglou/pretext 的溢出判断。
|
|
10
|
+
*
|
|
11
|
+
* - prepare(text, font) 一次性预处理(命中 pretext 内部缓存),仅随 text/font 变化重跑;
|
|
12
|
+
* - layout(prepared, width, lineHeight) 纯算力预算行数,随列宽/行数变化重算(符合 pretext 性能模型);
|
|
13
|
+
* - 宽度取自 ResizeObserver 的 contentRect.width(已扣除 padding);
|
|
14
|
+
* - font/lineHeight 于 mount 时通过 getComputedStyle 读取,保证与实际 CSS 渲染一致。
|
|
15
|
+
*
|
|
16
|
+
* lineCount > 期望行数 即判定为溢出。
|
|
17
|
+
*/
|
|
18
|
+
declare function useEllipsis(textRef: Ref<string>, linesRef: Ref<number>, cellElRef: Ref<HTMLElement | undefined>): UseEllipsisReturn;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { UseEllipsisReturn, useEllipsis };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { computed, onMounted, ref } from "vue";
|
|
2
|
+
import { useResizeObserver } from "@vueuse/core";
|
|
3
|
+
import { layout, prepare } from "@chenglou/pretext";
|
|
4
|
+
//#region src/hooks/useEllipsis.ts
|
|
5
|
+
/**
|
|
6
|
+
* 基于 @chenglou/pretext 的溢出判断。
|
|
7
|
+
*
|
|
8
|
+
* - prepare(text, font) 一次性预处理(命中 pretext 内部缓存),仅随 text/font 变化重跑;
|
|
9
|
+
* - layout(prepared, width, lineHeight) 纯算力预算行数,随列宽/行数变化重算(符合 pretext 性能模型);
|
|
10
|
+
* - 宽度取自 ResizeObserver 的 contentRect.width(已扣除 padding);
|
|
11
|
+
* - font/lineHeight 于 mount 时通过 getComputedStyle 读取,保证与实际 CSS 渲染一致。
|
|
12
|
+
*
|
|
13
|
+
* lineCount > 期望行数 即判定为溢出。
|
|
14
|
+
*/
|
|
15
|
+
function useEllipsis(textRef, linesRef, cellElRef) {
|
|
16
|
+
const contentWidth = ref(0);
|
|
17
|
+
const fontInfo = ref({
|
|
18
|
+
font: "14px sans-serif",
|
|
19
|
+
lineHeight: 22
|
|
20
|
+
});
|
|
21
|
+
useResizeObserver(cellElRef, (entries) => {
|
|
22
|
+
const entry = entries[0];
|
|
23
|
+
if (entry) contentWidth.value = entry.contentRect.width;
|
|
24
|
+
});
|
|
25
|
+
onMounted(() => {
|
|
26
|
+
const el = cellElRef.value;
|
|
27
|
+
if (!el) return;
|
|
28
|
+
const computedStyle = getComputedStyle(el);
|
|
29
|
+
const fontSize = Number.parseFloat(computedStyle.fontSize) || 14;
|
|
30
|
+
let lineHeight = Number.parseFloat(computedStyle.lineHeight);
|
|
31
|
+
if (!lineHeight || Number.isNaN(lineHeight)) lineHeight = fontSize * 1.5715;
|
|
32
|
+
fontInfo.value = {
|
|
33
|
+
font: `${fontSize}px ${computedStyle.fontFamily}`,
|
|
34
|
+
lineHeight
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
const prepared = computed(() => {
|
|
38
|
+
const text = textRef.value;
|
|
39
|
+
if (!text) return null;
|
|
40
|
+
return prepare(text, fontInfo.value.font);
|
|
41
|
+
});
|
|
42
|
+
return { isOverflow: computed(() => {
|
|
43
|
+
const preparedText = prepared.value;
|
|
44
|
+
const width = contentWidth.value;
|
|
45
|
+
if (!preparedText || width <= 0) return false;
|
|
46
|
+
const { lineCount } = layout(preparedText, width, fontInfo.value.lineHeight);
|
|
47
|
+
return lineCount > linesRef.value;
|
|
48
|
+
}) };
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { useEllipsis };
|
|
@@ -1,77 +1,54 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { PageState, ProTableFetchParams, ProTablePagination, ProTablePaginationConfig, ProTableProps } from "../types/TableTypings.js";
|
|
1
|
+
import { BeforeSearchSubmit, OperateRowProps, PageState, ProColumnType, ProTableFetchParams, ProTablePagination, ProTablePaginationConfig, RequestFunction } from "../interface.js";
|
|
3
2
|
import { ComputedRef, Reactive, Ref } from "vue";
|
|
4
|
-
import {
|
|
5
|
-
import { FilterValue, SorterResult, TableCurrentDataSource } from "ant-design-vue/es/table/interface";
|
|
3
|
+
import { FilterValue, SorterResult, TableCurrentDataSource } from "antdv-next/dist/table/interface";
|
|
6
4
|
|
|
7
5
|
//#region src/hooks/useFetchData.d.ts
|
|
8
|
-
interface
|
|
9
|
-
|
|
6
|
+
interface FetchDataConfig<T = any, R = any> {
|
|
7
|
+
rowKey: ComputedRef<string>;
|
|
8
|
+
polling: ComputedRef<boolean>;
|
|
9
|
+
pollingTime: ComputedRef<number>;
|
|
10
|
+
request: RequestFunction<T, R> | undefined;
|
|
11
|
+
postData: ((data: T[]) => T[]) | undefined;
|
|
12
|
+
dataSource: ComputedRef<T[] | undefined>;
|
|
13
|
+
immediate: ComputedRef<boolean>;
|
|
14
|
+
waitRequest: ComputedRef<boolean>;
|
|
15
|
+
autoRequest: ComputedRef<boolean>;
|
|
16
|
+
debounceTime: ComputedRef<number>;
|
|
17
|
+
params: ComputedRef<R | undefined>;
|
|
18
|
+
defaultFormSearch: Ref<Record<string, any>>;
|
|
19
|
+
formParamKeys: ComputedRef<string[]>;
|
|
20
|
+
getFormSearch: () => Record<string, any>;
|
|
21
|
+
onLoadingChange: ((loading: boolean) => any) | undefined;
|
|
22
|
+
onRequestError: ((e: Error) => void) | undefined;
|
|
23
|
+
onBeforeSearchSubmit: BeforeSearchSubmit<R> | undefined;
|
|
24
|
+
}
|
|
25
|
+
interface FetchDataAction<T = any> {
|
|
10
26
|
pageInfo: Reactive<PageState>;
|
|
11
27
|
paginationInfo: Ref<ProTablePagination | false>;
|
|
12
|
-
setPagination: (info: Partial<
|
|
28
|
+
setPagination: (info: Partial<ProTablePaginationConfig>) => void;
|
|
13
29
|
setLoading: (loading: boolean) => void;
|
|
14
|
-
setColumns: (
|
|
15
|
-
removeRowKeys: (
|
|
30
|
+
setColumns: (columns: ProColumnType<any>[]) => void;
|
|
31
|
+
removeRowKeys: (keys: (string | number)[]) => void;
|
|
16
32
|
syncSelectedRows: (dataList: any[]) => void;
|
|
17
|
-
columns: ComputedRef<
|
|
18
|
-
defaultFormSearch: Ref<RecordType>;
|
|
19
|
-
params: Ref<ProTableProps['params']>;
|
|
20
|
-
onRequestError: ProTableProps['onRequestError'];
|
|
21
|
-
onBeforeSearchSubmit: ProTableProps['onBeforeSearchSubmit'];
|
|
22
|
-
hasCustomRender: ComputedRef<boolean>;
|
|
23
|
-
}
|
|
24
|
-
interface ConfigFetchData {
|
|
25
|
-
rowKey: ComputedRef<ProTableProps['rowKey']>;
|
|
26
|
-
polling: ComputedRef<ProTableProps['polling']>;
|
|
27
|
-
request: ProTableProps['request'];
|
|
28
|
-
postData: ProTableProps['postData'];
|
|
29
|
-
waitRequest: Ref<ProTableProps['waitRequest']>;
|
|
30
|
-
debounceTime: ComputedRef<ProTableProps['debounceTime']>;
|
|
31
|
-
dataSource: ComputedRef<ProTableProps['dataSource']>;
|
|
32
|
-
autoRequest: ComputedRef<ProTableProps['autoRequest']>;
|
|
33
|
+
columns: ComputedRef<ProColumnType<T>[]>;
|
|
33
34
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}: ConfigFetchData, {
|
|
45
|
-
params,
|
|
46
|
-
columns,
|
|
47
|
-
setLoading,
|
|
48
|
-
setColumns,
|
|
49
|
-
removeRowKeys,
|
|
50
|
-
syncSelectedRows,
|
|
51
|
-
defaultFormSearch,
|
|
52
|
-
setPagination,
|
|
53
|
-
pageInfo,
|
|
54
|
-
paginationInfo,
|
|
55
|
-
onRequestError,
|
|
56
|
-
onBeforeSearchSubmit,
|
|
57
|
-
hasCustomRender
|
|
58
|
-
}: ActionType, emit: any): {
|
|
35
|
+
/**
|
|
36
|
+
* 核心请求引擎。
|
|
37
|
+
* 负责数据请求调度、分页状态、轮询、AbortController 中断、
|
|
38
|
+
* loading 管理、数据转换、行操作、排序/筛选变更。
|
|
39
|
+
*
|
|
40
|
+
* 调度模型:所有请求入口(run/reload/handleTableChange/params 变化等)
|
|
41
|
+
* 统一进入 dispatchFetch → debouncedFetch → fetchList。
|
|
42
|
+
* 通过 requestId + AbortController 双重保证旧响应不回写。
|
|
43
|
+
*/
|
|
44
|
+
declare function useFetchData(config: FetchDataConfig, action: FetchDataAction): {
|
|
59
45
|
dataSource: ComputedRef<any[]>;
|
|
60
46
|
isTreeDataRef: ComputedRef<boolean>;
|
|
61
|
-
setTableDataList: (list:
|
|
62
|
-
operateTableDataRow: (
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
value
|
|
67
|
-
}: {
|
|
68
|
-
row?: Partial<RecordType>;
|
|
69
|
-
key?: string;
|
|
70
|
-
value?: any;
|
|
71
|
-
type?: "update" | "push" | "delete" | "unshift";
|
|
72
|
-
}) => void;
|
|
73
|
-
handleTableChange: (pagination: ProTablePaginationConfig, filters?: Record<string, FilterValue | null>, sorter?: SorterResult | SorterResult[], extra?: TableCurrentDataSource) => void;
|
|
74
|
-
run: (info?: ProTableFetchParams) => Promise<void>;
|
|
47
|
+
setTableDataList: (list: any[]) => void;
|
|
48
|
+
operateTableDataRow: (props: OperateRowProps) => void;
|
|
49
|
+
handleTableChange: (paginationConfig: ProTablePaginationConfig, filters?: Record<string, FilterValue | null>, sorter?: SorterResult | SorterResult[], extra?: TableCurrentDataSource) => void;
|
|
50
|
+
run: (info?: ProTableFetchParams) => void;
|
|
51
|
+
reload: (info?: ProTableFetchParams) => void;
|
|
75
52
|
};
|
|
76
53
|
//#endregion
|
|
77
|
-
export {
|
|
54
|
+
export { FetchDataAction, FetchDataConfig, useFetchData };
|
|
@@ -1,50 +1,85 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { omit } from "es-toolkit";
|
|
5
|
-
|
|
1
|
+
import { computed, onActivated, onDeactivated, onUnmounted, ref, toRaw, watch } from "vue";
|
|
2
|
+
import { createUUIDFactory, getSortIndex, handleCurrentPage, isArray, isFunction, isObject, merge } from "@gx-design-vue/pro-utils";
|
|
3
|
+
import { useDebounceFn } from "@vueuse/core";
|
|
6
4
|
//#region src/hooks/useFetchData.ts
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
autoRequest
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
function useFetchData({ rowKey, autoRequest, polling, request, postData, dataSource, waitRequest, debounceTime }, { params, columns, setLoading, setColumns, removeRowKeys, syncSelectedRows, defaultFormSearch, setPagination, pageInfo, paginationInfo, onRequestError, onBeforeSearchSubmit, hasCustomRender }, emit) {
|
|
24
|
-
const updateKey = ref("");
|
|
25
|
-
const umountRef = ref(false);
|
|
26
|
-
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, formParamKeys, getFormSearch, onLoadingChange, onRequestError, onBeforeSearchSubmit } = config;
|
|
17
|
+
const { pageInfo, paginationInfo, setPagination, setLoading, setColumns, removeRowKeys, syncSelectedRows, columns } = action;
|
|
27
18
|
const tableDataList = ref([]);
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
+
function omitFormParams(source) {
|
|
52
|
+
if (!source) return {};
|
|
53
|
+
const omittedKeys = new Set(formParamKeys.value);
|
|
54
|
+
const result = {};
|
|
55
|
+
for (const key of Object.keys(source)) if (!omittedKeys.has(key)) result[key] = source[key];
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
/** 写入表格数据并同步 sortIndex,无 request 时同步 dataSource total */
|
|
59
|
+
function setTableDataList(list) {
|
|
60
|
+
tableDataList.value = getSortIndex(toRaw(list), toRaw(pageInfo));
|
|
61
|
+
if (!request || !isFunction(request)) {
|
|
62
|
+
const total = list.length || 0;
|
|
63
|
+
if (total !== pageInfo.total) setPagination({ total });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** 执行单次请求,处理参数合并、AbortController、轮询调度、错误处理 */
|
|
67
|
+
async function fetchList(fetchParams = {}) {
|
|
68
|
+
const { pagination: fetchPagination = {}, filters = {}, sorter = {}, removeKeys = [], isPolling = false, extra } = fetchParams;
|
|
36
69
|
if (!request || !isFunction(request)) return dataSource.value || [];
|
|
37
|
-
if (!isPolling)
|
|
38
|
-
|
|
39
|
-
|
|
70
|
+
if (!isPolling) {
|
|
71
|
+
setLoading(true);
|
|
72
|
+
notifyLoading(true);
|
|
73
|
+
}
|
|
74
|
+
if (fetchPagination && Object.keys(fetchPagination).length) setPagination(fetchPagination);
|
|
40
75
|
try {
|
|
41
76
|
if (removeKeys.length) removeRowKeys(removeKeys);
|
|
42
|
-
const sorterList = isObject(sorter)
|
|
43
|
-
setColumns(
|
|
44
|
-
const
|
|
77
|
+
const sorterList = isObject(sorter) && Object.keys(sorter).length ? [sorter] : isArray(sorter) ? sorter : [];
|
|
78
|
+
if (setColumns && columns) setColumns(columns.value.map((columnItem) => {
|
|
79
|
+
const matchedSorter = sorterList.find((sorterItem) => (sorterItem?.columnKey || sorterItem?.field) === columnItem.dataIndex);
|
|
45
80
|
return {
|
|
46
|
-
...
|
|
47
|
-
sortOrder:
|
|
81
|
+
...columnItem,
|
|
82
|
+
sortOrder: matchedSorter?.order
|
|
48
83
|
};
|
|
49
84
|
}));
|
|
50
85
|
let actionParams = {
|
|
@@ -52,9 +87,10 @@ function useFetchData({ rowKey, autoRequest, polling, request, postData, dataSou
|
|
|
52
87
|
pageSize: pageInfo.pageSize,
|
|
53
88
|
current: handleCurrentPage(toRaw(pageInfo), removeKeys.length)
|
|
54
89
|
},
|
|
55
|
-
...
|
|
56
|
-
...
|
|
57
|
-
...
|
|
90
|
+
...toRaw(defaultFormSearch.value),
|
|
91
|
+
...getFormSearch(),
|
|
92
|
+
...omitFormParams(toRaw(params.value)),
|
|
93
|
+
...fetchParams.params || {}
|
|
58
94
|
};
|
|
59
95
|
if (onBeforeSearchSubmit && isFunction(onBeforeSearchSubmit)) actionParams = await onBeforeSearchSubmit({
|
|
60
96
|
params: actionParams,
|
|
@@ -62,98 +98,66 @@ function useFetchData({ rowKey, autoRequest, polling, request, postData, dataSou
|
|
|
62
98
|
filter: filters,
|
|
63
99
|
extra
|
|
64
100
|
});
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
101
|
+
const currentRequestId = `table_request_${createUUIDFactory().uuid(10)}`;
|
|
102
|
+
requestId.value = currentRequestId;
|
|
103
|
+
const controller = new AbortController();
|
|
104
|
+
abortController.value = controller;
|
|
105
|
+
const response = await request({
|
|
106
|
+
params: { ...actionParams },
|
|
70
107
|
sorter: sorterList,
|
|
71
108
|
filter: filters,
|
|
72
|
-
extra
|
|
109
|
+
extra,
|
|
110
|
+
signal: controller.signal
|
|
73
111
|
});
|
|
74
|
-
if (
|
|
112
|
+
if (requestId.value !== currentRequestId || controller.signal.aborted) return [];
|
|
75
113
|
if (response) {
|
|
76
114
|
const { success = true, data = [] } = response;
|
|
77
115
|
if (!success) return [];
|
|
78
|
-
responseData = typeof postData === "function" ?
|
|
79
|
-
|
|
80
|
-
const total = response.total || responseData?.length || 0;
|
|
116
|
+
const responseData = typeof postData === "function" ? postData(data) : data;
|
|
117
|
+
const total = response.total || responseData.length || 0;
|
|
81
118
|
if (total !== pageInfo.total) setPagination({ total });
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
} else return [];
|
|
119
|
+
setTableDataList(responseData);
|
|
120
|
+
syncSelectedRows(responseData);
|
|
121
|
+
schedulePolling(fetchParams);
|
|
122
|
+
return responseData;
|
|
123
|
+
}
|
|
124
|
+
return [];
|
|
89
125
|
} catch (e) {
|
|
90
|
-
if (
|
|
91
|
-
if (
|
|
92
|
-
|
|
126
|
+
if (e.name === "AbortError") return [];
|
|
127
|
+
if (onRequestError) {
|
|
128
|
+
if (tableDataList.value === void 0) setTableDataList([]);
|
|
129
|
+
onRequestError(e);
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
throw e;
|
|
93
133
|
} finally {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const fetchListDebounce = useDebounceFn_default(async (props = {}) => {
|
|
99
|
-
if (pollingSetTimeRef.value) clearTimeout(pollingSetTimeRef.value);
|
|
100
|
-
if (!request) return;
|
|
101
|
-
const abort = new AbortController();
|
|
102
|
-
abortRef.value = abort;
|
|
103
|
-
try {
|
|
104
|
-
const msg = await Promise.race([fetchList(props), new Promise((_, reject) => {
|
|
105
|
-
abortRef.value?.signal?.addEventListener?.("abort", () => {
|
|
106
|
-
reject("aborted");
|
|
107
|
-
fetchListDebounce.cancel();
|
|
108
|
-
requestFinally();
|
|
109
|
-
});
|
|
110
|
-
})]);
|
|
111
|
-
if (abort.signal.aborted) return;
|
|
112
|
-
const needPolling = runFunction(polling.value, msg);
|
|
113
|
-
if (needPolling && !umountRef.value) pollingSetTimeRef.value = setTimeout(() => {
|
|
114
|
-
fetchListDebounce.run({
|
|
115
|
-
...props,
|
|
116
|
-
isPolling: needPolling
|
|
117
|
-
});
|
|
118
|
-
}, Math.max(needPolling, 2e3));
|
|
119
|
-
return msg;
|
|
120
|
-
} catch (error) {
|
|
121
|
-
if (error === "aborted") return;
|
|
122
|
-
throw error;
|
|
134
|
+
if (!isPolling) {
|
|
135
|
+
setLoading(false);
|
|
136
|
+
notifyLoading(false);
|
|
137
|
+
}
|
|
123
138
|
}
|
|
124
|
-
}
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
umountRef.value = false;
|
|
132
|
-
});
|
|
139
|
+
}
|
|
140
|
+
const debouncedFetch = useDebounceFn((fetchParams) => fetchList(fetchParams), () => debounceTime.value ?? 10);
|
|
141
|
+
/** 统一请求调度入口:先 abort 上一个请求,再 debounce 执行 */
|
|
142
|
+
function dispatchFetch(fetchParams = {}) {
|
|
143
|
+
abortCurrent();
|
|
144
|
+
debouncedFetch(fetchParams);
|
|
145
|
+
}
|
|
133
146
|
onActivated(() => {
|
|
134
|
-
|
|
147
|
+
unmounted.value = false;
|
|
135
148
|
});
|
|
136
149
|
onUnmounted(() => {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
150
|
+
unmounted.value = true;
|
|
151
|
+
abortCurrent();
|
|
152
|
+
stopPolling();
|
|
140
153
|
});
|
|
141
154
|
onDeactivated(() => {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
155
|
+
unmounted.value = true;
|
|
156
|
+
abortCurrent();
|
|
157
|
+
stopPolling();
|
|
145
158
|
});
|
|
146
|
-
watch(() =>
|
|
147
|
-
if (
|
|
148
|
-
if (!polling.value) clearTimeout(pollingSetTimeRef.value);
|
|
149
|
-
else fetchListDebounce.run({ isPolling: true });
|
|
150
|
-
}, { immediate: true });
|
|
151
|
-
watch(() => waitRequest.value, () => {
|
|
152
|
-
if (waitRequest.value) setLoading(true);
|
|
153
|
-
else fetchListDebounce.run({ isPolling: false });
|
|
154
|
-
}, { immediate: true });
|
|
155
|
-
watch(() => dataSource.value, () => {
|
|
156
|
-
if (dataSource.value) setTableDataList(dataSource.value || []);
|
|
159
|
+
watch(() => dataSource.value, (source) => {
|
|
160
|
+
if (source && !isFunction(request)) setTableDataList(source);
|
|
157
161
|
}, {
|
|
158
162
|
deep: true,
|
|
159
163
|
immediate: true
|
|
@@ -162,59 +166,33 @@ function useFetchData({ rowKey, autoRequest, polling, request, postData, dataSou
|
|
|
162
166
|
if (waitRequest.value) return;
|
|
163
167
|
if (autoRequest.value) {
|
|
164
168
|
setPagination({ current: 1 });
|
|
165
|
-
|
|
169
|
+
dispatchFetch({ isPolling: false });
|
|
166
170
|
}
|
|
167
|
-
}, {
|
|
168
|
-
|
|
169
|
-
immediate: true
|
|
170
|
-
});
|
|
171
|
-
watch(() => defaultFormSearch.value, (val, old) => {
|
|
171
|
+
}, { deep: true });
|
|
172
|
+
watch(() => polling.value, () => {
|
|
172
173
|
if (waitRequest.value) return;
|
|
173
|
-
if (!
|
|
174
|
-
|
|
175
|
-
fetchRunData();
|
|
176
|
-
}
|
|
177
|
-
}, {
|
|
178
|
-
deep: true,
|
|
179
|
-
immediate: true
|
|
174
|
+
if (!polling.value) stopPolling();
|
|
175
|
+
else dispatchFetch({ isPolling: true });
|
|
180
176
|
});
|
|
181
|
-
|
|
182
|
-
if (
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
} else setTableDataList(dataSource.value || []);
|
|
188
|
-
}
|
|
189
|
-
const getDataSourceRef = computed(() => {
|
|
190
|
-
if (hasCustomRender.value) return unref(tableDataList);
|
|
191
|
-
const viewColumns = columns.value.filter((column) => column.show || column.show === void 0);
|
|
192
|
-
if (!unref(tableDataList) || !viewColumns || viewColumns.length === 0) return [];
|
|
193
|
-
return unref(tableDataList);
|
|
177
|
+
watch(() => waitRequest.value, (waiting) => {
|
|
178
|
+
if (waiting) {
|
|
179
|
+
setLoading(true);
|
|
180
|
+
notifyLoading(true);
|
|
181
|
+
} else if (immediate.value) dispatchFetch({ isPolling: false });
|
|
194
182
|
});
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
abortFetch();
|
|
201
|
-
fetchListDebounce.run({
|
|
202
|
-
pagination,
|
|
183
|
+
if (!waitRequest.value && immediate.value) dispatchFetch({ isPolling: false });
|
|
184
|
+
const isTreeDataRef = computed(() => tableDataList.value.some((item) => isArray(item.children) && item.children.length > 0));
|
|
185
|
+
function handleTableChange(paginationConfig, filters = {}, sorter = {}, extra) {
|
|
186
|
+
dispatchFetch({
|
|
187
|
+
pagination: paginationConfig,
|
|
203
188
|
filters,
|
|
204
189
|
sorter,
|
|
205
190
|
extra,
|
|
206
191
|
isPolling: false
|
|
207
192
|
});
|
|
208
193
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
tableDataList.value = newData;
|
|
212
|
-
if (!request || !isFunction(request)) {
|
|
213
|
-
const total = newData.length || 0;
|
|
214
|
-
if (total !== pageInfo.total) setPagination({ total });
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
const operateTableDataRow = (props) => {
|
|
194
|
+
/** 对表格数据行执行增删改操作(update/push/unshift/delete) */
|
|
195
|
+
function operateTableDataRow(props) {
|
|
218
196
|
const { key, row, value, type = "update" } = props;
|
|
219
197
|
const dataIndex = key ?? rowKey.value;
|
|
220
198
|
const recordValue = row?.[dataIndex] ?? value;
|
|
@@ -222,7 +200,7 @@ function useFetchData({ rowKey, autoRequest, polling, request, postData, dataSou
|
|
|
222
200
|
switch (type) {
|
|
223
201
|
case "update":
|
|
224
202
|
if (dataIndex && recordValue && row) tableDataList.value = tableDataList.value.map((item) => {
|
|
225
|
-
if (recordValue === item[dataIndex]) return
|
|
203
|
+
if (recordValue === item[dataIndex]) return merge({}, item, row);
|
|
226
204
|
return item;
|
|
227
205
|
});
|
|
228
206
|
break;
|
|
@@ -236,23 +214,29 @@ function useFetchData({ rowKey, autoRequest, polling, request, postData, dataSou
|
|
|
236
214
|
if (dataIndex) tableDataList.value = tableDataList.value.filter((item) => value !== item[dataIndex]);
|
|
237
215
|
break;
|
|
238
216
|
}
|
|
239
|
-
}
|
|
217
|
+
}
|
|
218
|
+
/** 手动触发请求,waitRequest=true 时跳过 */
|
|
219
|
+
function run(info) {
|
|
220
|
+
if (waitRequest.value) return;
|
|
221
|
+
if (request) dispatchFetch({
|
|
222
|
+
...info,
|
|
223
|
+
isPolling: false
|
|
224
|
+
});
|
|
225
|
+
else setTableDataList(dataSource.value || []);
|
|
226
|
+
}
|
|
227
|
+
/** reload 是 run 的别名 */
|
|
228
|
+
function reload(info) {
|
|
229
|
+
run(info);
|
|
230
|
+
}
|
|
240
231
|
return {
|
|
241
|
-
dataSource:
|
|
232
|
+
dataSource: computed(() => tableDataList.value.length ? tableDataList.value : EMPTY_ARRAY),
|
|
242
233
|
isTreeDataRef,
|
|
243
234
|
setTableDataList,
|
|
244
235
|
operateTableDataRow,
|
|
245
236
|
handleTableChange,
|
|
246
|
-
run
|
|
247
|
-
|
|
248
|
-
if (request) await fetchListDebounce.run({
|
|
249
|
-
...info,
|
|
250
|
-
isPolling: false
|
|
251
|
-
});
|
|
252
|
-
else emit("reload");
|
|
253
|
-
}
|
|
237
|
+
run,
|
|
238
|
+
reload
|
|
254
239
|
};
|
|
255
240
|
}
|
|
256
|
-
|
|
257
241
|
//#endregion
|
|
258
|
-
export {
|
|
242
|
+
export { useFetchData };
|