index.js 27 KB

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