TableForm.js 7.07 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 5
import styles from './style.less';

export default class TableForm extends PureComponent {
陈帅's avatar
陈帅 committed
6 7 8 9
  index = 0;

  cacheOriginData = {};

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

    this.state = {
      data: props.value,
jim chen's avatar
jim chen committed
15
      loading: false,
16
      editData: [],
17 18
    };
  }
jim's avatar
jim committed
19

jim's avatar
jim committed
20 21 22 23 24 25 26 27
  static getDerivedStateFromProps(nextProps) {
    if ('value' in nextProps) {
      return {
        data: nextProps.value,
      };
    }
    return null;
  }
陈帅's avatar
陈帅 committed
28

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

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

  newMember = () => {
    this.index += 1;
    this.setState({
      editData: [
        {
          key: `NEW_TEMP_ID_${this.index}`,
          workId: '',
          name: '',
          department: '',
          editable: true,
          isNew: true,
        },
      ],
    });
  };

afc163's avatar
afc163 committed
65
  remove(key) {
陈帅's avatar
陈帅 committed
66 67
    const { editData, data } = this.state;
    const { onChange } = this.props;
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
    const editItem = editData.find(item => item.key === key);
    if (editItem && editItem.key) {
      // 如果存在缓存
      if (this.cacheOriginData[key]) {
        data.push(this.cacheOriginData[key]);
        this.setState(
          {
            data,
          },
          () => {
            delete this.cacheOriginData[key];
          }
        );
      }
      // 从 editData 中删除
      this.setState({
        editData: editData.filter(item => item.key !== key),
      });
      return;
    }
陈帅's avatar
陈帅 committed
88
    const newData = data.filter(item => item.key !== key);
89
    this.setState({ data: newData });
陈帅's avatar
陈帅 committed
90
    onChange(newData);
afc163's avatar
afc163 committed
91
  }
陈帅's avatar
陈帅 committed
92

93
  handleFieldChange(e, fieldName, key) {
陈帅's avatar
陈帅 committed
94 95
    const { data } = this.state;
    const newData = data.map(item => ({ ...item }));
afc163's avatar
afc163 committed
96
    const target = this.getRowByKey(key, newData);
97 98 99 100 101
    if (target) {
      target[fieldName] = e.target.value;
      this.setState({ data: newData });
    }
  }
陈帅's avatar
陈帅 committed
102

103
  saveRow(e, key) {
陈帅's avatar
陈帅 committed
104 105
    const { data } = this.state;
    const { onChange } = this.props;
afc163's avatar
afc163 committed
106
    e.persist();
jim chen's avatar
jim chen committed
107 108 109
    this.setState({
      loading: true,
    });
afc163's avatar
afc163 committed
110 111 112 113 114
    setTimeout(() => {
      if (this.clickedCancel) {
        this.clickedCancel = false;
        return;
      }
afc163's avatar
afc163 committed
115
      const target = this.getRowByKey(key) || {};
afc163's avatar
afc163 committed
116 117
      if (!target.workId || !target.name || !target.department) {
        message.error('请填写完整成员信息。');
afc163's avatar
afc163 committed
118
        e.target.focus();
119 120 121
        this.setState({
          loading: false,
        });
afc163's avatar
afc163 committed
122 123
        return;
      }
afc163's avatar
afc163 committed
124
      delete target.isNew;
afc163's avatar
afc163 committed
125
      this.toggleEditable(e, key);
陈帅's avatar
陈帅 committed
126
      onChange(data);
jim chen's avatar
jim chen committed
127 128 129 130
      this.setState({
        loading: false,
      });
    }, 500);
131
  }
陈帅's avatar
陈帅 committed
132

133
  cancel(e, key) {
陈帅's avatar
陈帅 committed
134
    const { data } = this.state;
afc163's avatar
afc163 committed
135
    this.clickedCancel = true;
136
    e.preventDefault();
陈帅's avatar
陈帅 committed
137
    const newData = data.map(item => ({ ...item }));
afc163's avatar
afc163 committed
138
    const target = this.getRowByKey(key, newData);
139 140 141 142 143
    if (this.cacheOriginData[key]) {
      Object.assign(target, this.cacheOriginData[key]);
      target.editable = false;
      delete this.cacheOriginData[key];
    }
afc163's avatar
afc163 committed
144
    this.setState({ data: newData });
145
    this.clickedCancel = false;
146
  }
陈帅's avatar
陈帅 committed
147

148
  render() {
jim's avatar
jim committed
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
    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;
        },
169
      },
jim's avatar
jim committed
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
      {
        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;
        },
188
      },
jim's avatar
jim committed
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
      {
        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;
        },
207
      },
jim's avatar
jim committed
208 209 210 211
      {
        title: '操作',
        key: 'action',
        render: (text, record) => {
陈帅's avatar
陈帅 committed
212 213
          const { loading } = this.state;
          if (!!record.editable && loading) {
jim's avatar
jim committed
214 215 216 217 218 219 220 221 222 223 224 225 226 227
            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>
              );
            }
228 229
            return (
              <span>
jim's avatar
jim committed
230
                <a onClick={e => this.saveRow(e, record.key)}>保存</a>
afc163's avatar
afc163 committed
231
                <Divider type="vertical" />
jim's avatar
jim committed
232
                <a onClick={e => this.cancel(e, record.key)}>取消</a>
233 234 235 236 237
              </span>
            );
          }
          return (
            <span>
jim's avatar
jim committed
238
              <a onClick={e => this.toggleEditable(e, record.key)}>编辑</a>
afc163's avatar
afc163 committed
239
              <Divider type="vertical" />
jim's avatar
jim committed
240 241 242
              <Popconfirm title="是否要删除此行?" onConfirm={() => this.remove(record.key)}>
                <a>删除</a>
              </Popconfirm>
243 244
            </span>
          );
jim's avatar
jim committed
245
        },
246
      },
jim's avatar
jim committed
247
    ];
陈帅's avatar
陈帅 committed
248 249
    const { data, editData, loading } = this.state;
    const dataSource = data.concat(editData);
250
    return (
陈帅's avatar
陈帅 committed
251
      <Fragment>
252
        <Table
陈帅's avatar
陈帅 committed
253
          loading={loading}
254
          columns={columns}
255
          dataSource={dataSource}
256
          pagination={false}
jim's avatar
jim committed
257
          rowClassName={record => {
258 259 260 261
            return record.editable ? styles.editable : '';
          }}
        />
        <Button
262
          style={{ width: '100%', marginTop: 16, marginBottom: 8 }}
263 264 265 266 267 268
          type="dashed"
          onClick={this.newMember}
          icon="plus"
        >
          新增成员
        </Button>
陈帅's avatar
陈帅 committed
269
      </Fragment>
270 271 272
    );
  }
}