import { createElement, forwardRef, useState, RefForwardingComponent } from 'rax'; import { useStyles } from '@rax-ui/styles'; import View from 'rax-view'; import Text from "rax-text"; import { isWeex } from 'universal-env'; import ScrollView from 'rax-scrollview'; import StyleProvider from './style'; import TableHeader from "./TableHeader"; import TableCellRow from "./TableCellRow"; import { TableProps, ColumnProps, SortOrder, CompareFn } from "./interface"; const Table: RefForwardingComponent = (props, ref) => { const { locale = { emptyText: "暂无数据" }, sortDirections = [ "ascend", "descend", null ] as SortOrder[], onHeaderRow, onRow, onChange, customStyles, descIconRender, onClickDescIcon, sortIconRender, bordered, dataSource, columns = [], children, ...others } = props; const defaultStyles = useStyles(StyleProvider, others, (classNames) => { let styles = { table: classNames(['table']), fixedTable: classNames(['table--fixed']), tableBorder: classNames(['table__border']), noData: classNames(['table__nodata']), noDataText: classNames(['table__nodata__text']), header: classNames(['table__header']), headerTitle: classNames(['table__header__title']), headerCellPadding: classNames(['table__header__cell--padding']), headerDesc: classNames(['table__header__desc']), headerDescIcon: classNames(['table__header__desc__icon']), sort: classNames(['table__header__sort']), sortIcon: classNames(['table__header__sort__icon']), sortIconAsce: classNames(['table__header__sort__icon--asce']), sortIconDesc: classNames(['table__header__sort__icon--desc']), sortIconSelected: classNames(['table__header__sort__icon--selected']), row: classNames(['table__row']), rowBorder: classNames(['table__row__border']), columnBorder: classNames(['table__column__border']), cell: classNames(['table__row__cell']), headerMinHeight: classNames(['table__header__min--height']), headerGroup: classNames(['table__header--group']), cellPadding: classNames(['table__row__cell__padding']), cellTitle: classNames(['table__row__cell__title']), }; if (bordered) { const { fixedTable, tableBorder } = styles; styles.fixedTable.left = (fixedTable.left as number) + (tableBorder.borderLeftWidth as number); } if (isWeex) { styles.fixedTable.left = 0; } return styles; }); const [sortedDataSource, setSortedDataSource] = useState(); const [currentSortColumn, setCurrentSortColumn] = useState(); const getCurrentSortColumn = () => { let sortColumn = null; if (currentSortColumn) { sortColumn = currentSortColumn; } return sortColumn; } const onSort = (column: ColumnProps, useDefaultSortOrder?) => { const sortedDataSource = [...dataSource]; const newColumn = { ...column }; const sortColumn = getCurrentSortColumn(); if (sortColumn && sortColumn.key === newColumn.key) { newColumn.sortOrder = sortColumn.sortOrder; } let { sortOrder } = newColumn; if (useDefaultSortOrder) { sortOrder = column.defaultSortOrder === "ascend" ? null : "ascend"; } const columnSortDirections = column.sortDirections || sortDirections; if (!columnSortDirections) { return; } const sortIndex = columnSortDirections.indexOf(sortOrder); if (!sortOrder || sortIndex === columnSortDirections.length - 1) { const [sortDirection] = columnSortDirections; newColumn.sortOrder = sortDirection; } else { newColumn.sortOrder = columnSortDirections[sortIndex + 1]; } const localSort = column.sorter && typeof column.sorter === "function"; if (localSort) { if (newColumn.sortOrder === "ascend") { sortedDataSource.sort(column.sorter as CompareFn); } if (newColumn.sortOrder === "descend") { sortedDataSource.sort(column.sorter as CompareFn).reverse(); } } setCurrentSortColumn(newColumn); setSortedDataSource(sortedDataSource); if (!useDefaultSortOrder && onChange) { onChange(newColumn); } } if (!sortedDataSource) { columns.forEach((column) => { if (column.defaultSortOrder) { onSort(column, true); } }); } const getChildrenColumns = (column: ColumnProps) => { if (column.children && Array.isArray(column.children)) { let childrenColumns = []; column.children.forEach((subColumn) => { const newSubColumn = { ...subColumn }; const children = getChildrenColumns(newSubColumn); if (children) { childrenColumns = childrenColumns.concat(children); } else { childrenColumns.push(newSubColumn); } }); return childrenColumns; } return null; } // 左侧固定的表格 const renderTable = (dataSource, childrenColumns, columns, style?) => { const tableCellRows = []; dataSource.forEach((item, index) => { tableCellRows.push( ); }); return ( { onSort(column); }} bordered={bordered} columns={columns} defaultSortDirections={sortDirections} sortColumn={getCurrentSortColumn()} styles={styles} onHeaderRow={onHeaderRow} sortIconRender={sortIconRender} descIconRender={descIconRender} onClickDescIcon={onClickDescIcon} /> {tableCellRows} ); } // 可滑动的表格 const renderScrollableTable = (dataSource, childrenColumns, columns) => { return ( {renderTable(dataSource, childrenColumns, columns)} ); } let tableDataSource = dataSource; const defaultStylesDeepCopy = JSON.parse(JSON.stringify(defaultStyles)); const styles = typeof customStyles === "function" ? customStyles(defaultStylesDeepCopy) : defaultStyles; if (sortedDataSource) { tableDataSource = sortedDataSource; } if (!tableDataSource || !columns) { return null; } if (!tableDataSource.length && columns.length) { // 有列配置,没行数据,显示暂无数据 const { emptyText } = locale; return ( {emptyText} ); } // 尺寸计算 let fixedWidth = 0; const scrollableColumns = []; const fixedColumns = []; let childrenColumns = []; columns.forEach((column) => { const children = getChildrenColumns(column); if (children) { childrenColumns = childrenColumns.concat(children); } else { childrenColumns.push(column); } }); const sortColumn = getCurrentSortColumn(); childrenColumns.forEach((column) => { const newColumn = { ...column }; if (sortColumn) { if (newColumn.key === sortColumn.key) { newColumn.sortOrder = sortColumn.sortOrder; } } const scrollableColumn = { ...newColumn }; const fixedColumn = { ...newColumn }; if (newColumn.fixed) { fixedWidth += newColumn.width; scrollableColumn.hidden = true; } else { fixedColumn.hidden = true; } fixedColumns.push(fixedColumn); scrollableColumns.push(scrollableColumn); }); const scrollableTable = renderScrollableTable( tableDataSource, scrollableColumns, columns ); const fixedTable = fixedWidth > 0 ? renderTable(tableDataSource, fixedColumns, columns, { ...styles.fixedTable, width: fixedWidth }) : null; let tableStyle; if (bordered) { tableStyle = { ...styles.table, ...styles.tableBorder }; } else { tableStyle = styles.table; } return ( {scrollableTable} {fixedTable} ); } export default forwardRef(Table);