index.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. import React, { Component } from 'react';
  2. import './index.less';
  3. import Assets from '@src/components/Assets';
  4. import { formatSecond, formatPercent } from '@src/services/Tools';
  5. import Icon from '../../../../components/Icon';
  6. import Button from '../../../../components/Button';
  7. import Tabs from '../../../../components/Tabs';
  8. import Progress from '../../../../components/Progress';
  9. import HardInput from '../../../../components/HardInput';
  10. import AnswerCheckbox from '../../../../components/AnswerCheckbox';
  11. import { SentenceOption } from '../../../../../Constant';
  12. import { Question } from '../../../../stores/question';
  13. export default class extends Component {
  14. constructor(props) {
  15. super(props);
  16. // 确保可以自身进行答案显示,外部也可以直接显示答案
  17. // 将props转入state
  18. this.state = {
  19. analysisTab: 'qx',
  20. focusKey: 'subject',
  21. scene: this.props.scene || 'answer',
  22. userQuestion: this.props.userQuestion,
  23. question: this.props.question,
  24. };
  25. const { question, userQuestion } = this.props;
  26. if (this.state.scene === 'answer') {
  27. this.state.stem = this.formatStem(question.stem, userQuestion.userAnswer, question.answer);
  28. } else {
  29. this.state.stem = question.stem;
  30. }
  31. }
  32. showAnswer() {
  33. const { userQuestion } = this.state;
  34. Question.getDetailById(userQuestion.id).then(result => {
  35. const { question } = result;
  36. this.setState({
  37. userQuestion: result,
  38. question: result.question,
  39. scene: 'answer',
  40. stem: this.formatStem(question.stem, result.userAnswer, question.answer),
  41. });
  42. });
  43. }
  44. addTarget(target) {
  45. const uuid = target.getAttribute('uuid');
  46. if (!uuid) return;
  47. const text = target.innerText;
  48. const { focusKey, answer = {}, question } = this.state;
  49. if (!answer[focusKey]) answer[focusKey] = [];
  50. if (answer[focusKey].filter(row => row.uuid === uuid).length > 0) return;
  51. answer[focusKey].push({
  52. text,
  53. uuid,
  54. });
  55. this.setState({
  56. answer,
  57. stem: this.formatStem(question.stem, answer),
  58. });
  59. }
  60. removeTarget(key, target) {
  61. const { answer = {}, question } = this.state;
  62. if (!answer[key]) return;
  63. answer[key] = answer[key].filter(row => row.uuid !== target.uuid);
  64. this.setState({
  65. answer,
  66. stem: this.formatStem(question.stem, answer),
  67. });
  68. }
  69. next() {
  70. const { flow } = this.props;
  71. const { scene } = this.state;
  72. if (scene === 'question') {
  73. const { answer } = this.state;
  74. flow.submit(answer).then(() => {
  75. this.showAnswer();
  76. });
  77. } else if (scene === 'answer') {
  78. flow.next();
  79. }
  80. }
  81. formatStem(stem, userAnswer, answer) {
  82. // userAnswer 添加蓝色字, 错误的添加红色背景
  83. // answer 添加绿色背景
  84. const uuidMap = {};
  85. const show = !!answer;
  86. answer = answer || {};
  87. userAnswer = userAnswer || {};
  88. Object.keys(userAnswer).forEach((key) => {
  89. if (key === 'options') return;
  90. const u = userAnswer[key];
  91. const a = answer[key] && answer[key].length > 0 ? answer[key][0] : [];
  92. const map = {};
  93. a.forEach((row) => {
  94. if (!uuidMap[row.uuid]) uuidMap[row.uuid] = [];
  95. uuidMap[row.uuid].push('true');
  96. map[row.uuid] = row;
  97. });
  98. u.forEach((row) => {
  99. if (!uuidMap[row.uuid]) uuidMap[row.uuid] = [];
  100. uuidMap[row.uuid].push('user');
  101. if (show && !map[row.uuid]) uuidMap[row.uuid].push('false');
  102. });
  103. });
  104. Object.keys(uuidMap).forEach(uuid => {
  105. stem = stem.replace(`uuid='${uuid}'`, `uuid='${uuid}' class='${uuidMap[uuid].join(' ')}'`);
  106. });
  107. return stem;
  108. }
  109. render() {
  110. const { flow, paper, userQuestion, singleTime } = this.props;
  111. return (
  112. <div id='paper-process-sentence'>
  113. <div className="layout">
  114. <div className="layout-header">
  115. <div className="left">
  116. <div className="title">{paper.title}</div>
  117. </div>
  118. <div className="right">
  119. <div className="text"><Assets name='timecost_icon' />Time cost {formatSecond(userQuestion.userTime || singleTime)}</div>
  120. <Icon name="star" active={userQuestion.collect} onClick={() => flow.toggleCollect()} />
  121. </div>
  122. </div>
  123. {this.renderBody()}
  124. <div className="layout-footer">
  125. <div className="left">
  126. <Icon name={this.props.isFullscreenEnabled ? 'sceen-restore' : 'sceen-full'} onClick={() => flow.toggleFullscreen()} />
  127. </div>
  128. <div className="center">
  129. <div className="p">
  130. <Progress theme="theme" progress={formatPercent(userQuestion.no, paper.questionNumber)} />
  131. </div>
  132. <div className="t">{userQuestion.no}/{paper.questionNumber}</div>
  133. </div>
  134. <div className="right">
  135. <Button size="lager" radius onClick={() => {
  136. this.next();
  137. }}>
  138. Next <Assets name="next_icon" />
  139. </Button>
  140. </div>
  141. </div>
  142. </div>
  143. </div>
  144. );
  145. }
  146. renderBody() {
  147. const { scene } = this.state;
  148. switch (scene) {
  149. case 'question':
  150. return this.renderQuestion();
  151. case 'answer':
  152. return this.renderAnswer();
  153. default:
  154. return null;
  155. }
  156. }
  157. renderQuestion() {
  158. const { focusKey, answer = {}, stem } = this.state;
  159. return (
  160. <div className="layout-body">
  161. <div className="title"><Icon name="question" />请分别找出句子中的主语,谓语和宾语,并做出逻辑关系判断。</div>
  162. <div className="desc" dangerouslySetInnerHTML={{ __html: stem }} onClick={(e) => {
  163. this.addTarget(e.target);
  164. }} />
  165. <div className="label">主语</div>
  166. <div className="input">
  167. <HardInput
  168. focus={focusKey === 'subject'}
  169. list={answer.subject || []}
  170. onClick={() => {
  171. this.setState({ focusKey: 'subject' });
  172. }}
  173. onDelete={(item) => {
  174. this.removeTarget('subject', item);
  175. }}
  176. />
  177. </div>
  178. <div className="label">谓语</div>
  179. <div className="input">
  180. <HardInput
  181. focus={focusKey === 'predicate'}
  182. list={answer.predicate || []}
  183. onClick={() => {
  184. this.setState({ focusKey: 'predicate' });
  185. }}
  186. onDelete={(item) => {
  187. this.removeTarget('predicate', item);
  188. }}
  189. />
  190. </div>
  191. <div className="label">宾语</div>
  192. <div className="input">
  193. <HardInput
  194. focus={focusKey === 'object'}
  195. list={answer.object || []}
  196. onClick={() => {
  197. this.setState({ focusKey: 'object' });
  198. }}
  199. onDelete={(item) => {
  200. this.removeTarget('object', item);
  201. }}
  202. />
  203. </div>
  204. <div className="select">
  205. <div className="select-title">本句存在以下哪种逻辑关系?(可多选)</div>
  206. <AnswerCheckbox list={SentenceOption} selected={answer.options} onChange={(values) => {
  207. answer.options = values;
  208. this.setState({ answer });
  209. }} />
  210. </div>
  211. </div>
  212. );
  213. }
  214. renderAnswer() {
  215. const { analysisTab, question, userQuestion, stem } = this.state;
  216. const { userAnswer = {} } = userQuestion;
  217. const { answer } = question;
  218. return <div className="layout-body">
  219. <div className="title"><Icon name="question" />请分别找出句子中的主语,谓语和宾语,并做出逻辑关系判断。</div>
  220. <div className="desc" dangerouslySetInnerHTML={{ __html: stem }} />
  221. <div className="label">主语</div>
  222. <div className="input">
  223. <HardInput
  224. show
  225. list={userAnswer.subject || []}
  226. answer={answer.subject}
  227. />
  228. </div>
  229. <div className="label">谓语</div>
  230. <div className="input">
  231. <HardInput
  232. show
  233. list={userAnswer.predicate || []}
  234. answer={answer.predicate}
  235. />
  236. </div>
  237. <div className="label">宾语</div>
  238. <div className="input">
  239. <HardInput
  240. show
  241. list={userAnswer.object || []}
  242. answer={answer.object}
  243. />
  244. </div>
  245. <div className="select">
  246. <div className="select-title">本句存在以下哪种逻辑关系?(可多选)</div>
  247. <AnswerCheckbox show list={SentenceOption} selected={userAnswer.options} answer={answer.options} />
  248. </div>
  249. <div className="analysis">
  250. <Tabs
  251. type="division"
  252. active={analysisTab}
  253. tabs={[{ key: 'qx', name: '解析详情' }, { key: 'chinese', name: '中文语意' }]}
  254. onChange={(key) => {
  255. this.setState({ analysisTab: key });
  256. }}
  257. />
  258. {this.renderText()}
  259. </div>
  260. </div>;
  261. }
  262. renderText() {
  263. const { analysisTab, question = {}, questionNo = {} } = this.state;
  264. let content;
  265. switch (analysisTab) {
  266. case 'chinese':
  267. content = <div className="detail-block text-block" dangerouslySetInnerHTML={{ __html: questionNo.chineseContent }} />;
  268. break;
  269. case 'qx':
  270. content = <div className="detail-block text-block" dangerouslySetInnerHTML={{ __html: question.qxContent }} />;
  271. break;
  272. default:
  273. break;
  274. }
  275. return content;
  276. }
  277. }