index.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  1. import React, { Component } from 'react';
  2. import ReactDOM from 'react-dom';
  3. import { Carousel, Tooltip } from 'antd';
  4. import { Link } from 'react-router-dom';
  5. import Fullscreen from 'react-fullscreen-crossbrowser';
  6. import './index.less';
  7. import { formatSeconds, formatPercent, formatDate } from '@src/services/Tools';
  8. import Assets from '@src/components/Assets';
  9. import Navigation from '../../../../components/Navigation';
  10. import Tabs from '../../../../components/Tabs';
  11. import Icon from '../../../../components/Icon';
  12. import Switch from '../../../../components/Switch';
  13. import Select from '../../../../components/Select';
  14. import { Button } from '../../../../components/Button';
  15. import AnswerSelect from '../../../../components/AnswerSelect';
  16. import AnswerList from '../../../../components/AnswerList';
  17. import AnswerButton from '../../../../components/AnswerButton';
  18. import AnswerTable from '../../../../components/AnswerTable';
  19. import OtherAnswer from '../../../../components/OtherAnswer';
  20. import { AskTarget } from '../../../../../Constant';
  21. import { Question } from '../../../../stores/question';
  22. import { My } from '../../../../stores/my';
  23. import Sentence from '../../process/sentence';
  24. export default class extends Component {
  25. constructor(props) {
  26. super(props);
  27. this.state = {
  28. step: 0,
  29. hideAnalysis: true,
  30. analysisTab: 'official',
  31. showAnswer: false,
  32. noteField: AskTarget[0].key,
  33. showIds: false,
  34. };
  35. }
  36. prevQuestion() {
  37. const { userQuestion } = this.props;
  38. if (userQuestion.no === 1) return;
  39. Question.getDetailByNo(userQuestion.reportId, userQuestion.no - 1).then(r => {
  40. linkTo(`/paper/question/${r.id}`);
  41. });
  42. }
  43. nextQuestion() {
  44. const { userQuestion } = this.props;
  45. if (userQuestion.questionNumber === userQuestion.no) return;
  46. Question.getDetailByNo(userQuestion.reportId, userQuestion.no + 1).then(r => {
  47. linkTo(`/paper/question/${r.id}`);
  48. });
  49. }
  50. submitAsk() {
  51. const { userQuestion, questionNo = {} } = this.props;
  52. const { ask = {} } = this.state;
  53. if (ask.originContent === '' || ask.content === '' || ask.target === '') return;
  54. My.addQuestionAsk(userQuestion.id, ask.target, questionNo.id, ask.originContent, ask.content).then(() => {
  55. this.setState({ askModal: false, askOkModal: true });
  56. }).catch(err => {
  57. this.setState({ askError: err.message });
  58. });
  59. }
  60. submitFeedbackError() {
  61. const { questionNo = {} } = this.props;
  62. const { feedback = {} } = this.state;
  63. if (feedback.originContent === '' || feedback.content === '' || feedback.target === '') return;
  64. My.addFeedbackErrorQuestion(
  65. questionNo.id,
  66. questionNo.title,
  67. feedback.target,
  68. feedback.originContent,
  69. feedback.content,
  70. )
  71. .then(() => {
  72. this.setState({ feedbackModal: false, feedbackOkModal: true });
  73. })
  74. .catch(err => {
  75. this.setState({ feedbackError: err.message });
  76. });
  77. }
  78. submitNote(close) {
  79. const { questionNo = {} } = this.props;
  80. const { note = {} } = this.state;
  81. My.updateQuestionNote(questionNo.id, note)
  82. .then(() => {
  83. if (close) this.setState({ noteModal: false });
  84. })
  85. .catch(err => {
  86. this.setState({ noteError: err.message });
  87. });
  88. }
  89. toggleFullscreen() {
  90. const { isFullscreenEnabled } = this.state;
  91. this.setState({ isFullscreenEnabled: !isFullscreenEnabled });
  92. }
  93. toggleCollect() {
  94. const { userQuestion = {}, questionNo = {}, flow } = this.props;
  95. if (!userQuestion.collect) {
  96. My.addQuestionCollect(questionNo.id).then(() => {
  97. userQuestion.collect = true;
  98. flow.setState({ userQuestion });
  99. });
  100. } else {
  101. My.delQuestionCollect(questionNo.id).then(() => {
  102. userQuestion.collect = false;
  103. flow.setState({ userQuestion });
  104. });
  105. }
  106. }
  107. switchNo(no) {
  108. linkTo(`/question/detail/${no.id}`);
  109. }
  110. formatStem(text) {
  111. if (!text) return '';
  112. const { showAnswer, question = { content: {} }, userQuestion } = this.props;
  113. const { table = {}, questions = [] } = question.content;
  114. text = text.replace(/#select#/g, "<span class='#select#' />");
  115. text = text.replace(/#table#/g, "<span class='#table#' />");
  116. setTimeout(() => {
  117. const selectList = document.getElementsByClassName('#select#');
  118. const tableList = document.getElementsByClassName('#table#');
  119. for (let i = 0; i < selectList.length; i += 1) {
  120. if (!questions[i]) break;
  121. ReactDOM.render(
  122. <AnswerSelect
  123. list={questions[i].select}
  124. type={'single'}
  125. selected={(userQuestion.userAnswer || { questions: [] }).questions[i]}
  126. answer={(question.answer || { questions: [] }).questions[i]}
  127. fix
  128. show={showAnswer}
  129. />,
  130. selectList[i],
  131. );
  132. }
  133. if (table.row && table.col && table.header) {
  134. const columns = table.header.map((title, index) => {
  135. return { title, key: index };
  136. });
  137. for (let i = 0; i < tableList.length; i += 1) {
  138. ReactDOM.render(<AnswerTable list={columns} columns={columns} data={table.data} />, tableList[i]);
  139. }
  140. }
  141. }, 1);
  142. return text;
  143. }
  144. render() {
  145. return (
  146. <Fullscreen
  147. enabled={this.state.isFullscreenEnabled}
  148. onChange={isFullscreenEnabled => this.setState({ isFullscreenEnabled })}
  149. >
  150. {this.renderDetail()}
  151. </Fullscreen>
  152. );
  153. }
  154. renderDetail() {
  155. const { paper = {} } = this.props;
  156. switch (paper.paperModule) {
  157. case 'sentence':
  158. return <Sentence {...this.props} {...this.state} flow={this} scene="answer" mode="question" />;
  159. default:
  160. return <div className="base">{this.renderBase()}</div>;
  161. }
  162. }
  163. renderHeader() {
  164. const {
  165. userQuestion = {},
  166. questionNo = {},
  167. paper = {},
  168. report = {},
  169. questionNos = [],
  170. question = {},
  171. info,
  172. detail,
  173. } = this.props;
  174. const { showIds } = this.state;
  175. return (
  176. <div className={'layout-header'}>
  177. {detail && (
  178. <div className="left">
  179. {paper.paperModule && paper.paperModule !== 'examination' && (
  180. <div className="btn">
  181. <Button
  182. radius
  183. onClick={() => {
  184. linkTo(`/paper/report/${report.id}`);
  185. }}
  186. >
  187. 返回练习报告
  188. </Button>
  189. </div>
  190. )}
  191. {paper.paperModule && paper.paperModule === 'examination' && (
  192. <div className="btn">
  193. <Button
  194. radius
  195. onClick={() => {
  196. linkTo(`/paper/report/${report.id}`);
  197. }}
  198. >
  199. 返回成绩单
  200. </Button>
  201. </div>
  202. )}
  203. <div className="no">No.{userQuestion.stageNo || userQuestion.no}</div>
  204. <div className="title">
  205. <Assets name="book" />
  206. {paper.title}
  207. </div>
  208. </div>
  209. )}
  210. <div className="center">
  211. <div className="menu-wrap">
  212. ID:{questionNo.title}
  213. {questionNos && questionNos.length > 0 && (
  214. <Icon
  215. name="other"
  216. onClick={() => {
  217. this.setState({ showIds: true });
  218. }}
  219. />
  220. )}
  221. {showIds && (
  222. <div className="menu-content">
  223. <p>题源汇总</p>
  224. {(questionNos || []).map(row => (
  225. <p onClick={() => info && this.switchNo(row)}>ID:{row.title}</p>
  226. ))}
  227. </div>
  228. )}
  229. </div>
  230. </div>
  231. <div className="right" hidden={question.questionType === 'awa'}>
  232. {detail && (
  233. <span className="b" hidden={!userQuestion.id}>
  234. 用时:
  235. <span
  236. dangerouslySetInnerHTML={{
  237. __html: formatSeconds(userQuestion.userTime).replace(
  238. /([0-9]+)(m|min|h|hour|s)/g,
  239. '<span class="s">$1</span>$2',
  240. ),
  241. }}
  242. />
  243. {/* 用时:<span className="s">1</span>m<span className="s">39</span>s */}
  244. </span>
  245. )}
  246. <span className="b">
  247. 全站:
  248. <span
  249. dangerouslySetInnerHTML={{
  250. __html: formatSeconds(questionNo.totalTime / questionNo.totalNumber).replace(
  251. /([0-9]+)(m|min|h|hour|s)/g,
  252. '<span class="s">$1</span>$2',
  253. ),
  254. }}
  255. />
  256. {/* 全站:<span className="s">1</span>m<span className="s">39</span>s */}
  257. </span>
  258. <span className="b">
  259. <span className="s">{formatPercent(questionNo.totalCorrect, questionNo.totalNumber)}</span>%
  260. </span>
  261. <Icon name="question" />
  262. <Icon name="star" active={userQuestion.collect} onClick={() => this.toggleCollect()} />
  263. </div>
  264. </div>
  265. );
  266. }
  267. renderBase() {
  268. const { questionStatus, userQuestion = {}, paper = {}, detail } = this.props;
  269. const { showIds } = this.state;
  270. return (
  271. <div
  272. className={`layout ${paper.paperModule}`}
  273. onClick={() => {
  274. if (showIds) this.setState({ showIds: false });
  275. }}
  276. >
  277. {this.renderHeader()}
  278. <div className="layout-body">{this.renderBody()}</div>
  279. <div className="layout-footer">
  280. <div className="left">
  281. <Tooltip overlayClassName="gray" placement="top" title="全屏">
  282. <a>
  283. <Icon
  284. name={this.state.isFullscreenEnabled ? 'sceen-restore' : 'sceen-full'}
  285. onClick={() => this.toggleFullscreen()}
  286. />
  287. </a>
  288. </Tooltip>
  289. </div>
  290. <div className="center">
  291. <AnswerButton className="item" onClick={() => this.setState({ noteModal: true })}>
  292. 笔记
  293. </AnswerButton>
  294. {questionStatus >= 0 && (
  295. <AnswerButton
  296. className="item"
  297. onClick={() => {
  298. if (questionStatus > 0) {
  299. this.setState({ askModal: true, ask: { target: AskTarget[0].value } });
  300. } else {
  301. this.setState({ askFailModal: true });
  302. }
  303. }}
  304. >
  305. 提问
  306. </AnswerButton>
  307. )}
  308. <AnswerButton className="item" onClick={() => this.setState({ feedbackModal: true })}>
  309. 纠错
  310. </AnswerButton>
  311. </div>
  312. {detail && (
  313. <div className="right">
  314. {userQuestion.no !== 1 && <Icon name="prev" onClick={() => this.prevQuestion()} />}
  315. {userQuestion.questionNumber !== userQuestion.no && (
  316. <Icon name="next" onClick={() => this.nextQuestion()} />
  317. )}
  318. </div>
  319. )}
  320. </div>
  321. {this.state.askModal && this.renderAsk()}
  322. {this.state.askOkModal && this.renderAskOk()}
  323. {this.state.askFailModal && this.renderAskFail()}
  324. {this.state.feedbackModal && this.renderFeedbackError()}
  325. {this.state.feedbackOkModal && this.renderFeedbackErrorOk()}
  326. {this.state.noteModal && this.renderNote()}
  327. </div>
  328. );
  329. }
  330. renderBody() {
  331. const { question = { content: {} } } = this.props;
  332. const { typeset = 'one' } = question.content;
  333. const { hideAnalysis } = this.state;
  334. const show = typeset === 'one' ? true : !hideAnalysis;
  335. return (
  336. <div className="layout-content">
  337. <div className="two">
  338. {this.renderContent()}
  339. {question.questionType !== 'awa' && this.renderAnswer()}
  340. {question.questionType === 'awa' && this.renderAWA()}
  341. </div>
  342. {question.questionType !== 'awa' && this.renderAnalysis()}
  343. {typeset === 'two' && question.questionType !== 'awa' && (
  344. <div className="fixed-analysis" onClick={() => this.setState({ hideAnalysis: !hideAnalysis })}>
  345. {show ? '收起解析 >' : '查看解析 <'}
  346. </div>
  347. )}
  348. </div>
  349. );
  350. }
  351. renderAnalysis() {
  352. const { question = { content: {} } } = this.props;
  353. const { typeset = 'one' } = question.content;
  354. const { hideAnalysis, analysisTab } = this.state;
  355. const show = typeset === 'one' ? true : !hideAnalysis;
  356. return (
  357. <div className={`block block-analysis two-analysis ${show ? 'show' : ''}`}>
  358. <Tabs
  359. type="division"
  360. active={analysisTab}
  361. space={2}
  362. tabs={[
  363. { key: 'official', name: '官方解析' },
  364. { key: 'qx', name: '千行解析' },
  365. { key: 'association', name: '题源联想' },
  366. { key: 'qa', name: '相关回答' },
  367. ]}
  368. onChange={key => {
  369. this.setState({ analysisTab: key });
  370. }}
  371. />
  372. <div className="detail">
  373. {typeset === 'two' && this.renderAnswer()}
  374. {this.renderText()}
  375. </div>
  376. </div>
  377. );
  378. }
  379. renderText() {
  380. const { question = {}, userQuestion = {} } = this.props;
  381. const { asks = [], associations = [] } = userQuestion;
  382. const { analysisTab } = this.state;
  383. let content;
  384. switch (analysisTab) {
  385. case 'official':
  386. content = (
  387. <div className="detail-block text-block" dangerouslySetInnerHTML={{ __html: question.officialContent }} />
  388. );
  389. break;
  390. case 'qx':
  391. content = <div className="detail-block text-block" dangerouslySetInnerHTML={{ __html: question.qxContent }} />;
  392. break;
  393. case 'association':
  394. content = (
  395. <div className="detail-block">
  396. <Carousel>
  397. {associations.map(association => {
  398. return <div className="text-block" dangerouslySetInnerHTML={{ __html: association.stem }} />;
  399. })}
  400. </Carousel>
  401. </div>
  402. );
  403. break;
  404. case 'qa':
  405. content = (
  406. <div className="detail-block answer-block">
  407. {asks.map((ask, index) => {
  408. return <OtherAnswer key={index} data={ask} />;
  409. })}
  410. </div>
  411. );
  412. break;
  413. default:
  414. break;
  415. }
  416. return content;
  417. }
  418. renderAnswer() {
  419. const { question = { content: {} }, userQuestion = {}, detail } = this.props;
  420. const { questions = [], type, typeset = 'one' } = question.content;
  421. const { showAnswer } = this.state;
  422. return (
  423. <div className="block block-answer">
  424. {detail && typeset === 'two' ? (
  425. <Switch
  426. checked={showAnswer}
  427. onChange={value => {
  428. this.setState({ showAnswer: value });
  429. }}
  430. >
  431. {showAnswer ? '显示答案' : '关闭答案'}
  432. </Switch>
  433. ) : (
  434. ''
  435. )}
  436. {questions.map((item, index) => {
  437. return (
  438. <div>
  439. <div className="text m-b-2">{item.description}</div>
  440. <AnswerList
  441. show={showAnswer}
  442. selected={(userQuestion.userAnswer || { questions: [] }).questions[index]}
  443. answer={(question.answer || { questions: [] }).questions[index]}
  444. distributed={(question.answerDistributed || { questions: [] }).questions[index]}
  445. list={item.select}
  446. type={type}
  447. first={item.first}
  448. second={item.second}
  449. direction={item.direction}
  450. />
  451. </div>
  452. );
  453. })}
  454. </div>
  455. );
  456. }
  457. renderContent() {
  458. const { question = { content: {} }, detail } = this.props;
  459. const { typeset = 'one' } = question.content;
  460. const { steps = [] } = question.content;
  461. const { showAnswer, step } = this.state;
  462. return (
  463. <div className="block block-content">
  464. {detail && typeset === 'one' && question.questionType !== 'awa' ? (
  465. <Switch
  466. checked={showAnswer}
  467. onChange={value => {
  468. this.setState({ showAnswer: value });
  469. }}
  470. >
  471. {showAnswer ? '显示答案' : '关闭答案'}
  472. </Switch>
  473. ) : (
  474. ''
  475. )}
  476. {question.questionType === 'awa' && <h2>Analytical Writing Assessment</h2>}
  477. {steps.length > 0 && (
  478. <Navigation
  479. theme="detail"
  480. list={question.content.steps}
  481. active={step}
  482. onChange={v => this.setState({ step: v })}
  483. />
  484. )}
  485. <div
  486. className="text"
  487. style={{ height: 2000 }}
  488. dangerouslySetInnerHTML={{ __html: this.formatStem(steps.length > 0 ? steps[step].stem : question.stem) }}
  489. />
  490. </div>
  491. );
  492. }
  493. renderAWA() {
  494. const { userQuestion = { detail: {}, userAnswer: {} } } = this.state;
  495. const { showAnswer } = this.state;
  496. return (
  497. <div className="block block-awa">
  498. <Switch
  499. checked={showAnswer}
  500. onChange={value => {
  501. this.setState({ showAnswer: value });
  502. }}
  503. >
  504. {showAnswer ? '显示答案' : '关闭答案'}
  505. </Switch>
  506. <div className="body">
  507. <h2>Your Response</h2>
  508. {showAnswer && (
  509. <div className="detail">
  510. <div className="info">
  511. <span className="b">
  512. 用时:
  513. <span
  514. dangerouslySetInnerHTML={{
  515. __html: formatSeconds(userQuestion.userTime).replace(
  516. /([0-9]+)(m|min|h|hour|s)/g,
  517. '<span class="s">$1</span>$2',
  518. ),
  519. }}
  520. />
  521. {/* 用时:<span className="s">1</span>m<span className="s">39</span>s */}
  522. </span>
  523. <span className="b">
  524. 单词数:<span className="s">{Number((userQuestion.detail || {}).words || 0)}</span>词
  525. </span>
  526. </div>
  527. <div className="content-awa" dangerouslySetInnerHTML={{ __html: userQuestion.userAnswer.awa || '' }} />
  528. </div>
  529. )}
  530. {!showAnswer && <div className="show-awa">选择「显示答案」查看自己的作文</div>}
  531. </div>
  532. </div>
  533. );
  534. }
  535. renderAsk() {
  536. const { ask = {} } = this.state;
  537. return (
  538. <div className="modal ask">
  539. <div className="mask" />
  540. <div className="body">
  541. <div className="title">提问</div>
  542. <div className="desc">
  543. <div className="select-inline">
  544. 我想对
  545. <Select
  546. excludeSelf
  547. size="small"
  548. theme="white"
  549. value={ask.target}
  550. list={AskTarget}
  551. onChange={item => {
  552. ask.target = item.value;
  553. this.setState({ ask });
  554. }}
  555. />
  556. 进行提问
  557. </div>
  558. <div className="label">有疑问的具体内容是:</div>
  559. <textarea
  560. className="textarea"
  561. value={ask.originContent}
  562. placeholder="请复制粘贴有疑问的内容。"
  563. onChange={e => {
  564. ask.originContent = e.target.value;
  565. this.setState({ ask });
  566. }}
  567. />
  568. <div className="label">针对以上内容的问题是:</div>
  569. <textarea
  570. className="textarea"
  571. value={ask.content}
  572. placeholder="提问频率高的问题会被优先回答哦。"
  573. onChange={e => {
  574. ask.content = e.target.value;
  575. this.setState({ ask });
  576. }}
  577. />
  578. </div>
  579. <div className="bottom">
  580. <AnswerButton theme="cancel" size="lager" onClick={() => this.setState({ askModal: false })}>
  581. 取消
  582. </AnswerButton>
  583. <AnswerButton size="lager" onClick={() => this.submitAsk()}>
  584. 提交
  585. </AnswerButton>
  586. </div>
  587. </div>
  588. </div>
  589. );
  590. }
  591. renderAskOk() {
  592. return (
  593. <div className="modal ask-ok">
  594. <div className="mask" />
  595. <div className="body">
  596. <div className="title">提问</div>
  597. <div className="content">
  598. <div className="left">
  599. <div className="text">已提交成功!</div>
  600. <div className="text">关注公众号,老师回答后会立即收到通知。</div>
  601. <div className="text">我们也会通过站内信的方式通知你。</div>
  602. <div className="small">
  603. 成为学员享受极速答疑特权。<Link>了解更多</Link>
  604. </div>
  605. </div>
  606. <div className="right">
  607. <div className="text">扫码关注公众号</div>
  608. <div className="text">千行GMAT</div>
  609. </div>
  610. </div>
  611. <div className="confirm">
  612. <AnswerButton
  613. size="lager"
  614. theme="confirm"
  615. onClick={() => {
  616. this.setState({ askOkModal: false });
  617. }}
  618. >
  619. 好的,知道了
  620. </AnswerButton>
  621. </div>
  622. </div>
  623. </div>
  624. );
  625. }
  626. renderAskFail() {
  627. return (
  628. <div className="modal ask-ok">
  629. <div className="mask" />
  630. <div className="body">
  631. <div className="title">提问</div>
  632. <div className="content">
  633. <div className="left">
  634. <div className="text">提问功能正在维护中。</div>
  635. <div className="text">可先查阅“相关问答” 或 成为学员享受极速 答疑特权。</div>
  636. <Link to="/">了解更多></Link>
  637. </div>
  638. <div className="right">
  639. <div className="text">扫码关注公众号</div>
  640. <div className="text">千行GMAT</div>
  641. </div>
  642. </div>
  643. <div className="confirm">
  644. <AnswerButton
  645. size="lager"
  646. theme="confirm"
  647. onClick={() => {
  648. this.setState({ askFailModal: false });
  649. }}
  650. >
  651. 好的,知道了
  652. </AnswerButton>
  653. </div>
  654. </div>
  655. </div>
  656. );
  657. }
  658. renderFeedbackError() {
  659. const { feedback = {} } = this.state;
  660. return (
  661. <div className="modal error">
  662. <div className="mask" />
  663. <div className="body">
  664. <div className="title">纠错</div>
  665. <div className="desc">
  666. <div className="select-inline">
  667. 我想对
  668. <Select
  669. excludeSelf
  670. size="small"
  671. theme="white"
  672. value={feedback.target}
  673. list={AskTarget}
  674. onChange={item => {
  675. feedback.target = item.value;
  676. this.setState({ feedback });
  677. }}
  678. />
  679. 进行提问
  680. </div>
  681. <div className="label">错误内容是:</div>
  682. <textarea
  683. className="textarea"
  684. value={feedback.originContent}
  685. placeholder="你可以适当扩大复制范围以使我们准确定位,感谢。"
  686. />
  687. <div className="label">应该改为:</div>
  688. <textarea className="textarea" placeholder="只需提供正确内容即可" />
  689. </div>
  690. <div className="bottom">
  691. <AnswerButton
  692. theme="cancel"
  693. size="lager"
  694. onClick={() => {
  695. this.setState({ feedbackModal: false });
  696. }}
  697. >
  698. 取消
  699. </AnswerButton>
  700. <AnswerButton
  701. size="lager"
  702. onClick={() => {
  703. this.submitFeedbackError();
  704. }}
  705. >
  706. 提交
  707. </AnswerButton>
  708. </div>
  709. </div>
  710. </div>
  711. );
  712. }
  713. renderFeedbackErrorOk() {
  714. return (
  715. <div className="modal error-ok">
  716. <div className="mask" />
  717. <div className="body">
  718. <div className="title">纠错</div>
  719. <div className="content">
  720. <div className="left">
  721. <div className="text">
  722. <Assets name="right" svg />
  723. 已提交成功!
  724. </div>
  725. <div className="text">感谢您的耐心反馈,我们会尽快核实并以站内信的方式告知结果。</div>
  726. <div className="text">您也可以关注公众号及时获取结果。</div>
  727. </div>
  728. <div className="right">
  729. <div className="text">扫码关注公众号</div>
  730. <div className="text">千行GMAT</div>
  731. </div>
  732. </div>
  733. <div className="confirm">
  734. <AnswerButton
  735. size="lager"
  736. theme="confirm"
  737. onClick={() => {
  738. this.setState({ feedbackOkModal: false });
  739. }}
  740. >
  741. 好的,知道了
  742. </AnswerButton>
  743. </div>
  744. </div>
  745. </div>
  746. );
  747. }
  748. renderNote() {
  749. const { noteField, note = {} } = this.state;
  750. return (
  751. <div className="modal note">
  752. <div className="mask" />
  753. <div className="body">
  754. <div className="title">笔记</div>
  755. <div className="content">
  756. <div className="tabs">
  757. {AskTarget.map(item => {
  758. return (
  759. <div
  760. className={`tab ${noteField === item.key ? 'active' : ''}`}
  761. onClick={() => {
  762. this.setState({ noteField: item.key });
  763. }}
  764. >
  765. <div className="text">{item.label}</div>
  766. <div className="date">{note[`${item.key}Time`] ? formatDate(note[`${item.key}Time`]) : ''}</div>
  767. </div>
  768. );
  769. })}
  770. </div>
  771. <div className="input">
  772. <textarea
  773. className="textarea"
  774. value={note[`${noteField}Content`] || ''}
  775. placeholder="记下笔记,方便以后复习"
  776. onChange={e => {
  777. note[`${noteField}Time`] = new Date();
  778. note[`${noteField}Content`] = e.target.value;
  779. this.setState({ note });
  780. }}
  781. />
  782. <div className="bottom">
  783. <AnswerButton
  784. theme="cancel"
  785. size="lager"
  786. onClick={() => {
  787. this.setState({ noteModal: false });
  788. }}
  789. >
  790. 取消
  791. </AnswerButton>
  792. <AnswerButton
  793. size="lager"
  794. onClick={() => {
  795. this.submitNote();
  796. }}
  797. >
  798. 编辑
  799. </AnswerButton>
  800. <AnswerButton
  801. size="lager"
  802. onClick={() => {
  803. this.submitNote(true);
  804. }}
  805. >
  806. 保存
  807. </AnswerButton>
  808. </div>
  809. </div>
  810. </div>
  811. </div>
  812. </div>
  813. );
  814. }
  815. }