index.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. import React, { PureComponent } from 'react';
  2. import { connect } from 'dva';
  3. import { routerRedux } from 'dva/router';
  4. import { Card, Table, Form, Spin, Input, InputNumber, Button, Icon, message } from 'antd';
  5. import queryString from 'query-string';
  6. import PageHeaderLayout from '../../../layouts/PageHeaderLayout';
  7. import ProductSelectModal from './product';
  8. import { Codes, pageSize, productType } from '../../../utils/config';
  9. @Form.create()
  10. @connect(state => ({
  11. comboDetail: state.comboDetail,
  12. product: state.product,
  13. }))
  14. export default class PackageProfile extends PureComponent {
  15. state = { proType: [Codes.CODE_COURSE] }; // 产品类型[默认为课程资源]
  16. handleEditProuctClick = () => {
  17. const { proType } = this.state;
  18. this.props.dispatch({ type: 'comboDetail/showModal' });
  19. this.props.dispatch({
  20. type: 'product/query',
  21. payload: {
  22. type: proType[0],
  23. pageNo: 1,
  24. pageSize,
  25. }
  26. });
  27. }
  28. handleInputNumberChange = (value, record, field) => {
  29. const { currentItem } = this.props.comboDetail;
  30. const { products } = currentItem;
  31. const boundPriceProducts = [...products];
  32. if (field == 'cp') {
  33. boundPriceProducts.map(item => item.pid == record.pid ? item.cpPrice = value : null);
  34. } else if (field == 'pj') {
  35. boundPriceProducts.map(item => item.pid == record.pid ? item.merchantPrice = value : null);
  36. }
  37. this.props.dispatch({
  38. type: 'comboDetail/savePrice',
  39. payload: boundPriceProducts,
  40. });
  41. }
  42. handleProductModalOk = (data) => {
  43. this.props.dispatch({
  44. type: 'comboDetail/saveProducts',
  45. payload: data ,
  46. });
  47. }
  48. handleProductModalCancel = () => {
  49. this.props.dispatch({ type: 'comboDetail/hideModal' });
  50. }
  51. handleProductModalSearch = (data) => {
  52. const newData = { ...data };
  53. const { proType } = this.state;
  54. if (newData.keyword) {
  55. newData[newData.field] = newData.keyword;
  56. }
  57. delete newData.field;
  58. delete newData.keyword;
  59. this.props.dispatch({
  60. type: 'product/query',
  61. payload: {
  62. ...newData,
  63. type: proType[0],
  64. pageNo: 1,
  65. pageSize,
  66. }
  67. });
  68. }
  69. handleProductModalTableChange = (pagination, filterArgs, filters) => {
  70. // 待选资源列表中资源类型过滤选项
  71. const { type } = filterArgs;
  72. if (Array.isArray(type) && type.length) {
  73. this.setState({ proType: type.map(item => item) });
  74. } else {
  75. this.setState({ proType: [Codes.CODE_COURSE] });
  76. filterArgs.type = [Codes.CODE_COURSE];
  77. }
  78. const newFilters = { ...filters };
  79. if (newFilters.keyword) {
  80. newFilters[newFilters.field] = newFilters.keyword;
  81. }
  82. delete newFilters.field;
  83. delete newFilters.keyword;
  84. // table header filter
  85. const getValue = obj => Object.keys(obj).map(key => obj[key]).join(',');
  86. const tableFilters = Object.keys(filterArgs).reduce((obj, key) => {
  87. const newObj = { ...obj };
  88. newObj[key] = getValue(filterArgs[key]);
  89. return newObj;
  90. }, {});
  91. const data = { ...newFilters, ...tableFilters, pageNo: pagination.current, pageSize: pagination.pageSize };
  92. Object.keys(data).map(key => data[key] ? null : delete data[key]);
  93. this.props.dispatch({ type: 'product/query', payload: data });
  94. }
  95. handlePageCancel = () => {
  96. const { filters } = this.props.comboDetail;
  97. this.props.dispatch(routerRedux.push({
  98. pathname: '/product/package',
  99. search: queryString.stringify(filters),
  100. }));
  101. this.props.dispatch({ type: 'comboDetail/initState' });
  102. }
  103. handlePageSubmit = (e) => {
  104. e.preventDefault();
  105. const { dispatch, form, comboDetail } = this.props;
  106. const { currentItem, operType, filters } = comboDetail;
  107. const { products, type, id, status } = currentItem;
  108. const { validateFields, getFieldsValue } = form;
  109. validateFields((errors) => {
  110. if (errors) return;
  111. if (products && products.filter(item => !item.cpPrice).length > 0 ) {
  112. message.error('还有供应商价格未填写!');
  113. return;
  114. }
  115. if (products && products.filter(item => !item.merchantPrice).length > 0 ) {
  116. message.error('还有渠道方售价未填写!');
  117. return;
  118. }
  119. // add params `code` and `name`
  120. const data = { ...getFieldsValue() };
  121. // add params `products`
  122. if (Array.isArray(products)) {
  123. data.products = products.map(item => ({
  124. pid: item.pid,
  125. type: item.type,
  126. cpPrice: item.cpPrice,
  127. merchantPrice: item.merchantPrice,
  128. }));
  129. }
  130. // add params `status`
  131. if (operType == 'create') {
  132. data.status = Codes.CODE_NORMAL;
  133. data.type = Codes.CODE_PACKAGE;
  134. }
  135. else if (operType == 'update') {
  136. data.type = Codes.CODE_PACKAGE;
  137. data.status = status;
  138. data.id = id;
  139. }
  140. dispatch({
  141. type: `comboDetail/${operType}`,
  142. payload: data,
  143. callback: () => {
  144. dispatch(routerRedux.push({
  145. pathname: '/product/package',
  146. search: queryString.stringify(filters),
  147. }));
  148. }
  149. });
  150. });
  151. }
  152. render() {
  153. const { form, comboDetail, product } = this.props;
  154. const { proType } = this.state;
  155. const { modalShow, currentItem, itemLoading } = comboDetail;
  156. const { list, listLoading, pagination } = product;
  157. const { code, name, products } = currentItem;
  158. const { getFieldDecorator } = form;
  159. const formItemLayout = {
  160. labelCol: { span: 4 },
  161. wrapperCol: { span: 15 },
  162. };
  163. const submitFormLayout = {
  164. wrapperCol: {
  165. xs: { span: 24, offset: 0 },
  166. sm: { span: 15, offset: 4 },
  167. },
  168. };
  169. const tableFormLayout = {
  170. wrapperCol: { offset: 4, span: 15 },
  171. };
  172. const columns = [{
  173. // title: '封面',
  174. // dataIndex: 'coverUrl',
  175. // key: 'coverUrl',
  176. // render: (text, record) => {},
  177. // },{
  178. title: '编号',
  179. dataIndex: 'code',
  180. key: 'code',
  181. width: '20%',
  182. },{
  183. title: '名称',
  184. dataIndex: 'name',
  185. key: 'name',
  186. width: '23%',
  187. },{
  188. title: '类型',
  189. dataIndex: 'type',
  190. key: 'type',
  191. render: (text, record) => productType[text],
  192. width: '13%',
  193. },{
  194. // title: '供应商',
  195. // dataIndex: 'cpName',
  196. // key: 'cpName',
  197. // width: '17%',
  198. // },{
  199. title: '供应商售价(¥)',
  200. dataIndex: 'cpPrice',
  201. key: 'cpPrice',
  202. render: (text, record) => (
  203. <InputNumber
  204. min={0}
  205. style={{ width: '100%' }}
  206. value={record.cpPrice}
  207. onChange={(value) => this.handleInputNumberChange(value, record, 'cp')}
  208. />
  209. ),
  210. width: '22%',
  211. },{
  212. title: '渠道售价(¥)',
  213. dataIndex: 'merchantPrice',
  214. key: 'merchantPrice',
  215. render: (text, record) => (
  216. <InputNumber
  217. min={0}
  218. style={{ width: '100%' }}
  219. value={record.merchantPrice}
  220. onChange={(value) => this.handleInputNumberChange(value, record, 'pj')}
  221. />
  222. ),
  223. width: '22%',
  224. }];
  225. return (
  226. <PageHeaderLayout>
  227. <Spin spinning={itemLoading}>
  228. <Card>
  229. <Form layout="horizontal" onSubmit={this.handlePageSubmit}>
  230. <Form.Item label="产品包编号" { ...formItemLayout }>
  231. {getFieldDecorator('code', {
  232. rules: [{ required: true, type: 'string', message: '编号为必填项!' }],
  233. initialValue: code,
  234. })(<Input placeholder="请输入" />)}
  235. </Form.Item>
  236. <Form.Item label="产品包名称" { ...formItemLayout }>
  237. {getFieldDecorator('name', {
  238. rules: [{ required: true, type: 'string', message: '名称为必填项!' }],
  239. initialValue: name,
  240. })(<Input placeholder="请输入" />)}
  241. </Form.Item>
  242. <Form.Item label="选择产品" { ...formItemLayout }>
  243. <Button onClick={this.handleEditProuctClick} type="primary" size="small" icon="select">选择</Button>
  244. </Form.Item>
  245. <Form.Item { ...tableFormLayout }>
  246. <Table
  247. simple
  248. bordered
  249. columns={columns}
  250. dataSource={products || []}
  251. pagination={false}
  252. rowKey={record => record.id}
  253. locale={{
  254. emptyText: <span style={{ color: "#C6D0D6" }}>&nbsp;&nbsp;<Icon type="frown-o"/>
  255. 该产品包内暂无相关内容!</span>
  256. }}
  257. />
  258. </Form.Item>
  259. <Form.Item { ...submitFormLayout } style={{ marginTop: 32 }}>
  260. <Button onClick={this.handlePageCancel}>取消</Button>
  261. <Button type="primary" style={{ marginLeft: 35 }} htmlType="submit">提交</Button>
  262. </Form.Item>
  263. </Form>
  264. {/*产品选择模态框*/}
  265. <ProductSelectModal
  266. rowKeyName="id"
  267. modalVisible={modalShow}
  268. selTableData={products || []}
  269. width={600}
  270. style={{ top: 20 }}
  271. fsTableDataSource={list}
  272. fsTableLoading={listLoading}
  273. fsTablePagination={pagination}
  274. fsFilteredValue={proType}
  275. onOk={this.handleProductModalOk}
  276. onCancel={this.handleProductModalCancel}
  277. onSearch={this.handleProductModalSearch}
  278. fsTableOnChange={this.handleProductModalTableChange}
  279. />
  280. </Card>
  281. </Spin>
  282. </PageHeaderLayout>
  283. );
  284. }
  285. }