123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- <template>
- <div class="tree-container">
- <!-- 搜索区域 -->
- <div class="search-bar">
- <el-input v-model="searchKeyword" placeholder="快速检索" class="search-input" prefix-icon="Search" />
- <el-button type="primary" class="search-btn" @click="handleSearch">查询</el-button>
- <el-button type="default" class="reset-btn" @click="handleReset">重置</el-button>
- </div>
- <!-- 树形结构区域 -->
- <div class="tree-wrapper">
- <el-tree
- ref="treeRef"
- v-model:checkedKeys="checkedKeys"
- :data="treeData"
- :props="treeProps"
- default-expand-all
- highlight-current
- show-checkbox
- check-on-click-node
- node-key="id"
- :filter-node-method="filterNode"
- @check-change="handleCheckChange"
- class="custom-tree"
- />
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import { ref, computed } from 'vue';
- import { ElTree } from 'element-plus';
- import { getDeptTree } from '@/api/address/index';
- import { el } from 'element-plus/es/locale';
- const emit = defineEmits(['treeCheck']);
- // 树形配置项
- const treeProps = {
- label: 'label',
- children: 'children',
- };
- interface Tree {
- id: number;
- label: string;
- children?: Tree[];
- }
- // 搜索关键词
- const searchKeyword = ref('');
- // 选中的节点ID(受控于v-model:checkedKeys)
- const checkedKeys = ref<(string | number)[]>([]);
- // 树形组件实例
- const treeRef = ref<InstanceType<typeof ElTree>>();
- // 树形结构数据(模拟后端返回数据)
- // const treeData = ref<Tree[]>();
- const treeData = ref<Tree[]>([
- {
- id: 1,
- label: '交通部根节点',
- children: [
- { id: 11, label: 'XXXXXXXX机构11' },
- {
- id: 12,
- label: 'XXXXXXXX机构12',
- children: [
- { id: 121, label: 'XXXXXXXX机构121' },
- { id: 122, label: 'XXXXXXXX机构123' },
- { id: 123, label: 'XXXXXXXX机构123' },
- { id: 124, label: 'XXXXXXXX机构124' },
- { id: 125, label: 'XXXXXXXX机构125' },
- { id: 126, label: 'XXXXXXXX机构126' },
- ],
- },
- {
- id: 13,
- label: 'XXXXXXXX机构13',
- children: [
- { id: 131, label: 'XXXXXXXX机构131' },
- { id: 132, label: 'XXXXXXXX机构132' },
- { id: 133, label: 'XXXXXXXX机构133' },
- { id: 134, label: 'XXXXXXXX机构134' },
- { id: 135, label: 'XXXXXXXX机构135' },
- { id: 136, label: 'XXXXXXXX机构136' },
- ],
- },
- {
- id: 14,
- label: 'XXXXXXXX机构14',
- children: [
- { id: 141, label: 'XXXXXXXX机构141' },
- { id: 142, label: 'XXXXXXXX机构142' },
- { id: 143, label: 'XXXXXXXX机构143' },
- { id: 144, label: 'XXXXXXXX机构144' },
- { id: 145, label: 'XXXXXXXX机构145' },
- { id: 146, label: 'XXXXXXXX机构146' },
- ],
- },
- ],
- },
- ]);
- onMounted(async () => {
- getTree();
- });
- // 过滤节点(搜索功能)
- const getTree = () => {
- getDeptTree().then((res: any) => {
- if (res.code == 200) {
- treeData.value = res.data;
- } else {
- treeData.value = [];
- }
- });
- };
- // 过滤节点(搜索功能)
- const filterNode = (value: string, data: any) => {
- if (!value) return true;
- return data.label.toLowerCase().includes(value.toLowerCase());
- };
- const handleCheckChange = (data: Tree, checked: boolean, indeterminate: boolean) => {
- // console.log('勾选状态变化:', {
- // nodeId: data.id,
- // nodeLabel: data.label,
- // isChecked: checked, // 是否完全勾选
- // isIndeterminate: indeterminate // 是否半选(父节点部分子节点勾选)
- // });
- // 以上参数按照项目需求取值,正常情况下只会用到 allCheckedKeys
- const allCheckedKeys = treeRef.value?.getCheckedKeys(false) || [];
- // console.log('所有勾选的节点ID:', allCheckedKeys);
- if (tabsItem.value) {
- emit('treeCheck', allCheckedKeys);
- }
- };
- // 处理搜索
- const handleSearch = () => {
- treeRef.value?.filter(searchKeyword.value);
- };
- // 处理重置
- const tabsItem = ref(true);
- const handleReset = (str: any) => {
- searchKeyword.value = '';
- treeRef.value!.setCheckedKeys([], false);
- treeRef.value?.filter('');
- tabsItem.value = str;
- };
- defineExpose({ handleReset });
- </script>
- <style scoped lang="scss">
- .tree-container {
- width: 100%;
- padding: 20px;
- background: #fff;
- border-radius: 4px;
- }
- /* 搜索区域样式 */
- .search-bar {
- display: flex;
- align-items: center;
- gap: 12px;
- margin-bottom: 20px;
- .search-input {
- flex: 1;
- height: 38px;
- width: 150px;
- }
- .search-btn,
- .reset-btn {
- min-width: 80px;
- height: 38px;
- padding: 0 16px;
- }
- .reset-btn {
- border: 1px solid #dcdfe6;
- color: #606266;
- margin-left: 0;
- }
- }
- /* 树形结构样式 */
- .tree-wrapper {
- border: 1px solid #e4e7ed;
- border-radius: 4px;
- min-height: 300px;
- overflow-y: auto;
- padding: 10px 0;
- }
- .custom-tree {
- --el-tree-node-content-hover-bg-color: transparent; /* 移除节点hover背景 */
- .el-tree-node__content {
- height: 36px;
- align-items: center;
- }
- /* 复选框样式调整 */
- .el-checkbox .el-checkbox__inner {
- width: 18px;
- height: 18px;
- border-radius: 4px;
- }
- .el-checkbox__input.is-checked .el-checkbox__inner {
- background-color: #10b981; /* 绿色勾选背景 */
- border-color: #10b981;
- }
- /* 自定义图标样式 */
- .tree-icon {
- font-size: 18px;
- &.checked {
- color: #10b981; /* 绿色勾选图标 */
- }
- &.unchecked {
- color: #c0c6cf; /* 未勾选灰色图标 */
- }
- }
- }
- </style>
|