121 lines
2.6 KiB
Vue
Raw Normal View History

2025-03-11 09:39:25 +01:00
<template>
<div :class="`custom-table-tree ${shadow ? 'custom-table-tree__shadow' : ''}`">
<div v-if="title" class="title">{{ title }}</div>
2025-03-24 09:55:44 +01:00
<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>
2025-03-11 09:39:25 +01:00
</div>
</template>
<script setup name="custom-table-tree">
2025-03-24 09:55:44 +01:00
import { reactive, ref, watch } from 'vue';
2025-03-11 09:39:25 +01:00
const props = defineProps({
title: { type: String, default: '' },
shadow: { type: Boolean, default: true },
2025-03-24 09:55:44 +01:00
filter: { type: Boolean, default: false },
2025-03-11 09:39:25 +01:00
data: { type: Array, default: () => [] },
option: {
type: Object,
default: () => {
return {
2025-03-20 09:16:17 +01:00
nodeKey: 'id',
2025-03-11 09:39:25 +01:00
showCheckbox: false,
2025-03-20 09:16:17 +01:00
props: {},
2025-03-11 09:39:25 +01:00
defaultProps: {
children: 'children',
label: 'label',
},
defaultExpandedKeys: [],
defaultCheckedKeys: [],
2025-03-24 09:55:44 +01:00
defaultExpandAll: false,
2025-03-11 09:39:25 +01:00
};
},
},
});
const emit = defineEmits(['node-click']);
2025-03-24 09:55:44 +01:00
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);
};
2025-03-20 09:16:17 +01:00
const handleNodeClick = (data, node) => {
emit('node-click', data, node);
2025-03-11 09:39:25 +01:00
};
</script>
<style lang="scss" scoped>
.custom-table-tree {
width: 100%;
height: 100%;
2025-03-24 09:55:44 +01:00
min-height: 400px;
2025-03-11 09:39:25 +01:00
min-width: 200px;
@include flex-column();
&__shadow {
box-shadow: 2px 0px 5px rgba(0, 0, 0, 0.1);
}
.title {
height: 36px;
padding: 0 20px;
line-height: 36px;
border-radius: 4px;
font-size: 16px;
color: #fff;
background: var(--el-color-primary);
}
2025-03-24 09:55:44 +01:00
.panel {
2025-03-11 09:39:25 +01:00
padding: 16px 10px 10px;
2025-03-24 09:55:44 +01:00
&-filter {
margin-bottom: 10px;
}
}
.el-tree {
2025-03-11 09:39:25 +01:00
box-sizing: border-box;
}
}
</style>