电商后台管理系统(前端)

前言

跟着编写电商后台管理系统时总是囫囵吞枣照抄代码却没有自己的思考,于是我将要复盘自己所学习的内容,进一步巩固和加深对知识理解,也为我后续遗忘时查找提供帮助

一、配置环境

在vue2中引入element-ui、axios、router

① 引入element-ui

1、安装
打开终端输入
npm i element-ui -S
2、全局引入element-ui
在main.js中写入

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

Vue.use(ElementUI);

②引入axios

1、安装
打开终端输入
npm i axios -S
2、全局引入axios(未封装)

import axios from "axios"
axios.defaults.baseURL = '<url>'
Vue.prototype.$http = axios//挂载到原型对象上

③引入router

1、安装
打开终端输入
npm install vue-router@3
2、全局引入router

import VueRouter from 'vue-router'
Vue.use(VueRouter);

3、创建router文件夹并暴露路由
在这里插入图片描述
在index文件夹写入

import Vue from 'vue'

//专门创建整个项目的路由
import VueRouter from 'vue-router'

import Login from '../components/Login'


Vue.use(VueRouter)

//创建并暴露一个路由器
const router  = new VueRouter({
	routes: [
		{ path: '/', redirect:'/login'},
		{ path: '/login', component: Login},
	]
})
export default router

在入口引入

import reuter from './router/index.js'

并在原型对象上写入

router:reuter

二、登录组件的实现

登录布局与实现

①登录布局

<div class="mei">
  		<div class="login-box">
  			<!-- 头像区域 -->
  			<div class="ava">
  				<img src="../assets/logo.png" alt="">
  			</div>
  			<!-- 登录表单区域 -->
  			<el-form   label-width="80px" class="ff">
  				<!-- 用户名  -->
  				<el-form-item >
  					<el-input  type="text" placeholder="请输入用户名" prop="username"
  						class="ipt1" prefix-icon="el-icon-user-solid">
  					</el-input>
  				</el-form-item>
  				<!-- 密码 -->
  				<br>
  				<br>
  				<el-form-item >
  					<el-input type="password" placeholder="请输如密码" class="ipt2"
  						prefix-icon="el-icon-lock">
  					</el-input>
					<br>
					<br>
					  
					
  				</el-form-item>
  				<!--  按钮 -->
  				
  <el-button type="primary" >登录</el-button>
  <el-button type="into" >重置</el-button>
  			</el-form>
  		</div>
  
  	</div>
.mei {
			height: 100%;
		}
		.login-box {
			width: 450px;
			height: 300px;
			background-color: #fff;
			border-radius: 3px;
			position: absolute;
			left: 50%;
			top: 50%;
			transform: translate(-50%, -50%);
			border-color: black;
		}
	
		.ava {
			height: 130px;
			width: 130px;
			border: 1px solid #eee;
			border-radius: 50%;
			padding: 10px;
			box-shadow: 0 0 10px #ddd;
			position: absolute;
			left: 50%;
			transform: translate(-50%, -50%);
			background-color: #fff;
		}
	
		img {
			height: 100%;
			width: 100%;
			border-radius: 50%;
			background-color: #fff;
	
		}
		.ff {
				position: absolute;
				bottom: 0;
				width: 50%;
				height: 68%;
				/* padding: 0 100px; */
				text-align: center;
				border-color: black;
			}
		.el-button{
			text-align: center;
			align-content: center;
		}
		
			.ipt1,
			.ipt2 {
				width: 250px;
				height: 26px;
				padding: 0px;
			}

②登录组件表单的数据绑定

1.在data写入

from:{			
	username:'admin',
	password:'123456'
	 } 

名称与后端接口一致
2.为el-form加入 :model=“from” 进行数据绑定

3.为登录和密码的el-input分别加入v-model="from.username"和v-model="from.password"进行数据绑定

4.实现表单验证
为el-form绑定:rules:“rules”
通过属性绑定在登录和密码的el-form-item分别绑定prop=“username”

prop=“password”
其值为表单的验证规则在data里写入

