Vue
Vue-Router
Element-UI
Axios
Echarts
Vue
脚手架Element-UI
,安装[babel-plugin-component]
,实现按需导入Axios
Axios
的发呢改装Element-UI
的按需引入。在目录src
下新建一个util
文件夹,在util
文件中新建一个elementUI
文件。在main.js
文件中导入。
import './util/elemt'
在elementUI
中,实现按需导入。
import Vue from 'vue';
import {
Pagination,
Dialog,
Autocomplete,
Dropdown,
DropdownMenu,
DropdownItem,
Menu,
Submenu,
MenuItem,
MenuItemGroup,
Input,
InputNumber,
Radio,
RadioGroup,
RadioButton,
Checkbox,
CheckboxButton,
CheckboxGroup,
Switch,
Select,
Option,
OptionGroup,
Button,
ButtonGroup,
Table,
TableColumn,
DatePicker,
TimeSelect,
TimePicker,
Popover,
Tooltip,
Breadcrumb,
BreadcrumbItem,
Form,
FormItem,
Tabs,
TabPane,
Tag,
Tree,
Alert,
Slider,
Icon,
Row,
Col,
Upload,
Progress,
Spinner,
Badge,
Card,
Rate,
Steps,
Step,
Carousel,
CarouselItem,
Collapse,
CollapseItem,
Cascader,
ColorPicker,
Transfer,
Container,
Header,
Aside,
Main,
Footer,
Timeline,
TimelineItem,
Link,
Divider,
Image,
Calendar,
Backtop,
PageHeader,
CascaderPanel,
Loading,
MessageBox,
Message,
Notification
} from 'element-ui';
Vue.use(Pagination);
Vue.use(Dialog);
Vue.use(Autocomplete);
Vue.use(Dropdown);
Vue.use(DropdownMenu);
Vue.use(DropdownItem);
Vue.use(Menu);
Vue.use(Submenu);
Vue.use(MenuItem);
Vue.use(MenuItemGroup);
Vue.use(Input);
Vue.use(InputNumber);
Vue.use(Radio);
Vue.use(RadioGroup);
Vue.use(RadioButton);
Vue.use(Checkbox);
Vue.use(CheckboxButton);
Vue.use(CheckboxGroup);
Vue.use(Switch);
Vue.use(Select);
Vue.use(Option);
Vue.use(OptionGroup);
Vue.use(Button);
Vue.use(ButtonGroup);
Vue.use(Table);
Vue.use(TableColumn);
Vue.use(DatePicker);
Vue.use(TimeSelect);
Vue.use(TimePicker);
Vue.use(Popover);
Vue.use(Tooltip);
Vue.use(Breadcrumb);
Vue.use(BreadcrumbItem);
Vue.use(Form);
Vue.use(FormItem);
Vue.use(Tabs);
Vue.use(TabPane);
Vue.use(Tag);
Vue.use(Tree);
Vue.use(Alert);
Vue.use(Slider);
Vue.use(Icon);
Vue.use(Row);
Vue.use(Col);
Vue.use(Upload);
Vue.use(Progress);
Vue.use(Spinner);
Vue.use(Badge);
Vue.use(Card);
Vue.use(Rate);
Vue.use(Steps);
Vue.use(Step);
Vue.use(Carousel);
Vue.use(CarouselItem);
Vue.use(Collapse);
Vue.use(CollapseItem);
Vue.use(Cascader);
Vue.use(ColorPicker);
Vue.use(Transfer);
Vue.use(Container);
Vue.use(Header);
Vue.use(Aside);
Vue.use(Main);
Vue.use(Footer);
Vue.use(Timeline);
Vue.use(TimelineItem);
Vue.use(Link);
Vue.use(Divider);
Vue.use(Image);
Vue.use(Calendar);
Vue.use(Backtop);
Vue.use(PageHeader);
Vue.use(CascaderPanel);
Vue.use(Loading.directive);
Vue.prototype.$loading = Loading.service;
Vue.prototype.$msgbox = MessageBox;
Vue.prototype.$alert = MessageBox.alert;
Vue.prototype.$confirm = MessageBox.confirm;
Vue.prototype.$prompt = MessageBox.prompt;
Vue.prototype.$notify = Notification;
Vue.prototype.$message = Message;
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
routes: [{
path: '/',
redirect: '/login',
},
{
path: '/login',
name: 'login',
component: () => import( /* webpackChunkName: "login_home-welcome" */ './views/Login.vue')
},]
},
]
})
在确保路由正确的情况下,也要对路由实现优化以及路由重定向。
Axios
的封装第一步:封装基本路径
首先:实现基准路径的简单封装。在utle
文件中新建index.js
文件。在index.js
文件中。
import Vue from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(axios)
// 设置请求基准路径
const Serve = axios.create({
baseURL: 'https://www.liulongbin.top:8888/api/private/v1',
timeout: 5000,
})
export default Serve
第二步:封装API
在src
中新建API
文件夹,在API
文件中新建Login.js
文件,文件名称尽量与组件或页面名称对应。方便日后的维护。
import request from '../util/index'
export default {
login(form) {
return request({
url: '/login',
method: "post",
data: form,
})
}
}
导入封装好的基准路径,在这里写好请求的路径以及方式。
第三步:使用
在Login.vue
页面中导入封装好对应的API
文件
import LoginApi from '../api/Login'
在数据请求时:
login() {
this.$refs.loginRef.validate(async (valid) => {
if (!valid) return;
let {
data: res } = await LoginApi.login(this.loginForm)
if (res.meta.status !== 200) {
this.$message.error(res.meta.msg);
}
sessionStorage.token = res.data.token;
this.$router.push("/home");
this.$message.success(res.meta.msg);
});
},
做好这些,基本可以开始了…
分析:
输入账号和密码,发送数据,发送时携带
token
值,对token
值进行保存,在后续的请求中用户会通过token
值确定用户账号身份。从而实现数据的请求。
**步骤1、**在view
中新建Login
页面。
**步骤2、**在Login
页面中:
<template>
<div id="login">
<div class="login-wraper">
<div class="img"><img src="../assets/logo.png" alt="" /></div>
<div class="from">
<el-form
:model="loginForm"
:rules="loginRules"
ref="loginRef"
class="demo-ruleForm"
>
<el-form-item prop="username">
<el-input
prefix-icon="el-icon-user-solid"
v-model="loginForm.username"
></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
type="password"
prefix-icon="el-icon-lock"
v-model="loginForm.password"
></el-input>
</el-form-item>
<el-form-item class="but">
<el-button type="primary" @click="login">登录</el-button>
<el-button type="info" @click="remove">重置</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
import LoginApi from '../api/Login'
export default {
data() {
return {
loginForm: {
username: "",
password: "",
},
loginRules: {
username: [
{
required: true, message: "请输入用户名", trigger: "blur" },
],
password: [
{
required: true, message: "请输入用户密码", trigger: "blur" },
{
min: 3,
max: 10,
message: "密码长度在3到10个字符",
trigger: "blur",
},
],
},
};
},
methods: {
login() {
this.$refs.loginRef.validate(async (valid) => {
if (!valid) return;
let {
data: res } = await LoginApi.login(this.loginForm)
if (res.meta.status !== 200) {
this.$message.error(res.meta.msg);
}
sessionStorage.token = res.data.token;
this.$router.push("/home");
this.$message.success(res.meta.msg);
});
},
remove() {
this.$refs.loginRef.resetFields();
},
},
};
</script>
<style lang='scss' scoped>
#login {
width: 100%;
height: 100%;
background-image: url("../assets/1.jpg");
background-size: 100%;
.login-wraper {
width: 400px;
height: 300px;
background-color: rgba(0, 0, 0, 0.4);
position: absolute;
top: 50%;
left: 50%;
transform: translate(50%, -50%);
border-radius: 10px;
box-shadow: 0px 0px 10px 0px #cccc;
.img {
width: 120px;
height: 120px;
padding: 10px;
background-color: rgb(54, 52, 52);
border-radius: 50%;
box-shadow: 0px 0px 10px 0px #fff;
position: absolute;
left: 50%;
transform: translate(-50%, -50%);
img {
width: 100%;
height: 100%;
background-color: rgb(163, 163, 163);
border-radius: 50%;
}
}
.el-form {
width: 100%;
position: absolute;
bottom: 0;
padding: 20px;
box-sizing: border-box;
.el-form-item {
width: 100%;
.el-input {
width: 100%;
}
}
}
.but {
display: flex;
justify-content: flex-end;
}
}
}
</style>
步骤三:
封装的基准路径中设置请求头
// 请求响应器
Serve.interceptors.request.use(config => {
config.headers.Authorization = sessionStorage.token;
return config
})
通过请求拦截器设置请求头。
步骤四:
在main.js
中设置路由守卫
// 路由导航守卫
router.beforeEach((to, from, next) => {
if (to.path == '/login') {
next()
} else {
if (sessionStorage.token) {
next()
} else {
next('/login')
}
}
})
判断如果当前本地中没有token
值,则说明用户没有登录,则跳转到登录页面。
步骤五:
添加Home.vue
页面
设置Home
页的初始状态。
<template>
<div>
<el-button type="info" @click="logout"> 退出 </el-button>
</div>
</template>
<script>
export default {
methods: {
logout() {
sessionStorage.removeItem("token");
if (!sessionStorage.token) {
this.$router.push("/login");
}
}
}
}
</script>
<style lang='less' scoped>
</style>
通过本地清除,在点击退出按钮时能够成功退出。
功能要求
1、首页布局
2、侧边栏导航
3、
welcome
页面。
1、首页布局
<template>
<div id="home">
<el-container>
<el-header>
</el-header>
<el-container>
<el-aside width="200px">
</el-aside>
<el-main>
</el-main>
</el-container>
</el-container>
</div>
</template>
通过elment-ui
中的布局容器对页面进行布局
2、实现侧边栏的导航功能
首先:封装对应的API
import request from '../util/index'
export default {
asside(form) {
return request({
url: '/menus',
method: "get",
})
}
}
页面实现
<template>
<div id="home">
<el-container>
<el-header>
<div class="headerLeft">
<img src="../assets/logo2.png" alt="" />
<span>电商管理后台</span>
</div>
<div class="headerRight">
<el-button type="info" @click="quit">退出</el-button>
</div>
</el-header>
<el-container>
<el-aside :width="has ? '64px' : '200px'">
<div class="hasSwith"><span @click="has = !has">|||</span></div>
<el-row>
<el-col :span="24">
<el-menu
:default-active="$route.path"
class="el-menu-vertical-demo"
background-color="#333744"
unique-opened
text-color="#fff"
active-text-color="#ffd04b"
:collapse="has"
collapse-transition
router >
<el-submenu
:index="item.id + ''"
v-for="item in menusList"
:key="item.id">
<template slot="title">
<i :class="iconObj[item.id]" class="icon"></i>
<span>{
{
item.authName }}</span>
</template>
<el-menu-item
:index="'/' + it.path"
v-for="it in item.children"
:key="it.id" >
<i class="el-icon-menu"></i>
<span>{
{
it.authName }}</span>
</el-menu-item>
</el-submenu>
</el-menu>
</el-col>
</el-row>
</el-aside>
<el-main>
<router-view />
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
import assideApi from "../api/Asside";
export default {
data() {
return {
menusList: [],
iconObj: {
//图标
125: "iconfont icon-users",
103: "iconfont icon-tijikongjian",
101: "iconfont icon-shangpin",
102: "iconfont icon-danju",
145: "iconfont icon-baobiao",
},
has: false,
};
},
created() {
this.menus();
},
methods: {
// 退出登录
quit() {
sessionStorage.removeItem("token");
if (!sessionStorage.token) {
this.$router.push("/login");
}
},
async menus() {
//向后台发送请求
const {
data: res } = await assideApi.asside();
if (res.meta.status !== 200) {
this.$message.error(res.meta.msg);
}
this.$message.success(res.meta.msg);
this.menusList = res.data;
},
},
};
</script>
<style lang='scss' scoped>
.icon {
margin-right: 10px;
}
#home {
width: 100%;
height: 100%;
}
.el-container {
width: 100%;
height: 100%;
}
.el-header {
display: flex;
justify-content: space-between;
background-color: #373d41;
color: #333;
line-height: 60px;
height: 60px;
width: 100%;
.headerLeft {
color: aliceblue;
display: flex;
align-items: center;
span {
margin-left: 10px;
font-size: 26px;
font-family: "楷体";
font-weight: 900;
}
}
}
.el-aside {
text-align: center;
background-color: #333744;
color: #333;
height: 100%;
.hasSwith {
height: 30px;
width: 100%;
color: aliceblue;
background-color: #4a5064;
display: flex;
align-items: center;
justify-content: center;
}
}
.el-main {
width: 100%;
height: 100%;
background-color: #eaedf1;
color: #333;
}
</style>
3、welcome
页面。
在components
中创建Welcome.vue
页面,
<template>
<div id="replace">
<h1>欢迎来到我的世界!</h1>
</div>
</template>
<script>
export default {
}
</script>
<style lang='scss' scoped>
</style>
在router.js
配置相应的路由。
{
path: '/home',
name: 'home',
component: () => import( /* webpackChunkName: "login_home-welcome" */ './views/Home.vue'),
redirect: '/welcome',
children: [{
path: '/welcome',
name: "welcome",
component: () => import( /* webpackChunkName: "login_home-welcome" */ './components/welcome.vue'),
},
这里的welcome
值是一个欢迎页面,所以只需在页面简单写一个welcome
,配置路由即可,但是,页面路由根据项目需求是要定义为重定向的。
路由配置这里要将之后的页面作为二级路由封装在home
页的路由下。
创建users.vue
文件,配置路由
{
path: '/home',
name: 'home',
component: () => import( /* webpackChunkName: "login_home-welcome" */ './views/Home.vue'),
redirect: '/welcome',
children: [{
path: '/welcome',
name: "welcome",
component: () => import( /* webpackChunkName: "login_home-welcome" */ './components/welcome.vue'),
}, {
path: '/users',
name: "users",
component: () => import( /* webpackChunkName: "users" */ './components/users.vue'),
},
},
注意:
作为home
的子路由,写在了children
中
在写用户列表之前,先封装一个面包屑导航。方便在多个组件中的应用
同样在componets
中新建bread.vue
组件
在需要写面包屑导航的页面的路由下面写
{
path: '/users',
name: "users",
component: () => import( /* webpackChunkName: "users" */ './components/users.vue'),
meta: {
bread: ['用户管理', '用户列表']
}
},
在组件中
<template>
<div id="bread">
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/welcome' }">首页</el-breadcrumb-item>
<el-breadcrumb-item v-for="(item, index) in breadList" :key="index">
<span> {
{
item }}</span>
</el-breadcrumb-item>
</el-breadcrumb>
</div>
</template>
<script>
export default {
data() {
return {
breadList: [],
};
},
mounted() {
this.breadList = this.$route.meta.bread;
},
};
</script>
<style lang='scss' scoped>
</style>
在用到的组件中通过组件注册的方式进行使用
<template>
<Bread />
</template>
<script>
import Bread from "./bread/bread";
components: {
Bread,
},
</script>
完整页面
<template>
<div id="users">
<!-- 导入面包屑 -->
<Bread />
<!-- 卡片视图 -->
<el-card>
<!-- 用户搜索区域 -->
<el-row :gutter="20">
<el-col :span="8">
<el-input
placeholder="请输入内容"
v-model="queryInfo.query"
class="input-with-select"
clearable>
<el-button
slot="append"
icon="el-icon-search"
@click="getList"></el-button>
</el-input>
</el-col>
<el-col :span="4">
<el-button type="primary" @click="addUser">添加用户</el-button></el-col>
</el-row>
<!-- 表格区块 -->
<el-table :data="userList" border style="margin-top: 15px">
<el-table-column label="#" type="index"> </el-table-column>
<el-table-column prop="username" label="姓名"> </el-table-column>
<el-table-column prop="email" label="邮箱"> </el-table-column>
<el-table-column prop="mobile" label="电话"> </el-table-column>
<el-table-column prop="role_name" label="角色"> </el-table-column>
<el-table-column prop="mg_state" label="状态">
<template slot-scope="scope">
<!-- 修改用户状态 -->
<el-switch
v-model="scope.row.mg_state"
active-color="#13ce66"
inactive-color="#ccc"
@change="stat(scope.row)">
</el-switch>
</template>
</el-table-column>
<el-table-column label="操作">
<!-- 操作区域 -->
<template v-slot="scope">
<!-- 编辑区域、 -->
<el-button
size="mini"
type="primary"
icon="el-icon-edit"
@click="edit(scope.row)"></el-button>
<!-- 删除按钮 -->
<el-button
size="mini"
type="danger"
icon="el-icon-delete"
@click="del(scope.row)"></el-button>
<!-- 设置角色-->
<el-button
size="mini"
type="warning"
icon="el-icon-setting"
@click="sett(scope.row)"></el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页区域 -->
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="queryInfo.pagenum"
:page-sizes="[1, 3, 6, 9]"
:page-size="queryInfo.pagesize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</el-card>
<!-- 编辑用户对话框 -->
<el-dialog title="提示" :visible.sync="editVisible" width="45%">
<el-form
:model="editList"
ref="editRef"
:rules="rulesFrom"
class="demo-ruleForm">
<el-form-item label="用户名" prop="username" label-width="75px">
<el-input v-model="editList.username" disabled></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email" label-width="75px">
<el-input v-model="editList.email"></el-input>
</el-form-item>
<el-form-item label="手机" prop="mobile" label-width="75px">
<el-input v-model="editList.mobile"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="editVisible = false">取 消</el-button>
<el-button type="primary" @click="editAdd">确 定</el-button>
</span>
</el-dialog>
<!-- 分配权限对话框 -->
<el-dialog title="分配角色" :visible.sync="settVisible" width="30%">
<p>
<span>当前的用户:{
{
list.username }}</span>
</p>
<p>
<span>当前的角色:{
{
list.role_name }}</span>
</p>
<div>
<span>分配新的角色:</span>
<el-select v-model="set" placeholder="请选择">
<el-option
v-for="item in setting"
:key="item.id"
:label="item.roleName"
:value="item.id">
</el-option>
</el-select>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="set">取 消</el-button>
<el-button type="primary" @click="settAdd">确 定</el-button>
</span>
</el-dialog>
<!-- 添加用户对话框 -->
<el-dialog title="添加用户" :visible.sync="addUsersVisible" width="40%">
<el-form
:model="addUsersForm"
:rules="rulesFrom"
ref="addUsersRef"
label-width="80px"
class="demo-ruleForm">
<el-form-item label="用户名称" prop="username">
<el-input v-model="addUsersForm.username"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="addUsersForm.password"></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="addUsersForm.email"></el-input>
</el-form-item>
<el-form-item label="电话" prop="mobile">
<el-input v-model="addUsersForm.mobile"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="addUsersVisible = false">取 消</el-button>
<el-button type="primary" @click="addDialog">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import Bread from "./bread/bread";
import UsersApi from "../api/Users";
export default {
components: {
Bread,
},
data() {
const checkEmail = (rule, value, callback) => {
const re = /^[a-z0-9A-Z]+[- | a-z0-9A-Z . _]+@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\.)+[a-z]{2,}$/;
if (!re.test(value)) {
callback(new Error("请输入正确的邮箱规则"));
} else {
callback();
}
};
const checkMoabile = (rule, value, callback) => {
const hua = /^1\d{10}$|^(0\d{2,3}-?|\(0\d{2,3}\))?[1-9]\d{4,7}(-\d{1,8})?$/;
if (!hua.test(value)) {
callback(new Error("请输入正确的电话格式"));
} else {
callback();
}
};
return {
// 添加用户对话框初始状态
addUsersVisible: false,
addUsersForm: {
username: "",
password: "",
email: "",
mobile: "",
},
editVisible: false,
set: "",
settVisible: false, //分配权限列表对话框
setting: [], //分配角色数据
list: {
}, //点击分配权限当前行信息
queryInfo: {
query: "",
pagenum: 1,
pagesize: 3,
},
total: 0,
userList: [], //所有数据
editList: {
},
rulesFrom: {
username: [
{
required: true, message: "请输入用户名", trigger: "blur" },
{
min: 2, max: 10, message: "请输入2到10位的字符", trigger: "blur" },
],
password: [
{
required: true, message: "请输入用户密码", trigger: "blur" },
{
min: 6, max: 10, message: "请输入2到10位的字符", trigger: "blur" },
],
email: [
{
required: true, message: "请输入用户邮箱", trigger: "blur" },
{
validator: checkEmail,
message: "请输入正确的邮箱地址",
trigger: "blur",
},
],
mobile: [
{
required: true, message: "请输入用户手机号", trigger: "blur" },
{
validator: checkMoabile,
message: "请输入正确的手机号",
trigger: "blur",
},
],
},
};
},
created() {
this.getList();
},
methods: {
// 点击添加用户按钮
addUser() {
this.addUsersVisible = true;
},
// 点击对话框确认按钮添加用户
async addDialog() {
const {
data: res } = await UsersApi.addFormApi(this.addUsersForm);
if (res.meta.status !== 200) {
this.$message.error(res.meta.msg);
}
this.addUsersVisible = false;
this.getList();
},
// 点击删除
async del(delList) {
const confirmText = await this.$confirm(
"此操作将永久删除该文件, 是否继续?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}
).catch((err) => err);
if (confirmText !== "confirm") {
this.$message.info("已取消删除");
}
const {
data: res } = await UsersApi.del(delList.id);
if (res.meta.status !== 200) {
this.$message.error(res.meta.msg);
}
this.getList();
},
async edit(scope) {
const {
data: res } = await UsersApi.editId(scope.id);
if (res.meta.status !== 200) {
this.$message.error(res.meta.msg);
}
this.editList = res.data;
this.editVisible = true;
},
editAdd() {
this.$refs.editRef.validate(async (valid) => {
if (!valid) return;
const {
data: res } = await UsersApi.edit(
this.editList.id,
this.editList
);
if (res.meta.status !== 200) {
this.$message.error(res.meta.msg);
}
this.$message.success(res.meta.msg);
this.getList();
});
this.editVisible = false;
},
async stat(scope) {
const {
data: res } = await UsersApi.state(scope.id, scope.mg_state);
if (res.meta.status !== 200) {
this.$message.error(res.meta.msg);
}
this.$message.success(res.meta.msg);
this.getList();
},
// 获取所有用户
async getList() {
const {
data: res } = await UsersApi.list({
params: this.queryInfo });
if (res.meta.status !== 200) {
this.$message.error(res.meta.msg);
}
this.userList = res.data.users;
this.total = res.data.total;
},
// 分页
handleSizeChange(val) {
this.queryInfo.pagesize = val;
this.getList();
},
handleCurrentChange(val) {
this.queryInfo.pagenum = val;
this.getList();
},
// 点击分配权限按钮
async sett(scope) {
this.list = scope;
this.settVisible = true;
const {
data: res } = await UsersApi.set();
if (res.meta.status !== 200) {
this.$message.error(res.meta.msg);
}
this.setting = res.data;
},
// 点击确定按钮,分配角色
async settAdd() {
if (this.set === "") {
this.$message({
message: "请选择要分配的角色",
type: "warning",
});
} else {
const {
data: res } = await UsersApi.settAd(this.list.id, {
rid: this.list.id,
});
if (res.meta.status !== 200) {
this.$message.error(res.meta.msg);
}
this.settVisible = false;
this.getList();
this.set = "";
}
},
},
};
</script>
<style lang='scss' scoped>
.el-card {
margin-top: 15px;
}
</style>
首先,封装对应的API
import Serve from '../../util/index'
export default {
// 分配权限
alloc() {
return Serve.get(`rights/tree`)
},
allocSubmit(allocatId, rids) {
return Serve.post(`roles/${
allocatId}/rights`, rids);
},
// 角色列表数据信息
getRolesListApi() {
return Serve.get(`roles`);
},
remove(id) {
return Serve.delete(`/roles/${
id.id}`);
},
// 编辑用户
queryId(item) {
return Serve.get(`roles/${
item.id}`);
},
sumbit(roleId, editList) {
return Serve.put(`roles/${
roleId}`, editList);
},
// tag标签删除
delTags(id, item) {
return Serve.delete(`roles/${
id}/rights/${
item}`);
},
// 添加用户
add(addForm){
return Serve.post(`roles`, addForm);
}
}
建立页面,配置路由
{
path: '/roles',
name: "roles",
component: () => import( /* webpackChunkName: "jurisdiction" */ './components/jurisdiction/roles.vue'),
meta: {
bread: ['权限管理', '角色列表']
}
},
页面代码:
<template>
<div class="roles">
<Bread />
<!-- 卡片式图 -->
<el-card>
<el-button type="primary" @click="addRoleDia = true">添加角色</el-button>
<!-- 表格区域 -->
<el-table :data="tableData" border style="width1: 100%">
<el-table-column type="expand">
<!-- 展开行信息 -->
<template v-slot="scope">
<!-- 一级权限 -->
<el-row
:class="[
'tags',
'rowBottom',
'rowleft',
index1 === 0 ? 'rowTop' : '',
]"
v-for="(item, index1) in scope.row.children"
:key="item.id"
>
<el-col :span="8">
<el-tag
closable
effect="dark"
@close="removeTag(scope.row, item)"
>
{
{
item.authName }}
</el-tag>
<i class="el-icon-caret-right"></i>
</el-col>
<el-col :span="16">
<el-row
:class="[
'rowleft',
'tags',
'rowRigth ',
index2 == 0 ? 'rowBottom' : 'rowTop',
]"
v-for="(item2, index2) in item.children"
:key="item2.id"
>
<!-- 二级权限 -->
<el-col :span="8" class="rowRight">
<el-tag
type="success"
closable
@close="removeTag(scope.row, item2)"
>{
{
item2.authName }}</el-tag
>
<i class="el-icon-caret-right"></i>
</el-col>
<!-- 三级权限 -->
<el-col :span="15" class="rowRight tags">
<el-tag
type="warning"
closable
v-for="item3 in item2.children"
:key="item3.id"
@close="removeTag(scope.row, item3)"
>{
{
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="姓名"> </el-table-column>
<el-table-column prop="roleDesc" label="角色描述"> </el-table-column>
<!-- 操作区域、 -->
<el-table-column label="操作">
<!-- 操作区域 -->
<template v-slot="scope">
<!-- 编辑区域、 -->
<el-button
size="mini"
type="primary"
icon="el-icon-edit"
@click="editQuery(scope.row)"
>编辑</el-button
>
<!-- 删除按钮 -->
<el-button
size="mini"
type="danger"
icon="el-icon-delete"
@click="del(scope.row)"
>删除</el-button
>
<!-- 设置角色-->
<el-button
size="mini"
type="warning"
icon="el-icon-setting"
@click="alloc(scope.row)"
>分配角色</el-button
>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 添加角色对话框 -->
<el-dialog title="添加角色" :visible.sync="addRoleDia" width="30%"
><el-form
:model="addruleForm"
:rules="rules"
ref="addRef"
label-width="80px"
class="demo-ruleForm"
>
<el-form-item label="角色名称" prop="roleName">
<el-input v-model="addruleForm.roleName"></el-input>
</el-form-item>
<el-form-item label="角色描述" prop="roleDesc">
<el-input v-model="addruleForm.roleDesc"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="addRoleDia = false">取 消</el-button>
<el-button type="primary" @click="addSubmit">确 定</el-button>
</span>
</el-dialog>
<!-- 编辑当前行角色对话框 -->
<el-dialog title="修改角色" :visible.sync="editRilesDia" width="30%"
><el-form
:model="editList"
:rules="rules"
ref="editRef"
label-width="80px"
class="demo-ruleForm"
>
<el-form-item label="角色名称" prop="roleName">
<el-input v-model="editList.roleName"></el-input>
</el-form-item>
<el-form-item label="角色描述" prop="roleDesc">
<el-input v-model="editList.roleDesc"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="editRilesDia = false">取 消</el-button>
<el-button type="primary" @click="editSubmit">确 定</el-button>
</span>
</el-dialog>
<!-- 分配权限对话框 -->
<el-dialog
title="分配角色"
@close="allDia"
:visible.sync="allocationDialog"
width="40%"
>
<!--
default-expand-all:默认展开所有节点
node-key:节点的唯一标识
props:配置选项
default-checked-keys:默认勾选的节点
-->
<el-tree
:data="list"
show-checkbox
node-key="id"
default-expand-all
:default-checked-keys="deafks"
:props="defaultProps"
ref="treeRef"
>
</el-tree>
<span slot="footer" class="dialog-footer">
<el-button @click="allocationDialog = false">取 消</el-button>
<el-button type="primary" @click="allocationSubmit">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
// 导入面包屑导航
import Bread from "../bread/bread";
import RolesApi from "../../api/jurisdiction/Roles";
export default {
components: {
Bread,
},
data() {
return {
//添加用户信息
addruleForm: {
roleName: "",
roleDesc: "",
},
addRoleDia: false, //添加用户对话框的初始状态
//表单校验规则
rules: {
roleName: {
required: true,
message: "请输入角色名称",
trigger: "blur",
},
roleDesc: {
required: true,
message: "请输入角色描述",
trigger: "blur",
},
},
tableData: [], //所有数据
// 编辑用户信息
editList: {
}, //点击编辑,获取当前行信息
editRilesDia: false,
// 分配角色数据
allocationDialog: false,
//树形控件
defaultProps: {
children: "children",
label: "authName",
},
allocatId: "",
deafks: [], //属性控件默认被选中的数组
list: [], //所有权限数据信息
};
},
created() {
this.getRolesList();
},
methods: {
// 分配权限
// 分配权限对话框回调函数
allDia() {
this.deafks = [];
},
// 点击分配权限按钮
async alloc(item) {
this.allocatId = item.id;
const {
data: res } = await RolesApi.alloc();
if (res.meta.status !== 200) {
this.$message.error(res.meta.msg);
}
this.list = res.data;
/*
调用递归方法,进行传参,
将点击的当前行的信息,以及保存默认勾选的节点的信息的空数组传入
*/
this.getKeys(item, this.deafks);
this.allocationDialog = true;
},
// 通过递归的方式,获取角色下所有三级权限的id,并且保存到defkeys中去
getKeys(node, arr) {
// 判断当前信息中没有children属性,则证明是三级节点,将其添加到新的数组中
if (!node.children) {
return arr.push(node.id);
}
/*
如果当前行信息中没有children节点的话,
通过遍历这个数组将所有拥有三级节点的节点添加到arr,
也就是defks这个节点中去。
*/
node.children.forEach((item) => this.getKeys(item, arr));
},
// 确定按钮提交分配权限,分配权限对话框
async allocationSubmit() {
/*
getCheckedKeys :
若节点可被选择(即 show-checkbox 为 true),
则返回目前被选中的节点的 key 所组成的数组
getHalfCheckedKeys:
若节点可被选择(即 show-checkbox 为 true),
则返回目前半选中的节点的 key 所组成的数组
*/
const keys = [
...this.$refs.treeRef.getCheckedKeys(),
...this.$refs.treeRef.getHalfCheckedKeys(),
];
// 要求是以字符串形式进行传递
const idObj = keys.join(",");
const {
data: res } = await RolesApi.allocSubmit(this.allocatId, {
rids: idObj,
});
if (res.meta.status !== 200) {
this.$message.error(res.meta.msg);
}
this.allocationDialog = false;
this.$message.success("分配权限成功");
this.getRolesList();
},
// 点击删除tag标签
async removeTag(line, item) {
const confirmText = await this.$confirm(
"此操作将永久删除该权限, 是否继续?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}
).catch((err) => err);
if (confirmText !== "confirm") {
return this.$message.info("已取消删除!");
} else {
const {
data: res } = await RolesApi.delTags(line.id, item.id);
if (res.meta.status !== 200) {
this.$message.success(res.meta.msg);
}
/*
页面在进行删除操作后,需要进行一次刷新,调用所有数据的刷新的话,会关闭展开行
在渲染中是通过插槽当前行下的chaildren进行渲染,所以通过对当前行重新赋值即可
scope.row.children = res.data
*/
line.children = res.data;
}
},
// 点击对话框确定按钮,添加用户
addSubmit() {
this.$refs.addRef.validate(async (valid) => {
if (!valid) return;
const {
data: res } = await RolesApi.add(this.addruleForm);
if (res.meta.status !== 201) {
this.$message.error(res.meta.msg);
}
this.addRoleDia = false;
this.getRolesList();
});
},
// 点击编辑用户按钮查询
async editQuery(item) {
const {
data: res } = await RolesApi.queryId(item);
if (res.meta.status !== 200) {
this.$message.error(res.meta.msg);
}
this.editList = res.data;
this.editRilesDia = true;
},
// 提交编辑用户
editSubmit() {
this.$refs.editRef.validate(async (valid) => {
if (!valid) return;
const {
data: res } = await RolesApi.sumbit(
this.editList.roleId,
this.editList
);
if (res.meta.status !== 200) {
this.$message.error(res.meta.msg);
}
this.editRilesDia = false;
this.getRolesList();
});
},
// 点击删除当前行角色信息
async del(id) {
const confirmText = await this.$confirm(
"此操作将永久删除该角色, 是否继续?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}
).catch((err) => err);
if (confirmText !== "confirm") {
return this.$message.info("已取消删除!");
} else {
const {
data: res } = await RolesApi.remove(id);
if (res.meta.status !== 200) {
this.$message.success(res.meta.msg);
}
this.$message.success(res.meta.msg);
this.getRolesList();
}
},
// 角色列表数据信息
async getRolesList() {
const {
data: res } = await RolesApi.getRolesListApi();
if (res.meta.status !== 200) {
this.$message.error(res.meta.msg);
}
this.$message.success(res.meta.msg);
this.tableData = res.data;
},
},
};
</script>
<style lang="scss" scoped>
.el-card {
margin-top: 15px;
}
.el-table {
margin-top: 15px;
}
.el-tag {
margin: 10px;
}
.el-row {
width: 100%;
border: right 1px #eee;
}
.tags {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.rowTop {
border-top: 1px solid #eee;
}
.rowBottom {
border-bottom: 1px solid #eee;
}
.rowRigth {
border-right: 1px solid #eee;
}
.rowleft {
border-left: 1px solid #eee;
}
</style>
需要注意的是在我们点击分配权限按钮时,引发的逻辑业务
// 点击分配权限按钮
async alloc(item) {
this.allocatId = item.id;
const {
data: res } = await RolesApi.alloc();
if (res.meta.status !== 200) {
this.$message.error(res.meta.msg);
}
this.list = res.data;
/*
调用递归方法,进行传参,
将点击的当前行的信息,以及保存默认勾选的节点的信息的空数组传入
*/
this.getKeys(item, this.deafks);
this.allocationDialog = true;
},
// 通过递归的方式,获取角色下所有三级权限的id,并且保存到defkeys中去
getKeys(node, arr) {
// 判断当前信息中没有children属性,则证明是三级节点,将其添加到新的数组中
if (!node.children) {
return arr.push(node.id);
}
/*
如果当前行信息中没有children节点的话,
通过遍历这个数组将所有拥有三级节点的节点添加到arr,
也就是defks这个节点中去。
*/
node.children.forEach((item) => this.getKeys(item, arr));
},
// 确定按钮提交分配权限,分配权限对话框
async allocationSubmit() {
/*
getCheckedKeys :
若节点可被选择(即 show-checkbox 为 true),
则返回目前被选中的节点的 key 所组成的数组
getHalfCheckedKeys:
若节点可被选择(即 show-checkbox 为 true),
则返回目前半选中的节点的 key 所组成的数组
*/
const keys = [
...this.$refs.treeRef.getCheckedKeys(),
...this.$refs.treeRef.getHalfCheckedKeys(),
];
// 要求是以字符串形式进行传递
const idObj = keys.join(",");
const {
data: res } = await RolesApi.allocSubmit(this.allocatId, {
rids: idObj,
});
if (res.meta.status !== 200) {
this.$message.error(res.meta.msg);
}
this.allocationDialog = false;
this.$message.success("分配权限成功");
this.getRolesList();
},
同样的是对其进行了API
的封装
import Serve from '../../util/index'
export default {
list(){
return Serve.get(`rights/list`)
}
}
其次就是在页面通过v-if
判断条件进行相应的渲染
<template>
<div id="rigths">
<Bread />
<!-- 卡片视图区域、 -->
<el-card>
<el-table :data="list" stripe border>
<el-table-column type="index" label="#"> </el-table-column>
<el-table-column prop="authName" label="权限名称"> </el-table-column>
<el-table-column prop="path" label="路径"> </el-table-column>
<el-table-column prop="level" label="权限等级">
<template v-slot="scope">
<el-tag size="small" type="primary" v-if="scope.row.level === '0'"
>一级</el-tag
>
<el-tag
size="small"
type="success"
v-else-if="scope.row.level === '1'"
>二级</el-tag
>
<el-tag size="small" type="warning" v-else>三级</el-tag>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
import Bread from "../bread/bread";
import RightApi from "../../api/jurisdiction/Rights";
export default {
components: {
Bread,
},
data() {
return {
list: [],
};
},
created() {
this.getList();
},
methods: {
async getList() {
const {
data: res } = await RightApi.list();
this.list = res.data;
},
},
};
</script>
<style lang='scss' scoped>
.el-card {
margin-top: 15px;
}
</style>
想要查看剩余功能的小伙伴请点击:
电商后台管理d02
码字不易,感谢点赞!!!