116 lines
2.6 KiB
Vue
Raw Normal View History

2025-05-20 11:51:08 +08:00
<template>
<div :class="`custom-table-tree ${shadow ? 'custom-table-tree__shadow' : ''}`">
<div v-if="title" class="title">{{ title }}</div>
<div class="panel">
<el-input v-if="filter" v-model="state.keyword" clearable placeholder="请输入关键字筛选" class="panel-filter" />
<el-tree
ref="treeRef"
:data="state.list"
:node-key="option.nodeKey"
:show-checkbox="option.showCheckbox"
:default-expanded-keys="option.defaultExpandedKeys"
:default-checked-keys="option.defaultCheckedKeys"
:default-expand-all="option.defaultExpandAll"
:props="option.props ?? option.defaultProps"
:filter-node-method="filterNodeMethod"
@node-click="handleNodeClick"
>
<template #default="{ data: rows }">
<slot :data="rows"></slot>
</template>
</el-tree>
</div>
</div>
</template>
<script setup name="custom-table-tree">
import { reactive, ref, watch } from 'vue';
const props = defineProps({
title: { type: String, default: '' },
shadow: { type: Boolean, default: false },
filter: { type: Boolean, default: false },
data: { type: Array, default: () => [] },
option: {
type: Object,
default: () => {
return {
nodeKey: 'id',
showCheckbox: false,
props: {},
defaultProps: {
children: 'children',
label: 'label',
},
defaultExpandedKeys: [],
defaultCheckedKeys: [],
defaultExpandAll: false,
};
},
},
});
const emit = defineEmits(['node-click']);
const treeRef = ref(null);
const state = reactive({
keyword: '',
list: [],
});
const label = props.option.props?.label ?? 'label';
watch(
() => props.data,
(val) => {
state.list = val;
},
{
immediate: true,
}
);
watch(
() => state.keyword,
(val) => {
treeRef.value.filter(val);
}
);
const filterNodeMethod = (value, data) => {
if (!value) return true;
return data[label].includes(value);
};
const handleNodeClick = (data, node) => {
emit('node-click', data, node);
};
</script>
<style lang="scss" scoped>
.custom-table-tree {
width: 100%;
min-width: 200px;
height: 100%;
min-height: 400px;
@include flex-column;
&__shadow {
box-shadow: 2px 0 5px rgb(0 0 0 / 10%);
}
.title {
padding: 0 20px;
height: 36px;
font-size: 16px;
border-radius: 4px;
color: #ffffff;
background: var(--el-color-primary);
line-height: 36px;
}
.panel {
padding: 16px 10px 10px;
&-filter {
margin-bottom: 10px;
}
}
.el-tree {
box-sizing: border-box;
}
}
</style>