dsy vor 1 Monat
Ursprung
Commit
bce7979a2e
42 geänderte Dateien mit 154 neuen und 75 gelöschten Zeilen
  1. 8 9
      src/components/CommonPreview.vue
  2. 58 0
      src/views/book/courseware/create/components/CreateCanvas.vue
  3. 1 1
      src/views/book/courseware/create/components/base/3d_model/3DModel.vue
  4. 1 1
      src/views/book/courseware/create/components/base/audio/Audio.vue
  5. 1 1
      src/views/book/courseware/create/components/base/character_base/CharacterBase.vue
  6. 1 1
      src/views/book/courseware/create/components/base/divider/Divider.vue
  7. 1 1
      src/views/book/courseware/create/components/base/h5_games/H5Games.vue
  8. 3 3
      src/views/book/courseware/create/components/base/label/Label.vue
  9. 1 1
      src/views/book/courseware/create/components/base/picture/Picture.vue
  10. 7 6
      src/views/book/courseware/create/components/base/rich_text/RichText.vue
  11. 1 1
      src/views/book/courseware/create/components/base/spacing/Spacing.vue
  12. 1 1
      src/views/book/courseware/create/components/base/stem/Stem.vue
  13. 1 1
      src/views/book/courseware/create/components/base/upload_control/UploadControl.vue
  14. 1 1
      src/views/book/courseware/create/components/base/upload_preview/UploadPreview.vue
  15. 1 1
      src/views/book/courseware/create/components/base/video/Video.vue
  16. 1 1
      src/views/book/courseware/create/components/base/write_base/WriteBase.vue
  17. 12 1
      src/views/book/courseware/create/components/common/ModuleBase.vue
  18. 5 5
      src/views/book/courseware/create/components/question/article/Article.vue
  19. 1 1
      src/views/book/courseware/create/components/question/character/Character.vue
  20. 1 1
      src/views/book/courseware/create/components/question/character_structure/CharacterStructure.vue
  21. 11 11
      src/views/book/courseware/create/components/question/dialogue_article/Article.vue
  22. 1 1
      src/views/book/courseware/create/components/question/drawing/Drawing.vue
  23. 1 1
      src/views/book/courseware/create/components/question/fill/Fill.vue
  24. 4 4
      src/views/book/courseware/create/components/question/image_text/ImageText.vue
  25. 1 1
      src/views/book/courseware/create/components/question/input/Input.vue
  26. 1 1
      src/views/book/courseware/create/components/question/judge/Judge.vue
  27. 1 1
      src/views/book/courseware/create/components/question/matching/Matching.vue
  28. 1 1
      src/views/book/courseware/create/components/question/math/Math.vue
  29. 1 1
      src/views/book/courseware/create/components/question/newWord_template/NewWordTemplate.vue
  30. 3 3
      src/views/book/courseware/create/components/question/new_word/NewWord.vue
  31. 1 1
      src/views/book/courseware/create/components/question/notes/Notes.vue
  32. 1 1
      src/views/book/courseware/create/components/question/other_word/OtherWord.vue
  33. 1 1
      src/views/book/courseware/create/components/question/pinyin_base/PinyinBase.vue
  34. 1 1
      src/views/book/courseware/create/components/question/record_input/RecordInput.vue
  35. 1 1
      src/views/book/courseware/create/components/question/select/Select.vue
  36. 1 1
      src/views/book/courseware/create/components/question/sort/Sort.vue
  37. 1 1
      src/views/book/courseware/create/components/question/table/Table.vue
  38. 1 1
      src/views/book/courseware/create/components/question/video_interaction/VideoInteraction.vue
  39. 1 1
      src/views/book/courseware/create/components/question/voice_matrix/VoiceMatrix.vue
  40. 1 1
      src/views/book/courseware/create/components/question/write/Write.vue
  41. 6 0
      src/views/book/courseware/create/index.vue
  42. 6 2
      src/views/personal_workbench/edit_task/edit/index.vue

+ 8 - 9
src/components/CommonPreview.vue

@@ -407,6 +407,7 @@ export default {
       getTitleList: () => this.title_list,
     };
   },
