ChengYuXuan пре 5 година
родитељ
комит
e65fd99255

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

@@ -91,7 +91,7 @@ export interface ChoiceQuestionSerializer extends QuestionSerializer {
   studentId?: number
   single?: boolean
   options?: Array<OptionSerializer>
-  lastCommitAnswers?: ChoiceAnswer
+  lastCommitAnswer?: ChoiceAnswer
 }
 
 export interface CodeTuple {
@@ -102,7 +102,7 @@ export interface CodeTuple {
 export interface CodeQuestionSerializer extends QuestionSerializer {
   studentId?: number
   codeTuples?: Array<CodeTuple>
-  lastCommitCode?: string
+  lastCommitCode?: Array<CodeTuple>
 }
 
 export interface ExamQuestionSerializer {

+ 16 - 0
src/mock/serializers.js

@@ -49,6 +49,7 @@ const serializersPlugin = (mock) => ({
       'id|1-1000': 1,
       stem: '@CPARAGRAPH',
       single: true,
+      lastCommitAnswer: '',
       options: [
         {
           label: 'A',
@@ -73,6 +74,7 @@ const serializersPlugin = (mock) => ({
       'id|1-1000': 1,
       stem: '@CPARAGRAPH',
       single: false,
+      lastCommitAnswer: '',
       options: [
         {
           label: 'A',
@@ -109,6 +111,20 @@ const serializersPlugin = (mock) => ({
           lang: 'python',
           code: "if __name__ == '__main__':"
         }
+      ],
+      lastCommitCode: [
+        {
+          lang: 'cpp',
+          code: 'int main(){}'
+        },
+        {
+          lang: 'java',
+          code: 'public class Main{}'
+        },
+        {
+          lang: 'python',
+          code: "if __name__ == '__main__':"
+        }
       ]
     }),
   EXAM_QUESTION_SERIALIZER: () =>

+ 14 - 8
src/views/exam/ExamPane.vue

@@ -148,7 +148,7 @@
         <code-pane
           v-else
           v-on:nextQuestion="nextQuestion"
-          :question="curCode"
+          :question="curCodeQuestion"
           :total-question-num="curTypeQuestionNum"
         ></code-pane>
       </v-container>
@@ -221,10 +221,9 @@ export default Vue.extend({
     choiceQuestionNum(): number {
       return this.singleChoiceNum + this.multiChoiceNum
     },
-
     curChoice(): ChoiceQuestionSerializer {
       if (!this.isChoiceProblem) {
-        return null
+        return {} as ChoiceQuestionSerializer
       }
       if (this.isSingleChoice) {
         return this.singleChoiceQuestions[this.currentQuestionIndex]
@@ -234,13 +233,13 @@ export default Vue.extend({
         ]
       }
     },
-    curCode(): CodeQuestionSerializer {
+    curCodeQuestion(): CodeQuestionSerializer {
       if (!this.isChoiceProblem) {
         return this.codeQuestions[
           this.currentQuestionIndex - this.choiceQuestionNum
         ]
       }
-      return null
+      return {} as CodeQuestionSerializer
     }
   },
   watch: {
@@ -256,7 +255,10 @@ export default Vue.extend({
     }
   },
   methods: {
+    // 切换题目时,先保存答过的选择题的答案;提交代码后,保存提交的代码题答案
+    saveAnswer(answer: string, lang?: string) {},
     onSelectQuestion(index: number) {
+      // this.saveAnswer()
       this.currentQuestionIndex = index - 1
     },
     leaveExam() {
@@ -267,13 +269,17 @@ export default Vue.extend({
       this.submitDialog = false
       this.$router.back()
     },
-    nextQuestion(answer: String) {
-      // this.choiceAnswers.push(answer)
+    nextQuestion(answer: string) {
+      // this.saveAnswer(answer)
       this.currentQuestionIndex += 1
     },
+    prevQuestion(answer: string) {
+      // this.saveAnswer(answer)
+      this.currentQuestionIndex -= 1
+    },
     fetchData() {
       this.examId = parseInt(this.$route.params.id)
-      getExamById(this.endId).then(({ data }) => {
+      getExamById(this.examId).then(({ data }) => {
         this.endTime = Date.parse(data.res.endAt)
         console.log(this.endTime)
       })

+ 53 - 46
src/views/exam/components/ChoicePane.vue

@@ -14,51 +14,47 @@
       </div>
       <markdown-text :raw="question.stem" class="pa-10"></markdown-text>
       <v-list class="px-10 flex">
-        <v-list-item-group v-model="answer" multiple>
+        <v-list-item-group v-if="question.single" v-model="answer">
           <v-divider></v-divider>
-          <div v-if="question.single">
-            <template v-for="choice in choices">
-              <v-list-item :key="choice.label" :value="choice.content">
-                <template v-slot:default="{ active }">
-                  <v-list-item-action>
-                    <v-checkbox
-                      hide-details
-                      :input-value="active"
-                      on-icon="mdi-radiobox-marked"
-                      off-icon="mdi-radiobox-blank"
-                    >
-                    </v-checkbox>
-                  </v-list-item-action>
-                  <v-list-item-content>
-                    <v-list-item-title class="text-wrap"
-                      >{{ choice.label }}:
-                      {{ choice.content }}</v-list-item-title
-                    >
-                  </v-list-item-content>
-                </template>
-              </v-list-item>
-              <v-divider :key="choice.content"></v-divider>
-            </template>
-          </div>
-          <div v-else>
-            <template v-for="choice in choices">
-              <v-list-item :key="choice.label" :value="choice.label">
-                <template v-slot:default="{ active }">
-                  <v-list-item-action>
-                    <v-checkbox hide-details :input-value="active">
-                    </v-checkbox>
-                  </v-list-item-action>
-                  <v-list-item-content>
-                    <v-list-item-title class="text-wrap"
-                      >{{ choice.label }}:
-                      {{ choice.content }}</v-list-item-title
-                    >
-                  </v-list-item-content>
-                </template>
-              </v-list-item>
-              <v-divider :key="choice.content"></v-divider>
-            </template>
-          </div>
+          <template v-for="choice in choices">
+            <v-list-item :key="choice.label" :value="choice.label">
+              <template v-slot:default="{ active }">
+                <v-list-item-action>
+                  <v-checkbox
+                    hide-details
+                    :input-value="active"
+                    on-icon="mdi-radiobox-marked"
+                    off-icon="mdi-radiobox-blank"
+                  >
+                  </v-checkbox>
+                </v-list-item-action>
+                <v-list-item-content>
+                  <v-list-item-title class="text-wrap"
+                    >{{ choice.label }}: {{ choice.content }}</v-list-item-title
+                  >
+                </v-list-item-content>
+              </template>
+            </v-list-item>
+            <v-divider :key="choice.content"></v-divider>
+          </template>
+        </v-list-item-group>
+        <v-list-item-group v-else v-model="answer" multiple>
+          <v-divider></v-divider>
+          <template v-for="choice in choices">
+            <v-list-item :key="choice.label" :value="choice.label">
+              <template v-slot:default="{ active }">
+                <v-list-item-action>
+                  <v-checkbox hide-details :input-value="active"> </v-checkbox>
+                </v-list-item-action>
+                <v-list-item-content>
+                  <v-list-item-title class="text-wrap"
+                    >{{ choice.label }}: {{ choice.content }}</v-list-item-title
+                  >
+                </v-list-item-content>
+              </template>
+            </v-list-item>
+            <v-divider :key="choice.content"></v-divider>
+          </template>
         </v-list-item-group>
       </v-list>
       <div class="d-flex justify-space-between px-10 py-10">
@@ -98,12 +94,23 @@ export default Vue.extend({
   mounted() {
     this.choices = clone(this.question.options) ?? []
   },
+  // beforeUpdate() {
+  //   this.answer = []
+  // },
   methods: {
     nextQuestion() {
-      this.$emit('nextQuestion', this.answer.join(''))
+      if (this.question.single) {
+        this.$emit('nextQuestion', this.answer)
+      } else {
+        this.$emit('nextQuestion', this.answer.sort().join(''))
+      }
     },
     prevQuestion() {
-      this.$emit('prevQuestion')
+      if (this.question.single) {
+        this.$emit('prevQuestion', this.answer)
+      } else {
+        this.$emit('prevQuestion', this.answer.sort().join(''))
+      }
     }
   }
 })

+ 62 - 72
src/views/exam/components/CodePane.vue

@@ -9,8 +9,11 @@
           </v-tabs>
           <v-tabs-items v-model="tab">
             <v-tab-item>
-              <div class="overflow-y-auto" style="height: 80vh">
-                <markdown-text :raw="stem" style="height: 100%"></markdown-text>
+              <div class="overflow-y-auto" style="height: 80vh;max-width: 30vw">
+                <markdown-text
+                  :raw="question.stem"
+                  style="height: 100%"
+                ></markdown-text>
               </div>
             </v-tab-item>
             <v-tab-item class="pa-2">
@@ -79,9 +82,9 @@
         </div>
 
         <div style="height: 32px" class="d-flex justify-space-between">
-          <v-btn color="info" small>上一题</v-btn>
-          <span> 代码题 1/4</span>
-          <v-btn color="info" small>下一题</v-btn>
+          <v-btn color="info" small @click="prevQuestion">上一题</v-btn>
+          <span> 代码题 {{ question.id }} / {{ totalQuestionNum }}</span>
+          <v-btn color="info" small @click="nextQuestion">下一题</v-btn>
         </div>
       </div>
       <v-divider vertical class="mx-1"></v-divider>
@@ -141,54 +144,51 @@
             >保存测试</v-btn
           >
         </div>
-        <code-editor
-          :language="currentLang"
-          v-model="currentCode"
-        ></code-editor>
+        <code-editor :language="currentLang" v-model="curCode"></code-editor>
       </div>
     </div>
   </v-card>
 </template>
 
 <script lang="ts">
-import Vue from 'vue'
+import Vue, { PropType } from 'vue'
 import CodeEditor from '@/views/exam/components/CodeEditor.vue'
 import MarkdownText from '@/views/exam/components/MarkdownText.vue'
 import { clone } from 'ramda'
+import { CodeQuestionSerializer, CodeTuple } from '@/api/types'
 
 interface CommitInfo {
   id?: string
   submitTime?: string
   status?: string
   score?: number
-  codes?: CodeQuestionPair[]
+  codes?: CodeTuple[]
   msg?: string
 }
 
-interface CodeQuestionPair {
-  id?: string
-  stem?: string
-  originalCode?: LanguageCode[]
-  currentCode?: LanguageCode[]
-}
-
-interface LanguageCode {
-  type?: string
-  code?: string
-}
-
 export default Vue.extend({
   components: {
     CodeEditor,
     MarkdownText
   },
+  props: {
+    question: {
+      required: true,
+      type: Object as PropType<CodeQuestionSerializer>
+    },
+    totalQuestionNum: {
+      required: true,
+      type: Number
+    }
+  },
   data() {
     return {
-      content: '213123123',
       tab: null,
       commits: [] as CommitInfo[],
       languages: ['cpp', 'java', 'python'],
-      currentLang: 'java',
+      currentLang: '',
+      curCode: '',
+      codeAnswer: {} as CodeQuestionSerializer,
       currentCommit: (null as unknown) as CommitInfo,
       statusTags: [
         '所有用例通过',
@@ -197,11 +197,7 @@ export default Vue.extend({
         '运行超时',
         '等待运行'
       ],
-      statusColors: ['success', 'warning', 'error', 'accent', 'info'],
-      stem: '',
-      codeQuestions: [] as CodeQuestionPair[],
-      currentQuestion: {} as CodeQuestionPair,
-      currentCode: [] as CodeQuestionPair[]
+      statusColors: ['success', 'warning', 'error', 'accent', 'info']
     }
   },
   computed: {
@@ -219,11 +215,33 @@ export default Vue.extend({
     // }
   },
   watch: {
-    // currentLang() {
-    //   this.currentCode = this.codeByLanguage
-    // }
+    currentLang(val, oldVal) {
+      if (oldVal !== '' && val !== oldVal) {
+        const newCode = this.codeAnswer.codeTuples?.find((value) => {
+          return value.lang === val
+        }).code
+
+        const oldCodeIndex = this.codeAnswer.codeTuples.findIndex((value) => {
+          return value.lang === oldVal
+        })
+        this.codeAnswer.codeTuples[oldCodeIndex].code = this.curCode
+
+        this.curCode = newCode
+      }
+    }
   },
-  beforeMount() {
+  created() {
+    console.log(this.question)
+
+    this.languages = this.question.codeTuples?.map((value) => {
+      return value.lang
+    })
+    this.currentLang = this.languages[0]
+
+    this.curCode = this.question.codeTuples[0].code
+
+    this.codeAnswer = clone(this.question)
+
     for (let i = 0; i < 10; i++) {
       const r = Math.floor(Math.random() * 4 + 1)
       this.commits.push({
@@ -234,25 +252,11 @@ export default Vue.extend({
       })
     }
     this.currentCommit = this.getCurrentCommit()
-
-    this.fetchData()
   },
   methods: {
     submitCode(): void {
-      const r = Math.floor(Math.random() * 5)
-      const id = Math.floor(Math.random() * 1000).toString()
-      this.commits = [
-        {
-          id: id,
-          submitTime: '2020-12-11 20:03',
-          status: this.statusTags[r],
-          score: 100
-        },
-        ...this.commits
-      ]
-      this.currentCommit = this.getCurrentCommit()
-
       console.log(this.currentCode)
+      this.$emit('submitCode')
     },
     getCurrentCommit(): CommitInfo {
       return this.commits[0]
@@ -260,28 +264,7 @@ export default Vue.extend({
     statusToColor(status: string): string {
       return this.statusColors[this.statusTags.indexOf(status)]
     },
-    fetchData() {
-      const cpp = { type: 'cpp', code: 'int main(){}' } as LanguageCode
-      const java = { type: 'java', code: 'int a=0;' } as LanguageCode
-      const python = { type: 'python', code: 'print a' } as LanguageCode
-
-      this.currentQuestion = {
-        id: '123',
-        stem: 'description',
-        originalCode: [cpp, java, python],
-        currentCode: [cpp, java, python]
-      }
-      this.codeQuestions.push(this.currentQuestion)
-      this.codeQuestions.push({
-        id: '234',
-        stem: 'description',
-        originalCode: [cpp, java, python],
-        currentCode: [cpp, java, python]
-      })
-
-      // this.currentCode = this.codeByLanguage
-      console.log(this.currentCode)
-    },
+    fetchData() {},
     resetCode() {
       for (const codeQuestion of this.codeQuestions) {
         if (codeQuestion.id === this.currentQuestion.id) {
@@ -289,7 +272,14 @@ export default Vue.extend({
         }
         // 添加完成后的提示
       }
-    }
+    },
+    prevQuestion() {
+      this.$emit('prevQuestion')
+    },
+    nextQuestion() {
+      this.$emit('nextQuestion')
+    },
+    onLanguageChange() {}
   }
 })
 </script>

+ 23 - 0
src/views/teacher/components/QuestionList.vue

@@ -0,0 +1,23 @@
+<template>
+  <div></div>
+</template>
+
+<script lang="ts">
+import Vue, { PropType } from 'vue'
+import { ChoiceQuestionSerializer, Pageable } from '@/api/types'
+
+export default Vue.extend({
+  name: 'QuestionList',
+  props: {
+    questions: {
+      required: true,
+      type: Object as PropType<Pageable<ChoiceQuestionSerializer>>
+    }
+  },
+  data() {
+    return {}
+  }
+})
+</script>
+
+<style scoped></style>