//表单验证规则
				rules: {
					username: [{//名字要与from中的名字一致
							required: true,//这项为必选项
							message: '请输入用户名',//错误提示
							trigger: 'blur'//当鼠标失去焦点时触发
						},
						{
							min: 5,//最小长度
							max: 11,//最大长度
							message: '请输入正确用户名',
							trigger: 'blur'
						}
					],
					password: [{
							required: true,
							message: '请输入密码',
							trigger: 'blur'
						},
						{
							min: 6,
							max: 25,
							message: '密码不少于6位数',
							trigger: 'blur'
						}
					]
				}

③实现表单的重置

为重置按钮绑定一个单击事件@click=“resetFromLogin”
为from绑定ref="ruleFormRef"使得可以调用from表表单得重置方法
在这里插入图片描述
在methods中写入resetFromLogin方法

methods:{
			resetFromLogin(){
				this.$refs.ruleFormRef.resetFields()
				}
		},

④登录前的校验

为登录按钮绑定@click=“login”

login() {
				this.$refs.ruleFormRef.validate(async valid => {
					if (!valid) return;
					const {data:res} = await this.$http.post('/login',this.from,)
					// console.log(res)
					if (res.meta.status !== 200) return this.$message.error('用户名或密码错误');
					this.$message.success('登录成功');//弹窗
					window.sessionStorage.setItem("token", res.data.token)//将token放置浏览器缓存
					this.$router.push("/home")//成功后跳转到home页面
				})
			}
			

⑤路由导航守卫控制访问权限

在index.js加入

router.beforeEach((to, from, next)=>{
	//to代表将要访问的路径
	//from代表从哪个路劲跳转而来
	//next是一个函数,表示放行
	//next()放行  next('/login')强制跳转
	
	if(to.path === '/login') return next()
	//获取token
	const tokenStr = window.sessionStorage.getItem('token')//必须携带tiken值,否则返回login,token值在请求拦截器中添加
	if(!tokenStr) return next('/login')
	next()
	
})

⑥页面效果
在这里插入图片描述

三、主页面的实现

注: 在router的index.js中添加home路由规则

主页面的布局

①主页菜单布局

创建home vue文件

<el-container class="home-container">
		<!-- 头部区域 -->
		<el-header>
			<div>
				<span>电商后台管理系统</span>
			</div>
			<el-button type="info">退出</el-button>
		</el-header>
		<!-- 页面主体区 -->
		<el-container>
			<!-- 侧边栏  -->
			<el-aside >
				<div class="TextButton" >|||</div>
				<!-- 侧边栏菜单区域 -->
				 <el-menu
				      :default-active="activPath"
				      class="el-menu-vertical-demo"
				      background-color="#333744"
				      text-color="#fff"
				      active-text-color="#409EFF"
					  
					  >
					  <!-- 一级菜单 -->
				      <el-submenu >
				        <template slot="title">
				          <i class="el-icon-menu"></i>
				          <span>导航</span>
				        </template>
						<!-- 二级菜单 -->
						
				          <el-menu-item >
						  <i class="el-icon-menu"></i>
						  二级
						 </el-menu-item>
				      </el-submenu>			  
				    </el-menu>
			</el-aside>
			<!-- 右侧内容主题  -->
			<el-main>
				<!-- 路由占位符  -->
				<router-view></router-view>
			</el-main>
		</el-container>
	</el-container>
.home-container {
		height: 100%;
		width: 100%;
		position: fixed;
	}

	.el-header {
		background-color: #373d41;
		display: flex;
		justify-content: space-between;
		padding-left: 0;
		align-items: center;
		color: #eaedf1;
		font-size: 20px;
	}

	>div {
		display: flex;
		align-items: center;
	}

	.el-aside {
		background-color: #333744;
		
	}
	
	.el-main {
		background-color: #eaedf1;
	}
	
	.TextButton{
		background-color: #4a5064;
		font-size: 15px;
		line-height: 24px;
		color: aliceblue;
		text-align: center;
		letter-spacing: 0.2em;
		cursor: pointer;
	}

②通过接口获取菜单数据

通过axios请求拦截器添加token,保证拥有获取数据的权限

//axios请求拦截
axios.interceptors.request.use(config => {
	//为请求头对象,添加Token验证的Authorization
	console.log(config)
	config.headers.Authorization = window.sessionStorage.getItem('token')
	//最后必须return config
	return config
})

③实现退出功能

为退出按钮绑定事件

