Ver Fonte

预览优化

dsy há 4 dias atrás
pai
commit
3b00aebf10
19 ficheiros alterados com 103 adições e 24 exclusões
  1. 1 1
      .env
  2. 14 6
      src/views/book/courseware/create/components/question/fill/Fill.vue
  3. 1 0
      src/views/book/courseware/preview/CoursewarePreview.vue
  4. 49 7
      src/views/book/courseware/preview/common/PreviewOperation.vue
  5. 3 1
      src/views/book/courseware/preview/components/character/CharacterPreview.vue
  6. 2 0
      src/views/book/courseware/preview/components/character_structure/CharacterStructurePreview.vue
  7. 1 1
      src/views/book/courseware/preview/components/common/PreviewMixin.js
  8. 2 0
      src/views/book/courseware/preview/components/fill/FillPreview.vue
  9. 2 0
      src/views/book/courseware/preview/components/image_text/ImageTextPreview.vue
  10. 2 0
      src/views/book/courseware/preview/components/input/InputPreview.vue
  11. 2 0
      src/views/book/courseware/preview/components/judge/JudgePreview.vue
  12. 2 0
      src/views/book/courseware/preview/components/matching/MatchingPreview.vue
  13. 2 0
      src/views/book/courseware/preview/components/newWord_template/NewWordTemplatePreview.vue
  14. 3 1
      src/views/book/courseware/preview/components/pinyin_base/PinyinBasePreview.vue
  15. 2 0
      src/views/book/courseware/preview/components/record_input/RecordInputPreview.vue
  16. 2 0
      src/views/book/courseware/preview/components/select/SelectPreview.vue
  17. 2 0
      src/views/book/courseware/preview/components/sort/SortPreview.vue
  18. 9 7
      src/views/book/courseware/preview/components/table/TablePreview.vue
  19. 2 0
      src/views/book/courseware/preview/components/voice_matrix/VoiceMatrixPreview.vue

+ 1 - 1
.env

@@ -11,4 +11,4 @@ VUE_APP_BookWebSI = '/GCLSBookWebSI/ServiceInterface'
 VUE_APP_EepServer = '/EEPServer/SI'
 
 #version
-VUE_APP_VERSION = '2026.05.28'
+VUE_APP_VERSION = '2026.06.01'

+ 14 - 6
src/views/book/courseware/create/components/question/fill/Fill.vue

