v-if="showCheckbox && showAllCheckbox" v-model="isSelectAll" @change="selectAll" /> {{ leftTitle }}
{{ leftTotal }}
v-model="filterText" prefix-icon="el-icon-search" :placeholder="placeholder" class="sy-transfer-input" clearable /> v-if="leftArr.length" ref="tree" class="sy-transfer-ul" :data="leftArr" :node-key="nodeKey" :props="defaultTreeProps" :default-expand-all="defaultExpandAll" :filter-node-method="filterNode" :show-checkbox="showCheckbox" :default-expanded-keys="defaultExpandedKeys" :default-checked-keys="defaultCheckedKeys" :current-node-key="currentNodeKey" :highlight-current="highlightCurrent" :check-strictly="checkStrictly" @node-click="handleNodeleftClick" @check="handleCheckleftChange" /> 暂无数据
style="
display: flex;
flex-direction: row;
align-items: center;
margin: 16px;
"
>
type="primary" icon="el-icon-arrow-left" circle :disabled="leftdisabled" @click="Btnleft" /> type="primary" icon="el-icon-arrow-right" circle :disabled="rightdisabled" @click="Btnright" />
v-if="showCheckbox && showAllCheckbox" v-model="isSelectrightAll" @change="selectrightAll" /> {{ rightTitle }}
{{ rightTotal }}
v-model="filterrightText" prefix-icon="el-icon-search" :placeholder="placeholder" class="sy-transfer-input" clearable /> v-if="rightArr.length" ref="righttree" class="sy-transfer-ul" :data="rightArr" :node-key="nodeKey" :props="defaultTreeProps" :default-expand-all="defaultExpandAll" :filter-node-method="filterNode" :show-checkbox="showCheckbox" :default-expanded-keys="defaultExpandedKeys" :default-checked-keys="defaultrightCheckedKeys" :current-node-key="currentrightNodeKey" :highlight-current="highlightCurrent" :check-strictly="checkStrictly" @node-click="handleNodeClick" @check="handleCheckChange" /> 暂无数据
export default {
name: 'SyTreeTransfer',
props: {
// 左边标题
leftTitle: {
type: String,
default: '备选列表',
},
// 右边标题
rightTitle: {
type: String,
default: '已选列表',
},
placeholder: {
type: String,
default: '请输入关键字',
},
// 左边初始数据
data: {
type: Array,
default: () => [],
},
// 左边初始显示数据
rightdata: {
type: Array,
default: () => [],
},
defaultTreeProps: {
type: Object,
default: () => ({
children: 'children',
label: 'label',
value: 'id'
}),
},
showCheckbox: {
type: Boolean,
default: true,
},
// 是否多选时有全选
showAllCheckbox: {
type: Boolean,
default: true,
},
openleftTotal: {
type: Boolean,
default: true,
},
openrightTotal: {
type: Boolean,
default: true,
},
nodeKey: {
type: String,
default: 'id',
},
defaultExpandAll: {
type: Boolean,
default: true,
},
defaultExpandedKeys: {
type: Array,
default: () => [],
},
// 左边回显
defaultCheckedKeys: {
type: Array,
default: () => [],
},
// 右边回显
defaultrightCheckedKeys: {
type: Array,
default: () => [],
},
currentNodeKey: {
type: [String, Number],
default: '',
},
currentrightNodeKey: {
type: [String, Number],
default: '',
},
highlightCurrent: {
type: Boolean,
default: false,
},
checkStrictly: {
type: Boolean,
default: false,
},
// 右边显示是否去掉父节点
rightcheckStrictly: {
type: Boolean,
default: true,
},
},
data() {
return {
isSelectAll: false,
isSelectrightAll: false,
filterText: '',
filterrightText: '',
leftArr: [], // 左边树数组
rightArr: [], // 右边树数组
leftTotal: 0,
rightTotal: 0,
NodeleftData: {},
leftdisabled: true,
rightdisabled: true,
leftArrlod: [],
}
},
watch: {
data: {
handler(newVal) {
this.leftArr = JSON.parse(JSON.stringify(newVal)) || []
// 标记下标字段,方便后面穿梭处理
this.leftArr.forEach((item, index) => {
item.syindexKey = index
})
this.leftArrlod = newVal
},
deep: true,
immediate: true,
},
rightdata: {
handler(newVal) {
this.rightArr = JSON.parse(JSON.stringify(newVal)) || []
// 标记下标字段,方便后面穿梭处理
this.rightArr.forEach((item, index) => {
item.syindexKey = index
})
this.$nextTick(() => {
this.rightdisabled = false
this.leftdisabled = true
if (newVal.length > 0) {
this.$refs.righttree.setCheckedKeys([])
}
})
},
deep: true,
immediate: true,
},
filterText(val) {
this.$refs.tree.filter(val)
},
filterrightText(val) {
this.$refs.righttree.filter(val)
},
defaultCheckedKeys(newVal) {
if (newVal && newVal.length > 0) {
this.$nextTick(() => {
const nodes = this.$refs.tree.getCheckedNodes()
this.leftTotal = nodes.length
this.rightdisabled = false
this.leftdisabled = true
this.isAllChecked('tree')
this.$refs.tree.setCheckedKeys(newVal)
})
}
},
},
methods: {
isAllChecked(type) {
// 判断是否全选
const allNodes = this.$refs[type].store.nodesMap
const allNodesarr = []
const arr = []
for (const key in allNodes) {
if (allNodes[key].level === 1) {
allNodesarr.push(allNodes[key])
}
}
const allarr = this.getallNodesarr(allNodesarr)
allarr.forEach((item) => {
if (item.childNodes) {
if (item.childNodes.length > 0) {
item.childNodes.forEach((v) => {
if (!v.checked && !v.disabled) {
arr.push(v)
}
})
} else {
if (!item.checked) {
arr.push(item)
}
}
}
})
if (arr && arr.length === 0) {
if (type === 'tree') {
this.isSelectAll = true
} else {
this.isSelectrightAll = true
}
} else {
if (type === 'tree') {
this.isSelectAll = false
} else {
this.isSelectrightAll = false
}
}
},
// 全选/不全选
selectAll() {
if (this.isSelectAll) {
// 设置目前勾选的节点,使用此方法必须设置 node-key 属性
this.$refs.tree.setCheckedNodes(this.leftArr)
this.rightdisabled = false
this.$nextTick(() => {
const nodes = this.$refs.tree.getCheckedNodes()
this.leftTotal = nodes.length || 0
})
} else {
// 全部不选中
this.$refs.tree.setCheckedNodes([])
this.rightdisabled = true
this.leftTotal = 0
}
},
// 右边全选/不全选
selectrightAll() {
if (this.isSelectrightAll) {
// 设置目前勾选的节点,使用此方法必须设置 node-key 属性
this.$refs.righttree.setCheckedNodes(this.rightArr)
this.leftdisabled = false
this.$nextTick(() => {
const nodes = this.$refs.righttree.getCheckedNodes()
this.rightTotal = nodes.length || 0
})
} else {
// 全部不选中
this.$refs.righttree.setCheckedNodes([])
this.leftdisabled = true
this.rightTotal = 0
}
},
// 点击向左边
Btnleft() {
if (this.showCheckbox) {
const rightnodes = this.$refs.righttree.getCheckedNodes()
const nodes = this.$refs.tree.getCheckedNodes(true)
const rightId = []
const arr = []
const arrId = []
if (rightnodes) {
rightnodes.forEach((item) => {
rightId.push(item[this.nodeKey])
})
this.rightArr.forEach((item) => {
if (!rightId.includes(item[this.nodeKey])) {
arr.push(item)
}
})
}
if (nodes) {
nodes.forEach((item) => {
if (!rightId.includes(item[this.nodeKey])) {
arrId.push(item[this.nodeKey])
}
})
this.$nextTick(() => {
this.leftArrlod = JSON.parse(JSON.stringify(this.leftArr))
this.$refs.tree.setCheckedKeys(arrId)
this.$refs.righttree.setCheckedKeys([])
this.isSelectrightAll = false
this.leftdisabled = true
this.isSelectAll = false
this.rightTotal = 0
})
}
if (this.isSelectrightAll) {
this.rightArr = []
} else {
this.rightArr = arr || []
}
if (arrId.length === 0) {
this.rightdisabled = true
} else {
this.rightdisabled = false
}
this.$nextTick(() => {
const nodesl = this.$refs.tree.getCheckedNodes()
this.leftTotal = nodesl.length || 0
})
const params = {
checkedNodes: this.rightArr,
}
this.$emit('Btnleft', params)
} else {
this.rightdisabled = true
this.rightArr = []
this.rightTotal = 0
this.$emit('Btnleft', {})
this.leftdisabled = true
}
},
// 单选-右边选中数据
handleNodeClick() {
if (!this.showCheckbox) {
this.rightTotal = 1
this.leftdisabled = false
}
},
// 多选-右边选中数据
handleCheckChange(a, b, c) {
this.rightTotal = b.checkedNodes.length || 0
this.$nextTick(() => {
this.isAllChecked('righttree')
if (b.checkedNodes.length === 0) {
this.leftdisabled = true
} else {
this.leftdisabled = false
}
})
},
// 单选-左边选中数据
handleNodeleftClick(data) {
if (!this.showCheckbox) {
this.leftTotal = 1
this.rightdisabled = false
this.NodeleftData = data
}
},
// 多选-左边选中数据
handleCheckleftChange(a, b, c) {
this.leftTotal = b.checkedNodes.length || 0
this.$nextTick(() => {
if (b && b.checkedNodes && b.checkedNodes.length > 0) {
this.rightdisabled = false
this.isAllChecked('tree')
} else {
this.rightdisabled = true
this.isSelectAll = false
}
})
},
// 点击向右边
Btnright() {
if (this.showCheckbox) {
const nodes = this.$refs.tree.getCheckedNodes(true)
const arrIds = []
nodes.forEach((item) => {
arrIds.push(item[this.defaultTreeProps.value])
})
if (this.rightcheckStrictly) {
// 去掉父节点
this.rightArr = nodes || []
} else {
// 不去掉父节点
let allarr = []
const allNodes = this.$refs.tree.store.nodesMap
const allNodesarr = []
for (const key in allNodes) {
if (allNodes[key].level === 1) {
allNodesarr.push(allNodes[key])
}
}
const arrList = this.getarrList(allNodesarr, arrIds)
arrList.forEach((item) => {
allarr.push(item.data)
})
allarr = this.unique(allarr)
this.rightArr = allarr || []
}
this.$nextTick(() => {
this.leftArr = JSON.parse(JSON.stringify(this.leftArrlod))
this.$refs.tree.setCheckedKeys(arrIds)
this.$refs.righttree.setCheckedKeys([])
this.rightTotal = 0
})
this.isSelectrightAll = false
this.$emit('Btnright', nodes, this.rightArr)
} else {
this.leftTotal = 0
this.rightArr = [this.NodeleftData]
this.$emit('Btnright', this.NodeleftData)
}
this.leftdisabled = true
this.$forceUpdate()
},
// 去重
unique(arr) {
const res = new Map()
return arr.filter(
(arr) =>
!res.has(arr[this.defaultTreeProps.value]) &&
res.set(arr[[this.defaultTreeProps.value]], 1)
)
},
getarrList(List, arrIds) {
const arr = []
if (List) {
for (const i in List) {
if (List[i].checked) {
arr.push(List[i])
} else {
if (List[i].childNodes) {
List[i].childNodes.forEach((item) => {
if (item.checked) {
item.parent.data[this.defaultTreeProps.children] =
item.parent.data[this.defaultTreeProps.children].filter(
(v) => {
return arrIds.includes(v[this.defaultTreeProps.value])
}
)
arr.push(item.parent)
}
})
this.getarrList(List[i].childNodes, arrIds)
}
}
}
}
return arr
},
getallNodesarr(List) {
const arr = []
if (List) {
for (const i in List) {
if (!List[i].checked) {
arr.push(List[i])
if (List[i].childNodes) {
List[i].childNodes.forEach((item) => {
if (!item.checked && !item.disabled) {
arr.push(item.parent)
}
})
this.getallNodesarr(List[i].childNodes)
}
}
}
}
return arr
},
// 过滤树结构规则
filterNode(value, data) {
if (!value) return true
return data[this.defaultTreeProps.label].indexOf(value) !== -1
},
},
}
.sy-transfer {
display: flex;
align-items: center;
color: #48505b;
.sy-transfer-left,
.sy-transfer-right {
width: 295px;
height: 444px;
background: #ffffff;
border: 1px solid #e3e5e8;
border-radius: 4px;
}
.sy-transfer-middle {
margin: 0 20px;
font-size: 22px;
color: #c4c4c4;
transform: rotate(90deg);
}
.sy-transfer-list-title {
display: flex;
justify-content: space-between;
align-items: center;
background-color: #f4f4f5;
padding: 8px 15px;
.sy-transfer-list-title-text {
font-size: 16px;
padding-right: 20px;
}
.sy-transfer-list-num {
font-size: 12px;
color: #86909c;
}
}
.sy-transfer-input {
margin: 12px 16px;
width: calc(100% - 32px);
::v-deep .el-input__inner {
border-radius: 32px;
}
}
.sy-transfer-ul {
height: calc(100% - 95px);
margin: 0;
padding: 0;
font-size: 14px;
color: #48505b;
overflow-y: auto;
li {
position: relative;
display: flex;
align-items: center;
padding: 7px 17px;
cursor: pointer;
.sy-transfer-icon {
color: #4b9cd5;
margin-right: 10px;
}
.sy-transfer-label {
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
li:hover {
background-color: #f4f4f5;
}
.sy-transfer-disabled {
color: #c0c4cc;
cursor: not-allowed;
}
}
.sy-transfer-right {
.sy-transfer-ul {
height: calc(100% - 40px);
.sy-transfer-close::after {
content: 'X';
position: absolute;
right: 20px;
top: 50%;
transform: translateY(-50%);
font-size: 14px;
color: #515972;
}
.sy-transfer-label {
padding-right: 20px;
}
}
}
.sy-transfer-nothing {
text-align: center;
color: #86909c;
font-size: 14px;
margin-top: 54px;
}
}