page.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. import React, { Component } from 'react';
  2. import './index.less';
  3. import { Icon, Radio } from 'antd';
  4. import Assets from '@src/components/Assets';
  5. import Page from '@src/containers/Page';
  6. import { asyncSMessage } from '@src/services/AsyncTools';
  7. import CheckboxItem from '../../../components/CheckboxItem';
  8. import Button from '../../../components/Button';
  9. import Modal from '../../../components/Modal';
  10. import UserTable from '../../../components/UserTable';
  11. import { Order } from '../../../stores/order';
  12. import { Course } from '../../../stores/course';
  13. import { User } from '../../../stores/user';
  14. import { getMap } from '../../../../../src/services/Tools';
  15. import { CourseVsType } from '../../../../Constant';
  16. const CourseVsTypeMap = getMap(CourseVsType, 'value', 'tips');
  17. export default class extends Page {
  18. initState() {
  19. return { courses: [] };
  20. }
  21. init() {
  22. Course.allVs()
  23. .then(result => {
  24. // 赠送选择选择
  25. this.setState({ courses: result.filter(row => ['novice', 'coach'].indexOf(row.vsType) >= 0) });
  26. });
  27. }
  28. initData() {
  29. Order.getOrder(34)
  30. .then((order) => {
  31. User.needPay(order);
  32. });
  33. Order.allCheckout()
  34. .then(result => {
  35. User.formatOrder(result);
  36. this.setState({ order: result, list: result.checkouts });
  37. });
  38. }
  39. onAll(checked) {
  40. const selectList = [];
  41. if (checked) {
  42. const { list = [] } = this.state;
  43. list.forEach(item => {
  44. if (selectList.indexOf(item.key) >= 0) return;
  45. selectList.push(item.key);
  46. });
  47. }
  48. this.setState({ selectList, allChecked: checked });
  49. }
  50. onSelect(key, checked) {
  51. const { selectList = [] } = this.state;
  52. if (checked) {
  53. selectList.push(key);
  54. } else {
  55. selectList.splice(selectList.indexOf(key), 1);
  56. }
  57. this.setState({ selectList });
  58. }
  59. onDelete(list) {
  60. Promise.all(list.map(row => {
  61. return Order.removeCheckout(row);
  62. }))
  63. .then(() => {
  64. this.refresh();
  65. });
  66. }
  67. onChangeNumber(id, number) {
  68. Order.changeCheckout(id, number)
  69. .then(() => {
  70. this.refresh();
  71. });
  72. }
  73. pay() {
  74. const { courseId, list, order } = this.state;
  75. if (list.length === 0) return;
  76. if (order.gift && order.gift.filter(row => row.key === 'vs').length > 0 && !courseId) {
  77. // 请选择课程
  78. asyncSMessage('请选择赠送的课程', 'warn');
  79. return;
  80. }
  81. Order.confirmPay(courseId)
  82. .then(result => {
  83. return User.needPay(result)
  84. .then(() => {
  85. linkTo(`/order/${result.id}`);
  86. })
  87. .catch(() => {
  88. this.refresh();
  89. });
  90. });
  91. }
  92. renderView() {
  93. const { courses = [], order = {}, list = [], allChecked, selectList = [], courseId } = this.state;
  94. return (
  95. <div style={{ paddingTop: 50 }}>
  96. <div className="content">
  97. <div className="t-1 m-b-2 f-w-b t-s-24">购物车</div>
  98. </div>
  99. <div className="list content">
  100. {(list || []).map(item => {
  101. return [
  102. item.productType === 'course_package' && <div className="content">
  103. <div className="m-b-1 t-8">您看中的课程已构成套餐,结算有优惠</div>
  104. </div>,
  105. <OrderItem
  106. data={item}
  107. checked={selectList.indexOf(item.id) >= 0}
  108. onDelete={() => this.onDelete([item.id])}
  109. onCheck={(checked) => this.onSelect(item.id, checked)}
  110. onChangeNumber={(number) => this.onChangeNumber(item.id, number)}
  111. />,
  112. ];
  113. })}
  114. </div>
  115. <div className="gift-list content">
  116. {(order.gift || []).map(item => {
  117. return <GiftItem
  118. data={item}
  119. courses={courses}
  120. courseId={courseId}
  121. onSelectCourse={(id) => item.key === 'vs' && this.setState({ courseId: id })}
  122. />;
  123. })}
  124. </div>
  125. <div className="footer">
  126. <div className="content">
  127. <div className="d-i-b m-t-1 m-r-2">
  128. <CheckboxItem className="v-a-m m-r-5" theme="white" checked={allChecked} onClick={() => this.onAll(!allChecked)} />
  129. 全选
  130. </div>
  131. <div style={{ marginRight: 50 }} className="d-i-b m-t-1">
  132. <Button size="small" radius disabled={selectList.length === 0} onClick={() => this.onDelete(selectList)}>
  133. 删除
  134. </Button>
  135. </div>
  136. {order.promote && order.promote.length > 0 && [
  137. <div style={{ marginTop: 15 }} className="d-i-b t-9 t-s-12 m-r-5">
  138. 优惠活动:
  139. </div>,
  140. <div style={{ marginTop: 15 }} className="d-i-b t-s-12">
  141. {order.promote.map(row => {
  142. return <div>{row.message}</div>;
  143. })}
  144. </div>,
  145. ]}
  146. <div className="f-r">
  147. <div className="d-i-b m-r-1 m-t-1">
  148. <div className="t-1 t-s-16 f-w-b">
  149. 实付<span className="m-l-5 t-7 t-s-20"> ¥ {order.money || 0}</span>
  150. </div>
  151. <div className="t-1">
  152. 原价<span className="m-l-5 t-8 t-d-l-t">¥ {order.originMoney || 0}</span>
  153. <span hidden={!((order.originMoney || 0) - (order.money || 0))} className="m-l-5 t-8">(优惠活动-¥{(order.originMoney || 0) - (order.money || 0)})</span>
  154. </div>
  155. </div>
  156. <Button className="submit" onClick={() => this.pay()}>立即付款</Button>
  157. </div>
  158. </div>
  159. </div>
  160. </div>
  161. );
  162. }
  163. }
  164. class GiftItem extends Component {
  165. render() {
  166. const { data } = this.props;
  167. return (
  168. <div className="gift-item">
  169. {this.renderInfo()}
  170. {data.key === 'vs' && this.renderVs()}
  171. </div>
  172. );
  173. }
  174. renderInfo() {
  175. const { data } = this.props;
  176. let message = '';
  177. if (data.money) {
  178. message = `实付金额满${data.money}元赠送`;
  179. } else if (data.from === 'vsNumber') {
  180. message = `1VS1课程满${data.number}节赠送`;
  181. }
  182. return (
  183. <div className="gift-item-info">
  184. <Assets name="gift2" className="gift" width={20} height={20} />
  185. <div style={{ width: 350 }} className="d-i-b t-1 t-s-16">
  186. {data.message}
  187. </div>
  188. <div style={{ width: 400 }} className="d-i-b t-8 t-s-12">
  189. {message}
  190. </div>
  191. </div>
  192. );
  193. }
  194. renderVs() {
  195. const { courses, courseId, onSelectCourse } = this.props;
  196. return (
  197. <div className="gift-item-detail l-h-20">
  198. <div className="select">
  199. <div style={{ width: 350 }} className="d-i-b t-1 t-s-12">
  200. <span className="d-i-b f-w-b m-r-5">请选择</span>
  201. </div>
  202. <div className="d-i-b t-1 t-s-12">可至「个人中心-课程」预约辅导时间。</div>
  203. </div>
  204. <div className="select-list m-b-5 l-h-16">
  205. {courses.map(course => {
  206. return <div>
  207. <div style={{ width: 350 }} className="d-i-b t-1 t-s-12">
  208. <span className="d-i-b m-r-5">
  209. <Radio className="m-r-5" checked={courseId === course.id} onChange={() => onSelectCourse(course.id)} /> {course.title}
  210. </span>
  211. </div>
  212. <div className="d-i-b t-8 t-s-12">{CourseVsTypeMap[course.vsType]}</div>
  213. </div>;
  214. })}
  215. </div>
  216. </div>
  217. );
  218. }
  219. }
  220. class OrderItem extends Component {
  221. constructor(props) {
  222. super(props);
  223. this.state = { open: false, showList: false };
  224. this.columns = [{
  225. key: 'label',
  226. title: '服务',
  227. }, {
  228. key: 'expireDays',
  229. title: '开通有效期',
  230. render: (text, checkout) => {
  231. return checkout.expireDays ? `${checkout.expireDays}天` : '付款后立即生效';
  232. },
  233. }, {
  234. key: 'useExpireDays',
  235. title: '使用有效期',
  236. render: (text, checkout) => {
  237. return checkout.useExpireDays ? `${checkout.useExpireDays}天` : '永久';
  238. },
  239. }];
  240. }
  241. render() {
  242. const { data } = this.props;
  243. const { showList } = this.state;
  244. return (
  245. <div className="order-item">
  246. {this.renderInfo()}
  247. {(data.children || data.gift) && this.renderDetail()}
  248. <Modal
  249. show={showList}
  250. maskClosable
  251. close={false}
  252. body={false}
  253. width={630}
  254. onClose={() => this.setState({ showList: false })}
  255. >
  256. <UserTable
  257. size="small"
  258. theme="top"
  259. columns={this.columns}
  260. data={data.gift}
  261. />
  262. </Modal>
  263. </div>
  264. );
  265. }
  266. renderInfo() {
  267. const { data, onCheck, onDelete, onChangeNumber, checked } = this.props;
  268. const checkout = data;
  269. return (
  270. <div className="order-item-info">
  271. <CheckboxItem theme="white" className="select" checked={checked} onClick={() => onCheck(!checked)} />
  272. <Icon className="close" type="close-circle" theme="filled" onClick={() => onDelete()} />
  273. <div style={{ width: 350 }} className="d-i-b t-1 t-s-16">
  274. {data.title}
  275. </div>
  276. <div style={{ width: 430 }} className="d-i-b t-8 t-s-12">
  277. <span className="m-r-2">开通有效期: {checkout.expireDays ? `${checkout.expireDays}天` : '付款后立即生效'}</span>
  278. <span className="m-l-2">使用有效期: {checkout.useExpireDays ? `${checkout.useExpireDays}天` : '永久'}</span>
  279. </div>
  280. <div style={{ width: 120 }} className="d-i-b t-8 t-s-12 p-r">
  281. {data.number > 0 && ['数量',
  282. <input value={data.number} style={{ width: 32 }} className="m-l-5 t-c" />,
  283. <Icon className="up" type="caret-up" onClick={() => data.number < data.maxNumber && onChangeNumber(data.number + 1)} />,
  284. <Icon className="down" type="caret-down" onClick={() => data.number > 1 && data.number > data.minNumber && onChangeNumber(data.number - 1)} />]}
  285. </div>
  286. <div className="d-i-b t-7 t-s-16"> ¥ {data.money}</div>
  287. </div>
  288. );
  289. }
  290. renderDetail() {
  291. const { data = {} } = this.props;
  292. const { children = [], gift } = data;
  293. const { open } = this.state;
  294. return (
  295. <div className="order-item-detail l-h-20">
  296. <div hidden={!children || children.length === 0} className="contain">
  297. <div style={{ width: 880 }} className="d-i-b t-1 t-s-12">
  298. <span className="d-i-b f-w-b m-r-5">
  299. 包含
  300. <Icon
  301. hidden={!open}
  302. className="t-10 c-p"
  303. type="caret-up"
  304. onClick={() => this.setState({ open: !open })}
  305. />
  306. <Icon
  307. hidden={open}
  308. className="t-10 c-p"
  309. type="caret-down"
  310. onClick={() => this.setState({ open: !open })}
  311. />
  312. </span>
  313. <span hidden={open} style={{ width: 300 }} className="d-i-b nowrap">
  314. {(children || []).map(checkout => checkout.title).join(' + ')}
  315. </span>
  316. </div>
  317. <div className="d-i-b t-1 t-s-12 t-d-l-t"> ¥ {data.originMoney}</div>
  318. </div>
  319. <div hidden={!open} className="contain-list m-b-5 l-h-16">
  320. {(children || []).map(checkout => {
  321. return <div>
  322. <div style={{ width: 350 }} className="d-i-b t-1 t-s-12">
  323. <span className="d-i-b m-r-5">{checkout.title}</span>
  324. </div>
  325. <div className="d-i-b t-8 t-s-12">
  326. <span className="m-r-2">开通有效期: {checkout.expireDays ? `${checkout.expireDays}天` : '付款后立即生效'}</span>
  327. <span className="m-l-2">使用有效期: {checkout.useExpireDays ? `${checkout.useExpireDays}天` : '永久'}</span>
  328. </div>
  329. </div>;
  330. })}
  331. </div>
  332. {gift && <div className="service">
  333. <div className="d-i-b t-1 t-s-12">
  334. <span className="d-i-b f-w-b m-r-5">赠送服务</span>
  335. <span className="d-i-b">
  336. {gift.map(row => {
  337. return `${row.label}x${row.param ? row.param.label : row.number}`;
  338. }).join(' ')}
  339. <Icon className="m-l-5 close" type="exclamation-circle" theme="filled" onClick={() => {
  340. this.setState({ showList: true });
  341. }} />
  342. </span>
  343. </div>
  344. </div>}
  345. </div>
  346. );
  347. }
  348. }