tuichu(){
				window.sessionStorage.clear()//清除token缓存
				this.$router.push('/login')//重定向
			},

④通过接口获取菜单数据

1.获取所有菜单

//获取所有菜单
			async getMenuList(){
			const {data: res}	= await this.$http.get('/menus')
			// console.log(res)
			if( res.meta.status !== 200) return this.$message.error();
			this.menulist = res.data;
			// console.log(this.menulist)
			}

定义空数组menulist将res.data值赋值给menulist
将其挂载到页面

created() {
			this.getMenuList()
		},

//检查res中的数据
在这里插入图片描述
2.一级菜单的渲染
在el-submenu进行遍历

:index="item.id + ''" v-for="item in menulist " :key="item.id"

将标签中替换为{{item.authName}}
定义对象

iconsobj:{
		'125':'el-icon-user-solid',
		'103':'el-icon-s-grid',
		'101':'el-icon-s-cooperation',
		'102':'el-icon-s-order',
		'145':'el-icon-s-marketing'
					},

其中前面数字为数组元素id
为一级菜单图标遍历此对象

<i :class="iconsobj[item.id]"></i>

3.二级菜单的渲染
在el-menu-item标签添加

<el-menu-item :index = " '/' + subitem.path" @click="savaNameStade('/' + subitem.path)" v-for="subitem in item.children" :key="subitem.id">
				  <i class="el-icon-menu"></i>
				  {{subitem.authName}}</el-menu-item>

定义

//被激活的链接地址
				activPath:'',

定义savaNameStade()函数

savaNameStade(activPath){
				window.sessionStorage.setItem("activPath",activPath)
				this.activPath = activPath
			},

挂载到created()钩子里

this.activPath = window.sessionStorage.getItem('activPath')

是否折叠菜单
添加点击事件
在这里插入图片描述
定义isCollapse:false,
添加方法

TextClick(){
	this.isCollapse = !this.isCollapse
			},

在el-menu添加和
折叠属性 :collapse=“isCollapse”
取消动画 :collapse-transition=“false”
激活导航时以index作为path作为路由进行跳转router=“true”

⑤用户列表开发

创建user
在这里插入图片描述

1.面包屑区域(搜索区域)

<div>
		<el-breadcrumb separator-class="el-icon-arrow-right">
		  <el-breadcrumb-item >首页</el-breadcrumb-item>
		  <el-breadcrumb-item>活动管理</el-breadcrumb-item>
		  <el-breadcrumb-item>活动列表</el-breadcrumb-item>
		  <el-breadcrumb-item>活动详情</el-breadcrumb-item>
		</el-breadcrumb>
	</div>

2.卡片视图区域

<!-- 卡片视图区域 -->
		<el-card class="box-card">
		 <!-- 搜索与添加区域 -->
		 			<el-row :gutter="28">
		 				<el-col :span="18">
		 					<el-input placeholder="请输入内容" class="input-with-select">
		 						<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>

3.获取用户列表


		
		created() {
			this.getUserList()
		},
		data(){
			return{
				//获取用户列表的参数对象
				queryInFo: {
					query: '',
					//当前页数
					pagenum: 1,
					//当前每页显示多少条数据
					pagesize: 2
				},
				userlist:[],
				total:''
			}
		},
		methods:{
			async getUserList(){
				const {data:res} = await this.$http.get('/users',{ params:this.queryInFo })
				if(res.meta.status !== 200) {return this.$message.error('获取用户列表失败')}
				this.userlist = res.data.users
				this.total = res.data.total
				console.log(res)
			}
			
		},
		
	

4.用户列表区域

<el-table
		      :data="userlist"
		      style="width: 100%">
		      <el-table-column
		        prop="username"
		        label="姓名"
		        width="180">
		      </el-table-column>
		      <el-table-column
		        prop="email"
		        label="邮箱"
		        width="180">
		      </el-table-column>
		      <el-table-column
		        prop="create_time"
		        label="电话"
				width="180">
		      </el-table-column>
			  <el-table-column
		        prop="role_name"
		        label="角色"
				width="180">
		      </el-table-column>
			  <el-table-column
		        
		        label="状态"
				width="180">
		      </el-table-column>
			  <el-table-column
		        
		        label="操作"
				width="180">
		      </el-table-column>
		    </el-table>

