Quellcode durchsuchen

feat: 推荐多道题逻辑

ChenYangfan vor 6 Jahren
Ursprung
Commit
0eb731d0b0

+ 48 - 0
src/utils/quiz-timing.js

@@ -0,0 +1,48 @@
+// 做题时间判断逻辑
+import { isEmpty } from '@/utils/types'
+
+export function getHandleChoice ({ that = null }) {
+  const handleChoice = function ({ questionId }) {
+    if (this.questionPointer === -1) {
+      // 初始化条件
+      this.questionPointer = questionId
+      this.choiceDate = new Date().valueOf()
+      return
+    }
+
+    if (this.questionPointer === questionId) {
+      this.choiceDate = new Date().valueOf()
+      return
+    }
+
+    if (this.questionPointer !== questionId) {
+      this.pushRecord({ questionId: this.questionPointer, startAt: this.lastDate, endAt: this.choiceDate })
+      // 切换题目
+      this.questionPointer = questionId
+      this.lastDate = this.choiceDate
+      this.choiceDate = new Date().valueOf()
+    }
+  }
+  if (that) {
+    return handleChoice.bind(that)
+  } else {
+    return handleChoice
+  }
+}
+
+// 将记录推到record中,当record中已经存在这个id,则将时间差累加到结束时间上
+export function getPushRecord ({ that = null }) {
+  const pushRecord = function ({ questionId, startAt, endAt }) {
+    const record = this.records[questionId]
+    if (isEmpty(record)) {
+      this.records[questionId] = { startAt, endAt }
+    } else {
+      record.endAt = record.endAt + (endAt - startAt)
+    }
+  }
+  if (that) {
+    return pushRecord.bind(that)
+  } else {
+    return pushRecord
+  }
+}

+ 91 - 40
src/views/quiz/DoRecommendQuestion.vue

@@ -8,7 +8,7 @@
         :options="knowledgeTree ? knowledgeTree : null"
         placeholder="选择相关知识点"
       />
-      <c-button icon="search" theme="green" :left="12">搜索</c-button>
+      <c-button icon="search" theme="green" :left="12" @click="getQuestions">设置偏好搜索</c-button>
     </div>
     <div v-else class="mt-24">知识点加载中...</div>
     <div class="no-content-warning" v-if="questions === null">
@@ -16,29 +16,30 @@
     </div>
     <template v-else>
       <template v-for="(question, index) in questions">
-        <do-quiz-question-card @choice="handleChoice" :key="question.id" :question-prop="question"
+        <do-quiz-question-card @choice="handleChoice" :question-prop="question" :key="question.id"
                                :marked-prop="interactiveMap ? interactiveMap[question.id].marked : false"
                                :rate-prop="interactiveMap ? interactiveMap[question.id].rate : 0"
-                               :index="index"></do-quiz-question-card>
-        <div :key="'detail-' + question.id">
-          <p class="mb-8" v-if="question.knowledgeId.length">知识点:{{question.knowledgeId.map(_ =>
-            knowledgeNaming[_]).join(',')}}</p>
-          <p class="mb-8" v-if="question.keyPoints">关键字:{{question.keyPoints}}</p>
-          <p class="mb-8" v-if="question.tag">标签:{{question.tag.join(',')}}</p>
-        </div>
-        <show-transition :key="'transition-' + question.id">
-          <div v-if="submitted" class="answer">
-            <p class="mb-8">
-              答案:{{question.answer}}
-            </p>
-            <p>
-              解析:{{question.analysis}}
-            </p>
+                               :index="index">
+          <div class="detail">
+            <p class="mb-4" v-if="question.knowledgeId.length">知识点:{{question.knowledgeId.map(_ =>
+              knowledgeNaming[_]).join(',')}}</p>
+            <p class="mb-4" v-if="question.keyPoints">关键字:{{question.keyPoints}}</p>
+            <p class="mb-4" v-if="question.tag">标签:{{question.tag.join(',')}}</p>
           </div>
-        </show-transition>
+          <show-transition>
+            <div v-if="submitted" class="answer" :class="question.studentAnswer.answer === question.answer ? 'b-green' : 'b-red'">
+              <p class="mb-8">
+                答案:{{question.answer}}
+              </p>
+              <p>
+                解析:{{question.analysis}}
+              </p>
+            </div>
+          </show-transition>
+        </do-quiz-question-card>
       </template>
       <c-button class="mt-16" :icon="submitted ? 'arrow_forward' : 'check'" theme="green" standout
-                @click="handleSubmit">{{submitted ? '下一题' : '提交答案'}}
+                @click="handleSubmit">{{submitted ? '再来 5 题' : '提交答案'}}
       </c-button>
     </template>
   </div>
@@ -54,6 +55,7 @@ import { getKnowledgeNodes } from '@/server/knowledge'
 import { constructTree } from '@/utils/construct-tree'
 import CButton from '@/components/Basic/CButton'
 import ShowTransition from '@/animations/ShowTransition'
