Ver código fonte

Merge branch 'master' of http://gcls-git.helxsoft.cn/GCLS/eep_page

zq 2 dias atrás
pai
commit
287c4387c3
22 arquivos alterados com 277 adições e 65 exclusões
  1. 1 1
      .env
  2. 23 3
      src/components/PinyinText.vue
  3. 4 1
      src/views/book/courseware/create/components/question/article/CheckStyle.vue
  4. 100 31
      src/views/book/courseware/create/components/question/fill/Fill.vue
  5. 1 0
      src/views/book/courseware/preview/CoursewarePreview.vue
  6. 54 8
      src/views/book/courseware/preview/common/PreviewOperation.vue
  7. 5 1
      src/views/book/courseware/preview/components/character/CharacterPreview.vue
  8. 4 1
      src/views/book/courseware/preview/components/character_structure/CharacterStructurePreview.vue
  9. 1 1
      src/views/book/courseware/preview/components/common/PreviewMixin.js
  10. 21 1
      src/views/book/courseware/preview/components/fill/FillPreview.vue
  11. 9 1
      src/views/book/courseware/preview/components/image_text/ImageTextPreview.vue
  12. 9 1
      src/views/book/courseware/preview/components/input/InputPreview.vue
  13. 3 1
      src/views/book/courseware/preview/components/judge/JudgePreview.vue
  14. 3 1
      src/views/book/courseware/preview/components/matching/MatchingPreview.vue
  15. 4 1
      src/views/book/courseware/preview/components/newWord_template/NewWordTemplatePreview.vue
  16. 5 1
      src/views/book/courseware/preview/components/pinyin_base/PinyinBasePreview.vue
  17. 4 0
      src/views/book/courseware/preview/components/record_input/RecordInputPreview.vue
  18. 2 0
      src/views/book/courseware/preview/components/select/SelectPreview.vue
  19. 2 0
      src/views/book/courseware/preview/components/sort/SortPreview.vue
  20. 15 7
      src/views/book/courseware/preview/components/table/TablePreview.vue
  21. 3 1
      src/views/book/courseware/preview/components/voice_matrix/VoiceMatrixPreview.vue
  22. 4 3
      src/views/personal_workbench/project/ProductionEditorialManage.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.02'

+ 23 - 3
src/components/PinyinText.vue

@@ -33,7 +33,7 @@
                   'align-items': getWordAlignItems(word, block),
                 }"
               >
-                <span class="pinyin" :style="getPinyinStyle(word)"> {{ getPinyinText(word) }}</span>
+                <span class="pinyin" :style="getPinyinStyle(word, block)"> {{ getPinyinText(word) }}</span>
                 <span class="py-char" :style="getCharStyle(word, block)">{{ convertText(word.text) }}</span>
               </span>
               <template v-else>
@@ -44,7 +44,7 @@
                       'align-items': getWordAlignItems(word, block),
                     }"
                   >
-                    <span class="pinyin" :style="getPinyinStyle(word)"> {{ getCharPinyin(word, cIndex) }}</span>
+                    <span class="pinyin" :style="getPinyinStyle(word, block)"> {{ getCharPinyin(word, cIndex) }}</span>
                     <span class="py-char" :style="getCharStyle(word, block, cIndex)">{{ convertText(char) }}</span>
                   </span>
                 </span>
@@ -606,6 +606,7 @@ export default {
         oldIndex,
         paragraphIndex,
         styleObj,
+        rawStyleText: combinedStyle,
         hasEmphasisDot,
       };
     },
@@ -619,12 +620,26 @@ export default {
       return styleObj;
     },
 
