Prechádzať zdrojové kódy

代码题提交记录界面

ChengYuXuan 5 rokov pred
rodič
commit
f25afb4efa

+ 1 - 1
src/mock/api/judge/code/post.json

@@ -1,5 +1,5 @@
 {
   "code": "00000",
-  "result": "TODO",
+  "result": "@CODE_JUDGE_RESULT_SERIALIZER",
   "msg": ""
 }

+ 1 - 1
src/mock/api/record/get.json

@@ -1,5 +1,5 @@
 {
-  "result": ["@EXAM_QUESTION_SUBMIT_RECORD"],
+  "result|5": ["@EXAM_QUESTION_SUBMIT_RECORD"],
   "code": "00000",
   "msg": ""
 }

+ 36 - 15
src/mock/serializers.js

@@ -6,7 +6,7 @@ const basicExtendsTypes = () => ({
   START_TIME: () =>
     randomArrayValue(['2021-02-01 00:00:00', '2021-03-01 00:00:00']),
   // START_TIME: () => randomArrayValue(['2021-02-01 00:00:00']),
-  END_TIME: () => randomArrayValue(['2021-04-01 00:00:00']),
+  END_TIME: () => randomArrayValue(['2021-06-01 00:00:00']),
   BUILD_STATUS: (status) =>
     status ||
     randomArrayValue([
@@ -24,7 +24,15 @@ const basicExtendsTypes = () => ({
     examStatus || randomArrayValue(['READY', 'AVAILABLE', 'FINISHED']),
   OBJECTIVE_QUESTION_TYPE: () =>
     // randomArrayValue(['choice', 'multi_choice', 'blank', 'code']) TODO code
-    randomArrayValue(['choice', 'multi_choice', 'blank'])
+    randomArrayValue(['choice', 'multi_choice', 'blank']),
+  CODE_RESULT_STATUS: () =>
+    randomArrayValue([
+      'Accepted',
+      'Wrong Answer',
+      'Compile Error',
+      'Time Limit Exceeded',
+      'Memory Limit Exceeded'
+    ])
 })
 
 const serializersPlugin = (mock) => ({
@@ -156,18 +164,18 @@ const serializersPlugin = (mock) => ({
       '19030': 2,
       '19031': 3,
       '19032': 4,
-      '19033': 3,
-      '19034': 2,
-      '19035': 2,
-      '19036': 3,
-      '19037': 4,
-      '19038': 3,
-      '19039': 2,
-      '19040': 2,
-      '19041': 3,
-      '19043': 4,
-      '19045': 3,
-      '19047': 2
+      '19033': 3
+      // '19034': 2,
+      // '19035': 2,
+      // '19036': 3,
+      // '19037': 4,
+      // '19038': 3,
+      // '19039': 2,
+      // '19040': 2,
+      // '19041': 3,
+      // '19043': 4,
+      // '19045': 3,
+      // '19047': 2
     }
   },
   QUESTION_STEM_SERIALIZER: () =>
@@ -209,7 +217,20 @@ const serializersPlugin = (mock) => ({
       'id|1-1000': 1,
       'questionId|1-1000': 1,
       'actualScore|1-10': 1,
-      submitAnswer: '@character("ABCD")'
+      submitAnswer: '@character("ABCD")',
+      submitTime: '@DATETIME',
+      message: '@CODE_RESULT_STATUS'
+    }),
+  CODE_JUDGE_RESULT_SERIALIZER: () =>
+    mock({
+      message: '@WORD',
+      'result_list|5': ['@CODE_JUDGE_RESULT']
+    }),
+  CODE_JUDGE_RESULT: () =>
+    mock({
+      result: '@CODE_RESULT_STATUS',
+      'timeused|1-1000': 1,
+      'memoryused|1-1000': 1
     })
 })
 

+ 121 - 50
src/views/exam/components/CodePane.vue

@@ -5,12 +5,13 @@
         <div>
           <v-tabs v-model="tab" class="pa-0 ma-0 elevation-1" grow>
             <v-tab>题目描述</v-tab>
+            <v-tab>运行结果</v-tab>
             <v-tab>提交记录</v-tab>
           </v-tabs>
           <v-tabs-items v-model="tab">
             <v-tab-item>
               <div
-                class="overflow-y-auto px-2"
+                class="overflow-y-auto pa-2"
                 style="height: 85vh;max-width: 30vw"
               >
                 <markdown-text
@@ -49,6 +50,66 @@
                 </v-simple-table>
               </div>
             </v-tab-item>
+            <v-tab-item>
+              <div class="d-flex flex-column justify-space-between pa-2">
+                <v-simple-table
+                  fixed-header
+                  class="overflow-y-auto"
+                  style="height: 84vh"
+                >
+                  <thead>
+                    <tr>
+                      <th>提交时间</th>
+                      <th>提交结果</th>
+                      <th>代码详情</th>
+                    </tr>
+                  </thead>
+                  <tbody>
+                    <tr v-for="item in submitRecords" :key="item.id">
+                      <td>
+                        {{ diffTime(item.submitTime) }}
+                      </td>
+                      <td>
+                        <v-chip
+                          :color="statusToColor(item.message)"
+                          small
+                          outlined
+                        >
+                          {{ item.message }}
+                        </v-chip>
+                      </td>
+                      <td>
+                        <v-btn
+                          class="mr-2"
+                          small
+                          outlined
+                          @click="onShowCode(item.submitAnswer)"
+                          >详情</v-btn
+                        >
+                        <v-tooltip top>
+                          <template v-slot:activator="{ on, attrs }">
+                            <v-btn
+                              id="rollbackBtn"
+                              class="elevation-0"
+                              rounded
+                              fab
+                              x-small
+                              outlined
+                              @click="onOpenRollbackDialog(item.submitAnswer)"
+                              v-bind="attrs"
+                              v-on="on"
+                            >
+                              <v-icon>mdi-refresh</v-icon>
+                            </v-btn>
+                          </template>
+                          <span>恢复到至该次提交的代码</span>
+                        </v-tooltip>
+                      </td>
+                    </tr>
+                  </tbody>
+                </v-simple-table>
+              </div>
+            </v-tab-item>
           </v-tabs-items>
         </div>
         <div style="height: 32px" class="d-flex justify-space-between px-2">
@@ -78,38 +139,6 @@
               >
               </v-select>
             </div>
-            <v-tooltip top>
-              <template v-slot:activator="{ on, attrs }">
-                <v-btn
-                  fab
-                  x-small
-                  tile
-                  class="mx-2 mb-2 pa-0 elevation-1 align-self-center"
-                  v-bind="attrs"
-                  v-on="on"
-                  @click="resetLastCommit"
-                >
-                  <v-icon>mdi-arrow-left</v-icon>
-                </v-btn>
-              </template>
-              <span>恢复到上次提交的代码</span>
-            </v-tooltip>
-            <v-tooltip top>
-              <template v-slot:activator="{ on, attrs }">
-                <v-btn
-                  fab
-                  x-small
-                  tile
-                  class="mx-2 mb-2 pa-0 elevation-1 align-self-center"
-                  v-bind="attrs"
-                  v-on="on"
-                  @click="resetOriginCode"
-                >
-                  <v-icon>mdi-refresh</v-icon>
-                </v-btn>
-              </template>
-              <span>重置代码至初始状态</span>
-            </v-tooltip>
           </div>
           <v-btn
             color="primary"
@@ -117,6 +146,7 @@
             v-on:click="submitCode"
             :disabled="running"
             :loading="running"
+            outlined
             >保存测试</v-btn
           >
         </div>
@@ -129,6 +159,29 @@
     <v-snackbar v-model="error" top color="warning" absolute
       >提交失败</v-snackbar
     >
+    <v-dialog v-if="showCode" v-model="showCode" max-width="800">
+      <v-card class="pt-3">
+        <v-card-title>代码详情</v-card-title>
+        <markdown-text :raw="codeDetailContent" class="mx-5"></markdown-text>
+      </v-card>
+    </v-dialog>
+    <v-dialog max-width="300" v-model="rollbackCodeDialog">
+      <v-card>
+        <v-card-title>确认恢复代码</v-card-title>
+        <v-card-actions class="justify-end">
+          <v-btn outlined color="success darken-1" @click="onRollback">
+            确定
+          </v-btn>
+          <v-btn
+            outlined
+            color="error darken-1"
+            @click="rollbackCodeDialog = false"
+          >
+            取消
+          </v-btn>
+        </v-card-actions>
+      </v-card>
+    </v-dialog>
   </v-card>
 </template>
 
@@ -142,10 +195,12 @@ import {
   CodeSubmitSerializer,
   CodeTuple,
   ExamQuestionSubmitRecord,
-  ID
+  ID,
+  LocalDateTime
 } from '@/api/types'
 import { codeJudge } from '@/api/judge'
 import { getExamQuestionSubmitRecord } from '@/api/record'
+import dayjs from 'dayjs'
 
 interface CodeJudgeInfo extends CodeJudgeResult {
   id: ID
@@ -190,7 +245,11 @@ export default Vue.extend({
         'info'
       ],
       running: false,
-      error: false
+      error: false,
+      showCode: false,
+      codeDetailContent: '',
+      rollbackCodeDialog: false,
+      rollbackAnswer: ''
     }
   },
   watch: {
@@ -220,15 +279,25 @@ export default Vue.extend({
       return { lang: val, code: '' }
     })
 
-    const examId = this.$route.params.examId
-    getExamQuestionSubmitRecord(examId, this.question.id).then(({ data }) => {
-      this.submitRecords = data.result
-    })
-    // this.codeJudgeResults = [
-    //   { id: 1, result: 'Accepted', timeused: 123, memoryused: 12345 }
-    // ]
+    this.updateSubmitRecords()
   },
   methods: {
+    onShowCode(content: string) {
+      content = '```\n' + content.replace('\r', '') + '\n```'
+      this.codeDetailContent = content
+      this.showCode = true
+    },
+    diffTime(time: LocalDateTime) {
+      let diffH = dayjs().diff(time, 'hour')
+      let diffM = dayjs().diff(time, 'minute') % 60
+      return diffH + '小时' + diffM + '分前'
+    },
+    async updateSubmitRecords() {
+      const examId = this.$route.params.examId
+      getExamQuestionSubmitRecord(examId, this.question.id).then(({ data }) => {
+        this.submitRecords = data.result
+      })
+    },
     submitCode(): void {
       this.tab = 1
       const examId = this.$route.params.examId
@@ -247,19 +316,21 @@ export default Vue.extend({
           this.error = true
         })
         .finally(() => {
-          this.running = false
+          this.updateSubmitRecords().finally(() => {
+            this.running = false
+          })
         })
     },
     statusToColor(status: string): string {
       return this.statusColors[this.statusTags.indexOf(status)]
     },
-    resetLastCommit() {
-      // const lastSubmitCodes = this.lastCommitCode
-      // const curLangLastSubmit = lastSubmitCodes.find((val) => {
-      //   return val.language === this.currentLang
-      // })
-      //
-      // this.currentCode = curLangLastSubmit?.code ?? ''
+    onOpenRollbackDialog(code: string) {
+      this.rollbackAnswer = code
+      this.rollbackCodeDialog = true
+    },
+    onRollback() {
+      this.currentCode = this.rollbackAnswer
+      this.rollbackCodeDialog = false
     },
     resetOriginCode() {
       // const originCodes = this.question.codeTuples ?? []

+ 1 - 1
src/views/student/Overview.vue

@@ -2,7 +2,7 @@
   <v-container>
     <page-header title="评测列表" :breadcrumb="breadcrumb">
       <template #extra>
-        <v-row no-gutters justify="end">
+        <v-row no-gutters justify="end" class="mb-7 mr-2">
           <v-btn
             color="secondary"
             fab