0


Vue框架教程-从入门到项目实战

创建Vue项目

我们通过vue-cli创建一个vue项目,

  1. 在cmd窗口输入 vue ui 进入vue-cli可视化界面(如果无效请升级vue-cli版本)
  2. 点击创建,选择一个项目目录image-20211211002427099
  3. 输入项目名称和git初始化窗口(可选)image-20211211002555427
  4. 选择预设,可以选择手动和预定的设置 (预设就是一套定义好的插件和配置。 你也可以将自己的配置保存成预设,方便以后创建项目使用。)image-20211211002727442
  5. 选择项目功能(也可以在创建后手动添加)image-20211211002844423
  6. 选择配置image-20211211002923446
  7. 等待创建完项目即可(如果是第一次可能有点慢)
  8. 启动项目image-20211211003611682

引入Element-Ui

  1. 点击左侧插件,点击右上角添加插件image-20211211003129847
  2. 点击所有插件,输入element,选中第一个,点击创建image-20211211003231831
  3. 配置插件,点击手工按需导入,选中zh-cn中文,完成按照即可image-20211211003455683

手动引入组件

image-20211211010749300

或者导入一行

image-20211211023656870

Git上传仓库

我们的代码一般都会上传到Gitee或者GitHub中的远程仓库托管,这样我们电脑项目丢失或者需要旧版本的项目可以直接将远程的代码下载(拉取)到本地进行开发。

  1. 我们先安装Git软件 https://git-scm.com/
  2. 前往Gitee注册账号https://gitee.com/
  3. 配置SSH公钥,点击怎么生成公钥然后按照步骤进行申请image-20211211004042579

image-20211211004202257

image-20211211004218003

image-20211211004237029

  1. 在CMD窗口输入上方黄色指令进行生成,其中的”xxx“改成注册的邮箱
  2. 如果cmd窗口生成失败,进入桌面鼠标右键点击Git GUl Hereimage-20211211004535944
  3. 点击show ssh key,将生成key的指令粘贴进去弹出账号密码输入gitee注册的账号密码即可生成完成
  4. 生成完成后第三步的公钥取和输入自定义标题即可完成添加公钥
  5. 新建仓库image-20211211004814720
  6. 输入仓库名称选择开源或者私有即可,点击创建image-20211211004922729
  7. 将创建的vue项目上传到刚刚创建的仓库中,我们初始化一下Git(一定要执行)image-20211211005433196image-20211211005502278
  8. 我们cd 进入vue项目的更目录查询一下项目是否干净image-20211211005639666
  9. 我们将当前下的文件提交到本地的git中,
  10. 然后我们在执行一个 git status,显示当前分支和目录处于干净状态image-202112110059309651. 我们将本地的git上传到远程gitee仓库,先复制黄色内容,在刚刚的cmd中执行一下,表示上传成功image-20211211010221162

image-20211211010205366

  1. 最后我们刷新一个我们的仓库,就可以看见我们项目了

创建新的分支

我们在添加新功能的时候会创建一个分支

git checkout -b login

PS D:\heima_shop\xcwl_shop> git checkout -b login
Switchedtoanew branch 'login'
PS D:\heima_shop\xcwl_shop>

查看所有分支

git branch

vscode从远程仓库拉代码

1,在你写项目的磁盘里新建文件夹
2,登录Gitee
3,复制克隆/下载处的地址
11

4,打开VScode,在新建的文件夹下,打开终端
5,运行 git clone + 地址 ,回车,项目就拉取下来了

提交代码

将本地代码提交到Git仓库

  1. 获取当前文件(跟仓库代码做对比,那些修改过,那些是新增的)

image-20211211024024744

  1. git add . 将代码全部添加在暂存区
  2. git commit -m “完成了登录功能” 将代码提交到本地git仓库
  3. 合并分支,获取当前分支:git branch,切换到主分支git checkout master
  4. 当前在主分支输入命令git merge login 将login分支合并到当前主分支
  5. 当前login分支的代码已经全部合并到主分支了,我们将主分支代码同步到gitee仓库通过 git push命令
  6. 在gitee仓库创建一个子分支,git push -u origin login,创建了一个login子分支

Vue

axios

注意:要先下载引入axios组件

在main.js中引入,即可全局使用

image-20211211010910503

本地存储Token

//1.将登录成功之后的Token存放到客户端的sessionStorage中,为什么不存放到localstorage中呢,因为他是持久性机制,sessionstorage是会话机制//1.1项目中除了登录之外的其他API接口,必须在登录之后才能访问//1.2token只能在当前网站打开期间生效,所以将token存放在sessionstorage中
        window.sessionStorage.setItem("token", req.data.data);//2.通过编程式导航跳转到后台首页,路由地址是/homethis.$router.push("/home");

路由导航守卫

image-20211211012854311

image-20211211014624851

