diff --git a/src/components/Table/EditableTable.tsx b/src/components/Table/EditableTable.tsx index 019c588..e1c2ccb 100644 --- a/src/components/Table/EditableTable.tsx +++ b/src/components/Table/EditableTable.tsx @@ -3,7 +3,7 @@ import { Form, Button, Popconfirm, TableProps } from 'antd' import { EditOutlined, SaveOutlined, PlusOutlined, CloseCircleOutlined, DeleteOutlined } from '@ant-design/icons' import { invokeWebApiWrapperAsync } from '@components/factory' -import { hasPermission } from '@utils' +import { hasPermission, isDev } from '@utils' import { Table, TableColumns } from '.' import { EditableCell } from './EditableCell' @@ -87,7 +87,7 @@ const EditableTableComponents = { body: { cell: EditableCell }} export type EditableTableProps> = TableProps & { columns: ColumnsType & TableColumns dataSource?: T[] - onChange + onChange?: ((data: T[]) => Promise) onRowAdd?: TableActionProps | ((record: T) => Promise) onRowEdit?: TableActionProps | ((record: T) => Promise) onRowDelete?: TableActionProps | ((record: T) => Promise) @@ -130,14 +130,19 @@ const _EditableTable = >({ }, [form]) const cancel = useCallback(() => { - if (editingKey === newRowKeyValue) { - const newData = [...data] - const index = newData.findIndex((item) => newRowKeyValue === item.key) - newData.splice(index, 1) - setData(newData) - } - setEditingKey('') - }, [data, editingKey]) + setEditingKey((prev) => { + if (prev === newRowKeyValue) { + setData((prev) => { + const newData = [...prev] + const index = newData.findIndex((item) => newRowKeyValue === item.key) + newData.splice(index, 1) + return newData + }) + } + + return '' + }) + }, []) const addNewRow = useCallback(async () => { const newRow: any = { key: newRowKeyValue } // TODO: Исправить тип @@ -146,43 +151,38 @@ const _EditableTable = >({ }, [edit]) const save = useCallback(async (record: T) => { + let row try { - const row = await form.validateFields() - const newData = [...data] - const index = newData.findIndex((item) => record.key === item.key) - const item = newData[index] - const newItem = { ...item, ...row } - - newData.splice(index, 1, newItem) - - if (item.key === newRowKeyValue) - item.key = newRowKeyValue + newData.length - - const isAdding = editingKey === newRowKeyValue - setEditingKey('') - setData(newData) - - if (isAdding) - try { - onAdd?.(newItem) - } catch (err) { - console.log('callback onRowAdd fault:', err) - } - else - try { - onEdit?.(newItem) - } catch (err) { - console.log('callback onRowEdit fault:', err) - } - - try { - onChange?.(newData) - } catch (err) { - console.log('callback onChange fault:', err) - } + row = await form.validateFields() } catch (errInfo) { - console.log('Validate Failed:', errInfo) + if (isDev()) + console.warn('Validate Failed:', errInfo) + return } + + const newData = [...data] + const index = newData.findIndex((item) => record.key === item.key) + const item = newData[index] + const newItem = { ...item, ...row } + + newData.splice(index, 1, newItem) + + if (item.key === newRowKeyValue) + item.key += newData.length + + try { + if (editingKey === newRowKeyValue) + await onAdd?.(newItem) + else + await onEdit?.(newItem) + await onChange?.(newData) + } catch (err) { + if (isDev()) + console.warn(err) + } + + setEditingKey('') + setData(newData) }, [data, editingKey, form, onChange, onAdd, onEdit]) const deleteRow = useCallback((record: T) => { diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index 36587af..6fab766 100755 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -1,26 +1,58 @@ -import { memo, useCallback, useEffect, useState } from 'react' +import { memo, ReactNode, useCallback, useEffect, useState } from 'react' import { ColumnGroupType, ColumnType } from 'antd/lib/table' import { Table as RawTable, TableProps } from 'antd' +import { NamePath } from 'antd/lib/form/interface' import type { OmitExtends } from '@utils/types' import { applyTableSettings, getTableSettings, setTableSettings, TableColumnSettings, TableSettings } from '@utils' import TableSettingsChanger from './TableSettingsChanger' +import { DataType, RenderMethod } from './Columns' import { tryAddKeys } from './EditableTable' import '@styles/index.css' export type BaseTableColumn = ColumnGroupType | ColumnType -export type TableColumns = OmitExtends, TableColumnSettings>[] +export type TableColumns = (OmitExtends, 'key' | 'render'>, TableColumnSettings> & { + key: NamePath + render: RenderMethod +})[] -export type TableContainer = Omit, 'columns'> & { +type MergedTableColumns = (OmitExtends, 'render'>, TableColumnSettings> & { + render: RenderMethod +})[] + +export type TableContainer = Omit, 'columns' | 'dataSource'> & { columns: TableColumns tableName?: string showSettingsChanger?: boolean + dataSource: DataType[] } -const _Table = ({ columns, dataSource, tableName, showSettingsChanger, ...other }: TableContainer) => { - const [newColumns, setNewColumns] = useState>([]) +export const keyToString = (key: NamePath): string => Array.isArray(key) ? key.join('.') : String(key) + +const defaultRender = (data: T): ReactNode => <>{data} + +const getValueFromKey = (key: NamePath, record: DataType): T | null => { + if (!key) return null + if (!Array.isArray(key)) + return record[String(key)] + if (key.length <= 0) return null + const child = record[key[0]] + if (key.length === 1) return child + if (typeof child !== 'object') return null + return getValueFromKey(key.slice(1), child as DataType) +} + +const columnRenderWrapper = (key: NamePath, render?: RenderMethod): RenderMethod => (_: T | null, record?: DataType, index?: number) => { + if (!record) return '-' + if (render) + return render(getValueFromKey(key, record), record, index) + return defaultRender(getValueFromKey(key, record)) +} + +const _Table = >({ columns, dataSource, tableName, showSettingsChanger, ...other }: TableContainer) => { + const [newColumns, setNewColumns] = useState>([]) const [settings, setSettings] = useState({}) const onSettingsChanged = useCallback((settings?: TableSettings | null) => { @@ -31,7 +63,12 @@ const _Table = ({ columns, dataSource, tableName, showSettings useEffect(() => setSettings(tableName ? getTableSettings(tableName) : {}), [tableName]) useEffect(() => setNewColumns(() => { - const newColumns = applyTableSettings(columns, settings) + const mergedColumns = applyTableSettings(columns, settings) + const newColumns = mergedColumns.map((column) => ({ + ...column, + render: columnRenderWrapper(column.key, column.render), + key: keyToString(column.key), + })) if (tableName && showSettingsChanger) { const oldTitle = newColumns[0].title newColumns[0].title = (props) => ( @@ -45,9 +82,9 @@ const _Table = ({ columns, dataSource, tableName, showSettings }), [settings, columns, onSettingsChanged, showSettingsChanger, tableName]) return ( - + > columns={newColumns} - dataSource={tryAddKeys(dataSource as any)} + dataSource={tryAddKeys>(dataSource)} {...other} /> )