page.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  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.resetTimes : 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. let tab1 = '';
  141. let tab2 = '';
  142. const navs = result.map(row => {
  143. row.title = row.level > 2 ? row.titleZh : `${row.titleZh}${row.titleEn}`;
  144. if (!tab1) {
  145. tab1 = row.extend;
  146. } else if (!tab2) {
  147. tab2 = row.extend;
  148. }
  149. row.tab1 = tab1;
  150. row.tab2 = tab2;
  151. return row;
  152. });
  153. this.inited = true;
  154. this.setState({ navs });
  155. });
  156. }
  157. initData() {
  158. const data = Object.assign(this.state, this.state.search);
  159. this.setState(data);
  160. this.refreshData();
  161. }
  162. refreshData(newLogic) {
  163. const { logic } = this.state;
  164. let handler = null;
  165. switch (newLogic || logic) {
  166. case LOGIC_PLACE:
  167. handler = this.refreshPlace();
  168. break;
  169. case LOGIC_DIFFICULT:
  170. handler = this.refreshDifficult();
  171. break;
  172. default:
  173. handler = Promise.resolve();
  174. }
  175. handler.then(() => {
  176. this.refreshExercise();
  177. });
  178. }
  179. refreshPlace() {
  180. const { id } = this.params;
  181. let handler;
  182. if (this.placeList.length > 0) {
  183. this.setState({ logicExtends: this.placeList });
  184. handler = Promise.resolve();
  185. } else {
  186. handler = Question.getExercisePlace(id).then(result => {
  187. this.placeList = result.map(row => {
  188. return {
  189. name: row,
  190. key: row,
  191. };
  192. });
  193. this.setState({ logicExtends: this.placeList });
  194. });
  195. }
  196. return handler.then(() => {
  197. let { logicExtend } = this.state;
  198. if (logicExtend === '') {
  199. logicExtend = this.placeList[0].key;
  200. this.setState({ logicExtend });
  201. }
  202. });
  203. }
  204. refreshDifficult() {
  205. let { logicExtend } = this.state;
  206. this.setState({
  207. logicExtends: QuestionDifficult.map(difficult => {
  208. difficult.name = difficult.label;
  209. difficult.key = difficult.value;
  210. return difficult;
  211. }),
  212. });
  213. return Promise.resolve().then(() => {
  214. if (logicExtend === '') {
  215. logicExtend = QuestionDifficult[0].key;
  216. this.setState({ logicExtend });
  217. }
  218. });
  219. }
  220. refreshExercise() {
  221. const { logic, logicExtend } = this.state;
  222. Question.getExerciseList(Object.assign({ structId: this.params.id, logic, logicExtend }, this.state.search))
  223. .then((result) => {
  224. this.setState({ list: result.list, total: result.total });
  225. });
  226. }
  227. onChangeTab(key, value) {
  228. const { logic } = this.state;
  229. const data = {};
  230. if (key === 'logicExtend') {
  231. data.logic = logic;
  232. data.logicExtend = value;
  233. } else {
  234. data.logic = value;
  235. }
  236. // this.refreshData(tab);
  237. this.refreshQuery(data);
  238. }
  239. restart(item) {
  240. asyncConfirm('提示', '你打算重做本套练习,过往做题记录可至「个人中心-报告」查看。', () => {
  241. Question.restart(item.paper.id).then(() => {
  242. this.refresh();
  243. });
  244. });
  245. }
  246. renderView() {
  247. const { logic, logicExtend, logics = [], logicExtends = [], list, search, navs } = this.state;
  248. const { finish } = search;
  249. return (
  250. <div>
  251. <div className="content">
  252. <Breadcrumb separator=">">
  253. <Breadcrumb.Item href="/exercise">练习</Breadcrumb.Item>
  254. {(navs || []).map(row => {
  255. return <Breadcrumb.Item href={`/exercise?tab1=${row.tab1}&tab2=${row.tab2}`}>{row.title}</Breadcrumb.Item>;
  256. })}
  257. </Breadcrumb>
  258. <Module className="m-t-2">
  259. <Tabs
  260. active={logic}
  261. border
  262. width="180px"
  263. space="0"
  264. tabs={logics}
  265. onChange={(key) => {
  266. this.onChangeTab('logic', key);
  267. }}
  268. />
  269. {logicExtends.length > 0 && <Tabs
  270. active={logicExtend}
  271. type="text"
  272. tabs={logicExtends}
  273. onChange={(key) => {
  274. this.onChangeTab('logicExtend', key);
  275. }}
  276. />}
  277. </Module>
  278. <ListTable
  279. filters={[
  280. {
  281. type: 'radio',
  282. checked: finish,
  283. list: [{ key: '0', title: '未完成' }, { key: '1', title: '已完成' }],
  284. onChange: item => {
  285. if (item.key === finish) {
  286. this.search({ finish: null });
  287. } else if (item.key === '0') {
  288. this.search({ finish: 0 });
  289. } else if (item.key === '1') {
  290. this.search({ finish: 1 });
  291. } else {
  292. this.search({ finish: null });
  293. }
  294. },
  295. },
  296. ]}
  297. data={list}
  298. columns={this.columns}
  299. />
  300. </div>
  301. </div>
  302. );
  303. }
  304. }