<template>
|
<div class="h100" v-loading="checkTreeLoading">
|
<el-input class="mb10" v-model="filterText" placeholder="搜索" clearable></el-input>
|
<el-tree
|
ref="treeRef"
|
:data="checkTreeData"
|
:node-key="treeProps.id"
|
show-checkbox
|
|
:props="{ children: treeProps.children, label: treeProps.label, class: treeNodeClass, disabled: 'Inherit' }"
|
icon="ele-Menu"
|
:filter-node-method="filterNode"
|
highlight-current
|
default-expand-all
|
/>
|
</div>
|
|
<!-- <template #default="{ node, data }">
|
<slot :node="node" :data="data"> </slot>
|
</template> -->
|
<!-- </el-tree> -->
|
</template>
|
|
<script setup lang="ts">
|
import { ElMessage, ElTree } from 'element-plus';
|
import type { PropType } from 'vue';
|
import { nextTick, ref, toRefs } from 'vue';
|
import { useFilterTree } from '/@/hooks/useFilterTree';
|
|
const props = defineProps({
|
treeProps: {
|
type: Object as PropType<{
|
id: string;
|
label: string;
|
children?: string;
|
}>,
|
default: () => ({
|
id: 'ID',
|
label: 'Name',
|
children: 'Children',
|
}),
|
},
|
/**
|
* 当不需要使用接口获取树数据时,直接传入 treeData
|
*/
|
treeData: {
|
type: Array<any>,
|
},
|
/**
|
* 获取树可 check 内容的树
|
*/
|
getCheckTreeApi: {
|
type: Function,
|
},
|
/**
|
* 提交 checked 内容接口
|
*/
|
submitCheckedApi: {
|
type: Function,
|
required: true,
|
},
|
/**
|
* 返回已经checked的 keys,传入树的数据
|
*/
|
filterCheckedKeys: {
|
type: Function as PropType<(data?) => Array<any>>,
|
},
|
/**
|
* 返回 true 的节点,表示该节点不能被 check
|
*/
|
hideCheckbox: {
|
type: Function as PropType<(data) => boolean>,
|
},
|
/** @description 操作提示词设置 */
|
tip: {
|
type: Object as PropType<{
|
success: string;
|
error: string;
|
unModified: string;
|
}>,
|
default: () => ({
|
success: '设置成功!',
|
error: '设置失败',
|
unModified: '未修改',
|
}),
|
},
|
/**
|
* 提交完成之后是否需要 ElMessage 提示
|
*/
|
showTip: {
|
type: Boolean,
|
default: true,
|
},
|
});
|
|
const { treeProps } = toRefs(props);
|
|
const checkTreeData = ref<any[]>([]);
|
const checkTreeLoading = ref(false);
|
const treeRef = ref<InstanceType<typeof ElTree>>(null);
|
const { filterNode, filterText } = useFilterTree(treeRef, treeProps.value.label);
|
|
// 叶子节点同行显示样式
|
const treeNodeClass = (data) => {
|
let addClass = true; // 添加叶子节点同行显示样式
|
for (const key in data.Children) {
|
// 当前节点的子节点的子节点存在且大于0 不添加
|
if (data.Children[key].Children?.length ?? 0 > 0) {
|
addClass = false;
|
break;
|
}
|
}
|
const penultimateClass = addClass ? 'penultimate-node' : '';
|
let treeNodeClass = penultimateClass;
|
if (typeof props.hideCheckbox !== 'undefined') {
|
if (props.hideCheckbox(data)) {
|
treeNodeClass = treeNodeClass + ' el-tree-node_hide-checkbox';
|
}
|
}
|
|
return treeNodeClass;
|
};
|
|
const getTreeData = async (...args) => {
|
if (props.getCheckTreeApi) {
|
// 是否成功获取
|
let isGetSuccess = true;
|
checkTreeLoading.value = true;
|
const res = await props.getCheckTreeApi(...args).finally(() => {
|
checkTreeLoading.value = false;
|
});
|
if (res?.Code === 0) {
|
const resData = (res.Data || []) as [];
|
checkTreeData.value = resData;
|
} else {
|
isGetSuccess = false;
|
ElMessage.error('获取失败' + (res?.Message ? `,${JSON.stringify(res.Message)}` : ''));
|
checkTreeData.value = [];
|
}
|
return isGetSuccess;
|
} else {
|
checkTreeData.value = props.treeData;
|
}
|
|
if (props.filterCheckedKeys) {
|
const checkedKeys = props.filterCheckedKeys(checkTreeData.value);
|
|
nextTick(() => {
|
treeRef.value.setCheckedKeys(checkedKeys);
|
});
|
}
|
};
|
|
const submitCheckedKeys = async (...args) => {
|
const res = await props.submitCheckedApi(...args);
|
if (res?.Code === 0) {
|
const resData = res.Data;
|
if (props.showTip) {
|
if (resData) {
|
ElMessage.success(props.tip.success);
|
} else {
|
ElMessage.info(props.tip.unModified);
|
}
|
}
|
|
return !!resData;
|
} else {
|
if (props.showTip) {
|
ElMessage.error(props.tip.unModified + (res?.Message ? `,${JSON.stringify(res.Message)}` : ''));
|
}
|
|
return false;
|
}
|
};
|
|
const resetTree = () => {
|
filterText.value = '';
|
treeRef.value.setCheckedKeys([]);
|
};
|
|
defineExpose({
|
treeRef,
|
getTreeData,
|
submitCheckedKeys,
|
resetTree,
|
});
|
</script>
|
<style scoped lang="scss">
|
// 隐藏 checkbox
|
:deep(.el-tree-node_hide-checkbox) {
|
> .el-tree-node__content {
|
> .el-checkbox {
|
display: none;
|
}
|
}
|
}
|
</style>
|