forked from ddrilling/asb_cloud_front
Частична улучшена типизация Editable table
This commit is contained in:
parent
32ec3c22d2
commit
4ad6f91c8a
@ -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<T extends CrudObject, S extends CrudService<T>> = TableProps<T> & {
|
||||
columns: ColumnsType<T> & TableColumns<T>
|
||||
dataSource?: T[]
|
||||
onChange
|
||||
onChange?: ((data: T[]) => Promise<void>)
|
||||
onRowAdd?: TableActionProps<T, S> | ((record: T) => Promise<void>)
|
||||
onRowEdit?: TableActionProps<T, S> | ((record: T) => Promise<void>)
|
||||
onRowDelete?: TableActionProps<T, S> | ((record: T) => Promise<void>)
|
||||
@ -130,14 +130,19 @@ const _EditableTable = <T extends CrudObject, S extends CrudService<T>>({
|
||||
}, [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 = <T extends CrudObject, S extends CrudService<T>>({
|
||||
}, [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) => {
|
||||
|
@ -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<T> = ColumnGroupType<T> | ColumnType<T>
|
||||
export type TableColumns<T> = OmitExtends<BaseTableColumn<T>, TableColumnSettings>[]
|
||||
export type TableColumns<T> = (OmitExtends<Omit<BaseTableColumn<T>, 'key' | 'render'>, TableColumnSettings> & {
|
||||
key: NamePath
|
||||
render: RenderMethod<T | null>
|
||||
})[]
|
||||
|
||||
export type TableContainer<T> = Omit<TableProps<T>, 'columns'> & {
|
||||
type MergedTableColumns<T> = (OmitExtends<Omit<BaseTableColumn<T>, 'render'>, TableColumnSettings> & {
|
||||
render: RenderMethod<T | null>
|
||||
})[]
|
||||
|
||||
export type TableContainer<T> = Omit<TableProps<T>, 'columns' | 'dataSource'> & {
|
||||
columns: TableColumns<T>
|
||||
tableName?: string
|
||||
showSettingsChanger?: boolean
|
||||
dataSource: DataType<T>[]
|
||||
}
|
||||
|
||||
const _Table = <T extends object>({ columns, dataSource, tableName, showSettingsChanger, ...other }: TableContainer<T>) => {
|
||||
const [newColumns, setNewColumns] = useState<TableColumns<T>>([])
|
||||
export const keyToString = (key: NamePath): string => Array.isArray(key) ? key.join('.') : String(key)
|
||||
|
||||
const defaultRender = <T,>(data: T): ReactNode => <>{data}</>
|
||||
|
||||
const getValueFromKey = <T,>(key: NamePath, record: DataType<T>): 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<T>)
|
||||
}
|
||||
|
||||
const columnRenderWrapper = <T,>(key: NamePath, render?: RenderMethod<T | null>): RenderMethod<T | null> => (_: T | null, record?: DataType<T | null>, index?: number) => {
|
||||
if (!record) return '-'
|
||||
if (render)
|
||||
return render(getValueFromKey(key, record), record, index)
|
||||
return defaultRender(getValueFromKey(key, record))
|
||||
}
|
||||
|
||||
const _Table = <T extends Record<string, any>>({ columns, dataSource, tableName, showSettingsChanger, ...other }: TableContainer<T>) => {
|
||||
const [newColumns, setNewColumns] = useState<MergedTableColumns<T>>([])
|
||||
const [settings, setSettings] = useState<TableSettings>({})
|
||||
|
||||
const onSettingsChanged = useCallback((settings?: TableSettings | null) => {
|
||||
@ -31,7 +63,12 @@ const _Table = <T extends object>({ 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 = <T extends object>({ columns, dataSource, tableName, showSettings
|
||||
}), [settings, columns, onSettingsChanged, showSettingsChanger, tableName])
|
||||
|
||||
return (
|
||||
<RawTable<T>
|
||||
<RawTable<DataType<T>>
|
||||
columns={newColumns}
|
||||
dataSource={tryAddKeys<T>(dataSource as any)}
|
||||
dataSource={tryAddKeys<DataType<T>>(dataSource)}
|
||||
{...other}
|
||||
/>
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user