Browse Source

组件分组问题修复

dsy 1 week ago
parent
commit
8894523be6
2 changed files with 85 additions and 10 deletions
  1. 1 1
      .env
  2. 84 9
      src/views/book/courseware/create/components/CreateCanvas.vue

+ 1 - 1
.env

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

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

@@ -1,11 +1,17 @@
 <template>
   <main ref="canvas" class="canvas">
     <div v-if="isEdit" class="edit">
-      <div v-for="item in lineList" :key="item[0]" class="group-line" :style="computedGroupLine(item)"></div>
+      <div
+        v-for="item in lineList"
+        :key="item[0]"
+        class="group-line"
+        :data-canvas-height="canvasHeight"
+        :style="computedGroupLine(item)"
+      ></div>
       <span class="drag-line" data-row="-1"></span>
       <!-- 行 -->
       <template v-for="(row, i) in data.row_list">
-        <div :key="row.row_id" class="row" :style="computedRowStyle(i)">
+        <div :key="`check-${row.row_id}`" class="row" :style="computedRowStyle(i)">
           <el-checkbox
             v-if="row?.row_id"
             v-model="rowCheckList[row.row_id]"
@@ -192,6 +198,7 @@ export default {
       projectResourcePopedom: [], // 当前编辑人员的项目资源权限
       componentsDataLoaded: false, // 组件数据是否加载完成
       visible_id: this.$route.query.visible_id, // 可见组件 id
+      canvasHeight: 0, // 画布高度,监听变化用于重绘分组线
     };
   },
   computed: {
@@ -268,13 +275,8 @@ export default {
           }
         });
 
-        // 过滤掉已经不存在的行,并将第一行的 is_pre_same_group 设置为 false
-        this.content_group_row_list = this.content_group_row_list.filter((group) =>
-          val.find((row) => row.row_id === group.row_id),
-        );
-        if (this.content_group_row_list[0]) {
-          this.content_group_row_list[0].is_pre_same_group = false;
-        }
+        // 过滤掉已经不存在的行,并修正行删除后的分组状态
+        this.content_group_row_list = this.normalizeGroupRowList(this.content_group_row_list, val);
       },
       immediate: true,
     },
@@ -411,11 +413,14 @@ export default {
     document.addEventListener('mousemove', this.dragMove);
     document.addEventListener('mouseup', this.dragEnd);
     window.addEventListener('keydown', this.handleCopy);
+    // 监听画布高度变化,重绘分组线
+    this.initCanvasResizeObserver();
   },
   beforeDestroy() {
     document.removeEventListener('mousemove', this.dragMove);
     document.removeEventListener('mouseup', this.dragEnd);
     window.removeEventListener('keydown', this.handleCopy);
+    this.destroyCanvasResizeObserver();
   },
   methods: {
     /**
@@ -1574,11 +1579,41 @@ export default {
     },
 
     /**
+     * 初始化画布 ResizeObserver,监听画布高度变化
+     * 高度变化时更新 canvasHeight,触发重新渲染以重绘分组线
+     */
+    initCanvasResizeObserver() {
+      const canvas = this.$refs.canvas;
+      if (!canvas || typeof ResizeObserver === 'undefined') return;
+
+      this.canvasResizeObserver = new ResizeObserver((entries) => {
+        entries.forEach((entry) => {
+          const height = entry.contentRect.height;
+          if (height !== this.canvasHeight) {
+            this.canvasHeight = height;
+          }
+        });
+      });
+      this.canvasResizeObserver.observe(canvas);
+    },
+    /**
+     * 销毁画布 ResizeObserver
+     */
+    destroyCanvasResizeObserver() {
+      if (this.canvasResizeObserver) {
+        this.canvasResizeObserver.disconnect();
+        this.canvasResizeObserver = null;
+      }
+    },
+
+    /**
      * 计算分组线样式
      * @param {Array} rowIdList 行 ID 列表
      * @returns {Object} 样式对象
      */
     computedGroupLine(rowIdList) {
+      // 画布高度变化时(canvasHeight 更新)会触发组件重渲染,此处重新读取 DOM 计算分组线位置
+
       // 获取画布顶部位置
       const canvas = this.$refs.canvas;
       const firstCheckbox = this.$el.querySelector(`.row-checkbox.${rowIdList[0]}`);
@@ -1682,6 +1717,46 @@ export default {
       return data;
     },
     /**
+     * 删除行后归一化行分组列表
+     *
+     * is_pre_same_group 为 true 表示该行与其前一行同属一个分组。
+     * 行删除后,content_group_row_list 中剩余行的 is_pre_same_group 仍是删除前的值,
+     * 若某分组的首行被删除,则组内剩余首行的 is_pre_same_group 需置为 false,
+     * 否则分组线(.group-line)会错误地连接到前一组。
+     *
+     * @param {Array} groupList 删除前(含新增行)的行分组列表
+     * @param {Array} rowList 删除后的 row_list
+     * @returns {Array} 归一化后的行分组列表
+     */
+    normalizeGroupRowList(groupList, rowList) {
+      const validRowIds = new Set((rowList || []).map((row) => row.row_id));
+
+      // 按删除前的分组划分:is_pre_same_group 为 false 的行是新分组的首行
+      const groups = [];
+      let curGroup = [];
+      (groupList || []).forEach((item) => {
+        if (item.is_pre_same_group) {
+          curGroup.push(item);
+        } else {
+          if (curGroup.length) groups.push(curGroup);
+          curGroup = [item];
+        }
+      });
+      if (curGroup.length) groups.push(curGroup);
+
+      // 过滤掉已删除的行,并将每组剩余首行的 is_pre_same_group 置为 false,其余保持 true
+      const result = [];
+      groups.forEach((group) => {
+        const remaining = group.filter((item) => validRowIds.has(item.row_id));
+        if (!remaining.length) return;
+        remaining.forEach((item, i) => {
+          item.is_pre_same_group = i > 0;
+        });
+        result.push(...remaining);
+      });
+      return result;
+    },
+    /**
      * 加载模板数据
      * @param {Object} param
      * @param {Object} param.data - 模板数据