page.js 13 KB

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