加入状态
插槽 :

<el-table-column
		        label="状态"
				width="180">
				<template v-slot="scope">
					{{scope.row}}
				</template>
				</el-table-column>

打印结果
在这里插入图片描述
加入状态

 <el-table-column
		        label="状态"
				width="180">
				<template v-slot="scope">
					<el-switch
					  v-model="scope.row.mg_state"
					  active-color="#13ce66"
					  inactive-color="#9ba6af"
					 >
					</el-switch>
				</template>
				

		      </el-table-column>

在<el-switch 绑定
@change=“userStateChanged(scope.row)”

async userStateChanged(userinfo){
				//console.log(userinfo)
				// 直接将开关状态传给数据库
				await this.$http.put(`users/${userinfo.id}/state/${userinfo.mg_state}`)
				if(res.meta.status !== 200){
					 userinfo.mg_state = !userinfo.mg_state
					return this.$message.error('更新用户状态失败')
				}
				this.$message.success('更新用户状态成功')
			}

实现点击开关按钮数据库中的值也发生改变(监听)

5.自定义操作列的渲染

<el-table-column
		        label="操作"
				width="180">
				<template>
				<!-- 修改按钮 -->
				<el-button type="primary" icon="el-icon-edit" size="small"></el-button>					
				<!-- 删除按钮 -->
				<el-button type="danger" icon="el-icon-delete" size="small"></el-button>
				<!-- 分配角色按钮 -->
				<el-tooltip effect="dark" content="分配角色" placement="top-start" :enterable="false">
				      <el-button type="warning" icon="el-icon-setting" size="small"></el-button>
				    </el-tooltip>
				</template>
		      </el-table-column>
		    </el-table>

6.分页页码条

<!-- 分页页码条 -->
			 <el-pagination
			      @size-change="handleSizeChange"
			      @current-change="handleCurrentChange"
			      :current-page="queryInFo.pagenum"
			      :page-sizes="[1, 2, 5, 10]"
			      :page-size="100"
			      layout="total, sizes, prev, pager, next, jumper"
			      :total=total>
			    </el-pagination>
		  
//监听 pasesize 改变的事件
			handleSizeChange(newsize){
				// console.log(newsize)
				this.queryInFo.pagesize = newsize
				this.getUserList()
			},
			//监听 页码值 改变的事件
			handleCurrentChange(newPage){
				// console.log(newPage)
				this.queryInFo.pagenum = newPage
				this.getUserList()
			},

实现搜索功能
为<el-input 绑定 v-model=“queryInFo.query”
为<el-button 绑定@click=“getUserList”
即能实现
清除功能
为<el-input 添加clearable 绑定@clear=“getUserList”

⑥实现添加功能

<!-- 添加用户的对话框 -->
		<el-dialog
		  title="添加用户"
		  :visible.sync="dialogVisible"
		  width="50%"
		  @close="adddDiaolog"
		  >
		  <!-- 内容主题区域 -->
		  <el-form :model="addForm" :rules="addFormRules" ref="addFormRed" label-width="70px" label-eight="300" >
		    <el-form-item label="用户名" prop="username">
		      <el-input v-model="addForm.username"></el-input>
		    </el-form-item>
			<el-form-item label="密码" prop="password">
		      <el-input show-password v-model="addForm.password"></el-input>
		    </el-form-item>
			<el-form-item label="邮箱" prop="emil">
		      <el-input  v-model="addForm.emil"></el-input>
		    </el-form-item>
			<el-form-item label="手机" prop="phone">
		      <el-input  v-model="addForm.phone"></el-input>
		    </el-form-item>
			</el-form>
		  <!-- 底部区域 -->
		  <span slot="footer" class="dialog-footer">
		    <el-button @click="dialogVisible = false">取 消</el-button>
		    <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
		  </span>
		</el-dialog>>

在data添加
//控制添加用户对话框显示与隐藏
dialogVisible: false
为button绑定事件<el-button type=“primary” @click=“dialogVisible = true”>添加用户

