page.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. import React from 'react';
  2. import { Breadcrumb } from 'antd';
  3. import './index.less';
  4. import Page from '@src/containers/Page';
  5. import { asyncConfirm } from '@src/services/AsyncTools';
  6. import { formatPercent, formatSeconds, formatDate } from '@src/services/Tools';
  7. import Tabs from '../../../components/Tabs';
  8. import Module from '../../../components/Module';
  9. import ListTable from '../../../components/ListTable';
  10. import ProgressText from '../../../components/ProgressText';
  11. import IconButton from '../../../components/IconButton';
  12. import { Main } from '../../../stores/main';
  13. import { Question } from '../../../stores/question';
  14. import { QuestionDifficult } from '../../../../Constant';
  15. const LOGIC_NO = 'no';
  16. const LOGIC_PLACE = 'place';
  17. const LOGIC_DIFFICULT = 'difficult';
  18. const LOGIC_ERROR = 'error';
  19. export default class extends Page {
  20. initState() {
  21. this.columns = [{
  22. title: '练习册',
  23. width: 250,
  24. align: 'left',
  25. render: (record) => {
  26. let progress = 0;
  27. if (record.report) {
  28. progress = formatPercent(record.report.userNumber, record.report.questionNumber);
  29. }
  30. return (
  31. <div className="table-row">
  32. <div className="night f-s-16">{record.title}</div>
  33. <div>
  34. <ProgressText progress={progress} times={record.paper ? record.paper.finishTimes : 0} size="small" />
  35. </div>
  36. </div>
  37. );
  38. },
  39. }, {
  40. title: '正确率',
  41. width: 150,
  42. align: 'left',
  43. render: (record) => {
  44. let correct = '--';
  45. if (record.report) {
  46. correct = formatPercent(record.report.userCorrect, record.report.userNumber, false);
  47. }
  48. return (
  49. <div className="table-row">
  50. <div className="night f-s-16 f-w-b">{correct}</div>
  51. <div className="f-s-12">全站{formatPercent(record.stat.totalCorrect, record.stat.totalNumber, false)}</div>
  52. </div>
  53. );
  54. },
  55. }, {
  56. title: '全站用时',
  57. width: 150,
  58. align: 'left',
  59. render: (record) => {
  60. let time = '--';
  61. if (record.report) {
  62. time = formatSeconds(record.report.userTime / record.report.userNumber);
  63. }
  64. return (
  65. <div className="table-row">
  66. <div className="night f-s-16 f-w-b">{time}</div>
  67. <div className="f-s-12">全站{formatSeconds(record.stat.totalTime / record.stat.totalNumber)}</div>
  68. </div>
  69. );
  70. },
  71. }, {
  72. title: '最近做题',
  73. width: 150,
  74. align: 'left',
  75. render: (record) => {
  76. const time = record.report ? record.report.updateTime : record.paper ? record.paper.latestTime : null;
  77. return (
  78. <div className="table-row">
  79. <div>{time && formatDate(time, 'YYYY-MM-DD')}</div>
  80. <div>{time && formatDate(time, 'HH:mm')}</div>
  81. </div>
  82. );
  83. },
  84. }, {
  85. title: '操作',
  86. width: 180,
  87. align: 'left',
  88. render: (record) => {
  89. return (
  90. <div className="table-row p-t-1">
  91. {!record.report && <IconButton type="start" tip="Start" onClick={() => {
  92. Question.startLink('exercise', record);
  93. }} />}
  94. {(record.report && !record.report.isFinish) && <IconButton className="m-r-2" type="continue" tip="Continue" onClick={() => {
  95. Question.continueLink('exercise', record);
  96. }} />}
  97. {(record.report) && <IconButton type="restart" tip="Restart" onClick={() => {
  98. this.restart(record);
  99. }} />}
  100. </div>
  101. );
  102. },
  103. }, {
  104. title: '报告',
  105. width: 30,
  106. align: 'right',
  107. render: (record) => {
  108. return (
  109. <div className="table-row p-t-1">
  110. {record.report && !!record.report.isFinish && <IconButton type="report" tip="Report" onClick={() => {
  111. Question.reportLink(record);
  112. }} />}
  113. </div>
  114. );
  115. },
  116. }];
  117. this.placeList = [];
  118. this.inited = false;
  119. return {
  120. logic: LOGIC_NO,
  121. logicExtend: '',
  122. logics: [{
  123. key: LOGIC_NO,
  124. title: '按顺序练习',
  125. }, {
  126. key: LOGIC_PLACE,
  127. title: '按考点练习',
  128. }, {
  129. key: LOGIC_DIFFICULT,
  130. title: '按难度练习',
  131. }, {
  132. key: LOGIC_ERROR,
  133. title: '按易错度练习',
  134. }],
  135. };
  136. }
  137. init() {
  138. const { id } = this.params;
  139. Main.getExerciseParent(id).then(result => {
  140. const navs = result.map(row => {
  141. row.title = row.level > 2 ? row.titleZh : `${row.titleZh}${row.titleEn}`;
  142. return row;
  143. });
  144. this.inited = true;
  145. this.setState({ navs });
  146. });
  147. }
  148. initData() {
  149. const data = Object.assign(this.state, this.state.search);
  150. this.setState(data);
  151. this.refreshData();
  152. }
  153. refreshData(newLogic) {
  154. const { logic } = this.state;
  155. let handler = null;
  156. switch (newLogic || logic) {
  157. case LOGIC_PLACE:
  158. handler = this.refreshPlace();
  159. break;
  160. case LOGIC_DIFFICULT:
  161. handler = this.refreshDifficult();
  162. break;
  163. default:
  164. handler = Promise.resolve();
  165. }
  166. handler.then(() => {
  167. this.refreshExercise();
  168. });
  169. }
  170. refreshPlace() {
  171. const { id } = this.params;
  172. let handler;
  173. if (this.placeList.length > 0) {
  174. this.setState({ logicExtends: this.placeList });
  175. handler = Promise.resolve();
  176. } else {
  177. handler = Question.getExercisePlace(id).then(result => {
  178. this.placeList = result.map(row => {
  179. return {
  180. name: row,
  181. key: row,
  182. };
  183. });
  184. this.setState({ logicExtends: this.placeList });
  185. });
  186. }
  187. return handler.then(() => {
  188. let { logicExtend } = this.state;
  189. if (logicExtend === '') {
  190. logicExtend = this.placeList[0].key;
  191. this.setState({ logicExtend });
  192. }
  193. });
  194. }
  195. refreshDifficult() {
  196. let { logicExtend } = this.state;
  197. this.setState({
  198. logicExtends: QuestionDifficult.map(difficult => {
  199. difficult.name = difficult.label;
  200. difficult.key = difficult.value;
  201. return difficult;
  202. }),
  203. });
  204. return Promise.resolve().then(() => {
  205. if (logicExtend === '') {
  206. logicExtend = QuestionDifficult[0].key;
  207. this.setState({ logicExtend });
  208. }
  209. });
  210. }
  211. refreshExercise() {
  212. const { logic, logicExtend } = this.state;
  213. Question.getExerciseList(Object.assign({ structId: this.params.id, logic, logicExtend }, this.state.search))
  214. .then((result) => {
  215. this.setState({ list: result.list, total: result.total });
  216. });
  217. }
  218. onChangeTab(key, value) {
  219. const { logic } = this.state;
  220. const data = {};
  221. if (key === 'logicExtend') {
  222. data.logic = logic;
  223. data.logicExtend = value;
  224. } else {
  225. data.logic = value;
  226. }
  227. // this.refreshData(tab);
  228. this.refreshQuery(data);
  229. }
  230. restart(item) {
  231. asyncConfirm('提示', '你打算重做本套练习,过往做题记录可至「个人中心-报告」查看。', () => {
  232. Question.restart(item.paper.id).then(() => {
  233. this.refresh();
  234. });
  235. });
  236. }
  237. renderView() {
  238. const { logic, logicExtend, logics = [], logicExtends = [], list, search, navs } = this.state;
  239. const { finish } = search;
  240. return (
  241. <div>
  242. <div className="content">
  243. <Breadcrumb separator=">">
  244. <Breadcrumb.Item href="/exercise">练习</Breadcrumb.Item>
  245. {(navs || []).map(row => {
  246. return <Breadcrumb.Item>{row.title}</Breadcrumb.Item>;
  247. })}
  248. </Breadcrumb>
  249. <Module className="m-t-2">
  250. <Tabs
  251. active={logic}
  252. border
  253. width="180px"
  254. space="0"
  255. tabs={logics}
  256. onChange={(key) => {
  257. this.onChangeTab('logic', key);
  258. }}
  259. />
  260. {logicExtends.length > 0 && <Tabs
  261. active={logicExtend}
  262. type="text"
  263. tabs={logicExtends}
  264. onChange={(key) => {
  265. this.onChangeTab('logicExtend', key);
  266. }}
  267. />}
  268. </Module>
  269. <ListTable
  270. filters={[
  271. {
  272. type: 'radio',
  273. checked: finish,
  274. list: [{ key: '0', title: '未完成' }, { key: '1', title: '已完成' }],
  275. onChange: item => {
  276. if (item.key === finish) {
  277. this.search({ finish: null });
  278. } else if (item.key === '0') {
  279. this.search({ finish: 0 });
  280. } else if (item.key === '1') {
  281. this.search({ finish: 1 });
  282. } else {
  283. this.search({ finish: null });
  284. }
  285. },
  286. },
  287. ]}
  288. data={list}
  289. columns={this.columns}
  290. />
  291. </div>
  292. </div>
  293. );
  294. }
  295. }