/* eslint-disable react-hooks/rules-of-hooks */ /* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable @typescript-eslint/no-use-before-define */ import React, { useMemo, isValidElement, useRef } from 'react' import { Table, Space, Badge, Tag, Typography, Image, Progress, Avatar, Rate } from 'antd' import { isExist, run, isObject, isArray, isFunction } from '@fexd/tools' import { Tooltip, Hook, EllipsisTooltip, useTranslation, useLazyRender, Action, ErrorBoundary } from '@fexd/pro-utils' import { ProFieldValueFieldType, ProFieldValueTypes, ProField, CopyButton, ReadonlyProField } from '@fexd/pro-form' import { useProps } from '../../../utils' import useQueryFieldPlugin from '../../queryField' import useValueTypePlugin, { getAllFieldFromColumn } from '../../valueType' import { ProTableEditFieldType, ProTableColumnType, ProTableColumnBuiltInRenderConfig, ProTableColumnBuiltInRenderType, } from '../../../types' import useEditableRow from './useEditableRow' import useDataSourceIndexColumn from './useDataSourceIndexColumn' import useActionsColumn from './useActionsColumn' import useItem from '../useItem' import useFieldParams from '../../editField/useFieldParams' import useColumnConfig from '../useColumnConfig' import useColumnSettings from './useColumnSettings' import { useMemoizedFn } from 'ahooks' // import useLazyRenderCell from './useLazyRenderCell' const defaultEllipsisTypes = ['input', 'text', 'number', 'digit', 'money', 'percent'] const defaultAlignConfig = { money: 'right', number: 'right', digit: 'right', percent: 'right', select: 'center', image: 'center', } // let renderTimes = 0 // let globalRenderTime = 0 // Object.assign(window, { // getCellTime() { // return `平均时间:${(globalRenderTime / renderTimes).toFixed(2)}ms,总计渲染次数:${renderTimes}` // }, // }) export default function useColumns(): ProTableColumnType[] { const { columns: propColumns, rowKey, dataSource: propDataSource, hideColumnsWhenNoData, lazyRenderCell: getLazyRenderCell, lightweightRenderCell, } = useProps() const { types } = useValueTypePlugin(() => []) const queryField = useQueryFieldPlugin(({ dataSource }) => [dataSource]) const { dataSource: tableDataSource } = queryField const dataSource = propDataSource ?? tableDataSource const editableRowController = useEditableRow() const columnIndexRef = useRef(0) columnIndexRef.current = 0 const getSingleConfig = useMemoizedFn((column: ProTableColumnType, arrIdx): ProTableColumnType => { if ([Table.EXPAND_COLUMN, Table.SELECTION_COLUMN].some((builtInColumn) => builtInColumn === column)) { return column } if (isArray(column?.children)) { return { ...column, children: column?.children.map(getSingleConfig), } } const valueType = column?.valueType ?? column?.type const ellipsis = column?.ellipsis ?? (defaultEllipsisTypes.includes(valueType as any) || !valueType) const columnIndex = columnIndexRef.current++ - 1 const columnSettingKey = column?.key ?? (`${arrIdx}:${column?.dataIndex ?? column?.name}:${column?.type ?? column?.valueType ?? 'text'}` as any) return { showSorterTooltip: !!column?.tooltip ? false : true, // width: 80, align: defaultAlignConfig[valueType as 'money'] as any, key: columnSettingKey, ...column, columnSettingKey, render: (value: any, record: any, recordIndex: number, ...args) => ( {() => { const { editField, viewField } = useMemo(() => { const { editField, viewField } = getAllFieldFromColumn({ ...column, viewField: !column?.viewField ? true : column?.viewField, }) return { editField, viewField: { ...viewField, props: { ...({ image: { imageProps: { width: 50, height: 50, }, }, slider: { style: { width: 100, }, }, }[viewField?.type as any] ?? {}), ...viewField?.props, }, label: undefined, }, } }, [column]) const key = record?.[String(run(rowKey, undefined, record))] const rowEditable = editableRowController.useEditable(key) const editable = !!editField && rowEditable if (!editable && isFunction(column?.render)) { const columnRenderResult = run(column, 'render', value, record, recordIndex, ...args) if (isObject(columnRenderResult) && 'builtIn' in columnRenderResult) { const config = columnRenderResult as ProTableColumnBuiltInRenderConfig return ( {() => { const props: any = config?.props ?? {} const content = props?.children ?? props?.content ?? value if (!isExist(content)) { return '--' } return ( ( { text: {content}, link: {content}, tag: {content}, button: ( {content} ), avatar: , badge: , image: , progress: , rate: , field: , } as Record )[(config?.builtIn as ProTableColumnBuiltInRenderType) ?? 'text'] ?? <>{value} ) }} ) } return columnRenderResult } return ( {() => { const { t } = useTranslation() const fieldConfig = (editable ? editField : viewField) ?? viewField const needEllipsisTooltip = column?.ellipsis ?? ((!editable && defaultEllipsisTypes.includes(valueType as any)) || (!valueType && isExist(value))) const lazyRenderCell = useMemo( () => run(getLazyRenderCell, undefined, { dataSource, // any[]; column, // ProTableColumnType; item: record, // any; field: fieldConfig, // ProTableEditFieldType; xIndex: columnIndex, yIndex: recordIndex, isActionColumn: false, }), [getLazyRenderCell, dataSource, column, record, fieldConfig, columnIndex, recordIndex], ) const content = useMemo(() => { function getFieldConfig(extendFieldConfig: ProFieldValueFieldType) { const fieldEditable = editable && extendFieldConfig?.mode !== 'view' const fieldTypeName: ProFieldValueTypes = extendFieldConfig?.type ?? 'text' const fieldType: any = types?.[fieldTypeName] ?? types.text const initialValue = run(fieldType, 'normalizeFieldValue', value) ?? value const fieldNamePath = fieldEditable ? extendFieldConfig?.name : undefined const form = fieldEditable ? editableRowController.getForm(key) : false const field: ProFieldValueFieldType = { ...extendFieldConfig, fromNowTooltip: extendFieldConfig?.fromNowTooltip ?? false, copyable: false, // needEllipsisTooltip ? false : extendFieldConfig?.copyable, form, initialValue, label: undefined, style: { margin: 0 }, name: fieldNamePath, } editableRowController.setFieldConfig(key, column?.dataIndex, { type: fieldTypeName, name: fieldNamePath, }) return field } const fieldProps: ProFieldValueFieldType = { preserve: false, mode: editable ? 'edit' : 'view', copyable: false, initialValue: value, label: undefined, ...getFieldConfig(fieldConfig as any), } const fieldNode = lightweightRenderCell && !editable ? ( ) : ( { const dynamicField = run( fieldConfig?.hook, undefined, { item: record, form: editableRowController.getForm(key), mode: !editable ? 'view' : 'edit', inTable: true, }, ) if (dynamicField === false) { return getFieldConfig({ mode: 'view', key: 'view', ...viewField } as any) } if (!isValidElement(dynamicField) && isObject(dynamicField)) { dynamicField.label = undefined delete dynamicField.name delete dynamicField.hook delete dynamicField.copyable // 单元格内已额外处理复制图标,此处不需处理 } return dynamicField } : undefined } /> ) return fieldNode }, [key, value, record, editable, t, fieldConfig?.options, ellipsis, needEllipsisTooltip]) const lazyContent = useLazyRender( fieldConfig?.lazyRender ?? { forceVisible: !lazyRenderCell || editable, ...(isObject(lazyRenderCell) ? (lazyRenderCell as any) : {}), placeholderWrapperClassName: 'f-pro-table-cell-placeholder', placeholder: ( {isValidElement(value) ? value : '--'} ), content, }, ) const fieldParamsContext = useMemo( () => ({ mode: 'view', viewType: 'table', form: editableRowController.getForm(key) }), [], ) const wrapperedContent = ( <>{lazyContent} ) if (needEllipsisTooltip) { return (
{isExist(value) && fieldConfig?.copyable && ( )} {wrapperedContent}
) } // const startRenderTime = React.useRef(0) // useMemo(() => { // startRenderTime.current = Date.now() // }, [Math.random()]) // React.useEffect(() => { // const currentTime = Date.now() // const timeSpend = currentTime - startRenderTime.current // globalRenderTime += timeSpend // renderTimes++ // }, [Math.random()]) if (!isExist(value) && !editable) { return '--' } return <>{wrapperedContent} // return '--' // return editable ? content : lazyContent }}
) }}
), dataIndex: column?.dataIndex ?? column?.name, ellipsis, onCell: column?.onCell ?? // 内部处理 ellipsis 时单元格宽度未做限制导致属性无效的问题 (ellipsis ? () => ({ style: { maxWidth: column?.width ?? 300, }, }) : undefined), title: !column?.tooltip ? ( (column?.title ?? column?.label) ) : ( {column?.title ?? column?.label} ), } }) const allColumns: ProTableColumnType[] = useMemo( () => (propColumns ?? []) .filter(Boolean) .filter((column) => column?.hidden !== true) .map(getSingleConfig) as ProTableColumnType[], [propColumns], ) const applyColumnSettings = useColumnSettings({ allColumns }) const columns: ProTableColumnType[] = useMemo( () => applyColumnSettings(allColumns ?? []), [applyColumnSettings, allColumns], ) const hasWidth = useMemo(() => (columns ?? []).some((col) => isExist(col?.width)), [columns]) const actionsColumn = useActionsColumn({ editableRowController, hasWidth, }) const dataSourceColumn = useDataSourceIndexColumn({ hasWidth }) return useMemo[]>( () => (hideColumnsWhenNoData && dataSource?.length === 0 ? [] : [dataSourceColumn, ...columns, actionsColumn].filter(Boolean)) as ProTableColumnType[], [hideColumnsWhenNoData, dataSource?.length, dataSourceColumn, columns, actionsColumn], ) }