dusenyao vor 1 Jahr
Ursprung
Commit
8db861c7da

+ 7 - 0
src/api/exercise.js

@@ -194,3 +194,10 @@ export function GetAnswerRecordInfo(data) {
 export function GetAnswerRecordReport(data) {
   return http.post(`/TeachingServer/ExerciseManager/GetAnswerRecordReport`, data);
 }
+
+/**
+ * 填写题目答题批注
+ */
+export function FillQuestionAnswerRemark(data) {
+  return http.post(`/TeachingServer/ExerciseAnswerManager/FillQuestionAnswerRemark`, data);
+}

+ 3 - 1
src/store/getters.js

@@ -1,3 +1,5 @@
-const getters = {};
+const getters = {
+  isTeacher: (state) => state.user.user_type === 'TEACHER',
+};
 
 export default getters;

+ 2 - 0
src/views/exercise_questions/answer/components/AnswerReport.vue

@@ -121,6 +121,7 @@ export default {
 
   .answer-list {
     display: flex;
+    flex-wrap: wrap;
     gap: 24px;
     width: 770px;
 
@@ -128,6 +129,7 @@ export default {
       width: 56px;
       height: 40px;
       padding: 8px;
+      line-height: 24px;
       text-align: center;
       cursor: pointer;
       background-color: #f0f0f0;

+ 164 - 43
src/views/exercise_questions/answer/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="answer">
+  <div v-loading="loading" class="answer">
     <header class="header">
       <div class="back round" @click="goBack">
         <i class="el-icon-arrow-left"></i>
@@ -38,8 +38,29 @@
     </main>
 
     <footer class="footer">
-      <el-popover placement="top-start" trigger="click">
-        <div>增加批注</div>
+      <el-popover v-model="isPopover" placement="top-start" trigger="click">
+        <div class="annotations-container">
+          <div class="title">增加批注</div>
+          <div class="score">
+            <span>分数</span>
+            <el-input-number v-model="annotations.score" :min="0" :step="1" />
+          </div>
+          <el-input v-model="annotations.remark" type="textarea" rows="6" resize="none" class="remark" />
+          <div>图片/视频</div>
+
+          <el-upload action="no" accept="audio/*,video/*,image/*" :show-file-list="true" :http-request="upload">
+            <div class="upload">
+              <i class="el-icon-plus avatar-uploader-icon"></i>
+              <span>Upload</span>
+            </div>
+          </el-upload>
+
+          <div class="popover-footer">
+            <el-button @click="isPopover = false">取消</el-button>
+            <el-button type="primary" @click="fillQuestionAnswerRemark">确定</el-button>
+          </div>
+        </div>
+
         <div v-show="isAnnotations" slot="reference" class="annotations"><i class="el-icon-plus"></i>批注</div>
       </el-popover>
 
@@ -58,10 +79,21 @@
 
         <template v-else>
           <el-button round @click="fillQuestionAnswer('pre')">上一题</el-button>
-          <el-button v-if="curQuestionIndex === questionList.length - 1" type="primary" round @click="submitAnswer">
+          <el-button
+            v-if="curQuestionIndex === questionList.length - 1 && !isTeacherAnnotations"
+            type="primary"
+            round
+            @click="submitAnswer"
+          >
             提交
           </el-button>
-          <el-button v-else type="primary" round @click="fillQuestionAnswer('next')">下一题</el-button>
+          <el-button
+            v-else-if="curQuestionIndex < questionList.length - 1 || !isTeacherAnnotations"
+            type="primary"
+            round
+            @click="fillQuestionAnswer('next')"
+            >下一题</el-button
+          >
         </template>
       </div>
     </footer>
@@ -78,8 +110,10 @@ import {
   FillQuestionAnswer,
   SubmitAnswer,
   GetQuestionInfo_AnswerRecord,
+  FillQuestionAnswerRemark,
 } from '@/api/exercise';
 import { subjectiveQuestionList } from './answer';
+import { fileUpload } from '@/api/app';
 
 import StartQuestion from './components/StartQuestion.vue';
 import AnswerReport from './components/AnswerReport.vue';
@@ -93,13 +127,14 @@ export default {
   },
   mixins: [PreviewQuestionTypeMixin],
   data() {
-    const { id, share_record_id } = this.$route.query;
+    const { id, share_record_id, answer_record_id, question_index } = this.$route.query;
 
     return {
       exercise_id: id, // 练习题id
       share_record_id, // 分享记录id
-      answer_record_id: '', // 答题记录id
+      answer_record_id: answer_record_id ?? '', // 答题记录id
       secondFormatConversion,
+      isTeacher: this.$store.getters.isTeacher, // 是否是教师
       user_answer_record_info: {
         correct_answer_show_mode: 1, // 正确答案显示模式
       }, // 当前用户的答题记录信息
@@ -109,6 +144,8 @@ export default {
       currentQuestion: {},
       // 当前问题索引
       curQuestionIndex: -1,
+      question_index: Number(question_index) || -1, // 跳转的问题索引
+      loading: false,
       // 倒计时
       countDownTimer: null,
       answer_mode: 1, // 答题模式
@@ -117,9 +154,27 @@ export default {
       isSubmit: false,
       isView: false, // 练习模式下是否查看
       curQuestionPage: '', // 当前问题页面
-      isAnnotations: false, // 是否显示批注
+      remark: {
+        is_remarked: 'false',
+      }, // 教师批注
+      isPopover: false,
+      annotations: {
+        score: 0,
+        remark: '',
+        file_id_list: [],
+      }, // 批注
     };
   },
+  computed: {
+    // 是否教师批改
+    isTeacherAnnotations() {
+      return this.question_index >= 0 && this.isTeacher;
+    },
+    // 是否显示批注
+    isAnnotations() {
+      return this.remark.is_remarked === 'true' || this.isTeacherAnnotations;
+    },
+  },
   watch: {
     curQuestionIndex() {
       this.getQuestionInfo();
@@ -140,6 +195,7 @@ export default {
       }
 
       if (this.share_record_id) {
+        this.loading = true;
         GetShareRecordInfo({ share_record_id: this.share_record_id }).then(
           ({ user_answer_record_info, share_record: { exercise_id, answer_mode, answer_time_limit_minute } }) => {
             this.user_answer_record_info = user_answer_record_info;
@@ -147,11 +203,12 @@ export default {
             this.getExerciseQuestionIndexList();
             this.answer_time_limit_minute = answer_time_limit_minute;
             this.time = answer_time_limit_minute * 60;
+            this.loading = false;
             // 如果是考试模式,且已经存在答题记录,则直接显示答题报告
-            if (this.user_answer_record_info.is_exist_answer_record === 'true' && answer_mode === 2) {
+            if (this.user_answer_record_info.is_exist_answer_record === 'true' && !this.isTeacher) {
               this.answer_record_id = this.user_answer_record_info.answer_record_id;
               this.answer_mode = answer_mode;
-              this.isSubmit = true;
+              if (this.answer_mode === 2) this.isSubmit = true;
             }
           },
         );
@@ -161,8 +218,11 @@ export default {
       GetExerciseQuestionIndexList({ exercise_id: this.exercise_id }).then(({ index_list }) => {
         this.questionList = index_list.map((item) => ({
           ...item,
-          isFill: false,
+          isFill: this.isTeacherAnnotations,
         }));
+        if (this.question_index >= 0) {
+          this.curQuestionIndex = this.question_index;
+        }
       });
     },
     goBack() {
@@ -230,11 +290,8 @@ export default {
         this.curQuestionIndex = type === 'pre' ? this.curQuestionIndex - 1 : this.curQuestionIndex + 1;
         return;
       }
-      // 如果是主观题或已填写,直接跳转
-      if (
-        this.questionList[this.curQuestionIndex].isFill ||
-        subjectiveQuestionList.includes(this.currentQuestion.type)
-      ) {
+      // 如果已填写,直接跳转
+      if (this.questionList[this.curQuestionIndex].isFill) {
         if (type === 'pre') return this.preQuestion();
         if (type === 'next') return this.nextQuestion();
       }
@@ -246,8 +303,10 @@ export default {
         answer: JSON.stringify(answer),
       }).then(() => {
         this.questionList[this.curQuestionIndex].isFill = true;
-        // if (type === 'pre') return this.preQuestion();
-        // if (type === 'next') return this.nextQuestion();
+        if (subjectiveQuestionList.includes(this.currentQuestion.type)) {
+          if (type === 'pre') return this.preQuestion();
+          if (type === 'next') return this.nextQuestion();
+        }
         // 显示答案
         this.$refs.exercise[0].showAnswer(
           this.answer_mode === 1,
@@ -261,11 +320,13 @@ export default {
       GetQuestionInfo_AnswerRecord({
         answer_record_id: this.answer_record_id,
         question_id: this.questionList[this.curQuestionIndex].id,
-      }).then(({ user_answer: { is_fill_answer, content } }) => {
+      }).then(({ user_answer: { is_fill_answer, content }, remark }) => {
+        this.remark = remark;
+        console.log(this.remark);
         if (is_fill_answer === 'false') return;
-        this.$refs.exercise[0].showAnswer(
-          this.answer_mode === 1,
-          this.user_answer_record_info.correct_answer_show_mode === 1,
+        this.$refs.exercise?.[0].showAnswer(
+          this.answer_mode === 1 && !this.isTeacherAnnotations,
+          this.user_answer_record_info.correct_answer_show_mode === 1 && !this.isTeacherAnnotations,
           JSON.parse(content || '{}'),
         );
       });
@@ -274,29 +335,56 @@ export default {
     submitAnswer() {
       if (!this.answer_record_id) return;
 
-      // 如果已经填写过答案,直接提交
-      if (this.questionList[this.curQuestionIndex].isFill) {
-        SubmitAnswer({ answer_record_id: this.answer_record_id })
-          .then(() => {
-            this.isSubmit = true;
-          })
-          .catch(() => {});
-        return;
-      }
+      this.$confirm('是否确认提交答题?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          clearInterval(this.countDownTimer);
+          // 如果已经填写过答案,直接提交
+          if (this.questionList[this.curQuestionIndex].isFill) {
+            SubmitAnswer({ answer_record_id: this.answer_record_id })
+              .then(() => {
+                this.isSubmit = true;
+              })
+              .catch(() => {});
+            return;
+          }
 
-      this.fillQuestionAnswer('next').then(() => {
-        SubmitAnswer({ answer_record_id: this.answer_record_id })
-          .then(() => {
-            this.isSubmit = true;
-          })
-          .catch(() => {});
-      });
+          this.fillQuestionAnswer('next').then(() => {
+            SubmitAnswer({ answer_record_id: this.answer_record_id })
+              .then(() => {
+                this.isSubmit = true;
+              })
+              .catch(() => {});
+          });
+        })
+        .catch(() => {});
     },
     selectQuestion(i) {
       this.isSubmit = false;
       this.isView = true;
       this.curQuestionIndex = i;
     },
+    upload(file) {
+      fileUpload('Mid', file).then(({ file_info_list }) => {
+        if (file_info_list.length > 0) {
+          const { file_id } = file_info_list[0];
+          this.annotations.file_id_list.push(file_id);
+        }
+      });
+    },
+    fillQuestionAnswerRemark() {
+      FillQuestionAnswerRemark({
+        answer_record_id: this.answer_record_id,
+        question_id: this.questionList[this.curQuestionIndex].id,
+        ...this.annotations,
+      }).then(() => {
+        this.$message.success('批注成功');
+        this.isPopover = false;
+      });
+    },
   },
 };
 </script>
@@ -366,12 +454,45 @@ export default {
   padding: 8px 8px 14px;
   font-size: 14px;
 
-  .title {
-    color: #000;
-  }
+  .annotations-container {
+    display: flex;
+    flex-direction: column;
+    row-gap: 8px;
+
+    .title {
+      color: #000;
+    }
+
+    .score {
+      display: flex;
+      column-gap: 8px;
+      align-items: center;
 
-  .score {
-    color: #999;
+      :first-child {
+        color: #999;
+      }
+    }
+
+    .remark {
+      width: 350px;
+    }
+
+    .upload {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: space-around;
+      width: 80px;
+      height: 80px;
+      padding: 8px;
+      background-color: $fill-color;
+      border: 1px solid $border-color;
+    }
+
+    .popover-footer {
+      display: flex;
+      justify-content: flex-end;
+    }
   }
 }
 </style>

+ 11 - 2
src/views/share/ShareExercise.vue

@@ -10,10 +10,12 @@ export default {
   name: 'ShareExercise',
 
   data() {
-    let { share_record_id } = this.$route.query;
+    let { share_record_id, answer_record_id, question_index } = this.$route.query;
 
     return {
       share_record_id,
+      answer_record_id: answer_record_id || '',
+      question_index: question_index || -1,
     };
   },
   created() {
@@ -37,7 +39,14 @@ export default {
             this.$router.push({ path: '/exercise', query: { id: share_record.exercise_id } });
           }
           if (share_record.access_popedom === 2) {
-            this.$router.push({ path: '/answer', query: { share_record_id: this.share_record_id } });
+            this.$router.push({
+              path: '/answer',
+              query: {
+                share_record_id: this.share_record_id,
+                answer_record_id: this.answer_record_id,
+                question_index: this.question_index,
+              },
+            });
           }
         })
         .catch(() => {