Bladeren bron

对接答题的部分接口

yellowtaotao 4 jaren geleden
bovenliggende
commit
8f44e968fd

+ 18 - 0
src/api/modules/exam.js

@@ -0,0 +1,18 @@
+// TMC系统相关api
+export default {
+  basePath: process.env.VUE_APP_JTXT_URL,
+  apiList: {
+    // 查询考试列表信息
+    GET_JTXT_GET_EXAMS: "/exams",
+    // 查询某场考试的详细信息
+    GET_JTXT_GET_EXAMS_ONE_DETAIL: "/exams/{examId}",
+    // 开始考试
+    POST_JTXT_GET_EXAMS_START: "/exams/{examId}/start",
+    // 查询某场考试的试题信息
+    GET_JTXT_GET_EXAMS_ONE_QUESTIONS_LIST: "/questions/{questionId}",
+    // 查询某道题的答案
+    // GET_JTXT_GET_EXAMS_ONE_QUESTIONS_ANSWER: "",
+    // 结束考试
+    POST_JTXT_GET_EXAMS_END: "/exams/{examId}/end"
+  }
+};

+ 17 - 3
src/views/home/exam/page-exam-item-detail.vue

@@ -3,15 +3,15 @@
     <van-nav-bar title="考试详情" />
     <div class="exam-item-detial-div">
       <div class="exam-item-detial">
-        <div class="exam-item-detial-title">{{ examItemData.title }}</div>
+        <div class="exam-item-detial-title">{{ examItemData.name }}</div>
         <div class="exam-item-detial-txt">
-          考试时间:{{ examItemData.examTime }}
+          考试时间:{{ examItemData.startTime }}
         </div>
         <div class="exam-item-detial-txt">
           考试时长:{{ examItemData.examTimeMins }}
         </div>
         <div class="exam-item-detial-describe">
-          考试描述:{{ examItemData.examDescribe }}
+          考试描述:{{ examItemData.description }}
         </div>
       </div>
     </div>
