Parcourir la source

add: 添加完成测试检测和教师端成绩显示

weijin il y a 4 ans
Parent
commit
74206619dd

+ 6 - 0
src/api/report.ts

@@ -7,3 +7,9 @@ export const getPersonalReport = (examId: ID) => {
     `${REPORT_MODULE}?examId=${examId}`
   )
 }
+
+export const getAllReportByExamId = (examId: ID) => {
+  return axios.get<ReceivedData<Array<PersonalReportSerializer>>>(
+    `${REPORT_MODULE}/all?examId=${examId}`
+  )
+}

+ 6 - 0
src/api/types.d.ts

@@ -57,6 +57,7 @@ export interface ExamSerializer {
   examId?: number
   inviteCode?: string
   isJoined?: boolean // 该变量仅在/exam/list 中有意义,其他接口要注意处理
+  isFinished?: boolean
 }
 
 export interface CreateExamResponse {
@@ -162,6 +163,10 @@ export interface UserSerializer {
   role: UserRole
 }
 
+export interface UserWithScoreSerializer extends UserSerializer {
+  score?: number
+}
+
 export type QuestionAndScore = Object // {ID:number}
 
 export interface Record {
@@ -180,6 +185,7 @@ export interface PersonalReportSerializer {
   score: number
   rank: number
   submitTime: LocalDateTime
+  userId: number
 }
 
 export interface ExamQuestionSubmitRecord {

+ 13 - 0
src/views/student/Overview.vue

@@ -44,6 +44,7 @@ import PageHeader from '@/views/components/PageHeader.vue'
 import { getAllExamList } from '@/api/exam'
 import { ExamSerializer } from '@/api/types'
 import StudentExamInfoCard from '@/views/student/components/StudentExamInfoCard.vue'
+import { getExamSubmitRecordsByUserId } from '@/api/record'
 
 export default Vue.extend({
   name: 'Overview',
@@ -101,6 +102,18 @@ export default Vue.extend({
         .then(({ data }) => {
           this.examList = data.result.examVOList
           this.totalNum = data.result.totalNum
+          const that = this
+          this.examList.forEach(function(exam) {
+            if (exam.examId) {
+              getExamSubmitRecordsByUserId(exam.examId).then(({ data }) => {
+                if (data.result.find((val) => !val.message)) {
+                  that.$set(exam, 'isFinished', true)
+                } else {
+                  that.$set(exam, 'isFinished', false)
+                }
+              })
+            }
+          })
         })
         .catch((err) => {
           this.examList = []

+ 13 - 2
src/views/student/StudentExamList.vue

@@ -48,6 +48,7 @@ import PageHeader from '@/views/components/PageHeader.vue'
 import { getExamsByStudentId } from '@/api/exam'
 import { ExamSerializer, ExamState } from '@/api/types'
 import StudentExamInfoCard from '@/views/student/components/StudentExamInfoCard.vue'
+import { getExamSubmitRecordsByUserId } from '@/api/record'
 
 export default Vue.extend({
   name: 'ExamList',
@@ -105,8 +106,18 @@ export default Vue.extend({
         .then(({ data }) => {
           this.examList = data.result.examVOList
           this.totalNum = data.result.totalNum
-          this.examList.forEach((val, index) => {
-            this.examList[index].isJoined = true // 该变量仅在/exam/list 中有意义
+          const that = this
+          this.examList.forEach(function(exam) {
+            if (exam.examId) {
+              getExamSubmitRecordsByUserId(exam.examId).then(({ data }) => {
+                if (data.result.find((val) => !val.message)) {
+                  that.$set(exam, 'isFinished', true)
+                } else {
+                  that.$set(exam, 'isFinished', false)
+                }
+              })
+            }
+            exam.isJoined = true // 该变量仅在/exam/list 中有意义
           })
         })
         .catch((err) => {

+ 15 - 4
src/views/student/components/StudentExamInfoCard.vue

@@ -5,13 +5,13 @@
         <v-card-title class="ma-0 pa-0">
           <v-tooltip top v-if="examInfo.isPublic">
             <template v-slot:activator="{ on, attrs }">
-              <v-icon v-bind="attrs" v-on="on">mdi-lock-off</v-icon>
+              <v-icon v-bind="attrs" v-on="on">mdi-lock-open-outline</v-icon>
             </template>
             <span>无需邀请码即可加入</span>
           </v-tooltip>
           <v-tooltip top v-else>
             <template v-slot:activator="{ on, attrs }">
-              <v-icon v-bind="attrs" v-on="on">mdi-lock</v-icon>
+              <v-icon v-bind="attrs" v-on="on">mdi-lock-outline</v-icon>
             </template>
             <span>输入邀请码加入评测</span>
           </v-tooltip>
@@ -21,6 +21,14 @@
         <v-chip :color="statusToColor(state)" label class="ml-5" outlined>{{
           state
         }}</v-chip>
+        <v-chip
+          color="secondary"
+          v-if="examInfo.isFinished"
+          label
+          class="ml-5"
+          outlined
+          >已完成</v-chip
+        >
       </v-col>
       <v-col class="mr-3 d-flex justify-end">
         <v-btn
@@ -45,14 +53,16 @@
           <template>等待加入</template>
         </v-btn>
         <v-btn
-          v-if="examInfo.isJoined && state === '进行中'"
+          v-if="examInfo.isJoined && state === '进行中' && !examInfo.isFinished"
           color="success"
           class="mx-2"
           @click="onStartExam"
           >开始评测</v-btn
         >
         <v-btn
-          v-if="examInfo.isJoined && state === '已结束'"
+          v-if="
+            examInfo.isJoined && (state === '已结束' || examInfo.isFinished)
+          "
           color="secondary"
           class="mx-2"
           @click="onOpenResult"
@@ -172,6 +182,7 @@ export default Vue.extend({
       this.examInfo.startTime,
       this.examInfo.endTime
     )
+    console.log(this.examInfo)
   },
   updated() {
     this.state = computeExamStateText(

+ 14 - 3
src/views/teacher/TeacherExamDetail.vue

@@ -128,7 +128,7 @@
                       {{ user.email }}
                     </v-col>
                     <v-col>
-                      
+                      {{ user.score }}
                     </v-col>
                   </v-row>
                 </v-list-item-content>
@@ -150,13 +150,14 @@ import {
   TeacherQuestionSerializer,
   LocalDateTime,
   ReceivedData,
-  UserSerializer
+  UserWithScoreSerializer
 } from '@/api/types'
 import { getQuestionInfo } from '@/api/question'
 import PageHeader from '@/views/components/PageHeader.vue'
 import ExamQuestionsInfo from '@/views/components/ExamQuestionsInfo.vue'
 import { getExamJoinedUsers } from '@/api/user'
 import { timeLength } from '@/utils/common'
+import { getAllReportByExamId } from '@/api/report'
 
 export default Vue.extend({
   name: 'TeacherExamDetail',
@@ -168,7 +169,7 @@ export default Vue.extend({
     return {
       fetching: false,
       examQuestions: [] as Array<TeacherQuestionSerializer>,
-      joinedUsers: [] as Array<UserSerializer>,
+      joinedUsers: [] as Array<UserWithScoreSerializer>,
       breadcrumb: [
         {
           text: '主页',
@@ -235,6 +236,16 @@ export default Vue.extend({
 
     getExamJoinedUsers(examId).then(({ data }) => {
       this.joinedUsers = data.result
+      getAllReportByExamId(examId).then(({ data }) => {
+        const that = this
+        this.joinedUsers.forEach((user) => {
+          data.result.forEach((report) => {
+            if (report.userId === user.id) {
+              that.$set(user, 'score', report.score)
+            }
+          })
+        })
+      })
     })
   }
 })

+ 3 - 2
vue.config.js

@@ -7,7 +7,6 @@ module.exports = {
     proxy: {
       '^/api': {
         // target: 'http://localhost:8080/',
-        // target: 'http://47.111.95.164:8080/',
         target: 'https://eval-server.seec.seecoder.cn/',
         ws: true,
         changeOrigin: true
@@ -16,7 +15,9 @@ module.exports = {
         target: 'https://analysis.seec.seecoder.cn',
         pathRewrite: {
           '^/analysis_api': '/eval'
-        }
+        },
+        ws: true,
+        changeOrigin: true
         //token eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJza3kiOiJXb0JpU2hlWWFvWGllQnVXYW5MZSEhIn0.QDF9l3beb2vodPMH87adsT4DZL60NU6Zf4uYAxelzg8
       }
     },