huangxiaomin
2023-09-27 9f6d61d02c6bee572ca5d6053339a1f965f570b9
提交 | 用户 | age
9c2f3f 1 import type { BasicColumn, BasicTableProps, CellFormat, GetColumnsParams } from '../types/table';
V 2 import type { PaginationProps } from '../types/pagination';
391da9 3 import type { ComputedRef } from 'vue';
4a4321 4 import { computed, Ref, ref, reactive, toRaw, unref, watch } from 'vue';
9c2f3f 5 import { renderEditCell } from '../components/editable';
5a3861 6 import { usePermission } from '/@/hooks/web/usePermission';
391da9 7 import { useI18n } from '/@/hooks/web/useI18n';
1214b7 8 import { isArray, isBoolean, isFunction, isMap, isString } from '/@/utils/is';
9 import { cloneDeep, isEqual } from 'lodash-es';
391da9 10 import { formatToDate } from '/@/utils/dateUtil';
1214b7 11 import { ACTION_COLUMN_FLAG, DEFAULT_ALIGN, INDEX_COLUMN_FLAG, PAGE_SIZE } from '../const';
354904 12
V 13 function handleItem(item: BasicColumn, ellipsis: boolean) {
14   const { key, dataIndex, children } = item;
15   item.align = item.align || DEFAULT_ALIGN;
16   if (ellipsis) {
17     if (!key) {
d3fd22 18       item.key = typeof dataIndex == 'object' ? dataIndex.join('-') : dataIndex;
354904 19     }
V 20     if (!isBoolean(item.ellipsis)) {
21       Object.assign(item, {
22         ellipsis,
23       });
24     }
25   }
26   if (children && children.length) {
27     handleChildren(children, !!ellipsis);
28   }
29 }
30
31 function handleChildren(children: BasicColumn[] | undefined, ellipsis: boolean) {
32   if (!children) return;
33   children.forEach((item) => {
34     const { children } = item;
35     handleItem(item, ellipsis);
36     handleChildren(children, ellipsis);
37   });
38 }
39
40 function handleIndexColumn(
41   propsRef: ComputedRef<BasicTableProps>,
42   getPaginationRef: ComputedRef<boolean | PaginationProps>,
56a966 43   columns: BasicColumn[],
faf3f4 44 ) {
391da9 45   const { t } = useI18n();
V 46
5c2735 47   const { showIndexColumn, indexColumnProps, isTreeTable } = unref(propsRef);
354904 48
V 49   let pushIndexColumns = false;
5c2735 50   if (unref(isTreeTable)) {
V 51     return;
52   }
53   columns.forEach(() => {
354904 54     const indIndex = columns.findIndex((column) => column.flag === INDEX_COLUMN_FLAG);
5c2735 55     if (showIndexColumn) {
354904 56       pushIndexColumns = indIndex === -1;
5c2735 57     } else if (!showIndexColumn && indIndex !== -1) {
354904 58       columns.splice(indIndex, 1);
V 59     }
60   });
61
62   if (!pushIndexColumns) return;
63
64   const isFixedLeft = columns.some((item) => item.fixed === 'left');
65
66   columns.unshift({
67     flag: INDEX_COLUMN_FLAG,
68     width: 50,
69     title: t('component.table.index'),
70     align: 'center',
71     customRender: ({ index }) => {
72       const getPagination = unref(getPaginationRef);
73       if (isBoolean(getPagination)) {
74         return `${index + 1}`;
75       }
76       const { current = 1, pageSize = PAGE_SIZE } = getPagination;
056fc1 77       return ((current < 1 ? 1 : current) - 1) * pageSize + index + 1;
354904 78     },
V 79     ...(isFixedLeft
80       ? {
81           fixed: 'left',
82         }
83       : {}),
84     ...indexColumnProps,
85   });
86 }
87
88 function handleActionColumn(propsRef: ComputedRef<BasicTableProps>, columns: BasicColumn[]) {
89   const { actionColumn } = unref(propsRef);
90   if (!actionColumn) return;
91
92   const hasIndex = columns.findIndex((column) => column.flag === ACTION_COLUMN_FLAG);
93   if (hasIndex === -1) {
94     columns.push({
95       ...columns[hasIndex],
96       fixed: 'right',
97       ...actionColumn,
98       flag: ACTION_COLUMN_FLAG,
99     });
100   }
101 }
102
103 export function useColumns(
104   propsRef: ComputedRef<BasicTableProps>,
56a966 105   getPaginationRef: ComputedRef<boolean | PaginationProps>,
354904 106 ) {
3ef508 107   const columnsRef = ref(unref(propsRef).columns) as unknown as Ref<BasicColumn[]>;
354904 108   let cacheColumns = unref(propsRef).columns;
faf3f4 109
110   const getColumnsRef = computed(() => {
43e4c2 111     const columns = cloneDeep(unref(columnsRef));
cdf2c5 112
354904 113     handleIndexColumn(propsRef, getPaginationRef, columns);
V 114     handleActionColumn(propsRef, columns);
116a1f 115     if (!columns) {
V 116       return [];
117     }
e09e0a 118     const { ellipsis } = unref(propsRef);
V 119
43e4c2 120     columns.forEach((item) => {
e09e0a 121       const { customRender, slots } = item;
V 122
123       handleItem(
124         item,
56a966 125         Reflect.has(item, 'ellipsis') ? !!item.ellipsis : !!ellipsis && !customRender && !slots,
e09e0a 126       );
V 127     });
43e4c2 128     return columns;
116a1f 129   });
V 130
5a3861 131   function isIfShow(column: BasicColumn): boolean {
Z 132     const ifShow = column.ifShow;
133
134     let isIfShow = true;
135
136     if (isBoolean(ifShow)) {
137       isIfShow = ifShow;
138     }
139     if (isFunction(ifShow)) {
140       isIfShow = ifShow(column);
141     }
142     return isIfShow;
143   }
144   const { hasPermission } = usePermission();
145
9c2f3f 146   const getViewColumns = computed(() => {
V 147     const viewColumns = sortFixedColumn(unref(getColumnsRef));
148
f7a1b0 149     const mapFn = (column) => {
C 150       const { slots, customRender, format, edit, editRow, flag } = column;
151
152       if (!slots || !slots?.title) {
153         // column.slots = { title: `header-${dataIndex}`, ...(slots || {}) };
154         column.customTitle = column.title;
155         Reflect.deleteProperty(column, 'title');
156       }
157       const isDefaultAction = [INDEX_COLUMN_FLAG, ACTION_COLUMN_FLAG].includes(flag!);
158       if (!customRender && format && !edit && !isDefaultAction) {
159         column.customRender = ({ text, record, index }) => {
160           return formatCell(text, format, record, index);
161         };
162       }
163
164       // edit table
165       if ((edit || editRow) && !isDefaultAction) {
166         column.customRender = renderEditCell(column);
167       }
168       return reactive(column);
169     };
170
7a07b7 171     const columns = cloneDeep(viewColumns);
5a3861 172     return columns
f7a1b0 173       .filter((column) => hasPermission(column.auth) && isIfShow(column))
5a3861 174       .map((column) => {
f7a1b0 175         // Support table multiple header editable
C 176         if (column.children?.length) {
177           column.children = column.children.map(mapFn);
5a3861 178         }
9c2f3f 179
f7a1b0 180         return mapFn(column);
5a3861 181       });
faf3f4 182   });
183
af5551 184   watch(
V 185     () => unref(propsRef).columns,
186     (columns) => {
187       columnsRef.value = columns;
188       cacheColumns = columns?.filter((item) => !item.flag) ?? [];
56a966 189     },
af5551 190   );
74d474 191
c96002 192   function setCacheColumnsByField(dataIndex: string | undefined, value: Partial<BasicColumn>) {
V 193     if (!dataIndex || !value) {
194       return;
195     }
196     cacheColumns.forEach((item) => {
197       if (item.dataIndex === dataIndex) {
198         Object.assign(item, value);
199         return;
200       }
201     });
202   }
354904 203   /**
V 204    * set columns
116a1f 205    * @param columnList key|column
354904 206    */
3d55b0 207   function setColumns(columnList: Partial<BasicColumn>[] | (string | string[])[]) {
116a1f 208     const columns = cloneDeep(columnList);
8b3a4d 209     if (!isArray(columns)) return;
V 210
faf3f4 211     if (columns.length <= 0) {
212       columnsRef.value = [];
213       return;
214     }
215
216     const firstColumn = columns[0];
354904 217
116a1f 218     const cacheKeys = cacheColumns.map((item) => item.dataIndex);
V 219
3d55b0 220     if (!isString(firstColumn) && !isArray(firstColumn)) {
354904 221       columnsRef.value = columns as BasicColumn[];
faf3f4 222     } else {
4a4321 223       const columnKeys = (columns as (string | string[])[]).map((m) => m.toString());
116a1f 224       const newColumns: BasicColumn[] = [];
V 225       cacheColumns.forEach((item) => {
3b3f6c 226         newColumns.push({
N 227           ...item,
4a4321 228           defaultHidden: !columnKeys.includes(item.dataIndex?.toString() || (item.key as string)),
3b3f6c 229         });
116a1f 230       });
V 231       // Sort according to another array
232       if (!isEqual(cacheKeys, columns)) {
233         newColumns.sort((prev, next) => {
234           return (
3d55b0 235             columnKeys.indexOf(prev.dataIndex?.toString() as string) -
LC( 236             columnKeys.indexOf(next.dataIndex?.toString() as string)
116a1f 237           );
V 238         });
239       }
faf3f4 240       columnsRef.value = newColumns;
241     }
242   }
243
354904 244   function getColumns(opt?: GetColumnsParams) {
116a1f 245     const { ignoreIndex, ignoreAction, sort } = opt || {};
354904 246     let columns = toRaw(unref(getColumnsRef));
V 247     if (ignoreIndex) {
248       columns = columns.filter((item) => item.flag !== INDEX_COLUMN_FLAG);
249     }
250     if (ignoreAction) {
251       columns = columns.filter((item) => item.flag !== ACTION_COLUMN_FLAG);
252     }
116a1f 253
V 254     if (sort) {
9c2f3f 255       columns = sortFixedColumn(columns);
116a1f 256     }
V 257
354904 258     return columns;
V 259   }
116a1f 260   function getCacheColumns() {
V 261     return cacheColumns;
262   }
b97d58 263   function setCacheColumns(columns: BasicColumn[]) {
G 264     if (!isArray(columns)) return;
265     cacheColumns = columns.filter((item) => !item.flag);
266   }
1cf2a8 267   /**
268    * 拖拽列宽修改列的宽度
269    */
270   function setColumnWidth(w: number, col: BasicColumn) {
271     col.width = w;
272   }
354904 273
c96002 274   return {
V 275     getColumnsRef,
276     getCacheColumns,
277     getColumns,
278     setColumns,
1cf2a8 279     setColumnWidth,
c96002 280     getViewColumns,
V 281     setCacheColumnsByField,
b97d58 282     setCacheColumns,
c96002 283   };
116a1f 284 }
V 285
9c2f3f 286 function sortFixedColumn(columns: BasicColumn[]) {
116a1f 287   const fixedLeftColumns: BasicColumn[] = [];
V 288   const fixedRightColumns: BasicColumn[] = [];
289   const defColumns: BasicColumn[] = [];
290   for (const column of columns) {
291     if (column.fixed === 'left') {
292       fixedLeftColumns.push(column);
293       continue;
294     }
295     if (column.fixed === 'right') {
296       fixedRightColumns.push(column);
297       continue;
298     }
299     defColumns.push(column);
300   }
1214b7 301   return [...fixedLeftColumns, ...defColumns, ...fixedRightColumns].filter(
56a966 302     (item) => !item.defaultHidden,
116a1f 303   );
faf3f4 304 }
9c2f3f 305
V 306 // format cell
307 export function formatCell(text: string, format: CellFormat, record: Recordable, index: number) {
308   if (!format) {
309     return text;
310   }
311
312   // custom function
313   if (isFunction(format)) {
314     return format(text, record, index);
315   }
316
317   try {
318     // date type
319     const DATE_FORMAT_PREFIX = 'date|';
0634f2 320     if (isString(format) && format.startsWith(DATE_FORMAT_PREFIX) && text) {
9c2f3f 321       const dateFormat = format.replace(DATE_FORMAT_PREFIX, '');
V 322
323       if (!dateFormat) {
324         return text;
325       }
326       return formatToDate(text, dateFormat);
327     }
328
1214b7 329     // Map
330     if (isMap(format)) {
9c2f3f 331       return format.get(text);
V 332     }
333   } catch (error) {
334     return text;
335   }
336 }