<template lang="html">
|
<div class="tree-transfer">
|
<div class="transfer-panel unselect">
|
<!-- <div class="transfer-panel__header">
|
<el-checkbox v-model="leftCheckAll" @change="clickLeftCheckAll">待选</el-checkbox>
|
</div> -->
|
<div class="transfer-panel__content">
|
<el-input size="mini" placeholder="输入关键字进行过滤" v-model="leftFilterText">
|
</el-input>
|
<el-tree filter ref="tree" :data="leftNodeData" show-checkbox node-key="proId"
|
:filter-node-method="filterNode" @check="nodeClick" :props="defaultProps">
|
</el-tree>
|
</div>
|
</div>
|
<div class="button">
|
<div :class="['btn', { 'disabled': !toLeft }]" @click="removeToLeft">
|
移除
|
</div>
|
<div :class="['btn', { 'disabled': !toRight }]" @click="removeToRight">
|
添加
|
</div>
|
</div>
|
<div class="transfer-panel selected">
|
<!-- <div class="transfer-panel__header">
|
<el-checkbox v-model="rightCheckAll" @change="clickRightCheckAll">已选</el-checkbox>
|
</div> -->
|
<div class="transfer-panel__content">
|
<el-input size="mini" placeholder="输入关键字进行过滤" v-model="rightFilterText">
|
</el-input>
|
<el-tree ref="selectedTree" :data="rightNodeData" show-checkbox node-key="proId"
|
:filter-node-method="filterNode" @check="selectedClick" :props="defaultProps">
|
</el-tree>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
export default {
|
props: {
|
defaultProps: {
|
type: Object,
|
default: () => {
|
return {
|
children: 'children',
|
label: 'name'
|
}
|
}
|
},
|
treeData: {
|
type: Array,
|
default: () => {
|
return []
|
}
|
},
|
defaultKeys: {
|
type: Array,
|
default: () => {
|
return []
|
}
|
}
|
},
|
watch: {
|
leftFilterText(val) {
|
this.$refs.tree.filter(val)
|
},
|
rightFilterText(val) {
|
this.$refs.selectedTree.filter(val)
|
},
|
rightKeys(val) {
|
this.$emit('changeKeys', val)
|
}
|
},
|
data() {
|
return {
|
leftCheckAll: false,
|
rightCheckAll: false,
|
toLeft: false,
|
toRight: false,
|
nodeData: this.treeData,
|
leftNodeData: [],
|
rightNodeData: [],
|
rightKeys: this.defaultKeys,
|
rightFilterText: '',
|
leftFilterText: ''
|
}
|
},
|
created() {
|
this.leftNodeData = this.nodeData
|
console.log(this.leftNodeData,111);
|
|
this.rightKeys.length > 0 ? this.rerenderData(this.rightKeys) : ''
|
},
|
methods: {
|
clickLeftCheckAll(v) {
|
//左侧全选
|
if (v) {
|
|
let keys = this.getChildNodeKeys(this.leftNodeData)
|
this.$refs.tree.setCheckedKeys(keys)
|
this.toRight = true
|
} else {
|
this.$refs.tree.setCheckedKeys([])
|
this.toRight = false
|
}
|
},
|
clickRightCheckAll(v) {
|
//右侧全选
|
if (v) {
|
let keys = this.getChildNodeKeys(this.rightNodeData)
|
this.$refs.selectedTree.setCheckedKeys(keys)
|
this.toLeft = true
|
} else {
|
this.$refs.selectedTree.setCheckedKeys([])
|
this.toLeft = false
|
}
|
},
|
//获取某个节点的子节点的id值
|
getChildNodeKeys(node) {
|
let keys = []
|
let childrenName = this.defaultProps.children
|
node.forEach((item) => {
|
if (item[childrenName].length > 0) {
|
item[childrenName].forEach((item2) => {
|
keys.push(item2.proId)
|
})
|
}
|
})
|
return keys
|
},
|
filterNode(value, data) {
|
let labelName = this.defaultProps.label
|
if (!value) return true
|
return data[labelName].indexOf(value) !== -1
|
},
|
nodeClick() {
|
let keys = this.$refs.tree.getCheckedKeys(true)
|
if (keys.length > 0) {
|
this.toRight = true
|
}
|
},
|
selectedClick() {
|
let keys = this.$refs.selectedTree.getCheckedKeys(true)
|
if (keys.length > 0) {
|
this.toLeft = true
|
}
|
},
|
removeToRight() {
|
//向右移动
|
//获取此时左边树状结构中被选中的节点,使用原始数据结构删除不包含在选中数组中的节点,创建新的数组,渲染在右侧
|
//获取此时左侧中被选中的节点数组id
|
this.leftCheckAll = false
|
this.leftFilterText = ""
|
let keys = this.$refs.tree.getCheckedKeys(true)
|
let checkedKeys = [...this.rightKeys, ...keys]
|
this.rightKeys = checkedKeys
|
this.rerenderData(this.rightKeys)
|
this.toRight = false
|
this.$refs.tree.setCheckedKeys([])
|
},
|
removeToLeft() {
|
//向左移动的时候
|
//说明有已选择的数据改变,此时判断右边选中的数据重新渲染左边树状的结构
|
//渲染逻辑:使用原始数据结构删除包含在右边选中数组中的数组
|
//找到目前被选中的keys,从rightKeys中去掉,在使用rightKeys过滤左右两侧数组
|
this.rightCheckAll = false
|
this.rightFilterText = ""
|
let keys = this.$refs.selectedTree.getCheckedKeys(true)
|
this.rightKeys = this.rightKeys.filter(v => {
|
return !keys.includes(v)
|
})
|
let checkedKeys = this.rightKeys
|
this.rerenderData(checkedKeys)
|
this.toLeft = false
|
this.$refs.selectedTree.setCheckedKeys([])
|
},
|
rerenderData(checkedKeys) {
|
let childrenName = this.defaultProps.children
|
let leftNodeData = JSON.parse(JSON.stringify(this.nodeData))
|
let rightNodeData = JSON.parse(JSON.stringify(this.nodeData))
|
for (let i = 0; i < rightNodeData.length; i++) {
|
if (rightNodeData[i][childrenName].length > 0) {
|
let children = rightNodeData[i][childrenName]
|
for (let j = 0; j < children.length; j++) {
|
if (!checkedKeys.includes(children[j].proId)) {
|
children.splice(j, 1)
|
j--
|
}
|
}
|
}
|
if (!rightNodeData[i][childrenName].length > 0) {
|
rightNodeData.splice(i, 1)
|
i--
|
}
|
}
|
|
//左侧渲染:包含的删除
|
for (let i = 0; i < leftNodeData.length; i++) {
|
if (leftNodeData[i][childrenName].length > 0) {
|
let children = leftNodeData[i][childrenName]
|
for (let j = 0; j < children.length; j++) {
|
if (checkedKeys.includes(children[j].proId)) {
|
children.splice(j, 1)
|
j--
|
}
|
}
|
}
|
if (!leftNodeData[i][childrenName].length > 0) {
|
leftNodeData.splice(i, 1)
|
i--
|
}
|
}
|
this.rightNodeData = rightNodeData
|
this.leftNodeData = leftNodeData
|
}
|
}
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
.tree-transfer {
|
display: flex;
|
justify-content: center;
|
.transfer-panel {
|
box-sizing: border-box;
|
width: 322px;
|
height: 460px;
|
border: 1px solid #ebeef5;
|
border-radius: 5px;
|
.transfer-panel__header {
|
box-sizing: border-box;
|
height: 40px;
|
border-bottom: 1px solid #ebeef5;
|
background-color: rgb(245, 247, 250);
|
padding-left: 10px;
|
line-height: 40px;
|
.title {
|
font-size: 16px;
|
margin-left: 5px;
|
}
|
}
|
|
.transfer-panel__content {
|
height: calc(100% - 40px);
|
overflow-y: scroll;
|
}
|
}
|
|
.button {
|
width: 80px;
|
// display: flex;
|
// justify-content: center;
|
align-items: center;
|
min-height: 480px;
|
line-height: 480px;
|
padding-top: 140px;
|
div {
|
margin-left: 10px;
|
width: 55px;
|
height: 40px;
|
background-color: rgb(64, 158, 255);
|
line-height: 40px;
|
text-align: center;
|
color: #fff;
|
font-weight: 700;
|
border-radius: 5px;
|
}
|
|
.disabled {
|
background-color: rgb(160, 207, 255);
|
margin: 10px;
|
}
|
}
|
}
|
</style>
|