纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

SpringBoot mybatis多级树形菜单 SpringBoot mybatis 实现多级树形菜单的代码实例

华大哥   2021-05-06 我要评论
想了解SpringBoot mybatis 实现多级树形菜单的代码实例的相关内容吗华大哥在本文为您仔细讲解SpringBoot mybatis多级树形菜单的相关知识和一些Code实例欢迎阅读和指正我们先划重点:SpringBoot,mybatis多级树形菜单,SpringBoot,mybatis树形菜单下面大家一起来学习吧

一、前言

iview-admin中提供了 v-org-tree 这么一个vue组件可以实现树形菜单下面小编来提供一下在element-ui中的使用教程(项目见:https://github.com/lison16/v-org-tree)

小编集成了el-dropdown下拉菜单(鼠标左击显示菜单)和右击自定义菜单两种方式效果图如下:

二、使用教程

(1)安装依赖

npm install clipboard
npm install v-click-outside-x
npm install v-org-tree

(2)引入组件

在main.js文件中引入

import TreeTable from 'tree-table-vue'
import VOrgTree from 'v-org-tree'

(3)引入部分js工具方法

在项目目录下 -> src -> directive文件夹中引入如下4个js文件

clipboard.js

import Clipboard from 'clipboard'
export default {
  bind: (el, binding) => {
    const clipboard = new Clipboard(el, {
      text: () => binding.value.value
    })
    el.__success_callback__ = binding.value.success
    el.__error_callback__ = binding.value.error
    clipboard.on('success', e => {
      const callback = el.__success_callback__
      callback && callback(e)
    })
    clipboard.on('error', e => {
      const callback = el.__error_callback__
      callback && callback(e)
    })
    el.__clipboard__ = clipboard
  },
  update: (el, binding) => {
    el.__clipboard__.text = () => binding.value.value
    el.__success_callback__ = binding.value.success
    el.__error_callback__ = binding.value.error
  },
  unbind: (el, binding) => {
    delete el.__success_callback__
    delete el.__error_callback__
    el.__clipboard__.destroy()
    delete el.__clipboard__
  }
}

draggable.js

import { on } from '@/libs/tools'
export default {
  inserted: (el, binding, vnode) => {
    const triggerDom = document.querySelector(binding.value.trigger)
    triggerDom.style.cursor = 'move'
    const bodyDom = document.querySelector(binding.value.body)
    let pageX = 0
    let pageY = 0
    let transformX = 0
    let transformY = 0
    let canMove = false
    const handleMousedown = e => {
      let transform = /\(.*\)/.exec(bodyDom.style.transform)
      if (transform) {
        transform = transform[0].slice(1, transform[0].length - 1)
        const splitxy = transform.split('px, ')
        transformX = parseFloat(splitxy[0])
        transformY = parseFloat(splitxy[1].split('px')[0])
      }
      pageX = e.pageX
      pageY = e.pageY
      canMove = true
    }
    const handleMousemove = e => {
      const xOffset = e.pageX - pageX + transformX
      const yOffset = e.pageY - pageY + transformY
      if (canMove) bodyDom.style.transform = `translate(${xOffset}px, ${yOffset}px)`
    }
    const handleMouseup = e => {
      canMove = false
    }
    on(triggerDom, 'mousedown', handleMousedown)
    on(document, 'mousemove', handleMousemove)
    on(document, 'mouseup', handleMouseup)
  },
  update: (el, binding, vnode) => {
    if (!binding.value.recover) return
    const bodyDom = document.querySelector(binding.value.body)
    bodyDom.style.transform = ''
  }
}

directives.js

import draggable from './module/draggable'
import clipboard from './module/clipboard'
 
const directives = {
  draggable,
  clipboard
}
 
export default directives

index.js

import directive from './directives'
 
const importDirective = Vue => {
  /**
   * 拖拽指令 v-draggable="options"
   * options = {
   *  trigger: /这里传入作为拖拽触发器的CSS选择器/,
   *  body:    /这里传入需要移动容器的CSS选择器/,
   *  recover: /拖动结束之后是否恢复到原来的位置/
   * }
   */
  Vue.directive('draggable', directive.draggable)
  /**
   * clipboard指令 v-draggable="options"
   * options = {
   *  value:    /在输入框中使用v-model绑定的值/,
   *  success:  /复制成功后的回调/,
   *  error:    /复制失败后的回调/
   * }
   */
  Vue.directive('clipboard', directive.clipboard)
}
 
export default importDirective

(4)正式使用v-org-tree组件

 在所要使用的地方新增如下几个文件比如我要写在user-group文件夹中

项目\src\components\org-view下面建立二个文件:

index.js

import OrgView from './org-view.vue'
export default OrgView

org-view.vue

<template>
  <div
    ref="dragWrapper"
    class="org-tree-drag-wrapper"
    @mousedown="mousedownView"
    @contextmenu="handleDocumentContextmenu"
  >
    <div class="org-tree-wrapper" :style="orgTreeStyle">
      <v-org-tree
        v-if="data"
        :data="data"
        :node-render="nodeRender"
        :expand-all="true"
        @on-node-click="handleNodeClick"
        collapsable
      ></v-org-tree>
    </div>
  </div>
</template>
 
<script>
import { on, off } from '@/directive/module/tools'
 
export default {
  name: 'OrgView',
  props: {
    zoomHandled: {
      type: Number,
      default: 1
    },
    data: Object,
    menuList: {
      type: Array,
      default: function () {
        return [
          {
            key: 'edit',
            label: '编辑公司'
          },
          {
            key: 'detail',
            label: '查看公司'
          },
          {
            key: 'add',
            label: '新增子公司'
          },
          {
            key: 'delete',
            label: '删除公司'
          }
        ]
      }
    }
  },
  data () {
    return {
      currentContextMenuId: '',
      orgTreeOffsetLeft: 0,
      orgTreeOffsetTop: 0,
      initPageX: 0,
      initPageY: 0,
      oldMarginLeft: 0,
      oldMarginTop: 0,
      canMove: false
    }
  },
  computed: {
    orgTreeStyle () {
      return {
        transform: `translate(-50%, -50%) scale(${this.zoomHandled}, ${
          this.zoomHandled
        })`,
        marginLeft: `${this.orgTreeOffsetLeft}px`,
        marginTop: `${this.orgTreeOffsetTop}px`
      }
    }
  },
  methods: {
    handleNodeClick (e, data, expand) {
      expand()
    },
    closeMenu () {
      this.currentContextMenuId = ''
    },
    getBgColor (data) {
      return this.currentContextMenuId === data.id
        ? data.isRoot
          ? '#0d7fe8'
          : '#5d6c7b'
        : ''
    },
    nodeRender (h, data) {
      return (
        <div
          class={[
            'custom-org-node',
            data.children && data.children.length ? 'has-children-label' : ''
          ]}
          on-mousedown={event => event.stopPropagation()}
          on-contextmenu={this.contextmenu.bind(this, data)}
        >
          {data.label}
          <dropdown
            trigger="custom"
            class="context-menu"
            visible={this.currentContextMenuId === data.id}
            nativeOn-click={this.handleDropdownClick}
            on-on-click={this.handleContextMenuClick.bind(this, data)}
            style={{
              transform: `scale(${1 / this.zoomHandled}, ${1 /
                this.zoomHandled})`
            }}
            v-click-outside={this.closeMenu}
          >
            <dropdown-menu slot="list">
              {this.menuList.map(item => {
                return (
                  <dropdown-item name={item.key}>{item.label}</dropdown-item>
                )
              })}
            </dropdown-menu>
          </dropdown>
        </div>
      )
    },
    contextmenu (data, $event) {
      const event = $event || window.event
      event.preventDefault
        ? event.preventDefault()
        : (event.returnValue = false)
      this.currentContextMenuId = data.id
    },
    setDepartmentData (data) {
      data.isRoot = true
      this.departmentData = data
    },
    mousedownView (event) {
      this.canMove = true
      this.initPageX = event.pageX
      this.initPageY = event.pageY
      this.oldMarginLeft = this.orgTreeOffsetLeft
      this.oldMarginTop = this.orgTreeOffsetTop
      on(document, 'mousemove', this.mousemoveView)
      on(document, 'mouseup', this.mouseupView)
    },
    mousemoveView (event) {
      if (!this.canMove) return
      const { pageX, pageY } = event
      this.orgTreeOffsetLeft = this.oldMarginLeft + pageX - this.initPageX
      this.orgTreeOffsetTop = this.oldMarginTop + pageY - this.initPageY
    },
    mouseupView () {
      this.canMove = false
      off(document, 'mousemove', this.mousemoveView)
      off(document, 'mouseup', this.mouseupView)
    },
    handleDropdownClick (event) {
      event.stopPropagation()
    },
    handleDocumentContextmenu () {
      this.canMove = false
    },
    handleContextMenuClick (data, key) {
      this.$emit('on-menu-click', { data, key })
    }
  },
  mounted () {
    on(document, 'contextmenu', this.handleDocumentContextmenu)
  },
  beforeDestroy () {
    off(document, 'contextmenu', this.handleDocumentContextmenu)
  }
}
</script>
 
<style>
</style>

项目\src\components\zoom-controller下面建立二个文件:

index.js

import ZoomController from './zoom-controller'
export default ZoomController

zoom-controller.vue

<template>
  <div class="zoom-wrapper">
    <button class="zoom-button" @click="scale('down')">
      <Icon type="md-remove" :size="14" color="#fff"/>
    </button>
    <span class="zoom-number">{{ value }}%</span>
    <button class="zoom-button" @click="scale('up')">
      <Icon type="md-add" :size="14" color="#fff"/>
    </button>
  </div>
</template>
 
<script>
export default {
  name: 'ZoomController',
  props: {
    value: {
      type: Number,
      default: 100
    },
    step: {
      type: Number,
      default: 20
    },
    min: {
      type: Number,
      default: 10
    },
    max: {
      type: Number,
      default: 200
    }
  },
  methods: {
    scale (type) {
      const zoom = this.value + (type === 'down' ? -this.step : this.step)
      if (
        (zoom < this.min && type === 'down') ||
        (zoom > this.max && type === 'up')
      ) {
        return
      }
      this.$emit('input', zoom)
    }
  }
}
</script>
 
<style lang="less">
.trans(@duration) {
  transition: ~"all @{duration} ease-in";
}
.zoom-wrapper {
  .zoom-button {
    width: 20px;
    height: 20px;
    line-height: 10px;
    border-radius: 50%;
    background: rgba(157, 162, 172, 1);
    box-shadow: 0px 2px 8px 0px rgba(218, 220, 223, 0.7);
    border: none;
    cursor: pointer;
    outline: none;
    &:active {
      box-shadow: 0px 0px 2px 2px rgba(218, 220, 223, 0.2) inset;
    }
    .trans(0.1s);
    &:hover {
      background: #1890ff;
      .trans(0.1s);
    }
  }
  .zoom-number {
    color: #657180;
    padding: 0 8px;
    display: inline-block;
    width: 46px;
    text-align: center;
  }
}
</style>

 项目\src\view下面建立org.vue文件

<template>
  <Card shadow style="height: 100%;width: 100%;overflow:hidden">
    <div class="department-outer">
      <div class="zoom-box">
        <zoom-controller v-model="zoom" :min="20" :max="200"></zoom-controller>
      </div>
      <div class="view-box">
        <org-view
            v-if="data"
            :data="data"
            :zoom-handled="zoomHandled"
            :menuList="menuList"
            @on-menu-click="handleMenuClick"
        ></org-view>
      </div>
    </div>
  </Card>
</template>
 
<script>
import { orgList } from '@/api/org'
import { layerDialog } from '@/libs/Diaglog'
import './org.less'
 
const OrgView = Vue.component('OrgView', function (resolve) {
  require(['/user/org-view'], resolve)
})
const ZoomController = Vue.component('ZoomController', function (resolve) {
  require(['/user/zoom-controller'], resolve)
})
export default {
  name: 'org_tree_page',
  components: {
    OrgView,
    ZoomController
  },
  data () {
    return {
      data: null,
      zoom: 100,
      menuList: [
        {
          key: 'add',
          label: '新增子公司'
        },
        {
          key: 'edit',
          label: '编辑公司'
        },
        {
          key: 'delete',
          label: '删除公司'
        }
      ]
    }
  },
  computed: {
    zoomHandled () {
      return this.zoom / 100
    }
  },
  methods: {
    setDepartmentData (data) {
      data.isRoot = true
      return data
    },
    handleMenuClick ({ data, key }) {
      switch (key) {
        case 'add':
        case 'edit':
          console.log(data)
          this.showDialog(data, key)
          break
        case 'delete':
          break
      }
    },
    showDialog (data, key) {
      data.key = key
      const option = {
        id: key + 'SaveDialog',
        title: this.$i18n.t(key),
        width: '600px',
        height: '550px',
        url: '/api/org/' + Qs.stringify(data, { arrayFormat: 'brackets' })
      }
      layerDialog(option)
    },
    getDepartmentData () {
      const entity = {}
      const levels = '0,1,2,3,4,5,6'
      entity.status = 1
      getOrgList(entity, 1, 20, levels).then(result => {
        if (result.data.code === 10000) {
          let len = 0
          const list = result.data.data.list
          if (list) {
            len = list.length
          }
          var data = { id: 0, label: '阿里巴巴集团', level: 0 }
          if (len > 0) {
            data.children = this.formatData(list, 1, 0)
          }
          this.data = data
        }
      })
    },
    formatData (list, level, pid, pname) {
      const childrenData = []
      for (let i = 0; i < list.length; i++) {
        const data = {}
        const item = list[i]
        if (level === item.level) {
          data.id = item.id
          data.label = item.name
          data.parentName = pname
          data.level = item.level
          data.children = this.formatData(list, level + 1, item.id, item.name)
          childrenData.push(data)
        }
      }
      return childrenData
    }
  },
  mounted () {
    this.getDepartmentData()
  }
}
</script>

接口中核心代码:

List<Station> stations = stationService.listByEntity(station,levelList);
        List<StationVo> stationVos = new ArrayList();
        for(Station s : stations) {
            StationVo vo = new StationVo();
            vo.setId(s.getId());
            vo.setLevel(s.getLevel());
            vo.setName(s.getName());
            stationVos.add(vo);
        }

数据库中四个字段

mybatis  配置:

返回的json如下:

{
  "data" : {
    "page" : 1,
    "pageSize" : 20,
    "total" : 6,
    "pages" : 1,
    "list" : [ {
      "id" : 1,
      "name" : "天猫科技服务有限公司",
      "level" : 1,
      "status" : 1,
    }, {
      "id" : 2,
      "name" : "淘宝技术服务有限公司",
      "level" : 1,
      "status" : 1,
    }, {
      "id" : 3,
      "name" : "聚划算科技服务有限公司",
      "level" : 1,
      "status" : 1,
    }, {
      "id" : 4,
      "name" : "菜鸟金服",
      "level" : 2,
      "status" : 1,
    }, {
      "id" : 5,
      "name" : "黑鸟网络",
      "level" : 3,
      "status" : 1,
    }, {
      "id" : 6,
      "name" : "白鸟 网络",
      "level" : 3,
      "status" : 1,
    } ]
  },
  "message" : "获取成功",
  "code" : 200
}

相关文章

猜您喜欢

网友评论

Copyright 2020 www.fresh-weather.com 【世纪下载站】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式