data() {
			//验证邮箱的规则
			var checkEmil = (rule, value, cb)=>{
				//验证邮箱的正则表达式
			 const regEmil = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/
			 
			 if(regEmil.test(value)){
				 //合法邮箱
				 return cb()
			 }
			 cb( new Error('请输入合法邮箱'))
			}
			//验证手机号的规则 
			var checkPhone = (rule, value, cb)=>{
				//验证手机号的正则表达式
				const regPhone = /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/
				if( regPhone.test(value) ){
					//合法手机号
					return cb()
				}
				cb( new Error('请输入合法手机号'))
			}
			return {
				//获取用户列表的参数对象
				queryInFo: {
					query: '',
					//当前页数
					pagenum: 1,
					//当前每页显示多少条数据
					pagesize: 2
				},
				userlist: [],
				total: 0,
				//控制添加用户对话框显示与隐藏
				 dialogVisible: false,
				 //添加用户的表单数据
				 addForm:{
					 username:'',
					 password: '',
					 emil:'',
					 phone:''
				 },
				 //添加表单的验证规则对象
				 addFormRules:{
					 username: [{
						 required:true,
						 message:'请输入用户名',
						 trigger: 'blur'
					 },
					 {
						min:3,
						max:10,
						message:'用户名在3~10个字符之间',
						trigger: 'blur'
					 }],
					 password: [{
						 required:true,
						 message:'请输入密码',
						 trigger: 'blur'
					 },
					 {
						min:6,
						max:16,
						message:'密码在6~16个字符之间',
						trigger: 'blur'
					 }],
					 emil: [{
						 required:true,
						 message:'请输入邮箱',
						 trigger: 'blur'
					 },
					 {
						 validator: checkEmil,
						 trigger: 'blur'
					 }],
					 phone: [{
						 required:true,
						 message:'请输入手机号',
						 trigger: 'blur'
					 },
					 {
						validator: checkPhone,
						trigger: 'blur'
					 }]
				 },
				
			}
		},
//监听添加 用户对话框的关闭事件
			adddDiaolog(){
				this.$refs.addFormRed.resetFields()
			}				 	

发起请求添加一个新用户
为确定按钮绑定事件
<el-button type=“primary” @click=“addUser”>确 定

//点击按钮添加新用户
   		  addUser(){
   			 this.$refs.addFormRed.validate( async valid => {
   				if( !valid )return
   				//可以发送添加用户的网络请求
   				const {data:res} = await this.$http.post('/users',this.addForm)
   				console.log(res)
   				if(res.meta.status !== 201){
   					return this.$message.error('发送添加请求网络失败')
   				}
   				this.$message.success('添加用户成功')
   				//隐藏添加用户的对话框
   				this.dialogVisible = false
   				//重新获取用户列表
   				this.getUserList()
   			} )
   		}

⑦实现修改功能

<!-- 修改用户的对话框 -->
		<el-dialog title="修改用户" :visible.sync="editDialogVisible" width="50%" @close="editDialogClose">
			<el-form :model="editForm" :rules="editFormRules" ref="editFormRef" label-width="70px">
				<el-form-item label="用户名">
					<el-input v-model="editForm.username" :disabled="true"></el-input>
				</el-form-item>
				<el-form-item label="邮箱" prop="email">
					<el-input v-model="editForm.email"></el-input>
				</el-form-item>
				<el-form-item label="手机" prop="mobile">
					<el-input v-model="editForm.mobile"></el-input>
				</el-form-item>
			</el-form>
			<span slot="footer" class="dialog-footer">
				<el-button @click="editDialogVisible = false">取 消</el-button>
				<el-button type="primary" @click="editUser">确 定</el-button>
			</span>
		</el-dialog>

@close="editDialogClose"在关闭对话框时清除校验

//监听修改用户对话框的关闭事件
   		editDialogClose(){
   			this.$refs.editFormRef.resetFields()
   		},

:model="editForm"新建空表单editForm
:rules="editFormRules"新建校验规则

//添加修改用户表单的验证规则对象
				editFormRules: {
					email: [{
							required: true,
							message: '请输入邮箱',
							trigger: 'blur'
						},
						{
							validator: checkEmail,
							trigger: 'blur'
						}
					],
					mobile: [{
							required: true,
							message: '请输入手机号',
							trigger: 'blur'
						},
						{
							validator: checkMobile,
							trigger: 'blur'
						}
					]
				}

