984 lines
26 KiB
Vue
984 lines
26 KiB
Vue
<template>
|
|
<view class="custom-tree-select-content">
|
|
<view
|
|
:class="['select-list', { disabled }, { active: selectList.length }]"
|
|
:style="boxStyle"
|
|
@click.stop="open"
|
|
>
|
|
<view class="left">
|
|
<view v-if="selectList.length" class="select-items">
|
|
<view
|
|
class="select-item"
|
|
v-for="item in selectedListBaseinfo"
|
|
:key="item[dataValue]"
|
|
>
|
|
<view class="name">
|
|
<text>{{ pathMode ? item.path : item[dataLabel] }}</text>
|
|
</view>
|
|
<view
|
|
v-if="!disabled && !item.disabled"
|
|
class="close"
|
|
@click.stop="removeSelectedItem(item)"
|
|
>
|
|
<uni-icons type="closeempty" size="16" color="#999"></uni-icons>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view v-else style="color: #6a6a6a" class="no-data">
|
|
<text style="#C0C4CB">{{ placeholder }}</text>
|
|
</view>
|
|
</view>
|
|
<view class="right">
|
|
<uni-icons
|
|
v-if="!selectList.length || !clearable"
|
|
type="bottom"
|
|
size="14"
|
|
color="#999"
|
|
></uni-icons>
|
|
<uni-icons
|
|
v-if="selectList.length && clearable"
|
|
type="clear"
|
|
size="24"
|
|
color="#c0c4cc"
|
|
@click.native.stop="clear"
|
|
></uni-icons>
|
|
</view>
|
|
</view>
|
|
<uni-popup
|
|
v-if="showPopup"
|
|
ref="popup"
|
|
:animation="animation"
|
|
:is-mask-click="isMaskClick"
|
|
:mask-background-color="maskBackgroundColor"
|
|
:background-color="backgroundColor"
|
|
:safe-area="safeArea"
|
|
type="bottom"
|
|
@change="change"
|
|
@maskClick="maskClick"
|
|
>
|
|
<view
|
|
class="popup-content"
|
|
:style="{ height: contentHeight || defaultContentHeight }"
|
|
>
|
|
<view class="title">
|
|
<view
|
|
v-if="mutiple && canSelectAll"
|
|
class="left"
|
|
@click.stop="handleSelectAll"
|
|
>
|
|
<text>{{ isSelectedAll ? '取消全选' : '全选' }}</text>
|
|
</view>
|
|
<view class="center">
|
|
<text>{{ placeholder }}</text>
|
|
</view>
|
|
<view
|
|
class="right"
|
|
:style="{ color: confirmTextColor }"
|
|
@click.stop="close"
|
|
>
|
|
<text>{{ confirmText }}</text>
|
|
</view>
|
|
</view>
|
|
<view v-if="search" class="search-box">
|
|
<uni-easyinput
|
|
:maxlength="-1"
|
|
prefixIcon="search"
|
|
placeholder="搜索"
|
|
v-model="searchStr"
|
|
confirm-type="search"
|
|
@confirm="handleSearch(false)"
|
|
@clear="handleSearch(true)"
|
|
>
|
|
</uni-easyinput>
|
|
<button
|
|
type="primary"
|
|
size="mini"
|
|
class="search-btn"
|
|
@click.stop="handleSearch(false)"
|
|
>
|
|
搜索
|
|
</button>
|
|
</view>
|
|
<view v-if="treeData.length" class="select-content">
|
|
<scroll-view
|
|
class="scroll-view-box"
|
|
:scroll-top="scrollTop"
|
|
scroll-y="true"
|
|
@touchmove.stop
|
|
>
|
|
<view v-if="!filterTreeData.length" class="no-data center">
|
|
<text>暂无数据</text>
|
|
</view>
|
|
<data-select-item
|
|
v-for="item in filterTreeData"
|
|
:key="item[dataValue]"
|
|
:node="item"
|
|
:dataLabel="dataLabel"
|
|
:dataValue="dataValue"
|
|
:dataChildren="dataChildren"
|
|
:choseParent="choseParent"
|
|
:border="border"
|
|
:linkage="linkage"
|
|
:load="load"
|
|
:lazyLoadChildren="lazyLoadChildren"
|
|
></data-select-item>
|
|
<view class="sentry" />
|
|
</scroll-view>
|
|
</view>
|
|
<view v-else class="no-data center">
|
|
<text>暂无数据</text>
|
|
</view>
|
|
</view>
|
|
</uni-popup>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
const partCheckedSet = new Set()
|
|
import { paging } from './utils'
|
|
import dataSelectItem from './data-select-item.vue'
|
|
export default {
|
|
name: 'custom-tree-select',
|
|
components: {
|
|
dataSelectItem
|
|
},
|
|
model: {
|
|
prop: 'value',
|
|
event: 'input'
|
|
},
|
|
props: {
|
|
boxStyle: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
canSelectAll: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
safeArea: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
search: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
clearResetSearch: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
animation: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
'is-mask-click': {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
'mask-background-color': {
|
|
type: String,
|
|
default: 'rgba(0,0,0,0.4)'
|
|
},
|
|
'background-color': {
|
|
type: String,
|
|
default: 'none'
|
|
},
|
|
'safe-area': {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
choseParent: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
placeholder: {
|
|
type: String,
|
|
default: '请选择'
|
|
},
|
|
confirmText: {
|
|
type: String,
|
|
default: '完成'
|
|
},
|
|
confirmTextColor: {
|
|
type: String,
|
|
default: '#007aff'
|
|
},
|
|
contentHeight: {
|
|
type: String
|
|
},
|
|
disabledList: {
|
|
type: Array,
|
|
default: () => []
|
|
},
|
|
listData: {
|
|
type: Array,
|
|
default: () => []
|
|
},
|
|
dataLabel: {
|
|
type: String,
|
|
default: 'name'
|
|
},
|
|
dataValue: {
|
|
type: String,
|
|
default: 'id'
|
|
},
|
|
dataChildren: {
|
|
type: String,
|
|
default: 'children'
|
|
},
|
|
linkage: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
clearable: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
mutiple: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
showChildren: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
border: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
pathMode: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
pathHyphen: {
|
|
type: String,
|
|
default: '/'
|
|
},
|
|
load: {
|
|
type: Function,
|
|
default: function () {}
|
|
},
|
|
lazyLoadChildren: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
value: {
|
|
type: Array,
|
|
default: () => []
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
defaultContentHeight: '500px',
|
|
treeData: [],
|
|
filterTreeData: [],
|
|
clearTimerList: [],
|
|
selectedListBaseinfo: [],
|
|
showPopup: false,
|
|
clickOpenTimer: null,
|
|
isSelectedAll: false,
|
|
scrollTop: 0,
|
|
searchStr: ''
|
|
}
|
|
},
|
|
computed: {
|
|
selectList() {
|
|
return this.value || []
|
|
}
|
|
},
|
|
watch: {
|
|
listData: {
|
|
deep: true,
|
|
immediate: true,
|
|
handler(newVal) {
|
|
if (newVal) {
|
|
partCheckedSet.clear()
|
|
this.treeData = this.initData(newVal)
|
|
|
|
if (this.value) {
|
|
this.changeStatus(this.treeData, this.value, true)
|
|
this.filterTreeData.length &&
|
|
this.changeStatus(this.filterTreeData, this.value)
|
|
}
|
|
if (this.showPopup) {
|
|
this.resetClearTimerList()
|
|
this.renderTree(this.treeData)
|
|
}
|
|
}
|
|
}
|
|
},
|
|
value: {
|
|
immediate: true,
|
|
handler(newVal) {
|
|
if (newVal) {
|
|
this.changeStatus(this.treeData, this.value, true)
|
|
this.filterTreeData.length &&
|
|
this.changeStatus(this.filterTreeData, this.value)
|
|
}
|
|
}
|
|
}
|
|
},
|
|
mounted() {
|
|
this.getContentHeight(uni.getSystemInfoSync())
|
|
},
|
|
methods: {
|
|
// 搜索完成返回顶部
|
|
goTop() {
|
|
this.scrollTop = 10
|
|
this.$nextTick(() => {
|
|
this.scrollTop = 0
|
|
})
|
|
},
|
|
// 获取对应数据
|
|
getReflectNode(node, arr) {
|
|
const array = [...arr]
|
|
while (array.length) {
|
|
const item = array.shift()
|
|
if (item[this.dataValue] === node[this.dataValue]) {
|
|
return item
|
|
}
|
|
if (item[this.dataChildren]?.length) {
|
|
array.push(...item[this.dataChildren])
|
|
}
|
|
}
|
|
return {}
|
|
},
|
|
getContentHeight({ screenHeight }) {
|
|
this.defaultContentHeight = `${Math.floor(screenHeight * 0.7)}px`
|
|
},
|
|
// 处理搜索
|
|
handleSearch(isClear = false) {
|
|
this.resetClearTimerList()
|
|
if (isClear) {
|
|
// 点击清空按钮并且设置清空按钮会重置搜索
|
|
if (this.clearResetSearch) {
|
|
this.renderTree(this.treeData)
|
|
}
|
|
} else {
|
|
this.renderTree(this.searchValue(this.searchStr, this.treeData))
|
|
}
|
|
this.goTop()
|
|
uni.hideKeyboard()
|
|
},
|
|
// 具体搜索方法
|
|
searchValue(str, arr) {
|
|
const res = []
|
|
arr.forEach((item) => {
|
|
if (item.visible) {
|
|
if (
|
|
item[this.dataLabel]
|
|
.toString()
|
|
.toLowerCase()
|
|
.indexOf(str.toLowerCase()) > -1
|
|
) {
|
|
res.push(item)
|
|
} else {
|
|
if (item[this.dataChildren]?.length) {
|
|
const data = this.searchValue(str, item[this.dataChildren])
|
|
if (data?.length) {
|
|
if (
|
|
str &&
|
|
!item.showChildren &&
|
|
item[this.dataChildren]?.length
|
|
) {
|
|
item.showChildren = true
|
|
}
|
|
res.push({
|
|
...item,
|
|
[this.dataChildren]: data
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|
|
return res
|
|
},
|
|
// 懒加载
|
|
renderTree(arr) {
|
|
const pagingArr = paging(arr)
|
|
this.filterTreeData.splice(
|
|
0,
|
|
this.filterTreeData.length,
|
|
...(pagingArr?.[0] || [])
|
|
)
|
|
this.lazyRenderList(pagingArr, 1)
|
|
},
|
|
// 懒加载具体逻辑
|
|
lazyRenderList(arr, startIndex) {
|
|
for (let i = startIndex; i < arr.length; i++) {
|
|
let timer = null
|
|
timer = setTimeout(() => {
|
|
this.filterTreeData.push(...arr[i])
|
|
}, i * 500)
|
|
this.clearTimerList.push(() => clearTimeout(timer))
|
|
}
|
|
},
|
|
// 中断懒加载
|
|
resetClearTimerList() {
|
|
const list = [...this.clearTimerList]
|
|
this.clearTimerList = []
|
|
list.forEach((fn) => fn())
|
|
},
|
|
// 打开弹窗
|
|
open() {
|
|
// disaled模式下禁止打开弹窗
|
|
if (this.disabled) return
|
|
this.showPopup = true
|
|
this.$nextTick(() => {
|
|
this.$refs.popup.open()
|
|
this.renderTree(this.treeData)
|
|
})
|
|
},
|
|
// 关闭弹窗
|
|
close() {
|
|
this.$refs.popup.close()
|
|
},
|
|
// 弹窗状态变化 包括点击回显框和遮罩
|
|
change(data) {
|
|
if (data.show) {
|
|
uni.$on('custom-tree-select-node-click', this.handleNodeClick)
|
|
uni.$on('custom-tree-select-name-click', this.handleHideChildren)
|
|
uni.$on('custom-tree-select-load', this.handleLoadNode)
|
|
} else {
|
|
uni.$off('custom-tree-select-node-click', this.handleNodeClick)
|
|
uni.$off('custom-tree-select-name-click', this.handleHideChildren)
|
|
uni.$off('custom-tree-select-load', this.handleLoadNode)
|
|
this.resetClearTimerList()
|
|
this.searchStr = ''
|
|
if (this.animation) {
|
|
setTimeout(() => {
|
|
this.showPopup = false
|
|
}, 200)
|
|
} else {
|
|
this.showPopup = false
|
|
}
|
|
}
|
|
this.$emit('change', data)
|
|
},
|
|
// 点击遮罩
|
|
maskClick() {
|
|
this.$emit('maskClick')
|
|
},
|
|
// 初始化数据
|
|
initData(arr, parentVisible = undefined, pathArr = []) {
|
|
if (!Array.isArray(arr)) return []
|
|
const res = []
|
|
|
|
for (let i = 0; i < arr.length; i++) {
|
|
const curPathArr = [...pathArr, arr[i][this.dataLabel]]
|
|
const obj = {
|
|
...arr[i],
|
|
[this.dataLabel]: arr[i][this.dataLabel],
|
|
[this.dataValue]: arr[i][this.dataValue],
|
|
path: curPathArr.join(this.pathHyphen)
|
|
}
|
|
|
|
obj.checked = this.selectList.includes(arr[i][this.dataValue])
|
|
|
|
obj.disabled = false
|
|
if (
|
|
Boolean(arr[i].disabled) ||
|
|
this.disabledList.includes(obj[this.dataValue])
|
|
) {
|
|
obj.disabled = true
|
|
}
|
|
|
|
//半选
|
|
obj.partChecked = Boolean(
|
|
arr[i].partChecked === undefined ? false : arr[i].partChecked
|
|
)
|
|
obj.partChecked && obj.partCheckedSet.add(obj[this.dataValue])
|
|
!obj.partChecked && (this.isSelectedAll = false)
|
|
|
|
const parentVisibleState =
|
|
parentVisible === undefined ? true : parentVisible
|
|
const curVisibleState =
|
|
arr[i].visible === undefined ? true : Boolean(arr[i].visible)
|
|
if (parentVisibleState === curVisibleState) {
|
|
obj.visible = parentVisibleState
|
|
} else if (!parentVisibleState || !curVisibleState) {
|
|
obj.visible = false
|
|
} else {
|
|
obj.visible = true
|
|
}
|
|
|
|
obj.showChildren =
|
|
'showChildren' in arr[i] && arr[i].showChildren != undefined
|
|
? arr[i].showChildren
|
|
: this.showChildren
|
|
|
|
if (arr[i][this.dataChildren]?.length) {
|
|
const childrenVal = this.initData(
|
|
arr[i][this.dataChildren],
|
|
obj.visible,
|
|
curPathArr
|
|
)
|
|
obj[this.dataChildren] = childrenVal
|
|
if (
|
|
!obj.checked &&
|
|
childrenVal.some((item) => item.checked || item.partChecked)
|
|
) {
|
|
obj.partChecked = true
|
|
partCheckedSet.add(obj[this.dataValue])
|
|
}
|
|
}
|
|
|
|
res.push(obj)
|
|
}
|
|
|
|
return res
|
|
},
|
|
// 获取某个节点后面所有元素
|
|
getChildren(node) {
|
|
if (!node[this.dataChildren]?.length) return []
|
|
const res = node[this.dataChildren].reduce((pre, val) => {
|
|
if (val.visible) {
|
|
return [...pre, val]
|
|
}
|
|
return pre
|
|
}, [])
|
|
for (let i = 0; i < node[this.dataChildren].length; i++) {
|
|
res.push(...this.getChildren(node[this.dataChildren][i]))
|
|
}
|
|
return res
|
|
},
|
|
// 获取某个节点所有祖先元素
|
|
getParentNode(target, arr) {
|
|
let res = []
|
|
|
|
for (let i = 0; i < arr.length; i++) {
|
|
if (arr[i][this.dataValue] === target[this.dataValue]) {
|
|
return true
|
|
}
|
|
|
|
if (arr[i][this.dataChildren]?.length) {
|
|
const childRes = this.getParentNode(target, arr[i][this.dataChildren])
|
|
if (typeof childRes === 'boolean' && childRes) {
|
|
res = [arr[i]]
|
|
} else if (Array.isArray(childRes) && childRes.length) {
|
|
res = [...childRes, arr[i]]
|
|
}
|
|
}
|
|
}
|
|
|
|
return res
|
|
},
|
|
// 点击checkbox
|
|
handleNodeClick(data, status) {
|
|
const node = this.getReflectNode(data, this.treeData)
|
|
node.checked = typeof status === 'boolean' ? status : !node.checked
|
|
node.partChecked = false
|
|
partCheckedSet.delete(node[this.dataValue])
|
|
// 如果是单选不考虑其他情况
|
|
if (!this.mutiple) {
|
|
let emitData = []
|
|
if (node.checked) {
|
|
emitData = [node[this.dataValue]]
|
|
}
|
|
this.$emit('input', emitData)
|
|
} else {
|
|
// 多选情况
|
|
if (!this.linkage) {
|
|
// 不需要联动
|
|
let emitData = null
|
|
if (node.checked) {
|
|
emitData = Array.from(
|
|
new Set([...this.selectList, node[this.dataValue]])
|
|
)
|
|
} else {
|
|
emitData = this.selectList.filter(
|
|
(id) => id !== node[this.dataValue]
|
|
)
|
|
}
|
|
this.$emit('input', emitData)
|
|
} else {
|
|
// 需要联动
|
|
let emitData = [...this.selectList]
|
|
const parentNodes = this.getParentNode(node, this.treeData)
|
|
const childrenVal = this.getChildren(node).filter(
|
|
(item) => !item.disabled
|
|
)
|
|
if (node.checked) {
|
|
// 选中
|
|
emitData = Array.from(new Set([...emitData, node[this.dataValue]]))
|
|
if (childrenVal.length) {
|
|
emitData = Array.from(
|
|
new Set([
|
|
...emitData,
|
|
...childrenVal.map((item) => item[this.dataValue])
|
|
])
|
|
)
|
|
// 孩子节点全部选中并且清除半选状态
|
|
childrenVal.forEach((childNode) => {
|
|
childNode.partChecked = false
|
|
partCheckedSet.delete(childNode[this.dataValue])
|
|
})
|
|
}
|
|
if (parentNodes.length) {
|
|
let flag = false
|
|
// 有父元素 如果父元素下所有子元素全部选中,选中父元素
|
|
while (parentNodes.length) {
|
|
const item = parentNodes.shift()
|
|
if (!item.disabled) {
|
|
if (flag) {
|
|
// 前一个没选中并且为半选那么之后的全为半选
|
|
item.partChecked = true
|
|
partCheckedSet.add(item[this.dataValue])
|
|
} else {
|
|
const allChecked = item[this.dataChildren]
|
|
.filter((node) => node.visible && !node.disabled)
|
|
.every((node) => node.checked)
|
|
if (allChecked) {
|
|
item.checked = true
|
|
item.partChecked = false
|
|
partCheckedSet.delete(item[this.dataValue])
|
|
emitData = Array.from(
|
|
new Set([...emitData, item[this.dataValue]])
|
|
)
|
|
} else {
|
|
item.partChecked = true
|
|
partCheckedSet.add(item[this.dataValue])
|
|
flag = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// 取消选中
|
|
emitData = emitData.filter((id) => id !== node[this.dataValue])
|
|
if (childrenVal.length) {
|
|
// 取消选中全部子节点
|
|
childrenVal.forEach((childNode) => {
|
|
emitData = emitData.filter(
|
|
(id) => id !== childNode[this.dataValue]
|
|
)
|
|
})
|
|
}
|
|
if (parentNodes.length) {
|
|
parentNodes.forEach((parentNode) => {
|
|
if (emitData.includes(parentNode[this.dataValue])) {
|
|
parentNode.checked = false
|
|
}
|
|
emitData = emitData.filter(
|
|
(id) => id !== parentNode[this.dataValue]
|
|
)
|
|
const hasChecked = parentNode[this.dataChildren]
|
|
.filter((node) => node.visible && !node.disabled)
|
|
.some((node) => node.checked || node.partChecked)
|
|
|
|
parentNode.partChecked = hasChecked
|
|
if (hasChecked) {
|
|
partCheckedSet.add(parentNode[this.dataValue])
|
|
} else {
|
|
partCheckedSet.delete(parentNode[this.dataValue])
|
|
}
|
|
})
|
|
}
|
|
}
|
|
this.$emit('input', emitData)
|
|
}
|
|
}
|
|
},
|
|
// 点击名称折叠或展开
|
|
handleHideChildren(node) {
|
|
const status = !node.showChildren
|
|
this.getReflectNode(node, this.treeData).showChildren = status
|
|
this.getReflectNode(node, this.filterTreeData).showChildren = status
|
|
},
|
|
// 根据 dataValue 找节点
|
|
changeStatus(list, ids, needEmit = false) {
|
|
const arr = [...list]
|
|
let flag = true
|
|
needEmit && (this.selectedListBaseinfo = [])
|
|
|
|
while (arr.length) {
|
|
const item = arr.shift()
|
|
|
|
if (ids.includes(item[this.dataValue])) {
|
|
this.$set(item, 'checked', true)
|
|
needEmit && this.selectedListBaseinfo.push(item)
|
|
// 数据被选中清除半选状态
|
|
item.partChecked = false
|
|
partCheckedSet.delete(item[this.dataValue])
|
|
} else {
|
|
this.$set(item, 'checked', false)
|
|
if (item.visible && !item.disabled) {
|
|
flag = false
|
|
}
|
|
if (partCheckedSet.has(item[this.dataValue])) {
|
|
this.$set(item, 'partChecked', true)
|
|
} else {
|
|
this.$set(item, 'partChecked', false)
|
|
}
|
|
}
|
|
|
|
if (item[this.dataChildren]?.length) {
|
|
arr.push(...item[this.dataChildren])
|
|
}
|
|
}
|
|
this.isSelectedAll = flag
|
|
needEmit && this.$emit('selectChange', [...this.selectedListBaseinfo])
|
|
},
|
|
// 移除选项
|
|
removeSelectedItem(node) {
|
|
this.isSelectedAll = false
|
|
if (this.linkage) {
|
|
this.handleNodeClick(node, false)
|
|
this.$emit('removeSelect', node)
|
|
} else {
|
|
const emitData = this.selectList.filter(
|
|
(item) => item !== node[this.dataValue]
|
|
)
|
|
this.$emit('removeSelect', node)
|
|
this.$emit('input', emitData)
|
|
}
|
|
},
|
|
// 全部选中
|
|
handleSelectAll() {
|
|
this.isSelectedAll = !this.isSelectedAll
|
|
if (this.isSelectedAll) {
|
|
if (!this.mutiple) {
|
|
uni.showToast({
|
|
title: '单选模式下不能全选',
|
|
icon: 'none',
|
|
duration: 1000
|
|
})
|
|
return
|
|
}
|
|
let emitData = []
|
|
this.treeData.forEach((item) => {
|
|
if (item.visible || (item.disabled && item.checked)) {
|
|
emitData = Array.from(new Set([...emitData, item[this.dataValue]]))
|
|
if (item[this.dataChildren]?.length) {
|
|
emitData = Array.from(
|
|
new Set([
|
|
...emitData,
|
|
...this.getChildren(item)
|
|
.filter(
|
|
(item) =>
|
|
!item.disabled || (item.disabled && item.checked)
|
|
)
|
|
.map((item) => item[this.dataValue])
|
|
])
|
|
)
|
|
}
|
|
}
|
|
})
|
|
this.$emit('input', emitData)
|
|
} else {
|
|
this.clear()
|
|
}
|
|
},
|
|
// 清空选项
|
|
clear() {
|
|
if (this.disabled) return
|
|
const emitData = []
|
|
partCheckedSet.clear()
|
|
this.selectedListBaseinfo.forEach((node) => {
|
|
if (node.visible && node.checked && node.disabled) {
|
|
emitData.push(node[this.dataValue])
|
|
}
|
|
})
|
|
this.$emit('input', emitData)
|
|
},
|
|
// 异步加载节点
|
|
handleLoadNode({ source, target }) {
|
|
// #ifdef MP-WEIXIN
|
|
const node = this.getReflectNode(source, this.treeData)
|
|
this.$set(
|
|
node,
|
|
this.dataChildren,
|
|
this.initData(
|
|
target,
|
|
source.visible,
|
|
source.path.split(this.pathHyphen)
|
|
)
|
|
)
|
|
this.$nextTick(() => {
|
|
this.handleHideChildren(node)
|
|
})
|
|
// #endif
|
|
|
|
// #ifndef MP-WEIXIN
|
|
this.$set(
|
|
source,
|
|
this.dataChildren,
|
|
this.initData(
|
|
target,
|
|
source.visible,
|
|
source.path.split(this.pathHyphen)
|
|
)
|
|
)
|
|
this.handleHideChildren(source)
|
|
// #endif
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
$primary-color: #007aff;
|
|
$col-sm: 4px;
|
|
$col-base: 8px;
|
|
$col-lg: 12px;
|
|
$row-sm: 5px;
|
|
$row-base: 10px;
|
|
$row-lg: 15px;
|
|
$radius-sm: 3px;
|
|
$radius-base: 6px;
|
|
|
|
.custom-tree-select-content {
|
|
.select-list {
|
|
padding-left: $row-base;
|
|
min-height: 35px;
|
|
border: 1px solid #e5e5e5;
|
|
border-radius: $radius-sm;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
|
|
&.active {
|
|
padding: calc(#{$col-sm} / 2) 0 calc(#{$col-sm} / 2) $row-base;
|
|
}
|
|
|
|
.left {
|
|
flex: 1;
|
|
|
|
.select-items {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.select-item {
|
|
margin: $col-sm $row-base $col-sm 0;
|
|
padding: $col-sm $row-sm;
|
|
max-width: auto;
|
|
height: auto;
|
|
background-color: #eaeaea;
|
|
border-radius: $radius-sm;
|
|
color: #333;
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
.name {
|
|
flex: 1;
|
|
padding-right: $row-base;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.close {
|
|
width: 18px;
|
|
height: 18px;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
overflow: hidden;
|
|
}
|
|
}
|
|
}
|
|
|
|
.right {
|
|
margin-right: $row-sm;
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
align-items: center;
|
|
}
|
|
|
|
&.disabled {
|
|
background-color: #f5f7fa;
|
|
|
|
.left {
|
|
.select-item {
|
|
.name {
|
|
padding: 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.popup-content {
|
|
flex: 1;
|
|
background-color: #fff;
|
|
border-top-left-radius: 20px;
|
|
border-top-right-radius: 20px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
.title {
|
|
padding: $col-base 3rem;
|
|
border-bottom: 1px solid $uni-border-color;
|
|
font-size: 14px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
position: relative;
|
|
|
|
.left {
|
|
position: absolute;
|
|
left: 10px;
|
|
}
|
|
|
|
.center {
|
|
flex: 1;
|
|
text-align: center;
|
|
}
|
|
|
|
.right {
|
|
position: absolute;
|
|
right: 10px;
|
|
}
|
|
}
|
|
|
|
.search-box {
|
|
margin: $col-base $row-base 0;
|
|
background-color: #fff;
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
.search-btn {
|
|
margin-left: $row-base;
|
|
height: 35px;
|
|
line-height: 35px;
|
|
}
|
|
}
|
|
|
|
.select-content {
|
|
margin: $col-base $row-base;
|
|
flex: 1;
|
|
overflow: hidden;
|
|
position: relative;
|
|
}
|
|
|
|
.scroll-view-box {
|
|
touch-action: none;
|
|
flex: 1;
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
left: 0;
|
|
}
|
|
|
|
.sentry {
|
|
height: 48px;
|
|
}
|
|
}
|
|
|
|
.no-data {
|
|
width: auto;
|
|
color: #C0C4CB !important;
|
|
font-size: 15px;
|
|
}
|
|
|
|
.no-data.center {
|
|
text-align: center;
|
|
}
|
|
}
|
|
</style>
|