Werheng Zhang
2024-03-27 05030ee9843d49f864576cd39b6e7f78a880527c
提交 | 用户 | age
9c2f3f 1 import type { BasicTableProps, FetchParams, SorterResult } from '../types/table';
a1ffb6 2 import type { PaginationProps } from '../types/pagination';
601368 3 import {
V 4   ref,
5   unref,
6   ComputedRef,
7   computed,
8   onMounted,
9   watch,
10   reactive,
11   Ref,
12   watchEffect,
13 } from 'vue';
fa1836 14 import { useTimeoutFn } from '@vben/hooks';
bab28a 15 import { buildUUID } from '@/utils/uuid';
X 16 import { isFunction, isBoolean, isObject } from '@/utils/is';
59b309 17 import { get, cloneDeep, merge } from 'lodash-es';
354904 18 import { FETCH_SETTING, ROW_KEY, PAGE_SIZE } from '../const';
e23e33 19 import { parseRowKeyValue } from '../helper';
X 20 import type { Key } from 'ant-design-vue/lib/table/interface';
faf3f4 21
22 interface ActionType {
354904 23   getPaginationInfo: ComputedRef<boolean | PaginationProps>;
faf3f4 24   setPagination: (info: Partial<PaginationProps>) => void;
354904 25   setLoading: (loading: boolean) => void;
V 26   getFieldsValue: () => Recordable;
9c2f3f 27   clearSelectedRowKeys: () => void;
601368 28   tableData: Ref<Recordable[]>;
9c2f3f 29 }
V 30
31 interface SearchState {
32   sortInfo: Recordable;
33   filterInfo: Record<string, string[]>;
faf3f4 34 }
35 export function useDataSource(
354904 36   propsRef: ComputedRef<BasicTableProps>,
9c2f3f 37   {
V 38     getPaginationInfo,
39     setPagination,
40     setLoading,
41     getFieldsValue,
42     clearSelectedRowKeys,
601368 43     tableData,
9c2f3f 44   }: ActionType,
56a966 45   emit: EmitType,
faf3f4 46 ) {
9c2f3f 47   const searchState = reactive<SearchState>({
V 48     sortInfo: {},
49     filterInfo: {},
50   });
354904 51   const dataSourceRef = ref<Recordable[]>([]);
f3cf16 52   const rawDataSourceRef = ref<Recordable>({});
faf3f4 53
601368 54   watchEffect(() => {
V 55     tableData.value = unref(dataSourceRef);
56   });
57
da76f3 58   watch(
V 59     () => unref(propsRef).dataSource,
60     () => {
61       const { dataSource, api } = unref(propsRef);
62       !api && dataSource && (dataSourceRef.value = dataSource);
63     },
64     {
65       immediate: true,
56a966 66     },
da76f3 67   );
9c2f3f 68
V 69   function handleTableChange(
70     pagination: PaginationProps,
71     filters: Partial<Recordable<string[]>>,
56a966 72     sorter: SorterResult,
9c2f3f 73   ) {
V 74     const { clearSelectOnPageChange, sortFn, filterFn } = unref(propsRef);
75     if (clearSelectOnPageChange) {
76       clearSelectedRowKeys();
77     }
78     setPagination(pagination);
79
80     const params: Recordable = {};
81     if (sorter && isFunction(sortFn)) {
82       const sortInfo = sortFn(sorter);
83       searchState.sortInfo = sortInfo;
84       params.sortInfo = sortInfo;
85     }
86
87     if (filters && isFunction(filterFn)) {
88       const filterInfo = filterFn(filters);
89       searchState.filterInfo = filterInfo;
90       params.filterInfo = filterInfo;
91     }
92     fetch(params);
93   }
faf3f4 94
95   function setTableKey(items: any[]) {
354904 96     if (!items || !Array.isArray(items)) return;
faf3f4 97     items.forEach((item) => {
98       if (!item[ROW_KEY]) {
99         item[ROW_KEY] = buildUUID();
100       }
101       if (item.children && item.children.length) {
102         setTableKey(item.children);
103       }
104     });
105   }
354904 106
faf3f4 107   const getAutoCreateKey = computed(() => {
108     return unref(propsRef).autoCreateKey && !unref(propsRef).rowKey;
354904 109   });
V 110
111   const getRowKey = computed(() => {
112     const { rowKey } = unref(propsRef);
113     return unref(getAutoCreateKey) ? ROW_KEY : rowKey;
faf3f4 114   });
115
116   const getDataSourceRef = computed(() => {
117     const dataSource = unref(dataSourceRef);
118     if (!dataSource || dataSource.length === 0) {
e78af6 119       return unref(dataSourceRef);
faf3f4 120     }
121     if (unref(getAutoCreateKey)) {
122       const firstItem = dataSource[0];
123       const lastItem = dataSource[dataSource.length - 1];
124
125       if (firstItem && lastItem) {
126         if (!firstItem[ROW_KEY] || !lastItem[ROW_KEY]) {
31ff05 127           const data = cloneDeep(unref(dataSourceRef));
V 128           data.forEach((item) => {
faf3f4 129             if (!item[ROW_KEY]) {
130               item[ROW_KEY] = buildUUID();
131             }
132             if (item.children && item.children.length) {
133               setTableKey(item.children);
134             }
135           });
31ff05 136           dataSourceRef.value = data;
faf3f4 137         }
138       }
139     }
140     return unref(dataSourceRef);
141   });
142
e23e33 143   async function updateTableData(index: number, key: Key, value: any) {
9c2f3f 144     const record = dataSourceRef.value[index];
V 145     if (record) {
146       dataSourceRef.value[index][key] = value;
147     }
148     return dataSourceRef.value[index];
149   }
150
e23e33 151   function updateTableDataRecord(keyValue: Key, record: Recordable): Recordable | undefined {
X 152     const row = findTableDataRecord(keyValue);
72f953 153
8e4f48 154     if (row) {
155       for (const field in row) {
156         if (Reflect.has(record, field)) row[field] = record[field];
157       }
158       return row;
159     }
72f953 160   }
LC( 161
e23e33 162   function deleteTableDataRecord(keyValues: Key | Key[]) {
59a908 163     if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
e23e33 164     const delKeyValues = !Array.isArray(keyValues) ? [keyValues] : keyValues;
9435b4 165
e23e33 166     function deleteRow(data, keyValue) {
X 167       const row: { index: number; data: [] } = findRow(data, keyValue);
9435b4 168       if (row === null || row.index === -1) {
M 169         return;
456a66 170       }
9435b4 171       row.data.splice(row.index, 1);
M 172
e23e33 173       function findRow(data, keyValue) {
9435b4 174         if (data === null || data === undefined) {
M 175           return null;
456a66 176         }
9435b4 177         for (let i = 0; i < data.length; i++) {
M 178           const row = data[i];
e23e33 179           if (parseRowKeyValue(unref(getRowKey), row) === keyValue) {
9435b4 180             return { index: i, data };
M 181           }
182           if (row.children?.length > 0) {
e23e33 183             const result = findRow(row.children, keyValue);
9435b4 184             if (result != null) {
M 185               return result;
186             }
187           }
188         }
189         return null;
190       }
191     }
192
e23e33 193     for (const keyValue of delKeyValues) {
X 194       deleteRow(dataSourceRef.value, keyValue);
195       deleteRow(unref(propsRef).dataSource, keyValue);
59a908 196     }
F 197     setPagination({
198       total: unref(propsRef).dataSource?.length,
199     });
200   }
201
31042d 202   function insertTableDataRecord(
V 203     record: Recordable | Recordable[],
d3fd22 204     index?: number,
bb1fee 205   ): Recordable[] | undefined {
de8ea5 206     // if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
59a908 207     index = index ?? dataSourceRef.value?.length;
31042d 208     const _record = isObject(record) ? [record as Recordable] : (record as Recordable[]);
V 209     unref(dataSourceRef).splice(index, 0, ..._record);
de8ea5 210     return unref(dataSourceRef);
59a908 211   }
F 212
e23e33 213   function findTableDataRecord(keyValue: Key) {
05030e 214     if (!dataSourceRef.value || dataSourceRef.value.length === 0) return;
72f953 215     const { childrenColumnName = 'children' } = unref(propsRef);
LC( 216
217     const findRow = (array: any[]) => {
218       let ret;
219       array.some(function iter(r) {
e23e33 220         if (parseRowKeyValue(unref(getRowKey), r) === keyValue) {
X 221           ret = r;
222           return true;
72f953 223         }
LC( 224         return r[childrenColumnName] && r[childrenColumnName].some(iter);
225       });
226       return ret;
227     };
228
229     return findRow(dataSourceRef.value);
8e4f48 230   }
231
faf3f4 232   async function fetch(opt?: FetchParams) {
acea18 233     const {
V 234       api,
235       searchInfo,
236       defSort,
237       fetchSetting,
238       beforeFetch,
239       afterFetch,
240       useSearchForm,
241       pagination,
242     } = unref(propsRef);
661db0 243     if (!api || !isFunction(api)) return;
faf3f4 244     try {
354904 245       setLoading(true);
e90646 246       const { pageField, sizeField, listField, totalField } = Object.assign(
b4a3f9 247         {},
e90646 248         FETCH_SETTING,
56a966 249         fetchSetting,
e90646 250       );
354904 251       let pageParams: Recordable = {};
V 252
253       const { current = 1, pageSize = PAGE_SIZE } = unref(getPaginationInfo) as PaginationProps;
254
745fcf 255       if ((isBoolean(pagination) && !pagination) || isBoolean(getPaginationInfo)) {
faf3f4 256         pageParams = {};
257       } else {
e034d1 258         pageParams[pageField] = (opt && opt.page) || current;
faf3f4 259         pageParams[sizeField] = pageSize;
260       }
261
9c2f3f 262       const { sortInfo = {}, filterInfo } = searchState;
V 263
59b309 264       let params: Recordable = merge(
H 265         pageParams,
266         useSearchForm ? getFieldsValue() : {},
267         searchInfo,
268         opt?.searchInfo ?? {},
269         defSort,
270         sortInfo,
271         filterInfo,
272         opt?.sortInfo ?? {},
273         opt?.filterInfo ?? {},
274       );
faf3f4 275       if (beforeFetch && isFunction(beforeFetch)) {
749ba5 276         params = (await beforeFetch(params)) || params;
faf3f4 277       }
278
279       const res = await api(params);
f3cf16 280       rawDataSourceRef.value = res;
354904 281
V 282       const isArrayResult = Array.isArray(res);
283
284       let resultItems: Recordable[] = isArrayResult ? res : get(res, listField);
929141 285       const resultTotal: number = isArrayResult ? res.length : get(res, totalField);
354904 286
877311 287       // 假如数据变少,导致总页数变少并小于当前选中页码,通过getPaginationRef获取到的页码是不正确的,需获取正确的页码再次执行
9090ce 288       if (Number(resultTotal)) {
0aeec5 289         const currentTotalPage = Math.ceil(resultTotal / pageSize);
V 290         if (current > currentTotalPage) {
291           setPagination({
292             current: currentTotalPage,
293           });
7b6d5e 294           return await fetch(opt);
0aeec5 295         }
877311 296       }
354904 297
faf3f4 298       if (afterFetch && isFunction(afterFetch)) {
749ba5 299         resultItems = (await afterFetch(resultItems)) || resultItems;
faf3f4 300       }
301       dataSourceRef.value = resultItems;
302       setPagination({
303         total: resultTotal || 0,
304       });
305       if (opt && opt.page) {
306         setPagination({
307           current: opt.page || 1,
308         });
309       }
310       emit('fetch-success', {
311         items: unref(resultItems),
312         total: resultTotal,
313       });
7b6d5e 314       return resultItems;
faf3f4 315     } catch (error) {
316       emit('fetch-error', error);
317       dataSourceRef.value = [];
318       setPagination({
319         total: 0,
320       });
321     } finally {
354904 322       setLoading(false);
faf3f4 323     }
324   }
325
354904 326   function setTableData<T = Recordable>(values: T[]) {
d3fd22 327     dataSourceRef.value = values as Recordable[];
faf3f4 328   }
354904 329
V 330   function getDataSource<T = Recordable>() {
331     return getDataSourceRef.value as T[];
332   }
333
f3cf16 334   function getRawDataSource<T = Recordable>() {
J 335     return rawDataSourceRef.value as T;
336   }
337
354904 338   async function reload(opt?: FetchParams) {
7b6d5e 339     return await fetch(opt);
354904 340   }
V 341
faf3f4 342   onMounted(() => {
d9b196 343     useTimeoutFn(() => {
faf3f4 344       unref(propsRef).immediate && fetch();
97180e 345     }, 16);
faf3f4 346   });
347
354904 348   return {
V 349     getDataSourceRef,
350     getDataSource,
f3cf16 351     getRawDataSource,
354904 352     getRowKey,
V 353     setTableData,
354     getAutoCreateKey,
355     fetch,
356     reload,
9c2f3f 357     updateTableData,
8e4f48 358     updateTableDataRecord,
59a908 359     deleteTableDataRecord,
F 360     insertTableDataRecord,
72f953 361     findTableDataRecord,
9c2f3f 362     handleTableChange,
354904 363   };
faf3f4 364 }