ok,登录界面我们已经开发完毕,并且我们已经能够进入管理系统的首页了,接下来我们就来开发首页的页面。一般来说,管理系统的页面我们都是头部是一个简单的信息展示系统名称和登录用户信息,然后中间的左边是菜单导航栏,右边是内容,对应到elementui的组件中,我们可以找到这个Container 布局容器用于布局,方便快速搭建页面的基本结构。而我们采用这个布局:
Index.vue
拷贝 Element-ui布局对应代码到Index.vue中,并简单修改Index.vue
<template>
<el-container>
<el-aside width="200px">Asideel-aside>
<el-container>
<el-header>
<strong>欢迎来到Daniel的vue-admin管理系统strong>
el-header>
<el-main>Mainel-main>
el-container>
el-container>
template>
<script>
export default {
name: "Index.vue"
}
script>
<style scoped>
.el-container{
padding: 0;
margin: 0;
height: 700px; /*这里写个100不起作用?*/
}
.el-header, .el-footer {
background-color: #B3C0D1;
color: #333;
text-align: center;
line-height: 60px;
}
.el-aside {
background-color: #D3DCE6;
color: #333;
text-align: center;
line-height: 200px;
}
.el-main {
background-color: #E9EEF3;
color: #333;
text-align: center;
line-height: 160px;
}
body > .el-container {
margin-bottom: 40px;
}
.el-container:nth-child(5) .el-aside,
.el-container:nth-child(6) .el-aside {
line-height: 260px;
}
.el-container:nth-child(7) .el-aside {
line-height: 320px;
}
style>
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Index from '../views/Index.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/Login',
name: 'Login',
component: () => import( '../views/Login.vue')
},
{
path: '/Index',
name: 'Index',
component: Index
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
http://localhost:8080/index
Index.vue 当前完整代码:
<template>
<el-container>
<el-aside width="200px">Asideel-aside>
<el-container>
<el-header>
<strong>欢迎来到Daniel的vue-admin管理系统strong>
<div class="header-avatar block">
<el-avatar size="medium" src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png">el-avatar>
<el-dropdown>
<span class="el-dropdown-link">下拉菜单<i class="el-icon-arrow-down el-icon--right">i>span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>个人中心el-dropdown-item>
<el-dropdown-item>退出el-dropdown-item>
el-dropdown-menu>
el-dropdown>
<el-link href="https://blog.csdn.net/weixin_42171159?spm=1010.2135.3001.5343" target="_blank">CSDNel-link>
<el-link href="https://mp.weixin.qq.com/s/pmeZuoOR1hj-KS2NSwPPHg" target="_blank">个人公众号el-link>
div>
el-header>
<el-main>
<el-image :src="require('@/assets/家乡.jpg')" style="width: 100%; height: 100%">el-image>
el-main>
el-container>
el-container>
template>
<script>
export default {
name: "Index.vue"
}
script>
<style scoped>
.el-container{
padding: 0;
margin: 0;
height: 700px; /*这里写个100不起作用?*/
}
.header-avatar{
float: right;
width: 250px;
display: flex;
justify-content: space-around;
align-items: center;
}
.el-dropdown-link {
cursor: pointer;
}
.el-header, .el-footer {
background-color: #B3C0D1;
color: #333;
text-align: center;
line-height: 60px;
}
.el-aside {
background-color: #D3DCE6;
color: #333;
text-align: center;
line-height: 200px;
}
.el-main {
background-color: #E9EEF3;
color: #333;
text-align: center;
line-height: 160px;
}
body > .el-container {
margin-bottom: 40px;
}
.el-container:nth-child(5) .el-aside,
.el-container:nth-child(6) .el-aside {
line-height: 260px;
}
.el-container:nth-child(7) .el-aside {
line-height: 320px;
}
style>
最终显示
<template>
<el-container>
<el-aside width="200px">
<el-menu
class="el-menu-vertical-demo"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b">
<router-link to="/index">
<el-menu-item index="Index">
<template slot="title">
<i class="el-icon-s-home">i>
<span slot="title">首页span>
template>
el-menu-item>
router-link>
<el-submenu index="1">
<template slot="title">
<i class="el-icon-s-operation">i>
<span>系统管理span>
template>
<el-menu-item index="1-1">
<template slot="title">
<i class="el-icon-s-custom">i>
<span slot="title">用户管理span>
template>
el-menu-item>
<el-menu-item index="1-2">
<template slot="title">
<i class="el-icon-rank">i>
<span slot="title">角色管理span>
template>
el-menu-item>
<el-menu-item index="1-3">
<template slot="title">
<i class="el-icon-menu">i>
<span slot="title">菜单管理span>
template>
el-menu-item>
el-submenu>
<el-submenu index="2">
<template slot="title">
<i class="el-icon-s-tools">i>
<span>系统工具span>
template>
<el-menu-item index="2-2">
<template slot="title">
<i class="el-icon-s-order">i>
<span slot="title">数字字典span>
template>
el-menu-item>
el-submenu>
el-menu>
el-aside>
<el-container>
<el-header>
<strong>欢迎来到Daniel的vue-admin管理系统strong>
<div class="header-avatar block">
<el-avatar size="medium" src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png">el-avatar>
<el-dropdown>
<span class="el-dropdown-link">下拉菜单<i class="el-icon-arrow-down el-icon--right">i>span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>个人中心el-dropdown-item>
<el-dropdown-item>退出el-dropdown-item>
el-dropdown-menu>
el-dropdown>
<el-link href="https://blog.csdn.net/weixin_42171159?spm=1010.2135.3001.5343" target="_blank">CSDNel-link>
<el-link href="https://mp.weixin.qq.com/s/pmeZuoOR1hj-KS2NSwPPHg" target="_blank">个人公众号el-link>
div>
el-header>
<el-main>
<el-image :src="require('@/assets/家乡.jpg')" style="width: 100%; height: 100%">el-image>
el-main>
el-container>
el-container>
template>
<script>
export default {
name: "Index.vue"
}
script>
<style scoped>
.el-container{
padding: 0;
margin: 0;
height: 700px; /*这里写个100不起作用?*/
}
.header-avatar{
float: right;
width: 250px;
display: flex;
justify-content: space-around;
align-items: center;
}
.el-dropdown-link {
cursor: pointer;
}
.el-menu-vertical-demo {
height: 100%;
}
.el-header{
background-color: #17b3a3;
color: #333;
text-align: center;
line-height: 60px;
}
.el-aside {
background-color: #D3DCE6;
color: #333;
text-align: center;
line-height: 200px;
}
.el-main {
color: #333;
text-align: center;
}
style>
最终显示: http://localhost:8080/index
2. 因为考虑到后面需要做动态菜单,所以单独 Home.vue 页面出来,因此我新建了个SideMenu.vue
:
SideMenu.vue
<template>
<el-menu
class="el-menu-vertical-demo"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b">
<router-link to="/index">
<el-menu-item index="Index">
<template slot="title">
<i class="el-icon-s-home">i>
<span slot="title">首页span>
template>
el-menu-item>
router-link>
<el-submenu index="1">
<template slot="title">
<i class="el-icon-s-operation">i>
<span>系统管理span>
template>
<el-menu-item index="1-1">
<template slot="title">
<i class="el-icon-s-custom">i>
<span slot="title">用户管理span>
template>
el-menu-item>
<el-menu-item index="1-2">
<template slot="title">
<i class="el-icon-rank">i>
<span slot="title">角色管理span>
template>
el-menu-item>
<el-menu-item index="1-3">
<template slot="title">
<i class="el-icon-menu">i>
<span slot="title">菜单管理span>
template>
el-menu-item>
el-submenu>
<el-submenu index="2">
<template slot="title">
<i class="el-icon-s-tools">i>
<span>系统工具span>
template>
<el-menu-item index="2-2">
<template slot="title">
<i class="el-icon-s-order">i>
<span slot="title">数字字典span>
template>
el-menu-item>
el-submenu>
el-menu>
template>
<script>
export default {
name: "SideMenu"
}
script>
<style scoped>
.el-menu-vertical-demo {
height: 100%;
}
style>
Home.vue
<template>
<el-container>
<el-aside width="200px">
<SideMenu>SideMenu>
el-aside>
<el-container>
<el-header>
<strong>欢迎来到Daniel的vue-admin管理系统strong>
<div class="header-avatar block">
<el-avatar size="medium" src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png">el-avatar>
<el-dropdown>
<span class="el-dropdown-link">下拉菜单<i class="el-icon-arrow-down el-icon--right">i>span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>个人中心el-dropdown-item>
<el-dropdown-item>退出el-dropdown-item>
el-dropdown-menu>
el-dropdown>
<el-link href="https://blog.csdn.net/weixin_42171159?spm=1010.2135.3001.5343" target="_blank">CSDNel-link>
<el-link href="https://mp.weixin.qq.com/s/pmeZuoOR1hj-KS2NSwPPHg" target="_blank">个人公众号el-link>
div>
el-header>
<el-main>
<el-image :src="require('@/assets/家乡.jpg')" style="width: 100%; height: 100%">el-image>
el-main>
el-container>
el-container>
template>
<script>
import SideMenu from "./inc/SideMenu";
export default {
name: "Home.vue",
components: {SideMenu},
}
script>
<style scoped>
.el-container{
padding: 0;
margin: 0;
height: 700px; /*这里写个100不起作用?*/
}
.header-avatar{
float: right;
width: 250px;
display: flex;
justify-content: space-around;
align-items: center;
}
.el-dropdown-link {
cursor: pointer;
}
.el-menu-vertical-demo {
height: 100%;
}
.el-header{
background-color: #17b3a3;
color: #333;
text-align: center;
line-height: 60px;
}
.el-aside {
background-color: #D3DCE6;
color: #333;
text-align: center;
line-height: 200px;
}
.el-main {
color: #333;
text-align: center;
}
style>
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Index from '../views/Index.vue'
Vue.use(VueRouter);
const routes = [
{
path: '/',
name: 'Home',
component: Home,
children:[
{
path: '/Index',
name: 'Index',
component: Index
}
]
},
{
path: '/Login',
name: 'Login',
component: () => import( '../views/Login.vue')
}
];
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
});
export default router
注意SideMenu出现的地方哈,最后效果如下:
这就很接近我们想要的效果了哈😂😂。
我们先来新建几个页面,先在views下新建文件夹sys,然后再新建vue页面,具体看下面,这样我们就能把链接和页面可以连接起来。
src\views\sys
User.vue
用户管理Role.vue
角色管理Menu.vue
菜单管理Dict.vue
数字字典
虽然建立了页面,但是因为我们没有在router中注册链接与组件的关系,所以我们现在打开链接还是打开不了页面的。下面我们就要动态联系起来。
完整 index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Index from '../views/Index.vue'
import User from '../views/sys/User'
import Role from '../views/sys/Role'
import Menu from '../views/sys/Menu'
import Dict from '../views/sys/Dict'
Vue.use(VueRouter);
const routes = [
{
path: '/',
name: 'Home',
component: Home,
children:[
{
path: '/Index',
name: 'Index',
component: Index
},
{
path: '/user',
name: 'User',
component: User
},
{
path: '/role',
name: 'Role',
component: Role
},
{
path: '/menu',
name: 'Menu',
component: Menu
},
{
path: '/dict',
name: 'Dict',
component: Dict
}
]
},
{
path: '/Login',
name: 'Login',
component: () => import( '../views/Login.vue')
}
];
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
});
export default router
完整 SideMenu.vue
<template>
<el-menu
class="el-menu-vertical-demo"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b">
<router-link to="/index">
<el-menu-item index="Index">
<template slot="title">
<i class="el-icon-s-home">i>
<span slot="title">首页span>
template>
el-menu-item>
router-link>
<el-submenu index="1">
<template slot="title">
<i class="el-icon-s-operation">i>
<span>系统管理span>
template>
<router-link to="/user">
<el-menu-item index="1-1">
<template slot="title">
<i class="el-icon-s-custom">i>
<span slot="title">用户管理span>
template>
el-menu-item>
router-link>
<router-link to="/role">
<el-menu-item index="1-2">
<template slot="title">
<i class="el-icon-rank">i>
<span slot="title">角色管理span>
template>
el-menu-item>
router-link>
<router-link to="/menu">
<el-menu-item index="1-3">
<template slot="title">
<i class="el-icon-menu">i>
<span slot="title">菜单管理span>
template>
el-menu-item>
router-link>
el-submenu>
<el-submenu index="2">
<template slot="title">
<i class="el-icon-s-tools">i>
<span>系统工具span>
template>
<router-link to="/dict">
<el-menu-item index="2-2">
<template slot="title">
<i class="el-icon-s-order">i>
<span slot="title">数字字典span>
template>
el-menu-item>
router-link>
el-submenu>
el-menu>
template>
<script>
export default {
name: "SideMenu"
}
script>
<style scoped>
.el-menu-vertical-demo {
height: 100%;
}
style>
最终显示:
管理界面的右上角的用户信息现在是写死的,因为我们现在已经登录成功,所以我们可以通过接口去请求获取到当前的用户信息了,这样我们就可以动态显示用户的信息,这个接口比较简单,然后退出登录的链接也一起完成,就请求接口同时把浏览器中的缓存删除就退出了哈。
①Home.vue
export default {
name: "Home.vue",
components: {SideMenu},
data(){
return{
userInfo:{ /*定义用户信息*/
id:'',
avatar:'',
username:''
}
}
},
created(){ /*调用获取用户的方法*/
this.getUserInfo() /*当页面渲染出来的时候,调用这个方法*/
},
methods:{
getUserInfo(){
this.$axios.get('/sys/userInfo').then(resp=>{
this.userInfo = resp.data.data;
});
}
}
}
③Mock.js
Mock.mock('/sys/userInfo', 'get',() => {
//无法在header中传入数jwt
Result.data = {
id:'1',
avatar:'https://image-1300566513.cos.ap-guangzhou.myqcloud.com/upload/images/5a9f48118166308daba8b6da7e466aab.jpg',
username:'Daniel'
};
return Result
});
最终显示:http://localhost:8080/index
个人中心用来展示用户的基本信息和修改密码,相对简单
UserCenter.vue
<template>
<div style="text-align: center;"><h2>你好!{{ userInfo.username }} 同学h2>
<el-form :model="passForm" status-icon :rules="rules" ref="passForm" label-width="100px">
<el-form-item label="旧密码" prop="currentPass">
<el-input type="password" v-model="passForm.currentPass" autocomplete="off">el-input>
el-form-item>
<el-form-item label="新密码" prop="password">
<el-input type="password" v-model="passForm.password" autocomplete="off">el-input>
el-form-item>
<el-form-item label="确认密码" prop="checkPass">
<el-input type="password" v-model="passForm.checkPass" autocomplete="off">el-input>
el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('passForm')">提交el-button>
<el-button @click="resetForm('passForm')">重置el-button>
el-form-item>
el-form>
div>
template>
<script> export default {
name: "Login", data() {
var validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码'));
} else if (value !== this.passForm.password) {
callback(new Error('两次输入密码不一致!'));
} else {
callback();
}
};
return {
userInfo: {},
passForm: {password: '111111', checkPass: '111111', currentPass: '111111'},
rules: {
password: [{required: true, message: '请输入新密码', trigger: 'blur'}, {
min: 6,
max: 12,
message: '长度在 6 到 12 个字符',
trigger: 'blur'
}],
checkPass: [{required: true, validator: validatePass, trigger: 'blur'}],
currentPass: [{required: true, message: '请输入当前密码', trigger: 'blur'},]
}
}
}, created() {
this.getUserInfo()
}, methods: {
getUserInfo() {
this.$axios.get("/sys/userInfo").then(res => {
this.userInfo = res.data.data;
})
}, submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
const _this = this
this.$axios.post('/sys/user/updataPass', this.passForm).then(res => {
_this.$alert(res.data.msg, '提示', {
confirmButtonText: '确定', callback: action => {
this.$refs[formName].resetFields();
}
});
})
} else {
console.log('error submit!!');
return false;
}
});
}, resetForm(formName) {
this.$refs[formName].resetFields();
}
}
}script>
<style scoped>.el-form {
width: 420px;
margin: 20px auto;
}style>
<el-dropdown-item>
<router-link :to="{name:'UserCenter'}">个人中心router-link>
el-dropdown-item>
当前完整 index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Index from '../views/Index.vue'
import User from '../views/sys/User'
import Role from '../views/sys/Role'
import Menu from '../views/sys/Menu'
import Dict from '../views/sys/Dict'
import UserCenter from '../views/UserCenter'
Vue.use(VueRouter);
const routes = [
{
path: '/',
name: 'Home',
component: Home,
children:[
{
path: '/Index',
name: 'Index',
component: Index
},
{
path: '/userCenter',
name: 'UserCenter',
component: () => import( '../views/UserCenter.vue')
},
{
path: '/sys/user', /*/sysm目的是后期模块的增多易于辨认*/
name: 'User',
component: User
},
{
path: '/sys/role',
name: 'Role',
component: Role
},
{
path: '/sys/menu',
name: 'Menu',
component: Menu
},
{
path: '/sys/dict',
name: 'Dict',
component: Dict
}
]
},
{
path: '/Login',
name: 'Login',
component: () => import( '../views/Login.vue')
}
];
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
});
export default router
5. 个人中心下划线的解决
在 Home.vue中添加样式
a {
text-decoration: none;
}
完整代码:
①②⑤ Home.vue
<template>
<el-container>
<el-aside width="200px">
<SideMenu>SideMenu>
el-aside>
<el-container>
<el-header>
<strong>欢迎来到Daniel的vue-admin管理系统strong>
<div class="header-avatar block">
<el-avatar size="medium" :src="userInfo.avatar">el-avatar>
<el-dropdown>
<span class="el-dropdown-link">{{userInfo.username}}<i class="el-icon-arrow-down el-icon--right">i>span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>
<router-link :to="{name:'UserCenter'}">个人中心router-link>
el-dropdown-item>
<el-dropdown-item @click.native="logout">退出el-dropdown-item>
el-dropdown-menu>
el-dropdown>
<el-link href="https://blog.csdn.net/weixin_42171159?spm=1010.2135.3001.5343" target="_blank">CSDNel-link>
<el-link href="https://mp.weixin.qq.com/s/pmeZuoOR1hj-KS2NSwPPHg" target="_blank">个人公众号el-link>
div>
el-header>
<el-main>
<router-view>router-view>
el-main>
el-container>
el-container>
template>
<script>
import SideMenu from "./inc/SideMenu";
export default {
name: "Home.vue",
components: {SideMenu},
data(){
return{
userInfo:{ /*定义用户信息*/
id:'',
avatar:'',
username:''
}
}
},
created(){ /*调用获取用户的方法*/
this.getUserInfo() /*当页面渲染出来的时候,调用这个方法*/
},
methods:{
getUserInfo(){
this.$axios.get('/sys/userInfo').then(resp=>{
this.userInfo = resp.data.data;
});
},
logout(){
this.$axios.post('/logout').then(resp=>{
//console.log(resp.data.data)
localStorage.clear();
sessionStorage.clear();
this.$store.commit('resetState');
this.$router.push('/Login')
})
}
}
}
script>
<style scoped>
.el-container{
padding: 0;
margin: 0;
height: 700px; /*这里写个100不起作用?*/
}
.header-avatar{
float: right;
width: 250px;
display: flex;
justify-content: space-around;
align-items: center;
}
.el-dropdown-link {
cursor: pointer;
}
.el-menu-vertical-demo {
height: 100%;
}
.el-header{
background-color: #17b3a3;
color: #333;
text-align: center;
line-height: 60px;
}
.el-aside {
background-color: #D3DCE6;
color: #333;
text-align: center;
line-height: 200px;
}
.el-main {
color: #333;
text-align: center;
}
a {
text-decoration: none;
}
style>
③index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
token:''
},
getters: {
},
mutations: {
SET_TOKEN:(state,token)=>{
state.token = token;
localStorage.setItem("token",token)
},
resetState(state){
state.token = "";
}
},
actions: {
},
modules: {
}
})
④mock.js
// 引入mockjs
const Mock = require('mockjs');
// 获取 mock.Random 对象
// 参考:https://github.com/nuysoft/Mock/wiki/Mock.Random
const Random = Mock.Random;
let Result = {
code: 200,
msg: '操作成功',
data: null
};
/** *
* Mock.mock( url, post/get , function(options));
* url 表示需要拦截的 URL,
* post/get 需要拦截的 Ajax 请求类型
* 用于生成响应数据的函数
*/
// 获取验证码图片base64编码以及一个随机码
Mock.mock('/captcha', 'get',() => {
Result.data = {
token: Random.string(32), // 获取一个32位的随机字符串,
captchaImg: Random.dataImage("120x40","p7n5w") //生成验证码为 p7n5w 的base64图片编码
};
return Result
});
Mock.mock('/login', 'post',() => {
//无法在header中传入数jwt
Result.code = 400;
Result.msg = "验证码错误";
return Result
});
Mock.mock('/sys/userInfo', 'get',() => {
//无法在header中传入数jwt
Result.data = {
id:'1',
avatar:'https://image-1300566513.cos.ap-guangzhou.myqcloud.com/upload/images/5a9f48118166308daba8b6da7e466aab.jpg',
username:'Daniel'
};
return Result
});
/*退出*/
Mock.mock('/logout', 'post',() => {
return Result
});
最终显示: