exam-start.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. <template>
  2. <ie-page :fix-height="true" :safe-area-inset-bottom="false">
  3. <block v-if="isReady">
  4. <exam-navbar :total-exam-time="totalExamTime" @left-click="handleLeftClick" @right-click="handleRightClick" />
  5. <exam-subtitle />
  6. <exam-swiper @submit="beforeSubmit" />
  7. <exam-toolbar ref="examToolbarRef" @submit="beforeSubmit" />
  8. </block>
  9. </ie-page>
  10. <fast-guide v-model:show="guideShow" :list="guideList" v-model:index="guideIndex" @close="handleGuideClose"
  11. @getQuery="getQuery"></fast-guide>
  12. <question-swiper-tip :visible="showSwiperTip" @next="handleSwiperTipNext" />
  13. <exam-mode ref="examModeRef" />
  14. </template>
  15. <script lang="ts" setup>
  16. import ExamNavbar from './components/exam-navbar.vue';
  17. import ExamSubtitle from './components/exam-subtitle.vue';
  18. import ExamSwiper from './components/exam-swiper.vue';
  19. import ExamToolbar from './components/exam-toolbar.vue';
  20. import ExamMode from './components/exam-mode.vue';
  21. import QuestionSwiperTip from './components/question-swiper-tip.vue';
  22. import { useTransferPage } from '@/hooks/useTransferPage';
  23. import { useUserStore } from '@/store/userStore';
  24. import { EnumPaperType, EnumQuestionType } from '@/common/enum';
  25. import { getOpenExaminee, getPaper, commitExamineePaper, beginExaminee, getExamineeResult } from '@/api/modules/study';
  26. import { useExam } from '@/composables/useExam';
  27. import { Study, Transfer } from '@/types';
  28. import {
  29. EXAM_AUTO_SUBMIT,
  30. EXAM_PAGE_OPTIONS,
  31. EXAM_DATA
  32. } from '@/types/injectionSymbols';
  33. import { useAppStore } from '@/store/appStore';
  34. import { useEnv } from '@/hooks/useEnv';
  35. import { useReport } from '@/hooks/useReport';
  36. const { report, events } = useReport();
  37. const appStore = useAppStore();
  38. const { platform } = useEnv();
  39. const userStore = useUserStore();
  40. // import { Examinee, ExamPaper, ExamPaperSubmit } from '@/types/study';
  41. const { prevData, transferBack, transferTo } = useTransferPage<Transfer.ExamAnalysisPageOptions, {}>();
  42. const examData = useExam();
  43. const { setQuestionList, questionList, flatQuestionList, setSubQuestionIndex,
  44. notDoneCount, isAllDone,
  45. practiceDuration, startTiming, stopTiming, submit, changeIndex, setDuration } = examData;
  46. //
  47. const showSwiperTip = ref(false);
  48. const guideShow = ref(false);
  49. const guideList = ref([
  50. {
  51. ref: 'examToolbarRef',
  52. target: '#question-calendar-btn',
  53. position: 'top',
  54. msg: '[答题卡]\n查看答题卡,掌握考试进度'
  55. },
  56. {
  57. ref: 'examToolbarRef',
  58. target: '#question-favorite-btn',
  59. position: 'top',
  60. msg: '[题目收藏]\n收藏的题目可以在收藏夹查看'
  61. },
  62. {
  63. ref: 'examToolbarRef',
  64. target: '#question-mark-btn',
  65. position: 'top',
  66. msg: '[题目标记]\n标记的题目可以在答题卡中快速找到'
  67. },
  68. {
  69. ref: 'examToolbarRef',
  70. target: '#question-correct-btn',
  71. position: 'top',
  72. msg: '[试题纠错]\n点击试题纠错,帮助我们改进题目'
  73. }
  74. ]);
  75. const guideIndex = ref(0);
  76. const isReady = ref(false);
  77. // 考试规定时间
  78. const totalExamTime = ref<number>(0);
  79. // 自动提交只提醒1次
  80. const hasShowSubmitConfirm = ref(false);
  81. const examineeId = ref<number | undefined>(undefined);
  82. const paperData = ref<Study.ExamPaper>({} as Study.ExamPaper);
  83. // 是否确认退出
  84. const confirmQuit = ref(false);
  85. const confirmShowing = ref(false);
  86. /**
  87. * 自动提交
  88. */
  89. const autoSubmit = () => {
  90. if (hasShowSubmitConfirm.value) {
  91. return;
  92. }
  93. hasShowSubmitConfirm.value = true;
  94. beforeSubmit();
  95. }
  96. provide(EXAM_PAGE_OPTIONS, prevData.value);
  97. provide(EXAM_DATA, examData);
  98. provide(EXAM_AUTO_SUBMIT, autoSubmit);
  99. const isPracticeExam = computed(() => {
  100. return prevData.value.paperType === EnumPaperType.PRACTICE || prevData.value.paperType === EnumPaperType.COURSE;
  101. });
  102. const isSimulationExam = computed(() => {
  103. // prevData.value
  104. return prevData.value.paperType === EnumPaperType.SIMULATED;
  105. });
  106. const isTestExam = computed(() => {
  107. return prevData.value.paperType === EnumPaperType.TEST;
  108. });
  109. const isReadOnly = computed(() => {
  110. return prevData.value.readonly || false;
  111. });
  112. const handleLeftClick = () => {
  113. if (!isReady.value || isReadOnly.value) {
  114. confirmQuit.value = true;
  115. transferBack();
  116. return;
  117. }
  118. beforeQuit();
  119. };
  120. const examModeRef = ref();
  121. const handleRightClick = () => {
  122. examModeRef.value.open();
  123. }
  124. const instance = getCurrentInstance();
  125. const getQuery = (fn: () => void) => {
  126. fn.call(instance?.proxy)
  127. }
  128. const beforeQuit = () => {
  129. const { paperType } = prevData.value;
  130. if (!isReady.value || isReadOnly.value) {
  131. return;
  132. }
  133. stopTime();
  134. const msg = paperType === EnumPaperType.PRACTICE ? '当前练习未完成,确认退出?' : '当前考试未完成,确认退出?';
  135. confirmShowing.value = true;
  136. uni.$ie.showModal({
  137. title: '提示',
  138. content: msg,
  139. }).then(confirm => {
  140. if (confirm) {
  141. handleSubmit(true);
  142. } else {
  143. confirmQuit.value = false;
  144. confirmShowing.value = false;
  145. startTime();
  146. }
  147. });
  148. };
  149. const startTime = () => {
  150. startTiming();
  151. }
  152. const stopTime = () => {
  153. stopTiming();
  154. }
  155. const beforeSubmit = async () => {
  156. const text = notDoneCount.value > 0 ? `还有${notDoneCount.value}题未做,确认交卷?` : '是否确认交卷?';
  157. stopTime();
  158. uni.$ie.showModal({
  159. title: '提示',
  160. content: text,
  161. }).then(confirm => {
  162. if (confirm) {
  163. handleSubmit(false);
  164. } else {
  165. startTime();
  166. }
  167. });
  168. }
  169. /**
  170. * 提交试卷
  171. * @param tempSave 是否临时保存
  172. */
  173. const handleSubmit = (tempSave: boolean = false) => {
  174. // 执行完后续逻辑
  175. submit();
  176. const msg = tempSave ? '保存中...' : '提交中...';
  177. uni.$ie.showLoading(msg);
  178. setTimeout(async () => {
  179. const params: Study.ExamPaperSubmit = {
  180. ...paperData.value,
  181. questions: questionList.value.map(item => {
  182. return {
  183. ...item,
  184. title: '',
  185. isDone: tempSave ? item.isDone : true,
  186. subQuestions: item.subQuestions.map(subItem => {
  187. return {
  188. ...subItem,
  189. title: '',
  190. };
  191. })
  192. };
  193. }),
  194. examineeId: examineeId.value,
  195. // examineeId: examineerData.value.examineeId,
  196. isDone: tempSave ? isAllDone.value : true,
  197. duration: practiceDuration.value
  198. };
  199. console.log('提交试卷参数', params)
  200. const start = Date.now();
  201. await commitExamineePaper(params);
  202. const costTime = Date.now() - start;
  203. report(events.ExamStartSubmitSuccess, { time: costTime });
  204. if (isSimulationExam.value || isTestExam.value) {
  205. if (!tempSave) {
  206. setTimeout(async () => {
  207. report(events.ExamStartExit);
  208. uni.$ie.hideLoading();
  209. await nextTick();
  210. confirmQuit.value = true;
  211. confirmShowing.value = false;
  212. transferTo('/pagesStudy/pages/simulation-analysis/simulation-analysis', {
  213. data: {
  214. examineeId: examineeId.value,
  215. paperType: prevData.value.paperType
  216. } as Transfer.SimulationAnalysisPageOptions,
  217. type: 'redirectTo'
  218. });
  219. }, 2500);
  220. } else {
  221. uni.$ie.hideLoading();
  222. confirmQuit.value = true;
  223. confirmShowing.value = false;
  224. nextTick(() => {
  225. transferBack();
  226. });
  227. }
  228. } else if (isPracticeExam.value) {
  229. if (!tempSave) {
  230. setTimeout(async () => {
  231. report(events.ExamStartExit);
  232. uni.$ie.hideLoading();
  233. await nextTick();
  234. confirmQuit.value = true;
  235. confirmShowing.value = false;
  236. transferTo('/pagesStudy/pages/knowledge-practice-detail/knowledge-practice-detail', {
  237. data: {
  238. paperType: prevData.value.paperType,
  239. examineeId: examineeId.value,
  240. name: prevData.value.practiceInfo?.name,
  241. directed: prevData.value.practiceInfo?.directed,
  242. questionType: prevData.value.practiceInfo?.questionType
  243. } as Transfer.PracticeResultPageOptions,
  244. type: 'redirectTo'
  245. });
  246. }, 2500);
  247. } else {
  248. report(events.ExamStartExit);
  249. uni.$ie.hideLoading();
  250. confirmQuit.value = true;
  251. confirmShowing.value = false;
  252. nextTick(() => {
  253. transferBack();
  254. });
  255. }
  256. }
  257. }, 300);
  258. }
  259. /**
  260. * 恢复上次做题历史数据
  261. * @param savedQuestion 上次做题历史数据
  262. * @param fullQuestion 当前试卷数据
  263. */
  264. const restoreQuestion = (savedQuestion: Study.ExamineeQuestion[], fullQuestion: Study.ExamineeQuestion[]) => {
  265. if (!savedQuestion) {
  266. return fullQuestion;
  267. }
  268. for (let index = 0; index < fullQuestion.length; index++) {
  269. const item = fullQuestion[index];
  270. const savedQs = savedQuestion[index]
  271. if (savedQs) {
  272. if (savedQs.answers) {
  273. item.answers = savedQs.answers.filter(ans => ans.trim());
  274. }
  275. item.answer1 = savedQs.answer1;
  276. item.answer2 = savedQs.answer2;
  277. item.isMark = savedQs.isMark;
  278. item.isFavorite = savedQs.isFavorite;
  279. item.isNotKnow = savedQs.isNotKnow;
  280. item.parse = savedQs.parse;
  281. item.totalScore = savedQs.totalScore;
  282. if (item.subQuestions) {
  283. restoreQuestion(savedQs.subQuestions, item.subQuestions);
  284. }
  285. }
  286. }
  287. return fullQuestion;
  288. }
  289. /**
  290. * 带超时检测的 getOpenExaminee 请求
  291. * 在 3s, 5s, 10s, 15s, 20s 这 5 个时间点检测超时并上报
  292. * 每个时间点如果请求还未返回,都会上报一次
  293. */
  294. const getOpenExamineeWithTimeoutCheck = async (params: Study.OpenExamineeRequestDTO) => {
  295. // 超时时间档次(单位:毫秒)
  296. const timeoutLevels = [3000, 5000, 10000, 15000, 20000];
  297. // 存储所有定时器ID,用于清理
  298. const timers: number[] = [];
  299. // 请求是否已完成
  300. let isCompleted = false;
  301. // 创建超时检测定时器
  302. timeoutLevels.forEach((timeout) => {
  303. const timer = setTimeout(() => {
  304. // 如果请求已完成,不进行上报
  305. if (isCompleted) {
  306. return;
  307. }
  308. // 上报超时数据,超时时间单位为秒
  309. // 每个时间点如果请求还未返回,都会上报一次
  310. report(events.ExamStartLoadSlow, { time: timeout });
  311. }, timeout) as unknown as number;
  312. timers.push(timer);
  313. });
  314. try {
  315. // 执行请求
  316. const result = await getOpenExaminee(params);
  317. // 标记请求已完成
  318. isCompleted = true;
  319. // 清除所有定时器
  320. timers.forEach((timer) => clearTimeout(timer));
  321. return result;
  322. } catch (error) {
  323. // 请求失败时也要清除定时器
  324. isCompleted = true;
  325. timers.forEach((timer) => clearTimeout(timer));
  326. throw error;
  327. }
  328. };
  329. /**
  330. * 带超时检测的 getPaper 请求
  331. * 在 3s, 5s, 10s, 15s, 20s 这 5 个时间点检测超时并上报
  332. * 每个时间点如果请求还未返回,都会上报一次
  333. */
  334. const getPaperWithTimeoutCheck = async (params: Study.GetExamPaperRequestDTO) => {
  335. // 超时时间档次(单位:毫秒)
  336. const timeoutLevels = [3000, 5000, 10000, 15000, 20000];
  337. // 存储所有定时器ID,用于清理
  338. const timers: number[] = [];
  339. // 请求是否已完成
  340. let isCompleted = false;
  341. // 创建超时检测定时器
  342. timeoutLevels.forEach((timeout) => {
  343. const timer = setTimeout(() => {
  344. // 如果请求已完成,不进行上报
  345. if (isCompleted) {
  346. return;
  347. }
  348. // 上报超时数据,超时时间单位为秒
  349. // 每个时间点如果请求还未返回,都会上报一次
  350. report(events.ExamStartGetPaperSlow, { time: timeout });
  351. }, timeout) as unknown as number;
  352. timers.push(timer);
  353. });
  354. try {
  355. // 执行请求
  356. const result = await getPaper(params);
  357. // 标记请求已完成
  358. isCompleted = true;
  359. // 清除所有定时器
  360. timers.forEach((timer) => clearTimeout(timer));
  361. return result;
  362. } catch (error) {
  363. // 请求失败时也要清除定时器
  364. isCompleted = true;
  365. timers.forEach((timer) => clearTimeout(timer));
  366. throw error;
  367. }
  368. };
  369. /**
  370. * 带超时检测的 beginExaminee 请求
  371. * 在 3s, 5s, 10s, 15s, 20s 这 5 个时间点检测超时并上报
  372. * 每个时间点如果请求还未返回,都会上报一次
  373. */
  374. const beginExamineeWithTimeoutCheck = async (examineeId: number) => {
  375. // 超时时间档次(单位:毫秒)
  376. const timeoutLevels = [3000, 5000, 10000, 15000, 20000];
  377. // 存储所有定时器ID,用于清理
  378. const timers: number[] = [];
  379. // 请求是否已完成
  380. let isCompleted = false;
  381. // 创建超时检测定时器
  382. timeoutLevels.forEach((timeout) => {
  383. const timer = setTimeout(() => {
  384. // 如果请求已完成,不进行上报
  385. if (isCompleted) {
  386. return;
  387. }
  388. // 上报超时数据,超时时间单位为秒
  389. // 每个时间点如果请求还未返回,都会上报一次
  390. report(events.ExamStartBeginExamineeSlow, { time: timeout });
  391. }, timeout) as unknown as number;
  392. timers.push(timer);
  393. });
  394. try {
  395. // 执行请求
  396. const result = await beginExaminee(examineeId);
  397. // 标记请求已完成
  398. isCompleted = true;
  399. // 清除所有定时器
  400. timers.forEach((timer) => clearTimeout(timer));
  401. return result;
  402. } catch (error) {
  403. // 请求失败时也要清除定时器
  404. isCompleted = true;
  405. timers.forEach((timer) => clearTimeout(timer));
  406. throw error;
  407. }
  408. };
  409. // 1、加载知识点练习数据
  410. const loadPracticeData = async () => {
  411. const { paperType, readonly, practiceInfo } = prevData.value;
  412. let data: Study.Examinee | null = null;
  413. if (readonly) {
  414. if (practiceInfo?.examineeId) {
  415. const res = await getExamineeResult(practiceInfo.examineeId);
  416. data = res.data;
  417. }
  418. } else {
  419. try {
  420. const params = {
  421. paperType: paperType,
  422. relateId: practiceInfo?.relateId,
  423. } as Study.OpenExamineeRequestDTO;
  424. if (userStore.isVHS) {
  425. params.questionType = practiceInfo?.questionType;
  426. } else {
  427. params.directed = practiceInfo?.directed || false;
  428. }
  429. const start = Date.now();
  430. const res = await getOpenExamineeWithTimeoutCheck(params);
  431. data = res.data || {};
  432. const costTime = Date.now() - start;
  433. console.log('开卷用时:', costTime);
  434. report(events.ExamStartLoadSuccess, { time: costTime, request: params, response: res.data || {} });
  435. } catch (error) {
  436. report(events.ExamStartLoadError, { error: error });
  437. }
  438. }
  439. if (!data) {
  440. uni.$ie.hideLoading();
  441. transferBack();
  442. return;
  443. }
  444. // 练习没有规定时间,设置为最大值
  445. totalExamTime.value = Number.MAX_SAFE_INTEGER;
  446. combinePaperData(data, paperType);
  447. }
  448. // 2、加载模拟考试数据
  449. const loadExamData = async () => {
  450. const { paperType, readonly, simulationInfo } = prevData.value;
  451. let data: Study.Examinee;
  452. if (simulationInfo?.examineeId) {
  453. if (readonly) {
  454. const res = await getExamineeResult(simulationInfo.examineeId);
  455. data = res.data;
  456. } else {
  457. try {
  458. const start = Date.now();
  459. const res = await beginExamineeWithTimeoutCheck(simulationInfo.examineeId);
  460. data = res.data || {};
  461. const costTime = Date.now() - start;
  462. report(events.ExamStartBeginExamineeSuccess, { time: costTime, request: { examineeId: simulationInfo.examineeId }, response: res.data || {} });
  463. } catch (error) {
  464. report(events.ExamStartBeginExamineeError, { error: error });
  465. throw error;
  466. }
  467. }
  468. if (!data) {
  469. uni.$ie.hideLoading();
  470. transferBack();
  471. return;
  472. }
  473. totalExamTime.value = data.paperInfo?.time || 0;
  474. combinePaperData(data, paperType);
  475. }
  476. }
  477. // 3、加载对口升学试卷数据
  478. // const loadVHSPaperData = async () => {
  479. // const { paperType, readonly, simulationInfo } = prevData.value;
  480. // let data: Study.Examinee;
  481. // if (simulationInfo?.examineeId) {
  482. // if (readonly) {
  483. // const res = await getExamineeResult(simulationInfo.examineeId);
  484. // data = res.data;
  485. // } else {
  486. // const params = {
  487. // paperType: paperType,
  488. // relateId: simulationInfo?.examineeId,
  489. // } as Study.OpenExamineeRequestDTO;
  490. // const res = await getOpenExaminee(params);
  491. // data = res.data || {};
  492. // }
  493. // if (!data) {
  494. // uni.$ie.hideLoading();
  495. // transferBack();
  496. // return;
  497. // }
  498. // totalExamTime.value = data.paperInfo?.time || Number.MAX_SAFE_INTEGER;
  499. // combinePaperData(data, paperType);
  500. // }
  501. // }
  502. const combinePaperData = async (examinee: Study.Examinee, paperType: EnumPaperType) => {
  503. examineeId.value = examinee.examineeId;
  504. report(events.ExamStartCombineData, {
  505. envUser: uni.getStorageSync('ie-user'),
  506. envApp: uni.getStorageSync('ie-app'),
  507. });
  508. if (!examinee.paperId) {
  509. report(events.ExamStartGetPaperError, {
  510. error: '获取试卷数据失败,没有paperId',
  511. examineeId: examinee.examineeId
  512. });
  513. return;
  514. }
  515. // 第一步:请求试卷数据(单独 try-catch)
  516. let res;
  517. try {
  518. const start = Date.now();
  519. res = await getPaperWithTimeoutCheck({
  520. type: paperType,
  521. id: examinee.paperId
  522. });
  523. const costTime = Date.now() - start;
  524. report(events.ExamStartGetPaperSuccess, {
  525. time: costTime,
  526. paperId: examinee.paperId,
  527. paperType: paperType
  528. });
  529. } catch (error: any) {
  530. // 请求失败的错误上报
  531. report(events.ExamStartGetPaperError, {
  532. error: error
  533. });
  534. throw error; // 继续抛出,让外层处理
  535. }
  536. // 第二步:处理和组装数据(单独 try-catch)
  537. try {
  538. paperData.value = res.data;
  539. paperData.value.questions = restoreQuestion(examinee.questions, res.data.questions);
  540. console.log('初始化数据', paperData.value.questions)
  541. setQuestionList(paperData.value.questions);
  542. setDuration(examinee.duration || 0);
  543. await nextTick();
  544. const targetQuestion = flatQuestionList.value.find(item => item.id === prevData.value.questionId);
  545. if (targetQuestion) {
  546. changeIndex(targetQuestion.index);
  547. } else {
  548. changeIndex(0);
  549. }
  550. setTimeout(() => {
  551. if (targetQuestion?.isSubQuestion) {
  552. setSubQuestionIndex(targetQuestion.subIndex || 0);
  553. }
  554. }, 50);
  555. await new Promise(resolve => setTimeout(resolve, 50));
  556. await nextTick();
  557. // 读取用户练习设置
  558. // setPracticeSettings(userStore.practiceSettings);
  559. isReady.value = true;
  560. console.log('试卷信息', res)
  561. if (!userStore.isExamGuideShow) {
  562. setTimeout(() => {
  563. uni.$ie.hideLoading();
  564. setTimeout(() => {
  565. showSwiperTip.value = true;
  566. }, 100);
  567. }, 300);
  568. } else {
  569. uni.$ie.hideLoading();
  570. if (!isReadOnly.value) {
  571. startTime();
  572. }
  573. }
  574. report(events.ExamStartCombineDataSuccess, {
  575. paperId: examinee.paperId,
  576. paperType: paperType
  577. });
  578. } catch (error: any) {
  579. // 数据处理失败的错误上报
  580. report(events.ExamStartCombineDataError, {
  581. error: error
  582. });
  583. throw error; // 继续抛出,让外层处理
  584. }
  585. }
  586. const handleSwiperTipNext = () => {
  587. showSwiperTip.value = false;
  588. guideShow.value = true;
  589. }
  590. const handleGuideClose = () => {
  591. userStore.isExamGuideShow = true;
  592. if (!isReadOnly.value) {
  593. startTime();
  594. }
  595. }
  596. const loadData = async () => {
  597. uni.$ie.showLoading();
  598. const { paperType } = prevData.value;
  599. try {
  600. if (paperType === EnumPaperType.PRACTICE || paperType === EnumPaperType.COURSE) {
  601. loadPracticeData();
  602. } else if (paperType === EnumPaperType.SIMULATED || paperType === EnumPaperType.TEST) {
  603. loadExamData();
  604. }
  605. } catch (error) {
  606. report(events.ExamStartInitError, { error });
  607. uni.$ie.showToast('加载失败,请稍后重试');
  608. setTimeout(() => {
  609. uni.$ie.hideLoading();
  610. transferBack();
  611. }, 1000);
  612. }
  613. };
  614. onLoad(() => {
  615. console.log(prevData.value)
  616. report(events.ExamStartEnter);
  617. loadData();
  618. uni.addInterceptor('navigateBack', {
  619. invoke: (e) => {
  620. if (confirmShowing.value) {
  621. return false;
  622. }
  623. if (confirmQuit.value) {
  624. return e;
  625. }
  626. handleLeftClick();
  627. return false;
  628. }
  629. })
  630. });
  631. onUnload(() => {
  632. uni.removeInterceptor('navigateBack');
  633. });
  634. </script>
  635. <style lang="scss" scoped></style>