导读
最近在做一个接口自动化测试平台,需要前端展示当前服务器上的测试用例,自然而然的想到展示成一个文件目录树的形状,这样不管浏览、添加、删除等操作都可以比较方便的实现,也比较方便浏览。( BTW,你是不是觉着我干得东西挺杂的?作为一个测试开发猿不容易啊,且行且珍惜吧,尤其是对我们这一批老猿来说 ? )
好了,不扯别的,直接开撸。
先看看效果:
后台设计
后台其实没有什么特殊的算法,就是将想要展示的目录做一个遍历,存取文件夹列表和文件列表。因为后台用的django框架,所以对python来讲,这个处理小菜一碟。处理完成后保存成如下格式:
Folder:
[
{'name': 'file0-1.txt', 'create_time': '2020-07-27 15:29:03', 'folder_id': 0, 'id': 10000, 'file_content': {'settings': [], 'test_cases': []}, 'file_path': 'E:\\WorkSpace\\Test\\folderexa0/file0-1.txt'},
{'name': 'file1-1.txt', 'create_time': '2020-07-27 15:29:03', 'folder_id': 1, 'id': 10001, 'file_content': {'settings': [], 'test_cases': []}, 'file_path':'E:\\WorkSpace\\Test\\folderexa0\\folder1/file1-1.txt'},
{'name': 'file1-2.txt', 'create_time': '2020-07-27 15:29:03', 'folder_id': 1, 'id': 10002, 'file_content': {'settings': [], 'test_cases': []}, 'file_path': 'E:\\WorkSpace\\Test\\folderexa0\\folder1/file1-2.txt'},
{'name': 'file3-1.txt', 'create_time': '2020-07-27 15:29:03', 'folder_id': 3, 'id': 10003, 'file_content': {'settings': [], 'test_cases': []}, 'file_path': 'E:\\WorkSpace\\Test\\folderexa0\\folder1\\folder3/file3-1.txt'},
{'name': 'file3-2.txt', 'create_time': '2020-07-27 15:29:03', 'folder_id': 3, 'id': 10004, 'file_content': {'settings': [], 'test_cases': []}, 'file_path': 'E:\\WorkSpace\\Test\\folderexa0\\folder1\\folder3/file3-2.txt'},
{'name': 'file2-1.txt', 'create_time': '2020-07-27 15:29:03', 'folder_id': 2, 'id': 10005, 'file_content': {'settings': [], 'test_cases': []}, 'file_path': 'E:\\WorkSpace\\Test\\folderexa0\\folder2/file2-1.txt'},
{'name': 'file2-2.txt', 'create_time': '2020-07-27 15:29:03', 'folder_id': 2, 'id': 10006, 'file_content': {'settings': [], 'test_cases': []}, 'file_path': 'E:\\WorkSpace\\Test\\folderexa0\\folder2/file2-2.txt'},
{'name': 'file2-3.txt', 'create_time': '2020-07-27 15:29:03', 'folder_id': 2, 'id': 10007, 'file_content': {'settings':[], 'test_cases': []}, 'file_path': 'E:\\WorkSpace\\Test\\folderexa0\\folder2/file2-3.txt'}
]
file:
[
{'name': 'folder1', 'create_time': '2020-07-27 15:29:03', 'folder_id': 0, 'id': 1, 'file_path': 'E:\\WorkSpace\\Test\\folderexa0/folder1'},
{'name': 'folder2', 'create_time': '2020-07-27 15:29:03', 'folder_id': 0, 'id': 2, 'file_path': 'E:\\WorkSpace\\Test\\folderexa0/folder2'},
{'name': 'folder3', 'create_time': '2020-07-27 15:29:03', 'folder_id': 1, 'id': 3, 'file_path': 'E:\\WorkSpace\\Test\\folderexa0\\folder1/folder3'}
]
解释一下:列表中每个文件或文件夹都包含几个属性。name是当前对象的名称;时间、文件内容可以不用管,是为了我自己用的;路径主要用于后续文件的打开、存储等(是的,不是用来辅助文件树显示的 ?);最重要的就是id和folder_id,这两个关系到后续前端文件树的展示,id是当前对象的id,folder_id是当前对象所在的文件夹。
python实现这个功能并不难,用os.walk就可以实现,针对不同的文件和文件夹再保存成字典列表的形式就ok了。
最终打包到接口:
getPathTree () {
var _this = this
_this.$axios.get('/getFileTreeList/').then(resp => {
if (resp && resp.status === 200) {
const resps = JSON.parse(JSON.stringify(resp))
this.fileList = resps.data.files
this.folderList = resps.data.folders
......
前端设计
重头戏来了,要展示文件树关键是前端的实现。后台过来的就是两个列表,一个文件列表,一个文件夹列表, 前端我这边用的是element 中的树形组件 el-tree
<el-tree
:data="folderTree"
:default-expand-all="false"
@node-click="handleSelect"
:render-content="renderTree">
</el-tree>
后面就需要我们去组装folderTree这个变量了。首先,在element 中Tree形控件的数据源有一定的格式, 如下所示。每个单元必须要有label属性,如果有自己的菜单必须用chirldre属性。
data: [{
label: '一级 1',
children: [{
label: '二级 1-1',
children: [{
label: '三级 1-1-1'
}]
}]
}, {
label: '一级 2',
children: [{
label: '二级 2-1',
children: [{
label: '三级 2-1-1'
}]
}, {
label: '二级 2-2',
children: [{
label: '三级 2-2-1'
}]
}]
}, {
label: '一级 3',
children: [{
label: '二级 3-1',
children: [{
label: '三级 3-1-1'
}]
}, {
label: '二级 3-2',
children: [{
label: '三级 3-2-1'
}]
}]
}]
因此,我们在处理后台返回的数据的时候,只需要定义好每个元素的这两个属性即可。label已经有了,只需要找出chirldren属性。
第一步:收拾文件
export const handleFile = (folderList, fileList) => {
const folderListCopy= clonedeep(folderList)
const fileListCopy = clonedeep(fileList)
return folderListCopy.map(folderItem => {
const folderId = folderItem.id
let index = fileListCopy.length
while (--index >= 0) {
const fileItem = fileListCopy[index]
if (fileItem.folder_id === folderId) {
const file = fileListCopy.splice(index, 1)[0]
file.label = file.name
file.type = 'file'
fileItem.icon = 'el-icon-notebook-2'
// file.children = putTestCaseIntoSuite(file)
if (folderItem.children) folderItem.children.push(file)
else folderItem.children = [file]
}
}
folderItem.type = 'folder'
folderItem.icon = 'el-icon-folder'
return folderItem
})
}
划重点:
- 首先这一段加下一段代码是在参考资料上加工的,致敬!
- clonedeep需要安装,可以自行度娘。主要是防止把原来的对象属性改了。
- 在上述代码块中定义了元素的type和icon功能,主要是为了后续展示的时候根据不同类型展示不同的图标。
- 通过上述函数就把文件都归拢到了相关的文件夹下面,用上了我们定义的folder_id。
下一步你肯定已经猜到了,需要把文件夹也收拾一遍。
第二步: 收拾文件夹
export const handleFolder = folderList => {
if (!folderList.length) return []
const folderListCopy = clonedeep(folderList)
const handle = id => {
let arr = []
folderListCopy.forEach(folder => {
if (folder.folder_id === id) {
const children = handle(folder.id)
if (folder.children) folder.children = [].concat(folder.children, children)
else folder.children = children
folder.title = folder.name
folder.label = folder.name
arr.push(folder)
}
})
return arr
}
return handle(0)
}
划重点:
- 文件夹处理跟文件处理差不多,主要是找出每个文件夹的children即可
- 上述函数用到了递归函数,从handle(0)开始,因为我们的第一个文件夹的id是0.
通过上述两个函数我们就把后台传过来的字典列表处理成了符合el-tree可以渲染的数据。
总结
以上展示了如何通过后台传递的数据展示文件目录,后边还会继续给大家展示如何显示文件的内容以及相关操作,敬请期待!
参考链接:
链接: https://blog.csdn.net/qq_40547061/article/details/106287343