page.js 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. import React from 'react';
  2. import './index.less';
  3. import { Icon } from 'antd';
  4. import Page from '@src/containers/Page';
  5. import Assets from '@src/components/Assets';
  6. import Footer from '../../../components/Footer';
  7. import { Contact, Comment, Consultation, AnswerCarousel } from '../../../components/Other';
  8. import Tabs from '../../../components/Tabs';
  9. import Button from '../../../components/Button';
  10. import { Main } from '../../../stores/main';
  11. import { Order } from '../../../stores/order';
  12. import { User } from '../../../stores/user';
  13. import { Course } from '../../../stores/course';
  14. import { CourseVsType } from '../../../../Constant';
  15. export default class extends Page {
  16. initState() {
  17. return {
  18. info: '1',
  19. number: 0,
  20. };
  21. }
  22. init() {
  23. this.courseVsMap = {};
  24. this.faqMap = {};
  25. this.faqs = [];
  26. this.commentMap = {};
  27. this.comments = [];
  28. this.promote = [];
  29. this.teacherMap = {};
  30. Main.getPromote().then(result => {
  31. this.promote = result.vs_list || [];
  32. this.setState({ promote: result });
  33. });
  34. Main.getBase().then(result => {
  35. this.setState({ base: result });
  36. });
  37. }
  38. initData() {
  39. Course.allVs().then(result => {
  40. result.forEach(row => {
  41. this.courseVsMap[row.vsType] = row;
  42. });
  43. this.onChangeItem(CourseVsType[0].value);
  44. });
  45. }
  46. onChangeTab(info) {
  47. this.setState({ info });
  48. }
  49. onChangeItem(key) {
  50. const item = this.courseVsMap[key];
  51. if (!this.faqs) {
  52. Main.listFaq({ page: 1, size: 100, channel: 'course-vs_index' }).then(result => {
  53. this.faqs = result.list;
  54. this.setState({ faqs: result.list });
  55. });
  56. }
  57. if (!this.commentMap[key]) {
  58. Main.listComment({ page: 1, size: 100, channel: 'course-vs', position: item.id }).then(result => {
  59. this.commentMap[key] = result.list;
  60. this.setState({ comments: result.list });
  61. });
  62. }
  63. if (!this.teacherMap[key]) {
  64. Course.allTeacher(item.id).then(result => {
  65. this.teacherMap[key] = result.list;
  66. this.setState({ teachers: result.list });
  67. });
  68. }
  69. this.setState({ key, data: item, faqs: this.faqs, comments: this.commentMap[key], teachers: this.teacherMap[key] });
  70. this.changeNumber(item.minNumber || 1);
  71. }
  72. changeNumber(number) {
  73. const { data } = this.state;
  74. let price = data.price * number;
  75. let max = 0;
  76. let maxIndex = -1;
  77. this.promote.forEach((row, i) => {
  78. if (row.number <= number) {
  79. if (row.number > max) {
  80. max = number;
  81. maxIndex = i;
  82. }
  83. }
  84. });
  85. if (maxIndex >= 0) {
  86. price *= this.promote[maxIndex].percent / 100;
  87. }
  88. this.setState({ number, price });
  89. }
  90. buy() {
  91. const { data } = this.props;
  92. Order.speedPay({ productType: 'course', productId: data.id }).then(result => {
  93. User.needPay(result).then(() => {
  94. linkTo('/my/course');
  95. });
  96. });
  97. }
  98. add() {
  99. const { data } = this.props;
  100. Order.addCheckout({ productType: 'course', productId: data.id }).then(() => {
  101. this.setState({ add: true });
  102. });
  103. }
  104. renderView() {
  105. const { number } = this.props.order;
  106. const { promote = {}, base = {} } = this.state;
  107. return (
  108. <div>
  109. <div className="top content">
  110. <Tabs
  111. type="text"
  112. active={'vs'}
  113. tabs={[
  114. { title: '在线课程', key: 'online', path: '/course/online' },
  115. { title: '1v1私教', key: 'vs', path: '/course/vs' },
  116. ]}
  117. />
  118. <div className="f-r">
  119. <span className="t-2 m-r-1">{(promote.vs || {}).text ? `优惠活动:${promote.vs.text}` : ''}</span>
  120. <Assets name="cart" onClick={() => linkTo('/cart')} />
  121. <span className="t-2">( {number || 0} )</span>
  122. </div>
  123. </div>
  124. {this.renderDetail()}
  125. <Contact data={base.contact} />
  126. <Footer />
  127. </div>
  128. );
  129. }
  130. renderDetail() {
  131. const { info, key, data, number, price } = this.state;
  132. return [
  133. <div className="center">
  134. <div className="content">
  135. <Assets className="m-b-2" width={1140} name="s" />
  136. <div className="item-list">
  137. {CourseVsType.map(t => {
  138. const course = this.courseVsMap[t.value] || {};
  139. return (
  140. <div className={`item ${key === t.value ? 'active' : ''}`} onClick={() => this.onChangeItem(t.value)}>
  141. <Assets name={t.icon} />
  142. <div className="t-1 t-s-20 f-w-b">{course.title}</div>
  143. <div className="t-2">{course.comment}</div>
  144. </div>
  145. );
  146. })}
  147. </div>
  148. <div className="item-detail">
  149. <div className="left">
  150. <Assets name={data.cover} />
  151. </div>
  152. <div className="right">
  153. <div className="t-1 t-s-16 m-b-2" dangerouslySetInnerHTML={{ __html: data.serviceContent }} />
  154. <div className="m-b-5">
  155. <div style={{ width: 120 }} className="d-i-b t-2">
  156. 适合人群
  157. </div>
  158. <div className="d-i-b t-1" dangerouslySetInnerHTML={{ __html: data.crowdContent }} />
  159. </div>
  160. <div className="m-b-5">
  161. <div style={{ width: 120 }} className="d-i-b t-2">
  162. 课时数
  163. </div>
  164. <div className="d-i-b t-1" dangerouslySetInnerHTML={{ __html: data.courseNoContent }} />
  165. </div>
  166. <div className="m-b-5">
  167. <div style={{ width: 120 }} className="d-i-b t-2">
  168. 授课流程
  169. </div>
  170. <div className="d-i-b t-1" dangerouslySetInnerHTML={{ __html: data.processContent }} />
  171. </div>
  172. <div className="m-b-5">
  173. <div style={{ width: 120 }} className="d-i-b t-2">
  174. 课程有效期
  175. </div>
  176. <div className="d-i-b t-1">{data.expirePreDays}天/10课时</div>
  177. </div>
  178. <div className="m-b-5 input">
  179. <div style={{ width: 120 }} className="d-i-b t-2">
  180. 购买课时
  181. </div>
  182. <div className="d-i-b t-1">
  183. <input value={number} style={{ width: 32 }} className="m-l-5 t-c" />
  184. <Icon
  185. className="up"
  186. type="caret-up"
  187. onClick={() => number < data.maxNumber && this.setState({ number: number + 1 })}
  188. />
  189. <Icon
  190. className="down"
  191. type="caret-down"
  192. onClick={() => number !== 1 && number > data.minNumber && this.setState({ number: number - 1 })}
  193. />
  194. </div>
  195. </div>
  196. <div className="m-b-5">
  197. <div style={{ width: 120 }} className="d-i-b t-2">
  198. 课程总价
  199. </div>
  200. <div className="d-i-b t-7 t-s-20 f-w-b"> ¥ {price}</div>
  201. </div>
  202. <div className="action">
  203. <Button className="m-r-1" radius size="lager" onClick={() => this.buy()}>
  204. 立即购买
  205. </Button>
  206. <Button theme="default" radius size="lager" onClick={() => this.add()}>
  207. <Assets name="add" />
  208. </Button>
  209. </div>
  210. </div>
  211. </div>
  212. </div>
  213. </div>,
  214. <div className="bottom">
  215. <div className="content">
  216. <Tabs
  217. type="full"
  218. border
  219. active={info}
  220. tabs={[
  221. { title: '老师资料', key: '1' },
  222. { title: '咨询方式', key: '2' },
  223. { title: 'FAQs', key: '3' },
  224. { title: '学员评价', key: '4' },
  225. ]}
  226. onChange={tab => this.onChangeTab(tab)}
  227. />
  228. {this[`renderTab${info}`]()}
  229. </div>
  230. </div>,
  231. ];
  232. }
  233. renderTab1() {
  234. return (
  235. <div className="tab-layout">
  236. <div className="teach-item">
  237. <div className="left t-c">
  238. <Assets className="m-b-1" />
  239. <div className="t-1 t-s-20">李奕都(DUKB24)</div>
  240. </div>
  241. <div className="right t-1 t-s-16">
  242. 针对 0G20 的集中训练针对 0G20 的集中训练针对 0G20 的集中训练针对 0G20 的集中训练。针对 0G20 的集中训练针对
  243. 0G20 的集中训练针对 0G20 的集,中训练针对 0G20 的集中训练针对 0G20 的集中训练针对。 针对 0G20
  244. 的集中训。练针对 0G20 的集中训练针对 0G20 的集中训练针对 0G20 的集中训练。 针对 0G20 的集中训练针对 0G20
  245. 的集中训练针对 0G。
  246. </div>
  247. </div>
  248. </div>
  249. );
  250. }
  251. renderTab2() {
  252. return (
  253. <div className="tab-layout">
  254. <Consultation />
  255. </div>
  256. );
  257. }
  258. renderTab3() {
  259. return (
  260. <div className="tab-layout">
  261. <AnswerCarousel
  262. hideBtn
  263. list={[
  264. { answer: '123123', content: '12312312' },
  265. { answer: '123123', content: '12312312' },
  266. { answer: '123123', content: '12312312' },
  267. { answer: '123123', content: '12312312' },
  268. ]}
  269. />
  270. </div>
  271. );
  272. }
  273. renderTab4() {
  274. return (
  275. <div className="tab-layout">
  276. <div className="m-b-1 t-r">
  277. <Button width={100} radius>
  278. 写评论
  279. </Button>
  280. </div>
  281. <Comment />
  282. <Comment />
  283. <Comment />
  284. <Comment />
  285. <Comment />
  286. </div>
  287. );
  288. }
  289. }