page.js 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437
  1. import React from 'react';
  2. import { Link } from 'react-router-dom';
  3. import './index.less';
  4. import LineChart from '@src/components/LineChart';
  5. import BarChart from '@src/components/BarChart';
  6. import PieChart from '@src/components/PieChart';
  7. import Assets from '@src/components/Assets';
  8. import Page from '@src/containers/Page';
  9. import { formatDate, formatPercent, formatSeconds, formatMinute, formatSecond, formatMinuteSecond, getMap } from '@src/services/Tools';
  10. import { Icon, Tooltip } from 'antd';
  11. import { Question } from '../../../stores/question';
  12. import { Button } from '../../../components/Button';
  13. import Tabs from '../../../components/Tabs';
  14. import { Icon as GIcon } from '../../../components/Icon';
  15. import {
  16. QuestionDifficult,
  17. ExaminationQuestionType,
  18. ExaminationSubject,
  19. } from '../../../../Constant';
  20. const QuestionDifficultMap = getMap(QuestionDifficult, 'value', 'label');
  21. const QuestionDifficultSort = getMap(QuestionDifficult, 'value', 'sort');
  22. function BarOption3(titles, source, data1, data2, color1, color2) {
  23. return {
  24. title: [
  25. {
  26. text: titles[0],
  27. textStyle: { fontSize: 24, fontWeight: 'bold', color: '#686872' },
  28. left: 100,
  29. top: 15,
  30. },
  31. {
  32. text: titles[1],
  33. textStyle: { fontSize: 24, fontWeight: 'bold', color: '#686872' },
  34. left: 195,
  35. top: 15,
  36. },
  37. {
  38. text: titles[2],
  39. textStyle: { fontSize: 24, fontWeight: 'bold', color: '#686872' },
  40. left: 695,
  41. top: 15,
  42. },
  43. ],
  44. grid: [{ width: 250, x: 200, bottom: 30 }, { width: 250, x: 700, bottom: 30 }],
  45. xAxis: [
  46. {
  47. gridIndex: 0,
  48. show: false,
  49. axisTick: { show: false },
  50. axisLine: { show: false },
  51. splitLine: { show: false },
  52. },
  53. {
  54. gridIndex: 1,
  55. show: false,
  56. axisTick: { show: false },
  57. axisLine: { show: false },
  58. splitLine: { show: false },
  59. },
  60. ],
  61. yAxis: [
  62. {
  63. gridIndex: 0,
  64. type: 'category',
  65. axisTick: { show: false },
  66. axisLine: { show: false },
  67. splitLine: { show: false },
  68. offset: 15,
  69. data: source,
  70. axisLabel: { color: '#686872', fontSize: 16 },
  71. },
  72. {
  73. gridIndex: 1,
  74. type: 'category',
  75. axisTick: { show: false },
  76. axisLine: { show: false },
  77. splitLine: { show: false },
  78. axisLabel: { show: false },
  79. },
  80. ],
  81. series: [
  82. {
  83. type: 'bar',
  84. xAxisIndex: 0,
  85. yAxisIndex: 0,
  86. barWidth: 30,
  87. data: data1.map((item, index) => ({
  88. value: item,
  89. itemStyle: { color: index % 2 ? color1[0] : color1[1] },
  90. label: {
  91. show: true,
  92. color: '#303036',
  93. align: 'right',
  94. position: [360, 5],
  95. fontSize: 16,
  96. formatter: item,
  97. },
  98. })),
  99. },
  100. {
  101. type: 'bar',
  102. xAxisIndex: 1,
  103. yAxisIndex: 1,
  104. barWidth: 30,
  105. data: data2.map((item, index) => ({
  106. value: item,
  107. itemStyle: { color: index % 2 ? color2[0] : color2[1] },
  108. label: {
  109. show: true,
  110. color: '#303036',
  111. align: 'right',
  112. fontSize: 16,
  113. position: [360, 5],
  114. formatter: item,
  115. },
  116. })),
  117. },
  118. ],
  119. };
  120. }
  121. function BarOption2(title, data, legend, color) {
  122. return {
  123. title: {
  124. text: title,
  125. textStyle: { fontSize: 24, fontWeight: 'bold', color: '#686872' },
  126. },
  127. tooltip: {
  128. trigger: 'axis',
  129. },
  130. legend: {
  131. show: legend.length > 1,
  132. data: legend,
  133. right: 20,
  134. },
  135. color,
  136. dataset: {
  137. source: [['type', ...legend], ...data],
  138. },
  139. grid: { left: 30, right: 30, height: 300 },
  140. xAxis: {
  141. type: 'category',
  142. axisLabel: { color: '#686872' },
  143. axisLine: { lineStyle: { color: '#D1D6DF' } },
  144. },
  145. yAxis: {
  146. type: 'value',
  147. min: 0,
  148. max: 100,
  149. axisLabel: { color: '#686872' },
  150. axisLine: { lineStyle: { color: '#D1D6DF' } },
  151. },
  152. series: legend.map(() => ({
  153. type: 'bar',
  154. barWidth: 40,
  155. })),
  156. };
  157. }
  158. function lineOption1(title, data, legend, color) {
  159. return {
  160. title: {
  161. text: title,
  162. textStyle: { fontSize: 24, fontWeight: 'bold', color: '#686872' },
  163. left: '0',
  164. },
  165. tooltip: {
  166. trigger: 'axis',
  167. },
  168. legend: {
  169. show: legend.length > 1,
  170. data: legend,
  171. right: 20,
  172. },
  173. color,
  174. grid: { left: 30, right: 30, height: 300 },
  175. xAxis: {
  176. type: 'category',
  177. axisLabel: { color: '#686872' },
  178. axisLine: { lineStyle: { color: '#D1D6DF' } },
  179. },
  180. yAxis: {
  181. type: 'value',
  182. min: 0,
  183. max: 100,
  184. axisLabel: { color: '#686872' },
  185. axisLine: { lineStyle: { color: '#D1D6DF' } },
  186. },
  187. dataset: {
  188. source: [['type', ...legend], ...data],
  189. },
  190. series: legend.map(() => ({
  191. type: 'line',
  192. smooth: true,
  193. symbol: 'circle',
  194. })),
  195. };
  196. }
  197. function barOption1(title, value, allValue, avgCorrect, avgIncorrent) {
  198. const xAxis1 = [
  199. {
  200. gridIndex: 0,
  201. type: 'category',
  202. axisTick: { show: false },
  203. axisLine: { lineStyle: { color: '#D1D6DF' } },
  204. splitLine: { show: false },
  205. },
  206. {
  207. gridIndex: 1,
  208. type: 'category',
  209. axisTick: { show: false },
  210. axisLine: { lineStyle: { color: '#D1D6DF' } },
  211. splitLine: { show: false },
  212. data: [
  213. {
  214. value: 'Avg Time\nCorrect',
  215. textStyle: { color: '#686872', fontWeight: '500', fontSize: 14, lineHeight: 20 },
  216. },
  217. {
  218. value: 'Avg Time\nIncorrect',
  219. textStyle: { color: '#686872', fontWeight: '500', fontSize: 14, lineHeight: 20 },
  220. },
  221. ],
  222. },
  223. ];
  224. const xAxis2 = {
  225. type: 'category',
  226. axisTick: { show: false },
  227. axisLine: { lineStyle: { color: '#D1D6DF' } },
  228. splitLine: { show: false },
  229. };
  230. const yAxis1 = [
  231. {
  232. gridIndex: 0,
  233. show: false,
  234. min: 0,
  235. max: 100,
  236. axisTick: { show: false },
  237. axisLine: { show: false },
  238. splitLine: { show: false },
  239. },
  240. {
  241. gridIndex: 1,
  242. show: false,
  243. min: 0,
  244. max: 100,
  245. axisTick: { show: false },
  246. axisLine: { show: false },
  247. splitLine: { show: false },
  248. },
  249. ];
  250. const yAxis2 = {
  251. show: false,
  252. min: 0,
  253. max: 100,
  254. axisTick: { show: false },
  255. axisLine: { show: false },
  256. splitLine: { show: false },
  257. };
  258. const data1 = {
  259. type: 'bar',
  260. barWidth: 50,
  261. xAxisIndex: 0,
  262. yAxisIndex: 0,
  263. data: [
  264. {
  265. value,
  266. itemStyle: { color: '#7AA7DC' },
  267. label: {
  268. show: true,
  269. position: 'top',
  270. formatter: `{a|${value}}`,
  271. rich: { a: { fontSize: 16, fontWeight: 'bold', color: '#686872' } },
  272. },
  273. },
  274. {
  275. value: allValue,
  276. itemStyle: { color: '#598FCF' },
  277. label: {
  278. show: true,
  279. position: 'top',
  280. formatter: `{a|${allValue}}`,
  281. rich: { a: { fontSize: 12, color: '#686872' } },
  282. },
  283. },
  284. ],
  285. };
  286. const data2 = {
  287. type: 'bar',
  288. barWidth: 50,
  289. xAxisIndex: 1,
  290. yAxisIndex: 1,
  291. data: [
  292. {
  293. value: avgCorrect,
  294. name: 'Avg Time\nCorrect',
  295. itemStyle: { color: '#7775CA' },
  296. label: {
  297. show: true,
  298. position: 'top',
  299. formatter: `{a|${avgCorrect}}`,
  300. rich: { a: { fontSize: 16, fontWeight: 'bold', color: '#686872' } },
  301. },
  302. },
  303. {
  304. value: avgIncorrent,
  305. name: 'Avg Time\nIncorrect',
  306. itemStyle: { color: '#9396C9' },
  307. label: {
  308. show: true,
  309. position: 'top',
  310. formatter: `{a|${avgIncorrent}}`,
  311. rich: { a: { fontSize: 16, fontWeight: 'bold', color: '#686872' } },
  312. },
  313. },
  314. ],
  315. };
  316. return {
  317. title: [
  318. {
  319. text: title,
  320. textStyle: { fontSize: 24, fontWeight: 'bold', color: '#686872' },
  321. left: '0',
  322. },
  323. {
  324. text: 'Avg Time\nTotal',
  325. textAlign: 'center',
  326. textVerticalAlign: 'middle',
  327. textStyle: { color: '#686872', fontWeight: '500', fontSize: 14, lineHeight: 20 },
  328. bottom: '2%',
  329. left: '26%',
  330. },
  331. ],
  332. xAxis: avgCorrect ? xAxis1 : xAxis2,
  333. yAxis: avgCorrect ? yAxis1 : yAxis2,
  334. grid: avgCorrect ? [{ width: 200, x: 72 }, { width: 350, x: 272 }] : { width: 200, left: '30%' },
  335. series: avgCorrect ? [data1, data2] : [data1],
  336. };
  337. }
  338. function pieOption1(title, userCorrect, userNumber, totalCorrect, totalNumber) {
  339. const value = formatPercent(userCorrect, userNumber);
  340. const allValue = formatPercent(totalCorrect, totalNumber);
  341. return {
  342. title: [
  343. {
  344. text: title,
  345. textStyle: { fontSize: 24, fontWeight: 'bold', color: '#686872' },
  346. left: '0',
  347. },
  348. {
  349. text: `${value}%`,
  350. textAlign: 'center',
  351. textVerticalAlign: 'middle',
  352. textStyle: { color: value < 50 ? '#f19057' : '#7AA7DC', fontSize: 45 },
  353. subtext: `${userCorrect}/${userNumber}`,
  354. subtextStyle: { color: '#686872', fontSize: 16 },
  355. top: '35%',
  356. left: '49%',
  357. },
  358. ],
  359. series: [
  360. {
  361. type: 'pie',
  362. radius: ['64%', '70%'],
  363. label: {
  364. show: false,
  365. },
  366. hoverAnimation: false,
  367. animation: false,
  368. data: [
  369. {
  370. value: allValue,
  371. itemStyle: { color: '#7775CA' },
  372. label: {
  373. show: true,
  374. position: 'outside',
  375. formatter: `{a|全站用户}:{b|${allValue}%}`,
  376. rich: {
  377. a: {
  378. color: '#686872',
  379. fontSize: 16,
  380. },
  381. b: {
  382. color: '#6865FD',
  383. fontSize: 16,
  384. },
  385. },
  386. },
  387. },
  388. {
  389. value: 100 - allValue,
  390. itemStyle: { color: '#e1e1e1' },
  391. emphasis: { itemStyle: { color: '#e1e1e1' } },
  392. },
  393. ],
  394. },
  395. {
  396. type: 'pie',
  397. radius: ['45%', '61%'],
  398. label: {
  399. show: false,
  400. },
  401. hoverAnimation: false,
  402. animation: false,
  403. data: [
  404. { value, itemStyle: { color: value < 50 ? '#f19057' : '#7AA7DC' } },
  405. { value: 100 - value, itemStyle: { color: '#e1e1e1' }, emphasis: { itemStyle: { color: '#e1e1e1' } } },
  406. ],
  407. },
  408. ],
  409. };
  410. }
  411. function pieOption2(title, value1, value2, value3) {
  412. return {
  413. title: [
  414. {
  415. text: title,
  416. textStyle: { fontSize: 24, fontWeight: 'bold', color: '#686872' },
  417. left: '0',
  418. },
  419. {
  420. text: `${value1 + value2 + value3}`,
  421. textAlign: 'center',
  422. textVerticalAlign: 'middle',
  423. textStyle: { color: '#686872', fontSize: 60 },
  424. subtext: '综合实力',
  425. subtextStyle: { color: '#686872', fontSize: 14 },
  426. top: '35%',
  427. left: '49.5%',
  428. },
  429. ],
  430. series: [
  431. {
  432. type: 'pie',
  433. radius: ['50%', '80%'],
  434. startAngle: 30,
  435. hoverAnimation: false,
  436. animation: false,
  437. data: [
  438. {
  439. value: value1,
  440. itemStyle: { color: '#6865FD' },
  441. label: {
  442. position: 'outside',
  443. formatter: `{a|逻辑关系} {b|${value1}}`,
  444. rich: {
  445. a: {
  446. color: '#686872',
  447. fontSize: 18,
  448. },
  449. b: {
  450. color: '#6865FD',
  451. fontSize: 18,
  452. },
  453. },
  454. },
  455. },
  456. {
  457. value: value2,
  458. itemStyle: { color: '#6EC28D' },
  459. label: {
  460. position: 'outside',
  461. formatter: `{a|句子结构} {b|${value2}}`,
  462. rich: {
  463. a: {
  464. color: '#686872',
  465. fontSize: 18,
  466. },
  467. b: {
  468. color: '#6EC28D',
  469. fontSize: 18,
  470. },
  471. },
  472. },
  473. },
  474. {
  475. value: value3,
  476. itemStyle: { color: '#598FCF' },
  477. label: {
  478. position: 'outside',
  479. formatter: `{a|阅读速度} {b|${value3}}`,
  480. rich: {
  481. a: {
  482. color: '#686872',
  483. fontSize: 18,
  484. },
  485. b: {
  486. color: '#598FCF',
  487. fontSize: 18,
  488. },
  489. },
  490. },
  491. },
  492. ],
  493. },
  494. ],
  495. };
  496. }
  497. export default class extends Page {
  498. initState() {
  499. return { tab: 'main', report: { paperModule: '' } };
  500. }
  501. initData() {
  502. const { id } = this.params;
  503. const { info = '' } = this.state.search;
  504. Question.detailReport(id).then(result => {
  505. switch (result.paperModule) {
  506. case 'sentence':
  507. this.refreshSentence(result);
  508. break;
  509. case 'textbook':
  510. this.refreshTextbook(result);
  511. break;
  512. case 'exercise':
  513. this.refreshExercise(result);
  514. break;
  515. case 'examination':
  516. this.refreshExamination(result);
  517. break;
  518. default:
  519. }
  520. this.setState({ report: result, paper: result.paper });
  521. });
  522. switch (info) {
  523. case 'question':
  524. // 题目回顾列表
  525. Question.questionReport(id).then(result => {
  526. switch (result.paperModule) {
  527. case 'sentence':
  528. result = result.map((row) => {
  529. row.struct = row.detail.subject && row.detail.predicate && row.detail.object ? 0 : 1;
  530. row.logic = row.detail.options ? 0 : 1;
  531. row.note = row.note ? 1 : 0;
  532. row.collect = row.collect ? 1 : 0;
  533. return row;
  534. });
  535. break;
  536. case 'textbook':
  537. case 'exercise':
  538. result = result.map((row) => {
  539. row.correct = row.isCorrect ? 0 : 1;
  540. row.diff = QuestionDifficultSort[row.question.difficult];
  541. row.note = row.note ? 1 : 0;
  542. row.collect = row.collect ? 1 : 0;
  543. return row;
  544. });
  545. this.refreshExercise(result);
  546. break;
  547. default:
  548. }
  549. this.setState({ list: result });
  550. });
  551. break;
  552. default:
  553. break;
  554. }
  555. }
  556. refreshSentence() {
  557. const { info = '' } = this.state.search;
  558. switch (info) {
  559. case 'question':
  560. break;
  561. default:
  562. }
  563. }
  564. refreshTextbook() {
  565. this.refreshExercise();
  566. }
  567. refreshExamination() {
  568. const { info = '' } = this.state.search;
  569. switch (info) {
  570. case 'score':
  571. break;
  572. default:
  573. }
  574. }
  575. refreshExercise() {
  576. const { info = '' } = this.state.search;
  577. switch (info) {
  578. case 'question':
  579. break;
  580. default:
  581. }
  582. }
  583. questionSort(field) {
  584. let { order } = this.state;
  585. const { list = [] } = this.state;
  586. if (order === field) {
  587. order = 'no';
  588. // direction = 'asc';
  589. } else {
  590. order = field;
  591. // direction = 'desc';
  592. }
  593. list.sort((a, b) => {
  594. const aValue = a[order];
  595. const bValue = a[order];
  596. if (aValue === bValue) {
  597. return a.no < b.no ? -1 : a.no > b.no ? 1 : 0;
  598. }
  599. return aValue > bValue ? -1 : 1;
  600. });
  601. // if (direction === 'desc') {
  602. // list.reverse();
  603. // }
  604. this.setState({ order, list });
  605. }
  606. renderView() {
  607. const { report = {}, search = {} } = this.state;
  608. const { info } = search;
  609. switch (report.paperModule) {
  610. case 'sentence':
  611. if (info === 'question') {
  612. return this.renderSentenceQuestion();
  613. }
  614. return this.renderSentence();
  615. case 'textbook':
  616. if (info === 'question') {
  617. return this.renderExerciseQuestion();
  618. }
  619. return this.renderTextbook();
  620. case 'exercise':
  621. if (info === 'question') {
  622. return this.renderExerciseQuestion();
  623. }
  624. return this.renderExercise();
  625. case 'examination':
  626. return this.renderExamination();
  627. default:
  628. return <div />;
  629. }
  630. }
  631. renderSentence() {
  632. const { paper = {}, report = {}, search = {} } = this.state;
  633. const { info } = search;
  634. const { user } = this.props;
  635. return (
  636. <div className="sentence">
  637. <div className="header">
  638. <div className="content">
  639. <div className="title">Report for 「{report.paperModule === 'examination' ? '模考' : '练习'}」{paper.title}</div>
  640. <div className="btns">
  641. <Button size="small" radius onClick={() => {
  642. linkTo('/');
  643. }}>返回首页</Button>
  644. {!info && <Button size="small" radius onClick={() => {
  645. linkTo(`/paper/report/${report.id}?info=question`);
  646. }}>题目回顾</Button>}
  647. {info === 'question' && <Button size="small" radius onClick={() => {
  648. linkTo(`/paper/report/${report.id}`);
  649. }}>详细报告</Button>}
  650. </div>
  651. <div className="right">
  652. <div className="text">{user.info.nickname}</div>
  653. <div className="desc">练习次数{paper.times}</div>
  654. <div className="desc">{formatDate(report.updateTime, 'YYYY-MM-DD HH:mm:ss')}</div>
  655. </div>
  656. </div>
  657. </div>
  658. {info === 'question' && this.renderSentenceQuestion()}
  659. {!info && this.renderSentenceDetail()}
  660. </div>
  661. );
  662. }
  663. renderTextbook() {
  664. return this.renderExercise();
  665. }
  666. renderExercise() {
  667. const { paper = {}, report = {}, search = {} } = this.state;
  668. const { info } = search;
  669. const { user } = this.props;
  670. return (
  671. <div className="exercise">
  672. <div className="header">
  673. <div className="content">
  674. <div className="title">Report for「练习」{paper.title}</div>
  675. <div className="btns">
  676. <Button size="small" radius onClick={() => {
  677. linkTo('/');
  678. }}>返回首页</Button>
  679. {!info && <Button size="small" radius onClick={() => {
  680. linkTo(`/paper/report/${report.id}?info=question`);
  681. }}>题目回顾</Button>}
  682. {info === 'question' && <Button size="small" radius onClick={() => {
  683. linkTo(`/paper/report/${report.id}`);
  684. }}>详细报告</Button>}
  685. </div>
  686. <div className="right">
  687. <div className="text">{user.info.nickname}</div>
  688. <div className="desc">练习次数{paper.times}</div>
  689. <div className="desc">{formatDate(report.updateTime, 'YYYY-MM-DD HH:mm:ss')}</div>
  690. </div>
  691. </div>
  692. </div>
  693. {info === 'question' && this.renderExerciseQuestion()}
  694. {!info && this.renderExerciseDetail()}
  695. </div>
  696. );
  697. }
  698. renderExamination() {
  699. const { paper = {}, report = {}, search = {} } = this.state;
  700. const { info } = search;
  701. const { user } = this.props;
  702. return (
  703. <div className="examination">
  704. <div className="header">
  705. <div className="content">
  706. <div className="title">Report for 「{report.paperModule === 'examination' ? '模考' : '练习'}」{paper.title}</div>
  707. <div className="btns">
  708. <Button size="small" radius onClick={() => {
  709. linkTo('/');
  710. }}>返回首页</Button>
  711. {!info && <Button size="small" radius onClick={() => {
  712. linkTo(`/paper/report/${report.id}?info=score`);
  713. }}>成绩单</Button>}
  714. {info === 'score' && <Button size="small" radius onClick={() => {
  715. linkTo(`/paper/report/${report.id}`);
  716. }}>详细报告</Button>}
  717. </div>
  718. <div className="right">
  719. <div className="text">{user.info.nickname}</div>
  720. <div className="desc">练习次数{paper.times}</div>
  721. <div className="desc">{formatDate(report.updateTime, 'YYYY-MM-DD HH:mm:ss')}</div>
  722. </div>
  723. </div>
  724. </div>
  725. {info === 'score' && this.renderExaminationScore()}
  726. {!info && this.renderExaminationDetail()}
  727. </div>
  728. );
  729. }
  730. renderSentenceQuestion() {
  731. const { report, list, order } = this.state;
  732. return <div className='sentence question'>
  733. <div className='header'>
  734. <div className='content'>
  735. <div className='title'>题目回顾</div>
  736. <Button className='back' radius onClick={() => {
  737. linkTo(`/paper/report/${report.id}`);
  738. }}>返回长难句报告</Button>
  739. </div>
  740. </div>
  741. <div className='body'>
  742. <div className='content'>
  743. <div className='tip'><Assets name='notice' />点击题目查看详情</div>
  744. <table>
  745. <thead>
  746. <tr>
  747. <th>序号</th>
  748. <th width='420'>题目</th>
  749. <th className="point" onClick={() => {
  750. this.questionSort('struct');
  751. }}>句子结构<GIcon name={order === 'struct' ? 'arrow-down' : 'arrow-up'} active={order === 'struct'} /></th>
  752. <th className="point" onClick={() => {
  753. this.questionSort('logic');
  754. }}>逻辑关系<GIcon name={order === 'logic' ? 'arrow-down' : 'arrow-up'} active={order === 'logic'} /></th>
  755. <th className="point" onClick={() => {
  756. this.questionSort('userTime');
  757. }}>用时<GIcon name={order === 'userTime' ? 'arrow-down' : 'arrow-up'} active={order === 'userTime'} /></th>
  758. <th className="point" onClick={() => {
  759. this.questionSort('collect');
  760. }}>收藏<GIcon name={order === 'collect' ? 'arrow-down' : 'arrow-up'} active={order === 'collect'} /></th>
  761. <th className="point" onClick={() => {
  762. this.questionSort('note');
  763. }}>笔记<GIcon name={order === 'note' ? 'arrow-down' : 'arrow-up'} active={order === 'note'} /></th>
  764. </tr>
  765. </thead>
  766. <tbody>
  767. {(list || []).map(row => {
  768. return <tr>
  769. <td>{row.no}</td>
  770. <td>
  771. <div className='n'><Link to={`/paper/question/${row.id}`}>{row.questionNo.title}</Link></div>
  772. <div className='desc'>{row.question.description}</div>
  773. </td>
  774. <td><GIcon name={row.detail.subject && row.detail.predicate && row.detail.object ? 'right' : 'error'} noHover /></td>
  775. <td><GIcon name={row.detail.options ? 'right' : 'error'} noHover /></td>
  776. <td>{formatMinuteSecond(row.userTime)}</td>
  777. <td><GIcon name='star' active={row.collect} noHover /></td>
  778. <td><GIcon name='note' active={row.note} noHover /></td>
  779. </tr>;
  780. })}
  781. </tbody>
  782. </table>
  783. </div>
  784. </div>
  785. </div>;
  786. }
  787. renderSentenceDetail() {
  788. const { report = {} } = this.state;
  789. const { detail = {} } = report;
  790. return <div>
  791. <div className="body">
  792. <div className="content">
  793. <div className="title">完成情况</div>
  794. <div className="detail">
  795. <div className="block">
  796. <div className="t1">总耗时</div>
  797. <div className="t2">{formatMinute(detail.info.userTime, true)}</div>
  798. <div className="t3">min</div>
  799. </div>
  800. {detail.info.userTime > detail.info.time && <div className="block">
  801. <div className="t1">超出建议用时</div>
  802. <div className="t2">{formatMinute(detail.info.userTime - detail.info.time, true)}</div>
  803. <div className="t3">min</div>
  804. </div>}
  805. <div className="line" />
  806. <div className="block">
  807. <div className="t1">完成题目</div>
  808. <div className="t2">{detail.info.userNumber}</div>
  809. <div className="t3">题</div>
  810. </div>
  811. {detail.info.userNumber !== detail.info.questionNumber && <div className="block">
  812. <div className="t1">剩余未做</div>
  813. <div className="t2">{detail.info.questionNumber || 0 - detail.info.userNumber}</div>
  814. <div className="t3">题</div>
  815. </div>}
  816. </div>
  817. </div>
  818. </div>
  819. <div className="body gray">
  820. <div className="content">
  821. <div className="title">基本情况</div>
  822. <div className="block-wrapper">
  823. <div className="block">
  824. <PieChart option={pieOption1('正确率', detail.info.userCorrect, detail.info.userNumber, detail.info.totalCorrect, detail.info.totalNumber)} />
  825. </div>
  826. <div className="block">
  827. <BarChart option={barOption1('用时', detail.info.userTime / detail.info.userNumber, detail.info.totalTime / detail.info.totalNumber, detail.info.correctTime, detail.info.incorrectTime)} />
  828. </div>
  829. </div>
  830. </div>
  831. </div>
  832. <div className="body">
  833. <div className="content">
  834. <div className="title">能力评估</div>
  835. <PieChart option={pieOption2('综合得分', detail.ability.logic, detail.ability.struct, detail.ability.speed)} />
  836. </div>
  837. </div>
  838. <div className="body gray">
  839. <div className="content t-c">
  840. <Button size="lager" width={200} radius>
  841. 继续做题
  842. </Button>
  843. </div>
  844. </div>
  845. </div>;
  846. }
  847. renderExerciseQuestion() {
  848. const { report, list, order } = this.state;
  849. return <div className='sentence question'>
  850. <div className='header'>
  851. <div className='content'>
  852. <div className='title'>题目回顾</div>
  853. <Button className='back' radius onClick={() => {
  854. linkTo(`/paper/report/${report.id}`);
  855. }}>返回练习报告</Button>
  856. </div>
  857. </div>
  858. <div className='body'>
  859. <div className='content'>
  860. <div className='tip'><Assets name='notice' />点击题目查看详情</div>
  861. <table>
  862. <thead>
  863. <tr>
  864. <th>序号</th>
  865. <th width='340'>题目</th>
  866. <th className="point" onClick={() => {
  867. this.questionSort('correct');
  868. }}>正误<GIcon name={order === 'correct' ? 'arrow-down' : 'arrow-up'} active={order === 'correct'} /></th>
  869. <th className="point" onClick={() => {
  870. this.questionSort('diff');
  871. }}>难度<GIcon name={order === 'diff' ? 'arrow-down' : 'arrow-up'} active={order === 'diff'} /></th>
  872. <th className="point" onClick={() => {
  873. this.questionSort('userTime');
  874. }}>用时<GIcon name={order === 'userTime' ? 'arrow-down' : 'arrow-up'} active={order === 'userTime'} /></th>
  875. <th className="point" onClick={() => {
  876. this.questionSort('place');
  877. }}>主要考点<GIcon name={order === 'place' ? 'arrow-down' : 'arrow-up'} active={order === 'place'} /></th>
  878. <th className="point" onClick={() => {
  879. this.questionSort('collect');
  880. }}>收藏<GIcon name={order === 'collect' ? 'arrow-down' : 'arrow-up'} active={order === 'collect'} /></th>
  881. <th className="point" onClick={() => {
  882. this.questionSort('note');
  883. }}>笔记<GIcon name={order === 'note' ? 'arrow-down' : 'arrow-up'} active={order === 'note'} /></th>
  884. </tr>
  885. </thead>
  886. <tbody>
  887. {(list || []).map(row => {
  888. return <tr>
  889. <td>{row.no}</td>
  890. <td>
  891. <div className='n'><Link to={`/paper/question/${row.id}`}>{row.questionNo.title}</Link></div>
  892. <div className='desc'>{row.question.description}</div>
  893. </td>
  894. <td><GIcon name={row.isCorrect ? 'right' : 'error'} noHover /></td>
  895. <td>{row.question.difficult}</td>
  896. <td>{formatMinuteSecond(row.userTime)}</td>
  897. <td>{row.question.place}</td>
  898. <td><GIcon name='star' active={row.collect} noHover /></td>
  899. <td><GIcon name='note' active={row.note} noHover /></td>
  900. </tr>;
  901. })}
  902. </tbody>
  903. </table>
  904. </div>
  905. </div>
  906. </div>;
  907. }
  908. renderExerciseDetail() {
  909. const { report = {} } = this.state;
  910. const { detail = {} } = report;
  911. return <div>
  912. <div className="body">
  913. <div className="content">
  914. <div className="title">完成情况</div>
  915. <div className="detail">
  916. <div className="block">
  917. <div className="t1">总耗时</div>
  918. <div className="t2">{formatMinute(detail.info.userTime, true)}</div>
  919. <div className="t3">min</div>
  920. </div>
  921. {detail.info.userTime > detail.info.time && <div className="block">
  922. <div className="t1">超出建议用时</div>
  923. <div className="t2">{formatMinute(detail.info.userTime - detail.info.time, true)}</div>
  924. <div className="t3">min</div>
  925. </div>}
  926. <div className="line" />
  927. <div className="block">
  928. <div className="t1">完成题目</div>
  929. <div className="t2">{detail.info.userNumber}</div>
  930. <div className="t3">题</div>
  931. </div>
  932. {detail.info.userNumber !== detail.info.questionNumber && <div className="block">
  933. <div className="t1">剩余未做</div>
  934. <div className="t2">{detail.info.questionNumber - detail.info.userNumber}</div>
  935. <div className="t3">题</div>
  936. </div>}
  937. </div>
  938. </div>
  939. </div>
  940. <div className="body gray">
  941. <div className="content">
  942. <div className="title">基本情况</div>
  943. <div className="block-wrapper">
  944. <div className="block">
  945. <PieChart option={pieOption1('正确率', detail.info.userCorrect, detail.info.userNumber, detail.info.totalCorrect, detail.info.totalNumber)} />
  946. </div>
  947. <div className="block">
  948. <BarChart option={barOption1('用时', detail.info.userTime / detail.info.userNumber, detail.info.totalTime / detail.info.totalNumber, detail.info.correctTime, detail.info.incorrectTime)} />
  949. </div>
  950. </div>
  951. </div>
  952. </div>
  953. <div className="body">
  954. <div className="content">
  955. <div className="title">PACE</div>
  956. <div className="detail-1">
  957. <div className="block">
  958. <div className="t1">平均用时</div>
  959. <div dangerouslySetInnerHTML={{ __html: formatSeconds(detail.info.userTime / detail.info.userNumber).replace(/([0-9]+)(m|min|h|hour|s)/g, '<div class="s">$1</div><div class="t3">$2</div>') }} />
  960. </div>
  961. <div className="block all">
  962. <div className="t1">全站用户</div>
  963. <div dangerouslySetInnerHTML={{ __html: formatSeconds(detail.info.totalTime / detail.info.totalNumber).replace(/([0-9]+)(m|min|h|hour|s)/g, '<div class="s">$1</div><div class="t3">$2</div>') }} />
  964. </div>
  965. </div>
  966. <LineChart
  967. height={400}
  968. option={lineOption1(
  969. '每题用时情况',
  970. detail.pace.map(row => {
  971. return [`${row.no}`, row.userTime, row.time];
  972. }),
  973. ['我的', '全站'],
  974. ['#7AA7DC', '#8684df'],
  975. )}
  976. />
  977. </div>
  978. </div>
  979. <div className="body gray">
  980. <div className="content">
  981. <div className="title">难度分析</div>
  982. <div className="detail-1">
  983. <div className="block">
  984. <div className="t1">正确率</div>
  985. <div className="t2">{formatPercent(detail.info.userCorrect, detail.info.userNumber, false)}</div>
  986. </div>
  987. <div className="block all">
  988. <div className="t1">全站用户</div>
  989. <div className="t2">90</div>
  990. <div className="t3">{formatPercent(detail.info.totalCorrect, detail.info.totalNumber, false)}</div>
  991. </div>
  992. </div>
  993. <BarChart
  994. height={400}
  995. option={BarOption2(
  996. '正确率',
  997. detail.difficult.map(row => {
  998. return [QuestionDifficultMap[row.key], formatPercent(row.userCorrect, row.userNumber), formatPercent(row.totalCorrect, row.totalNumber)];
  999. }),
  1000. ['我的', '全站'],
  1001. ['#8684df', '#5195e5'],
  1002. )}
  1003. />
  1004. </div>
  1005. </div>
  1006. <div className="body">
  1007. <div className="content">
  1008. <div className="title">知识体系分析</div>
  1009. <div className="detail-1">
  1010. <div className="block">
  1011. <div className="t1">平均用时</div>
  1012. <div dangerouslySetInnerHTML={{ __html: formatSeconds(detail.info.userTime / detail.info.userNumber).replace(/([0-9]+)(m|min|h|hour|s)/g, '<div class="s">$1</div><div class="t3">$2</div>') }} />
  1013. </div>
  1014. <div className="block all">
  1015. <div className="t1">正确率</div>
  1016. <div className="t2">{formatPercent(detail.info.userCorrect, detail.info.userNumber, false)}</div>
  1017. </div>
  1018. </div>
  1019. <BarChart
  1020. height={400}
  1021. option={BarOption3(
  1022. ['知识点', '正确率分析', '用时分析'],
  1023. detail.place.map(row => {
  1024. return row.key;
  1025. }),
  1026. detail.place.map(row => {
  1027. return formatPercent(row.userCorrect, row.userNumber);
  1028. }),
  1029. detail.place.map(row => {
  1030. return row.userTime / row.userNumber;
  1031. }),
  1032. ['#7AA7DC', '#BFD4EE'],
  1033. ['#8684df', '#C3C3E5'],
  1034. )}
  1035. />
  1036. </div>
  1037. </div>
  1038. <div className="body gray">
  1039. <div className="content">
  1040. <div className="title">实战提醒</div>
  1041. {detail.info.userTime > detail.info.time && <div className="tip">
  1042. <div className="t1">在实战限时情况下,本套题正确率为 </div>
  1043. <div className="t2">{formatPercent(detail.limit.userCorrect, detail.limit.userNumber)}</div>
  1044. <Tooltip message="仅统计在建议时间内完成题目正确率情况,更接近实战表现"><Icon type="question-circle" theme="filled" /></Tooltip>
  1045. </div>}
  1046. {detail.info.userTime <= detail.info.time && <div className="tip">
  1047. <div className="t1">目前的做题速度已达到实战标准!很棒!请继续保持!</div>
  1048. </div>}
  1049. </div>
  1050. </div>
  1051. <div className="body">
  1052. <div className="content t-c">
  1053. <Button size="lager" width={200} radius>
  1054. 继续做题
  1055. </Button>
  1056. </div>
  1057. </div>
  1058. </div>;
  1059. }
  1060. renderTextbookQuestion() {
  1061. return this.renderExerciseQuestion();
  1062. }
  1063. renderExaminationDetail() {
  1064. const { report = {}, tab } = this.state;
  1065. const { detail = {} } = report;
  1066. const subjectDetail = tab === 'main' ? null : (detail.subject || {})[tab] || { info: {}, defficlt: [], place: [], pace: [] };
  1067. return <div>
  1068. <div className="body">
  1069. <div className="content">
  1070. <Tabs
  1071. type="division"
  1072. theme="gray"
  1073. active={tab}
  1074. space={7}
  1075. tabs={[
  1076. { key: 'main', name: '总览 Overview' },
  1077. { key: 'verbal', name: '语文 Verbal' },
  1078. { key: 'quant', name: '数学 Quant' },
  1079. { key: 'ir', name: '综合推理 IR' },
  1080. ]}
  1081. onChange={(value) => {
  1082. this.setState({ tab: value });
  1083. }}
  1084. />
  1085. {!subjectDetail && <div className="list">
  1086. <div className="title">完成情况</div>
  1087. <div className="detail">
  1088. <div className="block">
  1089. <div className="t1" />
  1090. <div className="t4">Verbal</div>
  1091. <div className="t4">Quant</div>
  1092. <div className="t4">IR</div>
  1093. </div>
  1094. <div className="block">
  1095. <div className="t1">总耗时</div>
  1096. <div className="t1">
  1097. <div className="t2">{formatMinute((detail.subject.verbal || {}).userTime, true)}</div>
  1098. <div className="t3">min</div>
  1099. </div>
  1100. <div className="t1">
  1101. <div className="t2">{formatMinute((detail.subject.quant || {}).userTime, true)}</div>
  1102. <div className="t3">min</div>
  1103. </div>
  1104. <div className="t1">
  1105. <div className="t2">{formatMinute((detail.subject.ir || {}).userTime, true)}</div>
  1106. <div className="t3">min</div>
  1107. </div>
  1108. </div>
  1109. <div className="block">
  1110. <div className="t1">超出建议用时</div>
  1111. <div className="t1">
  1112. <div className="t2">{formatMinute((detail.subject.verbal || {}).userTime - (detail.subject.verbal || {}).time, true)}</div>
  1113. <div className="t3">min</div>
  1114. </div>
  1115. <div className="t1">
  1116. <div className="t2">{formatMinute((detail.subject.quant || {}).userTime - (detail.subject.quant || {}).time, true)}</div>
  1117. <div className="t3">min</div>
  1118. </div>
  1119. <div className="t1">
  1120. <div className="t2">{formatMinute((detail.subject.ir || {}).userTime - (detail.subject.ir || {}).time, true)}</div>
  1121. <div className="t3">min</div>
  1122. </div>
  1123. </div>
  1124. <div className="block">
  1125. <div className="t1" />
  1126. <div className="t1">
  1127. <div className="line" />
  1128. </div>
  1129. <div className="t1">
  1130. <div className="line" />
  1131. </div>
  1132. <div className="t1">
  1133. <div className="line" />
  1134. </div>
  1135. </div>
  1136. <div className="block">
  1137. <div className="t1">完成题目</div>
  1138. <div className="t1">
  1139. <div className="t2">{(detail.subject.verbal || {}).userNumber}</div>
  1140. <div className="t3">题</div>
  1141. </div>
  1142. <div className="t1">
  1143. <div className="t2">{(detail.subject.quant || {}).userNumber}</div>
  1144. <div className="t3">题</div>
  1145. </div>
  1146. <div className="t1">
  1147. <div className="t2">{(detail.subject.ir || {}).userNumber}</div>
  1148. <div className="t3">题</div>
  1149. </div>
  1150. </div>
  1151. <div className="block">
  1152. <div className="t1">剩余未做</div>
  1153. <div className="t1">
  1154. <div className="t2">{(detail.subject.verbal || {}).questionNumber - (detail.subject.verbal || {}).userNumber}</div>
  1155. <div className="t3">题</div>
  1156. </div>
  1157. <div className="t1">
  1158. <div className="t2">{(detail.subject.quant || {}).questionNumber - (detail.subject.quant || {}).userNumber}</div>
  1159. <div className="t3">题</div>
  1160. </div>
  1161. <div className="t1">
  1162. <div className="t2">{(detail.subject.ir || {}).questionNumber - (detail.subject.ir || {}).userNumber}</div>
  1163. <div className="t3">题</div>
  1164. </div>
  1165. </div>
  1166. </div></div>}
  1167. {subjectDetail && <div>
  1168. <div className="title">PACE</div>
  1169. <div className="detail-1">
  1170. <div className="block">
  1171. <div className="t1">平均用时</div>
  1172. <div dangerouslySetInnerHTML={{ __html: formatSeconds(subjectDetail.info.userTime / subjectDetail.info.userNumber).replace(/([0-9]+)(m|min|h|hour|s)/g, '<div class="s">$1</div><div class="t3">$2</div>') }} />
  1173. </div>
  1174. </div>
  1175. <LineChart
  1176. height={400}
  1177. option={lineOption1(
  1178. '每题用时情况',
  1179. subjectDetail.pace.map(row => {
  1180. return [`${row.no}`, row.userTime];
  1181. }),
  1182. ['我的'],
  1183. ['#A3A8BF'],
  1184. )}
  1185. />
  1186. <div className="m-b-4" />
  1187. <LineChart
  1188. height={400}
  1189. option={lineOption1(
  1190. '累计用时情况',
  1191. (function (sd) {
  1192. let userTime = 0;
  1193. let time = 0;
  1194. sd.pace.map(row => {
  1195. userTime += row.userTime;
  1196. time += row.time;
  1197. return [`${row.no}`, userTime, time];
  1198. });
  1199. }(subjectDetail)),
  1200. ['我的', '建议'],
  1201. ['#A3A8BF', '#7AA7DC'],
  1202. )}
  1203. />
  1204. </div>}
  1205. </div>
  1206. </div>
  1207. {!subjectDetail && <div className="body gray">
  1208. <div className="content">
  1209. <div className="title">成绩单</div>
  1210. <table>
  1211. <thead>
  1212. <tr>
  1213. <th>Question format</th>
  1214. <th>Total</th>
  1215. <th>Correct</th>
  1216. <th>%Correct</th>
  1217. <th>
  1218. Avg Time
  1219. </th>
  1220. <th>
  1221. Avg Time
  1222. <br />
  1223. Correct
  1224. </th>
  1225. <th>
  1226. Avg Time
  1227. <br />
  1228. Incorrect
  1229. </th>
  1230. <th>
  1231. Avg Diff
  1232. <br />
  1233. Correct
  1234. </th>
  1235. <th>
  1236. Avg Diff
  1237. <br />
  1238. Incorrect
  1239. </th>
  1240. </tr>
  1241. </thead>
  1242. <tbody>
  1243. {ExaminationQuestionType.map(row => {
  1244. const typeDetail = detail.type[row.value];
  1245. return <tr>
  1246. <td>{row.long}</td>
  1247. <td>{typeDetail.info.questionNumber}</td>
  1248. <td>{typeDetail.info.userCorrect}</td>
  1249. <td>
  1250. {formatPercent(typeDetail.info.userCorrect, typeDetail.info.userNumber)}
  1251. </td>
  1252. <td>
  1253. {formatSecond(typeDetail.info.userTime / typeDetail.info.userNumber)}
  1254. </td>
  1255. <td>
  1256. {formatSecond(typeDetail.info.correctTime / typeDetail.info.userCorrect)}
  1257. </td>
  1258. <td>
  1259. {formatSecond(typeDetail.info.incorrectTime / typeDetail.info.userNumber - typeDetail.info.userCorrect)}
  1260. </td>
  1261. <td>{typeDetail.info.avgDiffCorrect}</td>
  1262. <td>{typeDetail.info.avgDiffIncorrect}</td>
  1263. </tr>;
  1264. })}
  1265. </tbody>
  1266. </table>
  1267. </div>
  1268. </div>}
  1269. {subjectDetail && <div className="body gray">
  1270. <div className="content">
  1271. <div className="title">基本情况</div>
  1272. <table>
  1273. <thead>
  1274. <tr>
  1275. <th>%Correct</th>
  1276. <th>Avg Time</th>
  1277. <th>
  1278. Avg Time
  1279. <br />
  1280. Correct
  1281. </th>
  1282. <th>
  1283. Avg Time
  1284. <br />
  1285. Incorrect
  1286. </th>
  1287. <th>
  1288. Avg Diff
  1289. <br />
  1290. Correct
  1291. </th>
  1292. <th>
  1293. Avg Diff
  1294. <br />
  1295. Incorrect
  1296. </th>
  1297. </tr>
  1298. </thead>
  1299. <tbody>
  1300. <tr>
  1301. <td>
  1302. {formatPercent(subjectDetail.info.userCorrect, subjectDetail.info.userNumber)}
  1303. <br />
  1304. <span>{subjectDetail.info.userCorrect}题/{subjectDetail.info.userNumber}题</span>
  1305. </td>
  1306. <td>
  1307. {formatSecond(subjectDetail.info.userTime / subjectDetail.info.userNumber)}
  1308. <br />
  1309. <span>{formatMinute(subjectDetail.info.userTime)}min/{subjectDetail.info.userNumber}题</span>
  1310. </td>
  1311. <td>
  1312. {formatSecond(subjectDetail.info.correctTime / subjectDetail.info.userCorrect)}
  1313. <br />
  1314. <span>{formatMinute(subjectDetail.info.correctTime)}min/{subjectDetail.info.userCorrect}题</span>
  1315. </td>
  1316. <td>
  1317. {formatSecond(subjectDetail.info.incorrectTime / subjectDetail.info.userNumber - subjectDetail.info.userCorrect)}
  1318. <br />
  1319. <span>{formatMinute(subjectDetail.info.incorrectTime)}min/{subjectDetail.info.userNumber}题</span>
  1320. </td>
  1321. <td>{subjectDetail.info.avgDiffCorrect}</td>
  1322. <td>{subjectDetail.info.avgDiffIncorrect}</td>
  1323. </tr>
  1324. </tbody>
  1325. </table>
  1326. </div>
  1327. </div>}
  1328. {subjectDetail && <div className="body">
  1329. <div className="content">
  1330. <div className="title">难度分析</div>
  1331. <BarChart
  1332. height={400}
  1333. option={BarOption2(
  1334. '正确率',
  1335. subjectDetail.difficult.map(row => {
  1336. return [QuestionDifficultMap[row.key], formatPercent(row.userCorrect, row.userNumber)];
  1337. }),
  1338. ['我的'],
  1339. ['#989FC1'],
  1340. )}
  1341. />
  1342. </div>
  1343. </div>}
  1344. {subjectDetail && <div className="body gray">
  1345. <div className="content">
  1346. <div className="title">知识体系分析</div>
  1347. <BarChart
  1348. height={400}
  1349. option={BarOption3(
  1350. ['知识点', '正确率分析', '用时分析'],
  1351. subjectDetail.place.map(row => {
  1352. return row.key;
  1353. }),
  1354. subjectDetail.place.map(row => {
  1355. return formatPercent(row.userCorrect, row.userNumber);
  1356. }),
  1357. subjectDetail.place.map(row => {
  1358. return row.userTime / row.userNumber;
  1359. }),
  1360. ['#92AFD2', '#BFD4EE'],
  1361. ['#989FC1', '#CCCCDC'],
  1362. )}
  1363. />
  1364. </div>
  1365. </div>}
  1366. </div >;
  1367. }
  1368. renderExaminationScore() {
  1369. const { report = {} } = this.state;
  1370. const { score } = report;
  1371. return <div className="body">
  1372. <div className="content">
  1373. <div className="title">成绩单</div>
  1374. <table>
  1375. <thead>
  1376. <tr>
  1377. <th>学科</th>
  1378. <th>分数</th>
  1379. <th>排名</th>
  1380. <th>题目</th>
  1381. </tr>
  1382. </thead>
  1383. <tbody>
  1384. {ExaminationSubject.map(row => {
  1385. return <tr>
  1386. <td>{row.long}</td>
  1387. <td>{row.ignore ? '--' : score[`${row.value}Score`]}</td>
  1388. <td>{row.ignore ? '--' : score[`${row.value}Rank`]}</td>
  1389. <td><Button size="small" radius onClick={() => {
  1390. Question.getDetailByNo(report.id, 1, row.value).then((r) => {
  1391. linkTo(`/paper/question/${r.id}`);
  1392. });
  1393. }}>回顾</Button></td></tr>;
  1394. })}
  1395. <tr>
  1396. <td>Total</td>
  1397. <td>{score.totalScore}</td>
  1398. <td>{score.totalRank}</td>
  1399. <td><Button size="small" radius onClick={() => {
  1400. Question.getDetailByNo(report.id, 1).then((r) => {
  1401. linkTo(`/paper/question/${r.id}`);
  1402. });
  1403. }}>回顾</Button></td></tr>;
  1404. </tbody>
  1405. </table>
  1406. </div>
  1407. </div>;
  1408. }
  1409. }