效果图:
代码:
<template>
<div
name="input-tree"
id="input-tree"
>
<div class="el-input el-input--suffix">
<input
type="text"
placeholder="请选择"
class="el-input__inner"
@click="handleIconClick"
v-if="theSelected.all.length===0"
:disabled="theEdit"
:readonly="true"
>
<div
v-else
class="el-textarea__inner"
@click.stop="handleIconClick"
>
<!-- 选中的标签 -->
<el-tag
v-for="item in theSelected.all"
:key="item.albumid"
size="small"
type="success"
:closable="true"
@close="deleteTag($event, item)"
disable-transitions
>
<el-tooltip
:content="item.label"
placement="bottom-start"
>
<span>{{ item.label }}</span>
</el-tooltip>
</el-tag>
</div>
<span class="el-input__suffix">
<span class="el-input__suffix-inner">
<span
:class="['hand', 'el-icon-arrow-' + iconClass]"
@click.stop="handleIconClick"
></span>
</span>
</span>
</div>
<div
class="el-select-dropdown el-popper"
:style="{ display:popperDisplay, width: popperWidth}"
>
<div class="el-dialog__header">
<slot name="title">
<span class="el-dialog__title">{{ theTitle }}</span>
<el-input
placeholder="输入关键字进行过滤"
prefix-icon="el-icon-search"
v-model="filterText">
</el-input>
</slot>
<button
type="button"
class="el-dialog__headerbtn"
aria-label="Close"
@click="handleClose"
>
<i class="el-dialog__close el-icon el-icon-close"></i>
</button>
</div>
<el-scrollbar
:style="'height:250px'"
class="el-scrollbar--hidden"
>
<el-tree
v-show="!filterText"
ref="combotree"
node-key="theId"
show-checkbox
check-strictly
:lazy="true"
:highlight-current="true"
:props="theTreeConfig.defaultProps"
:default-expanded-keys="theTreeConfig.defaultExpandedKeys"
:load="loadTheTree"
:filter-node-method="filterNode"
@check-change="handleCheckChange"
>
<span slot-scope="{ data }">
<i class="tree-icon primary" v-if="data.theType == '1'"></i>
<i class="iconfont icon-edit-user" v-else-if="data.theType =='2'" style="color:#088fff"></i>
<i class="iconfont icon-mine" v-else-if="data.theType =='3'" style="color:#088fff"></i>
<i v-else class="tree-icon primary"></i>
<span>{{data.label}}</span>
</span>
</el-tree>
<!-- 查询机构显示 -->
<div v-show="filterText">
<el-checkbox-group v-model="checkList" @change="handleCheckAllChange">
<el-checkbox :label="item.theId" v-for="item in searchUnitlist" :key="item.index">
<i class="tree-icon primary" v-if="item.theType == '1'"></i>
<i class="iconfont icon-edit-user" v-else-if="item.theType =='2'" style="color:#088fff"></i>
<i class="iconfont icon-mine" v-else-if="item.theType =='3'" style="color:#088fff"></i>
<i v-else class="tree-icon primary"></i>
{{item.label}}
</el-checkbox>
</el-checkbox-group>
</div>
</el-scrollbar>
<div class="el-dialog__footer right">
<el-button
size="mini"
@click.stop="handlRefreshTheTree"
>刷新</el-button>
<el-button
type="primary"
size="mini"
@click.stop="handleClose"
>确定</el-button>
</div>
</div>
</div>
</template>
<script>
// 多选树,由文本框和树结构选择面板组成,选中后生成标签
// 导入接口
import { unitListApi } from '@/service/api/actions' // 人员/机构目录
import { searchUnitListApi,searchUnitParentsApi } from '@/service/api/actions' // 人员/机构查询、获取所有父节点
export default {
name: 'inputtree',
props: {
theTitle: { type: String, required: false },
theEdit: { type: Boolean, default: false }, // 文本框数据是否可以键盘输入
theRefresh: { type: String, required: false }
},
data () {
return {
checkList:[],//选中组织和人员
oldcheckList:[],//选中组织和人员
searchUnitlist:[],
filterText:'',//节点过滤字段
selectedLabel: '',
iconClass: 'down',
softFocus: false,
popperDisplay: 'none',
popperWidth: '100%',
theSelected: { all: [], current: {} },
theTreeConfig: {
defaultProps: {
value: 'theId',
label: 'label',
children: 'children',
isLeaf:(data,node) =>{
if(data.theType == 2){ // 根据需要进行条件判断添加is-leaf类名
return true
}else{
return false
}
}
},
defaultExpandedKeys: []
}
}
},
mounted () {
document.addEventListener(
'mouseup',
(event) => {
var sp = document.getElementById('input-tree')
if (sp) {
if (!sp.contains(event.target)) {
this.handleClose()
}
}
},
false
)
},
methods: {
// 查询机构、人员选中后
async handleCheckAllChange(val){
// console.log(val)
// let theIds = []
let newCheckList = val
//得到新增ID
let differenceId = newCheckList.concat(this.oldcheckList)
.filter(v => !newCheckList.includes(v) || !this.oldcheckList.includes(v))
// 新增选中数据
if(this.oldcheckList.length < newCheckList.length){
// 得到新增数据
let addObj = this.searchUnitlist.filter(item=>{
return item.theId == differenceId
})
// debugger
this.theSelected.all.push(addObj[0])
// 得到选中树节点的所有父节点,加载出数据,避免选中后懒加载未加载出数据bug
await searchUnitParentsApi(JSON.stringify(this.theSelected.all) , (res) => {
if (res.data.code === 200) {
this.theTreeConfig.defaultExpandedKeys = []
res.data.data.forEach(item=>{
item.forEach( el=>{
if(this.theTreeConfig.defaultExpandedKeys.indexOf(el)){// 避免重复
this.theTreeConfig.defaultExpandedKeys.push(el.theId)
}
})
})
this.$refs.combotree.setCheckedNodes(this.theSelected.all)
this.oldcheckList = val
}
})
}else{
let deleteObj
this.theSelected.all.forEach((item,index)=>{
if(item.theId == differenceId){
deleteObj = index
}
})
// 删除改变的数据
this.theSelected.all.splice(deleteObj, 1)
this.$refs.combotree.setCheckedNodes(this.theSelected.all)
}
},
//树形节点过滤
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
// 文本框内图标点击事件
handleIconClick () {
if (!this.theEdit) {
if (this.softFocus) {
// 1、切换图标
this.iconClass = 'down'
// 2、显示树结构内容面板
this.popperDisplay = 'none'
this.softFocus = false
} else {
this.iconClass = 'right'
this.popperDisplay = 'block'
this.softFocus = true
}
}
},
// 选中后关闭,设置失去焦点事件
handleClose (event) {
// 1、切换图标
this.iconClass = 'down'
// 2、显示树结构内容面板
this.popperDisplay = 'none'
this.softFocus = false
},
// 目录树数据初始化方法
loadTheTree (node, resolve) {
if (node.level === 0) {
let params = {
uniId: -1
}
unitListApi(params, (res) => {
if (res.data.code === 200) {
return resolve(res.data.data)
}
})
} else {
let params = {
uniId: node.data.theId
}
unitListApi(params, (res) => {
if (res.data.code === 200) {
return resolve(res.data.data)
}
})
}
},
// 刷新树的根目录
handlRefreshTheTree () {
let _root = this.$refs.combotree.root
if (_root !== undefined) {
_root.childNodes.length = 0
this.loadTheTree(_root, (data) => {
this.$refs.combotree.root.doCreateChildren(data)
})
}
},
// 获得全路径
handleTheTreeFullPath: function (node) {
if (node.data !== undefined) {
this.theSelected.all.push(node.data)
}
if (
node.parent !== null &&
node.parent !== undefined &&
node.parent.data !== undefined
) {
this.handleTheTreeFullPath(node.parent)
}
},
// 选中节点数据发生改变
handleCheckChange(data, checked, indeterminate) {
this.theSelected.all = this.$refs.combotree.getCheckedNodes()
this.checkList = this.$refs.combotree.getCheckedKeys()
this.oldcheckList = this.checkList
// 传递当前选中节点给父级
this.$emit('handleTreeSelected', this.theSelected)
},
// 标签删除事件
deleteTag (event, album) {
if (!this.theEdit) {
let index = this.theSelected.all.indexOf(album)
if (index > -1) {
this.theSelected.all.splice(index, 1)
this.$refs.combotree.setCheckedNodes(this.theSelected.all)
this.checkList = this.$refs.combotree.getCheckedKeys()
this.oldcheckList = this.checkList
}
this.$emit('handleTreeSelected', this.theSelected)
}
}
},
watch: {
checkList(val){
// console.log(val)
// debugger
},
theRefresh () {
this.theSelected.all = []
this.theSelected.current = {}
},
//输入框数据发生改变,过滤节点
filterText(val) {
if(val){
let params={
name:val
}
searchUnitListApi(params, (res) => {
if (res.data.code === 200) {
this.searchUnitlist =res.data.data
}
})
}
}
}
}
</script>
<style lang="scss" scoped>
.el-tag{
margin: 3px 5px;
}
/deep/ .el-dialog__header {
padding: 10px 20px 10px;
.el-input__inner{
font-size: 14PX;
height: 35PX;
line-height: 35PX;
}
}
/deep/ .el-dialog__footer {
padding: 10px 20px 10px;
}
.el-input__inner{
cursor: pointer;
}
.el-checkbox-group{
padding-left: 30px;
.el-checkbox{
height: 28PX;
display: block;
}
}
</style>