Browse Source

复制粘贴组件

dsy 3 days ago
parent
commit
005c7e2726

+ 1 - 1
.env

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

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "eep_page",
-  "version": "2025.12.07",
+  "version": "2025.12.13",
   "private": true,
   "main": "main.js",
   "description": "智慧梧桐数字教材编辑器",

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

@@ -82,6 +82,7 @@
                   :component-move="componentMove(i, j, k)"
                   @deleteComponent="deleteComponent"
                   @showSetting="showSetting"
+                  @copyComponent="copyComponent"
                   @changeData="changeData"
                 />
                 <span
@@ -1321,6 +1322,88 @@ export default {
       };
       this.content_group_row_list = content_group_row_list || [];
     },
+    /**
+     * @description 复制组件
+     * @param {object} data 组件数据
+     */
+    copyComponent(data) {
+      this.$emit('copyComponent', data);
+    },
+    /**
+     * @description 粘贴组件
+     * @param {Object} componentData 组件数据
+     * @param {String} position 放入位置类型
+     */
+    pasteComponent(componentData, position) {
+      if (!componentData) return;
+      let _data = JSON.parse(JSON.stringify(componentData));
+      const curId = this.getCurSettingId();
+      const attrs = this.findChildComponentByKey(`grid-${curId}`)?.$attrs;
+      if (!attrs) return;
+      const i = Number(attrs['data-row']);
+      const j = Number(attrs['data-col']);
+      let k = Number(attrs['data-grid']);
+      let type = _data.type;
+
+      let row = this.data.row_list[i];
+      let col = row.col_list[j];
+      let grid = col.grid_list;
+
+      const id = `ID-${getRandomNumber(12, true)}`;
+      const letter = `L${getRandomNumber(6, true)}`;
+
+      if (['top', 'bottom'].includes(position)) {
+        let rowNum = k === 0 ? 1 : grid[k - 1].row + 1;
+        if (position === 'bottom') {
+          rowNum = grid[k].row + 1;
+        }
+        k = position === 'top' ? k : k + 1;
+        grid.splice(k, 0, {
+          id,
+          grid_area: letter,
+          width: '100fr',
+          height: 'auto',
+          edit_height: 'auto',
+          row: rowNum,
+          type,
+        });
+        grid.forEach((item, i) => {
+          if (i > k) {
+            item.row += 1;
+          }
+        });
+      }
+
+      if (['left', 'right'].includes(position)) {
+        let rowNum = grid[position === 'left' ? k : k - 1].row;
+        let _k = position === 'left' ? k : k + 1;
+        grid.splice(_k, 0, {
+          id,
+          grid_area: letter,
+          width: '100fr',
+          height: 'auto',
+          edit_height: 'auto',
+          row: rowNum,
+          type,
+        });
+
+        let allRowNum = grid.filter(({ row }) => row === rowNum).length;
+        let w = 0;
+        grid.forEach((item, i) => {
+          if (item.row === rowNum && i !== k) {
+            let width = Number(item.width.replace('fr', ''));
+            let diff = width / allRowNum;
+            item.width = `${width - diff}fr`;
+            w += diff;
+          }
+        });
+        grid[_k].width = `${w}fr`;
+      }
+      this.$nextTick(() => {
+        let newComponent = this.findChildComponentByKey(`grid-${id}`); // 获取新添加的组件实例
+        newComponent?.setData(_data); // 设置新添加的组件数据
+      });
+    },
   },
 };
 </script>

+ 10 - 2
src/views/book/courseware/create/components/common/ModuleBase.vue

@@ -14,7 +14,7 @@
       <div class="module-top">
         <span class="title">{{ componentNameList[type] }}</span>
         <div class="module-icon">
-          <span><SvgIcon icon-class="copy" size="10" /></span>
+          <span><SvgIcon icon-class="copy" size="10" @click="copyComponent" /></span>
           <span :class="[{ active: getCurSettingId() === id }]" @click="showSetting">
             <SvgIcon icon-class="setup" size="10" />
           </span>
