TableForm.js 6.6 KB

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