Преглед на файлове

修改:教辅作业问题修改

吴朋磊 преди 3 дни
родител
ревизия
39f2a5b544

+ 1 - 1
src/main.js

@@ -95,7 +95,7 @@ window.receiveAppMsg = function(payload) {
       window.dispatchEvent(new CustomEvent('openHeaderDropdown'))
       break
     default:  
-      console.log('未知消息类型', payload)
+      // console.log('未知消息类型', payload)
       break
   }
 }

+ 6 - 1
src/views/analysisReport/components/dCharts/barChart.vue

@@ -136,6 +136,11 @@ import * as echarts from 'echarts';
       barMinWidth:{
         type:Number,
         default:20
+      },
+      // 数据多时是否倾斜 x 轴文字,默认倾斜;作业分析页传 false 保持水平
+      rotateXLabel:{
+        type:Boolean,
+        default:true
       }
     },
     watch:{
@@ -355,7 +360,7 @@ import * as echarts from 'echarts';
                         axisLabel: {
                             interval: 0, // 确保所有刻度标签都显示
                             fontWeight: 400,
-                            rotate: singleSeriesWidth < 80 ? 45 : 0,
+                            rotate: this.rotateXLabel && singleSeriesWidth < 80 ? 45 : 0,
                             formatter:function(value) {
                                 // console.log(value)
                                 

+ 3 - 1
src/views/teachingHomework/homeworkTask/analysis.vue

@@ -64,6 +64,7 @@
               unit="%"
               :gridLeft="0"
               :gridRight="0"
+              :rotateXLabel="false"
               :isClick="true"
               @HandleChartClick="onQuestionBarClick" />
             <RadarCharts
@@ -319,7 +320,8 @@
               typeName="得分率"
               unit="%"
               :gridLeft="0"
-              :gridRight="0" />
+              :gridRight="0"
+              :rotateXLabel="false" />
             <RadarCharts
               v-else
               :data="knowledgeRadarData"

+ 55 - 20
src/views/teachingHomework/homeworkTask/answer.vue

@@ -29,14 +29,18 @@
         <div class="nav_group" v-for="group in questionGroups" :key="group.type">
           <div class="group_name">{{ group.name }}</div>
           <div class="num_grid">
-            <!-- 序号仅展示作答进度,不支持点击跳题,只能按顺序逐题作答 -->
-            <span v-for="item in group.list" :key="item.id" class="num_btn" :class="numClass(item)">
+            <button
+              v-for="item in group.list"
+              :key="item.id"
+              type="button"
+              class="num_btn"
+              :class="numClass(item)"
+              @click="selectQuestion(item.index)">
               {{ item.index + 1 }}
-            </span>
+            </button>
           </div>
         </div>
       </div>
-
       <!-- 右侧题目:上方滚动题干,下方作答区不随题干滚动 -->
       <div class="question_panel" v-if="currentQuestion">
         <div class="question_scroll">
@@ -387,19 +391,37 @@ export default {
         done: answered && item.index !== this.currentIndex,
       };
     },
-    // 上一题
+    // 切题:当前题有作答才保存,没作答或为空则直接切换、不调接口
+    selectQuestion(index) {
+      if (index === this.currentIndex) return;
+      this.goToQuestion(index);
+    },
     prevQuestion() {
       if (this.currentIndex <= 0) return;
-      this.currentIndex -= 1;
-      this.persistState();
+      this.goToQuestion(this.currentIndex - 1);
     },
-    // 下一题先校验并保存,最后一题不走这里
     nextQuestion() {
       if (this.currentIndex >= this.questions.length - 1) return;
+      this.goToQuestion(this.currentIndex + 1);
+    },
+    goToQuestion(index) {
+      if (index === this.currentIndex) return;
+      if (this.uploading) {
+        this.$message.warning('图片正在上传,请稍候');
+        return;
+      }
+      const jump = () => {
+        this.currentIndex = index;
+        this.persistState();
+      };
+      const question = this.currentQuestion;
+      if (!question || !this.isAnswered(question.id)) {
+        jump();
+        return;
+      }
       this.saveCurrentAnswer(0).then(ok => {
         if (!ok) return;
-        this.currentIndex += 1;
-        this.persistState();
+        jump();
       });
     },
     // 选择题不可拍照;解答题达到上限或上传中也不可再选
@@ -492,17 +514,13 @@ export default {
     closePhotoPreview() {
       this.imgVisible = false;
     },
-    // 当前题未作答时提示题号;已作答则保存。最后一题 commitFlag 为 1
+    // 保存当前题;空作答不走这里
     saveCurrentAnswer(commitFlag) {
       const question = this.currentQuestion;
       if (!question || this.saving || this.uploading) {
         if (this.uploading) this.$message.warning('图片正在上传,请稍候');
         return Promise.resolve(false);
       }
-      if (!this.isAnswered(question.id)) {
-        this.$message.warning(`第${question.index + 1}题没有上传答案,请作答`);
-        return Promise.resolve(false);
-      }
       const isChoice = question.type === 'single';
       const payload = {
         homeWorkId: this.homework && this.homework.homeWorkId,
@@ -530,8 +548,22 @@ export default {
         this.saving = false;
       });
     },
-    // 最后一题提交
+    // 提交时检查全部题目,有未作答则提示并跳到第一道未作答;全部作答完再提交
     submitAnswer() {
+      if (this.uploading) {
+        this.$message.warning('图片正在上传,请稍候');
+        return;
+      }
+      const unanswered = this.questions
+        .map((item, index) => ({ ...item, index }))
+        .filter(item => !this.isAnswered(item.id));
+      if (unanswered.length) {
+        const nums = unanswered.map(item => item.index + 1).join('、');
+        this.$message.warning(`第${nums}题没有上传答案,请作答`);
+        this.currentIndex = unanswered[0].index;
+        this.persistState();
+        return;
+      }
       this.saveCurrentAnswer(1).then(ok => {
         if (!ok) return;
         this.persistState();
@@ -683,7 +715,7 @@ export default {
           grid-template-columns: repeat(5, 32px);
           gap: 15px;
 
-          /* 未作答蓝框,已作答绿框,当前题蓝底白字;仅展示进度,不可点击跳题 */
+          /* 未作答蓝框,已作答绿框,当前题蓝底白字;点击可跳题 */
           .num_btn {
             display: inline-flex;
             align-items: center;
@@ -697,7 +729,7 @@ export default {
             background: #fff;
             color: #2E64FA;
             font-size: 14px;
-            cursor: default;
+            cursor: pointer;
 
             &.done {
               border-color: #3BA272;
@@ -870,10 +902,13 @@ export default {
               }
             }
 
-            :deep(.el-checkbox__input.is-checked .el-checkbox__inner),
             :deep(.el-checkbox__input.is-focus .el-checkbox__inner) {
+              background-color: #fff;
+              border-color: #2E64FA;
+            }
+
+            :deep(.el-checkbox__input.is-checked .el-checkbox__inner) {
               background-color: #2E64FA;
-              box-shadow: none;
               border-color: #2E64FA;
             }
 

+ 25 - 5
src/views/teachingHomework/homeworkTask/list.vue

@@ -94,6 +94,8 @@
 <script>
 import FiltersItem from '@/components/FiltersItem_ruoyan.vue';
 
+const SUBJECT_STORAGE_KEY = 'teachingHomeworkSubject';
+
 export default {
   name: 'TeachingHomeworkList',
   components: { FiltersItem },
@@ -150,13 +152,30 @@ export default {
         this.total = 0;
         return;
       }
-      // 默认选中第一个科目
-      const first = list[0];
-      this.filtersData[0].value = first.value;
-      this.subjectCode = first.value;
-      this.subjectName = first.label;
+      const saved = this.readSavedSubject();
+      const matched = saved.subjectCode
+        ? list.find(item => item.value === saved.subjectCode)
+        : null;
+      const current = matched || list[0];
+      this.filtersData[0].value = current.value;
+      this.subjectCode = current.value;
+      this.subjectName = current.label;
+      this.saveSubject(current.value, current.label);
       this.fetchList();
     },
+    readSavedSubject() {
+      try {
+        return JSON.parse(sessionStorage.getItem(SUBJECT_STORAGE_KEY) || '{}') || {};
+      } catch (e) {
+        return {};
+      }
+    },
+    saveSubject(subjectCode, subjectName) {
+      sessionStorage.setItem(SUBJECT_STORAGE_KEY, JSON.stringify({
+        subjectCode: subjectCode || '',
+        subjectName: subjectName || '',
+      }));
+    },
     // 兼容接口返回数组或 { subjectData: [] } / { list: [] } 等结构
     extractSubjectList(data) {
       if (Array.isArray(data)) return data;
@@ -173,6 +192,7 @@ export default {
       this.filtersData[0].value = e.value;
       this.subjectCode = e.value;
       this.subjectName = item ? item.label : '';
+      this.saveSubject(this.subjectCode, this.subjectName);
       this.pageNum = 1;
       this.fetchList();
     },

+ 48 - 29
src/views/teachingHomework/homeworkTask/viewAnswer.vue

@@ -75,18 +75,18 @@
               <div class="dock_answer">
                 <span class="dock_label">我的作答:</span>
                 <span v-if="isSingle" class="dock_sub_no">(1)</span>
-                <el-radio-group
+                <el-checkbox-group
                   v-if="isSingle"
                   class="choice_radio"
                   :value="currentUserAnswer"
                   disabled>
-                  <el-radio
+                  <el-checkbox
                     v-for="opt in currentQuestion.options"
                     :key="opt.key"
                     :label="opt.key">
                     {{ opt.key }}
-                  </el-radio>
-                </el-radio-group>
+                  </el-checkbox>
+                </el-checkbox-group>
                 <div v-else class="photo_list">
                   <div
                     class="photo_item"
@@ -117,7 +117,12 @@
               <div class="analysis_row" v-if="hasAnalysis">
                 <span class="analysis_label" >【 答 案 】</span>
                 <div class="analysis_content">
-                  <span v-if="isSingle" class="correct_answer">{{ currentQuestion.correctAnswer }}</span>
+                  <span  class="correct_answer" v-html="currentQuestion.correctAnswer"> </span>
+                </div>
+              </div>
+              <div class="analysis_row" v-if="hasAnalysis" style="margin-top: 0;">
+                <span class="analysis_label" >【 详 解 】</span>
+                <div class="analysis_content">
                   <div class="analysis_text" v-html="currentQuestion.analysis"></div>
                 </div>
               </div>
@@ -181,6 +186,23 @@ function buildOptions(item) {
 }
 
 // 知识点可能是字符串数组,也可能是对象数组,统一收敛成字符串
+// 把接口答案归一化为合法选项 key 数组,兼容 "A,C"、"AC"、"A|C"、["A"] 等格式
+function normalizeChoiceAnswer(value, options) {
+  const validKeys = (options || []).map(opt => opt.key);
+  let keys = [];
+  if (Array.isArray(value)) {
+    keys = value;
+  } else if (value !== null && value !== undefined && String(value).trim() !== '') {
+    keys = String(value).toUpperCase().match(/[A-Z]/g) || [];
+  }
+  const result = [];
+  keys.forEach(key => {
+    const k = String(key);
+    if (validKeys.indexOf(k) !== -1 && result.indexOf(k) === -1) result.push(k);
+  });
+  return result;
+}
+
 function mapKnowledge(list) {
   if (!Array.isArray(list)) return [];
   return list.map(item => {
@@ -293,8 +315,8 @@ export default {
       return this.currentIndex >= this.questions.length - 1;
     },
     currentUserAnswer() {
-      if (!this.currentQuestion || !this.isSingle) return '';
-      return this.currentQuestion.userAnswer || '';
+      if (!this.currentQuestion || !this.isSingle) return [];
+      return normalizeChoiceAnswer(this.currentQuestion.userAnswer, this.currentQuestion.options);
     },
     currentPhotos() {
       if (!this.currentQuestion || this.isSingle) return [];
@@ -799,60 +821,57 @@ export default {
           .choice_radio {
             display: inline-flex;
             align-items: center;
-            height: 20px;
-            gap: 36px;
+            min-height: 20px;
+            gap: 20px;
 
-            :deep(.el-radio) {
+            :deep(.el-checkbox) {
               margin-right: 0 !important;
               height: 20px;
-              line-height: 20px;
               display: inline-flex !important;
               align-items: center;
+              cursor: default;
             }
 
-            :deep(.el-radio__input) {
+            :deep(.el-checkbox__input) {
               display: inline-flex;
               align-items: center;
               height: 16px;
               line-height: 16px;
+              cursor: default;
             }
 
-            :deep(.el-radio__inner) {
+            :deep(.el-checkbox__inner) {
               width: 16px;
               height: 16px;
               border: 1px solid #DCDFE6;
               background: #fff;
+              border-radius: 2px;
+              cursor: default;
 
               &::after {
-                width: 10px;
-                height: 10px;
-                background-color: #2E64FA;
-                border-radius: 50%;
+                top: 1px;
+                left: 5px;
+                width: 3px;
+                height: 8px;
               }
             }
 
-            :deep(.el-radio__input.is-checked .el-radio__inner) {
-              border-color: #2E64FA;
-              background: #fff;
-            }
-
-            :deep(.el-radio__input.is-disabled .el-radio__inner) {
-              background: #fff;
+            :deep(.el-checkbox__input.is-disabled .el-checkbox__inner) {
+              background-color: #fff;
               border-color: #DCDFE6;
-              cursor: default;
             }
 
-            :deep(.el-radio__input.is-disabled.is-checked .el-radio__inner) {
+            :deep(.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner) {
+              background-color: #2E64FA;
               border-color: #2E64FA;
-              background: #fff;
             }
 
-            :deep(.el-radio__input.is-disabled + span.el-radio__label) {
+            :deep(.el-checkbox__input.is-disabled + .el-checkbox__label) {
               color: #333;
               cursor: default;
             }
 
-            :deep(.el-radio__label) {
+            :deep(.el-checkbox__label) {
               display: inline-flex;
               align-items: center;
               height: 20px;

+ 2 - 2
vue.config.js

@@ -23,7 +23,7 @@ module.exports = {
     config.plugin('html').tap(args => {
       args[0].title = "慧教研-大数据精准教学诊断平台";
       return args
-    }) 
+    })  
     // 根据环境配置是否移除 console
     if (process.env.NODE_ENV === 'production') {
       config.optimization.minimizer('terser').tap((args) => {
@@ -105,7 +105,7 @@ module.exports = {
     proxy: {
       "/api": {
         target: "https://index.k12100.net/student/api/",
-        // target: "http://192.168.1.19:47003/api/",//静远本地
+        // target: "http://192.168.1.45:47003/api/",//静远本地
         // target: "https://www.k12100.com/student/api/",
         changeOrigin: true,
         pathRewrite: {