2021-10-09 06:59:38 +00:00
|
|
|
|
<script setup lang="ts">
|
2021-10-11 08:17:55 +00:00
|
|
|
|
import { VNode, VNodeChild } from 'vue'
|
2021-10-09 14:19:17 +00:00
|
|
|
|
import TreeEntity from './TreeEntity.vue'
|
2021-10-11 08:17:55 +00:00
|
|
|
|
import { useTreeData } from '/@src/module/tree/useTreeData'
|
|
|
|
|
import { TreeNode } from '/@src/module/tree/tree.type'
|
2021-10-11 10:09:38 +00:00
|
|
|
|
import { getEmitNode } from '/@src/module/tree/treeHelper'
|
2021-10-09 06:59:38 +00:00
|
|
|
|
|
2021-10-11 08:17:55 +00:00
|
|
|
|
type EditAction = 'add' | 'update' | 'del'
|
|
|
|
|
|
|
|
|
|
type EditType = boolean | EditAction[]
|
|
|
|
|
|
2021-10-11 10:09:38 +00:00
|
|
|
|
interface TreeData {
|
2021-10-09 06:59:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* 节点唯一索引值,用于对指定节点进行各类操作
|
|
|
|
|
*/
|
|
|
|
|
id: string | number
|
|
|
|
|
/**
|
|
|
|
|
* 节点标题
|
|
|
|
|
*/
|
|
|
|
|
title: string | (() => string)
|
|
|
|
|
/**
|
|
|
|
|
* 节点字段名
|
|
|
|
|
*/
|
|
|
|
|
field: string | (() => string)
|
|
|
|
|
/**
|
|
|
|
|
* 子节点。支持设定选项同父节点
|
|
|
|
|
*/
|
|
|
|
|
children: TreeData[]
|
|
|
|
|
/**
|
|
|
|
|
* 点击节点弹出新窗口对应的 url。需开启 isJump 参数
|
2021-10-09 14:19:17 +00:00
|
|
|
|
* 废弃,通过 on-click事件用户控制
|
2021-10-09 06:59:38 +00:00
|
|
|
|
*/
|
2021-10-12 03:30:07 +00:00
|
|
|
|
href?: string | URL
|
2021-10-09 06:59:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* 节点是否初始展开,默认 false
|
2021-10-09 14:19:17 +00:00
|
|
|
|
* 废弃:设置 v-model:spreadKeys
|
2021-10-09 06:59:38 +00:00
|
|
|
|
*/
|
2021-10-12 03:30:07 +00:00
|
|
|
|
spread?: boolean
|
2021-10-09 06:59:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* 节点是否初始为选中状态(如果开启复选框的话),默认 false
|
2021-10-09 14:19:17 +00:00
|
|
|
|
* 废弃:设置 v-model:checkedKeys
|
2021-10-09 06:59:38 +00:00
|
|
|
|
*/
|
2021-10-12 03:30:07 +00:00
|
|
|
|
checked?: boolean
|
2021-10-09 06:59:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* 节点是否为禁用状态。默认 false
|
|
|
|
|
*/
|
2021-10-12 03:30:07 +00:00
|
|
|
|
disabled?: boolean
|
2021-10-09 06:59:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-10-12 03:30:07 +00:00
|
|
|
|
interface TreeProps {
|
2021-10-09 14:19:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* 指定唯一的id
|
|
|
|
|
*/
|
2021-10-12 03:30:07 +00:00
|
|
|
|
// eslint-disable-next-line vue/require-default-prop
|
2021-10-11 08:17:55 +00:00
|
|
|
|
key?: string
|
2021-10-09 14:19:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* 选中的节点
|
|
|
|
|
*/
|
2021-10-12 03:30:07 +00:00
|
|
|
|
// eslint-disable-next-line vue/require-default-prop
|
2021-10-13 07:41:04 +00:00
|
|
|
|
checkedKeys?: NonNullable<(string | number)[]>
|
2021-10-09 14:19:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* 展开的节点
|
|
|
|
|
*/
|
2021-10-12 03:30:07 +00:00
|
|
|
|
// eslint-disable-next-line vue/require-default-prop
|
2021-10-11 08:17:55 +00:00
|
|
|
|
spreadKeys?: (string | number)[]
|
2021-10-09 06:59:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* 数据源
|
|
|
|
|
*/
|
2021-10-12 03:30:07 +00:00
|
|
|
|
// eslint-disable-next-line vue/require-default-prop
|
2021-10-11 08:17:55 +00:00
|
|
|
|
data?: TreeData[]
|
2021-10-09 06:59:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* 是否显示复选框 默认 false
|
|
|
|
|
*/
|
|
|
|
|
showCheckbox?: boolean
|
|
|
|
|
/**
|
|
|
|
|
* 是否开启节点的操作图标。默认 false。
|
|
|
|
|
若为 true,则默认显示“改删”图标
|
|
|
|
|
若为 数组,则可自由配置操作图标的显示状态和顺序,目前支持的操作图标有:add、update、del,如:
|
|
|
|
|
edit: ['add', 'update', 'del']
|
|
|
|
|
*/
|
|
|
|
|
edit?: EditType
|
|
|
|
|
/**
|
|
|
|
|
* 是否开启手风琴模式,默认 false
|
|
|
|
|
*/
|
|
|
|
|
accordion?: boolean
|
|
|
|
|
/**
|
|
|
|
|
* 是否仅允许节点左侧图标控制展开收缩。默认 false(即点击节点本身也可控制)。若为 true,则只能通过节点左侧图标来展开收缩
|
|
|
|
|
*/
|
|
|
|
|
onlyIconControl?: boolean
|
|
|
|
|
/**
|
|
|
|
|
* 是否允许点击节点时弹出新窗口跳转。默认 false,若开启,需在节点数据中设定 link 参数(值为 url 格式
|
2021-10-09 14:19:17 +00:00
|
|
|
|
* 废弃:能过事件用户自行控制
|
2021-10-09 06:59:38 +00:00
|
|
|
|
*/
|
|
|
|
|
isJump?: boolean
|
|
|
|
|
/**
|
|
|
|
|
* 是否开启连接线。默认 true,若设为 false,则节点左侧出现三角图标。
|
|
|
|
|
*/
|
|
|
|
|
showLine?: boolean
|
|
|
|
|
/**
|
|
|
|
|
* 自定义各类默认文本,目前支持以下设定:
|
|
|
|
|
*/
|
2021-10-12 03:30:07 +00:00
|
|
|
|
// eslint-disable-next-line vue/require-default-prop
|
2021-10-09 06:59:38 +00:00
|
|
|
|
text?: {
|
|
|
|
|
/**
|
|
|
|
|
* 节点默认名称
|
|
|
|
|
*/
|
|
|
|
|
defaultNodeName?: () => string | string
|
|
|
|
|
/**
|
|
|
|
|
* 数据为空时的提示文本
|
|
|
|
|
*/
|
2021-10-11 08:17:55 +00:00
|
|
|
|
none?: (() => string) | string | VNode | Element
|
2021-10-09 06:59:38 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-11 10:09:38 +00:00
|
|
|
|
interface EmitData {
|
2021-10-09 06:59:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* 当前点击的节点数据
|
|
|
|
|
*/
|
|
|
|
|
data: TreeData
|
|
|
|
|
/**
|
|
|
|
|
* 节点的展开状态
|
2021-10-11 10:09:38 +00:00
|
|
|
|
* remove
|
2021-10-09 06:59:38 +00:00
|
|
|
|
*/
|
2021-10-11 10:09:38 +00:00
|
|
|
|
state?: 'open' | 'close' | 'normal'
|
2021-10-09 06:59:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* 当前节点元素
|
2021-10-11 10:09:38 +00:00
|
|
|
|
* remove
|
2021-10-09 06:59:38 +00:00
|
|
|
|
*/
|
2021-10-11 10:09:38 +00:00
|
|
|
|
elem?: Element | VNode | VNodeChild
|
2021-10-09 06:59:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-10-11 10:09:38 +00:00
|
|
|
|
interface TreeEmits {
|
2021-10-09 06:59:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* 节点被点击后触发
|
|
|
|
|
* @param e 事件
|
|
|
|
|
* @param treeNode
|
|
|
|
|
*/
|
2021-10-11 10:09:38 +00:00
|
|
|
|
(e: 'node-click', treeNode: EmitData): void
|
2021-10-09 06:59:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* 点击复选框时触发
|
|
|
|
|
* @param e 事件
|
|
|
|
|
* @param treeNode
|
|
|
|
|
*/
|
2021-10-11 10:09:38 +00:00
|
|
|
|
(e: 'node-check', treeNode: EmitData): void
|
|
|
|
|
// /**
|
|
|
|
|
// * 操作节点的回调
|
|
|
|
|
// * @param e 事件
|
|
|
|
|
// * @param treeNode
|
|
|
|
|
// */
|
|
|
|
|
// (e: 'node-operate', treeNode: EmitData): void
|
2021-10-13 07:41:04 +00:00
|
|
|
|
(e: 'update:spreadKeys', spreadKeys: (string | number)[]): void
|
|
|
|
|
(e: 'update:checkedKeys', checkedKeys: (string | number)[]): void
|
2021-10-09 06:59:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const props = withDefaults(defineProps<TreeProps>(), {
|
|
|
|
|
showCheckbox: false,
|
|
|
|
|
accordion: false,
|
|
|
|
|
onlyIconControl: false,
|
|
|
|
|
isJump: false,
|
|
|
|
|
showLine: true,
|
2021-10-11 08:17:55 +00:00
|
|
|
|
edit: () => true,
|
2021-10-09 14:19:17 +00:00
|
|
|
|
})
|
|
|
|
|
|
2021-10-11 08:17:55 +00:00
|
|
|
|
const emit = defineEmits<TreeEmits>()
|
2021-10-09 14:19:17 +00:00
|
|
|
|
|
2021-10-14 08:37:17 +00:00
|
|
|
|
const {
|
|
|
|
|
innerTreeData,
|
|
|
|
|
updateInnerTreeData,
|
|
|
|
|
treeWrapperClass,
|
|
|
|
|
updateCheckedByNode,
|
|
|
|
|
} = useTreeData(props, emit)
|
2021-10-09 14:19:17 +00:00
|
|
|
|
|
2021-10-13 04:14:24 +00:00
|
|
|
|
function handleNodeClick(node: TreeNode, type: 'node' | 'icon') {
|
|
|
|
|
// 是否只通过icon控制展开收起
|
|
|
|
|
if (props.onlyIconControl) {
|
|
|
|
|
type === 'icon' && updateInnerTreeData(innerTreeData.value, node)
|
|
|
|
|
} else {
|
|
|
|
|
updateInnerTreeData(innerTreeData.value, node)
|
|
|
|
|
}
|
|
|
|
|
// icon 点击不emit出事件
|
2021-10-11 10:09:38 +00:00
|
|
|
|
const emitNode = getEmitNode(props.data!, node)
|
2021-10-13 07:41:04 +00:00
|
|
|
|
type !== 'icon' && emit('node-click', { data: emitNode! })
|
2021-10-11 08:17:55 +00:00
|
|
|
|
}
|
2021-10-09 06:59:38 +00:00
|
|
|
|
</script>
|
|
|
|
|
<script lang="ts">
|
|
|
|
|
export default {
|
|
|
|
|
name: 'LayTree',
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
<template>
|
2021-10-09 14:19:17 +00:00
|
|
|
|
<div :class="treeWrapperClass">
|
|
|
|
|
<TreeEntity
|
2021-10-12 03:30:07 +00:00
|
|
|
|
v-for="(node, index) in innerTreeData"
|
|
|
|
|
:key="node.id || index"
|
2021-10-09 14:19:17 +00:00
|
|
|
|
:node="node"
|
2021-10-14 08:37:17 +00:00
|
|
|
|
:show-checkbox="showCheckbox"
|
2021-10-11 08:17:55 +00:00
|
|
|
|
@node-click="handleNodeClick"
|
2021-10-14 08:37:17 +00:00
|
|
|
|
:updateCheckedByNode="updateCheckedByNode"
|
2021-10-12 03:30:07 +00:00
|
|
|
|
/>
|
2021-10-09 14:19:17 +00:00
|
|
|
|
</div>
|
2021-10-09 06:59:38 +00:00
|
|
|
|
</template>
|
|
|
|
|
<style scoped></style>
|