react antd 添加行内编辑
添加行
如图:
提示:下面案例可供参考
1.文件1
代码如下(示例):文件名称:
import * as React from 'react';
import { ActionButton, SelectTableDensity } from '@components';
import { Table, Form, Input, Popconfirm, Select, Switch, Button, Tooltip } from 'antd';
import "./index.scss"
const _ = require('lodash');
const { Option } = Select;
const reg_proName = /^[\da-zA-Z~!@#$%^&*()_\=\+\-\[\{\]\}\;\:\'\"\|\,\<\.\>\/\?\\]+$/;
const reg_fieldName = /^[\da-zA-Z_]+$/;
const EditableContext = React.createContext(null);
const getRowType = (params) => {
const { record, inputType, options, onChange, onClick } = params;
if (inputType === 'input' && record.first != true) {
return <Input />;
}
if (inputType === 'dataSelect') {
return <Input readOnly onClick={e => onClick(record)}/>;
}
if (inputType === 'select') {
return <Select onChange={onChange ? (data, node) => onChange(data, node, record) : onChange}>
{
_.map(options, item => {
return <Option value={item.value} {...item} >{item.text}</Option>
})
}
</Select>
}
return <Input disabled={inputType === "readOnly"}/>
};
const EditableCell = (props: any) => {
const renderCell = (prop) => {
const { getFieldDecorator, resetFields } = prop;
const { editing, dataIndex, title, record, index, children, columns } = props;
let inputType = null //输入类型
let options = null //选项
let rules = null // 规则
let onChange: any = null
let onClick: any = null
let reset:any = null
if ((editing) && dataIndex !== "index" && dataIndex !== 'action') {
const keyIndex = _.findIndex(columns, item => item.dataIndex === dataIndex)
if (keyIndex > -1) {
inputType = columns[keyIndex].inputType ? columns[keyIndex].inputType : null
options = columns[keyIndex].options ? columns[keyIndex].options : null
rules = columns[keyIndex].rules ? columns[keyIndex].rules : null
onChange = columns[keyIndex].onChange ? columns[keyIndex].onChange : null
onClick = columns[keyIndex].onClick ? columns[keyIndex].onClick : null
reset = columns[keyIndex].reset ? columns[keyIndex].reset : null
}
}
//表单验证重置
if(record[dataIndex] && reset){
resetFields([`editRow.${record.id}[${dataIndex}]`])
}
return (
<td>
{(editing) && dataIndex !== "index" && dataIndex !== 'action' && inputType !== 'disabled'
? FormItem({ getFieldDecorator, dataIndex, record, editing, inputType, options, rules, onChange, onClick })
: dataIndex !== 'action'?<Tooltip title={children} placement="top" arrowPointAtCenter>
<span className="edit-table-col">{children}</span>
</Tooltip>: children}
</td>
);
};
return <EditableContext.Consumer>{renderCell}</EditableContext.Consumer>;
};
const FormItem: React.FC<any> = (params) => {
const { getFieldDecorator, dataIndex, record, state, editing, inputType, options, rules, onChange, onClick } = params;
// 与保存事件 配合一致
return (
<Form.Item style={{ margin: 0 }}>
{getFieldDecorator(`editRow.${record.id}[${dataIndex}]`, {
'initialValue': record[dataIndex],
'rules': rules
})(getRowType({ dataIndex, record, state, editing, inputType, options, onChange, onClick }))}
</Form.Item>
);
};
const EditableTable: React.FC<any> = (props): React.ReactElement => {
const { columns, tableData, setTableData, form, noEdit = false, noAdd = false, isPermissions, buttonName = "新增", moreButton } = props;
const { getFieldDecorator } = form;
const [density, setDensity] = React.useState<string>('');
const [editingKey, setEditingKey] = React.useState<any>([])
const isEditing = (record) => {
return editingKey.indexOf(record.id) >= 0;
};
React.useEffect(() => {
if (tableData.length > 0) {
let keys = []
let _editingKey = _.cloneDeep(editingKey)
tableData.forEach(row => {
if (row.first && editingKey.indexOf(row.id) === -1) {
_editingKey.push(row.id)
}
});
setEditingKey(_editingKey)
}
}, [tableData])
const onDelete = (id) => {
const newData: any = _.cloneDeep(tableData);
const index = newData.findIndex((item) => id === item.id);
newData.splice(index, 1);
setTableData(newData);
let keys = _.cloneDeep(editingKey);
keys.splice(keys.indexOf(id), 1);
};
const save = (key) => {
form.validateFields([`editRow.${key}`], (err: any, values: any): void => {
if (!err) {
let _tableData = _.cloneDeep(tableData)
for (let i in _tableData) {
if (_tableData[i].id === key) {
_tableData[i] = {
..._tableData[i],
...values.editRow[key]
}
if (_tableData[i].first) {
_tableData[i].first = false
}
}
}
setTableData(_tableData)
//取消编辑状态
let keys = _.cloneDeep(editingKey);
let index = _.findIndex(editingKey, item => item === key)
keys.splice(index, 1)
setEditingKey(keys)
// onSubmit && onSubmit({...values});
}
});
};
const add = () => {
let _tableData = _.cloneDeep(tableData)
const id = new Date().getTime().toString()
_tableData.push(
{
first: true,
id: id
}
)
let keys = _.cloneDeep(editingKey);
keys.push(id)
setEditingKey(keys)
setTableData(_tableData)
}
const edit = (key) => {
//变为编辑对象
let keys = _.cloneDeep(editingKey);
keys.push(key)
setEditingKey(keys)
};
const cancel = (data) => {
//如果是第一次添加保存,去除tableData中的数据
if (data.first) {
const newData: any = _.cloneDeep(tableData);
const index = newData.findIndex((item) => data.id === item.id);
newData.splice(index, 1);
setTableData(newData);
}
let keys = _.cloneDeep(editingKey);
const num = keys.findIndex((item) => item === data.id);
keys.splice(num, 1)
setEditingKey(keys);
};
const components = {
body: {
cell: EditableCell,
},
};
const editColums = noEdit ? columns : [
...columns,
{
title: '操作',
dataIndex: 'action',
width: moreButton?100 + (moreButton.length*20) : 100,
render: (text, record, index) => {
const editable = isEditing(record);
return editable ? <span>
<ActionButton title='保存' placement="bottom" className="icon iconfont icon-bc" onClick={() => save(record.id)} />
<ActionButton title='取消' placement="bottom" className="icon iconfont icon--remove" onClick={() => cancel(record)} />
</span> :
<span>
{
moreButton? _.map(moreButton(record, index), item => {
return item
}) :""
}
<ActionButton title='编辑' placement="bottom" className="icon iconfont icon-k-i-edit1" onClick={() => edit(record.id)} />
<Popconfirm
title='你确定要删除吗?'
onConfirm={() => onDelete(record.id)}
okText='是'
cancelText='否'
>
<ActionButton title='删除' placement="bottom" className="icon iconfont icon-delete" />
</Popconfirm>
</span>
},
},
];
const _columns = editColums.map((col) => {
return {
...col,
onCell: (record) => ({
record,
dataIndex: col.dataIndex,
title: col.title,
editing: isEditing(record),
columns: columns
}),
};
});
return (
<EditableContext.Provider value={props.form} >
{
noEdit || noAdd ? "" : <Button className='add-children' type="primary" onClick={add}>
<i className='iconfont iconk-i-file-add'></i> {buttonName}
</Button>
}
{
<Table
pagination={false}
components={components}
bordered
dataSource={tableData}
columns={_columns}
className={'j-edit-table resizable-column ' + density}
rowClassName={(record: any, index: number) => 'editable-row'}
scroll={{ x: '100%' }}
/>
}
</EditableContext.Provider>
);
};
export default EditableTable;
2.文件2
代码如下(示例):文件名称’./usedrag’
const ruleColunms:any = [
{
dataIndex: 'ruleType',
title: '类型',
inputType: "select",
options:[
{
text: '规则',
value: '1'
}
],
render: (text) => {
return text==='1'?"内置":""
}
},
{
dataIndex: 'validName',
title: '名称',
inputType: "readOnly"
},
{
dataIndex: 'displayName',
title: '触发字段',
inputType:"dataSelect",
onClick: (record) => {
setVisible(true)
setOpenType("rule")
setColunmRow(record)
},
reset:true, //改变值的时候是否重置验证,自己写的要传这个,不然验证不会消失
rules: [
{ required: true, message: '触发字段不能为空' }
],
}
]
//保存规则列
const saveRuleData = (data) => {
for(let i in data){
if(data[i].first){
data[i].ruleType = '1'
data[i].validName = '唯一性校验(业务基础数据)'
}
}
setRuleData(data)
}
const ruleData =[
{
"id": "157566",
"simpleBizConfigId": "76aed960-1e7b-4",
"ruleType": "1",
"ruleId": null,
"dataEntityId": null,
"dataProId": null,
"validName": "唯一性校验(业务基础数据)",
"dataItemName": "ATTRIBUTE",
"dataProName": "attribute",
"displayName": "bbbbb",
"validType": null,
"validValue": null,
"message": "【bbbbb】在【testt】中不能重复",
"dataItemNameList": [
{
"dataItemName": "ATTRIBUTE",
"dataProName": "attribute"
}
]
}
]
<EditTable
columns={ruleColunms}
tableData={ruleData}
setTableData={saveRuleData}
pagination={false}
form={form}
buttonName={'添加'}
/>