nanjingliujinyu 4 hónapja
szülő
commit
b50e500fd4

+ 7 - 0
ruoyi-ui/src/api/service/info.js

@@ -95,4 +95,11 @@ export function deTree(id) {
     url: '/interfaces/cate/' + id,
     method: 'delete'
   })
+}
+export function getServiceReturn(query) {
+  return request({
+    url: "/service/return/list",
+    method: "get",
+    params: query,
+  });
 }

+ 10 - 1
ruoyi-ui/src/layout/components/editModel.vue

@@ -671,6 +671,13 @@
                                         </div>
                                     </template>
                                 </el-table-column>
+                                <el-table-column prop="itemName" label="参数示例">
+                                    <template #default="scope">
+                                        <div style="width: 100%;">
+                                            <el-input placeholder="请填写参数示例" type="primary" class="noBor" v-model="scope.row.paramValue" size="mini" text style="margin-left: 0%;"></el-input>
+                                        </div>
+                                    </template>
+                                </el-table-column>
                                 <el-table-column prop="itemName" label="参数说明" >
                                     <template #default="scope">
                                         <div style="width: 100%;">
@@ -1138,7 +1145,9 @@ async function addSer(){
     await addService(par).then(res=>{
       if(res.code===200){
         var parCan = tableDataCanAdd.value
-        parCan.srvId = res.data.srvId
+        parCan.forEach(item => {
+          item.srvId = res.data.srvId
+        });
         addServiceParam(parCan).then(res1=>{
           if(res1.code===200){
             proxy.$modal.msgSuccess("新增成功");

+ 1 - 1
ruoyi-ui/src/views/register/modelData/dataJi.vue

@@ -841,7 +841,7 @@ function addValueField(nodes) {
   for (const node of nodes) {
     // 添加value字段,其值等于id
     node.value = node.id;
-    
+ 
     // 如果存在子节点,递归处理
     if (node.children && Array.isArray(node.children)) {
       addValueField(node.children);

+ 566 - 56
ruoyi-ui/src/views/service/info/editModel.vue

@@ -14,7 +14,7 @@
       <!-- <Plus style="width: 1em; height: 1em; margin-left:90%;cursor: pointer;color: #337ecc;" @click="showAddTree"/> -->
       <el-tree :expand-on-click-node="false" ref="treeRef" :filter-node-method="filterNode" :current-node-key="currentNodeKey" class="treeLeft" :data="data" @node-click="handleNodeClick" node-key="id" style="margin-left: 5%;margin-top: 5%;width: 90%;background-color: transparent;" default-expand-all :key="valueKet">
           <template #default="{ node, data }">
-            <span  style="justify-content: space-between;display: flex;width: 100%;align-items: center;">
+            <span  style="justify-content: space-between;display: flex;width: 100%;align-items: center;" >
               <div class="custom-tree-node">
                   <!-- <el-tag v-if="data.nodeType=='MODEL'" class="ml-2" type="warning">模型</el-tag> -->
                    <svg-icon icon-class="model2" style="color: #eebe77;" v-if="data.nodeType=='MODEL'"/>
@@ -138,7 +138,7 @@
                               <el-form-item label="响应类型:" prop="" style="display: flex; align-items: center;">
                                 <el-radio-group :disabled="isEdit" v-model="formJi.rptype" class="ml-4" style="display: inline-flex; align-items: center;">
                                   <el-radio label="1" size="large" style="display: inline-flex; align-items: center;">
-                                    <span style="position: relative; top: -1px">JSON</span> <!-- 微调文字位置 -->
+                                    <span style="position: relative; top: -1px">JSON</span>
                                   </el-radio>
                                   <el-radio label="2" size="large" style="display: inline-flex; align-items: center;">
                                     <span style="position: relative; top: -1px">XML</span>
@@ -249,6 +249,81 @@
                             
                         </div>
                     </div>
+                    <div style="margin-top: 2%;">
+                        <div style="display: flex;justify-content: space-between;align-items: center;">
+                          <div>
+                            返回参数
+                          </div>
+                          <div style="display: flex;justify-content: flex-end;margin-right: 2%;">
+                          </div>
+                        </div>
+                        <div style="width: 98%;margin-left: 0%;height: 25vh;margin-top: 1%;overflow: auto;border: 1px solid #eee;">
+                          <el-tree :expand-on-click-node="false" ref="treeRefReturun" :filter-node-method="filterNode" :current-node-key="currentNodeKey" class="treeLeft" 
+                        :data="dataTreeReturn" @node-click="" node-key="id" style="margin-left: 1%;margin-top: 0%;width: 50%;background-color: transparent;"
+                         default-expand-all :key="valueKet" :props="defaultProps">
+                            <template #default="{ node, data }">
+                              <span  style="justify-content: space-between;display: flex;width: 30%;align-items: center;margin-left: 1%;" @mouseenter="setId(data)">
+                                <div class="custom-tree-node" style="align-items: center;line-height: 1.5;font-size: 10px;">
+                                  <span style="font-size: 1rem;">{{ node.label }}</span>
+                                </div>
+                                <div style="position: absolute;left:40%;">
+                                  <div style="color: #67C23A;" v-if="data.paramType=='string'">
+                                    string
+                                  </div>
+                                  <div style="color: #E6A23C;" v-else-if="data.paramType=='array'">
+                                    array
+                                  </div>
+                                  <div style="color: #F56C6C;" v-else-if="data.paramType=='number'">
+                                    number
+                                  </div>
+                                  <div style="color: #F56C6C;" v-else="data.paramType=='number'">
+                                    {{ data.paramType }}
+                                  </div>
+                                </div>
+                                <div style="margin-right: 1%;position: absolute;left:60%;">
+                                  <el-dropdown trigger="hover">
+                                      <svg-icon icon-class="zhankai"/>
+                                    <template #dropdown>
+                                      <el-dropdown-menu>
+                                        <el-dropdown-item style="display: flex;" @click="add1LevelTree">
+                                          <el-icon class="el-icon--right" style="color: black;">
+                                            <CirclePlus />
+                                          </el-icon>
+                                          <div>
+                                            添加同级
+                                          </div>
+                                        </el-dropdown-item>
+                                        <el-dropdown-item style="display: flex;"  @click="addNextLevelTree">
+                                          <el-icon class="el-icon--right" style="color: black;">
+                                            <Connection />
+                                          </el-icon>
+                                          <div>
+                                            新建下级
+                                          </div>
+                                        </el-dropdown-item>
+                                        <divider/>
+                                        <el-dropdown-item style="display: flex;"  @click="delAllTree" divided>
+                                          <el-icon class="el-icon--right" style="color: black;">
+                                            <CircleClose />
+                                          </el-icon>
+                                          <div>
+                                            删除
+                                          </div>
+                                        </el-dropdown-item>
+                                      </el-dropdown-menu>
+                                    </template>
+                                  </el-dropdown>
+                                </div>
+                                <div style="margin-right: 1%;position: absolute;left:70%;">
+                                  <div style="">
+                                    <span style="font-size: 1rem;">{{ data.paramName   }}</span>
+                                  </div>
+                                </div>
+                              </span>
+                            </template>
+                          </el-tree>
+                        </div>
+                    </div>
                     <div style="margin-top: 2%;">
                         <!-- <div>返回响应</div> -->
                         <div style="color: #909399;margin-left: 7%;margin-top:1%;">此处填写本服务接口响应信息描述</div>
@@ -509,6 +584,13 @@
                                         </div>
                                     </template>
                                 </el-table-column>
+                                <el-table-column prop="itemName" label="参数示例">
+                                    <template #default="scope">
+                                        <div style="width: 100%;">
+                                            <el-input placeholder="请填写参数示例" type="primary" class="noBor" v-model="scope.row.paramValue" size="mini" text style="margin-left: 0%;"></el-input>
+                                        </div>
+                                    </template>
+                                </el-table-column>
                                 <el-table-column prop="itemName" label="参数说明" >
                                     <template #default="scope">
                                         <div style="width: 100%;">
@@ -582,6 +664,79 @@
             </span>
           </template>
         </el-dialog>
+        <el-dialog @close="clearFromLev" title="添加目录" v-model="dialogVisibleTree" width="55%" destroy-on-close :key="tableKey">
+          <el-button  @click="addTreePar" style="margin-top: 1%;" type="success" size="mini" :disabled="isEdit" plain>新增参数</el-button>
+          <el-table 
+          style="margin-top: 1%;width: 98%;"
+          :data="tableDataCanAddTree" 
+          :cell-style="{ textAlign: 'center',padding:'2px 0' }"
+          :header-cell-style="{ textAlign: 'center'}"
+          :row-style="{ height: heightAll*0.01+'px',fontSize: '16px',textAlign:'center'  }"
+          border >
+              <el-table-column prop="itemName" label="参数字段">
+                  <template #default="scope">
+                      <div style="width: 100%;">
+                          <el-input placeholder="请填写参数编码" type="primary" class="noBor" v-model="scope.row.paramCode" size="mini" text style="margin-left: 0%;border: transparent;"></el-input>
+                      </div>
+                  </template>
+              </el-table-column>
+              <el-table-column prop="itemName" label="参数名称">
+                  <template #default="scope">
+                      <div style="width: 100%;">
+                          <el-input placeholder="请填写参数名称" type="primary" class="noBor" v-model="scope.row.paramName" size="mini" text style="margin-left: 0%;"></el-input>
+                      </div>
+                  </template>
+              </el-table-column>
+              <el-table-column prop="itemName" label="参数类型" width="200">
+                  <template #default="scope">
+                      <div style="width: 100%;">
+                          <el-select
+                          v-model="scope.row.paramType"
+                          class="noBorSel"
+                          placeholder=""
+                          style="width: 100%;margin-left: 0%;"
+                          >
+                              <el-option
+                              v-for="item in optionsCan"
+                              :key="item.value"
+                              :label="item.label"
+                              :value="item.value"
+                              />
+                  </el-select>
+                      </div>
+                  </template>
+              </el-table-column>
+              <el-table-column prop="itemName" label="参数示例">
+                  <template #default="scope">
+                      <div style="width: 100%;">
+                          <el-input placeholder="请填写参数示例" type="primary" class="noBor" v-model="scope.row.paramValue" size="mini" text style="margin-left: 0%;"></el-input>
+                      </div>
+                  </template>
+              </el-table-column>
+              <el-table-column prop="itemName" label="参数说明" >
+                  <template #default="scope">
+                      <div style="width: 100%;">
+                          <el-input type="primary" class="noBor" v-model="scope.row.paramNote" size="mini" text style="margin-left: 0%;"></el-input>
+                      </div>
+                  </template>
+              </el-table-column>
+              <el-table-column prop="address" label="操作" width="100">
+                  <template #default="scope">
+                      <div style="width: 100%;">
+                          <el-button type="danger" @click="delTreeAdd(scope.$index)" size="mini" text style="margin-left: 0%;">删除</el-button>
+                      </div>
+                  </template>
+              </el-table-column>
+          </el-table>
+          <template #footer>
+              <span class="dialog-footer">
+                <el-button size="mini" @click="dialogVisibleTree = false">取消</el-button>
+                <el-button type="primary" @click="addToTree" size="mini">
+                  确定
+                </el-button>
+            </span>
+          </template>
+        </el-dialog>
     </div>
   </div>
 </template>
@@ -589,7 +744,7 @@
 import {getCatalog} from "@/api/service/catalog";
 import { Plus,Search,Filter,Promotion,Check  } from '@element-plus/icons-vue'
 import { reactive } from 'vue'
-import { modelTreeSelect,getSerDe,addService,addParam,editService,editParam,addServiceParam,delService,getTreeDe,addTree,deTree } from "@/api/service/info";
+import { modelTreeSelect,getSerDe,addService,addParam,editService,editParam,addServiceParam,delService,getTreeDe,addTree,deTree,getServiceReturn } from "@/api/service/info";
 import { ref, onMounted, onUnmounted, nextTick,onBeforeMount } from 'vue';
 import JsonViewer from 'vue-json-viewer'
 import 'vue-json-viewer/style.css' 
@@ -601,11 +756,16 @@ const { proxy } = getCurrentInstance();
 const JsonAdd= ref(JSON.stringify({ data: "初始值1" }))
 const exampleAdd = ref('')
 const dialogVisibleLevel = ref(false)
+const dialogVisieTree = ref(false)
 const detail = ref({
   name:'',
   rqtype:'',
   rptype:''
 })
+const tableDataCanAddTree = ref([
+])
+const dataTreeReturn = ref([
+])
 const show1Lev = ref(true)
 const inputNode =ref('')
 const isEdit = ref(true)
@@ -645,6 +805,8 @@ const optionsCan = ref([
   },
   
 ])
+const parTreeId = ref('')
+const parTreeParentId = ref('')
 const currentNodeKey = ref('')
 const options =  ref([
     {label:'开发中',
@@ -654,7 +816,7 @@ const options =  ref([
     value:'2'
     },
 ])
-const dataJsonXiang = ref([])
+const dataJsonXiang = ref()
 const parTree = ref({})
 const valueKet = ref(0)
 const tableDataCan = ref([
@@ -674,6 +836,10 @@ const optionsRqtype = ref([
     value:'POST'
     },
 ])
+const defaultProps = ref({
+  children: 'children',
+  label: 'paramCode'
+})
 const optionsType=  ref([
     {label:'RESTful',
     value:'RESTful'
@@ -785,7 +951,7 @@ const props1 = ref({
   checkStrictly: true,
 })
 const detailJson = ref([])
-
+const parLev = ref(1)
 watch(inputNode, (val) => {
   treeRef.value?.filter(val); // 调用树的过滤方法
 });
@@ -795,7 +961,94 @@ const filterNode = (value, data) => {
 };
 
 const copied = ref(false);
-
+function addToTree() {
+  if(parLev.value === 1){
+    parTreeParentId.value
+    if(tableDataCanAddTree.value){
+      tableDataCanAddTree.value.forEach(item=>{
+        item.parentId = parTreeId.value
+        item.srvId = parId.value
+        addSiblingNode(dataTreeReturn.value,parTreeId.value,item)
+      })
+      dialogVisibleTree.value = false
+      }
+  }
+  if(parLev.value === 2){
+    tableDataCanAddTree.value.forEach(item=>{
+      item.parentId = parTreeId.value
+      item.srvId = parId.value
+      addChildNode(dataTreeReturn.value,parTreeId.value,item)
+    })
+    dialogVisibleTree.value = false
+  }
+  console.log(findNode(dataTreeReturn.value,parTreeParentId.value))
+}
+function findNode(nodes, targetId, mode = 'id') {
+  if (!Array.isArray(nodes)) return null;
+  
+  for (const node of nodes) {
+    // 检查当前节点是否匹配目标
+    if ((mode === 'id' && node.id === targetId) || (mode === 'parentId' && node.parentId === targetId)) {
+      return node;
+    }
+    // 如果该节点有子节点,则递归搜索其子树
+    if (node.children && node.children.length > 0) {
+      const found = findNode(node.children, targetId, mode);
+      if (found) return found;
+    }
+  }
+  return null; // 未找到
+}
+function addChildNode(treeData, parentId, newNode) {
+  const parentNode = findNode(treeData, parentId, 'id');
+  if (!parentNode) {
+    console.warn(`未找到ID为 ${parentId} 的父节点`);
+    return false;
+  }
+  
+  // 初始化父节点的children数组(如果不存在)
+  if (!Array.isArray(parentNode.children)) {
+    parentNode.children = [];
+  }
+  
+  // 将新节点添加到父节点的children数组中
+  parentNode.children.push(newNode);
+  return true;
+}
+function addSiblingNode(treeData, siblingId, newNode) {
+  // 1. 首先找到目标兄弟节点
+  const siblingNode = findNode(treeData, siblingId, 'id');
+  if (!siblingNode) {
+    console.warn(`未找到ID为 ${siblingId} 的兄弟节点`);
+    return false;
+  }
+  
+  // 2. 找到兄弟节点的父节点(通过parentId查找)
+  const parentNode = findNode(treeData, siblingNode.parentId, 'id');
+  if (!parentNode) {
+    console.warn(`未找到ID为 ${siblingNode.parentId} 的父节点(兄弟节点的父节点)`);
+    return false;
+  }
+  
+  // 3. 将新节点添加到父节点的children数组中
+  if (!Array.isArray(parentNode.children)) {
+    parentNode.children = [];
+  }
+  parentNode.children.push(newNode);
+  return true;
+}
+function setId(data){
+  parTreeId.value = data.id
+  parTreeParentId.value = data.parentId
+}
+function addTreePar(){
+  tableDataCanAddTree.value.push({
+    id:Math.random()
+  })
+}
+function delTreeAdd(index){
+  tableDataCanAddTree.value.splice(index, 1)
+}
 async function copyUrl(){
   try {
     await navigator.clipboard.writeText(detail.value.url);
@@ -828,6 +1081,14 @@ function filterModelNodes(nodes) {
   }
   return result;
 }
+function add1LevelTree(){
+  dialogVisibleTree.value = true
+  parLev.value = 1
+}
+function addNextLevelTree(){
+  dialogVisibleTree.value = true
+  parLev.value = 2
+}
 function clearAdd(){
   dialogVisible.value = false
   formAdd.value = {
@@ -844,25 +1105,6 @@ function clearAdd(){
   JsonAdd.value = ''
   exampleAdd.value = ''
 }
-function extractModelNodesDFSIterative(root) {
-  const result = [];
-  const stack = root;
-  
-  while (stack.length > 0) {
-    const node = stack.pop();
-    if (node.nodeType === 'MODEL') {
-      result.push(node);
-    }
-    
-    // 子节点逆序入栈(保证从左到右遍历)
-    if (node.children) {
-      for (let i = node.children.length - 1; i >= 0; i--) {
-        stack.push(node.children[i]);
-      }
-    }
-  }
-  return result;
-}
 function delAll(){
   proxy.$modal.confirm('是否确认删除?').then(function () {
     return deTree(parTree.value.id);
@@ -878,6 +1120,7 @@ function clearFromLev(){
     itemNo:'',
     itemNotes:'',
   }
+  tableDataCanAddTree.value = []
 }
 function addNextLevel(){
   dialogVisibleLevel.value = true
@@ -927,6 +1170,33 @@ async function delSer(){
     proxy.$modal.msgSuccess("删除成功");
   }).catch(() => {});
 }
+
+// 辅助函数:根据值获取参数类型
+function getParamType(value) {
+    if (Array.isArray(value)) {
+        return 'Array';
+    } else if (value === null) {
+        return 'Null';
+    } else {
+        return typeof value === 'object' ? 'Object' : capitalizeFirstLetter(typeof value);
+    }
+}
+
+// 辅助函数:首字母大写
+function capitalizeFirstLetter(string) {
+    return string.charAt(0).toUpperCase() + string.slice(1);
+}
+
+// 辅助函数:根据参数代码获取参数名称(可根据需要扩展映射关系)
+function getParamName(paramCode) {
+    const nameMap = {
+        'typhoonId': '台风编码',
+        'typhoonName': '台风名称',
+        'data': '数据体'
+        // 可以添加更多映射
+    };
+    return nameMap[paramCode] || '';
+}
 async function saveEditService(){
   console.log(JsonAdd.value)
   var valid
@@ -979,17 +1249,24 @@ async function addSer(){
     par.rpcontent = JsonAdd.value
     par.cateCode = par.cateCode[0]
     console.log(par)
-
     await addService(par).then(res=>{
       if(res.code===200){
         var parCan = tableDataCanAdd.value
-        parCan.srvId = res.data.srvId
-        addServiceParam(parCan).then(res1=>{
+        if(parCan.length !== 0){
+          parCan.forEach((item,index) => {
+            item.srvId = res.data.srvId
+            if(item.paramName===''){
+              parCan.splice(index, 1)
+            }
+          });
+          addServiceParam(parCan).then(res1=>{
           if(res1.code===200){
-            proxy.$modal.msgSuccess("新增成功");
-            getTreeLeft()
-          }
-        })
+              proxy.$modal.msgSuccess("新增成功");
+              getTreeLeft()
+            }
+          })
+        }
+        
       }
     })
     
@@ -1003,27 +1280,254 @@ function showAdd(){
 async function handleNodeClick(node,data,event){
   parTree.value = data.data
   currentNodeKey.value = data.data.id
-  console.log(data.data.id)
   isEdit.value = false
   parId.value = data.data.id
   await getSerDe(data.data.id).then(res=>{
     detail.value = res.data.ptService
     tableDataCan.value = res.data.list
-    dataReturn.value = res.data.returnList
-    console.log(tableDataCan.value)
     dataJsonXiang.value = res.data.ptService.rpcontent
     formJi.value = res.data.ptService
     example.value = res.data.ptService.example
   })
   detail.value.nodeType = data.data.nodeType
+  var par = {
+    srvId:data.data.id
+  }
+  getServiceReturn(par).then(res=>{
+    const fullTree = buildTree1(res.data)
+    fullTree.forEach((item,index) => {
+      if(item.children && item.children.length > 0){
+        item = dfsRecursive(item)
+      }
+    });
+    dataTreeReturn.value = fullTree
+    var par = JSON.parse(dataJsonXiang.value)
+    var par1 = transformDynamicDataToTree(par)
+    par1.length = par1.length - 1
+    console.log(par1)
+  })
+}
+/**
+ * 将API返回的扁平台风数据转换为具有层级关系的树形结构数据
+ * @param {Object} sourceData - 源数据对象(结构可动态变化)
+ * @param {String} srvId - 服务ID,默认为示例值
+ * @returns {Array} 转换后的树形结构数据数组
+ */
+function transformDynamicDataToTree(sourceData) {
+    let idCounter = 1; // ID计数器,确保每个节点有唯一ID
+    const result = []; // 最终返回的结果数组
+
+    // 辅助函数:为对象中的每个属性推断类型
+    function inferType(value) {
+        if (value === null) return 'null';
+        if (Array.isArray(value)) return 'array';
+        if (typeof value === 'object') return 'object';
+        if (typeof value === 'number') {
+            // 简单区分整数和浮点数(可根据需要调整)
+            return Number.isInteger(value) ? 'int' : 'float';
+        }
+        if (typeof value === 'boolean') return 'boolean';
+        return 'string'; // 默认字符串类型
+    }
+
+    // 辅助函数:生成带层级的节点
+    function createNode(parentId, paramCode, paramValue, paramType, paramName = null, arrayIndex = null, isArray = null) {
+        const node = {
+            createBy: null,
+            createTime: null,
+            updateBy: null,
+            updateTime: null,
+            remark: null,
+            id: idCounter++,
+            parentId: parentId,
+            srvId: parId.value, // 使用传入的服务ID或示例值
+            paramCode: paramCode,
+            paramName: paramName, // 可选的友好名称
+            paramType: paramType,
+            paramValue: paramValue !== null && paramValue !== undefined ? String(paramValue) : '', // 确保值为字符串或空
+            paramFormat: null,
+            paramNote: null,
+            isArray: isArray,
+            arrayIndex: arrayIndex,
+            sort: idCounter // 简单地用ID作为排序,可根据需要调整
+        };
+        // 移除可能为null的字段,保持整洁(可选)
+        Object.keys(node).forEach(key => {
+            if (node[key] === null) {
+                delete node[key];
+            }
+        });
+        return node;
+    }
+
+    // 1. 处理根级的"data"属性(如果存在且是数组)
+    if (sourceData.data && Array.isArray(sourceData.data)) {
+        // 创建根节点 (data array)
+        const dataRootNode = createNode(0, "data", "", "array", "数据体", null, "1");
+        result.push(dataRootNode);
+        const dataRootId = dataRootNode.id; // 记录根节点ID
+
+        // 遍历data数组中的每一项
+        sourceData.data.forEach((dataItem, dataIndex) => {
+            if (typeof dataItem === 'object' && dataItem !== null) {
+                // 为数组中的每一项(如台风对象)创建一个节点,其父节点是dataRootId
+                const arrayItemNode = createNode(dataRootId, `[${dataIndex}]`, "", "object", null, dataIndex, null);
+                result.push(arrayItemNode);
+                const arrayItemId = arrayItemNode.id; // 记录当前数组项节点ID
+
+                // 遍历该项的所有属性(如typhoonId, typhoonName)
+                for (const [key, value] of Object.entries(dataItem)) {
+                    const propNode = createNode(arrayItemId, key, value, inferType(value), null, null, null);
+                    result.push(propNode);
+                }
+            } else {
+                // 处理data数组中是非对象的情况(如基本类型)
+                const arrayItemNode = createNode(dataRootId, `[${dataIndex}]`, sourceData.data[dataIndex], inferType(sourceData.data[dataIndex]), null, dataIndex, null);
+                result.push(arrayItemNode);
+            }
+        });
+    }
+
+    // 2. 处理源数据中的其他根级属性(排除已经处理的data)
+    for (const [key, value] of Object.entries(sourceData)) {
+        // 跳过已经处理过的data属性、null和undefined,以及非自有属性
+        if (key === 'data' || value === null || value === undefined || !sourceData.hasOwnProperty(key)) continue;
+
+        const rootPropNode = createNode(0, key, value, inferType(value), null, null, null);
+        result.push(rootPropNode);
+    }
+
+    // 3. 特别处理源数据中值为null或undefined的根级属性(如果需要保留这些信息)
+    for (const key in sourceData) {
+        if (sourceData[key] === null && sourceData.hasOwnProperty(key) && key !== 'data') {
+            const nullNode = createNode(0, key, "", "null", null, null, null);
+            result.push(nullNode);
+        }
+    }
+
+    return result;
+}
+function buildTree1(list, rootParentId = 0) {
+  // 1. 创建一个映射(字典)以便通过id快速查找节点,并为每个节点初始化children数组
+  const nodeMap = {};
+  const tree = [];
   
+  // 初始化映射,每个节点初始时都有空的孩子数组
+  list.forEach(item => {
+    nodeMap[item.id] = { ...item, children: [] };
+  });
+  
+  // 2. 遍历数组,根据parentId将节点放入父节点的children中
+  list.forEach(item => {
+    const node = nodeMap[item.id];
+    const parentId = item.parentId;
+    
+    if (parentId === rootParentId) {
+      // 如果parentId是根父ID(默认为0),则作为根节点直接添加到树中
+      tree.push(node);
+    } else {
+      // 否则,尝试找到父节点并将当前节点加入其children数组
+      const parentNode = nodeMap[parentId];
+      if (parentNode) {
+        parentNode.children.push(node);
+      } else {
+        // 可选:处理parentId不存在于列表中的情况(孤儿节点)
+        // 这里选择将其提升为根节点,你也可以选择其他处理方式,如console.warn报警
+        tree.push(node);
+      }
+    }
+  });
+  
+  // 3. 返回构建好的树
+  return tree;
+}
+// function dfsRecursive(node, parent = null, grandParent = null) {
+//   if (!node) return;
+  
+//   const reg = /\[\d+\]/;
+//   let firstMatchHandled = false; // 标记第一个匹配是否已处理
+
+//   if (parent && reg.test(parent.paramCode)) {
+//     if (!firstMatchHandled) {
+//       // 处理第一个匹配的节点:提升其第一个子节点
+//       if (parent.children && parent.children.length > 0) {
+//         const firstChild = parent.children[0];
+//         // 将第一个子节点添加到祖父节点的子节点数组中
+//         if (grandParent) {
+//           if (!grandParent.children) grandParent.children = [];
+//           grandParent.children.push(firstChild);
+//         }
+//       }
+//       firstMatchHandled = true;
+//     }
+    
+//     // 删除当前父节点(从祖父节点的子节点数组中移除)
+//     if (grandParent && grandParent.children) {
+//       const index = grandParent.children.indexOf(parent);
+//       if (index > -1) {
+//         grandParent.children.splice(index, 1);
+//         // 注意:这里删除了节点,可能需要调整索引
+//       }
+//     }
+//   }
+
+//   // 递归遍历所有子节点
+//   if (Array.isArray(node.children)) {
+//     // 使用 for 循环而不是 forEach,以便在删除节点时调整索引
+//     for (let i = 0; i < node.children.length; i++) {
+//       dfsRecursive(node.children[i], node, parent);
+//     }
+//   }
+// }
+function dfsRecursive(node, parent = null, grandParent = null) {
+  if (!node) return;
+   const reg = /\[\d+\]/;
+  // 如果父节点存在且paramCode匹配正则表达式
+  if (parent && reg.test(parent.paramCode)) {
+    grandParent.children = []
+    grandParent.children.push(parent);
+    parent.children.forEach(child => {
+      child.parentId = grandParent.id
+      grandParent.children.push(child);
+    });
+    grandParent.children.splice(0,1)
+  }
+  if(node.children){
+      node.children.forEach(child => {
+      dfsRecursive(child, node, parent);
+    });
+  }
+  return node; // 返回处理后的当前节点
 }
+// function dfsRecursive(node, parent = null) {
+//   if (!node) return node; // 返回节点本身
+
+//   const reg = /\[\d+\]/;
+  
+//   // 如果父节点存在且paramCode匹配正则表达式
+//   if (parent && reg.test(parent.paramCode)) {
+//     console.log("Found matching paramCode:", parent.paramCode);
+//     // 只保留第一个子节点
+//     if (node.children && node.children.length > 0) {
+//       node.children = [node.children[0]];
+//     }
+    
+//   }
+//   // 递归遍历所有子节点
+//   if (Array.isArray(node.children)) {
+//     for (let i = 0; i < node.children.length; i++) {
+//       // 递归调用并更新子节点引用
+//       node.children[i] = dfsRecursive(node.children[i], node);
+//     }
+//   }
+//   return node; // 返回处理后的当前节点
+// }
+
 async function getTreeLeft(){
   var par
   await modelTreeSelect().then(res=>{
     par = res.data
     data.value = res.data
-    
   })
   optionsMdid.value = filterModelNodes(par)
   console.log(optionsMdid.value)
@@ -1062,27 +1566,27 @@ function fetchData() {
   });
 }
 function buildTree(flatData, rootValue = '0') {
-      const nodeMap = new Map();
-      const tree = [];
-      flatData.forEach(item => {
-        nodeMap.set(item.cateCode, { ...item, children: [] });
-      });
-      for (const [code, node] of nodeMap) {
-        const parentCode = node.catePcode;
-        if (parentCode === rootValue || !parentCode) {
-          tree.push(node);
-          continue;
-        }
-        const parent = nodeMap.get(parentCode);
-        if (parent) {
-          parent.children.push(node);
-        } else {
-          console.warn(`Orphan node detected: ${code}. Parent ${parentCode} not found`);
-        }
-      }
-
-      return tree;
+  const nodeMap = new Map();
+  const tree = [];
+  flatData.forEach(item => {
+    nodeMap.set(item.cateCode, { ...item, children: [] });
+  });
+  for (const [code, node] of nodeMap) {
+    const parentCode = node.catePcode;
+    if (parentCode === rootValue || !parentCode) {
+      tree.push(node);
+      continue;
     }
+    const parent = nodeMap.get(parentCode);
+    if (parent) {
+      parent.children.push(node);
+    } else {
+      console.warn(`Orphan node detected: ${code}. Parent ${parentCode} not found`);
+    }
+  }
+
+  return tree;
+}
 function addPa(){
     var par = {
       paramName:'',
@@ -1163,6 +1667,12 @@ onMounted(() => {
 }
 </style>
 <style scoped>
+:deep(.svg-icon) {
+  outline: none;
+}
+:deep(.svg-icon svg) {
+  stroke: none;
+}
 :deep(.treeLeft) .el-tree-node__content {
   display: flex !important;
   height: 28px;                  /* 按设计稿调整高度 */