index.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. import React, { Component } from 'react';
  2. import ReactDOM from 'react-dom';
  3. import './index.less';
  4. import { Checkbox } from 'antd';
  5. import Assets from '@src/components/Assets';
  6. import { formatSeconds, formatSecond, getMap } from '@src/services/Tools';
  7. import Button from '../../../../components/Button';
  8. import Navigation from '../../../../components/Navigation';
  9. import Answer from '../../../../components/Answer';
  10. import Calculator from '../../../../components/Calculator';
  11. import AnswerSelect from '../../../../components/AnswerSelect';
  12. import AnswerTable from '../../../../components/AnswerTable';
  13. import Editor from '../../../../components/Editor';
  14. import { QuestionType } from '../../../../../Constant';
  15. const QuestionTypeMap = getMap(QuestionType, 'value');
  16. export default class extends Component {
  17. constructor(props) {
  18. super(props);
  19. this.state = {
  20. showCalculator: false,
  21. disorder: false,
  22. order: [],
  23. step: 0,
  24. answer: {},
  25. modal: null,
  26. };
  27. }
  28. onChangeQuestion(index, value) {
  29. const { question = {}, answer = {} } = this.state;
  30. answer.questions[index] = { [question.type]: value };
  31. this.setState({ answer });
  32. }
  33. onChangeAwa(value) {
  34. const { answer = {} } = this.state;
  35. answer.awa = value;
  36. this.setState({ answer });
  37. }
  38. showConfirm(title, desc, cb) {
  39. this.showModal('confirm', title, desc, cb);
  40. }
  41. showToast(title, desc, cb) {
  42. this.showModal('toast', title, desc, cb);
  43. }
  44. showModal(type, title, desc, cb) {
  45. this.setState({ modal: { type, title, desc, cb } });
  46. }
  47. checkAnswer() {
  48. const { question, answer } = this.state;
  49. let result = null;
  50. if (question.type === 'awa' && !answer.awa) result = 'Please answer the question first.';
  51. if (result) return this.showToast(null, result);
  52. return true;
  53. }
  54. hideModal(b) {
  55. if (b) {
  56. const { modal = {} } = this.state;
  57. if (modal.cb) modal.cb();
  58. }
  59. this.setState({ modal: null });
  60. }
  61. formatStrem(text) {
  62. if (!text) return '';
  63. const { question = { content: {} } } = this.state;
  64. const { table = {}, questions = [] } = question.content;
  65. text = text.replace(/#select#/g, "<span class='#select#' />");
  66. text = text.replace(/#table#/g, "<span class='#table#' />");
  67. setTimeout(() => {
  68. const selectList = document.getElementsByClassName('#select#');
  69. const tableList = document.getElementsByClassName('#table#');
  70. for (let i = 0; i < selectList.length; i += 1) {
  71. ReactDOM.render(
  72. <AnswerSelect list={questions[i].select} onChange={v => this.onChangeQuestion(i, v)} />,
  73. selectList[i],
  74. );
  75. }
  76. for (let i = 0; i < tableList.length; i += 1) {
  77. ReactDOM.render(<AnswerTable list={table.header} columns={table.header} data={table.data} />, tableList[i]);
  78. }
  79. }, 1);
  80. return text;
  81. }
  82. next() {
  83. const { flow } = this.props;
  84. if (this.checkAnswer()) {
  85. flow.next();
  86. }
  87. }
  88. render() {
  89. const { modal } = this.state;
  90. const { scene, paper } = this.props;
  91. let content = null;
  92. switch (scene) {
  93. case 'start':
  94. content = paper.paperModule === 'examination' ? this.renderExaminationStart() : this.renderExerciseStart();
  95. break;
  96. case 'relax':
  97. content = this.renderRelax();
  98. break;
  99. default:
  100. content = this.renderDetail();
  101. break;
  102. }
  103. return <div id='paper-process-base'>
  104. {content}
  105. {modal ? this.renderModal() : ''}
  106. </div>;
  107. }
  108. renderContent() {
  109. const { question = { content: {} } } = this.props;
  110. const { step } = this.state;
  111. const { steps = [] } = question.content;
  112. return (
  113. <div className="block block-content">
  114. {steps.length > 0 && <Navigation list={question.content.steps} active={step} onChange={() => { }} />}
  115. <div className="text">{this.formatStrem(steps.length > 0 ? steps[step].stem : question.stem)}</div>
  116. </div>
  117. );
  118. }
  119. renderAnswer() {
  120. const { question = { content: {} } } = this.props;
  121. const { questions = [], type } = question.content;
  122. if (type === 'inline') return '';
  123. return (
  124. <div className="block block-answer">
  125. {question.questionType === 'awa' && <Editor onChange={v => this.onChangeAwa(v)} />}
  126. {questions.map((item, index) => {
  127. return (
  128. <div>
  129. <div className="text m-b-2">{item.description}</div>
  130. <Answer
  131. list={item.select}
  132. type={type}
  133. direction={question.direction}
  134. onChange={v => this.onChangeQuestion(index, v)}
  135. />
  136. </div>
  137. );
  138. })}
  139. </div>
  140. );
  141. }
  142. renderDetail() {
  143. const { paper, userQuestion, question = { content: {} }, singleTime, stageTime, flow } = this.state;
  144. const { showCalculator } = this.state;
  145. const { typeset = 'one' } = question.content;
  146. return (
  147. <div className="layout">
  148. <div className="fixed">
  149. {QuestionTypeMap[question.questionType].long}
  150. <Assets
  151. className="calculator-icon"
  152. name="calculator_icon"
  153. onClick={() => this.setState({ showCalculator: !showCalculator })}
  154. />
  155. <Assets className="collect-icon" name="collect_icon" />
  156. </div>
  157. <Calculator show={showCalculator} />
  158. <div className="layout-header">
  159. <div className="title">{paper.title}</div>
  160. <div className="right">
  161. <div className="block">
  162. <Assets name="timeleft_icon" />
  163. Time left {formatSecond(stageTime || singleTime)}
  164. </div>
  165. <div className="block">
  166. <Assets name="subjectnumber_icon" />
  167. {userQuestion.no} of {paper.questionNumer}
  168. </div>
  169. </div>
  170. </div>
  171. <div className={`layout-body ${typeset}`}>
  172. {this.renderContent()}
  173. {this.renderAnswer()}
  174. </div>
  175. <div className="layout-footer">
  176. <div className="help">
  177. <Assets name="help_icon" />
  178. Help
  179. </div>
  180. <div className="full">
  181. <Assets name="fullscreen_icon" onClick={() => flow.toggleFullscreen()} />
  182. </div>
  183. <div className="next" onClick={() => this.next()}>
  184. Next
  185. <Assets name="next_icon" />
  186. </div>
  187. </div>
  188. </div>
  189. );
  190. }
  191. renderExaminationStart() {
  192. const { disorder } = this.state;
  193. const { paper, flow } = this.props;
  194. return (
  195. <div className="start">
  196. <div className="bg" />
  197. <div className="fixed-content">
  198. <div className="title">{paper.title}</div>
  199. <div className="desc">
  200. <div className="block">
  201. <div className="desc-title">
  202. <Assets name="subject_icon" />
  203. 题目总数
  204. </div>
  205. <div className="desc-info">{paper.questionNumer}</div>
  206. </div>
  207. <div className="block">
  208. <div className="desc-title">
  209. <Assets name="time_icon" />
  210. 建议用时
  211. </div>
  212. <div className="desc-info">{formatSeconds(paper.time)}</div>
  213. </div>
  214. </div>
  215. <div className="tip">
  216. <Checkbox className="m-r-1" checked={disorder} onChange={() => this.setState({ disorder: !disorder })} />
  217. 题目选项乱序显示
  218. </div>
  219. <div className="submit">
  220. <Button size="lager" radius onClick={() => flow.start({ disorder })}>
  221. 开始练习
  222. </Button>
  223. </div>
  224. </div>
  225. </div>
  226. );
  227. }
  228. renderExerciseStart() {
  229. const { disorder } = this.state;
  230. const { paper, flow } = this.props;
  231. return (
  232. <div className="start">
  233. <div className="bg" />
  234. <div className="fixed-content">
  235. <div className="title">{paper.title}</div>
  236. <div className="desc">
  237. <div className="block">
  238. <div className="desc-title">
  239. <Assets name="subject_icon" />
  240. 题目总数
  241. </div>
  242. <div className="desc-info">{paper.questionNumber}</div>
  243. </div>
  244. <div className="block">
  245. <div className="desc-title">
  246. <Assets name="time_icon" />
  247. 建议用时
  248. </div>
  249. <div className="desc-info">{formatSeconds(paper.time)}</div>
  250. </div>
  251. </div>
  252. <div className="tip">
  253. <Checkbox className="m-r-1" checked={disorder} onChange={() => this.setState({ disorder: !disorder })} />
  254. 题目选项乱序显示
  255. </div>
  256. <div className="submit">
  257. <Button size="lager" radius onClick={() => flow.start({ disorder })}>
  258. 开始练习
  259. </Button>
  260. </div>
  261. </div>
  262. </div>
  263. );
  264. }
  265. renderRelax() {
  266. return <div />;
  267. }
  268. renderModal() {
  269. const { modal } = this.state;
  270. return (
  271. <div className="modal">
  272. <div className="mask" />
  273. <div className="body">
  274. <div className="title">{modal.title}</div>
  275. <div className="desc">{modal.desc}</div>
  276. {modal.type === 'confirm' ? (
  277. <div className="btn-list">
  278. <div className="btn" onClick={() => this.hideModal(true)}>
  279. <span className="t-d-l">Y</span>es
  280. </div>
  281. <div className="btn" onClick={() => this.hideModal(false)}>
  282. <span className="t-d-l">N</span>o
  283. </div>
  284. </div>
  285. ) : (<div className="btn-list">
  286. <div className="btn" onClick={() => this.hideModal(true)}>
  287. <span className="t-d-l">O</span>k
  288. </div>
  289. </div>)}
  290. </div>
  291. </div>
  292. );
  293. }
  294. }