Explorar o código

音频播放次数

Michael Wang %!s(int64=6) %!d(string=hai) anos
pai
achega
72347107af

+ 8 - 8
src/features/OnlineExam/Examing/BooleanQuestionView.vue

@@ -1,16 +1,16 @@
 <template>
   <div class="question-view">
-    <question-body :questionBody="question.body" :examQuestionId="examQuestion.id"></question-body>
+    <question-body :questionBody="question.body" :examQuestion="examQuestion"></question-body>
     <div class="ops">
-      <div class="stu-answer">{{studentAnswer}}</div>
+      <div class="stu-answer">{{studentAnswer === 'true' ? '正确' : '错误'}}</div>
       <div class="score">({{examQuestion.questionScore}}分)</div>
     </div>
-    <div @click="() => answerQuestion('正确')">
-      <input type="radio" name="question" value="正确" :checked="studentAnswer === '正确'" />
+    <div @click="() => answerQuestion('true')">
+      <input type="radio" name="question" value="true" :checked="studentAnswer === 'true'" />
       <span class="question-options">正确</span>
     </div>
-    <div @click="() => answerQuestion('错误')">
-      <input type="radio" name="question" value="错误" :checked="studentAnswer === '错误'" />
+    <div @click="() => answerQuestion('false')">
+      <input type="radio" name="question" value="false" :checked="studentAnswer === 'false'" />
       <span class="question-options">错误</span>
     </div>
     <div class="reset">
@@ -52,10 +52,10 @@ export default {
           ["checkbox", "radio"].includes(document.activeElement.type))
       ) {
         if ("KeyY" === e.code) {
-          this.answerQuestion("正确");
+          this.answerQuestion("true");
         }
         if ("KeyN" === e.code) {
-          this.answerQuestion("错误");
+          this.answerQuestion("false");
         }
       }
     },

+ 16 - 4
src/features/OnlineExam/Examing/ExamingHome.vue

@@ -116,10 +116,10 @@ export default {
       const exam = await this.$http.get(
         "/api/ecs_exam_work/exam/" + this.$route.params.examId
       );
-      const paperStruct = await this.$http.get(
+      const paperStruct = (await this.$http.get(
         "/api/ecs_oe_student/examRecordPaperStruct/getExamRecordPaperStruct?examRecordDataId=" +
           this.$route.params.examRecordDataId
-      );
+      )).data;
 
       let examQuestionList = (await this.$http.get(
         "/api/ecs_oe_student/examQuestion/findExamQuestionList"
@@ -138,10 +138,18 @@ export default {
         }
         return eq;
       });
+      examQuestionList = examQuestionList.map(eq => {
+        const paperStructQuestion = paperStruct.defaultPaper.questionGroupList[
+          eq.mainNumber - 1
+        ].questionWrapperList.find(q => q.questionId === eq.questionId);
+        return Object.assign(eq, {
+          limitedPlayTimes: paperStructQuestion.limitedPlayTimes
+        });
+      });
 
       this.updateExamState({
         exam: exam.data,
-        paperStruct: paperStruct.data,
+        paperStruct: paperStruct,
         examQuestionList: examQuestionList
       });
     },
