page.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. import React from 'react';
  2. import './index.less';
  3. import { Modal } from 'antd';
  4. import { Link } from 'react-router-dom';
  5. import Page from '@src/containers/Page';
  6. import { asyncConfirm } from '@src/services/AsyncTools';
  7. import { formatTreeData, formatSeconds, formatDate, formatPercent } from '@src/services/Tools';
  8. import Continue from '../../../components/Continue';
  9. import Step from '../../../components/Step';
  10. import Panel from '../../../components/Panel';
  11. import List from '../../../components/List';
  12. import Tabs from '../../../components/Tabs';
  13. import Module from '../../../components/Module';
  14. import Input from '../../../components/Input';
  15. import Button from '../../../components/Button';
  16. import AnswerButton from '../../../components/AnswerButton';
  17. import Division from '../../../components/Division';
  18. import Card from '../../../components/Card';
  19. import ListTable from '../../../components/ListTable';
  20. import ProgressText from '../../../components/ProgressText';
  21. import IconButton from '../../../components/IconButton';
  22. import { Main } from '../../../stores/main';
  23. import { My } from '../../../stores/my';
  24. import { Sentence } from '../../../stores/sentence';
  25. import { Question } from '../../../stores/question';
  26. import { Course } from '../../../stores/course';
  27. import { User } from '../../../stores/user';
  28. const SENTENCE = 'sentence';
  29. const PREVIEW = 'preview';
  30. const PREVIEW_CLASS = 'PREVIEW_CLASS';
  31. const PREVIEW_LIST = 'PREVIEW_LIST';
  32. const exerciseColumns = [
  33. {
  34. title: '练习册',
  35. width: 250,
  36. align: 'left',
  37. render: item => {
  38. return (
  39. <div className="table-row">
  40. <div className="night f-s-16">{item.title}</div>
  41. <div>
  42. <ProgressText
  43. progress={item.report.id ? formatPercent(item.repport.userNumber, item.report.questionNumber) : 0}
  44. size="small"
  45. />
  46. </div>
  47. </div>
  48. );
  49. },
  50. },
  51. {
  52. title: '正确率',
  53. width: 150,
  54. align: 'left',
  55. render: item => {
  56. return (
  57. <div className="table-row">
  58. <div className="night f-s-16 f-w-b">--</div>
  59. <div className="f-s-12">{formatPercent(item.stat.totalCorrect, item.stat.totalNumber, false)}</div>
  60. </div>
  61. );
  62. },
  63. },
  64. {
  65. title: '全站用时',
  66. width: 150,
  67. align: 'left',
  68. render: item => {
  69. return (
  70. <div className="table-row">
  71. <div className="night f-s-16 f-w-b">--</div>
  72. <div className="f-s-12">全站{formatSeconds(item.stat.totalTime / item.stat.totalNumber)}</div>
  73. </div>
  74. );
  75. },
  76. },
  77. {
  78. title: '最近做题',
  79. width: 150,
  80. align: 'left',
  81. render: () => {
  82. return (
  83. <div className="table-row">
  84. <div>2019-04-28</div>
  85. <div>07:30</div>
  86. </div>
  87. );
  88. },
  89. },
  90. {
  91. title: '操作',
  92. width: 180,
  93. align: 'left',
  94. render: item => {
  95. return (
  96. <div className="table-row p-t-1">
  97. {!item.report && (
  98. <IconButton type="start" tip="Start" onClick={() => Question.startLink('preview', item)} />
  99. )}
  100. {item.report.id && !item.report.isFinish && (
  101. <IconButton
  102. className="m-r-2"
  103. type="continue"
  104. tip="Continue"
  105. onClick={() => Question.continueLink('preview', item)}
  106. />
  107. )}
  108. {item.report.id && (
  109. <IconButton type="restart" tip="Restart" onClick={() => this.restart('preview', item)} />
  110. )}
  111. </div>
  112. );
  113. },
  114. },
  115. {
  116. title: '报告',
  117. width: 30,
  118. align: 'right',
  119. render: item => {
  120. return (
  121. <div className="table-row p-t-1">
  122. {item.report.isFinish && <IconButton type="report" tip="Report" onClick={() => Question.reportLink(item)} />}
  123. </div>
  124. );
  125. },
  126. },
  127. ];
  128. export default class extends Page {
  129. constructor(props) {
  130. super(props);
  131. this.sentenceColums = [
  132. {
  133. title: '练习册',
  134. width: 250,
  135. align: 'left',
  136. render: (record) => {
  137. let progress = 0;
  138. if (record.report) {
  139. progress = formatPercent(record.report.userNumber, record.report.questionNumber);
  140. }
  141. return (
  142. <div className="table-row">
  143. <div className="night f-s-16">{record.title}</div>
  144. <div>
  145. <ProgressText progress={progress} size="small" />
  146. </div>
  147. </div>
  148. );
  149. },
  150. },
  151. {
  152. title: '正确率',
  153. width: 150,
  154. align: 'left',
  155. render: (record) => {
  156. let correct = '--';
  157. if (record.report) {
  158. correct = formatPercent(record.report.userCorrect, record.report.userNumber, false);
  159. }
  160. return (
  161. <div className="table-row">
  162. <div className="night f-s-16 f-w-b">{correct}</div>
  163. <div className="f-s-12">全站{formatPercent(record.stat.totalCorrect, record.stat.totalNumber, false)}</div>
  164. </div>
  165. );
  166. },
  167. },
  168. {
  169. title: '全站用时',
  170. width: 150,
  171. align: 'left',
  172. render: (record) => {
  173. let time = '--';
  174. if (record.report) {
  175. time = formatSeconds(record.report.userTime / record.report.userNumber);
  176. }
  177. return (
  178. <div className="table-row">
  179. <div className="night f-s-16 f-w-b">{time}</div>
  180. <div className="f-s-12">全站{formatSeconds(record.stat.totalTime / record.stat.totalNumber)}</div>
  181. </div>
  182. );
  183. },
  184. },
  185. {
  186. title: '最近做题',
  187. width: 150,
  188. align: 'left',
  189. render: (record) => {
  190. const time = record.report ? record.report.updateTime : record.paper ? record.paper.latestTime : null;
  191. if (!time) return null;
  192. return (
  193. <div className="table-row">
  194. <div>{formatDate(time, 'YYYY-MM-DD')}</div>
  195. <div>{formatDate(time, 'HH:mm')}</div>
  196. </div>
  197. );
  198. },
  199. },
  200. {
  201. title: '操作',
  202. width: 180,
  203. align: 'left',
  204. render: (record) => {
  205. return (
  206. <div className="table-row p-t-1">
  207. {!record.report && <IconButton type="start" tip="Start" onClick={() => {
  208. Question.startLink('sentence', record);
  209. }} />}
  210. {(record.report && !record.report.isFinish) && <IconButton className="m-r-2" type="continue" tip="Continue" onClick={() => {
  211. Question.continueLink('sentence', record);
  212. }} />}
  213. {(record.report && !!record.report.isFinish) && <IconButton type="restart" tip="Restart" onClick={() => {
  214. this.restart(record);
  215. }} />}
  216. </div>
  217. );
  218. },
  219. },
  220. {
  221. title: '报告',
  222. width: 30,
  223. align: 'right',
  224. render: (record) => {
  225. if (!record.report || !record.report.isFinish) return null;
  226. return (
  227. <div className="table-row p-t-1">
  228. <IconButton type="report" tip="Report" onClick={() => {
  229. Question.reportLink(record);
  230. }} />
  231. </div>
  232. );
  233. },
  234. },
  235. ];
  236. }
  237. initState() {
  238. this.code = null;
  239. this.columns = exerciseColumns;
  240. this.exerciseProgress = {};
  241. this.inited = false;
  242. return {
  243. tab1: SENTENCE,
  244. tab2: '',
  245. pt: PREVIEW_CLASS,
  246. tabs: [],
  247. allClass: [],
  248. classProcess: {},
  249. };
  250. }
  251. init() {
  252. Main.getExercise().then(result => {
  253. const list = result.map((row) => {
  254. row.title = `${row.titleZh}${row.titleEn}`;
  255. row.key = row.extend;
  256. return row;
  257. });
  258. const tabs = formatTreeData(list, 'id', 'title', 'parentId');
  259. tabs.push({ key: PREVIEW, name: '预习作业' });
  260. this.setState({ tabs });
  261. this.inited = true;
  262. this.refreshData();
  263. });
  264. }
  265. initData() {
  266. const { info = {} } = this.props.user;
  267. if (info.latestExercise) {
  268. // 获取最后一次做题记录
  269. Question.baseReport(info.latestExercise).then((result) => {
  270. this.setState({ latest: result });
  271. });
  272. }
  273. const data = Object.assign(this.state, this.state.search);
  274. this.setState(data);
  275. if (this.inited) this.refreshData();
  276. }
  277. refreshData(tab) {
  278. const { tab1 } = this.state;
  279. switch (tab || tab1) {
  280. case SENTENCE:
  281. this.refreshSentence();
  282. break;
  283. case PREVIEW:
  284. this.refreshPreview();
  285. break;
  286. default:
  287. this.refreshExercise(tab || tab1);
  288. }
  289. }
  290. refreshSentence() {
  291. const { sentence } = this.state;
  292. if (!sentence) {
  293. User.clearSentenceTrail();
  294. Sentence.getInfo().then(result => {
  295. // result.code = '123123';
  296. // result.trailPages = 20;
  297. this.setState({ sentence: result });
  298. return result;
  299. })
  300. .then(({ code, trailPages, chapters }) => {
  301. return Sentence.listArticle().then(result => {
  302. const chapterSteps = [];
  303. const chapterMap = {};
  304. const map = {};
  305. const trailArticles = [];
  306. let totalPage = 0;
  307. let introduction = null;
  308. let exerciseChapter = null;
  309. let index = 0;
  310. let lastChapter = -1;
  311. chapters.forEach(row => {
  312. chapterMap[row.value] = row;
  313. if (row.exercise) exerciseChapter = row;
  314. });
  315. result.forEach((article) => {
  316. if (article.chapter === 0) introduction = article;
  317. if (!map[article.chapter]) {
  318. map[article.chapter] = [];
  319. }
  320. article.startPage = totalPage + 1;
  321. article.endPage = totalPage + article.pages;
  322. if (article.chapter) {
  323. article.position = `Part ${article.part}`;
  324. } else {
  325. // 设置list中的样式
  326. article.style = 'introduction';
  327. }
  328. totalPage += article.pages;
  329. if (article.startPage < trailPages) {
  330. if (lastChapter !== article.chapter) {
  331. lastChapter = article.chapter;
  332. trailArticles.push(Object.assign({ articles: [] }, chapterMap[article.chapter] || {}));
  333. }
  334. trailArticles[trailArticles.length - 1].articles.push(article);
  335. }
  336. map[article.chapter].push(article);
  337. });
  338. if (!code) {
  339. chapterSteps.push('试用');
  340. }
  341. // 添加前言
  342. if (introduction) {
  343. chapterSteps.push(`${introduction.title}`);
  344. chapterMap[0] = {
  345. title: introduction.title,
  346. value: 0,
  347. };
  348. }
  349. index += 1;
  350. chapters.forEach(row => {
  351. chapterSteps.push(`「${index}」${row.short}`);
  352. index += 1;
  353. });
  354. this.setState({ articleMap: map, trailArticles, chapterSteps, introduction, chapterMap, exerciseChapter });
  355. });
  356. })
  357. .then(() => {
  358. return Sentence.listPaper().then(result => {
  359. this.setState({ paperList: result, paperFilterList: result });
  360. });
  361. });
  362. }
  363. }
  364. refreshPreview() {
  365. const { pt } = this.state;
  366. switch (pt) {
  367. case PREVIEW_LIST:
  368. this.refreshListPreview();
  369. break;
  370. case PREVIEW_CLASS:
  371. default:
  372. this.refreshClassProcess();
  373. break;
  374. }
  375. }
  376. refreshClassProcess() {
  377. Course.classProcess().then(result => {
  378. const classProcess = {};
  379. for (let i = 0; i < result.length; i += 1) {
  380. const item = result[i];
  381. classProcess[item.category].push(item);
  382. }
  383. this.setState({ classProcess });
  384. });
  385. }
  386. refreshListPreview() {
  387. Question.listPreview().then(result => {
  388. this.setState({ previews: result });
  389. });
  390. }
  391. refreshExercise(tab) {
  392. const { tabs, tab1 } = this.state;
  393. let { tab2 } = this.state;
  394. if (!tabs) {
  395. // 等待数据加载
  396. return;
  397. }
  398. const [subject] = tabs.filter(row => row.key === tab);
  399. // 切换tab1的情况
  400. if (tab2 === '' || tab1 !== tab) {
  401. tab2 = subject.children[0].key;
  402. this.setState({ tab2 });
  403. }
  404. const [type] = subject.children.filter(row => row.key === tab2);
  405. Question.getExerciseProgress(type.id).then((result => {
  406. // const exerciseProgress = getMap(r, 'id');
  407. result = result.map(row => {
  408. row.info = [{
  409. title: '已做',
  410. number: row.userNumber || 0,
  411. unit: '题',
  412. }, {
  413. title: '剩余',
  414. number: row.questionNumber - row.userNumber || 0,
  415. unit: '题',
  416. }, {
  417. title: '总计',
  418. number: row.questionNumber || 0,
  419. unit: '题',
  420. }];
  421. if (row.userStat) {
  422. row.correct = formatPercent(row.userStat.userCorrect, row.userStat.userNumber, false);
  423. } else {
  424. row.correct = '--';
  425. }
  426. row.progress = formatPercent(row.questionNumber - row.userNumber || 0, row.questionNumber);
  427. row.totalCorrect = formatPercent(row.stat.totalCorrect, row.stat.totalNumber, false);
  428. row.children = row.children.map((r) => {
  429. r.title = r.title || r.titleZh;
  430. r.progress = formatPercent(r.userNumber, r.questionNumber);
  431. return r;
  432. });
  433. return row;
  434. });
  435. this.setState({ exerciseProgress: result });
  436. }));
  437. }
  438. onChangePreviewType(type) {
  439. this.setState({ pt: type });
  440. this.refreshPreview();
  441. }
  442. onChangeTab(level, tab) {
  443. const { tab1 } = this.state;
  444. const data = {};
  445. if (level > 1) {
  446. data.tab1 = tab1;
  447. data.tab2 = tab;
  448. } else {
  449. data.tab1 = tab;
  450. }
  451. // this.refreshData(tab);
  452. this.refreshQuery(data);
  453. }
  454. previewAction(type, item) {
  455. switch (type) {
  456. case 'start':
  457. Question.startLink('preview', item);
  458. break;
  459. case 'restart':
  460. this.restart(item);
  461. break;
  462. case 'continue':
  463. Question.continueLink('preview', item);
  464. break;
  465. default:
  466. break;
  467. }
  468. }
  469. restart(item) {
  470. asyncConfirm('提示', '是否重置', () => {
  471. Question.restart(item.paper.id).then(() => {
  472. this.refresh();
  473. });
  474. });
  475. }
  476. exerciseList(item) {
  477. linkTo(`/exercise/list/${item.id}`);
  478. }
  479. activeSentence() {
  480. Sentence.active(this.code)
  481. .then(() => {
  482. // 重新获取长难句信息
  483. User.clearSentenceTrail();
  484. this.setState({ sentence: null, articleMap: null, paperList: null });
  485. this.refresh();
  486. })
  487. .catch(err => {
  488. this.setState({ sentenceError: err.message });
  489. });
  490. }
  491. trailSentence() {
  492. User.sentenceTrail();
  493. this.setState({ sentenceError: null });
  494. }
  495. sentenceRead(article) {
  496. if (article) {
  497. linkTo(`/sentence/read?chapter=${article.chapter}&part=${article.part}`);
  498. } else {
  499. linkTo('/sentence/read');
  500. }
  501. }
  502. sentenceFilter(value) {
  503. const { paperList } = this.state;
  504. const list = paperList.filter(row => {
  505. const finish = row.paper ? row.paper.times > 0 : false;
  506. if (value === 0) {
  507. return !finish;
  508. }
  509. return finish;
  510. });
  511. this.setState({ paperFilterList: list, paperChecked: value });
  512. }
  513. clearExercise() {
  514. My.clearLatestExercise();
  515. this.setState({ latest: null });
  516. }
  517. renderView() {
  518. const { tab1, tab2, tabs, latest, sentenceModel } = this.state;
  519. const [subject] = tabs.filter(row => row.key === tab1);
  520. const children = subject ? subject.children : [];
  521. return (
  522. <div>
  523. {latest && <Continue
  524. data={latest}
  525. onClose={() => {
  526. this.clearExercise();
  527. }}
  528. onContinue={() => {
  529. Question.continueLink('exercise', latest);
  530. }}
  531. onRestart={() => {
  532. this.restart(latest);
  533. }}
  534. onNext={() => {
  535. Question.continueLink('exercise', latest);
  536. }} />}
  537. <div className="content">
  538. <Module className="m-t-2">
  539. <Tabs type="card" active={tab1} tabs={tabs} onChange={key => {
  540. this.onChangeTab(1, key);
  541. }} />
  542. {children.length > 1 && <Tabs active={tab2} tabs={children} onChange={key => this.onChangeTab(2, key)} />}
  543. </Module>
  544. {tab1 !== SENTENCE && tab1 !== PREVIEW && this.renderExercise()}
  545. {tab1 === SENTENCE && this.renderSentence()}
  546. {tab1 === PREVIEW && this.renderPreview()}
  547. </div>
  548. {sentenceModel && this.renderInputCodeModel()}
  549. </div>
  550. );
  551. }
  552. renderPreview() {
  553. const { previewType } = this.state;
  554. switch (previewType) {
  555. case PREVIEW_CLASS:
  556. return this.renderPreviewClass();
  557. case PREVIEW_LIST:
  558. return this.renderPreviewList();
  559. default:
  560. return <div />;
  561. }
  562. }
  563. renderPreviewClass() {
  564. const { allClass, classProcess } = this.state;
  565. return (
  566. <div className="work-body">
  567. <div className="work-nav">
  568. <div className="left">完成情况</div>
  569. <div className="right theme c-p" onClick={() => this.onChangePreviewType(PREVIEW_LIST)}>
  570. 全部作业 >
  571. </div>
  572. </div>
  573. <Division col="3">
  574. {allClass.map(item => {
  575. return <Card data={item} process={classProcess[item.id]} previewAction={this.previewAction} />;
  576. })}
  577. </Division>
  578. </div>
  579. );
  580. }
  581. renderPreviewList() {
  582. const { previews } = this.state;
  583. return (
  584. <div className="work-body">
  585. <div className="work-nav">
  586. <div className="left">全部作业</div>
  587. <div className="right theme c-p" onClick={() => this.onChangePreviewType(PREVIEW_CLASS)}>
  588. 我的课程 >
  589. </div>
  590. </div>
  591. <ListTable
  592. filters={[
  593. {
  594. type: 'radio',
  595. checked: 'today',
  596. list: [{ key: 'today', title: '今日需完成' }, { key: 'tomorrow', title: '明日需完成' }],
  597. },
  598. {
  599. type: 'radio',
  600. checked: 'unfinish',
  601. list: [{ key: 'unfinish', title: '未完成' }, { key: 'finish', title: '已完成' }],
  602. },
  603. { type: 'select', checked: 'all', list: [{ key: 'all', title: '全部' }] },
  604. ]}
  605. data={previews}
  606. columns={this.columns}
  607. />
  608. </div>
  609. );
  610. }
  611. renderSentence() {
  612. const { sentence = {} } = this.state;
  613. const { sentenceTrail } = this.props.user;
  614. if (sentence.code || sentenceTrail) {
  615. return this.renderSentenceArticle();
  616. }
  617. return this.renderInputCode();
  618. }
  619. renderSentenceArticle() {
  620. const { sentence = {}, introduction, chapterSteps, chapterStep = 1, exerciseChapter = {}, chapterMap = {}, articleMap = {}, trailArticles = [], paperFilterList = [], paperList = [], paperChecked } = this.state;
  621. const { sentenceTrail } = this.props.user;
  622. let maxStep = 0;
  623. if (sentenceTrail) {
  624. // 试用只能访问第一step
  625. maxStep = 1;
  626. // 查找练习章节
  627. }
  628. // 减去前言计算chapter
  629. const chapter = introduction ? chapterStep - 1 : chapterStep;
  630. const chapterInfo = chapterMap[chapter] || {};
  631. let isExercise = false;
  632. if (chapterInfo && chapterInfo.exercise) {
  633. isExercise = true;
  634. }
  635. return <div>
  636. {sentence.code && <div className='sentence-code'>CODE: {sentence.code}</div>}
  637. {sentenceTrail && <div className='sentence-code'>CODE: <Link to=''>去获取</Link><a onClick={() => {
  638. this.setState({ sentenceModel: true });
  639. }}>输入</a></div>}
  640. <Module>
  641. <Step
  642. list={chapterSteps}
  643. step={chapterStep}
  644. onClick={(step) => {
  645. this.setState({ chapterStep: step });
  646. }}
  647. message='请购买后访问'
  648. maxStep={maxStep}
  649. />
  650. </Module>
  651. {/* 正常前言 */}
  652. {sentence.code && chapter === 0 && <List
  653. // title={chapterInfo.title}
  654. list={[introduction]}
  655. onClick={() => {
  656. this.sentenceRead();
  657. }}
  658. />}
  659. {/* 正常文章 */}
  660. {sentence.code && chapter > 0 && !isExercise && <List
  661. position={`Chapter${chapter}`}
  662. title={chapterInfo.title}
  663. list={articleMap[chapter]}
  664. onClick={(part) => {
  665. this.sentenceRead(part);
  666. }}
  667. />}
  668. {/* 正常练习 */}
  669. {sentence.code && isExercise && <ListTable
  670. position={`Chapter${chapter}`}
  671. title={chapterInfo.title}
  672. filters={[{
  673. type: 'radio',
  674. checked: paperChecked,
  675. list: [{ key: 0, title: '未完成' }, { key: 1, title: '已完成' }],
  676. onChange: (item) => {
  677. this.sentenceFilter(item.key);
  678. },
  679. }]}
  680. data={paperFilterList}
  681. columns={this.sentenceColums}
  682. />}
  683. {/* 试读文章 */}
  684. {sentenceTrail && trailArticles.map((info) => {
  685. return <List
  686. position={info.value ? `Chapter${info.value}` : null}
  687. title={info.title}
  688. list={info.articles}
  689. onClick={(part) => {
  690. this.sentenceRead(part);
  691. }}
  692. />;
  693. })}
  694. {/* 试练 */}
  695. {sentenceTrail && <ListTable
  696. position={`Chapter${exerciseChapter.value}`}
  697. title={exerciseChapter.title}
  698. data={paperList}
  699. columns={this.sentenceColums}
  700. />}
  701. </div>;
  702. }
  703. renderInputCode() {
  704. const { sentenceError } = this.state;
  705. return (
  706. <Module className="code-module">
  707. <div className="title">输入《千行GMAT长难句》专属 Code,解锁在线练习功能。</div>
  708. <div className="input-block">
  709. <Input size="lager" placeholder="请输入CODE" onChange={(value) => {
  710. this.code = value;
  711. }} />
  712. <Button size="lager" onClick={() => {
  713. this.activeSentence();
  714. }}>解锁</Button>
  715. {sentenceError && <div className='error'>{sentenceError}</div>}
  716. </div>
  717. <div className="tip">
  718. <Link to="/" className="left link">
  719. 什么是CODE?
  720. </Link>
  721. <span>没有 CODE?</span>
  722. <Link to="/" className="link">
  723. 去获取 >>
  724. </Link>
  725. <a onClick={() => {
  726. this.trailSentence();
  727. }} className="right link">
  728. 试用 >>
  729. </a>
  730. </div>
  731. </Module>
  732. );
  733. }
  734. renderInputCodeModel() {
  735. const { sentenceError } = this.state;
  736. return <Modal visible closable={false} footer={false} title={false}>
  737. <div className="code-module-modal">
  738. <div className="title">请输入CODE</div>
  739. <div className="desc">
  740. <Input onChange={(value) => {
  741. this.code = value;
  742. }} />
  743. {sentenceError && <div className='error'>{sentenceError}</div>}
  744. <div className='tip'>
  745. <Link to="/" className="right link">
  746. 什么是CODE?
  747. </Link>
  748. </div>
  749. </div>
  750. <div className="btn-list">
  751. <AnswerButton size="lager" theme="confirm" width={150} onClick={() => this.activeSentence()}>确认</AnswerButton>
  752. <AnswerButton size="lager" theme="cancel" width={150} onClick={() => this.setState({ sentenceModel: false })}>取消</AnswerButton>
  753. </div>
  754. </div>
  755. </Modal>;
  756. }
  757. renderExercise() {
  758. const { exerciseProgress = [] } = this.state;
  759. return <div >
  760. <Division col="2">
  761. {(exerciseProgress || []).map((struct) => {
  762. const [first] = struct.children;
  763. let col = 3;
  764. if (first && first.type === 'paper') {
  765. col = 5;
  766. }
  767. return <Panel
  768. title={struct.titleEn}
  769. message={struct.description}
  770. data={struct}
  771. col={col}
  772. onClick={(item) => {
  773. if (item.type === 'paper') {
  774. if (item.progress === 0) {
  775. Question.startLink('exercise', item);
  776. } else if (item.progress === 100) {
  777. Question.startLink('exercise', item);
  778. } else {
  779. Question.continueLink('exercise', item);
  780. }
  781. } else {
  782. this.exerciseList(item);
  783. }
  784. }}
  785. />;
  786. })}
  787. </Division>
  788. </div>;
  789. }
  790. }