tiny-vue/examples/sites/demos/pc/app/dialog-select/nest-tree-multi.vue

232 lines
6.2 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="tiny-demo">
<tiny-button @click="visible = !visible">{{ `${visible ? '关闭' : '打开'}窗口` }}</tiny-button>
<tiny-dialog-select
ref="dialogSelect"
class="tiny-demo-tree-multi"
:visible="visible"
@update:visible="visible = $event"
popseletor="tree"
multi
:dialog-op="dialogOp"
:tree-op="treeOp"
:selected-box-op="selectedBoxOp"
:lookup-method="lookupMethod"
:before-close="beforeClose"
@change="onDialogSelectChange"
value-field="id"
text-field="label"
:main-height="290"
>
<template #option="{ option, mouseenter, mouseleave }">
<div class="tiny-demo-tree-multi-option" @mouseenter="mouseenter" @mouseleave="mouseleave">
<span class="title">{{ option._$title }}</span>
<span class="sub-text" v-if="option._$auxi">({{ option._$auxi }})</span>
</div>
</template>
<template #close="{ option, close }">
<div class="tiny-demo-tree-multi-close">
<span @click="close(option)">
<tiny-icon-close></tiny-icon-close>
</span>
</div>
</template>
</tiny-dialog-select>
</div>
</template>
<script>
import { DialogSelect, Button, Modal } from '@opentiny/vue'
import { iconClose } from '@opentiny/vue-icon'
import Sortable from 'sortablejs'
// 模拟服务侧数据
const datas = [
{ id: 1, pid: null, label: '一级 1' },
{ id: 2, pid: null, label: '一级 2' },
{ id: 3, pid: null, label: '一级 3', isLeaf: true, children: [] },
{ id: 4, pid: 1, label: '二级 4' },
{ id: 5, pid: 1, label: '二级 5', isLeaf: true, children: [] },
{ id: 6, pid: 2, label: '二级 6', isLeaf: true, children: [] },
{ id: 7, pid: 2, label: '二级 7', isLeaf: true, children: [] },
{ id: 8, pid: 4, label: '三级 8', isLeaf: true, children: [] },
{ id: 9, pid: 4, label: '三级 9', isLeaf: true, children: [] }
]
// 接口1根据pid查询直接子节点
const queryChildrenByPid = (pid) => datas.filter((record) => record.pid === pid)
// 接口2根据搜索文本找到匹配节点的所有父级节点id
// 支持通过节点id搜索只是为了简化示例代码业务使用时不必支持可把接口3实现为批量接口提高查询效率
const queryPidsBySearchFn = (search) => {
const ids = []
// 递归记录节点id
const ff = (node, path) => {
path.unshift(node.id)
if (!node.pid) return
const p = datas.find((record) => record.id === node.pid)
ff(p, path)
}
if (search) {
datas
.filter(
(record) =>
(typeof search === 'string' && ~record.label.indexOf(search)) ||
(typeof search === 'number' && record.id === search)
)
.forEach((node) => {
const path = []
ff(node, path)
ids.splice(ids.length, 0, ...path.slice(0, path.length - 1))
})
}
return dedup(ids)
}
// 接口3根据一组节点id找到匹配节点的所有父级节点id
// 使用了接口2只是为了简化示例代码实现为批量接口可提高查询效率
const queryPidsByIdsFn = (ids, pids = []) => {
let allPids = [...pids]
ids.forEach((id) => {
allPids = allPids.concat(queryPidsBySearchFn(id))
})
return dedup(allPids)
}
// 接口4根据一组节点id查询这组节点
const queryNodesByIds = (ids) => datas.filter((row) => ~ids.indexOf(row.id))
// 去重
const dedup = (ids, tmp = []) => {
const res = [...tmp, ...ids]
return Array.from(new Set(res))
}
export default {
components: {
TinyDialogSelect: DialogSelect,
TinyButton: Button,
TinyIconClose: iconClose()
},
data() {
return {
visible: false,
dialogOp: {
top: '20vh',
width: '800px',
title: '选择公司',
beforeClose: this.beforeClose,
dialogClass: 'custom-dialog-class'
},
selectedBoxOp: {
config: {
pkField: 'id',
pkFieldType: 'number',
showField: ['label'],
plugin: Sortable
}
},
treeOp: {
nodeKey: 'id',
pathSplit: '/',
props: { children: 'children', label: 'label', isLeaf: 'isLeaf' },
checkStrictly: true,
baseIndent: 0,
load: this.remoteSearch,
queryPidsBySearch: this.queryPidsBySearch,
queryPidsByIds: this.queryPidsByIds,
defaultCheckedKeys: [1, 4, 8]
}
}
},
methods: {
beforeClose() {
return true
},
remoteSearch(node, callback) {
setTimeout(() => {
const res = queryChildrenByPid(node.level === 0 ? null : node.data.id)
callback(res)
}, 300)
},
queryPidsBySearch(search, callback) {
setTimeout(() => {
const res = queryPidsBySearchFn(search)
callback(res)
}, 300)
},
queryPidsByIds(ids, callback) {
setTimeout(() => {
const res = queryPidsByIdsFn(ids)
callback(res)
}, 300)
},
lookupMethod(values) {
return new Promise((resolve) => {
setTimeout(() => {
const res = queryNodesByIds(values)
// 序列化是为了模拟每次返回的都是新对象
const copy = JSON.parse(JSON.stringify(res))
// 已选栏在插槽中使用字段_$title和_$auxi做定制显示所以要在lookup接口内设置如果使用其它字段就不用设置
copy.forEach((row) => {
row._$title = row.label
row._$auxi = '辅助文本'
})
resolve(copy)
}, 300)
})
},
onDialogSelectChange(values, texts, selectedDatas) {
Modal.message({
message: `values:${values},texts:${texts},selectedDatas:${JSON.stringify(selectedDatas)}`,
status: 'info'
})
}
}
}
</script>
<style scoped>
.tiny-demo-tree-multi .tiny-demo-tree-multi-option {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
height: 28px;
}
.tiny-demo-tree-multi .tiny-demo-tree-multi-option .title {
color: #161e26;
position: relative;
top: 4px;
}
.tiny-demo-tree-multi .tiny-demo-tree-multi-option .sub-text {
color: #8d959e;
position: relative;
top: 4px;
margin-left: 8px;
}
.tiny-demo-tree-multi-close {
height: 28px;
}
.tiny-demo-tree-multi-close > span {
position: relative;
top: 2px;
left: 12px;
}
</style>