<template>
|
<div class="card filter" v-if="CompanyLength">
|
<h4 v-if="title" class="title sle">
|
{{ title }}
|
</h4>
|
<div class="search">
|
<el-input v-model="filterText" :placeholder="labeltext" clearable />
|
<el-dropdown trigger="click">
|
<el-icon size="20"><More /></el-icon>
|
<template #dropdown>
|
<el-dropdown-menu>
|
<el-dropdown-item @click="toggleTreeNodes(true)">{{ zhankai }}</el-dropdown-item>
|
<el-dropdown-item @click="toggleTreeNodes(false)">{{ zhedie }}</el-dropdown-item>
|
</el-dropdown-menu>
|
</template>
|
</el-dropdown>
|
</div>
|
<el-scrollbar :style="{ height: title ? `calc(100% - 95px)` : `calc(100% - 56px)` }">
|
<el-tree
|
ref="treeRef"
|
default-expand-all
|
:node-key="id"
|
:data="multiple ? treeData : treeAllData"
|
:show-checkbox="multiple"
|
:check-strictly="false"
|
:current-node-key="!multiple ? selected : ''"
|
:highlight-current="!multiple"
|
:expand-on-click-node="false"
|
:check-on-click-node="multiple"
|
:props="defaultProps"
|
:filter-node-method="filterNode"
|
:default-checked-keys="multiple ? selected : []"
|
@node-click="handleNodeClick"
|
@check="handleCheckChange"
|
>
|
<template #default="scope">
|
<span class="el-tree-node__label">
|
<slot :row="scope">
|
<el-image
|
v-if="scope.node.label != '全部'"
|
style="position: relative; top: 5px; width: 20px; height: 20px; margin: 0 1px"
|
:src="scope.node.data.logo"
|
:zoom-rate="1.2"
|
:max-scale="7"
|
:min-scale="0.2"
|
show-progress
|
fit="cover"
|
/>{{ scope.node.label }}
|
</slot>
|
</span>
|
</template>
|
</el-tree>
|
</el-scrollbar>
|
</div>
|
</template>
|
|
<script setup lang="ts" name="TreeFilter">
|
import { ref, watch, onBeforeMount, nextTick } from "vue";
|
import { ElTree } from "element-plus";
|
import { SelectCompanyId } from "@/api/modules/hxzk/user/company";
|
const CompanyLength = ref(true);
|
|
// 接收父组件参数并设置默认值
|
interface TreeFilterProps {
|
requestApi?: (data?: any) => Promise<any>; // 请求分类数据的 api ==> 非必传
|
data?: { [key: string]: any }[]; // 分类数据,如果有分类数据,则不会执行 api 请求 ==> 非必传
|
title?: string; // treeFilter 标题 ==> 非必传
|
id?: string; // 选择的id ==> 非必传,默认为 “id”
|
label?: string; // 显示的label ==> 非必传,默认为 “label”
|
logo?: string; // 新增的显示内容字段 ==> 非必传
|
multiple?: boolean; // 是否为多选 ==> 非必传,默认为 false
|
defaultValue?: any; // 默认选中的值 ==> 非必传
|
labeltext: string;
|
zhankai: string;
|
zhedie: string;
|
}
|
const props = withDefaults(defineProps<TreeFilterProps>(), {
|
id: "id",
|
label: "label",
|
logo: "", // 新增字段的默认值
|
multiple: false
|
});
|
|
const defaultProps = {
|
children: "children",
|
label: props.label
|
};
|
|
const treeRef = ref<InstanceType<typeof ElTree>>();
|
const treeData = ref<{ [key: string]: any }[]>([]);
|
const treeAllData = ref<{ [key: string]: any }[]>([]);
|
|
const selected = ref();
|
const setSelected = async () => {
|
const companyname = await SelectCompanyId();
|
if (props.multiple) selected.value = Array.isArray(props.defaultValue) ? props.defaultValue : [props.defaultValue];
|
else selected.value = typeof props.defaultValue === "string" ? props.defaultValue : companyname;
|
};
|
|
onBeforeMount(async () => {
|
setSelected();
|
if (props.requestApi) {
|
const { data } = await props.requestApi!();
|
|
treeData.value = data;
|
console.log(treeData.value);
|
if (treeData.value.length == 1) {
|
if (treeData.value[0].children.length == 0) {
|
CompanyLength.value = false;
|
}
|
}
|
treeAllData.value = [...data];
|
}
|
});
|
|
// 使用 nextTick 防止打包后赋值不生效,开发环境是正常的
|
watch(
|
() => props.defaultValue,
|
() => nextTick(() => setSelected()),
|
{ deep: true, immediate: true }
|
);
|
|
watch(
|
() => props.data,
|
() => {
|
if (props.data?.length) {
|
treeData.value = props.data;
|
treeAllData.value = [...props.data];
|
}
|
},
|
{ deep: true, immediate: true }
|
);
|
|
const filterText = ref("");
|
watch(filterText, val => {
|
treeRef.value!.filter(val);
|
});
|
|
// 过滤
|
const filterNode = (value: string, data: { [key: string]: any }, node: any) => {
|
if (!value) return true;
|
let parentNode = node.parent,
|
labels = [node.label],
|
level = 1;
|
while (level < node.level) {
|
labels = [...labels, parentNode.label];
|
parentNode = parentNode.parent;
|
level++;
|
}
|
// 同时过滤新的展示内容
|
if (props.logo && data[props.logo]) {
|
labels.push(data[props.logo]);
|
}
|
return labels.some(label => label.indexOf(value) !== -1);
|
};
|
|
// 切换树节点的展开或折叠状态
|
const toggleTreeNodes = (isExpand: boolean) => {
|
let nodes = treeRef.value?.store.nodesMap;
|
if (!nodes) return;
|
for (const node in nodes) {
|
if (nodes.hasOwnProperty(node)) {
|
nodes[node].expanded = isExpand;
|
}
|
}
|
};
|
|
// emit
|
const emit = defineEmits<{
|
change: [value: any];
|
}>();
|
|
// 单选
|
const handleNodeClick = (data: { [key: string]: any }) => {
|
if (props.multiple) return;
|
emit("change", data[props.id]);
|
};
|
|
// 多选
|
const handleCheckChange = () => {
|
emit("change", treeRef.value?.getCheckedKeys());
|
};
|
|
// 暴露给父组件使用
|
defineExpose({ treeData, treeAllData, treeRef });
|
</script>
|
|
<style scoped lang="scss">
|
@import "./index";
|
</style>
|