Przeglądaj źródła

学生答题界面逻辑

ChengYuXuan 5 lat temu
rodzic
commit
8ae05bf2e5

+ 3 - 3
src/api/types.d.ts

@@ -94,14 +94,14 @@ export interface ChoiceQuestionSerializer extends QuestionSerializer {
   lastCommitAnswers?: ChoiceAnswer
 }
 
-export interface CodeTemplate {
+export interface CodeTuple {
   lang?: string
-  template?: string
+  code?: string
 }
 
 export interface CodeQuestionSerializer extends QuestionSerializer {
   studentId?: number
-  codeTemplates?: Array<CodeTemplate>
+  codeTuples?: Array<CodeTuple>
   lastCommitCode?: string
 }
 

+ 4 - 4
src/mock/serializers.js

@@ -96,18 +96,18 @@ const serializersPlugin = (mock) => ({
     mock({
       'id|1-1000': 1,
       stem: '@CPARAGRAPH',
-      codeTemplates: [
+      codeTuples: [
         {
           lang: 'cpp',
-          template: 'int main(){}'
+          code: 'int main(){}'
         },
         {
           lang: 'java',
-          template: 'public class Main{}'
+          code: 'public class Main{}'
         },
         {
           lang: 'python',
-          template: "if __name__ == '__main__':"
+          code: "if __name__ == '__main__':"
         }
       ]
     }),

+ 88 - 29
src/views/exam/ExamPane.vue

@@ -9,7 +9,7 @@
           <count-down
             class="align-self-center"
             :current-time="currentTime"
-            :end-time="`${currentTime + 10000}`"
+            :end-time="endTime"
           ></count-down>
         </v-col>
       </v-row>
@@ -35,11 +35,13 @@
               <h2>单选题</h2>
             </div>
             <v-btn
-              v-for="i in answeredChoices.slice(0, singleChoiceNum)"
+              v-for="i in answerStatus.slice(0, singleChoiceNum)"
               :key="i.index"
               class="ml-2 mt-2 pa-0 d-inline"
               x-small
               :disabled="i.answered"
+              :color="currentQuestionIndex + 1 === i.index ? 'secondary' : ''"
+              @click="onSelectQuestion(i.index)"
             >
               {{ i.index }}
             </v-btn>
@@ -49,14 +51,16 @@
               <h2>多选题</h2>
             </div>
             <v-btn
-              v-for="i in answeredChoices.slice(
+              v-for="i in answerStatus.slice(
                 singleChoiceNum,
-                singleChoiceNum + multiChoiceNum
+                choiceQuestionNum
               )"
               :key="i.index"
               class="ml-2 mt-2 pa-0 d-inline"
               x-small
               :disabled="i.answered"
+              :color="currentQuestionIndex + 1 === i.index ? 'secondary' : ''"
+              @click="onSelectQuestion(i.index)"
             >
               {{ i.index }}
             </v-btn>
@@ -66,11 +70,13 @@
               <h2>代码题</h2>
             </div>
             <v-btn
-              v-for="i in answeredCodes"
+              v-for="i in answerStatus.slice(choiceQuestionNum)"
               :key="i.index"
               class="ml-2 mt-2 pa-0 d-inline"
               x-small
               :disabled="i.answered"
+              :color="currentQuestionIndex + 1 === i.index ? 'secondary' : ''"
+              @click="onSelectQuestion(i.index)"
             >
               {{ i.index }}
             </v-btn>
@@ -132,18 +138,19 @@
       </div>
     </v-navigation-drawer>
     <v-main class="indigo lighten-5 pa-0">
-      <v-container fluid class="pa-2">
-        <code-pane
-          v-if="!isChoiceProblem"
-          v-on:nextQuestion="nextQuestion"
-          :question="curQuestion"
-        ></code-pane>
+      <v-container fluid class="pa-2" v-if="currentQuestionIndex >= 0">
         <choice-pane
           v-if="isChoiceProblem"
-          v-on:nextQuestion="nextQuestion(answer)"
-          :total-question-num="multiChoiceNum"
-          :question="curQuestion"
+          v-on:nextQuestion="nextQuestion"
+          :total-question-num="curTypeQuestionNum"
+          :question="curChoice"
         ></choice-pane>
+        <code-pane
+          v-else
+          v-on:nextQuestion="nextQuestion"
+          :question="curCode"
+          :total-question-num="curTypeQuestionNum"
+        ></code-pane>
       </v-container>
     </v-main>
   </div>
@@ -160,7 +167,7 @@ import {
   ExamQuestionSerializer,
   QuestionSerializer
 } from '@/api/types'
-import { getExamQuestions } from '@/api/exam'
+import { getExamById, getExamQuestions } from '@/api/exam'
 
 export default Vue.extend({
   name: 'ExamPane',
@@ -175,20 +182,27 @@ export default Vue.extend({
       submitDialog: false,
       submitted: false,
       currentTime: new Date().getTime(),
+      endTime: 0,
       choiceAnswers: [] as Array<{ num: number; answer: string }>, // TODO codeAnswers
       examId: 0,
-      examQuestionsObject: {} as ExamQuestionSerializer,
       singleChoiceQuestions: [] as Array<ChoiceQuestionSerializer>,
       multiChoiceQuestions: [] as Array<ChoiceQuestionSerializer>,
       codeQuestions: [] as Array<CodeQuestionSerializer>,
       allQuestions: [] as Array<QuestionSerializer>,
       answeredChoices: [] as Array<{ index: number; answered: boolean }>,
       answeredCodes: [] as Array<{ index: number; answered: boolean }>,
-
-      currentQuestionIndex: 0
+      answerStatus: [] as Array<{ index: number; answered: boolean }>,
+      currentQuestionIndex: -1
     }
   },
   computed: {
+    curTypeQuestionNum(): number {
+      return this.isChoiceProblem
+        ? this.isSingleChoice
+          ? this.singleChoiceNum
+          : this.multiChoiceNum
+        : this.codeQuestionNum
+    },
     isChoiceProblem(): boolean {
       return this.currentQuestionIndex < this.choiceQuestionNum
     },
@@ -207,8 +221,26 @@ export default Vue.extend({
     choiceQuestionNum(): number {
       return this.singleChoiceNum + this.multiChoiceNum
     },
-    curQuestion(): QuestionSerializer {
-      return this.allQuestions[this.currentQuestionIndex]
+
+    curChoice(): ChoiceQuestionSerializer {
+      if (!this.isChoiceProblem) {
+        return null
+      }
+      if (this.isSingleChoice) {
+        return this.singleChoiceQuestions[this.currentQuestionIndex]
+      } else {
+        return this.multiChoiceQuestions[
+          this.currentQuestionIndex - this.singleChoiceNum
+        ]
+      }
+    },
+    curCode(): CodeQuestionSerializer {
+      if (!this.isChoiceProblem) {
+        return this.codeQuestions[
+          this.currentQuestionIndex - this.choiceQuestionNum
+        ]
+      }
+      return null
     }
   },
   watch: {
@@ -224,6 +256,9 @@ export default Vue.extend({
     }
   },
   methods: {
+    onSelectQuestion(index: number) {
+      this.currentQuestionIndex = index - 1
+    },
     leaveExam() {
       this.exitDialog = false
       this.$router.back()
@@ -234,20 +269,35 @@ export default Vue.extend({
     },
     nextQuestion(answer: String) {
       // this.choiceAnswers.push(answer)
-      this.isChoiceProblem = !this.isChoiceProblem
       this.currentQuestionIndex += 1
     },
     fetchData() {
       this.examId = parseInt(this.$route.params.id)
-      console.log(this.examId)
+      getExamById(this.endId).then(({ data }) => {
+        this.endTime = Date.parse(data.res.endAt)
+        console.log(this.endTime)
+      })
+
       getExamQuestions(this.examId)
         .then(({ data }) => {
-          this.examQuestionsObject = data.res ?? {}
-          this.singleChoiceQuestions =
-            this.examQuestionsObject?.singleChoiceQuestions ?? []
-          this.multiChoiceQuestions =
-            this.examQuestionsObject?.multiChoiceQuestions ?? []
-          this.codeQuestions = this.examQuestionsObject?.codeQuestions ?? []
+          const examQuestionsObject: ExamQuestionSerializer = data.res
+
+          this.singleChoiceQuestions = examQuestionsObject.singleChoiceQuestions?.map(
+            (value, index) => {
+              return { ...value, id: index + 1 }
+            }
+          )
+          this.multiChoiceQuestions = examQuestionsObject.multiChoiceQuestions?.map(
+            (value, index) => {
+              return { ...value, id: index + 1 }
+            }
+          )
+          this.codeQuestions = examQuestionsObject.codeQuestions?.map(
+            (value, index) => {
+              return { ...value, id: index + 1 }
+            }
+          )
+
           this.allQuestions = [
             ...this.singleChoiceQuestions,
             ...this.multiChoiceQuestions,
@@ -257,8 +307,17 @@ export default Vue.extend({
             ...this.singleChoiceQuestions,
             ...this.multiChoiceQuestions
           ].map((value, index) => {
-            return { num: index + 1, answer: '' }
+            return { index: index + 1, answer: '' }
           })
+
+          this.answerStatus = this.allQuestions.map((value, index) => {
+            return {
+              index: index + 1,
+              answered: false
+            }
+          })
+
+          this.currentQuestionIndex = 0 // 表示数据初始化完成
         })
         .catch(() => {
           console.log('No data')

+ 0 - 1
src/views/exam/components/ChoicePane.vue

@@ -4,7 +4,6 @@
       class="questionCard d-flex flex-column justify-space-between"
       hover
       style="cursor: default"
-      v-if="question.single"
     >
       <div class="d-flex">
         <v-card-title v-if="question.single">单选题</v-card-title>

+ 2 - 2
src/views/teacher/components/TeacherExamInfoCard.vue

@@ -15,7 +15,7 @@
           color="secondary"
           class="mx-2"
           v-if="examInfo.status === 'AVAILABLE'"
-          @click="showExamDetail"
+          @click="onExtendTime"
           >延长时间</v-btn
         >
         <v-btn color="info" class="mx-2" v-if="examInfo.status === 'READY'"
@@ -74,7 +74,7 @@ export default Vue.extend({
     }
   },
   methods: {
-    onJoinExam() {},
+    onExtendTime() {},
     showExamDetail() {
       const examId = this.examInfo.id?.toString()
       if (examId !== undefined) {

+ 1 - 0
vue.config.js

@@ -2,6 +2,7 @@ const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin')
 
 module.exports = {
   transpileDependencies: ['vuetify'],
+  // productionSourceMap: false,
   devServer: {
     proxy: {
       '^/api': {