|
|
@@ -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 ?? []
|