TableForm.js 6.76 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';
afc163's avatar
afc163 committed
3
import isEqual from 'lodash/isEqual';
4 5 6
import styles from './style.less';

export default class TableForm extends PureComponent {
7 8 9
  index = 0;

  cacheOriginData = {};
陈帅's avatar
陈帅 committed
10

11 12 13 14 15
  constructor(props) {
    super(props);

    this.state = {
      data: props.value,
jim chen's avatar
jim chen committed
16
      loading: false,
17 18
      /* eslint-disable-next-line react/no-unused-state */
      value: props.value,
19 20
    };
  }
jim's avatar
jim committed
21

22 23 24
  static getDerivedStateFromProps(nextProps, preState) {
    if (isEqual(nextProps.value, preState.value)) {
      return null;
jim's avatar
jim committed
25
    }
26 27 28 29
    return {
      data: nextProps.value,
      value: nextProps.value,
    };
jim's avatar
jim committed
30
  }
陈帅's avatar
陈帅 committed
31

afc163's avatar
afc163 committed
32
  getRowByKey(key, newData) {
陈帅's avatar
陈帅 committed
33 34
    const { data } = this.state;
    return (newData || data).filter(item => item.key === key)[0];
35
  }
陈帅's avatar
陈帅 committed
36

jim's avatar
jim committed
37
  toggleEditable = (e, key) => {
38
    e.preventDefault();
陈帅's avatar
陈帅 committed
39 40
    const { data } = this.state;
    const newData = data.map(item => ({ ...item }));
afc163's avatar
afc163 committed
41
    const target = this.getRowByKey(key, newData);
42 43 44 45 46 47
    if (target) {
      // 进入编辑状态时保存原始数据
      if (!target.editable) {
        this.cacheOriginData[key] = { ...target };
      }
      target.editable = !target.editable;
afc163's avatar
afc163 committed
48
      this.setState({ data: newData });
49
    }
jim's avatar
jim committed
50
  };
陈帅's avatar
陈帅 committed
51 52

  newMember = () => {
53 54 55 56 57 58 59 60 61
    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
62
    });
63 64
    this.index += 1;
    this.setState({ data: newData });
陈帅's avatar
陈帅 committed
65 66
  };

afc163's avatar
afc163 committed
67
  remove(key) {
68
    const { data } = this.state;
陈帅's avatar
陈帅 committed
69 70
    const { onChange } = this.props;
    const newData = data.filter(item => item.key !== key);
71
    this.setState({ data: newData });
陈帅's avatar
陈帅 committed
72
    onChange(newData);
afc163's avatar
afc163 committed
73
  }
陈帅's avatar
陈帅 committed
74

75 76 77 78 79 80
  handleKeyPress(e, key) {
    if (e.key === 'Enter') {
      this.saveRow(e, key);
    }
  }

81
  handleFieldChange(e, fieldName, key) {
陈帅's avatar
陈帅 committed
82 83
    const { data } = this.state;
    const newData = data.map(item => ({ ...item }));
afc163's avatar
afc163 committed
84
    const target = this.getRowByKey(key, newData);
85 86 87 88 89
    if (target) {
      target[fieldName] = e.target.value;
      this.setState({ data: newData });
    }
  }
陈帅's avatar
陈帅 committed
90

91
  saveRow(e, key) {
afc163's avatar
afc163 committed
92
    e.persist();
jim chen's avatar
jim chen committed
93 94 95
    this.setState({
      loading: true,
    });
afc163's avatar
afc163 committed
96 97 98 99 100
    setTimeout(() => {
      if (this.clickedCancel) {
        this.clickedCancel = false;
        return;
      }
afc163's avatar
afc163 committed
101
      const target = this.getRowByKey(key) || {};
afc163's avatar
afc163 committed
102 103
      if (!target.workId || !target.name || !target.department) {
        message.error('请填写完整成员信息。');
afc163's avatar
afc163 committed
104
        e.target.focus();
105 106 107
        this.setState({
          loading: false,
        });
afc163's avatar
afc163 committed
108 109
        return;
      }
afc163's avatar
afc163 committed
110
      delete target.isNew;
afc163's avatar
afc163 committed
111
      this.toggleEditable(e, key);
WeiYang Qiu's avatar
WeiYang Qiu committed
112 113
      const { data } = this.state;
      const { onChange } = this.props;
陈帅's avatar
陈帅 committed
114
      onChange(data);
jim chen's avatar
jim chen committed
115 116 117 118
      this.setState({
        loading: false,
      });
    }, 500);
119
  }
陈帅's avatar
陈帅 committed
120

121
  cancel(e, key) {
afc163's avatar
afc163 committed
122
    this.clickedCancel = true;
123
    e.preventDefault();
124
    const { data } = this.state;
陈帅's avatar
陈帅 committed
125
    const newData = data.map(item => ({ ...item }));
afc163's avatar
afc163 committed
126
    const target = this.getRowByKey(key, newData);
127 128 129 130
    if (this.cacheOriginData[key]) {
      Object.assign(target, this.cacheOriginData[key]);
      delete this.cacheOriginData[key];
    }
WeiYang Qiu's avatar
WeiYang Qiu committed
131
    target.editable = false;
afc163's avatar
afc163 committed
132
    this.setState({ data: newData });
133
    this.clickedCancel = false;
134
  }
陈帅's avatar
陈帅 committed
135

136
  render() {
jim's avatar
jim committed
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
    const 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;
        },
157
      },
jim's avatar
jim committed
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
      {
        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;
        },
176
      },
jim's avatar
jim committed
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
      {
        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;
        },
195
      },
jim's avatar
jim committed
196 197 198 199
      {
        title: '操作',
        key: 'action',
        render: (text, record) => {
陈帅's avatar
陈帅 committed
200 201
          const { loading } = this.state;
          if (!!record.editable && loading) {
jim's avatar
jim committed
202 203 204 205 206 207 208 209 210 211 212 213 214 215
            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>
              );
            }
216 217
            return (
              <span>
jim's avatar
jim committed
218
                <a onClick={e => this.saveRow(e, record.key)}>保存</a>
afc163's avatar
afc163 committed
219
                <Divider type="vertical" />
jim's avatar
jim committed
220
                <a onClick={e => this.cancel(e, record.key)}>取消</a>
221 222 223 224 225
              </span>
            );
          }
          return (
            <span>
jim's avatar
jim committed
226
              <a onClick={e => this.toggleEditable(e, record.key)}>编辑</a>
afc163's avatar
afc163 committed
227
              <Divider type="vertical" />
jim's avatar
jim committed
228 229 230
              <Popconfirm title="是否要删除此行?" onConfirm={() => this.remove(record.key)}>
                <a>删除</a>
              </Popconfirm>
231 232
            </span>
          );
jim's avatar
jim committed
233
        },
234
      },
jim's avatar
jim committed
235
    ];
236 237 238

    const { loading, data } = this.state;

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