+  inject: ['processHtmlString'],
   props: {
     projectId: {
       type: String,
@@ -430,7 +431,6 @@ export default {
       default: false,
     },
   },
-  inject: ['processHtmlString'],
   data() {
     const sidebarIconList = [
       { icon: 'search', title: '搜索', handle: 'getSearch', param: { type: '5' } },
@@ -647,7 +647,7 @@ export default {
         ({ courseware_info }) => {
           this.courseware_info = { ...this.courseware_info, ...courseware_info };
           this.getLangList();
-        }
+        },
       );
     },
     /**
@@ -693,7 +693,7 @@ export default {
               let lev = Number(p.title_style_level);
               if (p.is_title !== 'true' || lev < 1 || !_c.content) return;
 
-              let style = this.title_list.find((y) => y.level == lev) || {};
+              let style = this.title_list.find((y) => y.level === lev) || {};
               if (style && style.style) {
                 style = JSON.parse(style.style);
                 let c_text = _c.content;
@@ -711,14 +711,14 @@ export default {
           });
 
           if (content_group_row_list) this.content_group_row_list = JSON.parse(content_group_row_list) || [];
-        }
+        },
       );
     },
     getLangList() {
       GetLanguageTypeList({ book_id: this.courseware_info.book_id, is_contain_zh: 'true' }).then(
         ({ language_type_list }) => {
           this.langList = language_type_list;
-        }
+        },
       );
     },
 
@@ -831,7 +831,7 @@ export default {
       this.$refs.courserware.handleResult(
         this.$refs.previewMain.scrollTop,
         this.$refs.previewMain.scrollLeft,
-        this.select_node
+        this.select_node,
       );
     },
     /**
@@ -1105,7 +1105,6 @@ export default {
      */
     handleLocation(item, type) {
       if (type === 3) {
-        console.log(item.courseware_id, item.component_id);
         let did = `${item.courseware_id}#${item.component_id}`;
         this.handleNodeClick(did);
         this.curSelectId = item.courseware_id;
@@ -1154,7 +1153,7 @@ export default {
           x.coursewareId === note.coursewareId &&
           x.blockId === note.blockId &&
           x.startIndex === note.startIndex &&
-          x.endIndex === note.endIndex
+          x.endIndex === note.endIndex,
       );
       if (old) {
         this.oldRichData = old;
@@ -1248,7 +1247,7 @@ export default {
           x.coursewareId === collect.coursewareId &&
           x.blockId === collect.blockId &&
           x.startIndex === collect.startIndex &&
-          x.endIndex === collect.endIndex
+          x.endIndex === collect.endIndex,
       );
       if (old) {
         this.$message({

+ 58 - 0
src/views/book/courseware/create/components/CreateCanvas.vue

@@ -1459,6 +1459,64 @@ export default {
         newComponent?.setData(_data); // 设置新添加的组件数据
       });
     },
+    // 交换组件位置
+    switchComponent() {
+      let checkedNum = 0;
+      let components = [];
+      this.$refs.component.forEach((child) => {
+        if (child.$refs.base.checked) {
+          checkedNum += 1;
+          components.push(child.id);
+        }
+      });
+      if (checkedNum !== 2) {
+        this.$message.error('请选择两个组件进行交换');
+        return;
+      }
+      this.$confirm('组件未保存改动将丢失。确定要交换这两个组件的位置吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          this.switchComponentData(components);
+        })
+        .catch(() => {
+          // 取消交换
+        });
+    },
+    /**
+     * 合并遍历 data.row_list,找到两个网格对象并直接交换它们的属性
+     * @param {Array} components 组件 ID 列表
+     */
+    switchComponentData(components) {
+      const [id1, id2] = components;
+      let g1 = null;
+      let g2 = null;
+
+      for (const row of this.data.row_list) {
+        for (const col of row.col_list) {
+          for (const grid of col.grid_list) {
+            if (grid.id === id1) g1 = grid;
+            else if (grid.id === id2) g2 = grid;
+            if (g1 && g2) break;
+          }
+          if (g1 && g2) break;
+        }
+        if (g1 && g2) break;
+      }
+
+      if (!g1 || !g2) return;
+
+      const tmp = { grid_area: g1.grid_area, id: g1.id, type: g1.type }; // 临时存储 g1 的属性
+      g1.grid_area = g2.grid_area;
+      g1.type = g2.type;
+      g1.id = g2.id;
+
+      g2.grid_area = tmp.grid_area;
+      g2.type = tmp.type;
+      g2.id = tmp.id;
+    },
   },
 };
 </script>

+ 1 - 1
src/views/book/courseware/create/components/base/3d_model/3DModel.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <UploadFile
         key="upload_games"

+ 1 - 1
src/views/book/courseware/create/components/base/audio/Audio.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <UploadFile
         :courseware-id="courseware_id"

+ 1 - 1
src/views/book/courseware/create/components/base/character_base/CharacterBase.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <!-- eslint-disable max-len -->
       <div class="fill-wrapper">

+ 1 - 1
src/views/book/courseware/create/components/base/divider/Divider.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <div v-if="'wavy' === data.property.line_type" class="wavy" :style="settingWavyStyle"></div>
       <hr v-else :style="settingStyle" />

+ 1 - 1
src/views/book/courseware/create/components/base/h5_games/H5Games.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <UploadFile
         key="upload_games"

+ 3 - 3
src/views/book/courseware/create/components/base/label/Label.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <div class="tag-edit">
         <el-tag
@@ -259,8 +259,8 @@ export default {
           this.getLabelList();
           if (color) {
             this.data.dynamicTags.push({
-              name: name,
-              color: color,
+              name,
+              color,
               id: res.id,
               mult_language_list: [],
             });

+ 1 - 1
src/views/book/courseware/create/components/base/picture/Picture.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <UploadFile
         :courseware-id="courseware_id"

+ 7 - 6
src/views/book/courseware/create/components/base/rich_text/RichText.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <div :style="{ width: data.note_list.length > 0 ? '' : '100%' }">
         <RichText
@@ -10,11 +10,11 @@
           :is-view-pinyin="isEnable(data.property.view_pinyin)"
           :font-size="data?.unified_attrib?.font_size"
           :font-family="data?.unified_attrib?.font"
+          placeholder="输入内容"
           @view-explanatory-note="viewExplanatoryNote"
           @selectContentSetMemo="selectContentSetMemo"
           @createParsedTextInfoPinyin="createParsedTextInfoPinyin"
           @compareAnnotationAndSave="compareAnnotationAndSave"
-          placeholder="输入内容"
         />
         <el-button class="btn" @click="openMultilingual">多语言</el-button>
         <MultilingualFill
@@ -107,7 +107,7 @@ export default {
             this.titleStyleList = this.getBookUnifiedTitleList() || [];
           }
           if (this.titleStyleList.length > 0) {
-            var style = this.titleStyleList.find((x) => x.level === newLevel) || {};
+            let style = this.titleStyleList.find((x) => x.level === newLevel) || {};
             this.$refs.richText.setRichTitleFormat(style);
           }
         });
@@ -152,7 +152,8 @@ export default {
         return;
       }
       data.text = text.replace(/<[^>]+>/g, '').replace(/&nbsp;/g, ' ');
-      data.is_first_sentence_first_hz_pinyin_first_char_upper_case = this.data.property.is_first_sentence_first_hz_pinyin_first_char_upper_case;
+      data.is_first_sentence_first_hz_pinyin_first_char_upper_case =
+        this.data.property.is_first_sentence_first_hz_pinyin_first_char_upper_case;
       PinyinBuild_OldFormat(data).then(({ parsed_text }) => {
         if (parsed_text) {
           const mergedData = parsed_text.paragraph_list.map((outerArr, i) =>
@@ -176,8 +177,8 @@ export default {
                   Object.assign(tmp.activeTextStyle, styles);
                 }
                 return tmp;
-              })
-            )
+              }),
+            ),
           );
           this.data.paragraph_list = mergedData; // 取出合并后的数组
         }

