TableForm.tsx 6.57 KB
Newer Older
陈帅's avatar
陈帅 committed
1
import React, { PureComponent, Fragment } from 'react';
afc163's avatar
afc163 committed
2
import { Table, Button, Input, message, Popconfirm, Divider } from 'antd';
3 4
import { isEqual } from 'lodash';
import styles from '../style.less';
5

lijiehua's avatar
lijiehua committed
6
class TableForm extends PureComponent {
陈帅's avatar
陈帅 committed
7 8 9 10 11 12 13 14 15
  static getDerivedStateFromProps(nextProps, preState) {
    if (isEqual(nextProps.value, preState.value)) {
      return null;
    }
    return {
      data: nextProps.value,
      value: nextProps.value,
    };
  }
16 17 18
  index = 0;

  cacheOriginData = {};
陈帅's avatar
陈帅 committed
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
  columns = [
    {
      title: '成员姓名',
      dataIndex: 'name',
      key: 'name',
      width: '20%',
      render: (text, record) => {
        if (record.editable) {
          return (
            <Input
              value={text}
              autoFocus
              onChange={e => this.handleFieldChange(e, 'name', record.key)}
              onKeyPress={e => this.handleKeyPress(e, record.key)}
              placeholder="成员姓名"
            />
          );
        }
        return text;
      },
    },
    {
      title: '工号',
      dataIndex: 'workId',
      key: 'workId',
      width: '20%',
      render: (text, record) => {
        if (record.editable) {
          return (
            <Input
              value={text}
              onChange={e => this.handleFieldChange(e, 'workId', record.key)}
              onKeyPress={e => this.handleKeyPress(e, record.key)}
              placeholder="工号"
            />
          );
        }
        return text;
      },
    },
    {
      title: '所属部门',
      dataIndex: 'department',
      key: 'department',
      width: '40%',
      render: (text, record) => {
        if (record.editable) {
          return (
            <Input
              value={text}
              onChange={e => this.handleFieldChange(e, 'department', record.key)}
              onKeyPress={e => this.handleKeyPress(e, record.key)}
              placeholder="所属部门"
            />
          );
        }
        return text;
      },
    },
    {
      title: '操作',
      key: 'action',
      render: (text, record) => {
        const { loading } = this.state;
        if (!!record.editable && loading) {
          return null;
        }
        if (record.editable) {
          if (record.isNew) {
            return (
              <span>
                <a onClick={e => this.saveRow(e, record.key)}>添加</a>
                <Divider type="vertical" />
                <Popconfirm title="是否要删除此行?" onConfirm={() => this.remove(record.key)}>
                  <a>删除</a>
                </Popconfirm>
              </span>
            );
          }
          return (
            <span>
              <a onClick={e => this.saveRow(e, record.key)}>保存</a>
              <Divider type="vertical" />
              <a onClick={e => this.cancel(e, record.key)}>取消</a>
            </span>
          );
        }
        return (
          <span>
            <a onClick={e => this.toggleEditable(e, record.key)}>编辑</a>
            <Divider type="vertical" />
            <Popconfirm title="是否要删除此行?" onConfirm={() => this.remove(record.key)}>
              <a>删除</a>
            </Popconfirm>
          </span>
        );
      },
    },
  ];
陈帅's avatar
陈帅 committed
118

119 120 121 122 123
  constructor(props) {
    super(props);

    this.state = {
      data: props.value,
jim chen's avatar
jim chen committed
124
      loading: false,
125 126
      /* eslint-disable-next-line react/no-unused-state */
      value: props.value,
127 128
    };
  }
jim's avatar
jim committed
129

afc163's avatar
afc163 committed
130
  getRowByKey(key, newData) {
陈帅's avatar
陈帅 committed
131 132
    const { data } = this.state;
    return (newData || data).filter(item => item.key === key)[0];
133
  }
陈帅's avatar
陈帅 committed
134

jim's avatar
jim committed
135
  toggleEditable = (e, key) => {
136
    e.preventDefault();
陈帅's avatar
陈帅 committed
137 138
    const { data } = this.state;
    const newData = data.map(item => ({ ...item }));
afc163's avatar
afc163 committed
139
    const target = this.getRowByKey(key, newData);
140 141 142 143 144 145
    if (target) {
      // 进入编辑状态时保存原始数据
      if (!target.editable) {
        this.cacheOriginData[key] = { ...target };
      }
      target.editable = !target.editable;
afc163's avatar
afc163 committed
146
      this.setState({ data: newData });
147
    }
jim's avatar
jim committed
148
  };
陈帅's avatar
陈帅 committed
149 150