@@ -156,9 +156,6 @@ export default {
   },
   methods: {
     async parsedContentPinyin() {
-      if (!this.isEnable(this.data.property.view_pinyin)) {
-        return;
-      }
       PinyinBuild_OldFormat({
         text: this.data.content,
         is_first_sentence_first_hz_pinyin_first_char_upper_case:
@@ -174,6 +171,10 @@ export default {
     },
     parseRichText() {
       let text_list = this.rich_text_list || [];
+      const preservedAnyOneAnswers = (this.data.answer.answer_list || [])
+        .filter(({ type }) => type === 'any_one')
+        .map(({ value }) => value);
+      const preservedAnyOneState = { index: 0 };
       this.data.answer.answer_list = [];
       const arr = [];
       let totalText = '';
@@ -217,7 +218,7 @@ export default {
             totalRichText = totalRichText.concat(textItem);
           }
         } else {
-          const splitBlocks = this.splitTextItemByUnderline(textItem);
+          const splitBlocks = this.splitTextItemByUnderline(textItem, preservedAnyOneAnswers, preservedAnyOneState);
 
           // 样式标签单独成块会导致 PinyinText 的样式栈断开,需并入紧随其后的文本块。
           if (totalText.length > 0) {
@@ -264,7 +265,13 @@ export default {
 
       return arr;
     },
-    splitTextItemByUnderline(textItem) {
+    /**
+     * 根据文本中的连续下划线分割文本块,并将下划线部分转换为输入块
+     * @param {Object} textItem 富文本中的一个文本项
+     * @param {Array} preservedAnyOneAnswers 预先保存的 any_one 类型答案列表
+     * @param {Object} preservedAnyOneState any_one 答案的当前索引状态
+     */
+    splitTextItemByUnderline(textItem, preservedAnyOneAnswers = [], preservedAnyOneState = { index: 0 }) {
       const text = textItem?.text || '';
       const matcher = /_{3,}/g;
       const blocks = [];
@@ -307,10 +314,11 @@ export default {
           ],
         });
         this.data.answer.answer_list.push({
-          value: '',
+          value: preservedAnyOneAnswers[preservedAnyOneState.index] || '',
           mark,
           type: 'any_one',
         });
+        preservedAnyOneState.index += 1;
 
         lastIndex = end;
         match = matcher.exec(text);

+ 1 - 0
src/views/book/courseware/preview/CoursewarePreview.vue

@@ -1161,6 +1161,7 @@ export default {
   flex-direction: column;
   row-gap: $component-spacing;
   width: 100%;
+  max-width: $courseware-width;
   height: 100%;
   min-height: calc(100vh - 226px);
   padding-top: $courseware-top-padding;

+ 49 - 7
src/views/book/courseware/preview/common/PreviewOperation.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="operation">
+  <div ref="operation" class="operation" :class="{ 'is-wrapped': isWrapped }">
     <!-- 重做 -->
     <div v-show="permissionControl.can_answer" class="button retry" @click="retry()"></div>
     <!-- 判断对错 -->
@@ -34,14 +34,54 @@ export default {
     },
   },
   data() {
-    return {};
+    return {
+      isWrapped: false, // 操作按钮是否换行
+      resizeObserver: null, // 监听操作按钮容器尺寸变化的 ResizeObserver 实例
+    };
   },
   computed: {
     permissionControl() {
       return this.getPermissionControl();
     },
   },
+  mounted() {
+    this.updateWrapState();
+    if (window.ResizeObserver) {
+      this.resizeObserver = new ResizeObserver(() => {
+        this.updateWrapState();
+      });
+      this.resizeObserver.observe(this.$refs.operation);
+    }
+  },
+  updated() {
+    this.updateWrapState();
+  },
+  beforeDestroy() {
+    if (this.resizeObserver) {
+      this.resizeObserver.disconnect();
+      this.resizeObserver = null;
+    }
+  },
   methods: {
+    updateWrapState() {
+      this.$nextTick(() => {
+        const container = this.$refs.operation;
+        if (!container) {
+          this.isWrapped = false;
+          return;
+        }
+
+        const visibleButtons = Array.from(container.children).filter((el) => el.offsetParent !== null); // 获取所有可见的按钮元素
+        if (visibleButtons.length <= 1) {
+          this.isWrapped = false;
+          return;
+        }
+
+        const firstLineTop = visibleButtons[0].offsetTop; // 获取第一行按钮的 offsetTop
+        // 如果有按钮的 offsetTop 与第一行按钮的 offsetTop 不同,说明换行了
+        this.isWrapped = visibleButtons.some((el) => Math.abs(el.offsetTop - firstLineTop) > 1);
+      });
+    },
     showAnswerAnalysis() {
       this.$emit('showAnswerAnalysis');
     },
@@ -59,20 +99,22 @@ export default {
 <style lang="scss" scoped>
 .operation {
   display: flex;
+  flex-wrap: wrap;
+  gap: 8px 12px;
+  align-items: center;
   justify-content: flex-end;
-  height: 40px;
   margin-top: 8px;
 
+  &.is-wrapped {
+    justify-content: flex-start;
+  }
+
   .button {
     width: 90px;
     height: 40px;
     cursor: pointer;
     border-radius: 5px;
 
-    & + .button {
-      margin-left: 24px;
-    }
-
     &.retry {
       background: url('@/assets/component/component-retry.png') no-repeat center;
     }

+ 3 - 1
src/views/book/courseware/preview/components/character/CharacterPreview.vue

@@ -421,10 +421,10 @@
       />
       <PreviewOperation
         v-if="data.property.model === 'miao'"
+        :is-show-answer="isShowAnswers"
         @showAnswerAnalysis="showAnswerAnalysis"
         @judgeCorrect="judgeCorrect"
         @retry="retry"
-        :isShowAnswer="isShowAnswers"
       />
       <AnswerCorrect
         :answer-correct="data?.answer_correct"
@@ -640,6 +640,8 @@ export default {
     retry() {
       this.handleData();
       this.handleWav([]);
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
       this.$refs.record.handleReset();
     },
     /**

+ 2 - 0
src/views/book/courseware/preview/components/character_structure/CharacterStructurePreview.vue

@@ -400,6 +400,8 @@ export default {
     },
     // 重做
     retry() {
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
       this.handleData([]);
     },
     /**

+ 1 - 1
src/views/book/courseware/preview/components/common/PreviewMixin.js

@@ -148,7 +148,7 @@ const mixin = {
       if (userAnswer) this.answer = userAnswer;
     },
     judgeCorrect() {
-      this.isJudgingRightWrong = !this.isJudgingRightWrong;
+      this.isJudgingRightWrong = true;
       this.isShowRightAnswer = false;
     },
     /**

+ 2 - 0
src/views/book/courseware/preview/components/fill/FillPreview.vue

@@ -404,6 +404,8 @@ export default {
         }
       });
       this.selectedWordList = [];
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
       this.handleWav([]);
     },
     /**

+ 2 - 0
src/views/book/courseware/preview/components/image_text/ImageTextPreview.vue

@@ -289,6 +289,8 @@ export default {
     },
     // 重做
     retry() {
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
       this.initData();
     },
     /**

+ 2 - 0
src/views/book/courseware/preview/components/input/InputPreview.vue

@@ -108,6 +108,8 @@ export default {
       };
     },
     retry() {
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
       this.data.answer.text = '';
     },
   },

+ 2 - 0
src/views/book/courseware/preview/components/judge/JudgePreview.vue

@@ -216,6 +216,8 @@ export default {
       return isCorrectType ? 'answer-right' : '';
     },
     retry() {
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
       this.answer.answer_list = [];
     },
 

+ 2 - 0
src/views/book/courseware/preview/components/matching/MatchingPreview.vue

@@ -519,6 +519,8 @@ export default {
       return isRight ? 'right' : 'wrong';
     },
     retry() {
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
       this.clearLine();
       this.$set(
         this,

+ 2 - 0
src/views/book/courseware/preview/components/newWord_template/NewWordTemplatePreview.vue

@@ -556,6 +556,8 @@ export default {
     },
     // 重做
     retry() {
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
       this.handleData();
       if (this.$refs.editDiv) {
         if (this.$refs.editDiv.length > 0) {

+ 3 - 1
src/views/book/courseware/preview/components/pinyin_base/PinyinBasePreview.vue

@@ -148,10 +148,10 @@
           data.property.fun_type !== 'show' ||
           (data.property.fun_type === 'show' && isEnable(data.property.is_enable_voice_answer))
         "
+        :is-show-answer="isShowAnswers"
         @showAnswerAnalysis="showAnswerAnalysis"
         @judgeCorrect="judgeCorrect"
         @retry="retry"
-        :isShowAnswer="isShowAnswers"
       />
       <AnswerCorrect
         :answer-correct="data?.answer_correct"
@@ -768,6 +768,8 @@ export default {
     },
     // 重做
     retry() {
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
       this.handleData();
       if (this.data.property.fun_type !== 'mark' && this.isEnable(this.data.property.is_enable_voice_answer)) {
         this.$refs.record.handleReset();

+ 2 - 0
src/views/book/courseware/preview/components/record_input/RecordInputPreview.vue

@@ -102,6 +102,8 @@ export default {
     },
     // 重做
     retry() {
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
       this.data.answer.answer_list.input = '';
       this.data.answer.answer_list.answer_record_list = [];
       this.$refs.record.handleReset();

+ 2 - 0
src/views/book/courseware/preview/components/select/SelectPreview.vue

@@ -191,6 +191,8 @@ export default {
     },
 
     retry() {
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
       this.answer.answer_list = [];
     },
 

+ 2 - 0
src/views/book/courseware/preview/components/sort/SortPreview.vue

@@ -203,6 +203,8 @@ export default {
           : optionList.sort(() => Math.random() - 0.5);
       this.answer.answer_list = [];
       this.is_all_right = false;
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
     },
 
     /**

+ 9 - 7
src/views/book/courseware/preview/components/table/TablePreview.vue

@@ -203,7 +203,7 @@
                           <!-- 换行符 -->
                           <br v-else-if="item.type === 'newline'" :key="'newline-' + index" />
 
-                          <!-- 
+                          <!--
                         <template v-else>
                           <span v-if="data.property.pinyin_position === 'top'" class="pinyin">
                             {{ item.pinyin.replace(/\s+/g, '') }}
@@ -294,14 +294,14 @@
 
                   <i
                     v-if="col.cell.isCross"
-                    @click="toggle(col)"
                     :class="[
                       { 'el-icon-check': col.crossAnswer === statusList[1] },
                       { 'el-icon-close': col.crossAnswer === statusList[2] },
                       ...computedAnswerCrossClass(col, i, j),
                     ]"
                     :style="{ display: 'block', width: '18px', height: '18px', border: '1px solid #000' }"
-                  />
+                    @click="toggle(col)"
+                  ></i>
                 </div>
                 <span v-if="showLang" class="multilingual" :style="[tdStyle, computedRichStyle(col.content)]">
                   {{
@@ -318,10 +318,10 @@
         </table>
       </div>
       <PreviewOperation
+        v-if="isHasInput"
         @showAnswerAnalysis="showAnswerAnalysis"
         @judgeCorrect="judgeCorrect"
         @retry="retry"
-        v-if="isHasInput"
       />
       <AnswerCorrect
         :answer-correct="data?.answer_correct"
@@ -431,9 +431,9 @@
                                 <template v-else-if="word.type === 'input'">
                                   <span v-if="data.property.pinyin_position === 'top'" class="pinyin">&nbsp;</span>
                                   <span
+                                    v-show="computedAnswerText(word, i, j).length > 0"
                                     :key="`answer-${j}`"
                                     class="right-answer"
-                                    v-show="computedAnswerText(word, i, j).length > 0"
                                   >
                                     {{ convertText(computedAnswerText(word, i, j)) }}
                                   </span>
@@ -567,9 +567,9 @@
                           </template> -->
 
                             <span
+                              v-show="computedAnswerText(item, i, j).length > 0"
                               :key="`answer-${j}`"
                               class="right-answer"
-                              v-show="computedAnswerText(item, i, j).length > 0"
                             >
                               {{ convertText(computedAnswerText(item, i, j)) }}
                             </span>
@@ -584,7 +584,7 @@
                         { 'el-icon-close': data.answer_lists[i][j].crossAnswer === statusList[2] },
                       ]"
                       style="display: block; width: 18px; height: 18px; border: 1px solid #30a47d"
-                    />
+                    ></i>
                   </div>
                   <span v-if="showLang" class="multilingual" :style="[tdStyle, computedRichStyle(col.content)]">
                     {{
@@ -1254,6 +1254,8 @@ export default {
           this.$refs.record.handleReset();
         }
       }
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
     },
     /**
      * 获取无文本内容的数据结构,用于保存为个人模板时的样式模板

+ 2 - 0
src/views/book/courseware/preview/components/voice_matrix/VoiceMatrixPreview.vue

@@ -590,6 +590,8 @@ export default {
       this.matrixSelectLrc = null;
       this.data.record_list = [];
       this.$refs.luyin?.handleReset();
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
     },
 
     /**