+ 1 - 1
src/views/book/courseware/create/components/base/spacing/Spacing.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <div :style="settingStyle"></div>
     </template>

+ 1 - 1
src/views/book/courseware/create/components/base/stem/Stem.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <RichText
         ref="richText"

+ 1 - 1
src/views/book/courseware/create/components/base/upload_control/UploadControl.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content> 学生上传文件控件 </template>
   </ModuleBase>
 </template>

+ 1 - 1
src/views/book/courseware/create/components/base/upload_preview/UploadPreview.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <UploadFile
         :type="data.type"

+ 1 - 1
src/views/book/courseware/create/components/base/video/Video.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <UploadFile
         :courseware-id="courseware_id"

+ 1 - 1
src/views/book/courseware/create/components/base/write_base/WriteBase.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <!-- eslint-disable max-len -->
       <div class="write-base-wrapper">

+ 12 - 1
src/views/book/courseware/create/components/common/ModuleBase.vue

@@ -14,6 +14,7 @@
       <div class="module-top">
         <span class="title">{{ componentNameList[type] }}</span>
         <div class="module-icon">
+          <el-checkbox v-model="checked" />
           <span><SvgIcon icon-class="copy" size="10" @click="copyComponent" /></span>
           <span :class="[{ active: getCurSettingId() === id }]" @click="showSetting">
             <SvgIcon icon-class="setup" size="10" />
