Selaa lähdekoodia

```
feat(formula): 支持多实例表格容器独立操作

duy 2 päivää sitten
vanhempi
commit
e10b44085a
2 muutettua tiedostoa jossa 165 lisäystä ja 137 poistoa
  1. 120 49
      src/views/formula/component/table-form-write.vue
  2. 45 88
      src/views/formula/edit.vue

+ 120 - 49
src/views/formula/component/table-form-write.vue

@@ -5,7 +5,7 @@
       style="margin-top:40px;height: 100%;"
       @click="parentClick($event)"
     >
-      <div style="width:100%;height: 100%;overflow: scroll;" class='parent' id='parent'></div>
+      <div style="width:100%;height: 100%;overflow: scroll;" class='parent'   :id="containerId"></div>
     </div>
   </div>
 </template>
@@ -13,12 +13,14 @@
 <script>
 import Vue from 'vue'
 import { getExcelHtml } from '@/api/exctab/excelmodel'
+import { log } from '@antv/g2plot/lib/utils';
 
 export default {
   props: [
     'pkeyId', 
     'initTableName',
-    'selectedTableKey' // 接收父组件传递的选中key
+    'selectedTableKey' ,// 接收父组件传递的选中key
+    'containerId'
   ],
   data() {
     return {
@@ -26,6 +28,13 @@ export default {
       exHtml: '',
       currentComponent: null
     }
+  },
+    // 确保每个实例有独立的容器ID
+  created() {
+    // 如果父组件没传,提供默认唯一ID
+    if (!this.containerId) {
+      this.containerId = `excel-container-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
+    }
   },
   watch: {
     pkeyId: {
@@ -34,6 +43,7 @@ export default {
       handler(newVal) {
         if (newVal) {
           this.exHtml = ''
+        
           this.getExcelHtml(newVal)
         } else {
           this.exHtml = ''
@@ -53,59 +63,89 @@ export default {
         }
       },
       immediate: true
-    }
+    },
+    containerId: {
+      handler(newVal) {
+        this.clearForm()
+      }
+     }
   },
   methods: {
-    // 根据key高亮对应的元素组
-    highlightElementsByKey(key) {
-      // 提取key前缀(例如从key_1中提取key_1)
-      const keyPrefix = key.split('__')[0];
-      
-      // 找到所有具有相同前缀的元素
-      const samePrefixElements = document.querySelectorAll(`[id^="${keyPrefix}__"]`);
-      
-      // 如果没有找到带__的元素,直接查找当前key的元素
-      if (samePrefixElements.length === 0) {
-        const element = document.getElementById(key);
-        if (element) {
-          this.selectElements([element]);
-          return;
-        }
-      }
-      
-      // 选中这组元素
-      this.selectElements(samePrefixElements);
-    },
-    
+    // 根据key高亮对应的元素组  // 确保所有DOM操作都限定在当前容器内
+  getContainerElement() {
+    return document.getElementById(this.containerId);
+  },    // 修改所有使用document.getElementById的地方,使用动态容器ID
+  highlightElementsByKey(key) {
+  if (!key) return;
+  
+  // 确保在当前组件容器内操作
+  const parent = document.getElementById(this.containerId);
+  if (!parent) return;
+  
+  const keyPrefix = key.split('__')[0];
+  
+  // 修复:始终在当前容器内查找,避免污染其他实例
+  const samePrefixElements = parent.querySelectorAll(`[id^="${keyPrefix}__"]`);
+  
+  if (samePrefixElements.length === 0) {
+    // 修复:使用 parent.querySelector 而不是 document.getElementById
+    const element = parent.querySelector(`#${key}`);
+    if (element) {
+      this.selectElements([element]);
+      return;
+    }
+  }
+  
+  this.selectElements(samePrefixElements);
+},
     async getExcelHtml(pkeyId) {
+      console.log(pkeyId,'pkeyId');
+      
       this.clearForm();
-      const { data: res } = await getExcelHtml({ pkeyId })
-      if (res.code === 200) {
-        this.exHtml = res.data
-        this.cop();
+      try {
+        const { data: res } = await getExcelHtml({ pkeyId })
+        if (res.code === 200) {
+          this.exHtml = res.data
+          this.cop();
+        }
+      } catch (error) {
+        console.error('获取HTML失败:', error)
       }
     },
-    
-    clearForm() {
-      const parentElement = document.getElementById('parent')
+     clearForm() {
+      // 使用动态容器ID
+      const parentElement = document.getElementById(this.containerId)
       if (parentElement) {
         parentElement.innerHTML = ''
       }
       this.clearAllSelected()
     },
     
-    async cop() {
-      let _that = this
-      var MyComponent = await Vue.extend({
-        template: this.exHtml,
-        data() {
-          return {
-            formData: {},
-            getTokenHeader: {},
-            dap_site_data: {}
-          }
-        },
-        methods: {
+ 
+     async cop() {
+      const _that = this;
+       const parentElement = this.getContainerElement();
+      if (!parentElement) {
+        console.error('父容器不存在:', this.containerId);
+        return;
+      }
+     
+      if (!parentElement) {
+        console.error('父容器不存在:', this.containerId);
+        return;
+      }
+      
+      try {
+        const MyComponent = Vue.extend({
+          template: this.exHtml,
+          data() {
+            return {
+              formData: {},
+              getTokenHeader: {},
+              dap_site_data: {}
+            }
+          },
+            methods: {
           contextmenuClick() {},
           getInformation() {},
           formUploadSuccess() {},
@@ -125,17 +165,33 @@ export default {
           keyupShiftRight() {},
           inputLeftClick() {},
         }
-      })
-      var component = new MyComponent().$mount()
-      document.getElementById('parent').appendChild(component.$el);
-      
-      // 组件渲染后,检查是否需要高亮元素
+        })
+        
+        await Vue.nextTick();
+        
+        // 先销毁可能存在的旧组件
+        if (this.currentComponent) {
+          this.currentComponent.$destroy();
+        }
+        
+        // 创建新组件
+        this.currentComponent = new MyComponent().$mount();
+        
+        // 清空并添加新内容
+        parentElement.innerHTML = '';
+        parentElement.appendChild(this.currentComponent.$el);
+           // 延迟执行高亮,确保DOM完全渲染
+    this.$nextTick(() => {
       if (this.selectedTableKey) {
         this.highlightElementsByKey(this.selectedTableKey);
       }
+    });
+      } catch (error) {
+        console.error('组件渲染失败:', error);
+      }
     },
-    
     async parentClick(e) {
+      
       // 原有点击处理逻辑保持不变
       let target = e.target;
       while (target && !target.id && target.parentNode) {
@@ -160,7 +216,10 @@ export default {
       }
       
       const id = target.id;
+   
+      
       const isAlreadySelected = this.selectedElements.some(item => item.id === id);
+      console.log(isAlreadySelected,'isAlreadySelected');
       
       this.clearAllSelected();
       
@@ -181,11 +240,20 @@ export default {
     },
     
     selectElements(elements) {
+
+      
+      
       elements.forEach(el => {
         const index = this.selectedElements.findIndex(item => item.id === el.id);
+        console.log(index,'index');
+        
         if (index === -1) {
           el.style.backgroundColor = '#ffa500'; // 橙色背景
+          console.log(this.initTableName,'initTableName');
+          
           const elementId = this.initTableName + ':' + this.extractKeyPrefix(el.id);
+        
+          
           const keyName = el.placeholder;
           this.selectedElements.push({ tableElementKey: elementId, eName: keyName, id: el.id });
           this.$emit('element-selected', { tableElementKey: elementId, eName: keyName, id: el.id }, true);
@@ -203,6 +271,9 @@ export default {
     },
     
     clearAllSelected() {
+    const container = this.getContainerElement();
+    if (!container) return
+    
       this.selectedElements.forEach(item => {
         const element = document.getElementById(item.id);
         if (element) {

+ 45 - 88
src/views/formula/edit.vue

@@ -141,7 +141,7 @@
                 </div>
             
                   <div class="flex mg-t-10" style="justify-content: space-between;width:100%;">
-                    <el-select v-model="eleTableId" @change="getTableEle" placeholder="请选择元素表1" style="width:45%">
+                    <el-select v-model="eleTableId" @change="getTableEle" placeholder="请选择元素表1" style="width:45%"  size="small">
                       <el-option v-if="paramDataList.length" label="选择节点参数2" value="选择节点参数"></el-option>
                       <el-option  v-for="item in eleTableList" :key="item.id" :label="item.tableName" :value="(item.pkeyId!==null&&item.pkeyId!==-1)?item.pkeyId:item.id"></el-option>
                     </el-select>
@@ -155,7 +155,7 @@
                 <div class="mg-t-10 no-mb-col flex1" >
                   <el-scrollbar style="height: 450px">
         
-                     <tableFormWrite :pkeyId="eleTableId" @element-selected="handleElementSelected" :initTableName="initTableName"  :selectedTableKey="selectedTableKey"></tableFormWrite>
+                     <tableFormWrite :pkeyId="eleTableId" @element-selected="handleElementSelected" :initTableName="initTableName"  :selectedTableKey="selectedTableKey"  :key="1" :container-id="'excel-container-1'" ></tableFormWrite>
                   </el-scrollbar>
                 </div>
          
@@ -241,13 +241,13 @@
               </div>
                 <div v-show="item.showSelectEle"  style="width:60%">
                   <div  class="flex" style="justify-content: space-between;width:100%">
-                        <el-select v-model="eleTableIdComp" @change="getTableEleComp" placeholder="请选择元素表" style="width:45%">
+                        <el-select v-model="eleTableIdComp" @change="getTableEleComp" placeholder="请选择元素表" style="width:45%" size="small" clearable>
                         <el-option v-if="paramDataList.length" label="选择节点参数" value="选择节点参数"></el-option>
                         <!-- <el-option  v-for="item in eleTableListComp" :key="item.id" :label="item.tableName" :value="(item.pkeyId!==null&&item.pkeyId!==-1)"></el-option> -->
                                                  <el-option  v-for="item in eleTableListComp" :key="item.id" :label="item.tableName" :value="item.pkeyId"></el-option>
                       </el-select>
                       <!-- 搜索元素下拉框 -->
-                      <el-select v-model="input3" filterable placeholder="搜索元素字段"  @change="getInput1" style="width:45%">
+                      <el-select v-model="input3" filterable placeholder="搜索元素字段888"  @change="getInput1" style="width:45%" size="small">
                       <el-option
                         v-for="item in eleListComp1"
                         :key="item.id"
@@ -257,7 +257,7 @@
                       </el-select>
                   </div>
                   
-                  <div class="mg-t-10 mg-b-10 no-mb-col" style="width:100%">
+                  <!-- <div class="mg-t-10 mg-b-10 no-mb-col" style="width:100%">
                     <el-scrollbar style="height:520px;">
                       <el-row>
                         <el-col :span="6" v-for="item in eleListComp" :key="item.id">
@@ -269,7 +269,13 @@
                         </el-col>
                       </el-row>
                     </el-scrollbar>
-                  </div>
+                  </div> -->
+                  <div class="mg-t-10 no-mb-col flex1" >
+                    <el-scrollbar style="height: 450px">
+          
+                      <tableFormWrite :pkeyId="eleTableIdComp" @element-selected="handleElementSelectedComp" :initTableName="initTableNameComp"    :key="2"   :container-id="'excel-container-2'" :selectedTableKey="selectedTableKeyComp"></tableFormWrite>
+                    </el-scrollbar>
+                </div>
                 </div>
             </div>
           </template>
@@ -467,6 +473,7 @@ import dataChange from "./component/funComponent/dataChange"
 import tableFormWrite from "./component/table-form-write.vue";
 import { log } from "@antv/g2plot/lib/utils";
 
+
 export default {
   components: {
     draggable,
@@ -627,6 +634,8 @@ export default {
       initTableName:'',//初始表名
       containerFocused:false,//公式编辑区域是否聚焦
       selectedTableKey:'', // 存储选中的表格元素key
+      initTableNameComp:'',//初始表名组件
+      selectedTableKeyComp:'', // 存储选中的表格元素key 组件
 
     };
   },
@@ -813,54 +822,6 @@ export default {
         }
       }
     },
-
-    // eleChang(value,item){
-    //   //console.log(value)
-    //   //console.log(item)
-    //   if(value){
-    //     //简单语法判断
-    //     if(this.selectEleFormula.length != 0 && this.deleEleIndex < 0){
-    //       let lastEle = this.selectEleFormula[this.selectEleFormula.length-1];
-    //       if(lastEle.type == 'Element'){
-    //         this.$message({
-    //           type: "warning",
-    //           message: "元素无法连续出现在元素后面"
-    //         });
-    //         item.checked = false;
-    //         return;
-    //       }
-    //       if(lastEle.type == 'Text'){
-    //         this.$message({
-    //           type: "warning",
-    //           message: "元素无法连续出现在输入值后面"
-    //         });
-    //         item.checked = false;
-    //         return;
-    //       }
-    //       if(lastEle.type == 'Brackets' && lastEle.name == ')'){
-    //         this.$message({
-    //           type: "warning",
-    //           message: "元素无法连续出现在右括号后面"
-    //         });
-    //         item.checked = false;
-    //         return;
-    //       }
-    //     }
-
-    //     this.eleAddFormulaHandle(item);
-    //   }else{
-    //     let index = -1;
-    //     for (let i = 0; i < this.selectEleFormula.length; i++) {
-    //       if(this.selectEleFormula[i].id == item.id){
-    //         index = i;
-    //         break;
-    //       }
-    //     }
-    //     if(index>-1){
-    //       this.selectEleFormula.splice(index,1);
-    //     }
-    //   }
-    // },
     eleChang(value,item){
       if(value){
         //简单语法判断
@@ -1479,40 +1440,6 @@ handleDelete(e) {
       this.actiFunIndex = (this.equationSelectEle.children.length-1).toString();
     },
 
-    //选择元素
-    // chooseEleHandle(){
-    //   for (let i = 0; i < this.eleList.length; i++) {
-    //     if (this.eleList[i].checked) {
-    //       let ele = this.eleList[i];
-    //       let obj = {};
-    //       if(ele.k){
-    //         obj = {
-    //           type:'ParamData',
-    //           name:ele.name,
-    //           id:ele.id,
-    //           selected:false,
-    //           v:ele.v,
-    //           k:ele.k,
-    //           children:[],
-    //         }
-    //       }else{
-    //         obj = {
-    //           type:'Element',
-    //           name:ele.eName,
-    //           id:ele.id,
-    //           selected:false,
-    //           tableElementKey:ele.tableElementKey,
-    //           children:[],
-    //         }
-    //       }
-
-
-    //       this.$set(this.argumenObj.arguments,this.argumenObj.index,obj);
-    //       this.chooseEleVisible = false;
-    //       break;
-    //     }
-    //   }
-    // },
     //选择元素多选
     chooseEleHandle(){
       this.eleChecks.forEach((element,index) => {
@@ -2192,7 +2119,20 @@ console.log(remark,'remark');
           this.eleListComp = res.data.data;
            this.eleListComp1 = res.data.data;
         })
+        console.log(this.eleTableListComp,'eleTableListComp');
+    
+        this.eleTableListComp.forEach((item)=>{
+          if(item.pkeyId===tableId){
+            this.initTableNameComp=item.initTableName
+          }
+          
+        })
+        
       }
+
+
+      
+
     },
 
     //取消方法下面 元素勾选
@@ -2356,6 +2296,23 @@ handleElementSelected(item, value) {
     }
   }
 },
+handleElementSelectedComp(item, value) {
+
+  console.log('选中的元素111',item);
+    if(!item.eName){
+    this.$message({
+      type: "warning",
+      message: "当前位置未配置元素,请重新选择或配置元素后再试"
+    });
+    return;
+  }
+  if(value){
+    const keyParts =item.tableElementKey
+    // this.selectedTableKeyComp = keyParts
+  }
+    
+  
+},
 
 // 新增:替换当前选中的元素
 replaceSelectedElement(newItem) {