在showEditDialog(id)方法中写入
this.editForm = res.data实现数据的绑定
@click="editUser"实现点击确定按钮时数据的修改

//点击按钮修改用户对话框
			editUser(){
				this.$refs.editFormRef.validate(async valid => {
					// console.log(valid)
					if(!valid) return 
					//可以发送修改用户的网络请求
					const {data: res} = await this.$http.put('users/' + this.editForm.id,{
						email: this.editForm.email,
						mobile: this.editForm.mobile
					})
					// console.log(res)
					if(res.meta.status !== 200){
						return this.$message.error('修改用户失败')					
					}
					//关闭对话框
					this.editDialogVisible = false
					//刷新数据列表
					this.getUserList()
					//提示修改成功
					this.$message.success('修改用户成功')
				})
				
			}

⑧实现删除功能

</el-button>
					<!-- 删除按钮 -->
					<el-button type="danger" icon="el-icon-delete" size="small" @click="deleteEditDialog(scope.row.id)"></el-button>
//使用ID实现删除功能
			async deleteEditDialog(id) {
				//弹窗询问是否删除
				const confirmResult = await this.$confirm('此操作将永久删除该用户, 是否继续?', '提示', {
					confirmButtonText: '确定',
					cancelButtonText: '取消',
					type: 'warning'
				}).catch(err => err);
				//如果用户确认删除,则返回字符串confirm
				//如果用户取消删除,则返回字符串cancel
				// console.log(confirmResult)
				if (confirmResult !== 'confirm') {
					return this.$message.info('已经取消删除')
				}
				
				const {data: res} = await this.$http.delete('users/' + id)
				if (res.meta.status !== 200) {
					return this.$message.error('删除用户失败')
				}
				this.getUserList()
				this.$message.success('删除用户成功')

			}

实现权限管理功能

①实现权限列表功能

<template>
	<div>
		<!-- 面包屑导航区域 -->
		<el-breadcrumb separator="/">
			<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
			<el-breadcrumb-item><a href="/">权限管理</a></el-breadcrumb-item>
			<el-breadcrumb-item>权限列表</el-breadcrumb-item>
		</el-breadcrumb>

		<!-- 卡片试图 -->
		<el-card>
			<!-- 用户列表区域 -->
			<el-table  style="width: 100%" :data="rightList" border stripe>
				<!-- 索引列 -->
				<el-table-column  type="index" label="#"></el-table-column>
				<el-table-column prop="authName" label="权限名称" width="340">
				</el-table-column>
				<el-table-column prop="path" label="路径" width="340">
				</el-table-column>
				<el-table-column prop="level" label="权限等级" width="340">
					<template v-slot="scope">
						<el-tag v-if="scope.row.level === '0'">一级</el-tag>
						<el-tag v-if="scope.row.level === '1'" type="success">二级</el-tag>
						<el-tag v-if="scope.row.level === '2'" type="warning">三级</el-tag>
					</template>
				</el-table-column>
				</el-table>
				
		</el-card>
	</div>
</template>

<script>
	export default {
		name: 'Rights',
		data() {
			return {
				//权限列表
				rightList: []
			}
		},
		created() {
			//获取所有权限
			this.getRightList()
		},
		methods: {
			async getRightList(){
				const {data: res} = await this.$http.get('rights/list')
				console.log(res)
				
				if(res.meta.status !== 200){
					return this.$message.error('获取权限列表失败')
				}
				this.rightList =  res.data
				
			}
		},

	}
</script>

<style scoped>
</style>

②角色列表