@@ -55,7 +56,7 @@ export default {
   props: {
     type: {
       type: String,
-      default: 'text',
+      required: true,
     },
   },
   data() {
@@ -68,6 +69,7 @@ export default {
         type: '',
       },
       activeBgColor: '#82b4ff',
+      checked: false,
     };
   },
   created() {
@@ -188,6 +190,15 @@ export default {
       display: flex;
       column-gap: 8px;
 
+      .el-checkbox {
+        line-height: 16px;
+
+        :deep .el-checkbox__inner {
+          width: 12px;
+          height: 12px;
+        }
+      }
+
       span {
         display: flex;
         align-items: center;

+ 5 - 5
src/views/book/courseware/create/components/question/article/Article.vue

@@ -1,12 +1,12 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <!-- eslint-disable max-len -->
       <div v-loading="loading" class="article-wrapper">
         <el-input v-model="data.content" placeholder="输入" type="textarea" />
         <div class="btn-box">
           <SelectUpload label="课文音频" type="audio" width="500px" @uploadSuccess="uploadAudioSuccess" />
-          <el-button @click="handleAutoAudio" :loading="autoLoading">自动生成音频</el-button>
+          <el-button :loading="autoLoading" @click="handleAutoAudio">自动生成音频</el-button>
         </div>
         <div v-if="data.mp3_list.length > 0" class="upload-file">
           <div class="file-name">
@@ -208,7 +208,7 @@ export default {
                 let sentenceList = []; // 句子按段数组
                 let segList = []; // 句子分词结果
                 item.forEach((items) => {
-                  let sentence = items.reduce((acc, itemss) => acc + itemss.text + '', '');
+                  let sentence = items.reduce((acc, itemss) => `${acc + itemss.text}`, '');
                   let seg = items.map((itemss) => itemss.text);
                   sentenceList.push(sentence);
                   segList.push(seg);
@@ -365,8 +365,8 @@ export default {
             let para = '';
             let wordsList = [];
             item.forEach((items) => {
-              let sentence = items.reduce((acc, itemss) => acc + itemss.text + '', '');
-              let sentenceS = items.reduce((acc, itemss) => acc + itemss.text + '&nbsp;&nbsp;', '');
+              let sentence = items.reduce((acc, itemss) => `${acc + itemss.text}`, '');
+              let sentenceS = items.reduce((acc, itemss) => `${acc + itemss.text}&nbsp;&nbsp;`, '');
               let seg = items.map((itemss) => itemss.text);
               para += items.map((itemss) => itemss.text);
               sentenceList.push(sentence);

+ 1 - 1
src/views/book/courseware/create/components/question/character/Character.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <!-- eslint-disable max-len -->
       <div class="character-wrapper">

+ 1 - 1
src/views/book/courseware/create/components/question/character_structure/CharacterStructure.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <UploadFile
         key="upload_image"

+ 11 - 11
src/views/book/courseware/create/components/question/dialogue_article/Article.vue

@@ -1,11 +1,11 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <!-- eslint-disable max-len -->
       <div v-loading="loading" class="article-wrapper">
         <div class="content">
           <div v-for="(item, index) in data.detail" :key="index" class="content-list">
-            <div class="content-item" v-if="item.type === 'notice'">
+            <div v-if="item.type === 'notice'" class="content-item">
               <span v-html="item.notice"></span>
               <div class="content-operation">
                 <div class="up-down">
@@ -21,7 +21,7 @@
                 <SvgIcon icon-class="delete" @click="deleteOption(index)" />
               </div>
             </div>
-            <div class="content-item" v-else>
+            <div v-else class="content-item">
               <span
                 v-if="
                   data.property.role_img_type === 'upload' &&
@@ -130,7 +130,7 @@
         </div>
         <div class="btn-box">
           <SelectUpload label="课文音频" type="audio" width="500px" @uploadSuccess="uploadAudioSuccess" />
-          <el-button @click="handleAutoAudio" :loading="autoLoading">自动生成音频</el-button>
+          <el-button :loading="autoLoading" @click="handleAutoAudio">自动生成音频</el-button>
         </div>
         <div v-if="data.mp3_list.length > 0" class="upload-file">
           <div class="file-name">
@@ -517,7 +517,7 @@ export default {
       this.data.detail.forEach((item, index) => {
         item.paraIndex = index;
         if (item.type === 'text') {
-          textList += item.para + '\n';
+          textList += `${item.para}\n`;
         }
       });
       BatchSegContent({
@@ -537,7 +537,7 @@ export default {
                 let sentenceList = []; // 句子按段数组
                 let segList = []; // 句子分词结果
                 res.paragraph_list[i].forEach((items) => {
-                  let sentence = items.reduce((acc, itemss) => acc + itemss.text + '', '');
+                  let sentence = items.reduce((acc, itemss) => `${acc + itemss.text}`, '');
                   let seg = items.map((itemss) => itemss.text);
                   sentenceList.push(sentence);
                   segList.push(seg);
@@ -689,7 +689,7 @@ export default {
       this.data.detail.forEach((item, index) => {
         item.paraIndex = index;
         if (item.type === 'text') {
-          textList += item.para + '\n';
+          textList += `${item.para}\n`;
         }
       });
       BatchSegContent({
@@ -708,8 +708,8 @@ export default {
             let para = '';
             let wordsList = [];
             item.forEach((items) => {
-              let sentence = items.reduce((acc, itemss) => acc + itemss.text + '', '');
-              let sentenceS = items.reduce((acc, itemss) => acc + itemss.text + '&nbsp;&nbsp;', '');
+              let sentence = items.reduce((acc, itemss) => `${acc + itemss.text}`, '');
+              let sentenceS = items.reduce((acc, itemss) => `${acc + itemss.text}&nbsp;&nbsp;`, '');
               let seg = items.map((itemss) => itemss.text);
               para += items.map((itemss) => itemss.text);
               sentenceList.push(sentence);
@@ -847,7 +847,7 @@ export default {
           _this.isWordTime = true;
           let data = {
             audio_file_id: _this.data.mp3_list[0].file_id,
-            text: text,
+            text,
             text_type: 'line_text_list',
             line_text_list: verseList,
           };
@@ -981,7 +981,7 @@ export default {
         }
       });
       TextToAudioFile({
-        text: text,
+        text,
         voice_type: this.data.property.voice_type,
         emotion: this.data.property.emotion,
         speed_ratio: this.data.property.speed_ratio,

+ 1 - 1
src/views/book/courseware/create/components/question/drawing/Drawing.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <UploadFile
         key="upload_image"

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

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <!-- eslint-disable max-len -->
       <div class="fill-wrapper">

+ 4 - 4
src/views/book/courseware/create/components/question/image_text/ImageText.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase v-loading="loading" :type="data.type">
+  <ModuleBase ref="base" v-loading="loading" :type="data.type">
     <template #content>
       <UploadFile
         key="upload_image"
@@ -324,14 +324,14 @@ export default {
     },
     startSelection(event) {
       this.isSelecting = true;
-      let clientRect = document.getElementById('selectableArea' + this.randomId).getBoundingClientRect();
+      let clientRect = document.getElementById(`selectableArea${this.randomId}`).getBoundingClientRect();
 
       this.startX = event.clientX - clientRect.left;
       this.startY = event.clientY - clientRect.top;
     },
     updateSelection(event) {
       if (!this.isSelecting) return;
-      let clientRect = document.getElementById('selectableArea' + this.randomId).getBoundingClientRect();
+      let clientRect = document.getElementById(`selectableArea${this.randomId}`).getBoundingClientRect();
 
       this.endX = event.clientX - clientRect.left;
       this.endY = event.clientY - clientRect.top;
@@ -413,7 +413,7 @@ export default {
 
       let data = {
         audio_file_id: this.data.mp3_list[0].file_id,
-        text: text,
+        text,
         line_text_list: verseList,
         text_type: 'line_text_list',
       };

+ 1 - 1
src/views/book/courseware/create/components/question/input/Input.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <RichText
         ref="richText"

+ 1 - 1
src/views/book/courseware/create/components/question/judge/Judge.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <ul class="option-list">
         <li v-for="(item, i) in data.option_list" :key="i" class="option-item">

+ 1 - 1
src/views/book/courseware/create/components/question/matching/Matching.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <ul class="option-list">
         <li v-for="(li, i) in data.option_list" :key="i" class="option-item">

+ 1 - 1
src/views/book/courseware/create/components/question/math/Math.vue

@@ -1,6 +1,6 @@
 <!-- eslint-disable vue/no-v-html -->
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <el-input
         ref="textarea"

+ 1 - 1
src/views/book/courseware/create/components/question/newWord_template/NewWordTemplate.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <div class="fun-type">
         <a

+ 3 - 3
src/views/book/courseware/create/components/question/new_word/NewWord.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <!-- <div style="text-align: left">
         <label>标题:</label>
@@ -717,13 +717,13 @@ export default {
         let text = '';
         this.data.new_word_list.forEach((sItem, index) => {
           // item.forEach((sItem, sIndex) => {
-          text += sItem.new_word + '。';
+          text += `${sItem.new_word}。`;
           // });
         });
         this.isWordTime = true;
         let data = {
           audio_file_id: this.data.audio_data.file_id,
-          text: text,
+          text,
           text_type: 'text',
         };
         getWordTimes(data)

+ 1 - 1
src/views/book/courseware/create/components/question/notes/Notes.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <!-- <label>标题:</label>
       <RichText

+ 1 - 1
src/views/book/courseware/create/components/question/other_word/OtherWord.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <el-table :data="data.option" border style="width: 100%">
         <el-table-column fixed prop="number" label="序号" width="70">

+ 1 - 1
src/views/book/courseware/create/components/question/pinyin_base/PinyinBase.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <!-- eslint-disable max-len -->
       <div class="fill-wrapper">

+ 1 - 1
src/views/book/courseware/create/components/question/record_input/RecordInput.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <el-form :model="data" label-width="72px" label-position="left">
         <el-form-item label="控件规格">

+ 1 - 1
src/views/book/courseware/create/components/question/select/Select.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <ul class="option-list">
         <li v-for="(item, i) in data.option_list" :key="item.mark" class="option-item">

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

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <div class="sort-wrapper" :style="getSortWrapperStyle()">
         <template v-for="(item, i) in data.option_list">

+ 1 - 1
src/views/book/courseware/create/components/question/table/Table.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <div class="fun-type">
         <a

+ 1 - 1
src/views/book/courseware/create/components/question/video_interaction/VideoInteraction.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <UploadFile
         key="upload_image"

+ 1 - 1
src/views/book/courseware/create/components/question/voice_matrix/VoiceMatrix.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <div class="container">
         <div class="batch-set">

+ 1 - 1
src/views/book/courseware/create/components/question/write/Write.vue

@@ -1,5 +1,5 @@
 <template>
-  <ModuleBase :type="data.type">
+  <ModuleBase ref="base" :type="data.type">
     <template #content>
       <!-- eslint-disable max-len -->
       <div class="write-wrapper">

+ 6 - 0
src/views/book/courseware/create/index.vue

@@ -228,6 +228,9 @@ export default {
     insertTemplateData_Create({ row_list, content_group_row_list }) {
       this.$refs.createCanvas.insertTemplateData_CreateCanvas({ row_list, content_group_row_list });
     },
+    /**
+     * 获取教材统一标题样式列表
+     */
     async getBookUnifiedTitle() {
       this.title_style_list = [];
       await GetTitleStyle({ book_id: this.$route.query.project_id }).then(({ title_list }) => {
@@ -238,6 +241,9 @@ export default {
         }
       });
     },
+    switchComponent() {
+      this.$refs.createCanvas.switchComponent();
+    },
   },
 };
 </script>

+ 6 - 2
src/views/personal_workbench/edit_task/edit/index.vue

@@ -43,11 +43,12 @@
               <i slot="reference" class="link el-icon-caret-bottom" :style="{ margin: '0 -10px 0 -4px' }"></i>
             </el-popover>
             <span class="link"></span>
-            <span class="link" @click="useTemplate">使用模板</span>
+            <span class="link" @click="useTemplate()">使用模板</span>
+            <span class="link" @click="switchComponent()">交换组件</span>
           </template>
           <span class="link" @click="showSetBackground">背景图</span>
           <span class="link" @click="saveCoursewareContent('quit')">退出编辑</span>
-          <span class="link" @click="saveCoursewareContent">保存</span>
+          <span class="link" @click="saveCoursewareContent()">保存</span>
           <span v-if="isEdit && !type" class="link" @click="showFullTextSettings">样式调整</span>
           <span v-if="type" class="link" @click="goBackTemplateList">返回模板列表</span>
           <span v-else class="link" @click="goBackBookList">返回教材列表</span>
@@ -304,6 +305,9 @@ export default {
         this.$router.push({ path: '/personal_workbench/template_list_manager' });
       }
     },
+    switchComponent() {
+      this.$refs.create.switchComponent();
+    },
   },
 };
 </script>