美文网首页VueRouter
vue-element-template实现权限管理、动态路由、

vue-element-template实现权限管理、动态路由、

作者: jesse28 | 来源:发表于2021-02-11 07:45 被阅读0次

    api地址:https://www.showdoc.com.cn/aoaoe?page_id=5696507784013382
    这些字段做项目时候需要跟后端说这几个字段是必须的。

    顶部是一级菜单,侧边是二级菜单参考链接:https://www.jianshu.com/p/44a9511bda9a

    image.png

    1.首先下载该模板https://gitee.com/PanJiaChen/vue-admin-template

    ├── build                      # 构建相关1
    ├── mock                       # 项目mock 模拟数据
    ├── public                     # 静态资源
    │   │── favicon.ico            # favicon图标
    │   └── index.html             # html模板
    ├── src                        # 源代码
    │   ├── api                    # 所有请求
    │   ├── assets                 # 主题 字体等静态资源
    │   ├── components             # 全局公用组件
    │   ├── icons                  # 项目所有 svg icons
    │   ├── layout                 # 全局 layout
    │   ├── router                 # 路由
    │   ├── store                  # 全局 store管理
    │   ├── styles                 # 全局样式
    │   ├── utils                  # 全局公用方法
    │   ├── views                  # views 所有页面
    │   ├── App.vue                # 入口页面
    │   ├── main.js                # 入口文件 加载组件 初始化等
    │   └── permission.js          # 权限管理
    ├── tests                      # 测试
    ├── .env.xxx                   # 环境变量配置
    ├── .eslintrc.js               # eslint 配置项
    ├── .babelrc                   # babel-loader 配置
    ├── .travis.yml                # 自动化CI配置
    ├── vue.config.js              # vue-cli 配置
    ├── postcss.config.js          # postcss 配置
    └── package.json               # package.json
    

    2.下载好了以后,打开vue.config.js文件注释掉before: require('./mock/mock-server.js'),关闭eslint


    image.png
    image.png

    3.打开router文件夹下的index.js,删除多余的路由,改成这样

    import Vue from 'vue'
    import Router from 'vue-router'
    
    Vue.use(Router)
    
    /* Layout */
    import Layout from '@/layout'
    
    /**
     * Note: sub-menu only appear when route children.length >= 1
     * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
     *
     * hidden: true                   if set true, item will not show in the sidebar(default is false)
     * alwaysShow: true               if set true, will always show the root menu
     *                                if not set alwaysShow, when item has more than one children route,
     *                                it will becomes nested mode, otherwise not show the root menu
     * redirect: noRedirect           if set noRedirect will no redirect in the breadcrumb
     * name:'router-name'             the name is used by <keep-alive> (must set!!!)
     * meta : {
        roles: ['admin','editor']    control the page roles (you can set multiple roles)
        title: 'title'               the name show in sidebar and breadcrumb (recommend set)
        icon: 'svg-name'/'el-icon-x' the icon show in the sidebar
        breadcrumb: false            if set false, the item will hidden in breadcrumb(default is true)
        activeMenu: '/example/list'  if set path, the sidebar will highlight the path you set
      }
     */
    
    /**
     * constantRoutes
     * a base page that does not have permission requirements
     * all roles can be accessed
     */
    export const constantRoutes = [{
            path: '/login',
            component: () => import('@/views/login/index'),
            hidden: true
        },
    
    
        {
            path: '/',
            component: Layout,
            redirect: '/dashboard',
            children: [{
                path: 'dashboard',
                name: 'Dashboard',
                component: () => import('@/views/dashboard/index'),
                meta: { title: 'Dashboard', icon: 'dashboard' }
            }]
        },
    ]
    
    const createRouter = () => new Router({
        // mode: 'history', // require service support
        scrollBehavior: () => ({ y: 0 }),
        routes: constantRoutes
    })
    
    const router = createRouter()
    
    // Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
    export function resetRouter() {
        const newRouter = createRouter()
        router.matcher = newRouter.matcher // reset router
    }
    
    export default router
    
    

    4.删除views文件夹内的form、nested、table、tree文件夹,清空api文件夹内的文件,新建index.js

    5.修改store/modules/user.js内的import { login, logout, getInfo } from '@/api/user',user改成index


    image.png

    6.在vue.config.js配置反向代理


    image.png
    proxy: {
                //配置跨域
                '/api': {
                    target: "http://localhost:8888", //测试服接口地址
                    ws: true,
                    changOrigin: true,
                    pathRewrite: {
                        '^/api': ''
                    }
                }
            }
    

    7.然后在.env.deveplopment文件内 VUE_APP_BASE_API = '/dev-api'改成VUE_APP_BASE_API = '/api',然后,重启项目,否则不生效


    image.png

    8.在api/index.js内把登录接口和获取用户详情和获取动态路由(侧边栏)接口配置好

    import request from '@/utils/request'
    //登录接口
    export function login(data) {
        return request({
            url: '/admin/api/login',
            method: 'post',
            data
        })
    }
    // 获取用户详情
    export function getInfo(data) {
        return request({
            url: '/admin/api/boss/detail',
            method: 'post',
            data
        })
    }
    // 动态路由
    export function DongtRouter() {
        return request({
            url: `/aoaoe/api/getMoveRouter`,
            method: 'get',
        })
    }
    
    
    

    9.修改store/modules/user.js内的import { login, logout, getInfo } from '@/api/index' 改成 import { login, DongtRouter, getInfo } from '@/api/index'

    10.修改src/utils/request.js中的config.headers['X-Token'] = getToken(),把 X-Token改成后端需要的key值,这里根据实际情况需要改成token,config.headers['token'] = getToken()


    image.png
    
    if (res.code !== 200) {
                Message({
                    message: res.message || 'Error',
                    type: 'error',
                    duration: 5 * 1000
                })
    
                // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
                if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
                    // to re-login
                    MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
                        confirmButtonText: 'Re-Login',
                        cancelButtonText: 'Cancel',
                        type: 'warning'
                    }).then(() => {
                        store.dispatch('user/resetToken').then(() => {
                            location.reload()
                        })
                    })
                }
                return Promise.reject(new Error(res.message || 'Error'))
            } else {
                return res
            }
    
    

    上面👆这段代码,根据实际情况改,主要就是修改code值,如果,后端返回的code成功状态值是200,那么这里就改成200。if (res.code === 50008 || res.code === 50012 || res.code === 50014)这里也根据后端返回的code按照实际情况来改,目前我没有动。

    image.png

    重点部分:开始了!!!

    11.接下来,打开views/login/index.vue,注释掉loginRules内的校验,你也可以根据实际情况来自定义校验,我懒省事,直接注释掉了


    image.png

    12.这时候打开项目,点击登录,提示该用户不存在,注意,本模版默认传给后端的是key值是username、password,而后端要求的key是loginame、password,把loginForm对象内的username改成loginame,

    <el-input ref="username" v-model="loginForm.username" placeholder="Username" name="username" type="text" tabindex="1" auto-complete="on" />
    

    改成

    <el-input ref="username" v-model="loginForm.loginame" placeholder="Username" name="username" type="text" tabindex="1" auto-complete="on" />
    

    在需要修改store/modules/user.js,把actions中的login方法修改成下面这样:

      // user login
      login({ commit }, userInfo) {
        const { loginame, password } = userInfo
        return new Promise((resolve, reject) => {
          login({ loginame: loginame.trim(), password: password }).then(response => {
            commit('SET_TOKEN', response.token)
            setToken(response.token)
            resolve()
          }).catch(error => {
            reject(error)
          })
        })
      },
    
    image.png

    13.这时候打开项目,点击登录,提示账号密码错误,说明接口已经跑通。


    image.png

    14.我们输入正确的账号密码 admin 123456 ,点击登录,登录成功是这样的


    image.png

    可以看到,因为还没请求获取动态路由的接口,所以侧边栏是空的,头像也是裂的,下面我们就来解决这些问题。

    15.头像裂是因为,我们还没请求用户信息,现在来操作
    首先打开store/modules/user.js,把getInfo这个方法改造成这样:(因为后台我没设计头像,存个死值,各位老表自己根据自己后端实际返回的来存)


    image.png

    然后,头像就正常了

    16.下面做渲染侧边栏,请求动态路由,请求接口之前,要先做一些配置:
    (1)先在router这个目录下新建两个js文件,开发环境和生产环境导入组件的方式略有不同
    _import_development.js

    // 开发环境导入组件
    module.exports = file => require('@/views/' + file + '.vue').default // vue-loader at least v13.0.0+
    
    

    _import_production.js

    // 生产环境导入组件
    module.exports = file => () => import('@/views/' + file + '.vue')
    
    image.png

    (2)在src/permission.js中引入文件

    import Layout from "@/layout";
    const _import = require('./router/_import_' + process.env.NODE_ENV) // 获取组件的方法
    
    image.png

    (3)在await store.dispatch('user/getInfo')下面写这段代码


    image.png

    (4)在最底部新写一个方法


    image.png

    这时候点击登录,报错,别着急。继续往下走


    image.png

    (5)打开store/modules/user.js,在actions中新建一个方法,请求路由表


    image.png

    (6)在getDefaultState中,新增menus: "",mutations中新增 SET_MENUS: (state, menus) => { state.menus = menus }


    image.png

    (7)在getters.js中新增 menus: state => state.user.menus


    image.png

    这时候点击登录,会报这个错:


    image.png

    意思就是找不到vue文件,根据实际情况,新建文件:
    (8)在views下新建:system文件夹,文件夹内新建三个文件夹,分别是 menu 、 roles 、user ,三个文件夹下分别新建index.vue
    这时候在点击登录,不报错,进来了,但是侧边栏还是没东西,还差一步:
    (9)打开layout/components/Sidebar/index.vue,计算属性中,把routes改成


    image.png

    这时候在刷新页面,完美展示:


    image.png

    17.下面准备开始开发菜单管理页面。老规矩,先把接口地址配置好。
    在api文件夹下,新建system文件夹,内新建index.js,
    里面这样写:

    import request from '@/utils/request'
    // 获取菜单列表接口
    export function getMenuList(params) {
        return request({
          url: '/aoaoe/api/getMenuList',
          method: 'get',
          params
        })
      }
    // 新增菜单
      export function addMenu(data) {
        return request({
          url: '/aoaoe/api/menu/add',
          method: 'post',
          data
        })
      }
    // 修改菜单
    export function updateMenu(id,data) {
        return request({
          url: `/aoaoe/api/menu/update/${id}`,
          method: 'put',
          data
        })
      }
    
     // 删除菜单
    export function delMenu(id) {
        return request({
          url: `/aoaoe/api/menu/delete/${id}`,
          method: 'delete',
        })
      }
    
    
    image.png

    把红圈中的封装成一个组件,方便复用

    在components/System下新建一个Toobar.vue文件,里面这样写:

    <template>
      <div>
        <!--工具栏-->
        <div class="head_container">
          <span>
            <el-input
              class="filter-item"
              v-model="searchKey"
              clearable
              placeholder="请输入内容"
              style="width: 200px"
              @keyup.enter.native="toQuery"
            ></el-input>
            <span class="filter-item">
              <el-button type="success" icon="el-icon-search">搜索</el-button>
              <el-button type="warning" icon="el-icon-refresh-left">重置</el-button>
              <el-button type="primary" icon="el-icon-plus" @click="Add" v-permission="AddBtnAuth">新增</el-button>
            </span>
          </span>
          <span>
            <el-button-group>
              <el-button icon="el-icon-search"></el-button>
                <el-button icon="el-icon-refresh"></el-button>
            </el-button-group>
          </span>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      props:["AddBtnAuth"],
      data() {
        return {
          searchKey: "",
        };
      },
      methods: {
        toQuery() {},
        Add(){
          this.$emit("handleAdd")
        },
      },
    };
    </script>
    
    <style lang="scss" scoped>
    .head_container{
      display: flex;
      align-items: center;
      justify-content: space-between;
      span{
        display: flex;
         align-items: center;
      }
      .filter-item{
        margin-left:10px;
      }
    }
    </style>
    
    
    

    props: { AddBtnAuth: { type: Array, }, },这段代码是接收的父组件传过来的添加按钮权限,后面会讲到

    在main.js内引入,让其成为全局组件

    Vue.component('toolbar', () => import('@/components/System/toolbar.vue'))
    

    在menu/index.vue内使用,出现说明成功,但是太大了,在main.js配置

    import Cookies from 'js-cookie'
    Vue.use(ElementUI, {size: Cookies.get('size') || 'mini' // set element-ui default size})
    

    这样就好了

    18.在components下新建System/menu/dialogMenu.vue;
    里面暂时这样写:

    <template>
      <div>
        <el-dialog :title="dialogMenu.title" :visible.sync="dialogMenu.show" width="40%">
          <el-form ref="form" :rules="rules" :model="formData" label-width="80px">
            <!--菜单类型-->
            <el-form-item label="菜单类型">
              <el-radio-group v-model="formData.type">
                <el-radio-button label="1" :disabled="formData.type != '1' && dialogMenu.option == 'edit'">目录</el-radio-button>
                <el-radio-button label="2" :disabled="formData.type != '2' && dialogMenu.option == 'edit'">菜单</el-radio-button>
                <el-radio-button label="3" :disabled="formData.type != '3' && dialogMenu.option == 'edit'">按钮</el-radio-button>
              </el-radio-group>
            </el-form-item>
            <!--选择图标-->
            <el-form-item label="选择图标" v-if="formData.type != 3" prop="icon">
              <e-icon-picker v-model="formData.icon" :options="options" style="width: 76%"></e-icon-picker>
            </el-form-item>
            <!--是否可见,菜单标题-->
            <div class="flex" style="display: flex" v-if="formData.type != 3">
              <el-form-item label="是否可见">
                <el-radio-group v-model="formData.hidden">
                  <el-radio-button label="1">是</el-radio-button>
                  <el-radio-button label="0">否</el-radio-button>
                </el-radio-group>
              </el-form-item>
              <el-form-item label="目录标题" style="margin-left: 10px" prop="title">
                <el-input v-model="formData.title" placeholder="请输入标题"></el-input>
              </el-form-item>
            </div>
            <!--路由地址和菜单排序-->
            <div class="flex" style="display: flex" v-if="formData.type != 3">
              <el-form-item label="路由地址" prop="path">
                <el-input v-model="formData.path" placeholder="路由地址(/:path)"></el-input>
              </el-form-item>
              <el-form-item label="菜单排序" style="margin-left: 10px" prop="sort">
                <el-input-number v-model="formData.sort" controls-position="right" placeholder="请排序"></el-input-number>
              </el-form-item>
            </div>
            <!--组件名称、组件路径-->
            <div class="flex" style="display: flex" v-if="formData.type == 2">
              <el-form-item label="组件名称" prop="name">
                <el-input v-model="formData.name" placeholder="请输入组件name"></el-input>
              </el-form-item>
              <el-form-item label="组件路径" style="margin-left: 15px" prop="component">
                <el-input placeholder="请输入组件路径" @input="change($event)" v-model="formData.component"></el-input>
              </el-form-item>
            </div>
            <!-- 按钮名称、权限标识 -->
            <div class="flex" style="display: flex" v-if="formData.type == 3">
              <el-form-item label="按钮名称" prop="title">
                <el-input placeholder="请输入按钮名称" v-model="formData.title"></el-input>
              </el-form-item>
              <el-form-item label="权限标识" style="margin-left: 15px" prop="permissions">
                <el-input placeholder="请输入权限标识" v-model="formData.permissions"></el-input>
              </el-form-item>
            </div>
            <!--上级类目-->
            <div class="flex" style="display: flex">
              <el-form-item label="上级类目" prop="pid">
                <el-cascader :options="allMenu" v-model="formData.pid" placeholder="请选择" :props="{ checkStrictly: true, label: 'title', value: '_id' }" :show-all-levels="false" clearable></el-cascader>
              </el-form-item>
              <el-form-item label="按钮排序" style="margin-left: 10px" prop="sort" v-if="formData.type == 3">
                <el-input-number v-model="formData.sort" controls-position="right" placeholder="请排序"></el-input-number>
              </el-form-item>
            </div>
          </el-form>
          {{this.formData}}
          <span slot="footer" class="dialog-footer">
            <el-button @click="close">取 消</el-button>
            <el-button type="primary" @click="handleSubmit('form')">确 定</el-button>
          </span>
        </el-dialog>
    
      </div>
    </template>
    
    <script>
    import { getMoveRouter } from "@/api/index";
    export default {
      props: {
        dialogMenu: Object,
        formData: Object,
      },
      data () {
        return {
          allMenu: [], //全部的路由
          nest: "0",//默认是0,不是嵌套路由
    
          options: {
            FontAwesome: false,
            ElementUI: true,
            eIcon: false, //自带的图标,来自阿里妈妈
            eIconSymbol: false, //是否开启彩色图标
            addIconList: [],
            removeIconList: [],
          },
          rules: {
            title: [{ required: true, message: "请输入标题", trigger: "blur" }],
            icon: [{ required: true, message: "请选择图标", trigger: "blur" }],
            sort: [{ required: true, message: "请输入排序编号", trigger: "blur" }],
            name: [{ required: true, message: "请输入组件name", trigger: "blur" }],
            path: [{ required: true, message: "请输入组件路径", trigger: "blur" }],
            icon: [{ required: true, message: "请选择图标", trigger: "change" }],
            pid: [{ required: true, message: "请选择上级类目", trigger: "change" }],
            component: [
              { required: true, message: "请输入组件路径", trigger: "blur" },
            ],
            permissions: [
              { required: true, message: "请输入权限标识", trigger: "blur" },
            ],
          },
        };
      },
      created () {
        this.init();
      },
      watch: {
        "formData.type": {
          handler: function () {
            if (this.formData.type == "1") {
              this.formData.redirect = "noRedirect"; //建议 必须是 ‘noRedirect’,因为如果是redirect的话面包屑那一块是可以点击跳转,这样做没有意义
              this.formData.alwaysShow = "1"; //设置成1 意思是总是显示父级,-----如果没这个字段或者这个字段为0 意思就是当只有一个子菜单的时候,不显示父级
              this.formData.component = "Layout"; //必须是 Layout
              this.nest = "0";
            } else {
              this.formData.redirect = "";
              this.formData.alwaysShow = "";
              if (this.dialogMenu.option == "add") {
                this.formData.component = "";
              }
            }
            if (this.formData.type == "3") {
              this.nest = "0";
            }
          },
          immediate: true,
        },
        //监听nest路由嵌套
        "nest": {
          handler: function () {
            if (this.nest == "1") {
              this.formData.redirect = "noRedirect";
              this.formData.alwaysShow = "1"
            } else {
              this.formData.redirect = "";
              this.formData.alwaysShow = ""
            }
          }
        }
      },
      methods: {
        close () {
          this.$emit("close");
        },
        init () {
          getMoveRouter().then((res) => {
            if (this.formData.type == 1) {
              res.data.push({
                _id: "0",
                title: "顶级目录",
              });
            }
            this.allMenu = res.data;
            if (this.dialogMenu.option == "edit") {
              if (this.formData.type == 2) {
                res.data.forEach((item) => {
                  if (item.children) {
                    item.children.forEach((ele) => {
                      ele.disabled = true;
                    });
                  }
                });
              }
            }
          });
        },
        //点击确定按钮提交
        handleSubmit (formName) {
          this.$refs[formName].validate((valid) => {
            if (valid) {
              if (this.dialogMenu.option == "add") {
                this.formData.pid = this.formData.pid[this.formData.pid.length - 1];
                this.$emit("handleSubmit");
                this.$emit("close");
              } else {
                if (typeof (this.formData.pid) != 'string') {
                  this.formData.pid = this.formData.pid[this.formData.pid.length - 1];
                }
                this.$emit("handleSubmitEdit");
    
              }
            } else {
              return false;
            }
          });
        },
        //change
        change (e) {
          this.$forceUpdate();
        },
      },
    };
    </script>
    
    <style lang="sass" scoped>
    </style>
    
    

    19.views/system/menu/index.vue里这样写:

    <template>
      <div class="main" style="margin: 10px">
        <el-card>
          <!--头部组件-->
          <Toobar :AddBtnAuth="AddBtnAuth" @handleAdd="handleAdd"></Toobar>
        </el-card>
        <el-button @click="PrintRow" type="success">打印按钮</el-button>
        <!--表格-->
        <el-card style="margin-top: 10px" ref="print">
          <el-table :data="tableData" v-loading="loading" style="width: 100%" row-key="_id" ref="table" lazy :load="getChildMenus" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }">>
            <el-table-column type="index" label="#" align="center">
            </el-table-column>
            <el-table-column prop="title" label="菜单标题" width="200">
            </el-table-column>
            <el-table-column prop="icon" label="图标" align="center">
            </el-table-column>
            <el-table-column prop="sort" label="排序" align="center">
            </el-table-column>
            <el-table-column prop="permissions" label="权限标识" align="center">
              <template slot-scope="scope">
                {{ scope.row.permissions == "" ? "--" : scope.row.hidden }}
              </template>
            </el-table-column>
            <el-table-column prop="component" label="组件路径" align="center">
              <template slot-scope="scope">
                <span v-if="scope.row.component == 'Layout'">--</span>
                <span v-else>{{
                  scope.row.component == undefined ? "--" : scope.row.component
                }}</span>
              </template>
            </el-table-column>
            <el-table-column prop="type" label="菜单类型" align="center">
              <template slot-scope="scope">
                <el-tag type="success" v-if="scope.row.type == 1">目录</el-tag>
                <el-tag type="warning" v-if="scope.row.type == 2">菜单</el-tag>
                <el-tag type="danger" v-if="scope.row.type == 3">按钮</el-tag>
              </template>
            </el-table-column>
            <el-table-column prop="hidden" label="是否可见" align="center">
              <template slot-scope="scope">
                <el-switch v-model="scope.row.hidden" active-color="#13ce66" inactive-color="#ff4949" active-text="是" active-value="1" inactive-text="否" inactive-value="0" disabled>
                </el-switch>
              </template>
            </el-table-column>
            <el-table-column label="创建日期" align="center" width="200">
              <template slot-scope="scope">
                {{ scope.row.date | formatDate }}
              </template>
            </el-table-column>
            <el-table-column label="操作" align="center" width="150">
              <template slot-scope="scope">
                <el-button type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button>
                <el-button size="small" type="danger" @click="handleDelete(scope.row)">删除</el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-card>
        <div style="height:100000px"></div>
        <!--弹窗组件-->
        <dialog-menu ref="haode" v-if="dialogMenu.show" :dialogMenu="dialogMenu" :formData="formData" @handleSubmit="handleSubmit" @handleSubmitEdit="handleSubmitEdit" @close="close"></dialog-menu>
      </div>
    </template>
    
    <script>
    import Toobar from "@/components/System/Toobar";
    import { getMenuList, delMenu, addMenu, updateMenu } from "@/api/system/index";
    import DialogMenu from "@/components/System/menu/dialogMenu.vue";
    
    export default {
      components: { Toobar, DialogMenu },
      data () {
        return {
          AddBtnAuth: ["add"],
          tableData: [],
          dialogMenu: {
            //定义弹窗是否显示属性
            show: false,
            title: "新增菜单",
            option: "add",
          },
          formData: {},
          oldPid: "",
          loading: true
        };
      },
      created () {
        this.init();
      },
      methods: {
        init () {
          console.log("init触发")
          console.log(this.$refs)
          getMenuList({ pid: 0 }).then((res) => {
            if (res.code == 200) {
              this.tableData = res.data;
              this.loading = false;
            } else {
              this.tableData = [];
              this.loading = false
            }
          });
        },
        //getChildMenus获取子菜单
        getChildMenus (tree, treeNode, resolve) {
          const data = { pid: tree._id };
          getMenuList(data).then((res) => {
            console.log(res);
            resolve(res.data);
          });
        },
        handleAdd () {
          this.dialogMenu = {
            show: true,
            title: "新增菜单",
            option: "add",
          };
          this.formData = {
            type: 1,
            hidden: 1,
            pid: "",
            icon: "",
            path: "",
            title: "",
            sort: "",
            name: "",
            component: "",
            permissions: "",
            noCache: "0",
          };
    
        },
        //提交新增请求
        handleSubmit (formData) {
          addMenu(this.formData).then((res) => {
            console.log(res);
            this.dialogMenu.show = false;
            this.$message.success("新增成功!");
            if (this.formData.pid != 0) {
              // 实现无感刷新
              getMenuList({ pid: this.formData.pid }).then((res) => {
                this.$set(
                  this.$refs.table.store.states.lazyTreeNodeMap,
                  this.formData.pid,
                  res.data
                );
              });
            } else {
              this.init();
            }
          });
        },
        //编辑请求
        handleSubmitEdit () {
          updateMenu(this.formData.id, this.formData).then((res) => {
            this.dialogMenu.show = false;
            this.$message.success("修改成功!");
            if (this.formData.pid != 0) {
              getMenuList({ pid: this.formData.pid }).then((res) => {
                this.$set(
                  this.$refs.table.store.states.lazyTreeNodeMap,
                  this.formData.pid,
                  res.data
                );
              });
            } else {
              this.init();
            }
          });
        },
        //关闭新增菜单的弹窗
        close () {
          this.dialogMenu.show = false;
        },
        // 删除按钮触发
        handleDelete (row) {
          console.log("点击触发")
          console.log(this.$refs)
          this.$confirm(
            "此操作将永久删除该菜单,并删除所属子级, 是否继续?",
            "提示",
            {
              confirmButtonText: "确定",
              cancelButtonText: "取消",
              type: "warning",
            }
          )
            .then(() => {
              delMenu(row._id).then((res) => {
                this.$message({
                  type: "success",
                  message: "删除成功!",
                });
                // 无感刷新
                getMenuList({ pid: row.pid }).then((res) => {
                  this.$set(
                    this.$refs.table.store.states.lazyTreeNodeMap,
                    row.pid,
                    res.data
                  );
                });
                if (row.pid == 0) {
                  this.init();
                }
              });
            })
            .catch(() => {
              this.$message({
                type: "info",
                message: "已取消删除",
              });
            });
        },
        //编辑
        handleEdit (row) {
    
          this.dialogMenu = {
            show: true,
            title: "编辑菜单",
            option: "edit",
          };
          this.formData = {
            id: row._id,
            type: row.type,
            icon: row.icon,
            hidden: row.hidden,
            title: row.title,
            path: row.path,
            sort: row.sort,
            name: row.name,
            component: row.component,
            pid: row.pid + "",
            permissions: row.permissions,
            noCache: row.noCache == 0 ? "0" : "1",
          };
          this.oldPid = row.pid;
        },
        //打印
        PrintRow (index, row) {
          this.$print(this.$refs.print);
        }
        //打印结束
      },
    };
    </script>
    
    <style>
    </style>
    

    20.因为用到e-icon-picker选择图标的插件,所以要安装下:


    image.png

    21.菜单就可以了。


    image.png

    相关文章

      网友评论

        本文标题:vue-element-template实现权限管理、动态路由、

        本文链接:https://www.haomeiwen.com/subject/gxuhxltx.html