ExamingHome.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. <template>
  2. <div v-if="exam && examQuestion()" class="container">
  3. <div class="header">
  4. <RemainTime></RemainTime>
  5. <OverallProgress :exam-question-list="examQuestionList"></OverallProgress>
  6. <QuestionFilters :exam-question-list="examQuestionList"></QuestionFilters>
  7. <Button class="qm-primary-button" @click="submitPaper">交卷</Button>
  8. </div>
  9. <div class="main">
  10. <QuestionView :exam-question="examQuestion()"></QuestionView>
  11. <ArrowNavView :previousQuestionOrder="previousQuestionOrder" :nextQuestionOrder="nextQuestionOrder"></ArrowNavView>
  12. </div>
  13. <div class="side">
  14. <div class="question-nav">
  15. <QuestionNavView :paperStruct="paperStruct" />
  16. </div>
  17. <div class="camera">
  18. <!-- <FaceRecognition width="100%" height="100%" :showRecognizeButton="false" /> -->
  19. </div>
  20. </div>
  21. </div>
  22. </template>
  23. <script>
  24. import RemainTime from "./RemainTime.vue";
  25. import OverallProgress from "./OverallProgress.vue";
  26. import QuestionFilters from "./QuestionFilters.vue";
  27. import QuestionView from "./QuestionView.vue";
  28. import ArrowNavView from "./ArrowNavView.vue";
  29. import QuestionNavView from "./QuestionNavView.vue";
  30. import FaceRecognition from "../../../components/FaceRecognition/FaceRecognition";
  31. import { createNamespacedHelpers } from "vuex";
  32. const { mapState, mapMutations } = createNamespacedHelpers("examingHomeModule");
  33. export default {
  34. name: "ExamingHome",
  35. created() {
  36. this.initData();
  37. if (!this.$route.params.order) {
  38. // created can access this.$route?
  39. this.$router.push(this.$route.fullPath + "/order/1");
  40. return;
  41. }
  42. setTimeout(() => {
  43. this.toggleSnapNow();
  44. }, 60 * 1000); // 一分钟后抓拍
  45. this.$http
  46. .get(
  47. "/api/ecs_exam_work/exam/examOrgProperty/" +
  48. this.$route.params.examId +
  49. `/SNAPSHOT_INTERVAL`
  50. )
  51. .then(res => {
  52. // console.log(res);
  53. if (res.data) {
  54. // 考务设置抓拍间隔
  55. setInterval(() => {
  56. this.toggleSnapNow();
  57. }, res.data * 60 * 1000);
  58. }
  59. })
  60. .catch(reason => {
  61. this.$Message.error(reason);
  62. });
  63. },
  64. // beforeRouteUpdate(to, from, next) {
  65. // this.updateQuestion(next);
  66. // },
  67. methods: {
  68. ...mapMutations(["updateExamState", "toggleSnapNow"]),
  69. async initData() {
  70. const exam = await this.$http.get(
  71. "/api/ecs_exam_work/exam/" + this.$route.params.examId
  72. );
  73. const paperStruct = await this.$http.get(
  74. "/api/ecs_oe_student/examRecordPaperStruct/getExamRecordPaperStruct?examRecordDataId=" +
  75. this.$route.params.examRecordDataId
  76. );
  77. const examQuestionList = await this.$http.get(
  78. "/api/ecs_oe_student/examQuestion/findExamQuestionList"
  79. );
  80. this.updateExamState({
  81. exam: exam.data,
  82. paperStruct: paperStruct.data,
  83. examQuestionList: examQuestionList.data
  84. });
  85. },
  86. updateQuestion: async function(next) {
  87. // 初始化套题的答案,为回填部分选项做准备
  88. // for (let q of this.examQuestionList) {
  89. // if (q.subQuestionList.length > 0) {
  90. // q.studentAnswer = [];
  91. // for (let sq of q.subQuestionList) {
  92. // q.studentAnswer.push(sq.studentAnswer);
  93. // }
  94. // }
  95. // }
  96. next && next();
  97. if (!this.exam) return;
  98. },
  99. async submitPaper() {
  100. //FIXME: submit precondition
  101. const answered = this.examQuestionList.filter(
  102. q => q.studentAnswer !== null
  103. ).length;
  104. const unanswered = this.examQuestionList.filter(
  105. q => q.studentAnswer === null
  106. ).length;
  107. this.$Modal.confirm({
  108. title: "确认交卷",
  109. content: `<p>已答题目:${answered}</p><p>未答题目:${unanswered}</p>`,
  110. onOk: this.realSubmitPaper
  111. });
  112. },
  113. async realSubmitPaper() {
  114. this.toggleSnapNow();
  115. await this.$http.get("/api/ecs_oe_student/examControl/endExam");
  116. this.$router.push({
  117. path: `/online-exam/exam/${this.$route.params.examId}/examRecordData/${
  118. this.$route.params.examRecordDataId
  119. }/end`
  120. });
  121. },
  122. examQuestion() {
  123. return (
  124. this.examQuestionList &&
  125. this.examQuestionList.find(
  126. eq => eq.order == this.$route.params.order // number == string
  127. )
  128. );
  129. }
  130. },
  131. computed: {
  132. ...mapState([
  133. "exam",
  134. "paperStruct",
  135. "examQuestionList",
  136. "snapNow",
  137. "shouldSubmitPaper"
  138. ]),
  139. previousQuestionOrder: vm => {
  140. if (vm.examQuestion().order > 1) {
  141. return vm.examQuestion().order - 1;
  142. } else {
  143. return null;
  144. }
  145. },
  146. nextQuestionOrder: vm => {
  147. if (vm.examQuestion().order < vm.examQuestionList.length) {
  148. return vm.examQuestion().order + 1;
  149. } else {
  150. return null;
  151. }
  152. }
  153. },
  154. watch: {
  155. $route: function() {
  156. this.examQuestion();
  157. },
  158. shouldSubmitPaper() {
  159. this.realSubmitPaper();
  160. }
  161. // examQuestionList(val, oldVal) {
  162. // // console.log(val, oldVal);
  163. // }
  164. },
  165. components: {
  166. RemainTime,
  167. OverallProgress,
  168. QuestionFilters,
  169. QuestionView,
  170. ArrowNavView,
  171. QuestionNavView,
  172. FaceRecognition
  173. }
  174. };
  175. </script>
  176. <style scoped>
  177. .container {
  178. display: grid;
  179. grid-template-areas:
  180. "header header"
  181. "main side";
  182. grid-template-rows: 80px 1fr;
  183. grid-template-columns: 1fr 400px;
  184. height: 100vh;
  185. width: 100vw;
  186. }
  187. .header {
  188. display: grid;
  189. place-items: center;
  190. grid-template-columns: 200px 1fr 300px 100px;
  191. grid-area: header;
  192. height: 80px;
  193. background-color: #f5f5f5;
  194. }
  195. .main {
  196. display: grid;
  197. grid-area: main;
  198. grid-template-rows: 1fr 50px;
  199. }
  200. .side {
  201. display: grid;
  202. grid-area: side;
  203. grid-template-rows: 1fr 300px;
  204. background-color: #f5f5f5;
  205. }
  206. .camera {
  207. align-self: flex-end;
  208. justify-self: flex-end;
  209. }
  210. @media screen and (max-height: 768px) {
  211. .container {
  212. grid-template-rows: 50px 1fr;
  213. }
  214. .header {
  215. height: 50px;
  216. }
  217. .side {
  218. grid-template-rows: 1fr 200px;
  219. }
  220. }
  221. </style>