page.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. import React, { Component } from 'react';
  2. import './index.less';
  3. import { Checkbox } from 'antd';
  4. import Page from '@src/containers/Page';
  5. import Modal from '../../../components/Modal';
  6. import HardInput from '../../../components/HardInput';
  7. import AnswerCheckbox from '../../../components/AnswerCheckbox';
  8. import { formatDate, getMap, formatPercent, formatSeconds } from '../../../../../src/services/Tools';
  9. import { My } from '../../../stores/my';
  10. import { User } from '../../../stores/user';
  11. import { SentenceOption } from '../../../../Constant';
  12. const ExportType = [
  13. { label: '收藏', value: 'question_collect' },
  14. { label: '错题', value: 'question_error' },
  15. { label: '笔记', value: 'note_question' },
  16. { label: '笔记', value: 'note_course' },
  17. ];
  18. const ExportTypeMap = getMap(ExportType, 'value', 'label');
  19. const AnswerIndex = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K'];
  20. const width = 595;
  21. const height = 1050;
  22. const top = 72;
  23. const left = 93;
  24. const size = 10;
  25. export default class extends Page {
  26. initState() {
  27. const { info } = this.props.user;
  28. return {
  29. showTip: !info.exportTips,
  30. nextTips: true,
  31. };
  32. }
  33. initData() {
  34. const { id } = this.params;
  35. My.exportDetail(id)
  36. .then(result => {
  37. this.setState({ data: result });
  38. setTimeout(() => {
  39. const { waters } = result;
  40. const waterList = [];
  41. const pageSize = Math.ceil(this.view.offsetHeight / height);
  42. console.log(pageSize, this.view.offsetHeight);
  43. for (let i = 0; i < pageSize; i += 1) {
  44. const a = [top, (height / 2 - top) / 2 - size / 2 + top, height / 2 - size / 2, (height / 2 + (height - top - height / 2) / 2) - size / 2, height - top - size];
  45. for (let j = 0; j < 5; j += 1) {
  46. waterList.push({
  47. style: { left, top: a[j] + height * i, textAlign: 'left' },
  48. text: waters[0],
  49. });
  50. waterList.push({
  51. style: { left: width / 2, top: a[j] + height * i, textAlign: 'center' },
  52. text: waters[1],
  53. });
  54. waterList.push({
  55. style: { left: width - left, top: a[j] + height * i, textAlign: 'right' },
  56. text: waters[0],
  57. });
  58. }
  59. }
  60. this.setState({ waterList });
  61. }, 1000);
  62. });
  63. }
  64. closeTips() {
  65. this.setState({ showTip: false });
  66. const { nextTips } = this.state;
  67. if (!nextTips) return;
  68. My.exportTips()
  69. .then(() => {
  70. const { info } = this.props.user;
  71. info.exportTips = 1;
  72. User.infoHandle(info);
  73. });
  74. }
  75. renderView() {
  76. const { data = {}, showTip, nextTips, waterList = [] } = this.state;
  77. return (
  78. <div ref={(ref) => {
  79. if (ref) this.view = ref;
  80. }}>
  81. {waterList.map(row => {
  82. return <div className="water" style={row.style}>{row.text}</div>;
  83. })}
  84. {this.renderHead()}
  85. {data.type !== 'note_course' && this.renderQuestion()}
  86. {data.type === 'note_course' && this.renderNote()}
  87. <Modal
  88. show={showTip}
  89. title="导出方法"
  90. onConfirm={() => this.closeTips()}
  91. confirmText="好的,知道了"
  92. btnAlign="center"
  93. >
  94. <div className="t-2 t-s-18">鼠标右键点击打印后,可直接保存为PDF或打印。</div>
  95. <div className="t-2 t-s-14"><Checkbox checked={nextTips} onClick={() => this.setState({ nextTips: !nextTips })} />下次进入时不再提醒。</div>
  96. </Modal>
  97. </div>
  98. );
  99. }
  100. renderHead() {
  101. const { data = {} } = this.state;
  102. const { content = {} } = data;
  103. const { info } = this.props.user;
  104. return (
  105. <div className="head-layout">
  106. <div className="content p-r">
  107. <div className="t-1 t-s-30">千行GMAT</div>
  108. <div className="t-1 t-s-18">
  109. <span>{info.nickname}</span> <span>ID {info.id}</span>
  110. </div>
  111. <div className="t-2 t-s-12">* 请勿外传或商用!</div>
  112. <div style={{ right: 0, top: 20 }} className="p-a t-r">
  113. <div className="t-2">第{data.no || 0}次导出{ExportTypeMap[data.type]}</div>
  114. <div className="t-2">本次导出 {(content.list || []).length} 道 </div>
  115. <div className="t-2">{formatDate(data.createTime, 'YYYY-MM-DD HH:mm:ss')}</div>
  116. </div>
  117. </div>
  118. </div>
  119. );
  120. }
  121. renderQuestion() {
  122. const { data } = this.state;
  123. const { content = {} } = data;
  124. const { list = [] } = content;
  125. return (
  126. <div className="detail-layout">
  127. <div className="content">
  128. {list.map(item => {
  129. return [this.renderTotal(item), item.question.questionType === 'sentence' ? <SentenceDetail data={item} /> : <BaseDetail data={item} />];
  130. })}
  131. </div>
  132. </div>
  133. );
  134. }
  135. renderTotal(item) {
  136. const { questionNo = {}, userTime, userPaper } = item;
  137. return (
  138. <div className="total-block p-l-2">
  139. <span className="m-l-1 t-1 t-s-20 f-w-b m-r-2"> {questionNo.title}</span>
  140. {userPaper && <span className="t-1 t-s-20 f-w-b m-r-2">{userPaper.title}</span>}
  141. <span className="t-1">ID:{questionNo.title}</span>
  142. <div className="f-r m-r-1">
  143. {userTime && <span className="t-1 m-r-2">
  144. 用时:
  145. <span
  146. dangerouslySetInnerHTML={{
  147. __html: formatSeconds(userTime).replace(
  148. /([0-9]+)(min|m|hour|h|s)/g,
  149. '<span class="t-4">$1</span>$2',
  150. ),
  151. }}
  152. />
  153. </span>}
  154. <span className="t-1 m-r-2">
  155. 全站:
  156. <span
  157. dangerouslySetInnerHTML={{
  158. __html: formatSeconds(questionNo.totalTime / questionNo.totalNumber).replace(
  159. /([0-9]+)(min|m|hour|h|s)/g,
  160. '<span class="t-4">$1</span>$2',
  161. ),
  162. }}
  163. />
  164. </span>
  165. <span className="t-1">
  166. <span className="t-4">{formatPercent(item.questionNo.totalCorrect, item.questionNo.totalNumber)}</span>%
  167. </span>
  168. </div>
  169. </div>
  170. );
  171. }
  172. renderNote() {
  173. const { data } = this.state;
  174. const { content = {} } = data;
  175. const { list = [] } = content;
  176. return (
  177. <div className="detail-layout">
  178. <div className="content">
  179. {list.map(item => {
  180. return <NoteDetail data={item} />;
  181. })}
  182. </div>
  183. </div>
  184. );
  185. }
  186. }
  187. class BaseDetail extends Component {
  188. render() {
  189. return (
  190. <div className="detail-item">
  191. {this.renderQuestion()}
  192. {this.renderOfficial()}
  193. {this.renderQx()}
  194. {this.renderConnect()}
  195. {this.renderAsk()}
  196. </div>
  197. );
  198. }
  199. renderQuestion() {
  200. const { data = {} } = this.props;
  201. const { question = {} } = data;
  202. if (!question.stem) return null;
  203. return [
  204. <div className="detail-item-block">
  205. <div className="t-1 t-s-16 m-b-2" dangerouslySetInnerHTML={{ __html: question.stem }} />
  206. {question.content.questions.map(q => {
  207. return [q.description && <div className="t-1 t-s-16 m-b-2" dangerouslySetInnerHTML={{ __html: q.description }} />, this.renderSelect(q.select)];
  208. })}
  209. </div>,
  210. this.renderAnswer(),
  211. ];
  212. }
  213. renderAnswer() {
  214. const { data = {} } = this.props;
  215. const { question = {}, note = {}, userAnswer } = data;
  216. const { answer } = question;
  217. let a = true;
  218. if (!answer.questions[0].single) a = false;
  219. return (
  220. <div className="detail-item-block">
  221. {a && <div className="title-item">答案</div>}
  222. {a && <div className="t-1 t-s-16 m-b-2">
  223. <span className="m-r-2">我的答案 {userAnswer && AnswerIndex[userAnswer.questions[0].single.indexOf(true)]}</span>
  224. <span>正确答案 {AnswerIndex[answer.questions[0].single.indexOf(true)]}</span>
  225. </div>}
  226. {this.renderNote('题目', note.questionContent)}
  227. </div>
  228. );
  229. }
  230. renderOfficial() {
  231. const { data = {} } = this.props;
  232. const { question = {}, note = {} } = data;
  233. if (!question.officialContent) return null;
  234. return (
  235. <div className="detail-item-block">
  236. <div className="title-item">官方解析</div>
  237. <div className="t-1 t-s-16 m-b-2" dangerouslySetInnerHTML={{ __html: question.officialContent }} />
  238. {this.renderNote('官方解析', note.officialContent)}
  239. </div>
  240. );
  241. }
  242. renderQx() {
  243. const { data = {} } = this.props;
  244. const { question = {}, note = {} } = data;
  245. if (!question.qxContent) return null;
  246. return (
  247. <div className="detail-item-block">
  248. <div className="title-item">千行解析</div>
  249. <div className="t-1 t-s-16 m-b-2" dangerouslySetInnerHTML={{ __html: question.qxContent }} />
  250. {this.renderNote('千行解析', note.qxContent)}
  251. </div>
  252. );
  253. }
  254. renderConnect() {
  255. const { data = {} } = this.props;
  256. const { associations = [], note = {} } = data;
  257. if (!associations || associations.length === 0) return null;
  258. return (
  259. <div className="detail-item-block">
  260. <div className="title-item">题源联想</div>
  261. {associations.filter(row => row).map((item, index) => {
  262. return (
  263. <div className="m-b-2">
  264. <div className="t-1 t-s-16 m-b-1">
  265. <span className="t-4 t-s-14 m-r-5">例题 {index + 1}</span><div dangerouslySetInnerHTML={{ __html: item.stem }} />
  266. </div>
  267. {this.renderSelect(item.content.questions[0].select)}
  268. </div>
  269. );
  270. })}
  271. {this.renderNote('题源联想', note.associationContent)}
  272. </div>
  273. );
  274. }
  275. renderAsk() {
  276. const { data = {} } = this.props;
  277. const { asks = [], note = {} } = data;
  278. if (!asks || asks.length === 0) return null;
  279. return (
  280. <div className="detail-item-block">
  281. <div className="title-item">相关问答</div>
  282. {asks.map((item) => {
  283. return (
  284. <div className="m-b-1 b-b p-b-1">
  285. <div className="ask-tag">提问</div>
  286. <div className="t-1 t-s-16 m-b-1" dangerouslySetInnerHTML={{ __html: item.content }} />
  287. <div className="ask-tag">回答</div>
  288. <div className="t-1 t-s-16 m-b-1" dangerouslySetInnerHTML={{ __html: item.answer }} />
  289. </div>
  290. );
  291. })}
  292. {this.renderNote('相关问答', note.qaContent)}
  293. </div>
  294. );
  295. }
  296. renderSelect(list) {
  297. return (
  298. <div className="select-item">
  299. {list.map((item) => {
  300. return (
  301. <div className="p-r m-b-2">
  302. <div className="select-icon p-a" />
  303. <div className="p-l-2 t-1 t-s-16">{item}</div>
  304. </div>
  305. );
  306. })}
  307. </div>
  308. );
  309. }
  310. renderNote(title, content) {
  311. if (!content) return null;
  312. return (
  313. <div className="note-item">
  314. <div className="t t-1 m-b-1">我的笔记-{title}</div>
  315. <div className="t-1 t-s-16">{content}</div>
  316. </div>
  317. );
  318. }
  319. }
  320. class SentenceDetail extends Component {
  321. render() {
  322. return (
  323. <div className="detail-item">
  324. {this.renderQuestion()}
  325. {this.renderDetail()}
  326. {this.renderChinese()}
  327. </div>
  328. );
  329. }
  330. renderQuestion() {
  331. const { data = {} } = this.props;
  332. const { question = {}, userAnswer = {} } = data;
  333. const { answer = {} } = question;
  334. return (
  335. <div className="detail-item-block">
  336. <div className="t-1 t-s-16 m-b-2" dangerouslySetInnerHTML={{ __html: question.stem }} />
  337. <div className="hard-body m-b-2">
  338. <div className="hard-row">
  339. <div className="label">主语</div>
  340. <div className="input">
  341. <HardInput show list={userAnswer.subject || []} answer={answer.subject} />
  342. </div>
  343. </div>
  344. <div className="hard-row">
  345. <div className="label">谓语</div>
  346. <div className="input">
  347. <HardInput show list={userAnswer.predicate || []} answer={answer.predicate} />
  348. </div>
  349. </div>
  350. <div className="hard-row">
  351. <div className="label">宾语</div>
  352. <div className="input">
  353. <HardInput show list={userAnswer.object || []} answer={answer.object} />
  354. </div>
  355. </div>
  356. </div>
  357. <div className="hard-select">
  358. <div className="t-2 t-s-12 m-b-2">本句存在以下哪种逻辑关系?(可多选)</div>
  359. <AnswerCheckbox
  360. show
  361. list={SentenceOption}
  362. selected={userAnswer.options}
  363. answer={answer.options}
  364. />
  365. </div>
  366. </div>
  367. );
  368. }
  369. renderDetail() {
  370. const { data = {} } = this.props;
  371. const { question = {} } = data;
  372. return (
  373. <div className="detail-item-block">
  374. <div className="title-item">解析详情</div>
  375. <div className="t-1 t-s-16" dangerouslySetInnerHTML={{ __html: question.qxContent }} />
  376. </div>
  377. );
  378. }
  379. renderChinese() {
  380. const { data = {} } = this.props;
  381. const { question = {} } = data;
  382. return (
  383. <div className="detail-item-block">
  384. <div className="title-item">中文语意</div>
  385. <div className="t-1 t-s-16" dangerouslySetInnerHTML={{ __html: question.chineseContent }} />
  386. </div>
  387. );
  388. }
  389. }
  390. class NoteDetail extends Component {
  391. render() {
  392. const { data } = this.props;
  393. return (
  394. <div className="detail-item">
  395. <div className="title-item">
  396. 课时{data.courseNo.no} {data.courseNo.title}<div className="f-r t-6 t-s-12 t-r f-w-d">{formatDate(data.updateTime, 'YYYY-MM-DD HH:mm:ss')}</div>
  397. </div>
  398. <div className="t-1 t-s-16">{data.content}</div>
  399. </div>
  400. );
  401. }
  402. }