+    getBlockColor(block) {
+      const colorFromObject = block?.styleObj?.color;
+      if (colorFromObject) return colorFromObject;
+
+      const styleText = block?.rawStyleText || '';
+      const colorMatch = styleText.match(/(?:^|;)\s*color\s*:\s*([^;]+)/i);
+      return colorMatch ? colorMatch[1].trim() : '';
+    },
+
     // 获取单个字符的样式(包括着重点)
     getCharStyle(word, block) {
       const baseStyle = { ...word.activeTextStyle };
       baseStyle['font-size'] = baseStyle.fontSize;
       baseStyle['font-family'] = baseStyle.fontFamily;
 
+      const blockColor = this.getBlockColor(block);
+      if (blockColor) {
+        baseStyle.color = `${blockColor} !important`;
+      }
+
       if (this.isAllSetting) {
         baseStyle['font-size'] = this.fontSize;
         baseStyle['font-family'] = this.fontFamily;
@@ -673,7 +688,7 @@ export default {
       return 'center';
     },
     // 拼音固定为拼音字体,跟随汉字的字号、颜色、粗细的样式
-    getPinyinStyle(item) {
+    getPinyinStyle(item, block) {
       const styles = {};
 
       // 固定使用 League 字体
@@ -689,6 +704,11 @@ export default {
         }
       }
 
+      const blockColor = this.getBlockColor(block);
+      if (blockColor) {
+        styles['color'] = `${blockColor} !important`;
+      }
+
       // 如果设置了全局字号,优先使用全局字号
       if (this.isAllSetting && this.fontSize) {
         styles['font-size'] = this.fontSize;

+ 4 - 1
src/views/book/courseware/create/components/question/article/CheckStyle.vue

@@ -38,7 +38,10 @@
                 :class="[/^[0-9]*$/.test(items.text)] ? (/^[\u4e00-\u9fa5]/.test(items.text) ? 'hanzi' : 'en') : ''"
                 :style="{
                   fontFamily: items.fontFamily,
-                  color: items.color,
+                  color:
+                    batchList.findIndex((itemss) => itemss.saveIndex === items.saveIndex) > -1
+                      ? '#F2555A'
+                      : items.color,
                   textDecoration: items.textDecoration,
                   borderBottom: items.border === 'dotted' ? '1px dotted' : '',
                   fontWeight: items.fontWeight,

+ 100 - 31
src/views/book/courseware/create/components/question/fill/Fill.vue

@@ -88,6 +88,7 @@
             ref="PinyinText"
             :rich-text-list="item.rich_text_list"
             :pinyin-position="data.property.pinyin_position"
+            :body-styles="getBodyStyles()"
             @fillCorrectPinyin="fillCorrectPinyin($event, i, -1, 'model_essay')"
           />
         </div>
@@ -156,9 +157,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,14 +172,19 @@ 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 = '';
       let totalRichText = [];
+      const openStyleTagStack = [];
       for (let i = 0; i < text_list.length; i++) {
         const textItem = text_list[i];
         const text = textItem.text || '';
-        const isStyle = textItem.is_style === 'true';
+        const isStyle = textItem.is_style === 'true' || textItem.is_style === true;
         if (isStyle) {
           const isRichFill = /class=\s*(\\?["'])rich-fill\1/.test(text);
           if (isRichFill) {
@@ -215,37 +218,39 @@ export default {
           } else {
             totalText += text;
             totalRichText = totalRichText.concat(textItem);
+            this.syncOpenStyleTagStack(openStyleTagStack, textItem);
           }
         } else {
-          const splitBlocks = this.splitTextItemByUnderline(textItem);
+          const splitBlocks = this.splitTextItemByUnderline(textItem, preservedAnyOneAnswers, preservedAnyOneState);
+
+          const currentOpenStyleTags = openStyleTagStack.map((tagItem) => ({ ...tagItem }));
+          const firstBlockPrefix =
+            totalText.length > 0
+              ? this.buildFirstBlockStylePrefix(totalRichText, currentOpenStyleTags)
+              : currentOpenStyleTags;
 
           // 样式标签单独成块会导致 PinyinText 的样式栈断开,需并入紧随其后的文本块。
-          if (totalText.length > 0) {
-            if (splitBlocks.length > 0) {
+          if (splitBlocks.length > 0) {
+            if (totalText.length > 0) {
               splitBlocks[0].content = `${totalText}${splitBlocks[0].content || ''}`;
-              const inheritedOpenStyleTags = totalRichText.filter((tagItem) => {
-                const tagText = tagItem?.text || '';
-                const isStyleTag = tagItem?.is_style === 'true' || tagItem?.is_style === true;
-                if (!isStyleTag) return false;
-                if (/^<\//.test(tagText)) return false;
-                if (/^<br\s*\/?\s*>$/i.test(tagText)) return false;
-                return /^<\w+[^>]*>$/.test(tagText);
-              });
-
-              splitBlocks.forEach((block, blockIndex) => {
-                const prevRichTextList = block.rich_text_list || [];
-                block.rich_text_list = [
-                  ...(blockIndex === 0 ? totalRichText : inheritedOpenStyleTags),
-                  ...prevRichTextList,
-                ];
-              });
-            } else {
-              arr.push({
-                content: totalText,
-                type: 'text',
-                rich_text_list: totalRichText,
-              });
             }
+
+            splitBlocks.forEach((block, blockIndex) => {
+              const prevRichTextList = block.rich_text_list || [];
+              block.rich_text_list = [
+                ...(blockIndex === 0 ? firstBlockPrefix : currentOpenStyleTags),
+                ...prevRichTextList,
+              ];
+            });
+
+            totalText = '';
+            totalRichText = [];
+          } else if (totalText.length > 0) {
+            arr.push({
+              content: totalText,
+              type: 'text',
+              rich_text_list: firstBlockPrefix,
+            });
             totalText = '';
             totalRichText = [];
           }
@@ -264,7 +269,66 @@ export default {
 
       return arr;
     },
-    splitTextItemByUnderline(textItem) {
+    getStyleTagName(tagText = '') {
+      const trimmedText = String(tagText).trim();
+      const closeMatch = trimmedText.match(/^<\/(\w+)>$/);
+      if (closeMatch) return closeMatch[1].toLowerCase();
+
+      const openMatch = trimmedText.match(/^<(\w+)([^>]*)>$/);
+      if (openMatch) return openMatch[1].toLowerCase();
+
+      return '';
+    },
+    isOpenStyleTag(tagItem = {}) {
+      const tagText = String(tagItem?.text || '').trim();
+      const isStyleTag = tagItem?.is_style === 'true' || tagItem?.is_style === true;
+      if (!isStyleTag) return false;
+      if (/^<\//.test(tagText)) return false;
+      if (/^<br\s*\/?\s*>$/i.test(tagText)) return false;
+      return /^<\w+[^>]*>$/.test(tagText);
+    },
+    syncOpenStyleTagStack(openStyleTagStack, styleTagItem) {
+      const tagText = String(styleTagItem?.text || '').trim();
+      const isStyleTag = styleTagItem?.is_style === 'true' || styleTagItem?.is_style === true;
+      if (!isStyleTag) return;
+      if (/^<br\s*\/?\s*>$/i.test(tagText)) return;
+
+      const closeMatch = tagText.match(/^<\/(\w+)>$/);
+      if (closeMatch) {
+        const closeTagName = closeMatch[1].toLowerCase();
+        for (let i = openStyleTagStack.length - 1; i >= 0; i--) {
+          const tagName = this.getStyleTagName(openStyleTagStack[i]?.text);
+          if (tagName === closeTagName) {
+            openStyleTagStack.splice(i, 1);
+            break;
+          }
+        }
+        return;
+      }
+
+      if (this.isOpenStyleTag(styleTagItem)) {
+        openStyleTagStack.push(styleTagItem);
+      }
+    },
+    buildFirstBlockStylePrefix(transitionStyleTags = [], currentOpenStyleTags = []) {
+      const transitionOpenTagNames = transitionStyleTags
+        .filter((tagItem) => this.isOpenStyleTag(tagItem))
+        .map((tagItem) => this.getStyleTagName(tagItem?.text));
+
+      const missingOpenTags = currentOpenStyleTags.filter((tagItem) => {
+        const tagName = this.getStyleTagName(tagItem?.text);
+        return tagName && !transitionOpenTagNames.includes(tagName);
+      });
+
+      return [...missingOpenTags, ...transitionStyleTags];
+    },
+    /**
+     * 根据文本中的连续下划线分割文本块,并将下划线部分转换为输入块
+     * @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 +371,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);
@@ -612,6 +677,10 @@ export default {
     removeWord(index) {
       this.data.word_list.splice(index, 1);
     },
+    getBodyStyles() {
+      if (!this.$refs.richText) return {};
+      return this.$refs.richText.getBodyInitialStyles();
+    },
   },
 };
 </script>

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

@@ -1159,6 +1159,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;

+ 54 - 8
src/views/book/courseware/preview/common/PreviewOperation.vue

@@ -1,9 +1,13 @@
 <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>
     <!-- 判断对错 -->
-    <div v-show="permissionControl.can_judge_correct" class="button correct" @click="judgeCorrect"></div>
+    <div
+      v-show="permissionControl.can_judge_correct && isShowAnswer"
+      class="button correct"
+      @click="judgeCorrect"
+    ></div>
     <!-- 查看答案 -->
     <div
       v-show="permissionControl.can_show_answer && isShowAnswer"
@@ -34,14 +38,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 +103,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;
     }

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

@@ -421,13 +421,15 @@
       />
       <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"
         :visible.sync="visibleAnswerCorrect"
+        :is-check-correct="isCheckCorrect"
         @closeAnswerCorrect="closeAnswerCorrect"
       />
       <AnswerAnalysis
@@ -638,6 +640,8 @@ export default {
     retry() {
       this.handleData();
       this.handleWav([]);
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
       this.$refs.record.handleReset();
     },
     /**

+ 4 - 1
src/views/book/courseware/preview/components/character_structure/CharacterStructurePreview.vue

@@ -161,10 +161,11 @@
           </div>
         </div>
       </div>
-      <PreviewOperation @showAnswerAnalysis="showAnswerAnalysis" @retry="retry" />
+      <PreviewOperation @showAnswerAnalysis="showAnswerAnalysis" @judgeCorrect="judgeCorrect" @retry="retry" />
       <AnswerCorrect
         :answer-correct="data?.answer_correct"
         :visible.sync="visibleAnswerCorrect"
+        :is-check-correct="isCheckCorrect"
         @closeAnswerCorrect="closeAnswerCorrect"
       />
       <AnswerAnalysis
@@ -399,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;
     },
     /**

+ 21 - 1
src/views/book/courseware/preview/components/fill/FillPreview.vue

@@ -20,6 +20,7 @@
                 :paragraph-list="li.paragraph_list"
                 :rich-text-list="li.rich_text_list"
                 :pinyin-position="data.property.pinyin_position"
+                :body-styles="getBodyStyles()"
                 :is-preview="true"
               />
               <span v-else :key="`text-${i}`" class="html-content" v-html="renderTextBlockContent(li)"></span>
@@ -109,10 +110,10 @@
       <div v-if="showLang" class="lang">
         {{ data.multilingual.find((item) => item.type === getLang())?.translation }}
       </div>
+      <PreviewOperation @showAnswerAnalysis="showAnswerAnalysis" @judgeCorrect="judgeCorrect" @retry="retry" />
     </div>
 
     <WriteDialog :visible.sync="writeVisible" @confirm="handleWriteConfirm" />
-    <PreviewOperation @showAnswerAnalysis="showAnswerAnalysis" @judgeCorrect="judgeCorrect" @retry="retry" />
     <AnswerCorrect
       :visible.sync="visibleAnswerCorrect"
       :is-check-correct="isCheckCorrect"
@@ -404,6 +405,8 @@ export default {
         }
       });
       this.selectedWordList = [];
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
       this.handleWav([]);
     },
     /**
@@ -475,6 +478,23 @@ export default {
 
       this.$set(this.inputWidthMap, mark, nextWidth);
     },
+    getBodyStyles() {
+      const styles = {};
+      const unifiedAttrib = this.data?.unified_attrib || {};
+
+      // 从统一属性中获取样式
+      if (unifiedAttrib.font) {
+        styles['font-family'] = unifiedAttrib.font;
+      }
+      if (unifiedAttrib.font_size) {
+        styles['font-size'] = unifiedAttrib.font_size;
+      }
+      if (unifiedAttrib.text_color) {
+        styles['color'] = unifiedAttrib.text_color;
+      }
+
+      return styles;
+    },
   },
 };
 </script>

+ 9 - 1
src/views/book/courseware/preview/components/image_text/ImageTextPreview.vue

@@ -58,10 +58,16 @@
         />
       </div>
     </div>
-    <PreviewOperation v-if="data.input_list.length > 0" @showAnswerAnalysis="showAnswerAnalysis" @retry="retry" />
+    <PreviewOperation
+      v-if="data.input_list.length > 0"
+      @showAnswerAnalysis="showAnswerAnalysis"
+      @judgeCorrect="judgeCorrect"
+      @retry="retry"
+    />
     <AnswerCorrect
       :answer-correct="data?.answer_correct"
       :visible.sync="visibleAnswerCorrect"
+      :is-check-correct="isCheckCorrect"
       @closeAnswerCorrect="closeAnswerCorrect"
     />
     <AnswerAnalysis
@@ -283,6 +289,8 @@ export default {
     },
     // 重做
     retry() {
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
       this.initData();
     },
     /**

+ 9 - 1
src/views/book/courseware/preview/components/input/InputPreview.vue

@@ -28,7 +28,13 @@
       </div>
     </div>
 
-    <PreviewOperation @showAnswerAnalysis="showAnswerAnalysis" @judgeCorrect="judgeCorrect" @retry="retry" />
+    <div></div>
+    <PreviewOperation
+      :is-show-answer="false"
+      @showAnswerAnalysis="showAnswerAnalysis"
+      @judgeCorrect="judgeCorrect"
+      @retry="retry"
+    />
     <AnswerCorrect
       :answer-correct="data?.answer_correct"
       :visible.sync="visibleAnswerCorrect"
@@ -108,6 +114,8 @@ export default {
       };
     },
     retry() {
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
       this.data.answer.text = '';
     },
   },

+ 3 - 1
src/views/book/courseware/preview/components/judge/JudgePreview.vue

@@ -60,9 +60,9 @@
           </div>
         </li>
       </ul>
+      <PreviewOperation @showAnswerAnalysis="showAnswerAnalysis" @judgeCorrect="judgeCorrect" @retry="retry" />
     </div>
 
-    <PreviewOperation @showAnswerAnalysis="showAnswerAnalysis" @judgeCorrect="judgeCorrect" @retry="retry" />
     <AnswerCorrect
       :answer-correct="data?.answer_correct"
       :visible.sync="visibleAnswerCorrect"
@@ -216,6 +216,8 @@ export default {
       return isCorrectType ? 'answer-right' : '';
     },
     retry() {
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
       this.answer.answer_list = [];
     },
 

+ 3 - 1
src/views/book/courseware/preview/components/matching/MatchingPreview.vue

@@ -38,9 +38,9 @@
           </template>
         </li>
       </ul>
+      <PreviewOperation @showAnswerAnalysis="showAnswerAnalysis" @judgeCorrect="judgeCorrect" @retry="retry" />
     </div>
 
-    <PreviewOperation @showAnswerAnalysis="showAnswerAnalysis" @judgeCorrect="judgeCorrect" @retry="retry" />
     <AnswerCorrect
       :answer-correct="data?.answer_correct"
       :visible.sync="visibleAnswerCorrect"
@@ -519,6 +519,8 @@ export default {
       return isRight ? 'right' : 'wrong';
     },
     retry() {
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
       this.clearLine();
       this.$set(
         this,

+ 4 - 1
src/views/book/courseware/preview/components/newWord_template/NewWordTemplatePreview.vue

@@ -216,10 +216,11 @@
         </div>
       </div>
     </div>
-    <PreviewOperation @showAnswerAnalysis="showAnswerAnalysis" @retry="retry" />
+    <PreviewOperation @showAnswerAnalysis="showAnswerAnalysis" @judgeCorrect="judgeCorrect" @retry="retry" />
     <AnswerCorrect
       :answer-correct="data?.answer_correct"
       :visible.sync="visibleAnswerCorrect"
+      :is-check-correct="isCheckCorrect"
       @closeAnswerCorrect="closeAnswerCorrect"
     />
     <AnswerAnalysis
@@ -555,6 +556,8 @@ export default {
     },
     // 重做
     retry() {
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
       this.handleData();
       if (this.$refs.editDiv) {
         if (this.$refs.editDiv.length > 0) {

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

@@ -148,13 +148,15 @@
           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"
         :visible.sync="visibleAnswerCorrect"
+        :is-check-correct="isCheckCorrect"
         @closeAnswerCorrect="closeAnswerCorrect"
       />
       <AnswerAnalysis
@@ -766,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();

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

@@ -31,11 +31,13 @@
         :is-show-answer="isShowAnswers"
         :is-show-retry="isEnable(data.is_enable_input)"
         @showAnswerAnalysis="showAnswerAnalysis"
+        @judgeCorrect="judgeCorrect"
         @retry="retry"
       />
       <AnswerCorrect
         :answer-correct="data?.answer_correct"
         :visible.sync="visibleAnswerCorrect"
+        :is-check-correct="isCheckCorrect"
         @closeAnswerCorrect="closeAnswerCorrect"
       />
       <AnswerAnalysis
@@ -100,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;
     },
 
     /**

+ 15 - 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)]">
                   {{
@@ -317,10 +317,16 @@
           </tr>
         </table>
       </div>
-      <PreviewOperation @showAnswerAnalysis="showAnswerAnalysis" @retry="retry" v-if="isHasInput" />
+      <PreviewOperation
+        v-if="isHasInput"
+        @showAnswerAnalysis="showAnswerAnalysis"
+        @judgeCorrect="judgeCorrect"
+        @retry="retry"
+      />
       <AnswerCorrect
         :answer-correct="data?.answer_correct"
         :visible.sync="visibleAnswerCorrect"
+        :is-check-correct="isCheckCorrect"
         @closeAnswerCorrect="closeAnswerCorrect"
       />
       <AnswerAnalysis
@@ -425,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>
@@ -561,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>
@@ -578,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)]">
                     {{
@@ -1248,6 +1254,8 @@ export default {
           this.$refs.record.handleReset();
         }
       }
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
     },
     /**
      * 获取无文本内容的数据结构,用于保存为个人模板时的样式模板

+ 3 - 1
src/views/book/courseware/preview/components/voice_matrix/VoiceMatrixPreview.vue

@@ -206,9 +206,9 @@
           @playing="playChange"
         />
       </div>
+      <PreviewOperation @showAnswerAnalysis="showAnswerAnalysis" @judgeCorrect="judgeCorrect" @retry="retry" />
     </div>
 
-    <PreviewOperation @showAnswerAnalysis="showAnswerAnalysis" @judgeCorrect="judgeCorrect" @retry="retry" />
     <AnswerCorrect
       :answer-correct="data?.answer_correct"
       :visible.sync="visibleAnswerCorrect"
@@ -590,6 +590,8 @@ export default {
       this.matrixSelectLrc = null;
       this.data.record_list = [];
       this.$refs.luyin?.handleReset();
+      this.isJudgingRightWrong = false;
+      this.isShowRightAnswer = false;
     },
 
     /**

+ 4 - 3
src/views/personal_workbench/project/ProductionEditorialManage.vue

@@ -13,8 +13,9 @@
           </span>
         </div>
         <span class="link" @click="visibleAuditSteps = true">设置审核步骤</span>
-        <div class="member-list">{{ member_list.map((member) => member.name).join(';') }}</div>
-        <span class="link" @click="selectMembers">修改</span>
+        <span class="line"></span>
+        <div class="member-list">项目成员:{{ member_list.map((member) => member.name).join(';') }}</div>
+        <span class="link" @click="selectMembers">设置项目成员</span>
         <div class="operator flex">
           <span class="link" @click="openBookUnifiedTitle()">教材标题设置</span>
           <span class="link" @click="openBookUnifiedAttrib()">教材样式设置</span>
@@ -175,7 +176,7 @@
     <BookUnifiedTitle :visible.sync="visibleTitle" :book-id="book_id" />
     <SelectMembers
       :visible.sync="visibleMembers"
-      title="选择项目成员"
+      title="设置项目成员"
       :selected-list="memberInfoList"
       type="member"
       @confirm="handleSelectedMembers"