TableForm.tsx 7.54 KB
Newer Older
陈帅's avatar
陈帅 committed
1 2 3
import { Button, Divider, Input, Popconfirm, Table, message } from 'antd';
import React, { Fragment, PureComponent } from 'react';

4 5
import { isEqual } from 'lodash';
import styles from '../style.less';
6

陈帅's avatar
陈帅 committed
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
interface TableFormDateType {
  key: string;
  workId?: string;
  name?: string;
  department?: string;
  isNew?: boolean;
  editable?: boolean;
}
interface TableFormProps {
  loading?: boolean;
  value?: TableFormDateType[];
  onChange?: (value: TableFormDateType[]) => void;
}

interface TableFormState {
  loading?: boolean;
  value?: TableFormDateType[];
  data?: TableFormDateType[];
}
class TableForm extends PureComponent<TableFormProps, TableFormState> {
  static getDerivedStateFromProps(nextProps: TableFormProps, preState: TableFormState) {
陈帅's avatar
陈帅 committed
28 29 30 31 32 33 34 35
    if (isEqual(nextProps.value, preState.value)) {
      return null;
    }
    return {
      data: nextProps.value,
      value: nextProps.value,
    };
  }
陈帅's avatar
陈帅 committed
36

陈帅's avatar
陈帅 committed
37 38
  clickedCancel: boolean = false;

39 40 41
  index = 0;

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

陈帅's avatar
陈帅 committed
43 44 45 46 47 48
  columns = [
    {
      title: '成员姓名',
      dataIndex: 'name',
      key: 'name',
      width: '20%',
陈帅's avatar
陈帅 committed
49
      render: (text: string, record: TableFormDateType) => {
陈帅's avatar
陈帅 committed
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
        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%',
陈帅's avatar
陈帅 committed
69
      render: (text: string, record: TableFormDateType) => {
陈帅's avatar
陈帅 committed
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
        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%',
陈帅's avatar
陈帅 committed
88
      render: (text: string, record: TableFormDateType) => {
陈帅's avatar
陈帅 committed
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
        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',
陈帅's avatar
陈帅 committed
105
      render: (text: string, record: TableFormDateType) => {
陈帅's avatar
陈帅 committed
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
        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
142

陈帅's avatar
陈帅 committed
143
  constructor(props: TableFormProps) {
144 145 146
    super(props);
    this.state = {
      data: props.value,
jim chen's avatar
jim chen committed
147
      loading: false,
148
      value: props.value,
149 150
    };
  }
jim's avatar
jim committed
151

陈帅's avatar
陈帅 committed
152 153
  getRowByKey(key: string, newData?: TableFormDateType[]) {
    const { data = [] } = this.state;
陈帅's avatar
陈帅 committed
154
    return (newData || data).filter(item => item.key === key)[0];
155
  }
陈帅's avatar
陈帅 committed
156

陈帅's avatar
陈帅 committed
157
  toggleEditable = (e: React.MouseEvent | React.KeyboardEvent, key: string) => {
158
    e.preventDefault();
陈帅's avatar
陈帅 committed
159
    const { data = [] } = this.state;
陈帅's avatar
陈帅 committed
160
    const newData = data.map(item => ({ ...item }));
afc163's avatar
afc163 committed
161
    const target = this.getRowByKey(key, newData);
162 163 164 165 166 167
    if (target) {
      // 进入编辑状态时保存原始数据
      if (!target.editable) {
        this.cacheOriginData[key] = { ...target };
      }
      target.editable = !target.editable;
afc163's avatar
afc163 committed
168
      this.setState({ data: newData });
169
    }
jim's avatar
jim committed
170
  };
陈帅's avatar
陈帅 committed
171 172

  newMember = () => {
陈帅's avatar
陈帅 committed
173
    const { data = [] } = this.state;
174 175 176 177 178 179 180 181
    const newData = data.map(item => ({ ...item }));
    newData.push({
      key: `NEW_TEMP_ID_${this.index}`,
      workId: '',
      name: '',
      department: '',
      editable: true,
      isNew: true,
陈帅's avatar
陈帅 committed
182
    });
183 184
    this.index += 1;
    this.setState({ data: newData });
陈帅's avatar
陈帅 committed
185 186
  };

陈帅's avatar
陈帅 committed
187 188
  remove(key: string) {
    const { data = [] } = this.state;
陈帅's avatar
陈帅 committed
189 190
    const { onChange } = this.props;
    const newData = data.filter(item => item.key !== key);
191
    this.setState({ data: newData });
陈帅's avatar
陈帅 committed
192 193 194
    if (onChange) {
      onChange(newData);
    }
afc163's avatar
afc163 committed
195
  }
陈帅's avatar
陈帅 committed
196

陈帅's avatar
陈帅 committed
197
  handleKeyPress(e: React.KeyboardEvent, key: string) {
198 199 200 201 202
    if (e.key === 'Enter') {
      this.saveRow(e, key);
    }
  }

陈帅's avatar
陈帅 committed
203 204
  handleFieldChange(e: React.ChangeEvent<HTMLInputElement>, fieldName: string, key: string) {
    const { data = [] } = this.state;
陈帅's avatar
陈帅 committed
205
    const newData = [...data];
afc163's avatar
afc163 committed
206
    const target = this.getRowByKey(key, newData);
207 208 209 210 211
    if (target) {
      target[fieldName] = e.target.value;
      this.setState({ data: newData });
    }
  }
陈帅's avatar
陈帅 committed
212

陈帅's avatar
陈帅 committed
213
  saveRow(e: React.MouseEvent | React.KeyboardEvent, key: string) {
afc163's avatar
afc163 committed
214
    e.persist();
jim chen's avatar
jim chen committed
215 216 217
    this.setState({
      loading: true,
    });
afc163's avatar
afc163 committed
218 219 220 221 222
    setTimeout(() => {
      if (this.clickedCancel) {
        this.clickedCancel = false;
        return;
      }
afc163's avatar
afc163 committed
223
      const target = this.getRowByKey(key) || {};
afc163's avatar
afc163 committed
224 225
      if (!target.workId || !target.name || !target.department) {
        message.error('请填写完整成员信息。');
陈帅's avatar
陈帅 committed
226
        (e.target as HTMLInputElement).focus();
227 228 229
        this.setState({
          loading: false,
        });
afc163's avatar
afc163 committed
230 231
        return;
      }
afc163's avatar
afc163 committed
232
      delete target.isNew;
afc163's avatar
afc163 committed
233
      this.toggleEditable(e, key);
陈帅's avatar
陈帅 committed
234
      const { data = [] } = this.state;
WeiYang Qiu's avatar
WeiYang Qiu committed
235
      const { onChange } = this.props;
陈帅's avatar
陈帅 committed
236 237 238
      if (onChange) {
        onChange(data);
      }
jim chen's avatar
jim chen committed
239 240 241 242
      this.setState({
        loading: false,
      });
    }, 500);
243
  }
陈帅's avatar
陈帅 committed
244

陈帅's avatar
陈帅 committed
245
  cancel(e: React.MouseEvent, key: string) {
afc163's avatar
afc163 committed
246
    this.clickedCancel = true;
247
    e.preventDefault();
陈帅's avatar
陈帅 committed
248
    const { data = [] } = this.state;
陈帅's avatar
陈帅 committed
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
    const newData = [...data];
    newData.map(item => {
      if (item.key === key) {
        if (this.cacheOriginData[key]) {
          delete this.cacheOriginData[key];
          return {
            ...item,
            ...this.cacheOriginData[key],
            editable: false,
          };
        }
      }
      return item;
    });

afc163's avatar
afc163 committed
264
    this.setState({ data: newData });
265
    this.clickedCancel = false;
266
  }
陈帅's avatar
陈帅 committed
267

268
  render() {
269 270
    const { loading, data } = this.state;

271
    return (
陈帅's avatar
陈帅 committed
272
      <Fragment>
陈帅's avatar
陈帅 committed
273
        <Table<TableFormDateType>
陈帅's avatar
陈帅 committed
274
          loading={loading}
陈帅's avatar
陈帅 committed
275
          columns={this.columns}
276
          dataSource={data}
277
          pagination={false}
278
          rowClassName={record => (record.editable ? styles.editable : '')}
279 280
        />
        <Button
281
          style={{ width: '100%', marginTop: 16, marginBottom: 8 }}
282 283 284 285 286 287
          type="dashed"
          onClick={this.newMember}
          icon="plus"
        >
          新增成员
        </Button>
陈帅's avatar
陈帅 committed
288
      </Fragment>
289 290 291
    );
  }
}
lijiehua's avatar
lijiehua committed
292 293

export default TableForm;