//路由守卫,在执行路由前执行本方法来做认证操作// to:要去的路径,from:获取从那个页面路径跳转而来的,next:放行
router.beforeEach((to,from,next)=>{// 判断当前路径是否为login ,如果是true 着放行if(to.path==="/login")returnnext();//获取当前tokenconst token=window.sessionStorage.getItem("token");//如果当前token为空,着返回到login页面if(!token)returnnext("/login");//如果上面全部都过了,那么执行放行next();})

配置请求token

我们在除了登录和注册接口中不需要携带token,但是其他所有的请求中必须要携带token来确保当前账户,

如果我们每个axios中手动在head中添加会很麻烦,所以我们定义一个全局的拦截器

在每次请求的方法中,会先调用我们定义的全局拦截器,在继续执行我们的请求接口

image-20211211231337167

image-20211211232228394

//通过调用axios中的interceptors属性中的request成员(请求拦截器)中的use函数来添加全局请求头
axios.interceptors.request.use(config=>{//通过返回的config对象中的headers属性添加一个Authorization=本地存储的token
  config.headers.Authorization=window.sessionStorage.getItem("token")//在最后必须teturn configreturn config
})

image-20211211233305319

作用域插槽

可以定义一个插槽,切插槽可以获取当前对象

        <el-table-column label="状态">
          <!-- 我们创建一个作用域插槽模板来写一个开关按钮 通过slot-scope="scope"来接收当前一行对象数据-->
          <template slot-scope="scope">
            <!-- 可以通过scope.row获取当前一行对象,通过.对象中的参数可以获取对应的值 -->
            {{ scope.row.mg_state }}
            <!-- 定义一个开关按钮,v-mode的值为true,false,对应开还是关 -->
            <el-switch v-model="scope.row.mg_state"> </el-switch>
          </template>
        </el-table-column>

字符串 数组转换

image-20211218173024963

数组转字符串用.join()方法不填参数表示转换已,分割 a,b,c 填参数 .join(“.”) 打印 a.b.c

Css

在创建vue项目中,页面样式默认都是有margin和padding所以我们创建一个全局css样式表来设置全部页面的默认样式

在assets下创建css文件在创建一个global.css文件

/* 全局css样式 */html,body,#app{height: 100%;margin: 0px;padding: 0px;}

flex布局

/*设置布局方式为flex*/display: flex;/*设置靠右对齐*/justify-content: space-between;/*设置上下居中*/align-items: center;

class绑定多css

:class="['borderbottom','vcenter']"

class做判断

image-20211214092847876

功能实现

退出功能

退出功能原理详解

基于token的方式实现退出比较简单,只需要将本地存储的token销毁掉,这样后续的请求就不会携带token并且路由守卫也获取不到存储的token就会被拦截强制跳转到login登录页面,必须重新登录才可以获取新的token存储到本地就可以访问其他页面

image-20211211015046495

<template>
    <div>
        <el-button type="info" @click="tuichu">退出</el-button>
    </div>
</template>
<script>
export default {
    methods:{
        tuichu(){
            //获取本地的sessionStorage执行remove方法清除token
            window.sessionStorage.removeItem("token");
            //通过路由puth跳转(重定向)到login登录界面
            this.$router.push("/login");
        }
    }
}
</script>
<style scoped>

</style>

首页布局

image-20211211025755025

Head头部

image-20211211224409628

<template>
  <!-- 创建布局容器 -->
  <el-container class="home-container">
    <!-- 头部 -->
    <el-header>
      <div class="header-div">
        <img
          src="../assets/logo.png"
          alt=""
          style="height: 50px; width: 50px"
        />
        <!-- 设置跟图片间隔15px -->
        <span style="margin-left: 15px">电商后台管理系统</span>
      </div>
      <el-button type="info" @click="tuichu">退出</el-button>
    </el-header>
    <!-- 内容主体区域 -->
    <el-container>
      <!-- 内容主体左侧侧边栏 -->
      <el-aside width="200px">Aside</el-aside>
      <!-- 内容主体右侧内容 -->
      <el-main>Main</el-main>
    </el-container>
  </el-container>
</template>
<script>
export default {
  methods: {
    tuichu() {
      // 获取本地的sessionStorage执行remove方法清除token
      window.sessionStorage.removeItem("token")
      // 通过路由puth跳转到login登录界面
      this.$router.push("/login")
    },
  },
}
</script>
<style scoped>
/* 给容器设置宽高 */
.home-container {
  height: 100%;
  width: 100%;
}

.el-header {
  background-color: #373d41;
  /* 设置flex布局方式 */
  display: flex;
  /* 靠右对齐 */
  justify-content: space-between;
  padding-left: 0;
  /* 设置上下居中 */
  align-items: center;
  color: #fff;
  font-size: 20px;
}
.header-div {
  /* 设置flex布局方式 */
  display: flex;
  /* 设置居中对其 */
  align-items: center;
}

.el-aside {
  background-color: #333744;
}
.el-main {
  background-color: #eaedf1;
}
</style>

左侧侧边栏

image-20211211224338283

<el-aside width="200px">
       <!-- 侧边栏内容区域 -->
       <el-menu
         background-color="rgb(51,55,68)"
         text-color="#fff"
         active-text-color="#ffd04b"
       >
         <!-- 一级菜单 -->
         <el-submenu index="1">
           <!-- 一级菜单模板区域 -->
           <template slot="title">
             <!-- 菜单图标 -->
             <i class="el-icon-location"></i>
             <!-- 采单文本 -->
             <span>导航一</span>
           </template>
           <!-- 二级菜单 -->
           <el-menu-item index="1-4-1">
             <!-- 二级菜单模板区域 -->
             <template slot="title">
               <!-- 菜单图标 -->
               <i class="el-icon-location"></i>
               <!-- 菜单文本 -->
               <span>导航一</span>
             </template>
           </el-menu-item>
         </el-submenu>
       </el-menu>
     </el-aside>

获取侧边栏数据,并且渲染到页面

<template>
  <!-- 创建布局容器 -->
  <el-container class="home-container">
    <!-- 头部 -->
    <el-header>
      <div class="header-div">
        <img
          src="../assets/logo.png"
          alt=""
          style="height: 50px; width: 50px"
        />
        <!-- 设置跟图片间隔15px -->
        <span style="margin-left: 15px">电商后台管理系统</span>
      </div>
      <el-button type="info" @click="tuichu">退出</el-button>
    </el-header>
    <!-- 内容主体区域 -->
    <el-container>
      <!-- 内容主体左侧侧边栏 -->
      <el-aside width="200px">
        <!-- 侧边栏内容区域 -->
        <el-menu
          background-color="rgb(51,55,68)"
          text-color="#fff"
          active-text-color="#ffd04b"
        >
          <!-- 一级菜单 -->
          <el-submenu :index="''+item.id" v-for="(item, index) in meaunList" :key="index">
            <!-- 一级菜单模板区域 -->
            <template slot="title">
              <!-- 菜单图标 -->
              <i class="el-icon-location"></i>
              <!-- 采单文本 -->
              <span>{{item.authName}}</span>
            </template>
            <!-- 二级菜单 -->
            <el-menu-item :index="''+item.children[0].id">
              <!-- 二级菜单模板区域 -->
              <template slot="title">
                <!-- 菜单图标 -->
                <i class="el-icon-location"></i>
                <!-- 菜单文本 -->
                <span>{{item.children[0].authName}}</span>
              </template>
            </el-menu-item>
          </el-submenu>
        </el-menu>
      </el-aside>
      <!-- 内容主体右侧内容 -->
      <el-main>Main</el-main>
    </el-container>
  </el-container>
</template>
<script>
export default {
  data(){
    return{
      meaunList: [],
    }
  },
  // created:生命周期函数,在进入页面时先加载这个函数在加载html....
  // created跟mounted有什么区别呢? created加载完在加载html,mounted是html加载完在执行mounted,所以created的执行优先级比mounted高
  //this.getMenuList()来获取axios返回的菜单数据
  created() {
    this.getMenuList()
  },
  methods: {
    tuichu() {
      // 获取本地的sessionStorage执行remove方法清除token
      window.sessionStorage.removeItem("token")
      // 通过路由puth跳转到login登录界面
      this.$router.push("/login")
    },
    //获取所有的菜单
    async getMenuList() {
      //变量名{data:req}这样写可以直接获取请求对象中的data属性 ,变量名称为req
      const { data: req } = await this.$http.get("/menus")
      // console.log(req);
      // const data = await this.$http.get("/menus")
      // 判断是否获取成功,如果失败返回失败信息
      if (req.meta.status !== 200) return this.$message.error(req.meta.msg)
      //成功后将菜单信息定义到data数组
      this.meaunList = req.data
    },
  },
}
</script>
<style scoped>
/* 给容器设置宽高 */
.home-container {
  height: 100%;
  width: 100%;
}

.el-header {
  background-color: #373d41;
  /* 设置flex布局方式 */
  display: flex;
  /* 靠右对齐 */
  justify-content: space-between;
  padding-left: 0;
  /* 设置上下居中 */
  align-items: center;
  color: #fff;
  font-size: 20px;
}
.header-div {
  /* 设置flex布局方式 */
  display: flex;
  /* 设置居中对其 */
  align-items: center;
}

.el-aside {
  background-color: #333744;
}
.el-main {
  background-color: #eaedf1;
}
</style>

侧边栏美化

.el-submenu{/* 给菜单图标设置间距 */margin-right: 10px;}.el-menu{/* 将侧边栏默认的边框去掉 */border-right: none;}

给手动设置图标icon

image-20211212022132553

侧边栏伸缩

侧边栏点击收缩,点击展开,其实就是定义一个点击事件然后修改侧边栏的collapse属性为true或者false

        <!-- 定义展开伸缩点击事件 -->
        <div class="toggle-button" @click="toggleCollapse">|||</div>
        <el-menu
          background-color="rgb(51,55,68)"
          text-color="#fff"
          active-text-color="#409eff"
          <!-- 是否只保持一个子菜单的展开 -->
          unique-opened
          <!-- 是否水平折叠收起菜单 这里调用的是toggleCollapse方法,如果方法里面有本方法会优先调用方法其次在调用data中的-->
          :collapse="iscollapse"
          <!-- 是否开启折叠动画 这里调用的是data中的transition-->
          :collapse-transition="transition"
        >
</el-menu>
data(){return{// 是否折叠iscollapse:false,//是否开启折叠动画transition:false}}
// 点击按钮,切换菜单显示和展开toggleCollapse(){this.iscollapse=!this.iscollapse
    },

实现路由重定向

我们在登录login成功后跳转到我们home页面,会默认加载welcome页面(这里使用重定向)

我们先将welcome页面注册到home子路由中

{path:"/Home",name:"Home",component:()=>import("../components/Home.vue"),// 默认页面时重定向/welcome子路由页面redirect:"/welcome",//注册子路由,主路由页面中可以随时切换到子路由页面,切换到那个区域由router-view标签决定children:[{path:"/welcome",name:"welcome",component:()=>import("../components/Welcome.vue"),},],},

将子路由页面加载到home主路由那个区域?在主路由用router-view来决定

      <!-- 内容主体右侧内容 -->
      <el-main>
          <!--定义到这里-->
        <router-view></router-view>
      </el-main>

导航栏小bug

我们点击二级菜单后虽然有高亮,但是刷新后就没有高亮了,

我们可以通过default-active=“二级菜单路径” 来定义高亮

解决方法:

我们在点击二级菜单时将path路径保存进sessionstora中,在将存放在sessiostora中的path路径赋值给default-active即可

<el-menu
          //设置二级菜单高亮//这里的active对应的时data中的active:default-active="active"><!-- 二级菜单 --><el-menu-item
              v-for="(item, index) in item.children":index="'/' + item.path":key="index"//定义一个点击方法将path传递过去
              @click="setactive('/' + item.path)">data(){return{// 获取本地存储的上次点击的菜单栏active:window.sessionStorage.getItem("active"),}}//点击后执行本方法,将path存放进sessionstora中setactive(active){
      window.sessionStorage.setItem("active", active)},

用户列表

因为每个页面都有面包屑导航栏,而且还跟卡片面板挨得太近,在全局css样式中添加样式

/* 面包屑 */.el-breadcrumb{margin-bottom: 15px;font-size: 12px;}/* 卡片面板 */.el-card{/* 设置卡片阴影 */box-shadow: 0,1px,1px rgb(0, 0,0, 0.15);}

面包屑

image-20211212033420619

    <!-- 面包屑导航 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
        <!--点击即可回到home首页-->
      <el-breadcrumb-item :to="{ path: '/Home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>用户管理</el-breadcrumb-item>
      <el-breadcrumb-item>用户列表</el-breadcrumb-item>
    </el-breadcrumb>

卡片面板

image-20211212033528304

    <!-- 卡片试图区 -->
    <el-card class="box-card">
        <!-- 设置两栏间距 -->
      <el-row :gutter="20">
          <!-- 设置这一栏大小 -->
          <el-col :span="8">
        <!-- 搜索与添加区域 -->
        <el-input placeholder="请输入内容">
          <el-button slot="append" icon="el-icon-search"></el-button>
        </el-input>
          </el-col>
        <el-col :span="4">
            <!-- 按钮 -->
            <el-button type="primary">添加用户</el-button>
          </el-col>
      </el-row>
    </el-card>

用户数据展示

  1. 获取所有用户数据
<script>
export default {
  data() {
    return {
      //存放用户数据的数组
      userList:[],
      //存放用户总数的数据
      usertotal:'',
      //请求用户数据传递的参数
      queryInfo:{
        query:'',
        pagenum:'1',
        pagesize:'10'
      }
    }
  },
  created() {
    //第一时间调用获取用户数据
    this.getUserList()
  },
  methods: {
    //通过axios获取用户数据
    async getUserList() {
      // get 传递参数{params:参数对象{a:1,b:2}}
      const {data:req} = await this.$http.get("/users",{params:this.queryInfo})
      // console.log(userList)
      if(req.meta.status!==200)return this.$message.error("获取用户数据失败!")
      // 将用户数组存放进data中的userList数组
      this.userList=req.data.users
      // 将用户总数存放usertotal
      this.usertotal=req.data.total
      // console.log(this.userList)
    },

  },
}
</script>
#### 用户数据渲染
      <!-- 用户数据表格 -->
      <el-table :data="userList" border stripe>
        <!-- :data表示获取用户数组 border纵向边框 stripe斑马纹 table -->
        <!-- el-table-column每一模板列数据 label列头部标题 prop列内容数据 -->
        <el-table-column label="用户名" prop="username"></el-table-column>
        <el-table-column label="邮箱" prop="email"></el-table-column>
        <el-table-column label="电话" prop="mobile"></el-table-column>
        <el-table-column label="角色" prop="role_name"></el-table-column>
        <el-table-column label="状态" prop="mg_state"></el-table-column>
        <el-table-column label="操作"></el-table-column>
      </el-table>

表格跟搜索框挨在一起不好看,在全局样式中设置table表格跟头部搜索框一段距离,并且表格字体太大修改小一点

/* tbale表格样式 */.el-table{/* 设置表格top外边距15px */margin-top: 15px;/* 设置表格内容字体大小 */font-size: 13px;}

image-20211212170735343

编写表格状态列

我们在状态这一列定义一个作用域插槽

        <el-table-column label="状态" prop="mg_state">
          <!-- 我们创建一个作用域插槽模板来写一个开关按钮,通过slot-scope="scope"来接收当前一行对象数据 -->
          <template slot-scope="scope">
            <!-- 可以通过scope.row获取当前一行对象,通过.对象中的参数可以获取对应的值 -->
            {{ scope.row.mg_state }}
            <!-- 定义一个开关按钮,v-mode的值为true,false,对应开还是关 -->
            <el-switch v-model="scope.row.mg_state"></el-switch>
          </template>
        </el-table-column>

编写操作列

操作列定义了三个按钮,编辑,清除,分配角色,这里我们依然使用作用域插槽

image-20211212175236317

<!-- 为了保持按钮在浏览器不同大小窗口都排列成一行不变形 我们给这行添加一个固定宽度 -->
        <el-table-column label="操作" width="180px">
          <template slot-scope="values">
            <!-- 修改按钮 type表示按钮颜色,icon表示按钮图标,size表示按钮大小-->
            <el-button type="primary" icon="el-icon-edit" size="mini"></el-button>
            <!-- 清除按钮 -->
            <el-button type="danger" icon="el-icon-delete" size="mini"></el-button>
            <!-- 分配角色按钮 -->
            <el-button type="warning" icon="el-icon-setting" size="mini"></el-button>
          </template>
        </el-table-column>

我们实现一下鼠标移到按钮上显示按钮功能提示

我们可以给按钮外侧套一层Tooltip 文字提示

image-20211212175701690

            <!-- 分配角色按钮 effect表示主体,content提示文字,placement提示方向-->
            <el-tooltip effect="dark" content="分配角色" placement="top">
               <el-button type="warning" icon="el-icon-setting" size="mini"></el-button>
            </el-tooltip>

数据分页

当我们数据足够多的时候,我们需要设置分页查看

先添加Pagination 分页组件

      <!-- 分页区域 -->
      <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="queryInfo.pagenum"
        :page-sizes="[1, 2, 3, 50]"
        :page-size="queryInfo.pagesize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="usertotal"
      >
      <!-- @size-change="handleSizeChange" 表示切换了每页条数的菜单会触发handleSizeChange方法函数 ,在这个函数中可以拿到最新的每页条数-->
      <!-- @current-change="handleCurrentChange"    页码值发生了切换会触发handleCurrentChange方法函数 -->
      <!-- :current-page="currentPage4" 当前显示的是第几页数据 -->
      <!-- :page-sizes="[100, 200, 300, 400]" 下拉菜单显示可以切换显示多少条数据 -->
      <!-- :page-size="100" 当前每页显示多少条数据-->
      <!-- layout 组件布局显示那些功能,比如每页显示多少条数据的下拉菜单 -->
      <!-- :total="400" 数据总数 -->
      </el-pagination>
<script>exportdefault{data(){return{//存放用户数据的数组userList:[],//存放用户总数的数据usertotal:"",//请求用户数据传递的参数queryInfo:{query:"",// 当前页数pagenum:1,// 显示多少条数据pagesize:10,},}},created(){//第一时间调用获取用户数据this.getUserList()},methods:{//通过axios获取用户数据asyncgetUserList(){// get 传递参数{params:参数对象{a:1,b:2}}const{data: req }=awaitthis.$http.get("/users",{params:this.queryInfo,})// console.log(userList)if(req.meta.status !==200)returnthis.$message.error("获取用户数据失败!")// 将用户数组存放进data中的userList数组this.userList = req.data.users
      // 将用户总数存放usertotalthis.usertotal = req.data.total
      // console.log(this.userList)},//当页面切换显示多少条数据时会触发并接收选择的多少条数据handleSizeChange(newSize){//用户切换每页显示多少条数据,我们修改data中的属性this.queryInfo.pagesize=newSize
      //设置完每页显示多少条数据后,重新获取一次每页显示多少条的数据this.getUserList()},// 当页码值发生了切换会触发并接收切换的页面值handleCurrentChange(newPage){//设置当前页面this.queryInfo.pagenum=newPage
       //设置完当前页码后重新获取当前设置完的页面的数据this.getUserList()}},}</script>

我们的分页组件需要跟表格设置点距离

在全局样式中添加

/* 分页样式 */.el-pagination{margin-top: 15px;}

用户状态修改

我们点击Switch开关按钮发送一条请求修改用户的状态

image-20211212200951045

@change="userStateChanged(values.row)" 代表开关点击后,会触发userStateChanged方法并且携带当前对象
<el-switch v-model="values.row.mg_state" @change="userStateChanged(values.row)"> </el-switch>
//状态按钮点击后执行这个函数方法,来修改用户状态函数asyncuserStateChanged(user_Row){//put请求const{data:req}=awaitthis.$http.put("/users/"+user_Row.id+"/state/"+user_Row.mg_state)// 如果修改失败if(req.meta.status!==200){// 当我们点击按钮后会直接在本地改成false/true,但是数据库没有修改成功,我们将本地的修改为原来的boolen
        user_Row.mg_state=!user_Row.mg_state
        // 发送提示信息returnthis.$message.error("修改用户状态失败!")}// 如果修改成功,我们发送提示信息this.$message.success("更新用户状态成功!")}

搜索用户

我们给input绑定一个v-model属性值为data中的queryInfo.query,在再buttom上添加一个点击事件,我们点击后调用getuserlist方法即可?

为什么我们不重新写个获取用户的请求而是重复用一个请求呢?

我们的获取用户请求中有三个参数,第一个参数是用户名(可以为空,我们为空代表获取所有用户,不为空代表查询当前输入的用户名)

所有我们可以复用getuserlist方法

 <el-input placeholder="请输入内容" v-model="queryInfo.query">
            <el-button slot="append" icon="el-icon-search" @click="getUserList" ></el-button>
          </el-input>

如果这个时候用户想查询全部用户信息了,又要吧输入框的信息全部清除再次点击一次查询,反而很麻烦

<!--我们给input加一个 clearable 属性代表 输入框可以显示清空按钮,@clear="getUserList"表示 当我们点击清空按钮后执行一个函数
我们清空后会默认执行一个getUserList函数,这个时候我们的v-model="queryInfo.query"的值为空,我们请求getUserList的时候就会显示全部用户信息了-->
<el-input placeholder="请输入内容" v-model="queryInfo.query" clearable @clear="getUserList">
            <el-button slot="append" icon="el-icon-search" @click="getUserList" ></el-button>
          </el-input>

添加用户

点击添加按钮弹出添加框

<!-- 添加用户对话框 -->
<el-dialog         
  title="提示"
  :visible.sync="addUservisiblesync"
  width="50%">
    <!--弹窗主体区域-->
  <span>这是一段信息</span>
    <!--底部按钮组件-->
  <span slot="footer" class="dialog-footer">
      <!--点击取消将addUservisiblesync修改为false 这样弹窗就会消失-->
    <el-button @click="addUservisiblesync = false">取 消</el-button>
    <el-button type="primary" @click="addUservisiblesync = false">确 定</el-button>
  </span>
</el-dialog>
<!--
title:弹窗标题
:visible.sync:表示是否显示
width:弹窗大小
-->

给弹出框添加表单

     <!--弹窗主体区域-->
      <el-form
        :model="addUserForm"
        :rules="addUserFormrules"
        ref="ruleAddUserForm"
        label-width="70px"
      >
      <!-- :model绑定表单对象,rules校验规则, -->
          <!--label表示input左侧文字 ,prop表示校验规则名称-->
        <el-form-item label="用户名" prop="username">
            <!--v-model表示与addUserForm对象下的属性绑定-->
          <el-input v-model="addUserForm.username"></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input v-model="addUserForm.password"></el-input>
        </el-form-item>
        <el-form-item label="邮箱" prop="email">
          <el-input v-model="addUserForm.email"></el-input>
        </el-form-item>
        <el-form-item label="手机号" prop="mobile">
          <el-input v-model="addUserForm.mobile"></el-input>
        </el-form-item>
      </el-form>
// 添加用户form表单对象addUserForm:{username:"",password:"",email:"",mobile:"",},//用户表单校验规则addUserFormrules:{username:[{required:true,message:"请输入用户名",trigger:"blur"},{min:4,max:18,message:"长度在 4 到 18 位",trigger:"blur"},],password:[{required:true,message:"请输入密码",trigger:"blur"},{min:4,max:18,message:"长度在 6 到 18 位",trigger:"blur"},],email:[{required:true,message:"请输入邮箱",trigger:"blur"},],mobile:[{required:true,message:"请输入手机号",trigger:"blur"},{min:11,max:11,message:"长度在11位",trigger:"blur"},],},

对表单重置

我们关闭表单后我们刚刚在表单输入的值任然还保存在data中,默认并不会清空。

所有我们要在表单关闭后将我们刚刚输入的信息全部清空重置

这里我们用dialog弹出层中的close属性来定义一个方法,close表示表单关闭后会执行触发

    <el-dialog title="提示" :visible.sync="addUservisiblesync" width="50%" @close="addUserClose">
//监听用户对话框关闭事件,添加用户对话关闭后执行,将添加用户的v-model绑定的值重置清空addUserClose(){// 通过refs获取页面定义的ref属性(当前对象)然后执行resetFields方法this.$refs.ruleAddUserForm.resetFields();}

添加用户功能

我们给添加按钮一个点击事件,点击后执行添加请求

        <el-button type="primary" @click="addUser"
          >确 定</el-button
        >

我们先请求用户数据,判断是否添加成功并返回提示,然后关闭弹窗,重新获取所有用户

asyncaddUser(){//添加用户请求const{data:req}=awaitthis.$http.post("/users",this.addUserForm);//添加失败if(req.meta.status!==201)returnthis.$message.error("添加用户失败!")//添加成功this.$message.success("添加成功!")//关闭弹窗this.addUservisiblesync=false//重新请求加载用户数据this.getUserList()}

修改用户

点击修改即可弹窗修改表单,跟我们添加用户一样添加一个Dialog标签和给:visible.sync添加一个数据双向绑定的值(true,false)

跟添加用户不同的是,我们点击按钮需要携带当前对象属性信息,所以我们在按钮添加一个点击事件执行updateUser方法,方法里面将:visible.sync绑定的值改为true

    <!-- 修改用户对话框 -->
    <el-dialog title="修改" :visible.sync="updateUserDialog" width="50%">
      <span>这是一段信息</span>
      <span slot="footer" class="dialog-footer">
        <el-button @click="updateUserDialog = false">取 消</el-button>
        <el-button type="primary" @click="updateUserDialog = false"
          >确 定</el-button
        >
      </span>
    </el-dialog>
data(){retrun:{
          updateUserDialog=false}}//修改用户updateUser(){//弹窗修改对话框this.updateUserDialog=true}

提交修改数据

//修改用户:请求修改用户返回成功还是失败updateUser(){//做表单验证this.$refs.updateUserRef.validate(async(validate)=>{if(!validate)returnthis.$message.error("请将信息填写正确!")try{const{data:req}=awaitthis.$http.put("/users/"+this.editUser.id,{email:this.editUser.email,mobile:this.editUser.mobile,})if(req.meta.status!==200)returnthis.$message.error("修改失败")//关闭弹窗this.updateUserDialog=false;//刷新用户列表this.getUserList();//返回提示returnthis.$message.success("修改成功!")}catch(e){this.$message.error("修改失败或超时!")}})},

用户清除

我们点击清除按钮后,要先弹出一个提示是否确认清除,以免用户误点导致清除。

我们在清除按钮地方添加一个点击事件,将id传递进去

           <!-- 清除按钮 -->
            <el-button
              type="danger"
              icon="el-icon-delete"
              size="mini"
              @click="deleteUser(acope.row.id)"
            ></el-button>

我们这里点击后先是弹出一个提示框,用户可以点击确定或者取消

这里用的是MessageBox 弹框,这里跟其他组件引入不同的是

我们要单独引入

  MessageBox
  
  Vue.prototype.$confirm=MessageBox.confirm
//用户清除点击asyncdeleteUser(id){// 参数一:提示信息,参数二,提示标题,参数三:显示按钮,//当我们点击确定按钮或者取消按钮后会返回两个字符串//确定:confirm,取消:cancelconst req =awaitthis.$confirm("此操作将永久删除该用户, 是否继续?","提示",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning",//这里点击取消会执行一个错误提示,我们将他捕捉一下}).catch(err=>err)//判断用户是否点击的是确定按钮if(req=="confirm"){//发送清除请求const{data:req}=awaitthis.$http.delete("/users/"+id);//判断是否清除成功if(req.meta.status!=200)returnthis.$message.error("清除失败!")//刷新用户列表this.getUserList();//界面提示this.$message.success("清除成功!")}},

分配角色

添加点击事件

            <!-- 分配角色按钮 effect表示主体,content提示文字,placement提示方向-->
            <el-tooltip effect="dark" content="分配角色" placement="top">
              <el-button
                type="warning"
                icon="el-icon-setting"
                size="mini"
                @click="roleUser(acope.row)"
              ></el-button>
            </el-tooltip>
// 获取角色列表asyncroleUser(row){this.UserInfo = row
      const{data: req }=awaitthis.$http.get("/roles")//判断是否成功if(req.meta.status !=200)returnthis.$message.error("获取权限失败!")this.rolesList = req.data
      this.rolesdialog =true},//设置角色asyncsetRole(){const{data: req }=awaitthis.$http.put(`/users/${this.UserInfo.id}/role`,{rid:this.rolesValue})//判断是否成功if(req.meta.status !=200)returnthis.$message.error("分配失败!")this.$message.success("分配成功!")this.rolesdialog =falsethis.getUserList()this.rolesValue=''},

用户列表完整代码

<template>
  <div>
    <!-- 面包屑导航 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/Home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>用户管理</el-breadcrumb-item>
      <el-breadcrumb-item>用户列表</el-breadcrumb-item>
    </el-breadcrumb>
    <!-- 卡片试图区 -->
    <el-card class="box-card">
      <!-- 搜索与添加 -->
      <el-row :gutter="20">
        <!-- :gutter="20"设置两栏间距 设置这一栏大小 -->
        <el-col :span="8">
          <!-- 搜索与添加区域 -->
          <el-input
            placeholder="请输入内容"
            v-model="queryInfo.query"
            clearable
            @clear="getUserList"
          >
            <el-button
              slot="append"
              icon="el-icon-search"
              @click="getUserList"
            ></el-button>
          </el-input>
        </el-col>
        <el-col :span="4">
          <!-- 按钮 -->
          <el-button type="primary" @click="addUservisiblesync = true"
            >添加用户</el-button
          >
        </el-col>
      </el-row>

      <!-- 用户数据表格 -->
      <el-table :data="userList" border stripe>
        <!-- :data表示获取用户数组 border纵向边框 stripe斑马纹 table -->
        <!-- el-table-column每一列数据 label列头部标题 prop列内容数据 -->
        <el-table-column type="index" label="#"></el-table-column>
        <el-table-column label="用户名" prop="username"></el-table-column>
        <el-table-column label="邮箱" prop="email"></el-table-column>
        <el-table-column label="电话" prop="mobile"></el-table-column>
        <el-table-column label="角色" prop="role_name"></el-table-column>
        <el-table-column label="状态">
          <!-- 我们创建一个作用域插槽模板来写一个开关按钮 通过slot-scope="scope"来接收当前一行对象数据-->
          <template slot-scope="values">
            <!-- 可以通过scope.row获取当前一行对象,通过.对象中的参数可以获取对应的值 -->
            <!-- {{ values.row.mg_state }} -->
            <!-- 定义一个开关按钮,v-mode的值为true,false,对应开还是关 -->
            <el-switch
              v-model="values.row.mg_state"
              @change="userStateChanged(values.row)"
            >
            </el-switch>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="180px">
          <template slot-scope="acope">
            <!-- 修改按钮 -->
            <el-button
              type="primary"
              icon="el-icon-edit"
              size="mini"
              @click="queryUserByid(acope.row.id)"
            ></el-button>
            <!-- 清除按钮 -->
            <el-button
              type="danger"
              icon="el-icon-delete"
              size="mini"
              @click="deleteUser(acope.row.id)"
            ></el-button>
            <!-- 分配角色按钮 effect表示主体,content提示文字,placement提示方向-->
            <el-tooltip effect="dark" content="分配角色" placement="top">
              <el-button
                type="warning"
                icon="el-icon-setting"
                size="mini"
                @click="roleUser(acope.row)"
              ></el-button>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>

      <!-- 分页区域 -->
      <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="queryInfo.pagenum"
        :page-sizes="[10, 20, 50, 100]"
        :page-size="queryInfo.pagesize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="usertotal"
      >
        <!-- @size-change="handleSizeChange" 表示切换了每页条数的菜单会触发handleSizeChange方法函数 ,在这个函数中可以拿到最新的每页条数-->
        <!-- @current-change="handleCurrentChange"    页码值发生了切换会触发handleCurrentChange方法函数 -->
        <!-- :current-page="currentPage4" 当前显示的是第几页数据 -->
        <!-- :page-sizes="[100, 200, 300, 400]" 下拉菜单显示可以切换显示多少条数据 -->
        <!-- :page-size="100" 当前每页显示多少条数据-->
        <!-- layout 组件布局显示那些功能,比如每页显示多少条数据的下拉菜单 -->
        <!-- :total="400" 数据总数 -->
      </el-pagination>
    </el-card>

    <!-- 添加用户对话框 -->
    <el-dialog
      title="提示"
      :visible.sync="addUservisiblesync"
      width="50%"
      @close="addUserClose"
    >
      <!--title:弹窗标题:visible.sync:表示是否显示width:弹窗大小-->
      <!--弹窗主体区域-->
      <el-form
        :model="addUserForm"
        :rules="addUserFormrules"
        ref="ruleAddUserForm"
        label-width="70px"
      >
        <!-- :model绑定表单对象,rules校验规则,ref表示当前表单对象 -->
        <el-form-item label="用户名" prop="username">
          <el-input v-model="addUserForm.username"></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <el-input v-model="addUserForm.password"></el-input>
        </el-form-item>
        <el-form-item label="邮箱" prop="email">
          <el-input v-model="addUserForm.email"></el-input>
        </el-form-item>
        <el-form-item label="手机号" prop="mobile">
          <el-input v-model="addUserForm.mobile"></el-input>
        </el-form-item>
      </el-form>
      <!--底部按钮组件-->
      <span slot="footer" class="dialog-footer">
        <!--点击取消将addUservisiblesync修改为false 这样弹窗就会消失-->
        <el-button @click="addUservisiblesync = false">取 消</el-button>
        <el-button type="primary" @click="addUser">确 定</el-button>
      </span>
    </el-dialog>

    <!-- 修改用户对话框 -->
    <el-dialog
      title="修改"
      :visible.sync="updateUserDialog"
      width="50%"
      @close="updateUserClose"
    >
      <!-- 修改用户表单 -->
      <el-form
        ref="updateUserRef"
        :model="editUser"
        :rules="addUserFormrules"
        label-width="80px"
      >
        <el-form-item label="用户名">
          <el-input v-model="editUser.username" :disabled="true"></el-input>
        </el-form-item>
        <el-form-item label="邮箱" prop="email">
          <el-input v-model="editUser.email"></el-input>
        </el-form-item>
        <el-form-item label="手机号" prop="mobile">
          <el-input v-model="editUser.mobile"></el-input>
        </el-form-item>
      </el-form>

      <span slot="footer" class="dialog-footer">
        <el-button @click="updateUserDialog = false">取 消</el-button>
        <el-button type="primary" @click="updateUser">确 定</el-button>
      </span>
    </el-dialog>

    <!-- 分配角色 -->
    <el-dialog title="分配角色" :visible.sync="rolesdialog" width="50%">
      <el-form label-width="80px">
        <el-form-item label="用户名">
          <el-input :disabled="true" v-model="UserInfo.username"></el-input>
        </el-form-item>
        <el-form-item label="用户名">
          <el-input :disabled="true" v-model="UserInfo.role_name"></el-input>
        </el-form-item>
        <el-form-item label="切换角色">
          <el-select v-model="rolesValue" placeholder="请选择">
            <el-option
              v-for="(item, index) in rolesList"
              :key="index"
              :label="item.roleName"
              :value="item.id"
            >
            </el-option>
          </el-select>
        </el-form-item>
      </el-form>

      <span slot="footer" class="dialog-footer">
        <el-button @click="rolesdialog = false">取 消</el-button>
        <el-button type="primary" @click="setRole">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
import { MessageBox } from "element-ui"
export default {
  data() {
    return {
      rolesList: [],
      rolesValue: "",

      //存放用户数据的数组
      userList: [],
      //存放用户总数的数据
      usertotal: 0,
      //请求用户数据传递的参数
      queryInfo: {
        query: "",
        // 当前页数
        pagenum: 1,
        // 显示多少条数据
        pagesize: 10,
      },
      //添加用户弹窗
      addUservisiblesync: false,
      //修改用户弹窗
      updateUserDialog: false,
      //用户信息
      UserInfo: {},
      // 添加用户form表单对象
      addUserForm: {
        username: "",
        password: "",
        email: "",
        mobile: "",
      },
      //修改用户,查询到的用户信息保存对象
      editUser: {},
      //分配角色弹窗
      rolesdialog: false,

      //用户表单校验规则
      addUserFormrules: {
        username: [
          { required: true, message: "请输入用户名", trigger: "blur" },
          { min: 4, max: 18, message: "长度在 4 到 18 位", trigger: "blur" },
        ],
        password: [
          { required: true, message: "请输入密码", trigger: "blur" },
          { min: 4, max: 18, message: "长度在 6 到 18 位", trigger: "blur" },
        ],
        email: [
          { required: true, message: "请输入邮箱地址", trigger: "blur" },
          {
            type: "email",
            message: "请输入正确的邮箱地址",
            trigger: ["blur", "change"],
          },
        ],
        mobile: [
          { required: true, message: "请输入手机号", trigger: "blur" },
          { min: 11, max: 11, message: "长度在11位", trigger: "blur" },
        ],
      },
    }
  },
  created() {
    //第一时间调用获取用户数据
    this.getUserList()
  },
  methods: {
    //通过axios获取用户数据
    async getUserList() {
      // get 传递参数{params:参数对象{a:1,b:2}}
      try {
        const { data: req } = await this.$http.get("/users", {
          params: this.queryInfo,
        })
        // console.log(userList)
        if (req.meta.status !== 200)
          return this.$message.error("获取用户数据失败!")
        // 将用户数组存放进data中的userList数组
        this.userList = req.data.users
        // 将用户总数存放usertotal
        this.usertotal = req.data.total
        // console.log(this.userList)
      } catch (e) {
        return this.$message.error("获取用户数据失败!")
      }
    },

    //当页面切换显示多少条数据时会触发并接收选择的多少条数据
    handleSizeChange(newSize) {
      //用户切换每页显示多少条数据,我们修改data中的属性
      this.queryInfo.pagesize = newSize
      //设置完每页显示多少条数据后,重新获取一次每页显示多少条的数据
      this.getUserList()
    },

    // 当页码值发生了切换会触发并接收切换的页面值
    handleCurrentChange(newPage) {
      //设置当前页面
      this.queryInfo.pagenum = newPage
      //设置完当前页码后重新获取当前设置完的页面的数据
      this.getUserList()
    },
    //状态按钮点击后执行这个函数方法,来修改用户状态函数
    async userStateChanged(user_Row) {
      //put请求
      const { data: req } = await this.$http.put(
        "/users/" + user_Row.id + "/state/" + user_Row.mg_state
      )
      // 如果修改失败
      if (req.meta.status !== 200) {
        // 当我们点击按钮后会直接在本地改成false/true,但是数据库没有修改成功,我们将本地的修改为原来的boolen
        user_Row.mg_state = !user_Row.mg_state
        // 发送提示信息
        return this.$message.error("修改用户状态失败!")
      }
      // 如果修改成功,我们发送提示信息
      this.$message.success("更新用户状态成功!")
    },
    //监听用户对话框关闭事件,添加用户对话关闭后执行,将添加用户的v-model绑定的值重置清空
    addUserClose() {
      // 通过refs获取页面定义的ref属性(当前对象)然后执行resetFields方法
      this.$refs.ruleAddUserForm.resetFields()
    },
    async addUser() {
      //添加用户请求
      const { data: req } = await this.$http.post("/users", this.addUserForm)
      //添加失败
      if (req.meta.status !== 201) return this.$message.error("添加用户失败!")
      //添加成功
      this.$message.success("添加成功!")
      //关闭弹窗
      this.addUservisiblesync = false
      //重新请求加载用户数据
      this.getUserList()
    },
    //通过id查询用户信息
    async queryUserByid(id) {
      try {
        const { data: req } = await this.$http.get("/users/" + id)
        //弹窗修改对话框
        if (req.meta.status !== 200)
          return this.$message.error("获取用户数据失败!")
        this.editUser = req.data
        console.log(this.editUser)
        this.updateUserDialog = true
      } catch (e) {
        return this.$message.error("获取用户数据超时!")
      }
    },

    //监听修改用户的弹窗关闭后执行的方法
    updateUserClose() {
      //通过this.$ref获取当前表单updateUserRef然后执行resetFields方法
      this.$refs.updateUserRef.resetFields()
    },
    //修改用户:请求修改用户返回成功还是失败
    updateUser() {
      //做表单验证
      this.$refs.updateUserRef.validate(async (validate) => {
        if (!validate) return this.$message.error("请将信息填写正确!")
        try {
          const { data: req } = await this.$http.put(
            "/users/" + this.editUser.id,
            {
              email: this.editUser.email,
              mobile: this.editUser.mobile,
            }
          )
          if (req.meta.status !== 200) return this.$message.error("修改失败")
          //关闭弹窗
          this.updateUserDialog = false
          //刷新用户列表
          this.getUserList()
          //返回提示
          return this.$message.success("修改成功!")
        } catch (e) {
          this.$message.error("修改失败或超时!")
        }
      })
    },
    //用户清除点击
    async deleteUser(id) {
      // 参数一:提示信息,参数二,提示标题,参数三:显示按钮,
      //当我们点击确定按钮或者取消按钮后会返回两个字符串
      //确定:confirm,取消:cancel
      const req = await this.$confirm(
        "此操作将永久删除该用户, 是否继续?",
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning",
          //这里点击取消会执行一个错误提示,我们将他捕捉一下
        }
      ).catch((err) => err)
      //判断用户是否点击的是确定按钮
      if (req == "confirm") {
        //发送清除请求
        const { data: req } = await this.$http.delete("/users/" + id)
        //判断是否清除成功
        if (req.meta.status != 200) return this.$message.error("清除失败!")
        //刷新用户列表
        this.getUserList()
        //界面提示
        this.$message.success("清除成功!")
      }
    },
    // 获取角色列表
    async roleUser(row) {
      //将传递的row存放在data数据中
      this.UserInfo = row
      //请求获取角色列表
      const { data: req } = await this.$http.get("/roles")
      //判断是否成功
      if (req.meta.status != 200)
      //判断失败
        return this.$message.error("获取权限失败!")
        //将角色列表存放在data中
      this.rolesList = req.data
      //将弹窗关闭
      this.rolesdialog = true
    },
    //设置角色
    async setRole() {
      //请求设置角色
      const { data: req } = await this.$http.put(
        `/users/${this.UserInfo.id}/role`,
        {rid: this.rolesValue}
      )
      //判断是否成功
      if (req.meta.status != 200)return this.$message.error("分配失败!")
      //提示信息
      this.$message.success("分配成功!")
      //关闭弹窗
      this.rolesdialog = false
      //刷新用户数据
      this.getUserList()
      //将默认选中的value清空以防下次覆盖
      this.rolesValue=''
    },
  },
}
</script>

<style scoped></style>

权限管理

权限列表

注册router路由

{path:"/rights",name:"Righs",component:()=>import("../components/power/Rights.vue"),},
<template>
  <div>
    <!-- 面包屑导航 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/Home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>权限管理</el-breadcrumb-item>
      <el-breadcrumb-item>权限列表</el-breadcrumb-item>
    </el-breadcrumb>
    <!-- 卡片视图 -->
    <el-card>
      <!-- table表格 :data表示对应的数据源 -->
      <el-table :data="rightsList">
        <el-table-column label="#" type="index"></el-table-column>
        <!-- label表格 label表示头部 prop表示数据源属性-->
        <el-table-column label="权限名称" prop="authName"></el-table-column>
        <el-table-column label="路径" prop="path"></el-table-column>
        <el-table-column label="权限等级">
          <template slot-scope="scope">
            <el-tag v-if="scope.row.level == 0">一级</el-tag>
            <el-tag v-else-if="scope.row.level == 1" type="success"
              >二级</el-tag
            >
            <el-tag v-else type="danger">三级</el-tag>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
  </div>
</template>
<script>
export default {
  data() {
    return {
      //权限列表
      rightsList: [],
    }
  },
  created() {
    //获取权限列表
    this.getrightsList()
  },
  methods: {
      //请求权限信息
    async getrightsList() {
      const { data: req } = await this.$http.get("/rights/list")
      if (req.meta.status !== 200) return this.$message.error("获取数据失败!")
      this.rightsList = req.data
    },
  },
}
</script>
<style scoped></style>

这里运用了Tag标签,element.js引入

Tag
Vue.use(Tag)

角色列表

image-20211213195037742

获取角色列表

<template>
  <div>
    <!-- 面包屑导航 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/Home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>权限管理</el-breadcrumb-item>
      <el-breadcrumb-item>角色列表</el-breadcrumb-item>
    </el-breadcrumb>
    <!-- 卡片视图 -->
    <el-card>
      <!-- 添加角色按钮 -->
      <el-row>
        <el-button type="primary">添加角色</el-button>
      </el-row>
      <!-- 角色列表视图 -->
      <el-table :data="roleList" border stripe>
        <!-- 索引列 -->
        <el-table-column label="#" type="index"></el-table-column>
        <el-table-column label="角色名称" prop="roleName"></el-table-column>
        <el-table-column label="角色描述" prop="roleDesc"></el-table-column>
        <el-table-column label="操作" width="300px">
          <template slot-scope="">
            <el-button type="primary" icon="el-icon-edit" size="mini">编辑</el-button>
            <el-button type="danger" icon="el-icon-delete"  size="mini">清除</el-button>
            <el-button type="warning" icon="el-icon-setting"  size="mini">分配权限</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
  </div>
</template>
<script>
export default {
  data() {
    return {
      //所以角色列表数据
      roleList: [],
    }
  },
  created() {
    this.getroleList()
  },
  methods: {
    //请求全部角色列表信息
    async getroleList() {
      const { data: req } = await this.$http.get("/roles")
      if(req.meta.status!==200)return this.$message.error("获取数据失败!")
      this.roleList=req.data
    },
  },
}
</script>
<style scoped></style>

image-20211213203708784

实现展开列

我们这里有三级权限,有多个一级权限,一级权限对应多个二级权限,二级权限对应多个三级权限

所以这里我们使用for循环嵌套三层

每循环一个一级权限,都会将这个一级权限包含的二级三级全部循环出来

我们直接渲染即可

<el-row
              :class="[
                item1 == 0 ? '' : 'bordertop',
                'borderbottom',
                'vcenter',
              ]"
              v-for="(item1, index) in scope.row.children"
              :key="index"
            >
    <!-- 占位符,将所有表格将右移动一格 可忽略-->
              <el-col :span="1"></el-col>
    
              <!-- 渲染一级权限 -->
              <el-col :span="5">
                <el-tag
                  closable
                  @close="removeRightById(scope.row, item1.id)"
                  >{{ item1.authName }}</el-tag
                >
                <i class="el-icon-caret-right"></i>
              </el-col>
              <!-- 通过一级权限下children,的渲染二级权限 -->
              <el-col :span="18">
                <!-- 通过for循环嵌套 -->
                <el-row
                  v-for="(item2, index) in item1.children"
                  :key="index"
                  :class="[item2 == 0 ? '' : 'bordertop', 'vcenter']"
                >
                  <!-- 渲染二级权限 -->
                  <el-col :span="6">
                    <el-tag
                      closable
                      @close="removeRightById(scope.row, item2.id)"
                      type="success"
                      >{{ item2.authName }}</el-tag
                    >
                    <i class="el-icon-caret-right"></i>
                  </el-col>
                  <!-- 渲染三级权限 -->
                  <el-col :span="18">
                    <el-tag
                      type="warning"
                      closable
                      @close="removeRightById(scope.row, item3.id)"
                      v-for="(item3, index) in item2.children"
                      :key="index"
                      >{{ item3.authName }}</el-tag
                    >
                  </el-col>
                </el-row>
              </el-col>
            </el-row>

完整代码

<template>
  <div>
    <!-- 面包屑导航 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/Home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>权限管理</el-breadcrumb-item>
      <el-breadcrumb-item>角色列表</el-breadcrumb-item>
    </el-breadcrumb>
    <!-- 卡片视图 -->
    <el-card>
      <!-- 添加角色按钮 -->
      <el-row>
        <el-button type="primary">添加角色</el-button>
      </el-row>
      <!-- 角色列表视图 -->
      <el-table :data="roleList" border stripe>
        <!-- 展开列 -->
        <el-table-column type="expand">
          <template slot-scope="scope">
            <!-- 栅格系统 将页面切割24份 -->
            <el-row
              :class="[
                item1 == 0 ? '' : 'bordertop',
                'borderbottom',
                'vcenter',
              ]"
              v-for="(item1, index) in scope.row.children"
              :key="index"
            >
              <el-col :span="1"></el-col>
              <!-- 渲染一级权限 -->
              <el-col :span="5">
                <el-tag
                  closable
                  @close="removeRightById(scope.row, item1.id)"
                  >{{ item1.authName }}</el-tag
                >
                <i class="el-icon-caret-right"></i>
              </el-col>
              <!-- 渲染二级权限 -->
              <el-col :span="18">
                <!-- 通过for循环嵌套 -->
                <el-row
                  v-for="(item2, index) in item1.children"
                  :key="index"
                  :class="[item2 == 0 ? '' : 'bordertop', 'vcenter']"
                >
                  <!-- 渲染二级权限 -->
                  <el-col :span="6">
                    <el-tag
                      closable
                      @close="removeRightById(scope.row, item2.id)"
                      type="success"
                      >{{ item2.authName }}</el-tag
                    >
                    <i class="el-icon-caret-right"></i>
                  </el-col>
                  <!-- 渲染三级权限 -->
                  <el-col :span="18">
                    <el-tag
                      type="warning"
                      closable
                      @close="removeRightById(scope.row, item3.id)"
                      v-for="(item3, index) in item2.children"
                      :key="index"
                      >{{ item3.authName }}</el-tag
                    >
                  </el-col>
                </el-row>
              </el-col>
            </el-row>
          </template>
        </el-table-column>
        <!-- 索引列 -->
        <el-table-column label="#" type="index"></el-table-column>
        <el-table-column label="角色名称" prop="roleName"></el-table-column>
        <el-table-column label="角色描述" prop="roleDesc"></el-table-column>
        <el-table-column label="操作" width="300px">
          <template slot-scope="">
            <el-button type="primary" icon="el-icon-edit" size="mini"
              >编辑</el-button
            >
            <el-button type="danger" icon="el-icon-delete" size="mini"
              >清除</el-button
            >
            <el-button type="warning" icon="el-icon-setting" size="mini"
              >分配权限</el-button
            >
          </template>
        </el-table-column>
      </el-table>
    </el-card>
  </div>
</template>
<script>
export default {
  data() {
    return {
      //所以角色列表数据
      roleList: [],
    }
  },
  created() {
    this.getroleList()
  },
  methods: {
    //获取角色列表
    async getroleList() {
      const { data: req } = await this.$http.get("/roles")
      if (req.meta.status !== 200) return this.$message.error("获取数据失败!")
      this.roleList = req.data
    },
    //根据id清除对应的权限
    async removeRightById(role, rightsid) {
      const res = await this.$confirm(
        "此操作将永久删除该用户, 是否继续?",
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning",
          //这里点击取消会执行一个错误提示,我们将他捕捉一下
        }
      ).catch((err) => err)
      //判断用户是否点击的是确定按钮
      if (res == "confirm") {
        //发送清除请求
        const { data: req } = await this.$http.delete(
          `roles/${role.id}/rights/${rightsid}`
        )
        //判断是否清除成功
        if (req.meta.status != 200) return this.$message.error("清除失败!")
        //刷新用户列表
        role.children = req.data
        //界面提示
        this.$message.success("清除成功!")
      }
    },
  },
}
</script>
<style scoped>
.el-tag {
  margin: 7px;
}
.bordertop {
  border-top: 1px solid #eee;
}
.borderbottom {
  border-bottom: 1px solid #eee;
}
.vcenter {
  display: flex;
  align-items: center;
}
</style>

角色分配权限

添加点击事件

            <el-button
              type="warning"
              icon="el-icon-setting"
              size="mini"
              @click="showSetRightDialog(scope.row)"
              >分配权限</el-button
            >
//分配权限加载树形控件asyncshowSetRightDialog(row){//将角色id赋值给data中的roleId,方便点击其他函数调用this.roleId=row.id
      //先获取当前所有权限在弹出对话框const{data: req }=awaitthis.$http.get("rights/tree")if(req.meta.status !==200)returnthis.$message.error("获取失败!")//将获取到的权限保存进权限列表this.rightsList = req.data
      //调用递归函数获取第三层的权限idthis.getLeafkeys(row,this.defkeys)//打开弹出框this.dialogVisible =true},//通过递归获取当前下所有的三级权限idgetLeafkeys(node, arr){//如果当前data数据不包含children属性,则是三级节点if(!node.children){return arr.push(node.id)}//如果当前右children属性表示不是三级权限id继续调用本方法继续循环
      node.children.forEach((item)=>this.getLeafkeys(item, arr))},//弹出框关闭后将树杈属性清空,否者再次会打开其他的会覆盖属性Dialogclose(){//将权限节点id数组清空this.defkeys =[]},// 为角色分配权限asyncallotRights(){//获取当前树杈全部选中的idconst kyes =[//获取一级和二级的权限id...this.$refs.treeRef.getCheckedKeys(),//获取三级的权限id...this.$refs.treeRef.getHalfCheckedKeys()]//将树杈选中的权限id解析成字符串以逗号(,)分割 例如1,2,3,4,5const idStr = kyes.join(",")//发送修改请求  this.roleId 从data中取的,从按钮中没有办法取,所以我们定义一个属性,在用户点击分配角色时加载树形控件(showSetRightDialog)时将角色id赋值一下const{data: req }=awaitthis.$http.post(`roles/${this.roleId}/rights`,{rids:idStr})if(req.meta.status !==200)returnthis.$message.error("获取失败!")this.$message.success("分配成功!")this.getroleList()this.dialogVisible=false},},

完整代码

角色列表代码
<template>
  <div>
    <!-- 面包屑导航 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/Home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>权限管理</el-breadcrumb-item>
      <el-breadcrumb-item>角色列表</el-breadcrumb-item>
    </el-breadcrumb>

    <!-- 卡片视图 -->
    <el-card>
      <!-- 添加角色按钮 -->
      <el-row>
        <el-button type="primary">添加角色</el-button>
      </el-row>
      <!-- 角色列表视图 -->
      <el-table :data="roleList" border stripe>
        <!-- 展开列 -->
        <el-table-column type="expand">
          <template slot-scope="scope">
            <!-- 栅格系统 将页面切割24份 -->
            <el-row
              :class="[
                item1 == 0 ? '' : 'bordertop',
                'borderbottom',
                'vcenter',
              ]"
              v-for="(item1, index) in scope.row.children"
              :key="index"
            >
              <el-col :span="1"></el-col>
              <!-- 渲染一级权限 -->
              <el-col :span="5">
                <el-tag
                  closable
                  @close="removeRightById(scope.row, item1.id)"
                  >{{ item1.authName }}</el-tag
                >
                <i class="el-icon-caret-right"></i>
              </el-col>
              <!-- 渲染二级权限 -->
              <el-col :span="18">
                <!-- 通过for循环嵌套 -->
                <el-row
                  v-for="(item2, index) in item1.children"
                  :key="index"
                  :class="[item2 == 0 ? '' : 'bordertop', 'vcenter']"
                >
                  <!-- 渲染二级权限 -->
                  <el-col :span="6">
                    <el-tag
                      closable
                      @close="removeRightById(scope.row, item2.id)"
                      type="success"
                      >{{ item2.authName }}</el-tag
                    >
                    <i class="el-icon-caret-right"></i>
                  </el-col>
                  <!-- 渲染三级权限 -->
                  <el-col :span="18">
                    <el-tag
                      type="warning"
                      closable
                      @close="removeRightById(scope.row, item3.id)"
                      v-for="(item3, index) in item2.children"
                      :key="index"
                      >{{ item3.authName }}</el-tag
                    >
                  </el-col>
                </el-row>
              </el-col>
            </el-row>
          </template>
        </el-table-column>
        <!-- 索引列 -->
        <el-table-column label="#" type="index"></el-table-column>
        <el-table-column label="角色名称" prop="roleName"></el-table-column>
        <el-table-column label="角色描述" prop="roleDesc"></el-table-column>
        <el-table-column label="操作" width="300px">
          <template slot-scope="scope">
            <el-button type="primary" icon="el-icon-edit" size="mini"
              >编辑</el-button
            >
            <el-button type="danger" icon="el-icon-delete" size="mini"
              >清除</el-button
            >
            <el-button
              type="warning"
              icon="el-icon-setting"
              size="mini"
              @click="showSetRightDialog(scope.row)"
              >分配权限</el-button
            >
          </template>
        </el-table-column>
      </el-table>
    </el-card>

    <!-- 弹出对话框 -->
    <el-dialog
      title="提示"
      :visible.sync="dialogVisible"
      width="50%"
      @close="Dialogclose()"
    >
      <!-- 树形控件 -->
      <el-tree
        show-checkbox
        :data="rightsList"
        ref="treeRef"
        :props="defaultProps"
        default-expand-all
        node-key="id"
        :default-checked-keys="defkeys"
      ></el-tree>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="allotRights()">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
export default {
  data() {
    return {
      //弹出对话框
      dialogVisible: false,
      //所以角色列表数据
      roleList: [],
      //所有权限列表数据
      rightsList: [],
      defaultProps: {
        children: "children",
        label: "authName",
      },
      // 默认选中的权限节点Id值数组
      defkeys: [],
      //当前角色ID
      roleId:''
    }
  },
  created() {
    this.getroleList()
  },
  methods: {
    //获取角色列表
    async getroleList() {
      const { data: req } = await this.$http.get("/roles")
      if (req.meta.status !== 200) return this.$message.error("获取数据失败!")
      this.roleList = req.data
    },
    //根据id清除对应的权限
    async removeRightById(role, rightsid) {
      const res = await this.$confirm(
        "此操作将永久删除该用户, 是否继续?",
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning",
          //这里点击取消会执行一个错误提示,我们将他捕捉一下
        }
      ).catch((err) => err)
      //判断用户是否点击的是确定按钮
      if (res == "confirm") {
        //发送清除请求
        const { data: req } = await this.$http.delete(
          `roles/${role.id}/rights/${rightsid}`
        )
        //判断是否清除成功
        if (req.meta.status != 200) return this.$message.error("清除失败!")
        //刷新用户列表
        role.children = req.data
        //界面提示
        this.$message.success("清除成功!")
      }
    },
    //分配权限加载树形控件
    async showSetRightDialog(row) {
      //将角色id赋值给data中的roleId,方便点击其他函数调用
      this.roleId=row.id
      //先获取当前所有权限在弹出对话框
      const { data: req } = await this.$http.get("rights/tree")
      if (req.meta.status !== 200) return this.$message.error("获取失败!")
      //将获取到的权限保存进权限列表
      this.rightsList = req.data
      //调用递归函数获取第三层的权限id
      this.getLeafkeys(row, this.defkeys)

      //打开弹出框
      this.dialogVisible = true
    },
    //通过递归获取当前下所有的三级权限id
    getLeafkeys(node, arr) {
      //如果当前data数据不包含children属性,则是三级节点
      if (!node.children) {
        return arr.push(node.id)
      }
      //如果当前右children属性表示不是三级权限id继续调用本方法继续循环
      node.children.forEach((item) => this.getLeafkeys(item, arr))
    },
    //弹出框关闭后将树杈属性清空,否者再次会打开其他的会覆盖属性
    Dialogclose() {
      //将权限节点id数组清空
      this.defkeys = []
    },
    // 为角色分配权限
    async allotRights() {
      //获取当前树杈全部选中的id
      const kyes = [
        //获取一级和二级的权限id
        ...this.$refs.treeRef.getCheckedKeys(),
        //获取三级的权限id
        ...this.$refs.treeRef.getHalfCheckedKeys()
      ]
      //将树杈选中的权限id解析成字符串以逗号(,)分割 例如1,2,3,4,5
      const idStr = kyes.join(",")
      //发送修改请求  this.roleId 从data中取的,从按钮中没有办法取,所以我们定义一个属性,在用户点击分配角色时加载树形控件(showSetRightDialog)时将角色id赋值一下
      const { data: req } = await this.$http.post(`roles/${this.roleId}/rights`,{rids:idStr})
      if (req.meta.status !== 200) return this.$message.error("获取失败!")
      this.$message.success("分配成功!")
      this.getroleList()
      this.dialogVisible=false
    },
  },
}
</script>
<style scoped>
.el-tag {
  margin: 7px;
}
.bordertop {
  border-top: 1px solid #eee;
}
.borderbottom {
  border-bottom: 1px solid #eee;
}
.vcenter {
  display: flex;
  align-items: center;
}
</style>

权限列表

<template>
  <div>
    <!-- 面包屑导航 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
     

本文转载自: https://blog.csdn.net/oemciemcier/article/details/126031953
版权归原作者 杨星辰Red 所有, 如有侵权,请联系我们删除。

“Vue框架教程-从入门到项目实战”的评论:

还没有评论