Django + Vue.js完成文件目录树的显示

导读

最近在做一个接口自动化测试平台,需要前端展示当前服务器上的测试用例,自然而然的想到展示成一个文件目录树的形状,这样不管浏览、添加、删除等操作都可以比较方便的实现,也比较方便浏览。( 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
})
}

划重点:

  1. 首先这一段加下一段代码是在参考资料上加工的,致敬!
  2. clonedeep需要安装,可以自行度娘。主要是防止把原来的对象属性改了。
  3. 在上述代码块中定义了元素的type和icon功能,主要是为了后续展示的时候根据不同类型展示不同的图标。
  4. 通过上述函数就把文件都归拢到了相关的文件夹下面,用上了我们定义的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)
}

划重点:

  1. 文件夹处理跟文件处理差不多,主要是找出每个文件夹的children即可
  2. 上述函数用到了递归函数,从handle(0)开始,因为我们的第一个文件夹的id是0.

通过上述两个函数我们就把后台传过来的字典列表处理成了符合el-tree可以渲染的数据。

总结

以上展示了如何通过后台传递的数据展示文件目录,后边还会继续给大家展示如何显示文件的内容以及相关操作,敬请期待!

参考链接:
链接: https://blog.csdn.net/qq_40547061/article/details/106287343


版权声明:本文为hhhhh11原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。