  newMember = () => {
151 152 153 154 155 156 157 158 159
    const { data } = this.state;
    const newData = data.map(item => ({ ...item }));
    newData.push({
      key: `NEW_TEMP_ID_${this.index}`,
      workId: '',
      name: '',
      department: '',
      editable: true,
      isNew: true,
陈帅's avatar
陈帅 committed
160
    });
161 162
    this.index += 1;
    this.setState({ data: newData });
陈帅's avatar
陈帅 committed
163 164
  };

afc163's avatar
afc163 committed
165
  remove(key) {
166
    const { data } = this.state;
陈帅's avatar
陈帅 committed
167 168
    const { onChange } = this.props;
    const newData = data.filter(item => item.key !== key);
169
    this.setState({ data: newData });
陈帅's avatar
陈帅 committed
170
    onChange(newData);
afc163's avatar
afc163 committed
171
  }
陈帅's avatar
陈帅 committed
172

173 174 175 176 177 178
  handleKeyPress(e, key) {
    if (e.key === 'Enter') {
      this.saveRow(e, key);
    }
  }

179
  handleFieldChange(e, fieldName, key) {
陈帅's avatar
陈帅 committed
180 181
    const { data } = this.state;
    const newData = data.map(item => ({ ...item }));
afc163's avatar
afc163 committed
182
    const target = this.getRowByKey(key, newData);
183 184 185 186 187
    if (target) {
      target[fieldName] = e.target.value;
      this.setState({ data: newData });
    }
  }
陈帅's avatar
陈帅 committed
188

189
  saveRow(e, key) {
afc163's avatar
afc163 committed
190
    e.persist();
jim chen's avatar
jim chen committed
191 192 193
    this.setState({
      loading: true,
    });
afc163's avatar
afc163 committed
194 195 196 197 198
    setTimeout(() => {
      if (this.clickedCancel) {
        this.clickedCancel = false;
        return;
      }
afc163's avatar
afc163 committed
199
      const target = this.getRowByKey(key) || {};
afc163's avatar
afc163 committed
200 201
      if (!target.workId || !target.name || !target.department) {
        message.error('请填写完整成员信息。');
afc163's avatar
afc163 committed
202
        e.target.focus();
203 204 205
        this.setState({
          loading: false,
        });
afc163's avatar
afc163 committed
206 207
        return;
      }
afc163's avatar
afc163 committed
208
      delete target.isNew;
afc163's avatar
afc163 committed
209
      this.toggleEditable(e, key);
WeiYang Qiu's avatar
WeiYang Qiu committed
210 211
      const { data } = this.state;
      const { onChange } = this.props;
陈帅's avatar
陈帅 committed
212
      onChange(data);
jim chen's avatar
jim chen committed
213 214 215 216
      this.setState({
        loading: false,
      });
    }, 500);
217
  }
陈帅's avatar
陈帅 committed
218

219
  cancel(e, key) {
afc163's avatar
afc163 committed
220
    this.clickedCancel = true;
221
    e.preventDefault();
222
    const { data } = this.state;
陈帅's avatar
陈帅 committed
223
    const newData = data.map(item => ({ ...item }));
afc163's avatar
afc163 committed
224
    const target = this.getRowByKey(key, newData);
225 226 227 228
    if (this.cacheOriginData[key]) {
      Object.assign(target, this.cacheOriginData[key]);
      delete this.cacheOriginData[key];
    }
WeiYang Qiu's avatar
WeiYang Qiu committed
229
    target.editable = false;
afc163's avatar
afc163 committed
230
    this.setState({ data: newData });
231
    this.clickedCancel = false;
232 233
  }
  render() {
234 235
    const { loading, data } = this.state;

236
    return (
陈帅's avatar
陈帅 committed
237
      <Fragment>
238
        <Table
陈帅's avatar
陈帅 committed
239
          loading={loading}
陈帅's avatar
陈帅 committed
240
          columns={this.columns}
241
          dataSource={data}
242
          pagination={false}
243
          rowClassName={record => (record.editable ? styles.editable : '')}
244 245
        />
        <Button
246
          style={{ width: '100%', marginTop: 16, marginBottom: 8 }}
247 248 249 250 251 252
          type="dashed"
          onClick={this.newMember}
          icon="plus"
        >
          新增成员
        </Button>
陈帅's avatar
陈帅 committed
253
      </Fragment>
254 255 256
    );
  }
}
lijiehua's avatar
lijiehua committed
257 258

export default TableForm;