mirror of
https://gitee.com/orangeform/orange-admin.git
synced 2026-01-17 18:46:36 +08:00
301 lines
8.3 KiB
Vue
301 lines
8.3 KiB
Vue
<template>
|
|
<el-popover ref="popover" placement="bottom-start" trigger="click" popper-class="tree-select-popover"
|
|
:width="width" @show="onShowPopover">
|
|
<el-scrollbar :style="{'height': this.height, 'min-width': this.width}" ref="scrollbar">
|
|
<el-tree ref="dropdownTree" :props="getTreeProps" :highlightCurrent="highlightCurrent" :nodeKey="getDataProps.value"
|
|
:defaultExpandAll="defaultExpandAll" :expandOnClickNode="expandOnClickNode" :checkOnClickNode="checkOnClickNode"
|
|
:autoExpandParent="autoExpandParent" :defaultExpandedKeys="defaultExpandedKeys" :showCheckbox="showCheckbox"
|
|
:checkStrictly="checkStrictly" :defaultCheckedKeys="defaultCheckedKeys" :currentNodeKey="getCurrentNodeKey"
|
|
:accordion="accordion" :indent="indent" :iconClass="iconClass" :load="loadChildrenNodes" lazy :show-checkbox="multiple"
|
|
@node-click="onTreeNodeClick" @check="onTreeNodeCheck">
|
|
<span :style="getNodeStyle(data)" slot-scope="{ node, data }">{{data[getDataProps.label]}}</span>
|
|
</el-tree>
|
|
</el-scrollbar>
|
|
<el-select slot="reference" v-model="selectKeys" :multiple="multiple" :disabled="false" :size="size"
|
|
:clearable="clearable" :collapseTags="collapseTags" :placeholder="placeholder" popper-class="select-tree-popper"
|
|
@clear="onClear" @remove-tag="onClear">
|
|
<el-option v-for="item in selectNodes" :key="item[getDataProps.value]"
|
|
:value="item[getDataProps.value]" :label="item[getDataProps.label]" />
|
|
</el-select>
|
|
</el-popover>
|
|
</template>
|
|
|
|
<script>
|
|
import { findTreeNode } from '@/utils';
|
|
|
|
export default {
|
|
name: 'TreeSelect',
|
|
props: {
|
|
value: {
|
|
type: [String, Number]
|
|
},
|
|
multiple: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
size: {
|
|
type: String
|
|
},
|
|
height: {
|
|
type: String,
|
|
default: '200px'
|
|
},
|
|
width: {
|
|
type: String,
|
|
default: '300px'
|
|
},
|
|
activeColor: {
|
|
type: String,
|
|
default: '#EF5E1C'
|
|
},
|
|
clearable: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
collapseTags: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
placeholder: {
|
|
type: String
|
|
},
|
|
loading: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
loadingText: {
|
|
type: String,
|
|
default: '加载中'
|
|
},
|
|
// 树属性
|
|
data: {
|
|
type: Array
|
|
},
|
|
props: {
|
|
type: Object,
|
|
default: () => {
|
|
return {
|
|
label: 'label',
|
|
value: 'value',
|
|
parentKey: 'parentId',
|
|
children: 'children',
|
|
disabled: 'disabled'
|
|
}
|
|
}
|
|
},
|
|
defaultExpandAll: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
expandOnClickNode: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
checkOnClickNode: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
autoExpandParent: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
defaultExpandedKeys: {
|
|
type: Array
|
|
},
|
|
checkStrictly: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
currentNodeKey: {
|
|
type: [String, Number]
|
|
},
|
|
accordion: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
indent: {
|
|
type: Number,
|
|
default: 16
|
|
},
|
|
iconClass: {
|
|
type: String
|
|
}
|
|
},
|
|
data () {
|
|
return {
|
|
rootNode: undefined,
|
|
rootResolve: undefined,
|
|
allTreeNode: [],
|
|
selectNodes: [],
|
|
scrollTop: 0,
|
|
selectKeys: undefined
|
|
}
|
|
},
|
|
methods: {
|
|
onShowPopover () {
|
|
setTimeout(() => {
|
|
this.$refs.scrollbar.wrap.scrollTop = this.scrollTop;
|
|
// this.$refs.scrollbar.update();
|
|
}, 20);
|
|
if (!this.multiple) {
|
|
this.$refs.dropdownTree.setCurrentKey(this.value);
|
|
}
|
|
},
|
|
onClear () {
|
|
this.$nextTick(() => {
|
|
this.$emit('input', this.selectKeys);
|
|
});
|
|
},
|
|
onTreeNodeClick (data, node) {
|
|
this.$refs.popover.showPopper = false;
|
|
if (!this.multiple) {
|
|
this.scrollTop = this.$refs.scrollbar.wrap.scrollTop;
|
|
this.$emit('input', data[this.getDataProps.value]);
|
|
this.$emit('change', data[this.getDataProps.value]);
|
|
}
|
|
},
|
|
onTreeNodeCheck (data, {checkedNodes, checkedKeys, halfCheckedNodes, halfCheckedKeys}) {
|
|
this.scrollTop = this.$refs.scrollbar.wrap.scrollTop
|
|
this.$emit('input', checkedKeys);
|
|
this.$emit('change', checkedKeys);
|
|
},
|
|
parseNode (node) {
|
|
if (Array.isArray(node) && node.length > 0) {
|
|
node.forEach((item) => {
|
|
item['__node_is_leaf__'] = !(Array.isArray(item[this.getDataProps.children]) && item[this.getDataProps.children].length > 0);
|
|
});
|
|
return node;
|
|
} else {
|
|
return [];
|
|
}
|
|
},
|
|
loadChildrenNodes (node, resolve) {
|
|
if (node.level === 0) {
|
|
this.rootNode = node;
|
|
this.rootResolve = resolve;
|
|
return resolve(this.parseNode(this.allTreeNode));
|
|
} else {
|
|
return resolve(this.parseNode(node.data[this.getDataProps.children]));
|
|
}
|
|
},
|
|
getNodeStyle (data) {
|
|
if (!this.multiple && (this.selectNodes[0] || {})[this.getDataProps.value] === data[this.getDataProps.value]) {
|
|
return {
|
|
color: this.activeColor,
|
|
'font-weight': 700
|
|
}
|
|
}
|
|
}
|
|
},
|
|
computed: {
|
|
showCheckbox () {
|
|
return this.multiple;
|
|
},
|
|
getCurrentNodeKey () {
|
|
if (!this.multiple && Array.isArray(this.selectNodes) && this.selectNodes.length > 0) {
|
|
return this.selectNodes[0][this.getDataProps.value];
|
|
} else {
|
|
return null;
|
|
}
|
|
},
|
|
highlightCurrent () {
|
|
return this.multiple;
|
|
},
|
|
defaultCheckedKeys () {
|
|
return this.multiple ? this.selectNodes : undefined
|
|
},
|
|
getDataProps () {
|
|
return {
|
|
label: this.props.label || 'label',
|
|
value: this.props.value || 'value',
|
|
parentKey: this.props.parentKey || 'parentId',
|
|
children: this.props.children || 'children',
|
|
disabled: this.props.disabled || 'disabled'
|
|
}
|
|
},
|
|
getTreeProps () {
|
|
return {
|
|
label: this.getDataProps.label,
|
|
children: '__children_list__',
|
|
disabled: this.getDataProps.disabled,
|
|
isLeaf: '__node_is_leaf__'
|
|
};
|
|
}
|
|
},
|
|
watch: {
|
|
data: {
|
|
handler (newValue, oldValue) {
|
|
this.allTreeNode = newValue;
|
|
if (this.rootNode != null && this.rootResolve != null) {
|
|
this.rootNode.childNodes = [];
|
|
this.loadChildrenNodes(this.rootNode, this.rootResolve);
|
|
}
|
|
this.selectNodes = [];
|
|
if (this.multiple) {
|
|
if (Array.isArray(this.value)) {
|
|
this.value.forEach((item) => {
|
|
let data = findTreeNode(this.allTreeNode, item, this.getDataProps.value, this.getDataProps.children);
|
|
if (data) this.selectNodes.push(data);
|
|
});
|
|
}
|
|
} else {
|
|
let data = findTreeNode(this.allTreeNode, this.value, this.getDataProps.value, this.getDataProps.children);
|
|
if (data) this.selectNodes.push(data);
|
|
}
|
|
},
|
|
immediate: true
|
|
},
|
|
value: {
|
|
handler (newValue) {
|
|
this.selectNodes = [];
|
|
if (Array.isArray(newValue)) {
|
|
newValue.forEach((item) => {
|
|
let data = findTreeNode(this.allTreeNode, item, this.getDataProps.value, this.getDataProps.children);
|
|
if (data) this.selectNodes.push(data);
|
|
});
|
|
this.selectKeys = newValue;
|
|
} else {
|
|
let data = findTreeNode(this.allTreeNode, newValue, this.getDataProps.value, this.getDataProps.children);
|
|
if (data) this.selectNodes.push(data);
|
|
this.selectKeys = newValue;
|
|
}
|
|
if (this.$refs.dropdownTree) {
|
|
this.multiple ? this.$refs.dropdownTree.setCheckedKeys(newValue) : this.$refs.dropdownTree.setCurrentKey(newValue);
|
|
}
|
|
},
|
|
immediate: true
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.select-tree-popper {
|
|
display: none;
|
|
}
|
|
.tree-select-popover {
|
|
padding: 6px 0px;
|
|
}
|
|
.tree-select-popover .popper__arrow {
|
|
left: 35px!important;
|
|
}
|
|
.tree-select-popover .el-tree .el-tree-node__content {
|
|
height: 34px;
|
|
line-height: 34px;
|
|
}
|
|
/*
|
|
.tree-select-popover .el-tree .el-tree-node.is-current .el-tree-node__content {
|
|
color: #fdb95c;
|
|
font-weight: 700;
|
|
}
|
|
*/
|
|
.current-node {
|
|
color: #EF5E1C;
|
|
font-weight: 700;
|
|
}
|
|
</style>
|