TableForm.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. import React, { PureComponent, Fragment } from 'react';
  2. import {
  3. Table,
  4. Button,
  5. Select,
  6. InputNumber,
  7. Popconfirm,
  8. Divider,
  9. message,
  10. } from 'antd';
  11. import {
  12. CHARGE_UNIT_YEAR,
  13. CHARGE_UNIT_SEASON,
  14. CHARGE_UNIT_HALF_YEAR,
  15. DURATION_HALF_YEAR,
  16. DURATION_YEAR,
  17. DURATION_SEASON,
  18. } from '../../../utils/config';
  19. import styles from './TableForm.less';
  20. const chargeUnitMap = [{
  21. text: CHARGE_UNIT_YEAR,
  22. value: CHARGE_UNIT_YEAR,
  23. }, {
  24. text: CHARGE_UNIT_HALF_YEAR,
  25. value: CHARGE_UNIT_HALF_YEAR,
  26. }, {
  27. text: CHARGE_UNIT_SEASON,
  28. value: CHARGE_UNIT_SEASON,
  29. }];
  30. const durationMap = {
  31. [CHARGE_UNIT_SEASON]: DURATION_SEASON,
  32. [CHARGE_UNIT_HALF_YEAR]: DURATION_HALF_YEAR,
  33. [CHARGE_UNIT_YEAR]: DURATION_YEAR,
  34. };
  35. export default class TableForm extends PureComponent {
  36. constructor(props) {
  37. super(props);
  38. this.state = {
  39. data: props.value,
  40. loading: props.loading,
  41. };
  42. }
  43. componentWillReceiveProps(nextProps) {
  44. if ('value' in nextProps) {
  45. this.setState({
  46. data: nextProps.value,
  47. });
  48. }
  49. }
  50. getRowByKey(key, newData) {
  51. return (newData || this.state.data).filter(item => item.key === key)[0];
  52. }
  53. index = 0;
  54. cacheOriginData = {};
  55. toggleEditable=(e, key) => {
  56. e.preventDefault();
  57. const newData = this.state.data.map(item => ({ ...item }));
  58. const target = this.getRowByKey(key, newData);
  59. if (target) {
  60. // 进入编辑状态时保存原始数据
  61. if (!target.editable) {
  62. this.cacheOriginData[key] = { ...target };
  63. }
  64. target.editable = !target.editable;
  65. this.setState({ data: newData });
  66. }
  67. }
  68. chargeUnitSelectable=(value) => {
  69. const tmp = this.state.data.find(item => item.chargeUnit === value);
  70. return tmp !== undefined;
  71. }
  72. remove(record) {
  73. const { key, isNew } = record;
  74. const newData = this.state.data.filter(item => item.key !== key);
  75. this.setState({ data: newData });
  76. if (!isNew) {
  77. this.props.onDelete({ goodsId: key });
  78. }
  79. }
  80. newPrice = () => {
  81. const newData = this.state.data.map(item => ({ ...item }));
  82. newData.push({
  83. key: `NEW_TEMP_ID_${this.index}`,
  84. cpPrice: '',
  85. merchantPrice: '',
  86. terminalPrice: '',
  87. editable: true,
  88. isNew: true,
  89. });
  90. this.index += 1;
  91. this.setState({ data: newData });
  92. }
  93. handleFieldChange(value, fieldName, key) {
  94. const newData = this.state.data.map(item => ({ ...item }));
  95. const target = this.getRowByKey(key, newData);
  96. if (target) {
  97. target[fieldName] = value;
  98. this.setState({ data: newData });
  99. }
  100. }
  101. handleSelectChange(value, key) {
  102. const newData = this.state.data.map(item => ({ ...item }));
  103. const target = this.getRowByKey(key, newData);
  104. if (target) {
  105. target.chargeUnit = value;
  106. this.setState({ data: newData });
  107. }
  108. }
  109. saveRow(e, key) {
  110. e.persist();
  111. if (this.clickedCancel) {
  112. this.clickedCancel = false;
  113. return;
  114. }
  115. const target = this.getRowByKey(key) || {};
  116. if (!target.chargeUnit || !target.cpPrice || !target.merchantPrice || !target.terminalPrice) {
  117. message.error('请填写完整价格信息');
  118. e.target.focus();
  119. return;
  120. }
  121. let sort = 0;
  122. const { chargeUnit, cpPrice, merchantPrice, terminalPrice, duration } = target;
  123. if (chargeUnit === CHARGE_UNIT_HALF_YEAR) {
  124. sort = 1;
  125. } else if (chargeUnit === CHARGE_UNIT_YEAR) {
  126. sort = 2;
  127. }
  128. if (target.isNew) {
  129. this.props.onCreate({
  130. sort,
  131. cpPrice,
  132. duration,
  133. chargeUnit,
  134. merchantPrice,
  135. terminalPrice,
  136. });
  137. } else {
  138. this.props.onUpdate({
  139. sort,
  140. cpPrice,
  141. duration,
  142. chargeUnit,
  143. merchantPrice,
  144. terminalPrice,
  145. });
  146. }
  147. delete target.isNew;
  148. this.toggleEditable(e, key);
  149. }
  150. cancel(e, key) {
  151. this.clickedCancel = true;
  152. e.preventDefault();
  153. const newData = this.state.data.map(item => ({ ...item }));
  154. const target = this.getRowByKey(key, newData);
  155. if (this.cacheOriginData[key]) {
  156. Object.assign(target, this.cacheOriginData[key]);
  157. target.editable = false;
  158. delete this.cacheOriginData[key];
  159. }
  160. this.setState({ data: newData });
  161. this.clickedCancel = false;
  162. }
  163. render() {
  164. const columns = [{
  165. title: '计价单位',
  166. dataIndex: 'chargeUnit',
  167. key: 'chargeUnit',
  168. width: '15%',
  169. align: 'center',
  170. render: (text, record) => {
  171. if (record.editable) {
  172. return (
  173. <Select
  174. placeholder="请选择"
  175. style={{ width: '100%' }}
  176. value={text}
  177. onChange={value => this.handleSelectChange(value, record.key)}
  178. >
  179. {
  180. chargeUnitMap.map(item => (
  181. <Select.Option
  182. key={item.value}
  183. value={item.value}
  184. disabled={this.chargeUnitSelectable(item.value)}
  185. >
  186. {item.text}
  187. </Select.Option>
  188. ))
  189. }
  190. </Select>
  191. );
  192. }
  193. return text;
  194. },
  195. }, {
  196. title: '时长(天)',
  197. dataIndex: 'duration',
  198. key: 'duration',
  199. width: '15%',
  200. align: 'center',
  201. render: (_, record) => {
  202. if (record.chargeUnit) {
  203. return durationMap[record.chargeUnit];
  204. }
  205. return '';
  206. },
  207. }, {
  208. title: '供应商售价(¥)',
  209. dataIndex: 'cpPrice',
  210. key: 'cpPrice',
  211. width: '20%',
  212. align: 'center',
  213. render: (text, record) => {
  214. if (record.editable) {
  215. return (
  216. <InputNumber
  217. min={1}
  218. value={text}
  219. onChange={e => this.handleFieldChange(e, 'cpPrice', record.key)}
  220. style={{ width: '100%', border: 'unset' }}
  221. placeholder="请输入"
  222. />
  223. );
  224. }
  225. return text;
  226. },
  227. }, {
  228. title: '平台方售价(¥)',
  229. dataIndex: 'merchantPrice',
  230. key: 'merchantPrice',
  231. width: '20%',
  232. align: 'center',
  233. render: (text, record) => {
  234. if (record.editable) {
  235. return (
  236. <InputNumber
  237. min={1}
  238. value={text}
  239. onChange={value => this.handleFieldChange(value, 'merchantPrice', record.key)}
  240. style={{ width: '100%', border: 'unset' }}
  241. placeholder="请输入"
  242. />
  243. );
  244. }
  245. return text;
  246. },
  247. }, {
  248. title: '终端显示价格(¥)',
  249. dataIndex: 'terminalPrice',
  250. key: 'terminalPrice',
  251. width: '20%',
  252. align: 'center',
  253. render: (text, record) => {
  254. if (record.editable) {
  255. return (
  256. <InputNumber
  257. min={1}
  258. value={text}
  259. onChange={value => this.handleFieldChange(value, 'terminalPrice', record.key)}
  260. style={{ width: '100%', border: 'unset' }}
  261. placeholder="请输入"
  262. />
  263. );
  264. }
  265. return text;
  266. },
  267. }, {
  268. title: '操作',
  269. key: 'action',
  270. align: 'center',
  271. render: (text, record) => {
  272. if (!!record.editable && this.state.loading) {
  273. return null;
  274. }
  275. if (record.editable) {
  276. if (record.isNew) {
  277. return (
  278. <span>
  279. <a onClick={e => this.saveRow(e, record.key)}>添加</a>
  280. <Divider type="vertical" />
  281. <Popconfirm title="是否要删除此种价格?" onConfirm={() => this.remove(record.key)}>
  282. <a>删除</a>
  283. </Popconfirm>
  284. </span>
  285. );
  286. }
  287. return (
  288. <span>
  289. <a onClick={e => this.saveRow(e, record.key)}>保存</a>
  290. <Divider type="vertical" />
  291. <a onClick={e => this.cancel(e, record.key)}>取消</a>
  292. </span>
  293. );
  294. }
  295. return (
  296. <span>
  297. <a onClick={e => this.toggleEditable(e, record.key)}>编辑</a>
  298. <Divider type="vertical" />
  299. <Popconfirm title="是否要删除此种价格?" onConfirm={() => this.remove(record)}>
  300. <a>删除</a>
  301. </Popconfirm>
  302. </span>
  303. );
  304. },
  305. }];
  306. return (
  307. <Fragment>
  308. <Table
  309. bordered
  310. pagination={false}
  311. columns={columns}
  312. loading={this.state.loading}
  313. dataSource={this.state.data}
  314. rowClassName={() => {
  315. return styles.editable;
  316. }}
  317. />
  318. <Button
  319. style={{ width: '100%', marginTop: 16, marginBottom: 8 }}
  320. type="dashed"
  321. onClick={this.newPrice}
  322. icon="plus"
  323. >
  324. 新增价格
  325. </Button>
  326. </Fragment>
  327. );
  328. }
  329. }