TableForm.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. import React, { PureComponent, Fragment } from 'react';
  2. import { Table, Button, Input, message, Popconfirm, Divider } from 'antd';
  3. import isEqual from 'lodash/isEqual';
  4. import styles from './style.less';
  5. class TableForm extends PureComponent {
  6. index = 0;
  7. cacheOriginData = {};
  8. constructor(props) {
  9. super(props);
  10. this.state = {
  11. data: props.value,
  12. loading: false,
  13. /* eslint-disable-next-line react/no-unused-state */
  14. value: props.value,
  15. };
  16. }
  17. static getDerivedStateFromProps(nextProps, preState) {
  18. if (isEqual(nextProps.value, preState.value)) {
  19. return null;
  20. }
  21. return {
  22. data: nextProps.value,
  23. value: nextProps.value,
  24. };
  25. }
  26. getRowByKey(key, newData) {
  27. const { data } = this.state;
  28. return (newData || data).filter(item => item.key === key)[0];
  29. }
  30. toggleEditable = (e, key) => {
  31. e.preventDefault();
  32. const { data } = this.state;
  33. const newData = data.map(item => ({ ...item }));
  34. const target = this.getRowByKey(key, newData);
  35. if (target) {
  36. // 进入编辑状态时保存原始数据
  37. if (!target.editable) {
  38. this.cacheOriginData[key] = { ...target };
  39. }
  40. target.editable = !target.editable;
  41. this.setState({ data: newData });
  42. }
  43. };
  44. newMember = () => {
  45. const { data } = this.state;
  46. const newData = data.map(item => ({ ...item }));
  47. newData.push({
  48. key: `NEW_TEMP_ID_${this.index}`,
  49. workId: '',
  50. name: '',
  51. department: '',
  52. editable: true,
  53. isNew: true,
  54. });
  55. this.index += 1;
  56. this.setState({ data: newData });
  57. };
  58. remove(key) {
  59. const { data } = this.state;
  60. const { onChange } = this.props;
  61. const newData = data.filter(item => item.key !== key);
  62. this.setState({ data: newData });
  63. onChange(newData);
  64. }
  65. handleKeyPress(e, key) {
  66. if (e.key === 'Enter') {
  67. this.saveRow(e, key);
  68. }
  69. }
  70. handleFieldChange(e, fieldName, key) {
  71. const { data } = this.state;
  72. const newData = data.map(item => ({ ...item }));
  73. const target = this.getRowByKey(key, newData);
  74. if (target) {
  75. target[fieldName] = e.target.value;
  76. this.setState({ data: newData });
  77. }
  78. }
  79. saveRow(e, key) {
  80. e.persist();
  81. this.setState({
  82. loading: true,
  83. });
  84. setTimeout(() => {
  85. if (this.clickedCancel) {
  86. this.clickedCancel = false;
  87. return;
  88. }
  89. const target = this.getRowByKey(key) || {};
  90. if (!target.workId || !target.name || !target.department) {
  91. message.error('请填写完整成员信息。');
  92. e.target.focus();
  93. this.setState({
  94. loading: false,
  95. });
  96. return;
  97. }
  98. delete target.isNew;
  99. this.toggleEditable(e, key);
  100. const { data } = this.state;
  101. const { onChange } = this.props;
  102. onChange(data);
  103. this.setState({
  104. loading: false,
  105. });
  106. }, 500);
  107. }
  108. cancel(e, key) {
  109. this.clickedCancel = true;
  110. e.preventDefault();
  111. const { data } = this.state;
  112. const newData = data.map(item => ({ ...item }));
  113. const target = this.getRowByKey(key, newData);
  114. if (this.cacheOriginData[key]) {
  115. Object.assign(target, this.cacheOriginData[key]);
  116. delete this.cacheOriginData[key];
  117. }
  118. target.editable = false;
  119. this.setState({ data: newData });
  120. this.clickedCancel = false;
  121. }
  122. render() {
  123. const columns = [
  124. {
  125. title: '成员姓名',
  126. dataIndex: 'name',
  127. key: 'name',
  128. width: '20%',
  129. render: (text, record) => {
  130. if (record.editable) {
  131. return (
  132. <Input
  133. value={text}
  134. autoFocus
  135. onChange={e => this.handleFieldChange(e, 'name', record.key)}
  136. onKeyPress={e => this.handleKeyPress(e, record.key)}
  137. placeholder="成员姓名"
  138. />
  139. );
  140. }
  141. return text;
  142. },
  143. },
  144. {
  145. title: '工号',
  146. dataIndex: 'workId',
  147. key: 'workId',
  148. width: '20%',
  149. render: (text, record) => {
  150. if (record.editable) {
  151. return (
  152. <Input
  153. value={text}
  154. onChange={e => this.handleFieldChange(e, 'workId', record.key)}
  155. onKeyPress={e => this.handleKeyPress(e, record.key)}
  156. placeholder="工号"
  157. />
  158. );
  159. }
  160. return text;
  161. },
  162. },
  163. {
  164. title: '所属部门',
  165. dataIndex: 'department',
  166. key: 'department',
  167. width: '40%',
  168. render: (text, record) => {
  169. if (record.editable) {
  170. return (
  171. <Input
  172. value={text}
  173. onChange={e => this.handleFieldChange(e, 'department', record.key)}
  174. onKeyPress={e => this.handleKeyPress(e, record.key)}
  175. placeholder="所属部门"
  176. />
  177. );
  178. }
  179. return text;
  180. },
  181. },
  182. {
  183. title: '操作',
  184. key: 'action',
  185. render: (text, record) => {
  186. const { loading } = this.state;
  187. if (!!record.editable && loading) {
  188. return null;
  189. }
  190. if (record.editable) {
  191. if (record.isNew) {
  192. return (
  193. <span>
  194. <a onClick={e => this.saveRow(e, record.key)}>添加</a>
  195. <Divider type="vertical" />
  196. <Popconfirm title="是否要删除此行?" onConfirm={() => this.remove(record.key)}>
  197. <a>删除</a>
  198. </Popconfirm>
  199. </span>
  200. );
  201. }
  202. return (
  203. <span>
  204. <a onClick={e => this.saveRow(e, record.key)}>保存</a>
  205. <Divider type="vertical" />
  206. <a onClick={e => this.cancel(e, record.key)}>取消</a>
  207. </span>
  208. );
  209. }
  210. return (
  211. <span>
  212. <a onClick={e => this.toggleEditable(e, record.key)}>编辑</a>
  213. <Divider type="vertical" />
  214. <Popconfirm title="是否要删除此行?" onConfirm={() => this.remove(record.key)}>
  215. <a>删除</a>
  216. </Popconfirm>
  217. </span>
  218. );
  219. },
  220. },
  221. ];
  222. const { loading, data } = this.state;
  223. return (
  224. <Fragment>
  225. <Table
  226. loading={loading}
  227. columns={columns}
  228. dataSource={data}
  229. pagination={false}
  230. rowClassName={record => (record.editable ? styles.editable : '')}
  231. />
  232. <Button
  233. style={{ width: '100%', marginTop: 16, marginBottom: 8 }}
  234. type="dashed"
  235. onClick={this.newMember}
  236. icon="plus"
  237. >
  238. 新增成员
  239. </Button>
  240. </Fragment>
  241. );
  242. }
  243. }
  244. export default TableForm;