@@ -56,6 +56,20 @@ export default {
     // 查询:当前考试的信息
     getExamItemDataFun() {
       this.examItemData = this.examItem;
+      // this.$store.commit("toggleLoading", true);
+      // this.$_http
+      //   .get(
+      //     this.$pathParams(this.$_API.GET_JTXT_GET_EXAMS_ONE_DETAIL, {
+      //       examId: this.examItem.id
+      //     })
+      //   )
+      //   .then(res => {
+      //     console.log(res);
+      //     this.$store.commit("toggleLoading", false);
+      //   })
+      //   .catch(() => {
+      //     this.$store.commit("toggleLoading", false);
+      //   });
     },
     // 操作:开始考试
     handleStartExamFun() {

+ 167 - 161
src/views/home/exam/page-exam-item-doing.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="page-exam-question-box">
+  <div v-if="isInited" class="page-exam-question-box">
     <van-nav-bar title="考试" />
     <!-- 倒计时 -->
     <div class="exam-question-countdown">
@@ -49,7 +49,7 @@
         </div>
         <!-- 描述 -->
         <div class="exam-question-describe">
-          {{ examQuestionList[answerIndex].describe }}
+          {{ examQuestionList[answerIndex].content }}
         </div>
         <!-- 答题列表 -->
         <!-- 单选题、多选题的选项区域 -->
@@ -61,7 +61,7 @@
           class="exam-question-options"
         >
           <div
-            v-for="(item, index) in examQuestionList[answerIndex].options"
+            v-for="(item, index) in examQuestionList[answerIndex].answers"
             :key="index"
             :class="{
               'exam-question-options-item': true,
@@ -98,6 +98,7 @@
             class="exam-question-button"
             type="primary"
             color="#FE6347"
+            :disabled="isOverAnswer"
             @click="handleSubmitFun"
             >交卷</van-button
           >
@@ -115,18 +116,34 @@ export default {
   components: {},
   data() {
     return {
+      userInfo: {
+        id: 0,
+        username: "string",
+        firstName: "string",
+        lastName: "string",
+        email: "string",
+        encodedPassword: "string",
+        userStatus: "suspended"
+      },
       questionType: {
-        singleChoice: 1, // 单选题
-        multipleChoice: 2, // 多选题
-        gapFilling: 3 // 填空题
+        singleChoice: "DanXuan", // 单选题
+        multipleChoice: "DuoXuan", // 多选题
+        gapFilling: "TianKong" // 填空题
       }, // 试题类型
-      startTimeSeconds: null, // 考试开始时间的信息
+      endTimeSeconds: null, // 考试开始时间的信息
       timeDiff: "00:00:00", // 距离考试结束的时间
       interval: null, // 计时器
       examQuestionList: [], // 试题列表
       answerIndex: null, // 当前试题的下标索引
       answerValue: [], // 当前试题的所答
-      inputValue: "" // 填空题时输入框的值
+      inputValue: "", // 填空题时输入框的值
+      isInited: false, // 是否已初始化完毕
+      answerTime: {
+        startTime: 0,
+        endTime: 0
+      }, // 答题的开始、结束时间
+
+      isOverAnswer: false // 是否已答完所有题目
     };
   },
   created() {
@@ -146,165 +163,93 @@ export default {
   methods: {
     // 初始化数据信息
     initDataFun() {
-      console.log("考试信息:", this.examItem);
-      // if (!this.examItem) {
-      //   return;
-      // }
-      this.getExamItemQuestionsListFun(); // 查询:当前考试的信息
-      this.getExamTimeFun(); // 获取:当前时间及考试限时
-      this.setIntervalFun(); // 设置:倒计时定时器
+      if (!this.examItem) {
+        Dialog({ message: "试题信息有误,请重新进入当前页面" });
+        return;
+      }
+      this.examStartFun(); // 方法:开始考试
     },
     // 查询:当前考试的信息
     getExamItemQuestionsListFun() {
-      // TODO...
-      let httpResultData = [
-        {
-          id: 1,
-          type: 1,
-          grade: 1,
-          options: ["选项一", "选项二", "选项三"],
-          result: ["选项一"],
-          describe: "这里是描述(选项一)"
-        },
-        {
-          id: 2,
-          type: 1,
-          grade: 2,
-          options: ["选项一", "选项二", "选项三", "选项四"],
-          result: ["选项一"],
-          describe: "这里是描述,这里是描述,这里是描述(选项一)"
-        },
-        {
-          id: 3,
-          type: 2,
-          grade: 3,
-          options: ["选项一", "选项二", "选项三", "选项四"],
-          result: ["选项一", "选项二"],
-          describe:
-            "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(选项一、选项二)"
-        },
-        {
-          id: 4,
-          type: 2,
-          grade: 3,
-          options: ["选项一", "选项二", "选项三", "选项四"],
-          result: ["选项一", "选项二", "选项三"],
-          describe:
-            "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(选项一、选项二、选项三)"
-        },
-        {
-          id: 5,
-          type: 3,
-          grade: 4,
-          options: [],
-          result: [1],
-          describe:
-            "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(1)"
-        },
-        {
-          id: 6,
-          type: 1,
-          grade: 1,
-          options: ["选项一", "选项二", "选项三"],
-          result: ["选项一"],
-          describe: "这里是描述(选项一)"
-        },
-        {
-          id: 7,
-          type: 1,
-          grade: 2,
-          options: ["选项一", "选项二", "选项三", "选项四"],
-          result: ["选项一"],
-          describe: "这里是描述,这里是描述,这里是描述(选项一)"
-        },
-        {
-          id: 8,
-          type: 2,
-          grade: 3,
-          options: ["选项一", "选项二", "选项三", "选项四"],
-          result: ["选项一", "选项二"],
-          describe:
-            "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(选项一、选项二)"
-        },
-        {
-          id: 9,
-          type: 2,
-          grade: 3,
-          options: ["选项一", "选项二", "选项三", "选项四"],
-          result: ["选项一", "选项二", "选项三"],
-          describe:
-            "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(选项一、选项二、选项三)"
-        },
-        {
-          id: 10,
-          type: 3,
-          grade: 4,
-          options: [],
-          result: [1],
-          describe:
-            "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(1)"
-        },
-        {
-          id: 11,
-          type: 1,
-          grade: 1,
-          options: ["选项一", "选项二", "选项三"],
-          result: ["选项一"],
-          describe: "这里是描述(选项一)"
-        },
-        {
-          id: 12,
-          type: 1,
-          grade: 2,
-          options: ["选项一", "选项二", "选项三", "选项四"],
-          result: ["选项一"],
-          describe: "这里是描述,这里是描述,这里是描述(选项一)"
-        },
-        {
-          id: 13,
-          type: 2,
-          grade: 3,
-          options: ["选项一", "选项二", "选项三", "选项四"],
-          result: ["选项一", "选项二"],
-          describe:
-            "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(选项一、选项二)"
-        },
-        {
-          id: 14,
-          type: 2,
-          grade: 3,
-          options: ["选项一", "选项二", "选项三", "选项四"],
-          result: ["选项一", "选项二", "选项三"],
-          describe:
-            "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(选项一、选项二、选项三)"
-        },
-        {
-          id: 15,
-          type: 3,
-          grade: 4,
-          options: [],
-          result: [1],
-          describe:
-            "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(1)"
-        }
-      ];
-      this.examQuestionList = this.setPersonDataFun(httpResultData);
-      this.handleExamQuestionItemFun(this.examQuestionList[0], 0); // 设置第一题开始
+      // let httpResultData = [
+      //   {
+      //     answerAnalysis: "", // 答案解析
+      //     id: 15,
+      //     type: 3,
+      //     grade: 4,
+      //     status: null, // 答题状态???
+      //     answers: [], // 选项
+      //     finalAnswer: [1], // 答案
+      //     content:
+      //       "这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述,这里是描述(1)"
+      //   }
+      // ];
+    },
+    // 方法:开始考试
+    examStartFun() {
+      this.$store.commit("toggleLoading", true);
+      this.$_http
+        .post(
+          this.$pathParams(this.$_API.POST_JTXT_GET_EXAMS_START, {
+            examId: this.examItem.id
+          }),
+          this.userInfo
+        )
+        .then(res => {
+          if (res.data) {
+            let httpResultData = [];
+            res.data.forEach((item, index) => {
+              this.getExamQuestionsListFun(
+                item,
+                httpResultData,
+                index === res.data.length - 1
+              );
+            });
+          }
+        })
+        .catch(() => {
+          this.$store.commit("toggleLoading", false);
+        });
+    },
+    // 查询:试题信息
+    async getExamQuestionsListFun(questionId, httpResultData, isLast) {
+      this.$_http
+        .get(
+          this.$pathParams(this.$_API.GET_JTXT_GET_EXAMS_ONE_QUESTIONS_LIST, {
+            questionId: questionId
+          })
+        )
+        .then(res => {
+          let resData = { ...res.data };
+          httpResultData.push(this.setPersonDataFun(resData));
+          if (isLast) {
+            this.examQuestionList = httpResultData;
+            this.handleExamQuestionItemFun(this.examQuestionList[0], 0); // 设置第一题开始
+            this.isInited = true;
+            this.getExamTimeFun(); // 获取:当前时间及考试限时
+            this.setIntervalFun(); // 设置:倒计时定时器
+            this.$store.commit("toggleLoading", false);
+          }
+        })
+        .catch(() => {
+          this.$store.commit("toggleLoading", false);
+        });
     },
     // 方法:过滤试题的类型,添加用户作答的字段
-    setPersonDataFun(httpResultData) {
-      httpResultData.forEach(item => {
-        item.typeTxt = this.formatQuestionType(item.type);
-        item.userAnswer = [];
-      });
-      return httpResultData;
+    setPersonDataFun(httpResultDataItme) {
+      httpResultDataItme.typeTxt = this.formatQuestionType(
+        httpResultDataItme.type
+      );
+      httpResultDataItme.userAnswer = [];
+      return httpResultDataItme;
     },
-    // 获取:当前时间及考试限时
+    // 获取:考试限定的时间点
     getExamTimeFun() {
       let tarTime = this.getTimeHoursMinuteSecondsFun(
         this.examItem.examTimeMins
       );
       let curTime = new Date();
+      this.answerTime.startTime = curTime; // 赋值开始时间
       // 在当前时间curTime变量上加上小时
       let addHour = curTime.setHours(curTime.getHours() + tarTime.hours);
       curTime = new Date(addHour);
@@ -318,7 +263,8 @@ export default {
         curTime.setSeconds(curTime.getSeconds() + tarTime.seconds)
       );
       curTime = new Date(addSeconds);
-      this.startTimeSeconds = curTime.getTime();
+      this.answerTime.endTime = curTime; // 赋值结束时间
+      this.endTimeSeconds = curTime.getTime(); // 赋值结束时间的秒数
     },
     // 方法:分别获取时 分 秒
     getTimeHoursMinuteSecondsFun(e) {
@@ -351,12 +297,12 @@ export default {
       // 获取距离目标时间的毫秒时间戳
       this.interval = setInterval(() => {
         let curTime = Date.now(); // 获取当前时间的毫秒时间戳
-        let diffTime = this.startTimeSeconds - curTime; // 计算出当前时间距离目标时间的时间差
+        let diffTime = this.endTimeSeconds - curTime; // 计算出当前时间距离目标时间的时间差
         // 判断倒计时是否完成,成立则清除定时器,关闭函数执行
         if (diffTime <= 0) {
           clearInterval(_self.interval);
           _self.timeDiff = "00:00:00";
-          this.handleSubmitFun(true); // 自动交卷
+          this.handleSubmitFun(); // 自动交卷
           return;
         }
         let hours = Math.floor(diffTime / (1000 * 60 * 60));
@@ -459,9 +405,11 @@ export default {
       this.examQuestionList[this.answerIndex].userAnswer = this.answerValue;
     },
     // 操作:交卷 isAuto:true(时间到了的自动交卷)  false(手动交卷)
-    handleSubmitFun(isAuto) {
+    handleSubmitFun() {
+      let isAuto = this.timeDiff === "00:00:00";
       if (isAuto) {
-        console.log("自动交卷");
+        Dialog({ message: "考试时间已到,该考试已结束" });
+        this.examsEndFun(isAuto);
       } else {
         Dialog.confirm({
           title: "温馨提示",
@@ -469,9 +417,67 @@ export default {
         })
           .then(() => {
             // TODO...
+            this.answerTime.endTime = new Date();
+            clearInterval(this.interval); // 销毁前清空计时器
+            this.$store.commit("toggleLoading", true);
+            this.examsEndFun(isAuto);
           })
           .catch(() => {});
       }
+    },
+    // 方法:结束考试
+    examsEndFun(isAuto) {
+      let allPoints = this.getUserExamAllPointsFun(); // 方法:计算成绩
+      let params = {
+        user: this.userInfo,
+        exam: {
+          id: this.examItem.id,
+          name: this.examItem.name,
+          description: this.examItem.description,
+          creator: this.userInfo,
+          duration: this.examItem.duration,
+          deadline: this.examItem.deadline,
+          startTime: this.examItem.startTime
+        },
+        points: allPoints, // 成绩:分数
+        startTime: this.answerTime.startTime,
+        endTime: this.answerTime.endTime
+      };
+      this.$_http
+        .post(
+          this.$pathParams(this.$_API.POST_JTXT_GET_EXAMS_END, {
+            examId: this.examItem.id
+          }),
+          params
+        )
+        .then(res => {
+          console.log("结束考试了", res);
+          this.$store.commit("toggleLoading", false);
+          if (!isAuto) {
+            Dialog("提交试卷成功,总分为:" + allPoints);
+          }
+        })
+        .catch(() => {
+          this.$store.commit("toggleLoading", false);
+        });
+    },
+    // 方法:计算成绩
+    getUserExamAllPointsFun() {
+      let allPoints = 0;
+      this.examQuestionList.forEach((item, index) => {
+        let sureNum = 0;
+        item.finalAnswer.forEach(it => {
+          item.userAnswer.forEach(answerItem => {
+            if (it === answerItem) {
+              sureNum++;
+            }
+          });
+        });
+        if (sureNum === item.finalAnswer.length) {
+          allPoints++;
+        }
+      });
+      return allPoints;
     }
   }
 };

+ 42 - 47
src/views/home/exam/page-exam.vue

@@ -7,13 +7,13 @@
         :key="index"
         @click="handleClickExamItemFun(item)"
       >
-        <div class="exam-item-title">{{ item.title }}</div>
-        <div class="exam-item-describe">考试时间:{{ item.examTime }}</div>
+        <div class="exam-item-name">{{ item.name }}</div>
+        <div class="exam-item-describe">考试时间:{{ item.startTime }}</div>
         <div class="exam-item-describe">
           考试时长:{{ item.examTimeMinsTxt }}
         </div>
         <div class="exam-item-describe">
-          考试描述:<span>{{ item.examDescribe }}</span>
+          考试描述:<span>{{ item.description }}</span>
         </div>
       </div>
     </div>
@@ -36,49 +36,44 @@ export default {
   methods: {
     // 查询:考试场次的列表信息
     getExamListFun() {
-      this.examList = [
-        {
-          id: 1,
-          title: "测试考试-fto",
-          examTime: "",
-          examTimeMins: "05:53:20",
-          examTimeMinsTxt: "05小时53分钟20秒",
-          examDescribe: "可以回家做"
-        },
-        {
-          id: 2,
-          title: "测试考试-xWs",
-          examTime: "",
-          examTimeMins: "17:31:40",
-          examTimeMinsTxt: "17小时31分钟40秒",
-          examDescribe:
-            "可以回家做,可以回家做,可以回家做,可以回家做,可以回家做,可以回家做,可以回家做,可以回家做"
-        },
-        {
-          id: 3,
-          title: "测试考试-vkx",
-          examTime: "",
-          examTimeMins: "12:35:00",
-          examTimeMinsTxt: "12小时35分钟00秒",
-          examDescribe: "可以回家做"
-        },
-        {
-          id: 4,
-          title: "测试考试-bMs",
-          examTime: "",
-          examTimeMins: "10:30:00",
-          examTimeMinsTxt: "10小时30分钟00秒",
-          examDescribe: "可以回家做"
-        },
-        {
-          id: 5,
-          title: "测试考试-yTb",
-          examTime: "",
-          examTimeMins: "02:00:00",
-          examTimeMinsTxt: "02小时00分钟00秒",
-          examDescribe: "可以回家做"
-        }
-      ];
+      this.$store.commit("toggleLoading", true);
+      this.$_http
+        .get(this.$pathParams(this.$_API.GET_JTXT_GET_EXAMS, {}))
+        .then(res => {
+          if (res.data) {
+            res.data.forEach(item => {
+              let formateTimeDiff = this.formateTimeDiffFun(item.duration);
+              item.examTimeMins = formateTimeDiff.examTimeMins;
+              item.examTimeMinsTxt = formateTimeDiff.examTimeMinsTxt;
+            });
+            this.examList = res.data;
+          }
+          this.$store.commit("toggleLoading", false);
+        })
+        .catch(() => {
+          this.$store.commit("toggleLoading", false);
+        });
+    },
+    // 过滤秒为 时:分:秒 及 xx小时xx分钟xx秒
+    formateTimeDiffFun(secondes) {
+      let hours = Math.floor(secondes / (1000 * 60 * 60));
+      let minutes = Math.floor(
+        (secondes - hours * 60 * 60 * 1000) / (1000 * 60)
+      );
+      let seconds = Math.floor(
+        (secondes - hours * 60 * 60 * 1000 - minutes * 60 * 1000) / 1000
+      );
+      let timeDiff = zero(hours) + ":" + zero(minutes) + ":" + zero(seconds);
+      let timeDiffTxt =
+        zero(hours) + "小时" + zero(minutes) + "分钟" + zero(seconds) + "秒";
+      // 数字补零
+      function zero(num) {
+        return num < 10 ? "0" + num : num;
+      }
+      return {
+        examTimeMins: timeDiff,
+        examTimeMinsTxt: timeDiffTxt
+      };
     },
     // 操作:点击了某个考试
     handleClickExamItemFun(item) {
@@ -107,7 +102,7 @@ export default {
       background-color: #fff;
       border-radius: 4px;
       box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
-      .exam-item-title {
+      .exam-item-name {
         height: 2rem;
         border-bottom: 1px solid #e4e8eb;
         line-height: 2rem;