page.js 9.4 KB

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