@@ -43,7 +43,15 @@ import { componentNameList } from '@/views/book/courseware/data/bookType.js';
 
 export default {
   name: 'ModuleBase',
-  inject: ['id', 'showSetting', 'getCurSettingId', 'deleteComponent', 'handleComponentMove', 'borderColor'],
+  inject: [
+    'id',
+    'showSetting',
+    'getCurSettingId',
+    'deleteComponent',
+    'handleComponentMove',
+    'borderColor',
+    'copyComponent',
+  ],
   props: {
     type: {
       type: String,

+ 14 - 0
src/views/book/courseware/create/components/common/ModuleMixin.js

@@ -55,6 +55,7 @@ const mixin = {
   provide() {
     return {
       showSetting: this.showSetting,
+      copyComponent: this.copyComponent,
       id: this.id,
       deleteComponent: this.deleteComponent,
       handleComponentMove: this.handleComponentMove,
@@ -132,6 +133,19 @@ const mixin = {
       );
     },
     /**
+     * @description 复制组件
+     */
+    copyComponent() {
+      this.$emit('copyComponent', this.data);
+    },
+    /**
+     * @description 设置组件数据(用于粘贴组件)
+     * @param {Object} data 组件数据
+     */
+    setData(data) {
+      this.data = data;
+    },
+    /**
      * @description 显示设置
      */
     showSetting() {

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

@@ -22,6 +22,7 @@
         :is-edit="isEdit"
         @showSetting="showSetting"
         @showSettingEmpty="showSettingEmpty"
+        @copyComponent="copyComponent"
         @changeData="changeData"
         @back="back"
         @changeEditStatus="changeEditStatus"
@@ -80,6 +81,7 @@ export default {
       isEdit: true, // 是否编辑状态
       isChange: false, // 是否有改动
       showBackTop: false,
+      copyData: null,
     };
   },
   mounted() {
@@ -142,6 +144,30 @@ export default {
         this.$refs.createCanvas.showFullTextSettings();
       }
     },
+    /**
+     * @description 粘贴组件
+     * @param {String} position 放入位置类型
+     */
+    pasteComponent(position) {
+      if (!this.copyData) {
+        this.$message.warning('请先复制组件');
+        return;
+      }
+      if (this.curSettingId.length === 0) {
+        this.$message.warning('请先选择组件');
+        return;
+      }
+      this.$refs.createCanvas.pasteComponent(this.copyData, position);
+    },
+    /**
+     * @description 复制组件
+     * @param {object} data 组件数据
+     */
+    copyComponent(data) {
+      if (!data) return;
+      this.$message.success('组件已复制,可以粘贴到其他位置');
+      this.copyData = data;
+    },
     // 显示设置置空
     showSettingEmpty() {
       this.curSettingType = '';

+ 21 - 0
src/views/personal_workbench/edit_task/edit/index.vue

@@ -34,6 +34,15 @@
           <template v-if="!type">
             <span class="link" @click="copyFormat">复制格式</span>
             <span :class="['link', { disabled: !format.isCopy }]" @click="pasteFormat">粘贴格式</span>
+            <span class="link" @click="pasteComponent('bottom')">粘贴组件</span>
+            <el-popover placement="bottom" width="100" trigger="click">
+              <el-link type="primary" @click="pasteComponent('bottom')">粘贴到下方</el-link>
+              <el-link type="primary" @click="pasteComponent('top')">粘贴到上方</el-link>
+              <el-link type="primary" @click="pasteComponent('left')">粘贴到左侧</el-link>
+              <el-link type="primary" @click="pasteComponent('right')">粘贴到右侧</el-link>
+              <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>
           </template>
           <span class="link" @click="showSetBackground">背景图</span>
@@ -178,6 +187,12 @@ export default {
       activeEditor.formatter.apply('customFormat');
     },
     /**
+     * @description 粘贴组件
+     */
+    pasteComponent(position = 'bottom') {
+      this.$refs.create.pasteComponent(position);
+    },
+    /**
      * 得到教材课件信息
      */
     getBookCoursewareInfo() {
@@ -350,3 +365,9 @@ export default {
   }
 }
 </style>
+
+<style lang="scss">
+.el-popover.el-popper {
+  min-width: 100px;
+}
+</style>