index.js 27 KB

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