@fe6/water-pro
Version:
An enterprise-class UI design language and Vue-based implementation
334 lines (292 loc) • 8.81 kB
text/typescript
/** @format */
import type {
BasicColumn,
TableProProps,
CellFormat,
CellFormatMap,
CellFormatFn,
GetColumnsParams,
} from '../types/table';
import type { PaginationProps } from '../types/pagination';
import { unref, ComputedRef, Ref, computed, watch, ref, toRaw } from 'vue';
import { isBoolean, isArray, isString, isPlainObject, isFunction } from '@fe6/shared';
import { isEqual, cloneDeep } from 'lodash-es';
import { DEFAULT_ALIGN, PAGE_SIZE, INDEX_COLUMN_FLAG, ACTION_COLUMN_FLAG } from '../const';
import { formatToDate } from '../date';
// TODO [feat] 因为 /directives/click-outside.ts yarn pub 报错,所以暂缓支持
// import { renderEditCell } from '../components/editable';
const indexText = '序号';
function handleItem(item: BasicColumn, ellipsis: boolean) {
const { key, dataIndex, children } = item;
item.align = item.align || DEFAULT_ALIGN;
if (ellipsis) {
if (!key) {
item.key = dataIndex;
}
if (!isBoolean(item.ellipsis)) {
Object.assign(item, {
ellipsis,
});
}
}
if (children && children.length) {
handleChildren(children, !!ellipsis);
}
}
function handleChildren(children: BasicColumn[] | undefined, ellipsis: boolean) {
if (!children) {
return;
}
children.forEach((item) => {
const { children } = item;
handleItem(item, ellipsis);
handleChildren(children, ellipsis);
});
}
function handleIndexColumn(
propsRef: ComputedRef<TableProProps>,
getPaginationRef: ComputedRef<boolean | PaginationProps>,
columns: BasicColumn[],
) {
const { showIndexColumn, indexColumnProps, isTreeTable } = unref(propsRef);
let pushIndexColumns = false;
if (unref(isTreeTable)) {
return;
}
columns.forEach(() => {
const indIndex = columns.findIndex((column) => column.flag === INDEX_COLUMN_FLAG);
if (showIndexColumn) {
pushIndexColumns = indIndex === -1;
} else if (!showIndexColumn && indIndex !== -1) {
columns.splice(indIndex, 1);
}
});
if (!pushIndexColumns) {
return;
}
const isFixedLeft = columns.some((item) => item.fixed === 'left');
columns.unshift({
flag: INDEX_COLUMN_FLAG,
width: 50,
title: indexText,
align: 'center',
customRender: ({ index }) => {
const getPagination = unref(getPaginationRef);
if (isBoolean(getPagination)) {
return `${index + 1}`;
}
const { current = 1, pageSize = PAGE_SIZE } = getPagination as PaginationProps;
return ((current < 1 ? 1 : current) - 1) * pageSize + index + 1;
},
...(isFixedLeft
? {
fixed: 'left',
}
: {}),
...indexColumnProps,
});
}
function handleActionColumn(propsRef: ComputedRef<TableProProps>, columns: BasicColumn[]) {
const { actionColumn } = unref(propsRef);
if (!actionColumn) {
return;
}
const hasIndex = columns.findIndex((column) => column.flag === ACTION_COLUMN_FLAG);
if (hasIndex === -1) {
columns.push({
...columns[hasIndex],
fixed: 'right',
...actionColumn,
flag: ACTION_COLUMN_FLAG,
});
}
}
export function useColumns(
propsRef: ComputedRef<TableProProps>,
getPaginationRef: ComputedRef<boolean | PaginationProps>,
) {
const columnsRef = ref(unref(propsRef).columns) as unknown as Ref<BasicColumn[]>;
let cacheColumns = unref(propsRef).columns;
const getColumnsRef = computed(() => {
const columns = unref(columnsRef);
handleIndexColumn(propsRef, getPaginationRef, columns);
handleActionColumn(propsRef, columns);
if (!columns) {
return [];
}
const { ellipsis } = unref(propsRef);
const cloneColumns = cloneDeep(columns);
cloneColumns.forEach((item) => {
const { customRender, slots } = item;
handleItem(
item,
Reflect.has(item, 'ellipsis') ? !!item.ellipsis : !!ellipsis && !customRender && !slots,
);
});
return cloneColumns;
});
const getViewColumns = computed(() => {
const viewColumns = sortFixedColumn(unref(getColumnsRef));
const columns = cloneDeep(viewColumns);
columns.forEach((column) => {
const {
slots,
dataIndex,
customRender,
format,
edit,
// editRow,
flag,
} = column;
if (!slots || !slots?.title) {
column.slots = { title: `header-${dataIndex}`, ...(slots || {}) };
column.customTitle = column.customTitle || column.title;
Reflect.deleteProperty(column, 'title');
}
const isDefaultAction = [INDEX_COLUMN_FLAG, ACTION_COLUMN_FLAG].includes(flag!);
if (!customRender && format && !edit && !isDefaultAction) {
column.customRender = ({ text, record, index }) => {
return formatCell(text, format, record, index);
};
}
});
return columns;
});
watch(
() => unref(propsRef).columns,
(columns) => {
columnsRef.value = columns;
cacheColumns = columns?.filter((item) => !item.flag) ?? [];
},
);
// watchEffect(() => {
// const columns = toRaw(unref(propsRef).columns);
// console.log('======================');
// console.log(111);
// console.log('======================');
// columnsRef.value = columns;
// cacheColumns = columns?.filter((item) => !item.flag) ?? [];
// });
function setCacheColumnsByField(dataIndex: string | undefined, value: Partial<BasicColumn>) {
if (!dataIndex || !value) {
return;
}
cacheColumns.forEach((item) => {
if (item.dataIndex === dataIndex) {
Object.assign(item, value);
}
});
}
/**
* set columns
* @param columnList key|column
*/
function setColumns(columnList: Partial<BasicColumn>[] | string[]) {
const columns = cloneDeep(columnList);
if (!isArray(columns)) {
return;
}
if (columns.length <= 0) {
columnsRef.value = [];
return;
}
const firstColumn = columns[0];
const cacheKeys = cacheColumns.map((item) => item.dataIndex);
if (!isString(firstColumn)) {
columnsRef.value = columns as BasicColumn[];
} else {
const columnKeys = columns as string[];
const newColumns: BasicColumn[] = [];
cacheColumns.forEach((item) => {
if (columnKeys.includes(item.dataIndex! || (item.key as string))) {
newColumns.push({
...item,
defaultHidden: false,
});
}
});
// Sort according to another array
if (!isEqual(cacheKeys, columns)) {
newColumns.sort((prev, next) => {
return (
columnKeys.indexOf(prev.dataIndex as string) -
columnKeys.indexOf(next.dataIndex as string)
);
});
}
columnsRef.value = newColumns;
}
}
function getColumns(opt?: GetColumnsParams) {
const { ignoreIndex, ignoreAction, sort } = opt || {};
let columns = toRaw(unref(getColumnsRef));
if (ignoreIndex) {
columns = columns.filter((item) => item.flag !== INDEX_COLUMN_FLAG);
}
if (ignoreAction) {
columns = columns.filter((item) => item.flag !== ACTION_COLUMN_FLAG);
}
if (sort) {
columns = sortFixedColumn(columns);
}
return columns;
}
function getCacheColumns() {
return cacheColumns;
}
return {
getColumnsRef,
getCacheColumns,
getColumns,
setColumns,
getViewColumns,
setCacheColumnsByField,
};
}
function sortFixedColumn(columns: BasicColumn[]) {
const fixedLeftColumns: BasicColumn[] = [];
const fixedRightColumns: BasicColumn[] = [];
const defColumns: BasicColumn[] = [];
for (const column of columns) {
if (column.fixed === 'left') {
fixedLeftColumns.push(column);
continue;
}
if (column.fixed === 'right') {
fixedRightColumns.push(column);
continue;
}
defColumns.push(column);
}
const resultColumns = [...fixedLeftColumns, ...defColumns, ...fixedRightColumns].filter(
(item) => !item.defaultHidden,
);
return resultColumns;
}
// format cell
export function formatCell(text: string, format: CellFormat, record: Recordable, index: number) {
if (!format) {
return text;
}
// custom function
if (isFunction(format)) {
return (format as CellFormatFn)(text, record, index);
}
try {
// date type
const DATE_FORMAT_PREFIX = 'date|';
if (isString(format) && (format as string).startsWith(DATE_FORMAT_PREFIX)) {
const dateFormat = (format as string).replace(DATE_FORMAT_PREFIX, '');
if (!dateFormat) {
return text;
}
return formatToDate(text, dateFormat);
}
// enum
if (isPlainObject(format) && Reflect.has(format as CellFormatMap, 'size')) {
return (format as CellFormatMap).get(text);
}
} catch (error) {
return text;
}
}