Browse Source

修改:学生作答详情判断题显示问题

吴朋磊 3 days ago
parent
commit
ad231038cc

+ 1 - 1
src/http/api/teachingHomework.js

@@ -17,7 +17,7 @@ const teachingHomework = {
   queryClassHomeWorkByPage(data) {
     return get(base.prefix + `/api/v1/student_class_home_work/query_class_home_work_by_page`, data);
   },
-  // 作业任务详情
+  // 作业任务详情。data 为作业对象,题目列表在 questionDetails
   viewHomeWorkWriteDetail(data) {
     return get(base.prefix + `/api/v1/student_class_home_work/view_home_work_write_detail`, data);
   },

+ 106 - 16
src/views/teachingHomework/homeworkTask/answer.vue

@@ -63,8 +63,13 @@
           <!-- 选择题:我的作答 + 选项;解答题:已上传图片,可删除 -->
           <div class="dock_answer">
             <span class="dock_label">我的作答:</span>
-            <span v-if="isSingle" class="dock_sub_no">(1)</span>
-            <el-checkbox-group v-if="isSingle" class="choice_radio" v-model="answers[currentQuestion.id]"
+            <!-- <span v-if="isSingle" class="dock_sub_no">(1)</span> -->
+            <el-radio-group v-if="isJudge" class="choice_radio" v-model="answers[currentQuestion.id]"
+              @change="persistState">
+              <el-radio label="T">对</el-radio>
+              <el-radio label="F">错</el-radio>
+            </el-radio-group>
+            <el-checkbox-group v-else-if="isSingle" class="choice_radio" v-model="answers[currentQuestion.id]"
               @change="persistState">
               <el-checkbox v-for="opt in currentQuestion.options" :key="opt.key" :label="opt.key">
                 {{ opt.key }}
@@ -139,18 +144,20 @@ function buildOptions(item) {
 }
 
 function mapQuestion(item, index) {
-  const choice = isChoiceQuestion(item);
+  const judge = Number(item.isJudge) === 1;
+  const choice = judge || isChoiceQuestion(item);
   const id = item.homeWorkStuQuesId || item.questionId || index;
   return {
     id,
     questionId: item.questionId,
     homeWorkStuQuesId: item.homeWorkStuQuesId,
+    isJudge: judge,
     type: choice ? 'single' : 'photo',
-    typeName: item.questionTypeName || (choice ? '客观题' : '主观题'),
-    groupName: item.questionTypeName || (choice ? '客观题' : '主观题'),
+    typeName: item.questionTypeName || (judge ? '判断题' : (choice ? '客观题' : '主观题')),
+    groupName: item.questionTypeName || (judge ? '判断题' : (choice ? '客观题' : '主观题')),
     difficulty: item.difficultyName || '',
     stem: item.questionContent || '',
-    options: choice ? buildOptions(item) : [],
+    options: judge ? [] : (choice ? buildOptions(item) : []),
     writeAnswer: item.writeAnswer || '',
     writeUrls: Array.isArray(item.writeUrls) ? item.writeUrls : [],
     submitEndTime: item.submitEndTime || '',
@@ -193,13 +200,14 @@ export default {
       const name = (this.homework && this.homework.subjectName) || '';
       return this.$global.getSubjectsName(name, null, 'color');
     },
-    // 按题型分组,供左侧序号导航使用
+    // 按接口返回的 questionTypeName 分组,有几种题型就显示几组
     questionGroups() {
       const groups = [];
       this.questions.forEach((item, index) => {
-        let group = groups.find(g => g.type === item.type);
+        const name = item.groupName || item.typeName || '其他';
+        let group = groups.find(g => g.name === name);
         if (!group) {
-          group = { type: item.type, name: item.groupName, list: [] };
+          group = { type: name, name, list: [] };
           groups.push(group);
         }
         group.list.push({ ...item, index });
@@ -212,10 +220,14 @@ export default {
       if (!item) return null;
       return { ...item, index: this.currentIndex };
     },
-    // 当前题是否为选择题
+    // 当前题是否为选择题(含判断题)
     isSingle() {
       return !!(this.currentQuestion && this.currentQuestion.type === 'single');
     },
+    // isJudge 为 1 时是判断题,只显示对 / 错
+    isJudge() {
+      return !!(this.currentQuestion && this.currentQuestion.isJudge);
+    },
     hasOptionText() {
       const options = (this.currentQuestion && this.currentQuestion.options) || [];
       return options.some(opt => opt.text);
@@ -315,9 +327,13 @@ export default {
       return null;
     },
     applyDetail(res) {
-      const list = Array.isArray(res && res.data) ? res.data : [];
+      const detail = this.pickDetail(res);
+      const list = detail.questionDetails;
+      this.mergeHomework(detail);
       this.questions = list.map(mapQuestion);
-      const endTime = (this.questions[0] && this.questions[0].submitEndTime) || this.homework.endTime;
+      const endTime = detail.submitEndTime
+        || (this.questions[0] && this.questions[0].submitEndTime)
+        || (this.homework && this.homework.endTime);
       if (endTime && this.homework) this.homework.endTime = endTime;
       this.fillAnswers();
       if (this.currentIndex < 0 || this.currentIndex >= this.questions.length) {
@@ -325,6 +341,33 @@ export default {
       }
       this.persistState();
     },
+    // 详情 data 为作业对象,题目在 questionDetails;兼容旧的题目数组
+    pickDetail(res) {
+      const data = res && res.data;
+      if (Array.isArray(data)) return { questionDetails: data };
+      if (data && typeof data === 'object') {
+        return {
+          ...data,
+          questionDetails: Array.isArray(data.questionDetails) ? data.questionDetails : [],
+        };
+      }
+      return { questionDetails: [] };
+    },
+    // 用详情里的作业信息补齐头部:名称、教师、科目、截止时间
+    mergeHomework(detail) {
+      const current = this.homework || {};
+      this.homework = {
+        ...current,
+        homeWorkId: detail.homeWorkId != null ? detail.homeWorkId : current.homeWorkId,
+        homeWorkStuId: detail.homeWorkStuId != null ? detail.homeWorkStuId : current.homeWorkStuId,
+        homeworkName: detail.homeWorkName || current.homeworkName || '',
+        teacherName: detail.createUserName || current.teacherName || '',
+        subjectName: detail.courseName || current.subjectName || '',
+        courseCode: detail.courseCode != null ? detail.courseCode : current.courseCode,
+        endTime: detail.submitEndTime || current.endTime || '',
+        questionNum: detail.questionNumber != null ? detail.questionNumber : current.questionNum,
+      };
+    },
     fillAnswers() {
       const savedAnswers = this.savedAnswers || {};
       const answers = {};
@@ -333,6 +376,8 @@ export default {
         const hasSaved = savedAnswers[item.id] != null || savedAnswers[String(item.id)] != null;
         if (item.type === 'photo') {
           answers[item.id] = hasSaved && Array.isArray(saved) ? saved : item.writeUrls.slice();
+        } else if (item.isJudge) {
+          answers[item.id] = this.normalizeJudgeAnswer(hasSaved ? saved : item.writeAnswer);
         } else {
           // 选择题多选,答案统一为选项 key 数组;兼容历史字符串缓存与接口回显
           answers[item.id] = this.normalizeChoiceAnswer(hasSaved ? saved : item.writeAnswer, item.options);
@@ -340,6 +385,13 @@ export default {
       });
       this.answers = answers;
     },
+    // 判断题回显:T 为对,F 为错
+    normalizeJudgeAnswer(value) {
+      const text = String(value == null ? '' : value).trim();
+      if (text === 'T' || text === 't' || text === '对' || text.toLowerCase() === 'true') return 'T';
+      if (text === 'F' || text === 'f' || text === '错' || text.toLowerCase() === 'false') return 'F';
+      return '';
+    },
     // 把接口/缓存里的答案归一化为合法选项 key 数组,兼容 "A,C"、"AC"、"A|C"、["A"] 等格式
     normalizeChoiceAnswer(value, options) {
       const validKeys = (options || []).map(opt => opt.key);
@@ -521,16 +573,20 @@ export default {
         if (this.uploading) this.$message.warning('图片正在上传,请稍候');
         return Promise.resolve(false);
       }
-      const isChoice = question.type === 'single';
+      const isJudge = !!question.isJudge;
+      const isChoice = question.type === 'single' && !isJudge;
+      const judgeValue = this.answers[question.id];
       const payload = {
         homeWorkId: this.homework && this.homework.homeWorkId,
         homeWorkStuId: this.homework && this.homework.homeWorkStuId,
         homeWorkStuQuesId: question.homeWorkStuQuesId,
         questionId: question.questionId,
         commitFlag,
-        // 选择题多选,以英文逗号拼接所选选项;拍照题提交图片地址
-        writeAnswer: isChoice ? (this.answers[question.id] || []).join(',') : '',
-        writeUrls: isChoice ? [] : (this.answers[question.id] || []),
+        // 判断题传 T / F;选择题多选以英文逗号拼接;拍照题提交图片地址
+        writeAnswer: isJudge
+          ? (judgeValue === 'T' || judgeValue === 'F' ? judgeValue : '')
+          : (isChoice ? (this.answers[question.id] || []).join(',') : ''),
+        writeUrls: isJudge || isChoice ? [] : (this.answers[question.id] || []),
       };
       this.saving = true;
       return this.$api.teachingHomework.commitHomeWorkWriteAnswer(payload).then(res => {
@@ -925,6 +981,40 @@ export default {
               color: #333;
               line-height: 20px;
             }
+
+            :deep(.el-radio) {
+              margin-right: 0 !important;
+              height: 20px;
+              display: inline-flex !important;
+              align-items: center;
+            }
+
+            :deep(.el-radio__input) {
+              display: inline-flex;
+              align-items: center;
+              height: 16px;
+              line-height: 16px;
+            }
+
+            :deep(.el-radio__inner) {
+              width: 16px;
+              height: 16px;
+              border: 1px solid #DCDFE6;
+              background: #fff;
+            }
+
+            :deep(.el-radio__input.is-checked .el-radio__inner) {
+              background-color: #2E64FA;
+              border-color: #2E64FA;
+            }
+
+            :deep(.el-radio__input.is-checked + .el-radio__label),
+            :deep(.el-radio__label) {
+              padding-left: 8px;
+              font-size: 14px;
+              color: #333;
+              line-height: 20px;
+            }
           }
 
           .photo_list {

+ 125 - 12
src/views/teachingHomework/homeworkTask/viewAnswer.vue

@@ -75,8 +75,16 @@
               <div class="dock_answer">
                 <span class="dock_label">我的作答:</span>
                 <span v-if="isSingle" class="dock_sub_no">(1)</span>
+                <el-radio-group
+                  v-if="isJudge"
+                  class="choice_radio"
+                  :value="currentJudgeAnswer"
+                  disabled>
+                  <el-radio label="T">对</el-radio>
+                  <el-radio label="F">错</el-radio>
+                </el-radio-group>
                 <el-checkbox-group
-                  v-if="isSingle"
+                  v-else-if="isSingle"
                   class="choice_radio"
                   :value="currentUserAnswer"
                   disabled>
@@ -117,7 +125,7 @@
               <div class="analysis_row" v-if="hasAnalysis">
                 <span class="analysis_label" >【 答 案 】</span>
                 <div class="analysis_content">
-                  <span  class="correct_answer" v-html="currentQuestion.correctAnswer"> </span>
+                  <span class="correct_answer" v-html="displayCorrectAnswer"></span>
                 </div>
               </div>
               <div class="analysis_row" v-if="hasAnalysis" style="margin-top: 0;">
@@ -203,6 +211,14 @@ function normalizeChoiceAnswer(value, options) {
   return result;
 }
 
+// 判断题回显:T 为对,F 为错
+function normalizeJudgeAnswer(value) {
+  const text = String(value == null ? '' : value).trim();
+  if (text === 'T' || text === 't' || text === '对' || text.toLowerCase() === 'true') return 'T';
+  if (text === 'F' || text === 'f' || text === '错' || text.toLowerCase() === 'false') return 'F';
+  return '';
+}
+
 function mapKnowledge(list) {
   if (!Array.isArray(list)) return [];
   return list.map(item => {
@@ -217,19 +233,21 @@ function mapKnowledge(list) {
  * type: single 客观题 / photo 主观题
  */
 function mapQuestion(item, index) {
-  const choice = isChoiceQuestion(item);
+  const judge = Number(item.isJudge) === 1;
+  const choice = judge || isChoiceQuestion(item);
   const id = item.homeWorkStuQuesId || item.questionId || index;
   return {
     id,
     questionId: item.questionId,
     homeWorkStuQuesId: item.homeWorkStuQuesId,
+    isJudge: judge,
     type: choice ? 'single' : 'photo',
-    typeName: item.questionTypeName || (choice ? '客观题' : '主观题'),
-    groupName: item.questionTypeName || (choice ? '客观题' : '主观题'),
+    typeName: item.questionTypeName || (judge ? '判断题' : (choice ? '客观题' : '主观题')),
+    groupName: item.questionTypeName || (judge ? '判断题' : (choice ? '客观题' : '主观题')),
     difficulty: item.difficultyName || '',
     stem: item.questionContent || '',
-    options: choice ? buildOptions(item) : [],
-    // 客观题取 ABCD 答案,主观题取作答图片地址
+    options: judge ? [] : (choice ? buildOptions(item) : []),
+    // 判断题取 T / F,客观题取 ABCD,主观题取作答图片地址
     userAnswer: choice
       ? (item.writeAnswer || '')
       : (Array.isArray(item.writeUrls) ? item.writeUrls : []),
@@ -277,12 +295,14 @@ export default {
       const name = (this.homework && this.homework.subjectName) || '';
       return this.$global.getSubjectsName(name, null, 'color');
     },
+    // 按接口返回的 questionTypeName 分组,有几种题型就显示几组
     questionGroups() {
       const groups = [];
       this.questions.forEach((item, index) => {
-        let group = groups.find(g => g.type === item.type);
+        const name = item.groupName || item.typeName || '其他';
+        let group = groups.find(g => g.name === name);
         if (!group) {
-          group = { type: item.type, name: item.groupName, list: [] };
+          group = { type: name, name, list: [] };
           groups.push(group);
         }
         group.list.push({ ...item, index });
@@ -297,6 +317,10 @@ export default {
     isSingle() {
       return !!(this.currentQuestion && this.currentQuestion.type === 'single');
     },
+    // isJudge 为 1 时是判断题,详情只展示对 / 错
+    isJudge() {
+      return !!(this.currentQuestion && this.currentQuestion.isJudge);
+    },
     hasOptionText() {
       const options = (this.currentQuestion && this.currentQuestion.options) || [];
       return options.some(opt => opt.text);
@@ -315,9 +339,23 @@ export default {
       return this.currentIndex >= this.questions.length - 1;
     },
     currentUserAnswer() {
-      if (!this.currentQuestion || !this.isSingle) return [];
+      if (!this.currentQuestion || !this.isSingle || this.isJudge) return [];
       return normalizeChoiceAnswer(this.currentQuestion.userAnswer, this.currentQuestion.options);
     },
+    // 判断题作答回显:T 选中「对」,F 选中「错」
+    currentJudgeAnswer() {
+      if (!this.currentQuestion || !this.isJudge) return '';
+      return normalizeJudgeAnswer(this.currentQuestion.userAnswer);
+    },
+    // 判断题标准答案同样把 T / F 显示为对 / 错
+    displayCorrectAnswer() {
+      const raw = (this.currentQuestion && this.currentQuestion.correctAnswer) || '';
+      if (!this.isJudge) return raw;
+      const judge = normalizeJudgeAnswer(raw);
+      if (judge === 'T') return '对';
+      if (judge === 'F') return '错';
+      return raw;
+    },
     currentPhotos() {
       if (!this.currentQuestion || this.isSingle) return [];
       const val = this.currentQuestion.userAnswer;
@@ -383,8 +421,9 @@ export default {
       return null;
     },
     applyDetail(res) {
-      const list = Array.isArray(res && res.data) ? res.data : [];
-      this.questions = list.map(mapQuestion);
+      const detail = this.pickDetail(res);
+      this.mergeHomework(detail);
+      this.questions = detail.questionDetails.map(mapQuestion);
       if (this.currentIndex < 0 || this.currentIndex >= this.questions.length) {
         this.currentIndex = 0;
       }
@@ -395,6 +434,33 @@ export default {
         if (box) box.scrollTop = 0;
       });
     },
+    // 详情 data 为作业对象,题目在 questionDetails;兼容旧的题目数组
+    pickDetail(res) {
+      const data = res && res.data;
+      if (Array.isArray(data)) return { questionDetails: data };
+      if (data && typeof data === 'object') {
+        return {
+          ...data,
+          questionDetails: Array.isArray(data.questionDetails) ? data.questionDetails : [],
+        };
+      }
+      return { questionDetails: [] };
+    },
+    // 用详情里的作业信息补齐头部:名称、教师、科目
+    mergeHomework(detail) {
+      const current = this.homework || {};
+      this.homework = {
+        ...current,
+        homeWorkId: detail.homeWorkId != null ? detail.homeWorkId : current.homeWorkId,
+        homeWorkStuId: detail.homeWorkStuId != null ? detail.homeWorkStuId : current.homeWorkStuId,
+        homeworkName: detail.homeWorkName || current.homeworkName || '',
+        teacherName: detail.createUserName || current.teacherName || '',
+        subjectName: detail.courseName || current.subjectName || '',
+        courseCode: detail.courseCode != null ? detail.courseCode : current.courseCode,
+        endTime: detail.submitEndTime || current.endTime || '',
+        questionNum: detail.questionNumber != null ? detail.questionNumber : current.questionNum,
+      };
+    },
     persistState() {
       if (!this.homework) return;
       sessionStorage.setItem(STORAGE_KEY, JSON.stringify({
@@ -880,6 +946,53 @@ export default {
               color: #333;
               line-height: 20px;
             }
+
+            :deep(.el-radio) {
+              margin-right: 0 !important;
+              height: 20px;
+              display: inline-flex !important;
+              align-items: center;
+              cursor: default;
+            }
+
+            :deep(.el-radio__input) {
+              display: inline-flex;
+              align-items: center;
+              height: 16px;
+              line-height: 16px;
+              cursor: default;
+            }
+
+            :deep(.el-radio__inner) {
+              width: 16px;
+              height: 16px;
+              border: 1px solid #DCDFE6;
+              background: #fff;
+              cursor: default;
+            }
+
+            :deep(.el-radio__input.is-disabled .el-radio__inner) {
+              background-color: #fff;
+              border-color: #DCDFE6;
+            }
+
+            :deep(.el-radio__input.is-disabled.is-checked .el-radio__inner) {
+              background-color: #2E64FA;
+              border-color: #2E64FA;
+            }
+
+            :deep(.el-radio__input.is-disabled.is-checked .el-radio__inner::after) {
+              background-color: #fff;
+            }
+
+            :deep(.el-radio__input.is-disabled + .el-radio__label),
+            :deep(.el-radio__label) {
+              padding-left: 8px;
+              font-size: 14px;
+              color: #333;
+              line-height: 20px;
+              cursor: default;
+            }
           }
 
           .photo_list {