<template>
	<div>
		<!-- 面包屑导航区域 -->
		<el-breadcrumb separator="/">
			<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
			<el-breadcrumb-item>权限管理</a></el-breadcrumb-item>
			<el-breadcrumb-item>权限列表</el-breadcrumb-item>
		</el-breadcrumb>

		<!-- 卡片试图 -->
		<el-card>
			<!-- 添加角色按钮 -->
			<el-row>
				<el-col>
					<el-button type="primary" @click="rolesAdd">添加角色</el-button>
				</el-col>
			</el-row>
			<!-- 角色列表区域 -->
			<el-table row-key="id" style="width: 100% " :data="rolesList" border stripe>
				<!-- 展开列 -->
				<el-table-column type="expand">
					<template v-slot="scope">
						<!-- <pre>{{scope.row}}</pre> -->
						<el-row :class="['db-bottom', i1 === 0 ? 'db-top' : '', 'vcenter']"
							v-for="(item1,i1) in scope.row.children" :key="item1.id">
							<!-- 渲染一级权限 -->
							<el-col :span="5">
								<el-tag closable @close="removeRightById(scope.row.id , item1.id)">{{item1.authName}}
								</el-tag>
								<i class="el-icon-caret-right"></i>
							</el-col>
							<!-- 渲染二级和三级权限 -->
							<el-col :span="19">
								<!-- 通过 for 循环 嵌套渲染二级权限 -->
								<el-row :class="[i2 === 0 ? '' : 'db-top', 'vcenter']"
									v-for="(item2,i2) in item1.children" key="item2.id">
									<el-col :span="6">
										<el-tag type="success" closable
											@close="removeRightById(scope.row.id , item2.id)">{{item2.authName}}
										</el-tag>
										<i class="el-icon-caret-right"></i>
									</el-col>
									<!-- 三级 -->
									<el-col :span="18">
										<el-tag type="warning" v-for="(item3,i3) in item2.children" :key="item3.id"
											closable @close="removeRightById(scope.row.id , item3.id)">
											{{item3.authName}}
										</el-tag>
									</el-col>
								</el-row>
							</el-col>
						</el-row>
					</template>
				</el-table-column>
				<!-- 索引列 -->
				<el-table-column type="index" label="#"></el-table-column>
				<el-table-column prop="roleName" label="角色名称" width="340">
				</el-table-column>
				<el-table-column prop="roleDesc" label="角色描述" width="340">
				</el-table-column>
				<el-table-column label="操作" width="340">
					<template v-slot="scope">
						<!-- 修改按钮 -->
						<el-button type="primary" icon="el-icon-edit" size="small">
							编辑
						</el-button>
						<!-- 删除按钮 -->
						<el-button type="danger" icon="el-icon-delete" size="small">
							删除
						</el-button>
						<!-- 分配角色按钮 -->
						<el-button type="warning" icon="el-icon-setting" size="small"
							@click="showSetRightDiaLog(scope.row)">分配角色
						</el-button>

					</template>
				</el-table-column>

			</el-table>

		</el-card>

		<!-- 添加角色对话框 -->
		<el-dialog title="添加用户" :visible.sync="rolesVisible" width="50%" @close="adddDiaolog" append-to-body="true">
			<!-- 内容主题区域 -->
			<el-form :model="rolesForm" :rules="rolesFormRules" ref="rolesFormRed" label-width="70px" label-eight="300">
				<el-form-item label="角色名称" prop="roleName">
					<el-input v-model="rolesForm.roleName"></el-input>
				</el-form-item>
				<el-form-item label="角色负责人" prop="roleDesc">
					<el-input v-model="rolesForm.roleDesc"></el-input>
				</el-form-item>
			</el-form>
			<!-- 底部区域 -->
			<span slot="footer" class="dialog-footer">
				<el-button @click="rolesVisible = false">取 消</el-button>
				<el-button type="primary" @click="rolesQ">确 定</el-button>
			</span>
		</el-dialog>

		<!-- 分配权限对话框 -->
		<el-dialog title="分配用户权限" :visible.sync="showSetVisible" width="50%" append-to-body="true"
			@close="setRightDialogClose">
			<!-- 树形控件 -->
			<el-tree show-checkbox node-key="id" default-expand-all :data="rightslist" :props="treeProps"
				:default-checked-keys="defKey" ref="treeRef"></el-tree>
			<span slot="footer" class="dialog-footer">
				<el-button @click="showSetVisible = false">取 消</el-button>
				<el-button type="primary" @click="allotRight()">确 定</el-button>
			</span>
		</el-dialog>
	</div>
