import * as React from 'react'; import { BasicContainer, runTimeType } from '../../render/core/Container/types'; import { Table } from '@native-ads/antd'; import { Map } from 'immutable'; import componentLoader from '../../render/util/componentLoader'; import * as _ from 'lodash'; import { createChild } from '../../render/util/createChild'; import { compileExpressionString } from '../../render/util/vm'; import { TableProps } from '@native-ads/antd/lib/table'; import { PaginationProps } from '@native-ads/antd/lib/pagination'; import { DataSource, TablePropsInterface, TableStateInterface, TableColumnsItem, TableConfig, TableCustomerColumnControlItem } from './types'; export class TableDriver extends Table { } export class AbstractTable extends BasicContainer { constructor(props: TablePropsInterface) { super(props); this.state = { total: 0, current: 0, expandedRowKeys: [] }; this.handleTableChange = this.handleTableChange.bind(this); this.addExpand = this.addExpand.bind(this); } componentWillMount() { let info = this.getPropsInfo(this.props.info); if (info.expandedRowKeys) { this.setState({ expandedRowKeys: info.expandedRowKeys }); } } // TODO 使用高阶组件来整理组件库 shouldComponentUpdate() { return true; } private handleTableChange(pagination: PaginationProps | boolean, filters: string[], sorter: Object) { if (typeof pagination !== 'boolean') { this.commonEventHandler('onPagination', { pageSize: pagination.pageSize, current: pagination.current }); } } private addExpand(expanded: boolean, record: DataSource) { let expandeds = this.state.expandedRowKeys; let rowKey = this.props.info.rowKey || 'key'; if (expanded) { expandeds.push(record[rowKey]); } else { expandeds = expandeds.filter((expandedsItem: any) => { return expandedsItem !== record[rowKey]; }); } this.setState({ expandedRowKeys: expandeds }); } private mapTableOptions(info: TableConfig): TableProps<{}> { return { pagination: info.pagination, size: info.size, loading: info.loading, locale: info.locale, indentSize: info.indentSize, useFixedHeader: info.useFixedHeader, bordered: info.bordered, showHeader: info.showHeader, className: info.className, style: info.style }; } private rewriteColumn(columnsMapping: TableColumnsItem, column: TableColumnsItem, runTime: runTimeType) { let newColumn = compileExpressionString(columnsMapping, { ...runTime, $item: column })!; return Object.assign(column, newColumn); } private columnProcessor( columns: TableColumnsItem[], info: TableConfig, dataSource: DataSource[] ): TableColumnsItem[] { if (info.extendColumns instanceof Array) { columns = columns.concat(info.extendColumns); } return columns.map(column => { // 列映射 if (info.columnsMapping) { let runTime = this.getRuntimeContext(); this.rewriteColumn(info.columnsMapping, column, runTime); } if (info.mergeFirstColumn) { this.collectColSpanInfo(dataSource); this.mergeFColumnControls(columns, dataSource); } let customConfig = info.customerColumnControls; let dataIndex = column.dataIndex; let targetCustomConfig = _.find(customConfig, columnConfig => columnConfig.dataIndex === dataIndex); if (targetCustomConfig) { Object.assign(column, targetCustomConfig); column.render = (text: any, record: DataSource, index: number) => { let childElement = this.renderTableCell( targetCustomConfig!, text, record, index ); return ( {childElement} ); }; } return column; }); } private dataSourceProcessor( dataSource: DataSource[], info: TableConfig ) { if (info.dataSourceMapping) { let runTime = this.getRuntimeContext(); dataSource = dataSource.map(source => { let newDataSource = compileExpressionString(info.dataSourceMapping, { ...runTime, $item: source }); return Object.assign(source, newDataSource); }); } return dataSource; } /** * 获取表格单元格自定义渲染元素 * * @param info Table的配置 * @param column 每列的配置 * @param text 单元格要渲染的文本 * @param record 整行的数据对象 * @param index 行数 * @returns {React.ReactNode} */ private renderTableCell( column: TableCustomerColumnControlItem, text: any, record: DataSource, index: number ): React.ReactNode { if (column.controls) { return column.controls.map((controlInfo, controlIndex) => { let defaultProps = this.getChildProps(controlInfo, { key: `table_column_${controlInfo.type}_${controlIndex}}` }); return createChild(controlInfo, { ...defaultProps, $item: record, $index: index }); }); } return text; } private collectColSpanInfo(dataSource: DataSource[]) { dataSource.forEach(source => { let sourceKeys = Object.keys(source); let sourceInfo = {}; sourceKeys.forEach(key => { sourceInfo[key] = 1; }); source.colSpanInfo = Map(sourceInfo); }); } private mergeFColumnControls(columns: TableColumnsItem[], dataSource: DataSource) { let item = columns[0]; item.render = (source, row, index) => { const obj = { children: source, props: { rowSpan: item.dataIndex ? row.colSpanInfo.get(item.dataIndex) : 1 } }; if (this.props.info.mergeFirstColumn && item.dataIndex && row.colSpanInfo.get(item.dataIndex) > 0) { let start = index + 1; let count = 1; let remain = dataSource.length - index; let pointer = start; for (let i = 1; (pointer = start) && i < remain && source === dataSource[pointer][item.dataIndex]; i++) { dataSource[pointer].colSpanInfo = dataSource[pointer].colSpanInfo.set(item.dataIndex, 0); start++; count++; } obj.props.rowSpan = count; } return obj; }; return item; } render() { let info = this.getPropsInfo(this.props.info, this.props, ['columnsMapping', 'dataSourceMapping', 'customerColumnControls', 'mergeFirstColumn'], true); let dataSource: DataSource[] = info.dataSource || []; let columns: TableColumnsItem[] = info.columns || []; let $loading = info.loading; let tableProps = this.mapTableOptions(info); const tableStyle = { width: '100%', ...info.style }; if (this.isUnderContainerEnv()) { $loading = this.getValueFromDataStore('$loading') || false; } if (info.expandedRowKeys && Array.isArray(info.expandedRowKeys)) { tableProps.expandedRowKeys = this.state.expandedRowKeys; tableProps.onExpand = this.addExpand; } if (info.fixedHeader) { tableProps.scroll = { y: info.fixedHeader.fixedHeight || '', x: info.fixedHeader.fixedWidth || '' }; } if (info.rowSelection && _.isPlainObject(info.rowSelection)) { tableProps.rowSelection = { fixed: info.rowSelection.fixed, type: info.rowSelection.type, hideDefaultSelections: info.rowSelection.hideDefaultSelections, onChange: (selectedRowKeys: string[] | number[], selectedRows: Object[]) => { this.commonEventHandler('onRowSelectionChange', { selectedRowKeys: selectedRowKeys, selectedRows: selectedRows }); }, onSelect: (record: DataSource, selected: boolean, selectedRows: Object[]) => { this.commonEventHandler('onRowSelectionSelect', { record: record, selected: selected, selectedRows: selectedRows }); } }; } columns = this.columnProcessor(columns, info, dataSource); dataSource = this.dataSourceProcessor(dataSource, info); return ( { if (info.rowKey) { return record[info.rowKey]; } else if (record['key']) { return record['key']; } else { console.error('请提供rowKey属性来让表格组件工作在正常的状态下'); } }} columns={columns} dataSource={dataSource} loading={$loading} style={tableStyle} onChange={this.handleTableChange} /> ); } } componentLoader.addComponent('table', AbstractTable, TablePropsInterface);