page.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. import React, { Component } from 'react';
  2. import { Link } from 'react-router-dom';
  3. import './index.less';
  4. import { Icon } from 'antd';
  5. import FileUpload from '@src/components/FileUpload';
  6. import Page from '@src/containers/Page';
  7. import Assets from '@src/components/Assets';
  8. import UserLayout from '../../../layouts/User';
  9. import Button from '../../../components/Button';
  10. import ProgressText from '../../../components/ProgressText';
  11. import { Icon as GIcon } from '../../../components/Icon';
  12. import menu from '../index';
  13. import Tabs from '../../../components/Tabs';
  14. import UserTable from '../../../components/UserTable';
  15. import More from '../../../components/More';
  16. import Modal from '../../../components/Modal';
  17. import Date from '../../../components/Date';
  18. import Note from '../../../components/Note';
  19. export default class extends Page {
  20. initState() {
  21. return {
  22. tab1: '1',
  23. tab2: '1',
  24. data: [
  25. {
  26. status: 'ing',
  27. history: [{}],
  28. list: [
  29. { status: 'ing', type: '1' },
  30. { status: 'not', type: '2' },
  31. { status: 'end', type: '3' },
  32. { status: 'not', type: '4' },
  33. { status: 'end', type: '5' },
  34. { status: 'not', type: '6' },
  35. { status: 'end', type: '7' },
  36. ],
  37. },
  38. {
  39. status: 'not',
  40. history: [{}],
  41. list: [
  42. { status: 'ing', type: '1' },
  43. { status: 'not', type: '2' },
  44. { status: 'end', type: '3' },
  45. { status: 'not', type: '4' },
  46. { status: 'end', type: '5' },
  47. { status: 'not', type: '6' },
  48. { status: 'end', type: '7' },
  49. ],
  50. },
  51. { status: 'end', history: [{}], list: [] },
  52. ],
  53. };
  54. }
  55. onAction() {}
  56. refresh(tab1, tab2) {
  57. this.setState({ tab1, tab2 });
  58. }
  59. renderView() {
  60. const { config } = this.props;
  61. return <UserLayout active={config.key} menu={menu} center={this.renderDetail()} />;
  62. }
  63. renderDetail() {
  64. const { tab1, tab2 } = this.state;
  65. return (
  66. <div className="detail-layout">
  67. <div className="tip">
  68. <div className="text">理清备考思路,避开常见误区,让学习的每一分钟发光发热!</div>
  69. <Link to="">去填写 ></Link>
  70. <Icon type="close-circle" theme="filled" />
  71. </div>
  72. <Tabs
  73. type="division"
  74. theme="theme"
  75. size="small"
  76. space={2.5}
  77. width={100}
  78. active={tab1}
  79. tabs={[{ key: '1', title: '在线课程' }, { key: '2', title: '1V1私教' }]}
  80. onChange={key => this.refresh(key, tab2)}
  81. />
  82. <Tabs
  83. type="tag"
  84. theme="white"
  85. size="small"
  86. space={5}
  87. width={54}
  88. active={tab2}
  89. tabs={[
  90. { key: '1', title: '全部' },
  91. { key: '2', title: '未开通' },
  92. { key: '3', title: '学习中' },
  93. { key: '4', title: '已结束' },
  94. ]}
  95. onChange={key => this.refresh(tab1, key)}
  96. />
  97. {this[`renderTab${tab1}`]()}
  98. <Modal className="clock-modal" title="打卡表" width={460} onClose={() => {}}>
  99. <div>
  100. <div className="d-i-b w-3">
  101. <div className="t-2 t-s-14">听课频率</div>
  102. <div className="t-4 t-s-18">2天/课时</div>
  103. </div>
  104. <div className="d-i-b w-3">
  105. <div className="t-2 t-s-14">作业完成度</div>
  106. <div className="t-4 t-s-18">50%</div>
  107. </div>
  108. </div>
  109. <div className="b-b m-t-1 m-b-1" />
  110. <div className="m-b-1">
  111. <div className="tag d-i-b t-s-16">
  112. <i style={{ background: '#6865FD' }} />
  113. 听课
  114. </div>
  115. <div className="tag d-i-b t-s-16">
  116. <i style={{ background: '#4299FF' }} />
  117. 预习
  118. </div>
  119. <div className="tag d-i-b t-s-16">
  120. <i style={{ background: '#E7E7E7' }} />
  121. 停课
  122. </div>
  123. </div>
  124. <Date
  125. hideInput
  126. disabledDate={() => false}
  127. dateRender={current => {
  128. return (
  129. <div className="ant-calendar-date">
  130. {current.get('date')}
  131. <i className="s1" style={{ background: '#6865FD' }} />
  132. <i className="s2" style={{ background: '#4299FF' }} />
  133. </div>
  134. );
  135. }}
  136. checkRefresh={(date, refresh) => {
  137. console.log(date);
  138. setTimeout(() => {
  139. refresh();
  140. }, 2000);
  141. return true;
  142. }}
  143. />
  144. <div className="t-2 t-s-12">*听课频率≤2天/课时,作业完成度≥90%,课程有效期可延长7-10天。</div>
  145. </Modal>
  146. <Modal title="恢复学习" onConfirm={() => {}} onCancel={() => {}}>
  147. <div className="t-2 t-s-18">恢复学习后,本课程的停课功能将无法使用。是否恢复学习?</div>
  148. </Modal>
  149. <Modal title="上传笔记" width={630} confirmText="提交" onConfirm={() => {}} onCancel={() => {}}>
  150. <textarea
  151. className="b-c-1 w-10 p-10 m-b-1"
  152. rows={6}
  153. placeholder="请输入留言内容,也可将文件拖动到这里上传。"
  154. />
  155. <div className="t-2 t-s-16 m-b-1">
  156. 上传文件 <FileUpload type="file" title="选择文件" />
  157. <span className="t-3 t-s-14">支持 docx, xls, PDF, rar, zip, PNG, JPG 等类型的文件</span>
  158. </div>
  159. <div className="b-b m-t-2" />
  160. </Modal>
  161. <Modal title="课后笔记" width={500} height={500} onClose={() => {}}>
  162. <Note />
  163. <Note />
  164. <Note />
  165. <Note />
  166. </Modal>
  167. </div>
  168. );
  169. }
  170. renderTab1() {
  171. const { data = [] } = this.state;
  172. return data.map(item => {
  173. return <Course data={item} />;
  174. });
  175. }
  176. renderTab2() {
  177. const { data = [] } = this.state;
  178. return data.map(item => {
  179. return <Education data={item} />;
  180. });
  181. }
  182. }
  183. class Course extends Component {
  184. constructor(props) {
  185. super(props);
  186. this.columns = [
  187. { title: '学习内容' },
  188. { title: '预习作业' },
  189. { title: '进度' },
  190. { title: '最近学习' },
  191. { title: '笔记' },
  192. { title: '问答' },
  193. ];
  194. this.state = { open: false };
  195. }
  196. render() {
  197. const { data = {} } = this.props;
  198. switch (data.status) {
  199. case 'ing':
  200. return this.renderIng();
  201. case 'not':
  202. return this.renderNot();
  203. case 'end':
  204. return this.renderEnd();
  205. default:
  206. return <div />;
  207. }
  208. }
  209. renderIng() {
  210. const { data } = this.props;
  211. const { history = [] } = data;
  212. return (
  213. <div className="course-item ing">
  214. <div className="title">
  215. <div className="tag">学习中</div>
  216. <div className="text">OG20整合刷题-语法SC</div>
  217. </div>
  218. <div className="continue">
  219. <Assets name="notice" />
  220. 继续学习:课时 13:解读句子属性
  221. </div>
  222. <div className="detail">
  223. <div className="left">
  224. <Assets name="sun_blue" />
  225. <div className="info">
  226. <div className="t1">授课老师</div>
  227. <div className="t2">李小小</div>
  228. <div className="t1">有效期</div>
  229. <div className="t2">88Day</div>
  230. </div>
  231. </div>
  232. <div className="right">
  233. <div className="item">
  234. <GIcon name="speed-block" noHover />
  235. <div className="text">
  236. <span>12</span>/20
  237. </div>
  238. </div>
  239. <div className="item">
  240. <GIcon name="question-block" active noHover />
  241. <div className="text">
  242. <span>12</span>/20
  243. </div>
  244. </div>
  245. <div className="item">
  246. <GIcon name="clockin-block" noHover />
  247. <div className="text">
  248. <span>12</span>/20
  249. </div>
  250. </div>
  251. <div className="item">
  252. <GIcon name="note-block" noHover />
  253. <div className="text">
  254. <span>12</span>/20
  255. </div>
  256. </div>
  257. </div>
  258. </div>
  259. <UserTable size="small" columns={this.columns} data={history} />
  260. </div>
  261. );
  262. }
  263. renderNot() {
  264. return (
  265. <div className="course-item not">
  266. <div className="title">
  267. <div className="tag">未开通</div>
  268. <div className="text">OG20整合刷题-语法SC</div>
  269. </div>
  270. <div className="detail">
  271. <div className="left">
  272. <Assets name="sun_blue" />
  273. <div className="info">
  274. <div className="t1">授课老师</div>
  275. <div className="t2">李小小</div>
  276. <div className="t1">有效期</div>
  277. <div className="t2">88Day</div>
  278. </div>
  279. </div>
  280. <div className="right t-c">
  281. <div className="text">请于 2020-06-26 前开通</div>
  282. <Button size="lager" radius>
  283. 立即开通
  284. </Button>
  285. </div>
  286. </div>
  287. </div>
  288. );
  289. }
  290. renderEnd() {
  291. return (
  292. <div className="course-item end">
  293. <div className="title">
  294. <div className="tag">已结束</div>
  295. <div className="text">OG20整合刷题-语法SC</div>
  296. </div>
  297. <div className="detail">
  298. <div className="left">
  299. <Assets name="sun_blue" />
  300. <div className="info">
  301. <div className="t1">授课老师</div>
  302. <div className="t2">李小小</div>
  303. <div className="t1">有效期</div>
  304. <div className="t2">88Day</div>
  305. </div>
  306. </div>
  307. <div className="right">
  308. <div className="item">
  309. <GIcon name="gift-block" active />
  310. <div className="text">赠送7天</div>
  311. </div>
  312. </div>
  313. </div>
  314. </div>
  315. );
  316. }
  317. }
  318. class Education extends Component {
  319. constructor(props) {
  320. super(props);
  321. this.columns = [
  322. { title: '学习内容' },
  323. { title: '预习作业' },
  324. { title: '授课时间' },
  325. { title: '课后笔记' },
  326. { title: '课后补充' },
  327. ];
  328. this.state = { open: true, tab: '1' };
  329. }
  330. render() {
  331. const { data = {} } = this.props;
  332. switch (data.status) {
  333. case 'ing':
  334. return this.renderIng();
  335. case 'not':
  336. return this.renderNot();
  337. case 'end':
  338. return this.renderEnd();
  339. default:
  340. return <div />;
  341. }
  342. }
  343. renderIng() {
  344. const { tab } = this.state;
  345. return (
  346. <div className="education-item ing">
  347. <div className="title">
  348. <div className="tag">学习中</div>
  349. <div className="text">OG20整合刷题-语法SC</div>
  350. <div className="right">
  351. <More menu={[{ label: '评价', key: '1' }, { label: '停课', key: '2' }]} />
  352. </div>
  353. </div>
  354. <div className="continue">
  355. <Assets name="notice" />
  356. 继续学习:课时 13:解读句子属性
  357. </div>
  358. <div className="detail">
  359. <div className="left">
  360. <Assets name="sun_blue" />
  361. <div className="info">
  362. <div className="t1">授课老师</div>
  363. <div className="t2">李小小</div>
  364. <div className="t1">有效期</div>
  365. <div className="t2">88Day</div>
  366. </div>
  367. </div>
  368. <div className="right">
  369. <div className="item">
  370. <GIcon name="speed-block" noHover />
  371. <div className="text">
  372. <span>12</span>/20
  373. </div>
  374. </div>
  375. <div className="item">
  376. <GIcon name="question-block" active noHover />
  377. <div className="text">
  378. <span>12</span>/20
  379. </div>
  380. </div>
  381. </div>
  382. </div>
  383. <Tabs
  384. className="t-l"
  385. type="line"
  386. theme="theme"
  387. size="small"
  388. width={80}
  389. active={tab}
  390. tabs={[{ key: '1', title: '在线课程' }, { key: '2', title: '1V1私教' }]}
  391. onChange={key => this.setState({ tab: key })}
  392. />
  393. <div className="class-hour">
  394. <div className="text">课时 5:解读句子属性</div>
  395. <div className="right">
  396. <GIcon name="prev" onClick={() => {}} />
  397. <span>上一课时</span>
  398. <span>下一课时</span>
  399. <GIcon name="next" onClick={() => {}} />
  400. </div>
  401. </div>
  402. {tab === '1' ? this.renderTimeLine() : this.renderTable()}
  403. </div>
  404. );
  405. }
  406. renderNot() {
  407. return (
  408. <div className="education-item not">
  409. <div className="title">
  410. <div className="tag">未开通</div>
  411. <div className="text">OG20整合刷题-语法SC</div>
  412. </div>
  413. <div className="detail">
  414. <div className="left">
  415. <Assets name="sun_blue" />
  416. <div className="info">
  417. <div className="t1">授课老师</div>
  418. <div className="t2">李小小</div>
  419. <div className="t1">有效期</div>
  420. <div className="t2">88Day</div>
  421. </div>
  422. </div>
  423. <div className="right">
  424. <div className="qr-code">
  425. <Assets name="qrcode" />
  426. <div className="i">
  427. <div className="t1">请尽快与老师预约上课时间</div>
  428. <div className="t2">请于 2019-07-25 前开通课程</div>
  429. </div>
  430. </div>
  431. </div>
  432. </div>
  433. {this.renderTimeLine()}
  434. </div>
  435. );
  436. }
  437. renderEnd() {
  438. const { open } = this.state;
  439. return (
  440. <div className="education-item end">
  441. <div className="title">
  442. <div className="tag">已结课</div>
  443. <div className="text">OG20整合刷题-语法SC</div>
  444. </div>
  445. <div className="detail">
  446. <div className="left">
  447. <Assets name="sun_blue" />
  448. <div className="info">
  449. <div className="t1">授课老师</div>
  450. <div className="t2">李小小</div>
  451. <div className="t1">有效期</div>
  452. <div className="t2">88Day</div>
  453. </div>
  454. </div>
  455. <div className="right">
  456. <div className="item">
  457. <GIcon name="speed-block" noHover />
  458. <div className="text">
  459. <span>12</span>/20
  460. </div>
  461. </div>
  462. <div className="item">
  463. <GIcon name="question-block" active noHover />
  464. <div className="text">
  465. <span>12</span>/20
  466. </div>
  467. </div>
  468. </div>
  469. <div className="open">
  470. <GIcon name={open ? 'up' : 'down'} onClick={() => this.setState({ open: !open })} />
  471. </div>
  472. </div>
  473. {open && this.renderTable()}
  474. </div>
  475. );
  476. }
  477. renderTimeLine() {
  478. const { data = {} } = this.props;
  479. const { list = [] } = data;
  480. return (
  481. <div className="time-line">
  482. {list.map(item => {
  483. return <TimeLineItem data={item} />;
  484. })}
  485. </div>
  486. );
  487. }
  488. renderTable() {
  489. const { data = {} } = this.props;
  490. const { history = [] } = data;
  491. return <UserTable size="small" columns={this.columns} data={history} />;
  492. }
  493. }
  494. class TimeLineItem extends Component {
  495. constructor(props) {
  496. super(props);
  497. this.titleMap = {
  498. 1: '预约时间',
  499. 2: '答疑文档',
  500. 3: '上课',
  501. 4: '课后笔记',
  502. 5: '课后补充',
  503. 6: '备考信息',
  504. 7: '完成作业',
  505. };
  506. this.iconMap = {
  507. 1: 'time-icon',
  508. 2: 'QA-icon',
  509. 3: 'class-icon',
  510. 4: 'note-icon',
  511. 5: 'supplement-icon',
  512. 6: 'information-icon',
  513. 7: 'homework-icon',
  514. };
  515. }
  516. onClick(key) {
  517. const { data = {}, onClick } = this.props;
  518. const { status } = data;
  519. if (status === 'not') return;
  520. if (onClick) onClick(key);
  521. }
  522. render() {
  523. const { data = {} } = this.props;
  524. const { status, type } = data;
  525. return (
  526. <div className={`time-line-item ${status}`}>
  527. <div className="icon-title">
  528. <GIcon name={this.iconMap[type]} active={status !== 'not'} noHover />
  529. <div className="title">{this.titleMap[type]}</div>
  530. </div>
  531. <div className="time-line-detail">{this.renderDetail()}</div>
  532. </div>
  533. );
  534. }
  535. renderDetail() {
  536. const { data = {} } = this.props;
  537. const { type, status } = data;
  538. switch (type) {
  539. case '1':
  540. return status === 'not' ? (
  541. <span>请尽快与老师预约上课时间,扫码加微信</span>
  542. ) : (
  543. <span>2019-07-24 09:00 ~ 10:00</span>
  544. );
  545. case '2':
  546. return <span className="link">点此上传</span>;
  547. case '3':
  548. return status === 'end' ? (
  549. <span>
  550. CCtalk 频道号 :1234567 <span className="link">CC talk使用手册</span>
  551. </span>
  552. ) : (
  553. <input placeholder="请输入CCtalk用户名查看授课频道" />
  554. );
  555. case '4':
  556. return (
  557. <div>
  558. <div>
  559. <span className="link">点此上传</span>
  560. </div>
  561. <div className="note-list">
  562. <Note onAction={() => {}} actionList={[{ key: '123', label: '123' }]} />
  563. <Note />
  564. <Note />
  565. <Note />
  566. </div>
  567. </div>
  568. );
  569. case '5':
  570. return <span className="link">写留言</span>;
  571. case '6':
  572. return [
  573. <div>
  574. <span>基本情况梳理</span>
  575. <span>2019-08-20 更新</span>
  576. <span className="link">修改</span>
  577. </div>,
  578. <div>
  579. <span>备考细节梳理</span>
  580. <span className="link">填写</span>
  581. </div>,
  582. ];
  583. case '7':
  584. return <ProgressText progress={10} size="small" />;
  585. default:
  586. return <div />;
  587. }
  588. }
  589. }