</template>
<script>
	export default {
		name: 'Roles',
		data() {
			return {
				//所有角色列表数据
				rolesList: {},
				//是否展示添加角色对话框
				rolesVisible: false,
				//是否展示分配权限对话框
				showSetVisible: false,
				//所有权限的数据
				rightslist: [],
				//添加用户列表
				rolesForm: {
					roleName: '',
					roleDesc: ''
				},
				//当前即将分配权限的角色id
				roleId: '',
				//添加用户验证规则
				rolesFormRules: {
					roleName: [{
							required: true,
							message: '请输入角色名称',
							trigger: 'blur'
						},
						{
							min: 2,
							max: 10,
							message: '角色名称在3~15个字符之间',
							trigger: 'blur'
						}
					],
					roleDesc: [{
							required: true,
							message: '请输入角色负责人',
							trigger: 'blur'
						},
						{
							min: 2,
							max: 10,
							message: '角色负责人在3~15个字符之间',
							trigger: 'blur'
						}
					]

				},
				// 树形控件的属性绑定对象
				treeProps: {
					children: 'children',
					label: 'authName'
				},
				//默认选中的节点id值数组
				defKey: []
			}
		},
		created() {
			this.getRolesList()
		},
		methods: {
			//获取所有角色的列表
			async getRolesList() {
				const {
					data: res
				} = await this.$http.get('/roles')
				// console.log(res)
				if (res.meta.status !== 200) {
					return this.$message.error('获取角色列表失败')
				}
				this.rolesList = res.data

			},
			//点击添加按钮添加用户
			rolesAdd() {
				this.rolesVisible = true
			},
			//关闭后清除验证规则
			adddDiaolog() {
				this.$refs.rolesFormRed.resetFields()
			},
			//确定按钮添加用户
			async rolesQ() {
				const {
					data: res
				} = await this.$http.post('roles', this.rolesForm)
				// console.log(res)
				if (res.meta.status !== 201) {
					return this.$message.error('添加角色失败')
				}
				this.$message.success('添加角色成功')
				this.getRolesList()
				this.rolesVisible = false

			},
			//根据ID删除标签
			async removeRightById(role, rightId) {
				const confirmResult = await this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
					confirmButtonText: '确定',
					cancelButtonText: '取消',
					type: 'warning'
				}).catch(err => err);
				// console.log(confirmResult)
				if (confirmResult !== 'confirm') {
					return this.$message.info('已经取消删除')
				}
				//如果用户确认删除,则返回字符串confirm
				//如果用户取消删除,则返回字符串cancel
				const {
					data: res
				} = await this.$http.delete(`roles/${role}/rights/${rightId}`)
				// console.log(res)
				if (res.meta.status !== 200) {
					return this.$message.error('取消权限失败')
				}

				this.$message.success('取消权限成功')
				this.getRolesList()
			},
			//展示分配权限的对话框
			async showSetRightDiaLog(role) {
				this.roleId = role.id
				//获取所有的权限数据
				const {
					data: res
				} = await this.$http.get('rights/tree')
				// console.log(res)
				if (res.meta.status !== 200) {
					return this.$message.error('获取权限列表失败')
				}
				//把获取到的权限数据保存到data中
				this.rightslist = res.data
				// console.log(this.rightslist)

				//递归获取三级节点的id
				this.getLeafKeys(role, this.defKey)

				this.showSetVisible = true
			},
			// 通过递归的新式,获取角色下所有三级权限 
			//的id并保存到 defKey数组中
			getLeafKeys(node, arr) {
				//如果当前节点不包含children属性,则是三级节点
				if (!node.children) {
					return arr.push(node.id)
				}

				node.children.forEach(item =>
					this.getLeafKeys(item, arr)
				)
			},
			//监听分配权限对话框事件
			setRightDialogClose() {
				this.defKey = []
			},
			//点击为角色分配权限
			async allotRight() {
				const keys = [
					...this.$refs.treeRef.getCheckedKeys(),

					...this.$refs.treeRef.getHalfCheckedKeys()
				]

				const idStr = keys.join(',')
				const {
					data: res
				} = await this.$http.post(`roles/${this.roleId}/rights`, {
					rids: idStr
				})
				if(res.meta.status !== 200){
					return this.$message.error('更新角色失败')
				}
				this.$message.success('更新角色成功')
				
				this.showSetVisible = false
				this.getRolesList()
			},
		}
	}
</script>
<style>
	.el-tag {
		margin: 7px;

	}

	.db-top {
		border-top: 1px solid #eee;
	}

	.db-bottom {
		border-bottom: 1px solid #eee;
	}

	.vcenter {
		display: flex;
		align-items: center;
	}
</style>

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值