|
|
@@ -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; /* 按设计稿调整高度 */
|