page.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. import React from 'react';
  2. import './index.less';
  3. import Page from '@src/containers/Page';
  4. import { Checkbox } from 'antd';
  5. // import Assets from '@src/components/Assets';
  6. import { getMap, formatDate } from '@src/services/Tools';
  7. import Button from '../../../components/Button';
  8. import Money from '../../../components/Money';
  9. import Icon from '../../../components/Icon';
  10. import { Order } from '../../../stores/order';
  11. import { My } from '../../../stores/my';
  12. import { Main } from '../../../stores/main';
  13. import { ServiceParamMap, OrderInfoMap } from '../../../../Constant';
  14. import { Common } from '../../../stores/common';
  15. const ServiceParamRelation = getMap(Object.keys(ServiceParamMap).map(key => {
  16. return {
  17. map: getMap(ServiceParamMap[key].map((row, index) => {
  18. row.index = index;
  19. return row;
  20. }), 'value', 'index'),
  21. key,
  22. };
  23. }), 'key', 'map');
  24. function formatTitle(record) {
  25. if (record.productType === 'course_package') {
  26. return (record.coursePackage || {}).title;
  27. }
  28. if (record.productType === 'course') {
  29. return (record.course || {}).title;
  30. }
  31. if (record.productType === 'data') {
  32. return (record.data || {}).title;
  33. }
  34. if (record.productType === 'service') {
  35. return record.info.label || ((record.serviceInfo || {}).title);
  36. }
  37. return '';
  38. }
  39. function formatCheckout(checkouts) {
  40. checkouts.forEach(checkout => {
  41. checkout.info = OrderInfoMap[checkout.productType];
  42. if (checkout.productType === 'service') {
  43. const index = (ServiceParamRelation[checkout.service] && ServiceParamRelation[checkout.service][checkout.param]) || 0;
  44. checkout.info = Object.assign({}, checkout.info[checkout.service], checkout.serviceInfo.package[index]);
  45. }
  46. checkout.title = formatTitle(checkout);
  47. });
  48. }
  49. export default class extends Page {
  50. initState() {
  51. return { show: true, showEnd: false };
  52. }
  53. initData() {
  54. const { id } = this.params;
  55. Order.getOrder(id).then(order => {
  56. formatCheckout(order.checkouts);
  57. const [checkout] = order.checkouts;
  58. this.setState({ order, checkout });
  59. });
  60. Main.getContract('course').then(result => {
  61. this.setState({ contract: result });
  62. });
  63. }
  64. pay() {
  65. const { id } = this.params;
  66. if (this.paying) return;
  67. this.paying = true;
  68. this.setState({ paying: true });
  69. Order.wechatJs(id).then((info) => {
  70. return Common.readyWechatBridge().then(() => {
  71. WeixinJSBridge.invoke(
  72. 'getBrandWCPayRequest', info,
  73. (res) => {
  74. if (res.err_msg === 'get_brand_wcpay_request:ok') {
  75. // 使用以上方式判断前端返回,微信团队郑重提示:
  76. // res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
  77. this.queryPay(true);
  78. } else if (res.err_msg === 'get_brand_wcpay_request:cancel' || res.err_msg === 'get_brand_wcpay_request:fail') {
  79. // 支付失败
  80. this.paying = false;
  81. this.setState({ paying: false });
  82. }
  83. console.log(res);
  84. },
  85. );
  86. });
  87. });
  88. }
  89. queryPay(force) {
  90. const { order } = this.state;
  91. if (this.time) {
  92. clearTimeout(this.time);
  93. }
  94. if (force) {
  95. this.times = 0;
  96. } else {
  97. this.times = (this.times || 0) + 1;
  98. }
  99. this.time = setTimeout(() => {
  100. Order.query(order.id)
  101. .then(result => {
  102. if (result) {
  103. // 支付成功
  104. this.paySuccess();
  105. } else if (order) {
  106. this.queryPay();
  107. } else {
  108. this.setState({ select: null, pay: null, order: null, info: null });
  109. }
  110. });
  111. }, 1000);
  112. }
  113. paySuccess() {
  114. const { order } = this.state;
  115. const { info } = this.props.user;
  116. Order.getOrder(order.id).then(result => {
  117. // 确保开通用的是record记录id
  118. const [checkout] = result.checkouts;
  119. formatCheckout(result.checkouts);
  120. checkout.info.result = checkout.info.result.replace('{email}', info.email).replace('{useExpireDays}', checkout.useExpireDays).replace('{title}', checkout.title);
  121. if (checkout.service === 'vip') {
  122. // 查询最后有效期
  123. My.getVipInfo().then(vip => {
  124. checkout.info.result = checkout.info.result.replace('{endTime}', formatDate(vip.expireTime, 'YYYY-MM-DD'));
  125. this.setState({ show: false, showEnd: true, order: result, checkout });
  126. });
  127. } else {
  128. this.setState({ show: false, showEnd: true, order: result, checkout });
  129. }
  130. });
  131. }
  132. renderView() {
  133. const { show, showEnd } = this.state;
  134. if (show) {
  135. return this.renderPay();
  136. }
  137. if (showEnd) {
  138. return this.renderEnd();
  139. }
  140. return null;
  141. }
  142. renderPay() {
  143. const { order = {}, contract = {}, checkout = {} } = this.state;
  144. const { info = {}, productType } = checkout;
  145. let content = '';
  146. switch (productType) {
  147. case 'data':
  148. content = this.renderData();
  149. break;
  150. case 'course_package':
  151. content = this.renderCoursePackage();
  152. break;
  153. case 'course':
  154. case 'service':
  155. content = this.renderSingle();
  156. break;
  157. default:
  158. }
  159. return (
  160. <div className="detail">
  161. <div className="title" style={{ marginBottom: 0 }}>
  162. 商品信息
  163. </div>
  164. {content}
  165. {info.refund_policy && [< div className="title">退款政策</div>,
  166. <div className="desc">{info.refund_policy}</div>]}
  167. {info.copyright_notes && [<div className="title">版权说明</div>,
  168. <div className="desc">{info.copyright_notes}</div>]}
  169. {order.productTypes && order.productTypes.indexOf('course') > 0 && <div className="agree">
  170. <Checkbox checked />
  171. 我已阅读并同意 <a onClick={() => this.setState({ showContract: true })}>{contract.title}</a>
  172. </div>}
  173. <div className="fixed">
  174. <div className="tip">*若在购买过程中遇到问题,请联系千行小助手协助解决</div>
  175. <div className="fee">
  176. 应付: <Money value={order.money} size="lager" />
  177. </div>
  178. <Button
  179. width={110}
  180. className="f-r"
  181. radius
  182. disabled={this.state.paying}
  183. onClick={() => {
  184. this.pay();
  185. }}
  186. >
  187. 立即购买
  188. </Button>
  189. </div>
  190. </div >
  191. );
  192. }
  193. renderData() {
  194. const { checkout } = this.state;
  195. return (
  196. <div className="info data">
  197. <div className="info-block">
  198. {checkout.title} <Money className="f-r" value={checkout.money} />
  199. </div>
  200. <div className="info-block">
  201. 开通有效期 <span className="f-r">{checkout.expireDays ? `${checkout.expireDays}天` : '永久'}</span>
  202. </div>
  203. </div>
  204. );
  205. }
  206. renderCoursePackage() {
  207. const { checkout, order } = this.state;
  208. return (
  209. <div className="info course-package">
  210. <div className="info-block">
  211. {checkout.title} <Money className="f-r" value={checkout.money} />
  212. </div>
  213. <div className="info-block">
  214. {order.checkouts.map(row => {
  215. if (row.parentId === 0) return null;
  216. return <div className="info-item">
  217. {row.title} <span className="f-r">开通有效期: {checkout.expireDays ? `${checkout.expireDays}天` : '付款后立即生效'} 使用有效期: {checkout.useExpireDays ? `${checkout.useExpireDays}天` : '永久'}</span>
  218. </div>;
  219. })}
  220. </div>
  221. </div>
  222. );
  223. }
  224. renderSingle() {
  225. const { checkout = {} } = this.state;
  226. return (
  227. <div className="info single">
  228. <div className="info-block">
  229. {checkout.title} <Money className="f-r" value={checkout.money} />
  230. </div>
  231. <div className="info-block">
  232. 开通有效期 <span className="f-r">{checkout.expireDays ? `${checkout.expireDays}天` : '付款后立即生效'}</span>
  233. </div>
  234. <div className="info-block">
  235. 使用有效期 <span className="f-r">{checkout.useExpireDays ? `${checkout.useExpireDays}天` : '永久'}</span>
  236. </div>
  237. </div>
  238. );
  239. }
  240. renderEnd() {
  241. const { checkout = {} } = this.state;
  242. const { info = {} } = checkout;
  243. return (
  244. <div className="finish">
  245. <div className="icon">
  246. <Icon type="check-circle" />
  247. </div>
  248. <div className="title">支付成功!</div>
  249. <div className="desc">{info.result}</div>
  250. </div>
  251. );
  252. }
  253. }