最近因为工作需要,要基于react-ant做一个可编辑表格,具体功能如图所示,带分页可新增,删除,批量删除,保存等功能,
可编辑表格是依照官方文档实现的,具体参考https://3x.ant.design/components/table-cn/#components-table-demo-edit-cell;
/* eslint-disable no-duplicate-case */
/* eslint-disable no-const-assign */
/* eslint-disable react/jsx-no-duplicate-props */
/* eslint-disable react/prop-types */
/* eslint-disable no-undef */
/* eslint-disable no-unused-vars */
import React, { Component } from 'react';
// import PropTypes from 'prop-types';
import './unit-cost.less';
import {Table, Input, Button, Modal, Form, InputNumber } from 'antd';
import * as getUnitCost from '../../../actions/getUnitCost';
import { toast } from '../../toast';
const EditableContext = React.createContext();
const EditableRow = ({ form, index, ...props }) => (
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
);
const EditableFormRow = Form.create()(EditableRow);
class EditableCell extends React.Component {
state = {
editing: false,
};
toggleEdit = () => {
const editing = !this.state.editing;
this.setState({ editing }, () => {
if(editing) {
this.input.focus();
}
});
};
save = e => {
const { record, handleSave } = this.props;
this.form.validateFields((error, values) => {
if(error && error[e.currentTarget.id]) {
return;
}
this.toggleEdit();
handleSave({ ...record, ...values });
});
};
renderCell = form => {
this.form = form;
const { children, dataIndex, record, title } = this.props;
const { editing } = this.state;
return editing ? (
<Form.Item style={{ margin: 0 }}>
{form.getFieldDecorator(dataIndex, {
//为可编辑表格设定规则,下面注释掉的是非空
// rules: [
// {
// required: new RegExp(),
// message: `${title} is required.`,
// },
// ],
initialValue: record[dataIndex],
})(<InputNumber className = 'number' ref={node => (this.input = node)} onChange={this.onChange} onPressEnter={this.save} onBlur={this.save} min={0}/>)}
</Form.Item>
) : (
<div
className="editable-cell-value-wrap"
style={{ paddingRight: 24 }}
onClick={this.toggleEdit}
>
{children}
</div>
);
};
render() {
const {
editable,
dataIndex,
title,
record,
index,
handleSave,
children,
...restProps
} = this.props;
return (
<td {...restProps}>
{editable ? (
<EditableContext.Consumer>{this.renderCell}</EditableContext.Consumer>
) : (
children
)}
</td>
);
}
}
class UnitCost extends Component {
constructor(props) {
super(props);
this.columns = [
{
title: '机组容量等级',
dataIndex: 'title',
width: '500',
},
{
title: '20万千瓦级以下',
dataIndex: 'January',
width: '150',
editable: true,
children: [
{
title: '出力(MW)',
dataIndex: 'costlt20',
editable: true,
},
{
title: '边际成本(元/兆瓦时)',
dataIndex: 'pricelt20',
editable: true,
}
],
},
{
title: '20万千瓦级',
dataIndex: 'February',
width: '150',
editable: true,
children: [
{
title: '出力(MW)',
dataIndex: 'costeq20',
editable: true,
},
{
title: '边际成本(元/兆瓦时)',
dataIndex: 'priceeq20',
editable: true,
}
],
},
{
title: '30万千瓦级',
dataIndex: 'March',
width: '150',
editable: true,
children: [
{
title: '出力(MW)',
dataIndex: 'costeq30',
editable: true,
},
{
title: '边际成本(元/兆瓦时)',
dataIndex: 'priceeq30',
editable: true,
}
],
},
{
title: '60万千瓦级',
dataIndex: 'April',
width: '150',
editable: true,
children: [
{
title: '出力(MW)',
dataIndex: 'costeq60',
editable: true,
},
{
title: '边际成本(元/兆瓦时)',
dataIndex: 'priceeq60',
editable: true,
}
],
},
{
title: '100万千瓦级',
dataIndex: 'May',
width: '150',
editable: true,
children: [
{
title: '出力(MW)',
dataIndex: 'costeq100',
editable: true,
},
{
title: '边际成本(元/兆瓦时)',
dataIndex: 'priceeq100',
editable: true,
}
],
}
];
this.state = {
dataSource: [],
count: 0,
record: [],
selectedRowKeys: [],
visible: false,
currentPage: 1, //当前页
pageSize: 10, //一页多少条数据
total: 0 //数据总数
};
}
componentWillMount = () => {
this.getUnitCostData();
}
//获取表格数据
getUnitCostData = () => {
getUnitCost.getUnitCost((json) => {
if(json) {
let keys = 0;
let data = [];
if(json.length > 0) {
json.map(((item, index)=> {
data.push(Object.assign(
{}, item, {title: '机组边际成本'}, {key: index}
));
}));
let key = [];
console.log(data);
for(let i = 0; i < data.length; i++) {
if(data[i].key) {
key.push(data[i].key);
} else {
key = [0];
}
}
keys = (Math.max(...key));
//为保证key唯一,取出后台数据中最大的key
this.setState({
dataSource: data,
count: keys + 1,
total: data.length
});
} else {
this.setState({
dataSource: json,
count: keys,
total: 0
});
}
}
});
}
handleSave = row => {
const newData = [...this.state.dataSource];
const index = newData.findIndex(item => row.key === item.key);
const item = newData[index];
newData.splice(index, 1, {
...item,
...row,
});
this.setState({ dataSource: newData });
};
//保存
save = () => {
let datalist = this.state.dataSource;
//这里可以加一些数据校验
getUnitCost.setUnitCost(datalist, (json) => {
if(json) {
if(json && json == 1) {
toast({ type: 'success', message: '保存成功' });
this.getUnitCostData();
} else {
toast({ type: 'error', message: '保存失败' });
}
}
});
}
}
//添加
add = () => {
const {dataSource, currentPage, pageSize, total, count } = this.state;
// 总数为零:页数=1, 不为零:总数/每页的条数 = 整数,页数 = (总数/每页的条数+1) !=整数 页数 = (总数/每页的条数) 向上取整
let page = total == 0 ? currentPage : (total % pageSize == 0 ? total / pageSize + 1 : Math.ceil(total / pageSize));
this.setState({currentPage: page, total: total + 1}, () => {});
const newData = {
indexKey: count,
title: '机组边际成本',
costlt20: null,
costeq20: null,
costeq30: null,
costeq60: null,
costeq100: null,
pricelt20: null,
priceeq20: null,
priceeq30: null,
priceeq60: null,
priceeq100: null,
eq100: '100w千瓦级',
eq20: '20w千瓦级',
eq30: '30w千瓦级',
eq60: '60w千瓦级',
lt20: '20W千瓦级以下',
key: count + 1,
};
this.setState({
dataSource: [...dataSource, newData],
});
}
deleteUnitCostData = (id) => {
console.log(id);
if(id.length == 0) {
let newarr = this.state.dataSource.pop();
this.setState({
dataSource: this.state.dataSource,
selectedRowKeys: []
});
} else {
getUnitCost.deleteUnitCost(id, (json) => {
if(json) {
if(json && json == 1) {
toast({ type: 'success', message: '删除成功' });
this.getUnitCostData();
this.setState({ selectedRowKeys: []});
} else {
toast({ type: 'error', message: '删除失败' });
}
}
});
}
};
//删除
delete = ()=> {
Modal.confirm({
title: '确认删除?',
okText: '确认',
cancelText: '取消',
onOk: () => {
let datalist = this.state.record;
console.log(datalist);
let id = [];
for(let i = 0 ; i < datalist.length; i++) {
if(datalist[i].id) {
let item = {
'id': datalist[i].id
};
id.push(item);
}
}
this.deleteUnitCostData(id);
}
});
}
showModal = () => {
this.setState({
visible: true,
});
};
onSelectChange = (selectedRowKeys, record) => {
console.log(selectedRowKeys, record);
this.setState({ selectedRowKeys, record});
};
//递归实现子级可编辑
columnseditable = (data) => {
let newdata = data.map(col => {
if(!col.editable) {
return {
...col,
};
}
if(col.children) {
col.children = this.columnseditable(col.children);
}
return {
...col,
onCell: record => ({
record,
editable: col.editable,
dataIndex: col.dataIndex,
title: col.title,
handleSave: this.handleSave,
}),
};
});
return newdata;
}
render() {
const { dataSource, selectedRowKeys} = this.state;
const components = {
body: {
row: EditableFormRow,
cell: EditableCell,
},
};
const rowSelection = {
selectedRowKeys,
onChange: this.onSelectChange,
};
const hasSelected = selectedRowKeys.length > 0;
const columns = this.columnseditable(this.columns);
return (
<div className="unit_cost">
<div className='title'>
<span className="table-title">机组边际成本基本数据表</span>
<span className="save">
<Button
type="primary"
style={{backgroundColor: '#40a9ff', border: 'none'}}
onClick = {this.add}
>添加</Button></span>
<span className="save">
<Button
type="primary"
onClick = {this.save}
>保存</Button></span>
<span className="save">
<Button
style={{color: 'white'}}
type="danger"
onClick = {this.delete}
disabled={!hasSelected}
>删除</Button></span>
<Modal
title="Modal"
visible={this.state.visible}
>
</Modal>
</div>
<div className="table">
<Table
className="tables"
components={components}
rowClassName={() => 'editable-row'}
bordered
dataSource={dataSource}
// scroll={true} //这个为true时,删除完所有数据后会有bug,目前解决办法就是变为false或者删除
columns={columns}
pagination={{
current: this.state.currentPage,
pageSize: this.state.pageSize,
onChange: (page, pageSize) => this.setState({currentPage: page, pageSize: pageSize}),
}}
rowSelection={rowSelection}
rowKey={(record, index)=>record.id}
/>,
</div>
</div>
);
}
}
export default UnitCost;