Răsfoiți Sursa

feat: directory tree

Casper Dai 2 ani în urmă
părinte
comite
15365ce3a1

+ 40 - 0
src/components/tree/DirectoryTree/api.js

@@ -0,0 +1,40 @@
+import { tenantRequest } from '@/utils/request'
+import {
+  add,
+  update,
+  messageSend,
+  addTenant,
+  addTenantAndOrg
+} from '@/api/base'
+
+export function getSourceTree () {
+  return tenantRequest({
+    url: '/minio-data/sourceTree/detail',
+    method: 'GET',
+    params: addTenant({})
+  })
+}
+
+export function addTreeNode (data) {
+  return add({
+    url: '/minio-data/sourceTree',
+    method: 'POST',
+    data: addTenantAndOrg(data)
+  }, tenantRequest)
+}
+
+export function deleteTreeNode ({ id }) {
+  return messageSend({
+    url: '/minio-data/sourceTree/delete',
+    method: 'POST',
+    data: [id]
+  }, '删除')
+}
+
+export function updateTreeNodeName (data) {
+  return update({
+    url: '/minio-data/sourceTree',
+    method: 'PUT',
+    data
+  })
+}

+ 145 - 34
src/components/tree/DirectoryTree/index.vue

@@ -1,14 +1,23 @@
 <template>
-  <div class="l-flex--col c-sidebar">
-    <div class="l-flex__none">11</div>
-    <div class="l-flex__fill u-overflow-y--auto">
+  <div class="l-flex--col c-directory-tree">
+    <div class="l-flex__none l-flex--row c-sibling-item--v u-line-height">
+      <i
+        class="l-flex__none c-sibling-item el-icon-circle-plus-outline u-font-size--lg u-color--blue u-bold has-active"
+        @click.stop="onAddRoot"
+      />
+      <div class="l-flex__auto c-sibling-item near u-font-size--md u-ellipsis">
+        {{ title }}
+      </div>
+    </div>
+    <div class="l-flex__fill c-sibling-item--v u-overflow-y--auto">
       <el-tree
+        ref="treeRef"
         :data="groups"
-        node-key="path"
-        :current-node-key="groups[0].path"
-        :expand-on-click-node="false"
+        :props="defaultProps"
+        node-key="id"
         accordion
         highlight-current
+        @node-click="closeContentMenu"
         @node-contextmenu="onRightClick"
       />
     </div>
@@ -20,63 +29,103 @@
     >
       <div
         class="l-flex--row c-contentmenu__item has-active"
-        @click="onAddNode"
+        @click="onEditNode"
+      >
+        <i class="c-sibling-item el-icon-edit" /><span class="c-sibling-item">重命名</span>
+      </div>
+      <div
+        class="l-flex--row c-contentmenu__item has-active"
+        @click="onAddChildNode"
       >
-        <i class="c-sibling-item el-icon-circle-plus-outline" /><span class="c-sibling-item">增加节点</span>
+        <i class="c-sibling-item el-icon-circle-plus-outline" /><span class="c-sibling-item">新增子节点</span>
       </div>
       <div
         class="l-flex--row c-contentmenu__item has-active"
         @click="onDeleteNode"
       >
-        <i class="c-sibling-item el-icon-remove-outline" /><span class="c-sibling-item">删除节点</span>
+        <i class="c-sibling-item el-icon-remove-outline" /><span class="c-sibling-item">删除</span>
       </div>
     </el-card>
+    <confirm-dialog
+      ref="nodeDialog"
+      :title="dialogTitle"
+      @confirm="onSubmitNode"
+    >
+      <div class="c-grid-form u-align-self--center">
+        <span class="c-grid-form__label u-required">名称</span>
+        <el-input
+          v-model.trim="node.name"
+          placeholder="最多30个字符"
+          maxlength="30"
+          clearable
+        />
+      </div>
+    </confirm-dialog>
   </div>
 </template>
 
 <script>
