最近因为工作需要,要基于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;