@@ -162,7 +170,11 @@ export default {
     async answerAllQuestions() {
       // TODO: reset dirty
       const answers = this.examQuestionList.filter(eq => eq.dirty).map(eq => {
-        return { order: eq.order, studentAnswer: eq.studentAnswer };
+        return {
+          order: eq.order,
+          studentAnswer: eq.studentAnswer,
+          audioPlayTimes: eq.audioPlayTimes
+        };
       });
       await this.$http.post(
         "/api/ecs_oe_student/examQuestion/submitQuestionAnswer",

+ 1 - 1
src/features/OnlineExam/Examing/FillBlankQuestionView.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="question-view">
-    <question-body :questionBody="questionBody" :examQuestionId="examQuestion.id"></question-body>
+    <question-body :questionBody="questionBody" :examQuestion="examQuestion"></question-body>
     <div class="ops">
       <div class="score">({{examQuestion.questionScore}}分)</div>
     </div>

+ 1 - 1
src/features/OnlineExam/Examing/MultipleQuestionView.vue

@@ -1,6 +1,6 @@
 <template>
   <div v-if="examQuestion.questionType === 'MULTIPLE_CHOICE'" class="question-view">
-    <question-body :questionBody="question.body" :examQuestionId="examQuestion.id"></question-body>
+    <question-body :questionBody="question.body" :examQuestion="examQuestion"></question-body>
     <div class="ops">
       <div class="stu-answer"> {{oldIndexToABCD}}</div>
       <div class="score">({{examQuestion.questionScore}}分)</div>

+ 56 - 38
src/features/OnlineExam/Examing/QuestionBody.vue

@@ -1,11 +1,14 @@
 <template>
-  <div v-if="questionDetail" class="question-body" :key="examQuestionId">
+  <div v-if="questionDetail" class="question-body">
     <div v-html="questionDetail.text"></div>
     <div v-html="questionDetail.audio"></div>
   </div>
 </template>
 
 <script>
+import { createNamespacedHelpers } from "vuex";
+const { mapMutations } = createNamespacedHelpers("examingHomeModule");
+
 export default {
   name: "QuestionBody",
   data() {
@@ -13,68 +16,83 @@ export default {
   },
   props: {
     questionBody: String,
-    examQuestionId: String
+    examQuestion: Object
   },
   mounted() {
-    const audio = document.getElementsByTagName("audio")[0];
-
-    audio &&
-      audio.addEventListener("play", () => {
-        console.log("开始播放");
-
-        //FIXME: error
-        this.$http
-          .post("/api/exam_question_playtimes", {
-            questionId: this.examQuestionId
-            // mediaName: mediaName
-          })
-          .then(
-            function() {
-              console.log("保存播放次数成功");
-            },
-            function() {
-              console.log("保存播放次数失败");
-            }
-          );
-      });
-
     this.parseQuestion();
   },
   methods: {
+    ...mapMutations(["updateExamQuestion"]),
     async parseQuestion() {
       let question = {};
       if (this.questionBody.includes("question-audio")) {
-        const audioArray = this.questionBody.match(
-          /<a.*?question-audio.*?\/a>/g
-        );
+        let audioArray = this.questionBody.match(/<a.*?question-audio.*?\/a>/g);
+        if (!this.examQuestion.audioPlayTimes) {
+          // 初始化音频播放次数
+          this.examQuestion.audioPlayTimes = new Array(audioArray.length).fill(
+            0
+          );
+        }
         question.text = this.questionBody.replace(
           /<a.*?question-audio.*?\/a>/g,
           ""
         );
+        // 测试 v-html中含有directive是否生效。结论:不生效
+        // question.text += "<span v-html='<text>abc</text>'>empty</span>";
+        audioArray = audioArray.map((v, i) => {
+          const remainTimes =
+            this.examQuestion.limitedPlayTimes -
+            this.examQuestion.audioPlayTimes[i];
+          if (remainTimes <= 0) {
+            v = v.replace("<a", "<a disabled"); // disabled不生效,仅仅起标明作用
+            v = v.replace(/url=/g, "");
+          }
+          return `${v}<span>(剩余播放次数:${remainTimes})</span><br/>`;
+        });
         question.audio = audioArray
           .join("")
           .replace(/<a/g, "<audio controls controlsList='nodownload'")
           .replace(/url=/g, "src=")
           .replace(/a>/g, "audio>");
 
-        this.$http
-          .get("/api/exam_question_playtimes", {
-            params: {
-              questionId: this.examQuestionId
-            }
-          })
-          .then(res => {
-            //FIXME: audio playtimes
-            console.log(res.data);
-          });
+        setTimeout(this.bindAudioPlay, 1000);
       } else {
         question.text = this.questionBody;
         question.audio = "";
       }
       this.questionDetail = question;
+    },
+    bindAudioPlay() {
+      const audios = document.getElementsByTagName("audio");
+      if (audios.length === 0) {
+        setTimeout(this.bindAudioPlay, 1000);
+        return;
+      }
+
+      [...audios].forEach((audio, index) => {
+        audio.addEventListener("play", () => {
+          console.log("开始播放");
+          if (
+            this.examQuestion.limitedPlayTimes -
+              this.examQuestion.audioPlayTimes[index] <=
+            0
+          ) {
+            console.log("无剩余播放次数");
+          }
+        });
+        audio.addEventListener("ended", () => {
+          console.log("结束播放");
+          this.examQuestion.audioPlayTimes[index] =
+            this.examQuestion.audioPlayTimes[index] + 1;
+          this.updateExamQuestion({
+            order: this.examQuestion.order,
+            audioPlayTimes: this.examQuestion.audioPlayTimes
+          });
+          this.parseQuestion(); // 不会死循环,因为这个是音频播放触发的
+        });
+      });
     }
   },
-  computed: {},
   watch: {
     questionBody() {
       this.parseQuestion();

+ 2 - 2
src/features/OnlineExam/Examing/QuestionNavView.vue

@@ -46,8 +46,8 @@ export default {
         // questionGroupList [
         //   {
         //     questionWrapperList [
-        //       questionUnitWrapperList [
-        //         question
+        //       questionUnitWrapperList{questionId} [  // 套题只有一个questionId
+        //         questionUnit  // 套题这里为数组大于1。
         //       ]
         //     ]
         //   }

+ 1 - 1
src/features/OnlineExam/Examing/QuestionView.vue

@@ -4,7 +4,7 @@
       <Icon :type="examQuestion.isSign ? 'ios-star':'ios-star-outline'" :style="{color: '#ffcc00'}" class="star" @click="toggleSign" />
     </div>
     <div v-if="parentQuestionBody" class="question-view">
-      <question-body :questionBody="parentQuestionBody" :examQuestionId="examQuestion.id" style="margin-bottom: 20px" :key="examQuestion.order"></question-body>
+      <question-body :questionBody="parentQuestionBody" :examQuestion="examQuestion" style="margin-bottom: 20px" :key="examQuestion.order"></question-body>
       <div class="hr" />
     </div>
     <template v-if="question.questionType === 'SINGLE_CHOICE'">

+ 1 - 1
src/features/OnlineExam/Examing/SingleQuestionView.vue

@@ -1,6 +1,6 @@
 <template>
   <div v-if="examQuestion.questionType === 'SINGLE_CHOICE'" class="question-view">
-    <question-body :questionBody="questionBody" :examQuestionId="examQuestion.id"></question-body>
+    <question-body :questionBody="questionBody" :examQuestion="examQuestion"></question-body>
     <div class="ops">
       <div class="stu-answer">{{oldIndexToABCD}}</div>
       <div class="score">({{examQuestion.questionScore}}分)</div>

+ 1 - 1
src/features/OnlineExam/Examing/TextQuestionView.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="question-view">
-    <question-body :questionBody="question.body" :examQuestionId="examQuestion.id"></question-body>
+    <question-body :questionBody="question.body" :examQuestion="examQuestion"></question-body>
     <div class="ops">
       <div class="score">({{examQuestion.questionScore}}分)</div>
     </div>

+ 5 - 1
src/store.js

@@ -42,7 +42,10 @@ const examingHomeModule = {
     updateQuestionFilter(state, type) {
       state.questionFilterType = type;
     },
-    updateExamQuestion(state, { order, studentAnswer, isSign }) {
+    updateExamQuestion(
+      state,
+      { order, studentAnswer, isSign, audioPlayTimes }
+    ) {
       const examQuestionList = state.examQuestionList.map(eq => {
         // console.log(eq.order, order);
         if (eq.order == order) {
@@ -51,6 +54,7 @@ const examingHomeModule = {
             eq,
             { dirty: true },
             studentAnswer !== undefined && { studentAnswer },
+            audioPlayTimes !== undefined && { audioPlayTimes },
             isSign !== undefined && { isSign }
           );
         }