+import {
+  getSourceTree,
+  addTreeNode,
+  deleteTreeNode,
+  updateTreeNodeName
+} from './api'
+
 export default {
   name: 'DirectoryTree',
   props: {
-    size: {
+    title: {
       type: String,
-      default: ''
+      default: '目录'
     }
   },
   data () {
     return {
       menuVisible: false,
-      groups: [{
-        path: '/msr',
-        label: '资源分类',
-        children: [
-          {
-            path: '/msr1',
-            label: '资源分类1',
-            children: []
-          },
-          {
-            path: '/msr2',
-            label: '资源分类1',
-            children: []
-          }
-        ]
-      }]
+      groups: [],
+      defaultProps: {
+        label: 'name',
+        children: 'childrenNode'
+      },
+      node: {}
     }
   },
+  computed: {
+    dialogTitle () {
+      const { id, parentId } = this.node
+      return parentId && parentId !== '0'
+        ? '新增下级节点'
+        : id
+          ? '重命名'
+          : '新增一级节点'
+    }
+  },
+  created () {
+    this.getSource()
+  },
   beforeDestroy () {
     this.closeContentMenu()
   },
   methods: {
+    getSource () {
+      return getSourceTree().then(({ data }) => {
+        console.log('groups', data)
+        this.groups = data
+      })
+    },
     onRightClick (event, data, vnode, node) {
-      console.log(event, data, vnode, node)
+      console.log('right_click', event, data, vnode, node)
       this.$selectedNode = data
+      this.$selectedVNode = vnode
+      this.$selectedComponent = node
       this.$refs.card.$el.style.left = `${event.clientX}px`
       this.$refs.card.$el.style.top = `${event.clientY}px`
       if (!this.menuVisible) {
         this.menuVisible = true
         document.addEventListener('click', this.closeContentMenu)
       }
+      this.$refs.treeRef.setCurrentKey(this.$selectedNode.id)
     },
     closeContentMenu () {
       if (this.menuVisible) {
@@ -84,20 +133,82 @@ export default {
         document.removeEventListener('click', this.closeContentMenu)
       }
     },
-    onAddNode () {
-      this.$selectedNode.children.push({
-        path: '/msr3',
-        label: '资源分类1'
-      })
+    onAddRoot () {
+      this.node = { parentId: '0', name: '' }
+      this.$refs.nodeDialog.show()
+    },
+    onAddChildNode () {
+      this.node = { parentId: this.$selectedNode.id, name: '' }
+      this.$refs.nodeDialog.show()
+      this.closeContentMenu()
+    },
+    onEditNode () {
+      this.node = { id: this.$selectedNode.id, name: this.$selectedNode.name }
+      this.$refs.nodeDialog.show()
+      this.closeContentMenu()
+    },
+    onSubmitNode (done) {
+      if (!this.node.name) {
+        this.$message({
+          type: 'warning',
+          message: '请填写节点名称'
+        })
+        return
+      }
+      if (this.node.id) {
+        updateTreeNodeName(this.node).then(() => {
+          done()
+          this.$selectedNode.name = this.node.name
+        })
+      } else {
+        addTreeNode(this.node).then(({ data }) => {
+          done()
+          if (this.node.parentId === '0') {
+            this.$refs.treeRef.append({ id: data, ...this.node })
+          } else {
+            this.$refs.treeRef.append({ id: data, ...this.node }, this.$selectedNode)
+          }
+          if (!this.$selectedVNode.expanded) {
+            this.$selectedComponent.handleExpandIconClick()
+          }
+        })
+      }
     },
     onDeleteNode () {
-      // todo
+      this.menuVisible = false
+      const { name, childrenNode } = this.$selectedNode
+      if (childrenNode.length) {
+        this.$confirm(
+          '删除节点会连带删除所有子节点',
+          `删除${name}`,
+          { type: 'warning' }
+        ).then(this.deleteNode)
+        return
+      }
+      this.$confirm(
+        `删除${name}?`,
+        '操作确认',
+        { type: 'warning' }
+      ).then(this.deleteNode)
+    },
+    deleteNode () {
+      deleteTreeNode(this.$selectedNode).then(() => {
+        this.$refs.treeRef.remove(this.$selectedNode)
+        this.$refs.treeRef.setCurrentKey(null)
+      })
     }
   }
 }
 </script>
 
 <style lang="scss" scoped>
+.c-directory-tree {
+  ::v-deep .el-tree-node__label {
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+}
+
 .c-contentmenu {
   position: fixed;
   width: 150px;