子组件
<template>
<div class="relation">
<div class="compose-trunk">
<div v-if="!isEmptyObj(currentNode) && currentNode.conditions.length > 0">
<div
class="compose-leaf rule-leaf"
v-for="(subItem, subIndex) in currentNode.conditions"
:key="subIndex"
>
<div class="item leaf-item leaf-edit">
<el-select
v-model="subItem.dimension"
placeholder="请选择维度"
size="mini"
>
<el-option
v-for="(dItem, DIndex) in dimensionList"
:key="DIndex"
:value="dItem.columnName"
:label="dItem.columnName"
></el-option>
</el-select>
<i
class="el-icon-circle-close close"
@click="handleDeleteDimension(subIndex)"
></i>
</div>
<div class="rule-text">
<span
v-if="
subItem.dimensionSubGroup.conditionDetails[0].value == '' &&
subItem.dimensionSubGroup.conditionDetails[0].subOperator == ''
"
>该维度暂未设置条件</span
>
<i
class="cond"
v-if="
subItem.dimensionSubGroup.conditionDetails[0].value == '' &&
subItem.dimensionSubGroup.conditionDetails[0].subOperator == ''
"
@click="handleSetConfig(subItem, subIndex)"
>设置条件</i
>
<i class="cond" v-else @click="handleSetConfig(subItem, subIndex)"
>修改条件</i
>
</div>
</div>
</div>
<div
v-if="
currentNode.subGroups &&
currentNode.subGroups.length > 0 &&
maxDepth > 0
"
>
<!--递归-->
<tree-node
v-for="(nodeItem, nodeIndex) in currentNode.subGroups"
:key="nodeIndex"
class="tree-node"
:nodeData="nodeItem"
:maxDepth="maxDepth - 1"
:dimensionList="dimensionList"
></tree-node>
</div>
<div class="compose-add" v-if="!isEmptyObj(currentNode)">
<div class="item add-item">
<el-dropdown>
<div class="add-btn"><i class="el-icon-plus"></i>添加</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="handleAddFather(currentNode)"
>添加父层关系</el-dropdown-item
>
<el-dropdown-item @click.native="handleAddChild(currentNode)"
>添加子层关系</el-dropdown-item
>
<el-dropdown-item @click.native="handleAddBrother(currentNode)"
>添加维度条件</el-dropdown-item
>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
<div class="compose-node" v-if="!isEmptyObj(currentNode)">
<div class="item node-item">
<el-select
class="node"
v-model="currentNode.logicalOperator"
placeholder="请选择"
size="mini"
>
<el-option label="且" value="AND"></el-option>
<el-option label="或" value="OR"></el-option>
</el-select>
<i
class="el-icon-circle-close close"
@click="handleDeleteNode(currentNode)"
></i>
</div>
</div>
</div>
</div>
</template>
<script>
import Bus from '@/assets/js/eventBus'
export default {
name: 'TreeNode',
props: {
nodeData: {
type: Object,
default: () => {
return {}
},
},
dimensionList: {
type: Array,
},
maxDepth: {
type: Number,
default: 4,
},
},
data() {
return {
value: 'and',
currentNode: this.nodeData,
}
},
methods: {
isEmptyObj(obj) {
return Object.keys(obj).length === 0
},
handleAddFather(data) {
let newData = {
logicalOperator: 'AND',
conditions: [],
subGroups: [
{
logicalOperator: data.logicalOperator,
id: Date.now() + 1,
conditions: [].concat(data.conditions),
},
],
}
this.currentNode = newData
},
handleAddChild(data) {
console.log('zi', data)
if (data.subGroups == undefined) {
let obj = [
{
logicalOperator: 'AND',
conditions: [
{
dimension: '',
dimensionSubGroup: {
logicalOperator: '',
conditionDetails: [
{
dimension: '',
operator: '',
value: '',
subOperator: null,
},
],
},
},
],
},
]
this.$set(data, 'subGroups', obj)
} else {
data.subGroups.push({
logicalOperator: 'AND',
conditions: [
{
dimension: '',
dimensionSubGroup: {
logicalOperator: '',
conditionDetails: [
{
dimension: '',
operator: '',
value: '',
subOperator: null,
},
],
},
},
],
})
}
},
handleAddBrother(data) {
console.log('data---', data)
let obj = {
dimension: '',
dimensionSubGroup: {
logicalOperator: '',
conditionDetails: [
{
dimension: '',
operator: '',
value: '',
subOperator: null,
},
],
},
}
data.conditions.push(obj)
},
handleDeleteDimension(index) {
console.log('this.nodeData----', this.nodeData)
this.currentNode.conditions.splice(index, 1)
Bus.$emit('getNodeData', this.nodeData)
},
handleDeleteNode(data) {
console.log('this.nodeData----', this.nodeData)
this.currentNode = {}
Bus.$emit('getNodeData', this.nodeData)
},
},
}
</script>
<style lang="scss" scoped>
.compose-trunk {
margin-left: 57px;
overflow: hidden;
position: relative;
vertical-align: top;
}
.compose-leaf,
.compose-leaf .leaf-item {
position: relative;
}
.compose-leaf {
margin-left: 94px;
padding-right: 80px;
padding-top: 12px;
}
.compose-leaf .leaf-edit {
height: 28px;
line-height: 27px;
width: 140px;
}
.compose-leaf:first-child .leaf-item:before {
@include theme_background_color('mainBackColor');
content: '';
height: 30px;
left: -37px;
position: absolute;
top: -17px;
width: 1px;
z-index: 1;
}
.compose-leaf:first-child .leaf-item:after {
border-top: 1px solid #ccc;
content: '';
left: -37px;
position: absolute;
top: 13px;
width: 37px;
}
.compose-leaf + .compose-leaf .leaf-item:after,
.compose-trunk + .compose-leaf .leaf-item:after {
border: 1px solid #ccc;
border-width: 0 0 1px 1px;
content: '';
height: 10px;
left: -37px;
position: absolute;
top: 4px;
width: 37px;
}
.compose-add,
.compose-add .add-item {
position: relative;
}
.compose-add {
margin-left: 94px;
padding-right: 80px;
padding-top: 12px;
}
.compose-leaf .compose-add .add-item:before,
.compose-trunk .compose-add .add-item:before {
border-left: 1px solid #ccc;
bottom: 19px;
content: '';
left: -37px;
position: absolute;
top: -10000px;
}
.compose-leaf .compose-add .add-item:after,
.compose-trunk .compose-add .add-item:after {
border: 1px solid #ccc;
border-width: 0 0 1px 1px;
content: '';
height: 10px;
left: -37px;
position: absolute;
top: 4px;
width: 37px;
}
.compose-add .add-item .add-btn {
color: var(--main-color);
cursor: pointer;
height: 28px;
line-height: 28px;
padding: 0 6px;
width: 100px;
}
.compose-node {
left: 0;
margin-left: 34px;
margin-top: -18px;
padding-top: 12px;
position: absolute;
top: 50%;
}
.compose-node .item {
position: relative;
}
.compose-node .close {
@include theme_background_color('moduleBackColor');
color: var(--main-color);
display: none;
position: absolute;
right: -3px;
top: 3px;
}
.compose-node .item:hover {
.close {
display: block;
}
::v-deep {
.el-input .el-input__inner:hover {
border: 1px solid var(--main-color);
}
}
}
.compose-trunk .compose-trunk:first-child > .compose-node .node-item:before {
@include theme_background_color('mainBackColor');
content: '';
height: 99999px;
left: -35px;
position: absolute;
top: -99988px;
width: 1px;
z-index: 2;
}
.compose-trunk .compose-trunk:first-child > .compose-node .node-item:after {
border-top: 1px solid #ccc;
content: '';
left: -37px;
position: absolute;
top: 11px;
width: 37px;
}
.compose-leaf + .compose-trunk > .compose-node .node-item:after,
.compose-trunk + .compose-trunk > .compose-node .node-item:after {
border: 1px solid #ccc;
border-width: 0 0 1px 1px;
content: '';
height: 10px;
left: -37px;
position: absolute;
top: 0;
width: 37px;
}
.compose-leaf .rule-text {
left: 150px;
position: absolute;
top: 5px;
}
.compose-leaf .rule-text span {
display: inline-block;
max-width: 300px;
overflow: hidden;
word-wrap: normal;
text-overflow: ellipsis;
vertical-align: middle;
white-space: nowrap;
}
.compose-leaf .rule-text .cond {
padding-left: 5px;
position: static;
vertical-align: middle;
color: var(--main-color);
cursor: pointer;
}
.compose-leaf .close {
color: var(--main-color);
display: none;
position: absolute;
right: -5px;
top: -5px;
@include theme_background_color('moduleBackColor');
}
.compose-leaf .item:hover {
.close {
display: block;
}
::v-deep {
.el-input .el-input__inner:hover {
border: 1px solid var(--main-color);
}
}
}
.node {
width: 47px;
::v-deep {
.el-input .el-input__inner {
border-radius: 60px;
height: 24px;
line-height: 24px;
padding: 0 14px 0;
}
.el-input .el-input__inner:hover {
border: 1px solid var(--main-color);
}
.el-input__suffix {
width: 5px;
top: -3px;
}
.el-input__icon {
width: 5px;
}
}
}
</style>
父组件调用
<tree-node-all
:nodeData="treeData"
:dimensionList="dimensionList"
:maxDepth="maxDepth"
></tree-node-all>
数据格式参考
treeData: {
logicalOperator: 'AND',
conditions: [
{
dimension: '',
dimensionSubGroup: {
logicalOperator: '',
conditionDetails: [
{
dimension: '',
operator: '',
value: '',
subOperator: null,
},
],
},
},
{
dimension: '',
dimensionSubGroup: {
logicalOperator: '',
conditionDetails: [
{
dimension: '',
operator: '',
value: '',
subOperator: null,
},
],
},
},
],
},
效果