+import { getHandleChoice, getPushRecord } from '@/utils/quiz-timing'
 
 export default {
   components: { ShowTransition, CButton, Treeselect, DoQuizQuestionCard, BackTitle },
@@ -65,8 +67,12 @@ export default {
       interactiveMap: null,
       selectedKnowledgeIdList: [],
       submitted: false,
-      startAt: new Date(),
-      endAt: new Date()
+
+      // 做题起止时间相关,时间为了方便加减采用毫秒表示
+      lastDate: new Date().valueOf(),
+      choiceDate: 0,
+      questionPointer: -1,
+      records: {}
     }
   },
   mounted () {
@@ -85,7 +91,7 @@ export default {
     getQuestions () {
       this.questions = null
       this.interactiveMap = null
-      getRecommendationQuestions({ questionNum: 1 })
+      getRecommendationQuestions({ questionNum: 5, knowledgeId: this.selectedKnowledgeIdList })
         .then(res => {
           this.questions = res.map(question => ({
             ...question,
@@ -105,14 +111,36 @@ export default {
         })
         .catch(err => this.$setErrorMessage(err.response.data.msg))
     },
-    handleChoice () {
-      this.endAt = new Date()
-    },
+    handleChoice: getHandleChoice({ that: this }),
+    pushRecord: getPushRecord({ that: this }),
     handleSubmit () {
-      // ! 目前是每次只有一道题
-      //   如果需要多道题的话这里的开始结束时间做法
-      //   应该需要参考学生做题界面的处理
-      //   records 也应该做相应的更改
+      this.questionPointer !== -1 && this.pushRecord({
+        questionId: this.questionPointer,
+        startAt: this.lastDate,
+        endAt: this.choiceDate
+      })
+
+      const answers = {}
+      let uncompleted = false
+      this.questions.map(question => {
+        if (question.studentAnswer) {
+          answers[question.id] = question.studentAnswer.answer
+        } else {
+          this.$setErrorMessage('题目:"' + question.stem + '"尚未填写')
+          uncompleted = true
+        }
+      })
+      if (uncompleted) return
+
+      const records = {}
+      Object.keys(this.records).forEach(key => {
+        records[key] = {
+          answer: answers[key],
+          startAt: new Date(this.records[key].startAt),
+          endAt: new Date(this.records[key].endAt)
+        }
+      })
+
       if (this.submitted) {
         // 点击展示下一题
         this.getQuestions()
@@ -120,18 +148,16 @@ export default {
         this.submitted = false
       } else {
         // 点击上传答案,并显示解析
-        submitAnswerRecord({
-          records: {
-            [this.questions[0].id]: {
-              answer: this.questions[0].studentAnswer.answer,
-              startAt: this.startAt,
-              endAt: this.endAt
-            }
-          }
-        })
+        submitAnswerRecord({ records })
           .then(_ => {
             this.$setSuccessMessage('提交成功')
             this.submitted = true
+
+            // 显示正确与否
+            this.questions = [...this.questions.map(question => {
+              question.studentAnswer.correct = question.answer === question.studentAnswer.answer
+              return question
+            })]
           })
           .catch(err => this.$setErrorMessage(err.response.data.msg))
       }
@@ -141,19 +167,44 @@ export default {
 </script>
 
 <style lang="scss" scoped>
+@import "~@/style/theme.scss";
 .do-recommend-question {
   padding: 64px 24px;
   max-width: 800px;
   margin: 0 auto;
+  background-color: #fafafa;
+  box-shadow: 0 0 0 1000px #fafafa;
 }
 
 .do-quiz-question-card {
   border: none;
-  margin: 0 -16px;
+}
+
+.do-quiz-question-card:nth-child(2n) {
+  background-color: #f7f7f7;
+}
+
+.do-quiz-question-card:nth-child(2n + 1) {
+  background-color: #fff;
 }
 
 .answer {
   padding: 12px;
-  border: 1px solid #aabaca;
+  margin: 0 12px 12px 12px;
+}
+
+.b-red {
+  background-color: $theme-red-light;
+}
+
+.b-green {
+  background-color: $theme-green-light;
+}
+
+.detail {
+  color: #7a8a9a;
+  font-weight: normal;
+  font-size: 14px;
+  padding: 0 36px 16px 36px;
 }
 </style>

+ 3 - 31
src/views/quiz/StudentDoQuiz.vue

@@ -33,6 +33,7 @@ import { getInteractiveList, getQuestionsByQuiz } from '@/server/question'
 import momentFromNow from '@/utils/moment-from-now'
 import { isEmpty } from '@/utils/types'
 import DoQuizQuestionCard from '@/views/quiz/components/DoQuizQuestionCard'
+import { getHandleChoice, getPushRecord } from '@/utils/quiz-timing'
 
 /**
  * 起止时间算法见同级目录下的readme
@@ -146,37 +147,8 @@ export default {
         this.$router.go(-1)
       }).catch(err => { this.$setErrorMessage(err.response.data.msg) })
     },
-    // 做题时间判断逻辑
-    handleChoice ({ questionId }) {
-      if (this.questionPointer === -1) {
-        // 初始化条件
-        this.questionPointer = questionId
-        this.choiceDate = new Date().valueOf()
-        return
-      }
-
-      if (this.questionPointer === questionId) {
-        this.choiceDate = new Date().valueOf()
-        return
-      }
-
-      if (this.questionPointer !== questionId) {
-        this.pushRecord({ questionId: this.questionPointer, startAt: this.lastDate, endAt: this.choiceDate })
-        // 切换题目
-        this.questionPointer = questionId
-        this.lastDate = this.choiceDate
-        this.choiceDate = new Date().valueOf()
-      }
-    },
-    // 将记录推到record中,当record中已经存在这个id,则将时间差累加到结束时间上
-    pushRecord ({ questionId, startAt, endAt }) {
-      const record = this.records[questionId]
-      if (isEmpty(record)) {
-        this.records[questionId] = { startAt, endAt }
-      } else {
-        record.endAt = record.endAt + (endAt - startAt)
-      }
-    },
+    handleChoice: getHandleChoice({ that: this }),
+    pushRecord: getPushRecord({ that: this }),
     momentFromNow,
     isEmpty
   }

+ 1 - 0
src/views/quiz/components/DoQuizQuestionCard.vue

@@ -25,6 +25,7 @@
       </div>
     </div>
     <mark-action-bar :marked-prop="markedProp" :rate-prop="rateProp" :question-id="question.id"></mark-action-bar>
+    <slot></slot>
   </div>
 </template>