You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
537 lines
14 KiB
537 lines
14 KiB
|
|
<template>
|
|
<div class="el-tree-node">
|
|
<div class="filter-input">
|
|
<el-input placeholder="输入关键字进行过滤"
|
|
v-model="filterText"
|
|
clearable>
|
|
</el-input>
|
|
</div>
|
|
<el-tree v-if="lazy === true"
|
|
ref="tree"
|
|
lazy
|
|
node-key="id"
|
|
v-loading="loading"
|
|
:default-expanded-keys="defaultExpandKeys"
|
|
:expand-on-click-node="defaultExpandOnClickNode"
|
|
:render-content="renderContent"
|
|
:show-checkbox="showCheckbox"
|
|
:default-checked-keys="defaultCheckedKeys"
|
|
:default-expand-all="defaultExpandAll"
|
|
:current-node-key="currentNodeKey"
|
|
:filter-node-method="filterNode"
|
|
:check-on-click-node="checkOnClickNode"
|
|
highlight-current
|
|
:props="props"
|
|
:load="loadNode"
|
|
@node-click="handleNodeClick"
|
|
@node-expand="handleNodeExpand"></el-tree>
|
|
<el-tree v-else
|
|
node-key="id"
|
|
ref="tree"
|
|
:data="nodeData"
|
|
v-loading="loading"
|
|
:default-expand-all="defaultExpandAll"
|
|
:default-expanded-keys="defaultExpandKeys"
|
|
:filter-node-method="filterNode"
|
|
:expand-on-click-node="defaultExpandOnClickNode"
|
|
:render-content="renderContent"
|
|
:show-checkbox="showCheckbox"
|
|
:current-node-key="currentNodeKey"
|
|
:check-on-click-node="checkOnClickNode"
|
|
highlight-current
|
|
:props="props"
|
|
@node-click="handleNodeClick"
|
|
@check="handleCheckBox"
|
|
@current-change="handleCurrentChange"></el-tree>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
data () {
|
|
return {
|
|
nodeData: [],
|
|
currentNodeKey: this.defaultNodeKey,
|
|
checkedKeys: this.defaultCheckedKeys,
|
|
firstData: null,
|
|
props: {
|
|
children: 'children',
|
|
label: 'label',
|
|
isLeaf: 'leaf'
|
|
},
|
|
filterText: '',
|
|
defaultExpandKeys: ['0'],
|
|
|
|
loading: false, // 加载中
|
|
selNode: '',// 后台数据选中的节点
|
|
expandKeys: []
|
|
}
|
|
},
|
|
watch: {
|
|
filterText (val) {
|
|
this.$refs.tree.filter(val)
|
|
}
|
|
},
|
|
props: {
|
|
url: {
|
|
type: String,
|
|
required: true
|
|
},
|
|
params: {
|
|
type: Object,
|
|
default () {
|
|
return {}
|
|
}
|
|
},
|
|
// 默认全展开
|
|
defaultExpandAll: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
lazy: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
autoLoad: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
showCheckbox: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
defaultOnlyLeaf: {
|
|
// 点击所有节点都能选中,为true时表示:只能选择叶节点
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
defaultExpandOnClickNode: {
|
|
// 默认点击节点时展开节点
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
defaultCheckedKeys: {
|
|
// 默认勾选节点
|
|
type: Array,
|
|
default () {
|
|
return []
|
|
}
|
|
},
|
|
|
|
defaultNodeKey: {
|
|
// 默认选中节点(节点id)
|
|
type: [Number, String]
|
|
},
|
|
|
|
isDialogTree: {
|
|
// 是否是从选择树弹出框打开的树
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
// 能够选择的节点类型,默认为空
|
|
nodeType: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
// 是否在点击节点的时候选中节点,默认值为 false,即只有在点击复选框时才会选中节点
|
|
checkOnClickNode: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
tenantCode: {
|
|
type: String,
|
|
default: ''
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
setExpandKeys (expandKeys) {
|
|
|
|
this.expandKeys = expandKeys
|
|
},
|
|
filterNode (value, data) {
|
|
if (!value) return true
|
|
return data.label.indexOf(value) !== -1
|
|
},
|
|
loadData (callback, currentKey, checkedKeys, expandKeys) {
|
|
|
|
this.expandKeys = expandKeys
|
|
var headers = {}
|
|
if (this.tenantCode !== '') {
|
|
headers = {
|
|
tenantCode: this.tenantCode
|
|
}
|
|
}
|
|
this.selNode = ''
|
|
this.currentNodeKey = currentKey
|
|
this.checkedKeys = checkedKeys
|
|
|
|
this.resetFilterText()
|
|
window.app.ajax.post(
|
|
this.url,
|
|
this.params,
|
|
(data, rspMsg) => {
|
|
let arrayData = data
|
|
if (!Array.isArray(data)) {
|
|
arrayData = []
|
|
arrayData.push(data)
|
|
}
|
|
// alert(JSON.stringify(data))
|
|
this.nodeData = data
|
|
// console.log(this.nodeData)
|
|
this.processData(this.nodeData, null)
|
|
this.initCheckNodes()
|
|
this.loading = false
|
|
},
|
|
(rspMsg, data) => {
|
|
this.$message.error(rspMsg)
|
|
this.loading = false
|
|
}, headers
|
|
)
|
|
if (typeof callback === 'function') callback()
|
|
},
|
|
loadDataByUrl (url, callback, currentKey) {
|
|
this.selNode = ''
|
|
this.currentNodeKey = currentKey
|
|
|
|
this.loading = true
|
|
this.resetFilterText()
|
|
window.app.ajax.get(
|
|
url,
|
|
this.params,
|
|
(data, rspMsg) => {
|
|
this.nodeData = data
|
|
console.log(this.nodeData)
|
|
this.firstData = null
|
|
this.processData(this.nodeData, null)
|
|
this.initCheckNodes()
|
|
this.loading = false
|
|
},
|
|
(rspMsg, data) => {
|
|
this.$message.error(rspMsg)
|
|
this.loading = false
|
|
}
|
|
)
|
|
if (typeof callback === 'function') callback()
|
|
},
|
|
processData (data, parentData) {
|
|
// 处理节点数据
|
|
data.forEach(_data => {
|
|
_data.parent = parentData
|
|
|
|
if (_data.selectNode === '1') {
|
|
this.selNode = _data.id
|
|
}
|
|
if (_data.children && _data.children.length > 0) {
|
|
this.processData(_data.children, _data)
|
|
} else {
|
|
_data.isLeaf = true // 叶子节点
|
|
|
|
if (!this.firstData) { // 保存第一层节点数据
|
|
this.firstData = _data
|
|
}
|
|
}
|
|
})
|
|
},
|
|
initCheckNodes () {
|
|
// 默认展开的节点
|
|
|
|
if (this.expandKeys.length > 0) {
|
|
this.expandKeys.forEach((oneKey, index) => { // 组织数据
|
|
this.defaultExpandKeys.push(oneKey + '')
|
|
})
|
|
}
|
|
// 设置节点状态
|
|
if (this.showCheckbox) { // 多选节点
|
|
// if (this.defaultCheckedKeys.length > 0) {
|
|
// 设置勾选节点
|
|
if (this.checkedKeys === undefined) {
|
|
this.$nextTick(() => {
|
|
this.$refs['tree'].setCheckedKeys(this.defaultCheckedKeys)
|
|
})
|
|
} else {
|
|
this.$nextTick(() => {
|
|
this.$refs['tree'].setCheckedKeys(this.checkedKeys)
|
|
})
|
|
}
|
|
|
|
// }
|
|
} else { // 单选节点
|
|
// 如果没有设置默认勾选和展开节点,设置第一层级的第一个叶子节点为勾选状态
|
|
if (this.currentNodeKey === undefined || this.currentNodeKey === null) {
|
|
if (this.selNode !== '') {
|
|
this.currentNodeKey = this.selNode
|
|
} else {
|
|
this.currentNodeKey = this.firstData.id
|
|
}
|
|
|
|
// if (this.showCheckbox) {
|
|
// this.defaultCheckedKeys.push(this.currentNodeKey)
|
|
// }
|
|
|
|
// 要在数据更新视图之后,设置高亮, 设置勾选
|
|
this.$nextTick(() => {
|
|
this.setCurrentKey(this.currentNodeKey)
|
|
// if (this.showCheckbox)
|
|
// this.$refs['tree'].setCheckedKeys(this.defaultCheckedKeys)
|
|
})
|
|
} else {
|
|
this.$nextTick(() => {
|
|
this.setCurrentKey(this.currentNodeKey)
|
|
})
|
|
}
|
|
}
|
|
// if (this.defaultCheckedKeys.length > 0) { // 多选节点
|
|
// // 设置勾选节点
|
|
// this.$nextTick(() => {
|
|
// this.$refs['tree'].setCheckedKeys(this.defaultCheckedKeys)
|
|
// })
|
|
// } else { // 单选节点
|
|
|
|
// }
|
|
this.$emit('dataFinish')
|
|
},
|
|
setCurrentKey (key) {
|
|
this.$refs['tree'].setCurrentKey(key)
|
|
if (!this.isDialogTree) {
|
|
// 获取当前被选中节点的 data,主动触发点击事件
|
|
this.handleNodeClick(this.$refs['tree'].getCurrentNode(), '', '')
|
|
}
|
|
},
|
|
renderContent (h, { node, data, store }) {
|
|
// 渲染tree
|
|
return h(
|
|
'span',
|
|
{
|
|
class: 'custom-tree-node'
|
|
},
|
|
[
|
|
data.icon
|
|
? h('svg-icon', {
|
|
class: 'blue', // 图标颜色
|
|
props: {
|
|
iconClass: data.icon
|
|
}
|
|
})
|
|
: '',
|
|
h('span', {
|
|
class: 'mLeft'// 节点名称span新增左边距属性
|
|
}, node.label)
|
|
]
|
|
)
|
|
},
|
|
addDefaultExpandedKeys (data) {
|
|
if (data.parent && data.parent.length > 0) {
|
|
this.addDefaultExpandedKeys(data.parent)
|
|
} else {
|
|
this.defaultExpandKeys.push(data)
|
|
}
|
|
},
|
|
handleNodeClick (data, node, store) {
|
|
let checkedArr = this.$refs['tree'].getCheckedNodes()
|
|
if (this.defaultOnlyLeaf) { // 只能选择叶子节点
|
|
if (data.children && data.children.length > 0) { // 如果没有子节点
|
|
} else {
|
|
this.$emit('nodeClick', data, node)
|
|
}
|
|
} else {
|
|
this.$emit('nodeClick', data, node, checkedArr)
|
|
}
|
|
},
|
|
handleCheckBox (data, status) {
|
|
let checkedArr = this.$refs['tree'].getCheckedNodes()
|
|
this.$emit('chechBoxClick', data, checkedArr)
|
|
},
|
|
handleCurrentChange (data, node, store) {
|
|
// console.logconsole.log(data, node)
|
|
},
|
|
handleNodeExpand (data, node, store) {
|
|
// console.log(data, node, store)
|
|
},
|
|
loadNode (node, resolve) {
|
|
if (node.level === 0) {
|
|
this.loadData(() => {
|
|
resolve(this.nodeData[0])
|
|
this.$refs['tree'].setCurrentKey(this.nodeData[0].id)
|
|
})
|
|
} else {
|
|
resolve([])
|
|
}
|
|
},
|
|
// 获取多选节点的id数组(全部)
|
|
getCheckedKeysAll () {
|
|
return this.$refs['tree'].getCheckedKeys()
|
|
},
|
|
// 获取多选节点的id字符串(只有叶子节点)
|
|
getCheckedKeys () {
|
|
var checkedNodes = this.getCheckedNodes()
|
|
var p = /[a-z]/i
|
|
var selIds = ''
|
|
if (this.nodeType === '') { // 没有指定的节点类型
|
|
checkedNodes.forEach(element => {
|
|
var id = element.id
|
|
// if (p.test(element.id)) { // 判断第一位是否是字母,是的话截掉
|
|
if (p.test(element.id.substring(0, 1))) { // 判断第一位是否是字母,是的话截掉
|
|
id = element.id.substring(1)
|
|
}
|
|
selIds = selIds + id + ','
|
|
})
|
|
} else { // 指定了节点类型
|
|
checkedNodes.forEach(element => {
|
|
if (element.role === this.nodeType) {
|
|
var id = element.id
|
|
selIds = selIds + id + ','
|
|
}
|
|
})
|
|
}
|
|
if (selIds !== '') {
|
|
selIds = selIds.substring(0, selIds.length - 1)
|
|
}
|
|
return selIds
|
|
},
|
|
setCheckedKeys (key) {
|
|
this.$refs['tree'].setCheckedKeys(key)
|
|
// 获取当前被选中节点的 data,主动触发点击事件
|
|
// this.handleNodeClick(this.$refs['tree'].getCurrentNode())
|
|
},
|
|
// 获取多选节点的对象数组(全部)
|
|
getCheckedNodesAll () {
|
|
return this.$refs['tree'].getCheckedNodes()
|
|
},
|
|
// 获取多选节点的对象数组(只有叶子节点)
|
|
getCheckedNodes () {
|
|
var checkedNodesAll = this.$refs['tree'].getCheckedNodes()// 所有选中的节点,包括父节点
|
|
var checkedNodes = []
|
|
// 剔除父节点
|
|
checkedNodesAll.forEach(oneNodes => {
|
|
if (oneNodes.children && oneNodes.children.length > 0) {
|
|
} else {
|
|
checkedNodes.push(oneNodes)
|
|
}
|
|
})
|
|
// console.log(checkedNodes)
|
|
return checkedNodes
|
|
},
|
|
// 重置查询条件
|
|
resetFilterText () {
|
|
this.filterText = ''
|
|
}
|
|
},
|
|
mounted () {
|
|
if (!this.lazy) {
|
|
if (this.autoLoad) {
|
|
this.loading = true
|
|
this.loadData(null, this.currentNodeKey, this.checkedKeys, this.expandKeys)
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.mLeft {
|
|
margin-left: 6px;
|
|
}
|
|
.blue {
|
|
color: #003585;
|
|
}
|
|
</style>
|
|
<style scoped>
|
|
.el-tree-node {
|
|
outline: 0;
|
|
font-size: 14px;
|
|
word-wrap: break-word !important;
|
|
line-height: 14px !important;
|
|
}
|
|
|
|
.el-tree-node:focus > .el-tree-node__content {
|
|
background-color: #f5f7fa;
|
|
}
|
|
|
|
.el-tree-node.is-drop-inner > .el-tree-node__content .el-tree-node__label {
|
|
background-color: #00d1b2;
|
|
color: #fff;
|
|
}
|
|
|
|
.el-tree-node__content {
|
|
display: -webkit-box;
|
|
display: -ms-flexbox;
|
|
display: flex;
|
|
-webkit-box-align: center;
|
|
-ms-flex-align: center;
|
|
align-items: center;
|
|
height: 26px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.el-tree-node__content > .el-tree-node__expand-icon {
|
|
padding: 6px;
|
|
}
|
|
|
|
.el-tree-node__content > .el-checkbox {
|
|
margin-right: 8px;
|
|
}
|
|
|
|
.el-tree-node__content:hover {
|
|
background-color: #f5f7fa;
|
|
}
|
|
|
|
.el-tree.is-dragging .el-tree-node__content {
|
|
cursor: move;
|
|
}
|
|
|
|
.el-tree.is-dragging.is-drop-not-allow .el-tree-node__content {
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.el-tree-node__expand-icon {
|
|
cursor: pointer;
|
|
color: #c0c4cc;
|
|
font-size: 12px;
|
|
-webkit-transform: rotate(0);
|
|
transform: rotate(0);
|
|
-webkit-transition: -webkit-transform 0.3s ease-in-out;
|
|
transition: -webkit-transform 0.3s ease-in-out;
|
|
transition: transform 0.3s ease-in-out;
|
|
transition: transform 0.3s ease-in-out, -webkit-transform 0.3s ease-in-out;
|
|
}
|
|
|
|
.el-tree-node__expand-icon.expanded {
|
|
-webkit-transform: rotate(90deg);
|
|
transform: rotate(90deg);
|
|
}
|
|
|
|
.el-tree-node__expand-icon.is-leaf {
|
|
color: transparent;
|
|
cursor: default;
|
|
}
|
|
|
|
.el-tree-node__label {
|
|
font-size: 14px;
|
|
}
|
|
|
|
.el-tree-node__loading-icon {
|
|
margin-right: 8px;
|
|
font-size: 14px;
|
|
color: #c0c4cc;
|
|
}
|
|
|
|
.el-tree-node > .el-tree-node__children {
|
|
overflow: hidden;
|
|
background-color: transparent;
|
|
}
|
|
|
|
.el-tree-node.is-expanded > .el-tree-node__children {
|
|
display: block;
|
|
}
|
|
|
|
.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
|
|
background-color: #f0f7ff;
|
|
}
|
|
|
|
.filter-input {
|
|
margin-bottom: 10px;
|
|
}
|
|
</style>
|
|
|