ExamEnd.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. <script setup lang="ts">
  2. import { onlineExamDataApi } from "@/api/onlinePractice";
  3. import { httpApp } from "@/plugins/axiosApp";
  4. import router from "@/router";
  5. import { useUnmounted } from "@/setups/useUnmouted";
  6. import { store } from "@/store/store";
  7. import { Store } from "@/types/student-client";
  8. import { onMounted, onUnmounted } from "vue";
  9. import { useRoute } from "vue-router";
  10. const route = useRoute();
  11. const examId = +route.params.examId;
  12. const examRecordDataId = +route.params.examRecordDataId;
  13. const { isUnmounted } = useUnmounted();
  14. let loading = $ref(true);
  15. let afterExamRemark = $ref("");
  16. let cheatingRemark = $ref("");
  17. let showObjectScore = $ref(false);
  18. let showCheatingRemark = $ref(false);
  19. let examResult: { isWarn: boolean; objectiveScore: number } | null = $ref(null);
  20. onMounted(async function () {
  21. _hmt.push(["_trackEvent", "考试结束页面", "进入页面"]);
  22. logger({ cnl: ["server"], pgn: "考试结束页面", act: "进入页面" });
  23. try {
  24. loading = true;
  25. if (!store.exam.examType) {
  26. const exam = (await onlineExamDataApi(examId)).data;
  27. store.exam.examType = exam.examType;
  28. if (exam.examType === "PRACTICE") {
  29. void router.replace(
  30. `/online-practice/exam/${examId}/detail?examRecordDataId=${examRecordDataId}&disableGoBack=true`
  31. );
  32. return;
  33. }
  34. }
  35. const resp = await httpApp.get(
  36. "/api/ecs_exam_work/exam/getExamPropertyFromCacheByStudentSession/" +
  37. examId +
  38. `/AFTER_EXAM_REMARK,IS_OBJ_SCORE_VIEW,SHOW_CHEATING_REMARK,CHEATING_REMARK`
  39. );
  40. afterExamRemark = resp.data.AFTER_EXAM_REMARK || "";
  41. cheatingRemark = resp.data.CHEATING_REMARK || "";
  42. showObjectScore = resp.data.IS_OBJ_SCORE_VIEW === "true";
  43. showCheatingRemark = resp.data.SHOW_CHEATING_REMARK === "true";
  44. loading = false;
  45. } catch (error) {
  46. logger({
  47. cnl: ["server"],
  48. pgn: "考试结束页面",
  49. act: "onmounted",
  50. dtl: "获取考试设置错误,请在待考列表查看成绩!",
  51. });
  52. $message.error("获取考试设置错误,请在待考列表查看成绩!");
  53. void router.push("/");
  54. return;
  55. }
  56. if (showObjectScore) {
  57. await getExamResult();
  58. }
  59. logger({ cnl: ["server"], pgn: "考试结束页面", act: "完成成绩显示" });
  60. });
  61. let examResultLoading = $ref(true);
  62. async function getExamResult() {
  63. try {
  64. const startTime = Date.now();
  65. for (let i = 0; i < 20; i++) {
  66. if (isUnmounted) {
  67. return;
  68. }
  69. examResult = (
  70. await httpApp.get(
  71. "/api/ecs_oe_student/examControl/getEndExamInfo?examRecordDataId=" +
  72. examRecordDataId,
  73. { "axios-retry": { retries: 10 }, noErrorMessage: true }
  74. )
  75. ).data;
  76. // examResult = { isWarn: true, objectiveScore: 0.0 };
  77. if (examResult) {
  78. break;
  79. }
  80. await new Promise((res) => setTimeout(res, 5 * 1000));
  81. }
  82. logger({
  83. cnl: ["server"],
  84. pgn: "考试结束页面",
  85. dtl: "等待时间: " + (Date.now() - startTime) / 1000,
  86. });
  87. } catch (error) {
  88. logger({
  89. cnl: ["server"],
  90. pgn: "考试结束页面",
  91. act: "getExamResult",
  92. dtl: "获取考试设置错误,请在待考列表查看成绩!",
  93. });
  94. $message.info("获取考试设置错误,请在待考列表查看成绩!");
  95. } finally {
  96. examResultLoading = false;
  97. }
  98. }
  99. const backTo = $computed(() => {
  100. const examType = store.exam.examType;
  101. if (examType === "PRACTICE") {
  102. return "/online-practice";
  103. } else if (examType === "ONLINE_HOMEWORK") {
  104. return "/online-homework";
  105. }
  106. return "/online-exam";
  107. });
  108. onUnmounted(() => {
  109. // 清除考试中间数据
  110. store.exam = {} as Store["exam"];
  111. });
  112. </script>
  113. <template>
  114. <div v-if="!loading" id="exam-end" class="container">
  115. <div class="instructions">
  116. <h1 class="tw-text-3xl tw-font-bold tw-text-center">考试已结束</h1>
  117. <div class="tw-flex tw-items-center">
  118. <img class="user-avatar" :src="store.user.photoPath" alt="无底照" />
  119. <div v-if="showObjectScore" class="tw-text-center tw-flex-1">
  120. <div v-if="examResultLoading" class="score-text">
  121. 考试结果计算中...
  122. </div>
  123. <div v-else>
  124. <div v-if="examResult">
  125. <div v-if="examResult.isWarn" class="qm-big-text score-text">
  126. 客观题得分: 成绩待审核
  127. </div>
  128. <div v-else class="score-text tw-flex tw-items-center">
  129. 客观题得分:
  130. <span style="color: red; font-size: 40px">{{
  131. examResult.objectiveScore
  132. }}</span>
  133. </div>
  134. </div>
  135. <div v-else class="qm-big-text score-text" style="font-size: 20px">
  136. 请稍后在待考列表中查看客观题得分。
  137. </div>
  138. </div>
  139. </div>
  140. </div>
  141. <div v-if="showObjectScore && showCheatingRemark" class="tw-flex-1">
  142. <div v-if="examResult?.isWarn">
  143. <div class="tw-text-xl">违纪提示:</div>
  144. <div style="text-align: left; padding-bottom: 20px">
  145. <p v-html="cheatingRemark"></p>
  146. </div>
  147. </div>
  148. </div>
  149. <div class="tw-text-xl">考后说明:</div>
  150. <div style="text-align: left; padding-bottom: 20px">
  151. <p v-html="afterExamRemark"></p>
  152. </div>
  153. <router-link
  154. class="qm-primary-button tw-inline-block tw-text-center tw-w-full"
  155. :to="backTo"
  156. ondragstart="return false;"
  157. >
  158. 返回主页
  159. </router-link>
  160. </div>
  161. </div>
  162. <div v-else>正在等待数据返回...</div>
  163. </template>
  164. <style scoped>
  165. .container {
  166. margin: 0 auto;
  167. width: 80vw;
  168. max-width: 800px;
  169. overflow: auto;
  170. }
  171. .instructions {
  172. padding: 40px 20px;
  173. }
  174. .instructions > h1,
  175. .instructions > div {
  176. padding-bottom: 30px;
  177. }
  178. .user-avatar {
  179. display: inline-block;
  180. width: 140px;
  181. height: 140px;
  182. object-fit: contain;
  183. }
  184. .score-text {
  185. font-size: 24px;
  186. }
  187. </style>
  188. <style>
  189. #exam-end img {
  190. max-width: 100%;
  191. height: auto !important;
  192. }
  193. </style>