TableForm.js 6.37 KB
Newer Older
1
import React, { PureComponent } from 'react';
jim chen's avatar
jim chen committed
2 3
import Debounce from 'lodash-decorators/debounce';
import Bind from 'lodash-decorators/bind';
afc163's avatar
afc163 committed
4
import { Table, Button, Input, message, Popconfirm, Divider } from 'antd';
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
import styles from './style.less';

export default class TableForm extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      data: props.value,
    };
  }
  componentWillReceiveProps(nextProps) {
    if ('value' in nextProps) {
      this.setState({
        data: nextProps.value,
      });
    }
  }
afc163's avatar
afc163 committed
22 23
  getRowByKey(key, newData) {
    return (newData || this.state.data).filter(item => item.key === key)[0];
24 25 26 27 28 29 30 31 32 33 34 35 36 37
  }
  index = 0;
  cacheOriginData = {};
  handleSubmit = (e) => {
    e.preventDefault();
    this.props.form.validateFieldsAndScroll((err, values) => {
      if (!err) {
        this.props.dispatch({
          type: 'form/submit',
          payload: values,
        });
      }
    });
  }
jim chen's avatar
jim chen committed
38 39
  @Bind()
  @Debounce(400)
40 41
  toggleEditable(e, key) {
    e.preventDefault();
afc163's avatar
afc163 committed
42 43
    const newData = this.state.data.map(item => ({ ...item }));
    const target = this.getRowByKey(key, newData);
44 45 46 47 48 49
    if (target) {
      // 进入编辑状态时保存原始数据
      if (!target.editable) {
        this.cacheOriginData[key] = { ...target };
      }
      target.editable = !target.editable;
afc163's avatar
afc163 committed
50
      this.setState({ data: newData });
51 52
    }
  }
afc163's avatar
afc163 committed
53
  remove(key) {
54 55 56 57 58
    const newData = this.state.data.filter(item => item.key !== key);
    this.setState({ data: newData });
    this.props.onChange(newData);
  }
  newMember = () => {
afc163's avatar
afc163 committed
59
    const newData = this.state.data.map(item => ({ ...item }));
60 61 62 63 64 65
    newData.push({
      key: `NEW_TEMP_ID_${this.index}`,
      workId: '',
      name: '',
      department: '',
      editable: true,
afc163's avatar
afc163 committed
66
      isNew: true,
67 68 69 70
    });
    this.index += 1;
    this.setState({ data: newData });
  }
afc163's avatar
afc163 committed
71 72 73 74 75
  handleKeyPress(e, key) {
    if (e.key === 'Enter') {
      this.saveRow(e, key);
    }
  }
76
  handleFieldChange(e, fieldName, key) {
afc163's avatar
afc163 committed
77 78
    const newData = this.state.data.map(item => ({ ...item }));
    const target = this.getRowByKey(key, newData);
79 80 81 82 83 84
    if (target) {
      target[fieldName] = e.target.value;
      this.setState({ data: newData });
    }
  }
  saveRow(e, key) {
afc163's avatar
afc163 committed
85 86 87 88 89 90 91 92 93 94 95
    e.persist();
    // save field when blur input
    setTimeout(() => {
      if (document.activeElement.tagName === 'INPUT' &&
          document.activeElement !== e.target) {
        return;
      }
      if (this.clickedCancel) {
        this.clickedCancel = false;
        return;
      }
afc163's avatar
afc163 committed
96
      const target = this.getRowByKey(key) || {};
afc163's avatar
afc163 committed
97 98
      if (!target.workId || !target.name || !target.department) {
        message.error('请填写完整成员信息。');
afc163's avatar
afc163 committed
99
        e.target.focus();
afc163's avatar
afc163 committed
100 101
        return;
      }
afc163's avatar
afc163 committed
102
      delete target.isNew;
afc163's avatar
afc163 committed
103 104 105
      this.toggleEditable(e, key);
      this.props.onChange(this.state.data);
    }, 10);
106 107
  }
  cancel(e, key) {
afc163's avatar
afc163 committed
108
    this.clickedCancel = true;
109
    e.preventDefault();
afc163's avatar
afc163 committed
110 111
    const newData = this.state.data.map(item => ({ ...item }));
    const target = this.getRowByKey(key, newData);
112 113 114 115 116
    if (this.cacheOriginData[key]) {
      Object.assign(target, this.cacheOriginData[key]);
      target.editable = false;
      delete this.cacheOriginData[key];
    }
afc163's avatar
afc163 committed
117
    this.setState({ data: newData });
118 119 120 121 122 123 124 125 126 127 128 129 130 131
  }
  render() {
    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)}
afc163's avatar
afc163 committed
132 133
              onBlur={e => this.saveRow(e, record.key)}
              onKeyPress={e => this.handleKeyPress(e, record.key)}
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
              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)}
afc163's avatar
afc163 committed
151 152
              onBlur={e => this.saveRow(e, record.key)}
              onKeyPress={e => this.handleKeyPress(e, record.key)}
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
              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)}
afc163's avatar
afc163 committed
170 171
              onBlur={e => this.saveRow(e, record.key)}
              onKeyPress={e => this.handleKeyPress(e, record.key)}
172 173 174 175 176 177 178 179 180 181 182
              placeholder="所属部门"
            />
          );
        }
        return text;
      },
    }, {
      title: '操作',
      key: 'action',
      render: (text, record) => {
        if (record.editable) {
afc163's avatar
afc163 committed
183
          if (record.isNew) {
184 185
            return (
              <span>
afc163's avatar
afc163 committed
186
                <a>保存</a>
afc163's avatar
afc163 committed
187
                <Divider type="vertical" />
afc163's avatar
afc163 committed
188 189 190
                <Popconfirm title="是否要删除此行?" onConfirm={() => this.remove(record.key)}>
                  <a>删除</a>
                </Popconfirm>
191 192 193 194 195
              </span>
            );
          }
          return (
            <span>
afc163's avatar
afc163 committed
196
              <a>保存</a>
afc163's avatar
afc163 committed
197
              <Divider type="vertical" />
198 199 200 201 202 203 204
              <a onClick={e => this.cancel(e, record.key)}>取消</a>
            </span>
          );
        }
        return (
          <span>
            <a onClick={e => this.toggleEditable(e, record.key)}>编辑</a>
afc163's avatar
afc163 committed
205
            <Divider type="vertical" />
afc163's avatar
afc163 committed
206 207 208
            <Popconfirm title="是否要删除此行?" onConfirm={() => this.remove(record.key)}>
              <a>删除</a>
            </Popconfirm>
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
          </span>
        );
      },
    }];

    return (
      <div>
        <Table
          columns={columns}
          dataSource={this.state.data}
          pagination={false}
          rowClassName={(record) => {
            return record.editable ? styles.editable : '';
          }}
        />
        <Button
225
          style={{ width: '100%', marginTop: 16, marginBottom: 8 }}
226 227 228 229 230 231 232 233 234 235
          type="dashed"
          onClick={this.newMember}
          icon="plus"
        >
          新增成员
        </Button>
      </div>
    );
  }
}