效果图:
一、渲染目录
1.1添加目录树标签
<div class="box">
<a-directory-tree
v-model:expandedKeys="expandedKeys"
v-model:selectedKeys="selectedKeys"
multiple
:tree-data="treeData"
style="background-color: #e5e5e5;"
>
</a-directory-tree>
</div>
1.2调用接口查询并渲染目录
const expandedKeys = ref([]);
const selectedKeys = ref([]);
const treeData = ref([])
//获取目录信息
const getDirData = async () => {
try {
const res = await getAllDir({id: 2});//这儿的id是整个目录的id,根据这个id获取全部目录数据
// 解析目录数据,确保每个目录对象有'title'和'key'属性
const directories = res.data.data.directoryVOS.map(dir => ({
title: dir.directoryName,
key: String(dir.id), // 将id转换为字符串作为key
children: dir.directoryVOS.map(subDir => ({ // 遍历一级目录的子目录(二级目录)
title: subDir.directoryName,
key: String(subDir.id),
children: subDir.directoryVOS.map(subSubDir => ({ // 遍历二级目录的子目录(三级目录)
title: subSubDir.directoryName,
key: String(subSubDir.id),
isLeaf: true // 标记为叶子节点
})),
})),
}));
// 更新treeData
treeData.value = directories;
// 输出获取到的目录信息
console.log(res, '------');
} catch (error) {
console.error('Error fetching directory data:', error);
}
};
// 调用函数以获取目录信息,这里可以根据实际情况传递id值
getDirData();
注意:目录数据结构可根据打印的数据结构来修改,也可自行遍历添加四级五级获取目录数据逻辑
效果图就是上面的目录数据
二、添加一级目录
2.1增添新增按钮
<div class="box">
<div style="margin-bottom: 10px;margin-top: 10px;text-align: center;">
<a-button style="background-color: #e5e5e5;border: none;color: #000;" @click="addDir">数据资产表目录<PlusOutlined /></a-button>
</div>
<a-directory-tree
v-model:expandedKeys="expandedKeys"
v-model:selectedKeys="selectedKeys"
multiple
:tree-data="treeData"
style="background-color: #e5e5e5;"
>
</a-directory-tree>
</div>
2.2组件中加入新增一级目录模态框
<!-- 新增一级目录 -->
<a-modal v-model:open="isOpen" title="新增一级目录" style="text-align: center;">
<a-form :v-model="DirData" :rules="rules">
<a-form-item label="目录名称" name="directoryName" :rules="[{ required: true, message: '请输入目录名称' }]">
<a-input v-model:value="DirData.directoryName"></a-input>
</a-form-item>
</a-form>
<template #footer>
<div class="modal-buttons">
<a-button @click="cancelForm">取消</a-button>
<a-button @click="createDir" type="primary">确认</a-button>
</div>
</template>
</a-modal>
定义isOpen、DirData
const isOpen = ref(false);
const DirData = ref([])
2.3打开模态框并实现新增一级目录
//新增目录
const addDir = () =>{
isOpen.value = true
}
//取消模态框
const cancelForm = () => {
isOpen.value = false;
}
// 新增一级目录
const createDir = async () => {
const directoryData = {
directoryName: DirData.value.directoryName,
superId:2,
};
const res = await createDirectory(directoryData);
console.log('======', res);
message.success('新增一级目录成功!')
isOpen.value = false
getDirData();
// 更新treeData
const newDirectory = res.data; // 假设返回的数据就是新创建的目录对象
treeData.value.push(newDirectory); // 将新目录添加到treeData中
};
三、添加菜单栏按钮和搜索框
3.1添加按钮
<div class="box">
<div style="margin-bottom: 10px;margin-top: 10px;text-align: center;">
<a-button style="background-color: #e5e5e5;border: none;color: #000;" @click="addDir">数据资产表目录<PlusOutlined /></a-button>
</div>
<a-input-search v-model:value="searchValue" style="margin-bottom: 8px" placeholder="按数据资产表名称或目录名称查询" />
<!-- 功能菜单 -->
<div :style="menuStyle" v-if="NodeTreeItem">
<a-space>
<div>菜单</div>
<div>
<a-button title="添加二级目录" size="small" @click="addDirNext" ><PlusOutlined /></a-button>
<a-button title="编辑" size="small" @click="editDir" ><EditOutlined /></a-button>
<a-button title="删除" size="small" @click="showDeleteModal" ><DeleteOutlined :style="{ color: 'red'}"/></a-button>
<a-button title="添加三级目录" size="small" @click="addDirThird"><PlusCircleOutlined /></a-button>
</div>
</a-space>
</div>
<a-directory-tree
v-model:expandedKeys="expandedKeys"
v-model:selectedKeys="selectedKeys"
multiple
:tree-data="treeData"
style="background-color: #e5e5e5;"
>
</a-directory-tree>
</div>
定义参数
// 右键单击节点时触发
const NodeTreeItem = ref([]);
const menuStyle = ref('');
3.2引入图标
import { CaretRightOutlined,PlusOutlined,PlusCircleOutlined, EditOutlined, DeleteOutlined} from '@ant-design/icons-vue'
如无法引入显示运行代码:
npm install --save @ant-design/icons-vue或
pnpm install --save @ant-design/icons-vue
四、添加各个按钮模态框
4.1添加二级、三级、编辑模态框组件
<!-- 新增二级目录 -->
<a-modal v-model:open="isOpenNext" title="新增下级目录" style="text-align: center;">
<a-form :v-model="DirDataNext" :rules="rules">
<a-form-item label="目录名称" name="directoryName" :rules="[{ required: true, message: '请输入目录名称' }]">
<a-input v-model:value="DirDataNext.directoryName"></a-input>
</a-form-item>
</a-form>
<template #footer>
<div class="modal-buttons">
<a-button @click="cancelFormNext">取消</a-button>
<a-button @click="createDirNext" type="primary">确认</a-button>
</div>
</template>
</a-modal>
<!-- 新增三级目录 -->
<a-modal v-model:open="isOpenThird" title="新增三级目录" style="text-align: center;">
<a-form :v-model="DirDataThird" :rules="rules">
<a-form-item label="目录名称" name="directoryName" :rules="[{ required: true, message: '请输入目录名称' }]">
<a-input v-model:value="DirDataThird.directoryName"></a-input>
</a-form-item>
</a-form>
<template #footer>
<div class="modal-buttons">
<a-button @click="cancelFormThird">取消</a-button>
<a-button @click="createDirThird" type="primary">确认</a-button>
</div>
</template>
</a-modal>
<!-- 编辑目录 -->
<a-modal v-model:open="isOpenEdit" title="编辑目录" style="text-align: center;">
<a-form :v-model="DirDataEdit" :rules="rules">
<a-form-item label="目录名称" name="directoryName" :rules="[{ required: true, message: '请输入目录名称' }]">
<a-input v-model:value="DirDataEdit.directoryName"></a-input>
</a-form-item>
</a-form>
<template #footer>
<div class="modal-buttons">
<a-button @click="cancelFormEdit">取消</a-button>
<a-button @click="EditDir" type="primary">保存</a-button>
</div>
</template>
</a-modal>
定义模态框各参数
const isOpenNext = ref(false);
const isOpenEdit = ref(false);
const isOpenThird = ref(false)
const DirDataNext = ref([])
const DirDataThird = ref([])
const DirDataEdit = ref([])
4.2删除目录模态框
<div class="box">
<div style="margin-bottom: 10px;margin-top: 10px;text-align: center;">
<a-button style="background-color: #e5e5e5;border: none;color: #000;" @click="addDir">数据资产表目录<PlusOutlined /></a-button>
</div>
<a-input-search v-model:value="searchValue" style="margin-bottom: 8px" placeholder="按数据资产表名称或目录名称查询" />
<!-- 功能菜单 -->
<div :style="menuStyle" v-if="NodeTreeItem">
<a-space>
<div>菜单</div>
<div>
<a-button title="添加二级目录" size="small" @click="addDirNext" ><PlusOutlined /></a-button>
<a-button title="编辑" size="small" @click="editDir" ><EditOutlined /></a-button>
<a-button title="删除" size="small" @click="showDeleteModal" ><DeleteOutlined :style="{ color: 'red'}"/></a-button>
<a-button title="添加三级目录" size="small" @click="addDirThird"><PlusCircleOutlined /></a-button>
</div>
<a-modal v-model:visible="deleteModalVisible" style="text-align: center;">
<p style="font-size: 20px;margin-top: 20px;"><ExclamationCircleOutlined :style="{ color: 'red'}"/> 确定要删除该目录吗?</p>
<template #footer>
<div style="display: flex; justify-content: center; margin-top: 20px;">
<a-button @click="handleDelete" type="primary" style="margin-right: 10px;">确认</a-button>
<a-button @click="cancelDelete">取消</a-button>
</div>
</template>
</a-modal>
</a-space>
</div>
<a-directory-tree
v-model:expandedKeys="expandedKeys"
v-model:selectedKeys="selectedKeys"
multiple
:tree-data="treeData"
style="background-color: #e5e5e5;"
>
</a-directory-tree>
</div>
定义参数
const deleteModalVisible = ref(false);
引入图标
import { CaretRightOutlined,PlusOutlined,PlusCircleOutlined, EditOutlined, DeleteOutlined,ExclamationCircleOutlined} from '@ant-design/icons-vue'
4.3点击按钮打开模态框
//新增二级目录
const addDirNext = () =>{
isOpenNext.value = true
DirDataNext.value = {}
}
//取消模态框
const cancelFormNext = () => {
isOpenNext.value = false;
}
// 新增三级目录
const addDirThird = () => {
isOpenThird.value = true;
DirDataThird.value = {};
};
//取消模态框(三级目录)
const cancelFormThird = () => {
isOpenThird.value = false;
};
// 编辑目录
const editDir = () => {
// 填充编辑表单数据
DirDataEdit.value.directoryName = NodeTreeItem.value.title; // 使用右键点击的节点的名称填充编辑表单
// 打开二级目录模态框
isOpenEdit.value = true;
};
//取消模态框
const cancelFormEdit = () => {
isOpenEdit.value = false;
}
//删除目录
const showDeleteModal = () => {
deleteModalVisible.value = true;
};
const cancelDelete = () => {
// 取消删除操作,关闭模态框
deleteModalVisible.value = false;
};
五、目录树添加右键点击事件
5.1目录树添加@rightClick="onRightClick"
<a-directory-tree
v-model:expandedKeys="expandedKeys"
v-model:selectedKeys="selectedKeys"
multiple
:tree-data="treeData"
style="background-color: #e5e5e5;"
@rightClick="onRightClick"
>
</a-directory-tree>
5.2实现点击逻辑
const onRightClick = ({ event, node }) => {
const x = event.currentTarget.offsetLeft + event.currentTarget.clientWidth;
const y = event.currentTarget.offsetTop;
NodeTreeItem.value = {
pageX: x,
pageY: y,
id: node.key, // 使用节点的 key 属性作为唯一标识符
title: node.title, // 使用节点的 title 属性作为显示名称
parentOrgId: node.superId || null // 如果有的话,使用节点的父级 ID 属性作为父级组织的标识符
};
// 设置菜单位置和样式
menuStyle.value = `
maxHeight: 40;
textAlign: center;
left: ${x + 4 - 0}px;
top: ${y + 4 - 0}px;
display: flex;
flexDirection: row;
`;
};
注意:该点击事件是右击选中当前目录进行各个功能操作(增加、删除、修改)
六、添加各个功能逻辑
6.1增加、删除、修改
//新增二级目录
const createDirNext = async (directoryName:String, superId:Number) => {
const directoryData = {
// directoryDescription: directoryDescription,..,
directoryName: DirDataNext.value.directoryName,
superId: NodeTreeItem.value.id,
};
const res = await createDirectory(directoryData);
console.log('======', res);
if (res.data.code === 200) {
// 这里可以执行成功后的逻辑,比如提示成功或其他操作
message.success('新增二级目录成功!')
isOpenNext.value = false
getDirData();
} else if (res.data.code === 500) {
// 如果测试失败,提示失败信息
message.error(res.data.msg); // 显示后端返回的错误信息
}
// 更新treeData
const newDirectory = res.data; // 假设返回的数据就是新创建的目录对象
treeData.value.push(newDirectory); // 将新目录添加到treeData中
};
//新增三级目录
const createDirThird = async (directoryName:String, superId:Number) => {
const directoryData = {
directoryName: DirDataThird.value.directoryName,
superId: NodeTreeItem.value.id,
};
const res = await createDirectory(directoryData);
console.log('=====ssss=', res);
if (res.data.code === 200) {
// 这里可以执行成功后的逻辑,比如提示成功或其他操作
message.success('新增三级目录成功!')
isOpenThird.value = false;
getDirData();
} else if (res.data.code === 500) {
// 如果测试失败,提示失败信息
message.error(res.data.msg); // 显示后端返回的错误信息
}
// 更新treeData
const newDirectory = res.data; // 假设返回的数据就是新创建的目录对象
treeData.value.push(newDirectory); // 将新目录添加到treeData中
};
const EditDir = async () => {
const directoryData = {
directoryName: DirDataEdit.value.directoryName,
id: parseInt(NodeTreeItem.value.id), // 将字符串ID转换为数字
};
const res = await updateDirectory(directoryData,directoryData.id);
// console.log(NodeTreeItem.value,'=-=-=-=-=');
message.success('目录修改成功!')
isOpenEdit.value = false
getDirData();
// 更新treeData
const newDirectory = res.data; // 假设返回的数据就是新创建的目录对象
treeData.value.push(newDirectory); // 将新目录添加到treeData中
};
const handleDelete = async() => {
await deleteDirectory(NodeTreeItem.value.id);
deleteModalVisible.value = false
message.success('目录删除成功!')
getDirData()
};
注意:在新增三级目录注意是第四个按钮
6.2查询
6.2.1添加change事件
<a-input-search v-model:value="searchValue" @change="searchDir" style="margin-bottom: 8px" placeholder="按数据资产表名称或目录名称查询" />
定义
const searchValue = ref('');
6.2.2查询逻辑
// 在函数外部声明 enumOptions
const enumOptions = ref([]);
// 处理搜索事件
const searchDir = async () => {
try {
// 调用接口搜索目录数据
const response = await selectDirectoryByName({ name: searchValue.value.trim() });
// 假设您的搜索接口返回的是一个数组,表示搜索结果
const directories = response.data.data;
if (directories && directories.length > 0) {
// 将搜索结果转换为树形结构
const treeData = transformToTreeData(directories);
// 设置展开和选中的节点
expandedKeys.value = getExpandedKeys(treeData);
selectedKeys.value = getSelectedKeys(treeData);
// 更新树形目录数据
enumOptions.value = treeData;
} else {
// 如果未搜索到目录,则清空展开和选中的节点
clearSelection();
}
} catch (error) {
console.error('搜索目录失败:', error);
}
};
// 将搜索结果转换为树形结构
const transformToTreeData = (directories) => {
// 假设您的目录对象中有一个 children 字段,用于存储子目录
return directories.map(dir => ({
title: dir.name,
key: String(dir.id),
children: dir.children ? transformToTreeData(dir.children) : [],
}));
};
// 获取需要展开的节点的 keys
const getExpandedKeys = (treeData) => {
const keys = [];
treeData.forEach(node => {
// 如果节点是搜索结果的直接父节点,则需要展开
if (node.children.length > 0) {
keys.push(node.key);
}
});
return keys;
};
// 获取需要选中的节点的 keys
const getSelectedKeys = (treeData) => {
const keys = [];
treeData.forEach(node => {
// 如果节点是搜索结果的叶子节点,则需要选中
if (node.children.length === 0) {
keys.push(node.key);
}
});
return keys;
};
注意:现在我只有查询到一级目录并定位,二级三级可自行修改实现
!!!各个接口信息自行引入并添加