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

1、填空题 br 换行问题修改 2、背景图设置问题 3、可以拖拽分隔组件

dsy преди 2 дни
родител
ревизия
96ccbc1545

+ 1 - 1
.env

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

+ 9 - 0
src/components/CommonPreview.vue

@@ -856,6 +856,15 @@ export default {
           if (background) {
             this.background = JSON.parse(background);
             this.$emit('updateBackground', this.background);
+          } else {
+            this.background = {
+              background_image_url: '',
+              background_position: {
+                left: 0,
+                top: 0,
+              },
+              background: {},
+            };
           }
 
           if (content) {

+ 9 - 8
src/views/book/courseware/create/components/CreateCanvas.vue

@@ -757,7 +757,7 @@ export default {
 
       // 上下移动
       if (['top', 'bottom'].includes(type)) {
-        this.handleVerticalMove(col, grid, offsetY, id, min_height);
+        this.handleVerticalMove({ grid, offsetY, id, min_height, type });
         return;
       }
 
@@ -791,13 +791,13 @@ export default {
 
     /**
      * 处理垂直移动
-     * @param {number} col 列数据
-     * @param {object} grid 格子数据
-     * @param {number} offsetY y 轴偏移量
-     * @param {string} id 组件 id
-     * @param {number} min_height 最小高度
+     * @param {object} data 移动数据
+     * @param {object} data.grid 格子数据
+     * @param {number} data.offsetY y 轴偏移量
+     * @param {string} data.id 组件 id
+     * @param {number} data.min_height 最小高度
      */
-    handleVerticalMove(col, grid, offsetY, id, min_height = 0) {
+    handleVerticalMove({ grid, offsetY, id, min_height = 0, type }) {
       let height = 0;
       const _h = this.isEdit ? grid?.edit_height : grid.height;
 
@@ -813,8 +813,9 @@ export default {
         const gridHeight = Number(h?.replace('px', ''));
         height = gridHeight + offsetY;
       }
+      let minHeight = type === 'divider' ? 10 : min_height;
       // 当高度小于最小高度时,设置为最小高度
-      height = Math.max(height, min_height, 50);
+      height = Math.max(height, min_height, minHeight);
 
       if (this.isEdit) {
         grid.edit_height = `${height}px`;

+ 1 - 1
src/views/book/courseware/create/components/PreviewEdit.vue

@@ -107,7 +107,7 @@ export default {
       ],
       dragElement: null, // 当前拖拽的组件实例
       // 不需要移动的组件
-      noMoveComponent: ['divider', 'spacing'],
+      noMoveComponent: ['spacing'],
       bookInfo: {
         theme_color: '',
       },

+ 1 - 1
src/views/book/courseware/create/components/SetBackground.vue

@@ -648,7 +648,7 @@ export default {
           throw new Error('upload failed');
         }
 
-        this.file_url = file_info_list[0].file_url;
+        this.file_url = file_info_list[0].file_url_open;
         this.normalComputed(safeWidth, safeHeight);
         this.cancelRectCrop();
         this.$message.success('裁切成功');

+ 39 - 8
src/views/book/courseware/create/components/question/fill/Fill.vue

@@ -14,7 +14,7 @@
           :font-size="data?.unified_attrib?.font_size"
           :font-family="data?.unified_attrib?.font"
           :font-color="data?.unified_attrib?.text_color"
-          @handleRichTextBlur="identifyText"
+          @handleRichTextBlur="identifyText(false)"
         />
         <div v-if="data.property.fill_type === fillTypeList[1].value" class="select-vocabulary">
           <h5 class="title">选词列表:</h5>
@@ -70,7 +70,17 @@
         </div>
       </div>
 
-      <el-divider v-if="isEnable(data.property.view_pinyin)" content-position="left">拼音效果</el-divider>
+      <el-divider v-if="isEnable(data.property.view_pinyin)" content-position="left">
+        <span>拼音效果</span>
+        <el-button
+          v-show="isEnable(data.property.view_pinyin)"
+          type="text"
+          icon="el-icon-refresh"
+          title="刷新"
+          class="refresh-pinyin-btn"
+          @click.native="handleViewPinyin"
+        />
+      </el-divider>
       <template v-if="isEnable(data.property.view_pinyin)">
         <div v-for="(item, i) in data.model_essay" :key="i" class="pinyin-text-list">
           <template v-for="(li, j) in item">
@@ -146,8 +156,11 @@ export default {
     },
   },
   methods: {
-    // 识别文本
-    identifyText() {
+    /**
+     * 识别文本中
+     * @param {Boolean} isUpdatePinyin 是否更新拼音,默认为 true
+     */
+    identifyText(isUpdatePinyin = true) {
       this.data.answer.answer_list = [];
       const content = this.data.content || '';
 
@@ -166,7 +179,7 @@ export default {
         return;
       }
 
-      const splitSource = content.split('\n').map((item) => {
+      const splitSource = content.split(/\n|<br>/).map((item) => {
         // rich-fill 和 ___ 均转为统一占位符,交给 splitRichText 处理
         return this.splitRichText(
           item.replace(/<span[^>]*class="[^"]*rich-fill[^"]*"[^>]*>.*?<\/span>|_{3,}/gi, '###$&###'),
@@ -175,7 +188,7 @@ export default {
 
       this.data.model_essay = splitSource;
 
-      this.handleViewPinyin();
+      if (isUpdatePinyin) this.handleViewPinyin();
     },
     /**
      * 分割富文本
@@ -249,14 +262,32 @@ export default {
      * @returns {String} 包含向前两个标签内容中最后一个html标签的内容
      */
     setTag(index, parts, content) {
-      if (index < 2) return content;
+      let i = index;
+      if (i < 2) return content;
       let _content = content;
       const isEndWithTag = /<\/[^>]+>$/.test(_content); // 判断是否以标签结尾
       let startTag = '';
-      const part = parts[index - 2] ?? '';
+      const part = parts[i - 2] ?? '';
+
       const tagMatch = part.match(/<[^>]+>/g);
       if (tagMatch) {
         startTag = tagMatch[tagMatch.length - 1]; // 获取最后一个标签
+        // 如果是 <br> 标签,继续往前找,直到找到非 <br> 标签或者没有标签为止
+
+        while (startTag.toLowerCase() === '<br>') {
+          const prevPart = parts[i - 3] ?? '';
+          const prevTagMatch = prevPart.match(/<[^>]+>/g);
+          if (prevTagMatch === null) {
+            startTag = '';
+            break;
+          }
+          if (prevTagMatch) {
+            startTag = prevTagMatch[prevTagMatch.length - 1];
+            i -= 1;
+          } else {
+            break;
+          }
+        }
       }
       _content = `${startTag}${_content}`;
       if (!isEndWithTag) {

+ 31 - 17
src/views/book/courseware/create/components/question/sort/Sort.vue

@@ -53,7 +53,17 @@
       </div>
       <div class="tips">{{ tips }}</div>
 
-      <el-divider v-if="isEnable(data.property.view_pinyin)" content-position="left">拼音效果</el-divider>
+      <el-divider v-if="isEnable(data.property.view_pinyin)" content-position="left">
+        <span>拼音效果</span>
+        <el-button
+          v-show="isEnable(data.property.view_pinyin)"
+          type="text"
+          icon="el-icon-refresh"
+          title="刷新"
+          class="refresh-pinyin-btn"
+          @click.native="handleViewPinyin"
+        />
+      </el-divider>
       <PinyinText
         v-for="(item, i) in data.option_list"
         v-show="isEnable(data.property.view_pinyin)"
@@ -132,28 +142,32 @@ export default {
     'data.property.order_type': 'handleMindMap',
     'data.property': {
       handler({ view_pinyin }) {
-        if (!this.isEnable(view_pinyin)) {
-          this.data.option_list.forEach((item) => {
-            item.paragraph_list = [];
-            item.paragraph_list_parameter = {
-              text: '',
-              pinyin_proofread_word_list: [],
-            };
-          });
-          return;
+        if (view_pinyin) {
+          this.handleViewPinyin();
         }
-        if (this.data.option_list.length > 0 && this.data.option_list[0].paragraph_list.length > 0) return;
-        this.data.option_list.forEach((item, i) => {
-          const text = item.content;
-          if (!text) return;
-          item.paragraph_list_parameter.text = text;
-          this.createParsedTextInfoPinyin(text, i);
-        });
       },
       deep: true,
     },
   },
   methods: {
+    handleViewPinyin() {
+      if (!this.isEnable(this.data.property.view_pinyin)) {
+        this.data.option_list.forEach((item) => {
+          item.paragraph_list = [];
+          item.paragraph_list_parameter = {
+            text: '',
+            pinyin_proofread_word_list: [],
+          };
+        });
+        return;
+      }
+      this.data.option_list.forEach((item, i) => {
+        const text = item.content;
+        if (!text) return;
+        item.paragraph_list_parameter.text = text;
+        this.createParsedTextInfoPinyin(text, i);
+      });
+    },
     getSortWrapperStyle() {
       let gridTemplateAreas = '';
       let gridTemplateColumns = '';

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

@@ -509,12 +509,17 @@ export default {
     grid-area: fill;
     font-size: 16pt;
 
+    :deep .pinyin-area .rich-text-container,
+    :deep .pinyin-area .pinyin-paragraph {
+      display: inline;
+    }
+
     p {
       margin: 0;
     }
 
     .content {
-      display: inline-block;
+      display: inline;
     }
 
     .record-box {

+ 8 - 2
src/views/personal_workbench/edit_task/preview/index.vue

@@ -7,7 +7,7 @@
       ref="preview"
       :project-id="project_id"
       type="edit_preview"
-      @updateBackground="background = $event"
+      @updateBackground="updateBackground"
       @selectedComponent="curComponentData = $event"
     >
       <template #operator="{ courseware }">
@@ -247,11 +247,17 @@ export default {
         background_position: position,
         background,
       };
-      SaveCoursewareBackground({ id: this.id, background: JSON.stringify(this.background) }).then(() => {
+      SaveCoursewareBackground({
+        id: this.$refs.preview.select_node,
+        background: JSON.stringify(this.background),
+      }).then(() => {
         this.$message.success('背景设置成功');
         this.$refs.preview.updateBackground(this.background);
       });
     },
+    updateBackground(background) {
+      this.background = background;
+    },
   },
 };
 </script>