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