asb_cloud_front/src/components/Table/EditableTable.jsx

191 lines
5.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Form, Table, Button, Popconfirm } from "antd"
import { EditOutlined, SaveOutlined, PlusOutlined, CloseCircleOutlined, DeleteOutlined } from '@ant-design/icons'
import { useState, useEffect } from "react";
import { EditableCell } from './EditableCell'
const newRowKeyValue = 'newRow'
export const tryAddKeys = (items) => {
if(!items?.length || !items[0])
return []
if(items[0].key)
return items
return items.map((item, index) => ({...item, key: item.key ?? item.id ?? index }))
}
export const EditableTable = ({
columns,
dataSource,
onChange, // Метод вызывается со всем dataSource с измененными элементами после любого действия
onRowAdd, // Метод вызывается с новой добавленной записью. Если метод не определен, то кнопка добавления строки не показывается
onRowEdit,// Метод вызывается с новой отредактированной записью. Если метод не поределен, то кнопка редактирования строки не показывается
onRowDelete,// Метод вызывается с удаленной записью. Если метод не поределен, то кнопка удаления строки не показывается
...otherTableProps
}) => {
const [form] = Form.useForm()
const [data, setData] = useState(tryAddKeys(dataSource))
const [editingKey, setEditingKey] = useState('')
useEffect(()=>{
setData(tryAddKeys(dataSource))
},[dataSource])
const isEditing = (record) => record?.key === editingKey
const edit = (record) => {
form.setFieldsValue({...record})
setEditingKey(record.key)
}
const cancel = () => {
if(editingKey === newRowKeyValue)
{
const newData = [...data]
const index = newData.findIndex((item) => newRowKeyValue === item.key)
newData.splice(index, 1)
setData(newData)
}
setEditingKey('')
}
const addNewRow = async () => {
let newRow = {
...form.initialValues,
key:newRowKeyValue
}
const newData = [newRow, ...data]
setData(newData)
edit(newRow)
}
const save = async (record) => {
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{
onRowAdd(newItem)
}catch(err){
console.log('callback onRowAdd fault:', err)
}
else
try{
onRowEdit(newItem)
}catch(err){
console.log('callback onRowEdit fault:', err)
}
try{
if(onChange)
onChange(newData)
}catch(err){
console.log('callback onChange fault:', err)
}
} catch (errInfo) {
console.log('Validate Failed:', errInfo)
}
}
const deleteRow = (record) =>{
const newData = [...data]
const index = newData.findIndex((item) => record.key === item.key)
newData.splice(index, 1)
setData(newData)
onRowDelete(record)
if(onChange)
onChange(newData)
}
const operationColumn = {
width: 82,
title: (!!onRowAdd) && <Button
onClick={addNewRow}
disabled={editingKey !== ''}
icon={<PlusOutlined/>}
/>,
dataIndex: 'operation',
render: (_, record) => {
const editable = isEditing(record)
return editable
?(<span>
<Button
onClick={() => save(record)}
icon={<SaveOutlined/>}/>
<Button
onClick={cancel}
icon={<CloseCircleOutlined/>}/>
</span>)
:(<span>
{onRowEdit&&<Button
disabled={editingKey !== ''}
onClick={() => edit(record)}
icon={<EditOutlined/>}/>}
{onRowDelete&&
<Popconfirm title="Удалить?" onConfirm={()=>deleteRow(record)}>
<Button icon={<DeleteOutlined/>}/>
</Popconfirm>}
</span>)
},
}
const handleColumn = (col) => {
if (col.children)
col.children = col.children.map(handleColumn)
if (!col.editable)
return col
return {
...col,
onCell: (record) => ({
editing: isEditing(record),
record,
dataIndex: col.dataIndex ?? col.key,
key: col.key ?? col.dataIndex,
input: col.input,
isRequired: col.isRequired,
title: col.title,
dataType: col.dataType,
formItemClass: col.formItemClass,
formItemRules: col.formItemRules,
initialValue: col.initialValue,
}),
}
}
const mergedColumns = [...columns.map(handleColumn), operationColumn]
return (
<Form form={form} component={false}>
<Table
components={{
body: {
cell: EditableCell,
},
}}
columns={mergedColumns}
dataSource={data}
{...otherTableProps}
/>
</Form>
)
}