<template>
<div class="business-architecture-container">
<div class="leftMenu">
<!-- 搜索框 -->
<div class="returnBack" @click="$router.go(-1)">
<i class="el-icon-d-arrow-left"></i> 返回
</div>
<div class="left-title">
业务架构树
</div>
<el-input class="left-search" v-model="sysName" placeholder="请输入搜索关键字" size="mini" @input="debouncedFetchData"
@keyup.enter.native="getBusiTree('', '', '')">
<i slot="suffix" class="el-input__icon el-icon-search" @click="getBusiTree('', '', '')"></i></el-input>
<!-- 树状组件 -->
<!-- <el-tree ref="tree" class="tree" :data="treeData" :props="defaultProps" :filter-node-method="filterNode"
:highlight-current="true" node-key="id" @node-click="handleNodeClick" :expand-on-click-node="false" :indent="0">
</el-tree> -->
<el-tree v-if="!lazy" ref="tree" class="tree" :props="lazy ? defaultProps : defaultProp" :highlight-current="true"
node-key="id" :expand-on-click-node="false" :indent="10" :lazy="lazy" :load="loadNode" key="1" :data="treeData"
@node-click="handleNodeClick" default-expand-all>
<!-- 原有自定义节点内容保持不变 -->
<!-- 自定义节点内容 -->
<span slot-scope="{ node, data }" class="custom-tree-node" :class="{
'selected-node': isNodeSelected(data.id),
'level-1': node.level === 1,
'level-2': node.level === 2,
'level-3': node.level === 3
}">
<span class="node-label">{{ getLevelPrefix(node.level) }} </span>
<span :class="[{ 'blue-text': isNodeSelected(data.id) }]">
{{ node.label }}
</span>
</span>
</el-tree>
<el-tree v-else ref="tree" class="tree" :props="defaultProps" :highlight-current="true" node-key="id"
:expand-on-click-node="false" :indent="10" :lazy="lazy" :load="loadNode" key="2" @node-click="handleNodeClick">
<!-- 原有自定义节点内容保持不变 -->
<!-- 自定义节点内容 -->
<span slot-scope="{ node, data }" class="custom-tree-node" :class="{
'selected-node': isNodeSelected(data.id),
'level-1': data.level === 1,
'level-2': data.level === 2,
'level-3': data.level === 3
}">
<span class="node-label">{{ getLevelPrefix(data.level) }}</span>
<span :class="[{ 'blue-text': isNodeSelected(data.id) }]">
{{ node.label }}
</span>
</span>
</el-tree>
</div>
<div class="y-resize"></div>
<div class="content-box">
<!-- <div class="breadcrumb">
<span>{{ currentPath.join(' / ') }}</span>
</div> -->
<detailsContent ref="detailsContent" :currentNode="currentNode"></detailsContent>
</div>
</div>
</template>
<script>
import { busiFirstThreeLevel, busiTree } from '@/api/newTwinBusinessArchitecture';
import detailsContent from './detailsContent.vue'
export default {
data() {
return {
sysName: '',
filterText: '',
currentPath: ['家庭业务体系', '宽带电视', '宽带电视解装'],
treeData: [], // 树形结构数据
currentNode: null, // 当前选中的节点
selectedNodeId: '', // 所有选中的节点ID(包括父节点)
// 树形结构配置
defaultProps: {
children: 'children',
label: 'name',
isLeaf: 'leaf'
},
defaultProp: {
children: 'children',
label: 'name',
isLeaf: 'leaf'
},
lazy: true,
};
},
components: { detailsContent },
watch: {
async sysName(val) {
if (!val) {
this.lazy = true
clearTimeout(this.debounceTimer);
const res = await busiTree({ level: 0 })
this.currentNode = res.data.data[0];
this.selectedNodeId = res.data.data[0].id;
this.$nextTick(() => {
this.$refs.detailsContent.init()
})
} else {
this.lazy = false
}
},
},
async created() {
// console.log(this.$route.query.idArr, 'this.$route.path')
if (this.$route.query.idArr) {
this.lazy = false
const sysId = this.$route.query.idArr.split(",").pop()
this.selectedNodeId = sysId
console.log(this.$route.query.idArr, 'this.$route.query.idArr')
await this.getBusiTree(sysId, '', '', 'create')
}
},
mounted() {
// console.log('mounted')
this.handleYResize()
// this.$refs.detailsContent.init()
// this.generateTreeData();
// this.handleNodeClick(this.treeData[0],{});
},
deactivated() {
clearTimeout(this.debounceTimer)
},
methods: {
//sysId=1196&level=2&parentIdArr=100044,230
async getBusiTree(sysId, level, parentIdArr, type) {
const res = await busiTree({ sysId, level, parentIdArr, name: this.sysName })
console.log('getBusiTree res.data.data: ', res.data.data);
this.treeData = res.data.data
if (this.sysName) {
this.currentNode = res.data.data[0];
this.selectedNodeId = res.data.data[0].id;
this.$nextTick(() => {
this.$refs.detailsContent.init()
})
}
else if (type === 'create') {
const sysIdArr = this.$route.query.idArr.split(",")
// 提取三级ID
const [firstId, secondId, thirdId] = sysIdArr;
// 第一步:匹配一级节点(treeData直接匹配firstId)
const firstLevelNode = this.treeData.find(
node => node.id.toString() === firstId.toString()
);
if (!firstLevelNode) {
// 一级节点未找到,currentNode设为null
this.currentNode = null;
} else {
// 第二步:在一级节点的children中匹配secondId
const secondLevelNode = firstLevelNode.children.find(
node => node.id.toString() === secondId.toString()
);
if (!secondLevelNode) {
// 二级节点未找到,currentNode设为null
this.currentNode = null;
} else {
// 第三步:在二级节点的children中匹配thirdId
const thirdLevelNode = secondLevelNode.children.find(
node => node.id.toString() === thirdId.toString()
);
// 最终赋值(找到则为三级节点,否则为null)
this.currentNode = thirdLevelNode || null;
}
}
}
this.$nextTick(() => {
this.$refs.detailsContent.init()
})
},
handleYResize() {
const box = document.getElementsByClassName('business-architecture-container')
const left = document.getElementsByClassName('leftMenu')
const resize = document.getElementsByClassName('y-resize')
const right = document.getElementsByClassName('content-box')
for (let i = 0; i < resize.length; i++) {
// 鼠标按下事件
resize[i].onmousedown = function (e) {
// 颜色改变提醒
resize[i].style.background = '#C0C4CC'
const startX = e.clientX
resize[i].left = resize[i].offsetLeft
// 鼠标拖动事件
document.onmousemove = function (e) {
const endX = e.clientX
let moveLen = resize[i].left + (endX - startX) // (endX-startX)=移动的距离。resize[i].left+移动的距离=左侧最终的高度
const maxT = box[i].clientWidth - resize[i].offsetWidth // 容器宽度 - 左边区域的宽度 = 右边区域的宽度
if (moveLen < 30) moveLen = 30 // left最小宽度度为30px
if (moveLen > maxT - 30) moveLen = maxT - 30 // right最小宽度度为30px
resize[i].style.left = moveLen // 设置left区域的宽度
for (let j = 0; j < left.length; j++) {
left[j].style.width = moveLen + 'px'
right[j].style.width = (box[i].clientWidth - moveLen - 10) + 'px'
}
}
// 鼠标松开事件
document.onmouseup = function (evt) {
// 颜色恢复
resize[i].style.background = '#ecedee'
document.onmousemove = null
document.onmouseup = null
resize[i].releaseCapture && resize[i].releaseCapture() // 当你不在需要继续获得鼠标消息就要应该调用ReleaseCapture()释放掉
}
resize[i].setCapture && resize[i].setCapture() // 该函数在属于当前线程的指定窗口里设置鼠标捕获
return false
}
}
},
// 搜索树
async debouncedFetchData() {
this.lazy = false
clearTimeout(this.debounceTimer)
this.debounceTimer = setTimeout(() => {
this.getBusiTree('', '', '')
}, 500)
},
// // 树节点过滤方法
// filterNode(value, data) {
// if (!value) return true;
// return data.name.indexOf(value) !== -1;
// },
// 处理节点点击事件
handleNodeClick(data, node) {
!this.sysName && (this.lazy = true)
console.log(data, '处理节点点击事件 data,')
console.log(node, '处理节点点击事件 node')
// 统一数据结构处理
this.currentNode = {
...data,
// // 非懒加载模式从node获取层级
// level: !this.lazy ? node.level : data.level,
// // 确保parentIdArr存在
// parentIdArr: data.parentIdArr || []
};
// 安全处理节点ID数组
this.selectedNodeId = this.currentNode.id;
console.log('this.currentNode', this.currentNode)
this.$nextTick(() => {
this.$refs.detailsContent.init()
})
},
// 判断节点是否被选中
isNodeSelected(id) {
return this.selectedNodeId.includes(id);
},
// 获取层级前缀
getLevelPrefix(level) {
switch (level) {
case 1: return '体系';
case 2: return '业务';
case 3: return '场景';
default: return '';
}
},
async loadNode(node, resolve) {
console.log('loadNode node, resolve', node, resolve)
if (node.level === 0) { // 根节点加载
const res = await busiTree({ level: 0 })
this.currentNode = res.data.data[0];
this.selectedNodeId = res.data.data[0].id;
this.$nextTick(() => {
this.$refs.detailsContent.init()
})
return resolve(res.data.data)
}
// 获取当前节点信息
const currentNode = node.data
const params = {
sysId: currentNode.id,
level: currentNode.level,
parentIdArr: currentNode.parentIdArr ? currentNode.parentIdArr + '' : []
}
try {
const res = await busiTree(params)
resolve(res.data.data)
} catch (error) {
resolve([])
}
},
// 格式化树节点数据
formatTreeData(nodes) {
return nodes.map(node => ({
...node,
hasChild: node.children && node.children.length > 0
}))
},
// 获取父节点ID链
// getParentIds(node) {
// const ids = []
// let parent = node.parent
// while (parent && parent.level !== 0) {
// ids.unshift(parent.data.id)
// parent = parent.parent
// }
// return ids.join(',')
// }
}
};
</script>
<style scoped lang="less">
.business-architecture-container {
height: 100%;
display: flex;
padding: 5px;
// .business-architecture-container {
// display: flex;
background: #fff;
// height: 100%;
.y-resize {
width: 10px;
height: 100%;
// background: #ecedee;
background: #fff;
cursor: w-resize;
}
.leftMenu {
width: 15%;
height: 100%;
overflow-y: auto;
// background-size: cover;
// border: #ecedee 1px solid;
.left-title {
color: #353535;
padding: 2px 5px 5px;
}
.left-search {
padding: 5px;
}
.blue-text {
color: #409EFF;
}
/deep/.el-tree-node__content {
height: 35px;
}
.node-label {
margin-right: 20px;
border-radius: 3px;
padding: 1px 5px;
font-size: 14px;
}
/* 层级标识 */
.level-1 .node-label {
/* font-weight: bold; */
color: #d42a38;
border: 1px solid #ffc9c6;
background: #fff1f0;
}
.level-2 .node-label {
/* padding-left: 10px; */
color: #e1ab4a;
border: 1px solid #ffe99f;
background: #fffbe6;
}
.level-3 .node-label {
/* padding-left: 20px; */
color: #84b713;
border: 1px solid #ecff97;
background: #fcffe6;
}
}
.content-box {
flex: 1;
height: 100%;
border-radius: 4px;
overflow-y: auto;
padding: 10px 15px 0 0;
.breadcrumb {
padding: 5px;
margin-bottom: 10px;
// font-size: 16px;
color: #606266;
}
// .breadcrumb span {
// color: #409EFF;
// }
}
.returnBack {
width: 100px;
color: #66b1ff;
cursor: pointer;
}
}
</style>
优化以上代码 实现 :
将两棵树合并成一棵树,实现现有两棵树的效果 或者实现两棵树无痕切换
最新发布