1.欢迎页实现
<template>
<div class="welcome">
<div class="content">
<div class="sub-title">欢迎体验</div>
<div class="title">Vue3通用后台管理系统</div>
<div class="desc">
- Vue3.0+ElementPlus+Node+Mongo打造通用后台管理系统
</div>
</div>
<div class="img"></div>
</div>
</template>
<script>
export default {
name: "welcome",
};
</script>
<style lang="scss">
.welcome {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-color: #fff;
.content {
position: relative;
bottom: 40px;
.sub-title {
font-size: 30px;
line-height: 42px;
color: #333;
}
.title {
font-size: 40px;
line-height: 62px;
color: #409eff;
}
.desc {
text-align: right;
font-size: 14px;
color: #999;
}
}
.img {
margin-left: 105px;
background-image: url("./../assets/images/welcome.png");
width: 371px;
height: 438px;
}
}
</style>
2.首页菜单功能实现
<template>
<div class="basic-layout">
<div :class="['nav', isCollapse ? 'fold' : 'unfold']">
<!-- 系统logo -->
<div class="logo">
<img src='../assets/img/logo-small.png' alt=""/>
<span>HHS_Admin</span>
</div>
<!-- 导航菜单 -->
<el-menu :default-active="activeMenu" class="nav-menu" background-color="#001529"
:router="true" text-color="#fff" :collapse="isCollapse">
<el-submenu index="1">
<template #title>
<i class="el-icon-setting"></i>
<span>系统管理</span>
</template>
<el-menu-item index="1-1">用户管理</el-menu-item>
<el-menu-item index="1-2">菜单管理</el-menu-item>
</el-submenu>
<el-submenu index="2">
<template #title>
<i class="el-icon-s-flag"></i>
<span>审批管理</span>
</template>
<el-menu-item index="2-1">休假申请</el-menu-item>
<el-menu-item index="2-2">待我审核</el-menu-item>
</el-submenu>
</el-menu>
</div>
<div :class="['content', isCollapse ? 'fold' : 'unfold']">
<div class="top-crumb">
<div class="top-crumb-left">
<div class="fold-menu" @click="toggleNav">
<i class="el-icon-s-operation"></i>
</div>
<div class="bread">
面包屑
</div>
</div>
<div class="user-info">
<el-badge :is-dot="true" class="notice" type="danger">
<i class="el-icon-bell"></i>
</el-badge>
<el-dropdown @command="handleCommand">
<span class="username-span">
zzm
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="user">个人中心</el-dropdown-item>
<el-dropdown-item command="updatePwd">修改密码</el-dropdown-item>
<el-dropdown-item command="logout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
<div class="wrapper">
<div class="main">
<router-view></router-view>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "home",
data() {
return {
activeMenu: location.hash.slice(1),
isCollapse: false,
menuTree: [],
userInfo:this.$store.state.userInfo
}
},
mounted() {
},
methods: {
toggleNav() {
this.isCollapse = !this.isCollapse
},
handleCommand(key) {
if (key === 'updatePwd') {
this.$message.success('操作成功')
this.$router.push('/updatePwd')
} else if (key === 'logout') {
this.$storage.clearAll()
this.$store.commit('saveUserInfo','')
this.userInfo = null
this.$router.push('/login')
}else if (key === 'user') {
this.$router.push('/user')
}
},
}
}
</script>
<style lang="scss" scoped>
.basic-layout {
position: relative;
.nav {
position: fixed;
width: 200px;
height: 100vh;
background-color: #001529;
color: white;
overflow-y: auto;
overflow-x: hidden;
transition: width 0.3s;
.logo {
display: flex;
align-items: center;
font-size: 18px;
height: 50px;
img {
margin: 0 16px;
width: 32px;
height: 32px;
}
}
.nav-menu {
height: calc(100vh - 50px);
border-right: none;
}
&.fold {
width: 64px;
}
&.unfold {
width: 200px;
}
}
.content {
margin-left: 200px;
&.fold {
margin-left: 64px;
}
&.unfold {
margin-left: 200px;
}
.top-crumb {
height: 50px;
line-height: 50px;
display: flex;
justify-content: space-between;
border-bottom: 1px solid #ddd;
padding: 0 20px;
.top-crumb-left {
display: flex;
align-items: center;
.fold-menu {
cursor: pointer;
}
.bread {
margin-left: 10px;
}
}
.user-info {
.notice {
margin-right: 20px;
line-height: 25px;
}
.username-span {
cursor: pointer;
color: #4091ff;
}
}
}
.wrapper {
background: #eef0f3;
padding: 20px;
height: calc(100vh - 50px);
.main {
background-color: #fff;
height: 100%;
}
}
}
}
</style>
3.菜单交互及递归实现
<template>
<div class="basic-layout">
<div :class="['nav', isCollapse ? 'fold' : 'unfold']">
<!-- 系统logo -->
<div class="logo">
<img src='../assets/img/logo-small.png' alt=""/>
<span>HHS_Admin</span>
</div>
<!-- 导航菜单 -->
<el-menu
:default-active="activeMenu"
class="nav-menu"
background-color="#001529"
:router="true"
text-color="#fff"
:collapse="isCollapse">
<tree-menu :menuTree="menuTree"/>
</el-menu>
</div>
<div :class="['content', isCollapse ? 'fold' : 'unfold']">
<div class="top-crumb">
<div class="top-crumb-left">
<div class="fold-menu" @click="toggleNav">
<i class="el-icon-s-operation"></i>
</div>
<div class="bread">
面包屑
</div>
</div>
<div class="user-info">
<el-badge :is-dot="noticeCount > 0 ? true : false" class="notice" type="danger">
<i class="el-icon-bell"></i>
</el-badge>
<el-dropdown @command="handleCommand">
<span class="username-span">
{{userInfo.userName}}
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="user">个人中心</el-dropdown-item>
<el-dropdown-item command="email65">邮箱:{{userInfo.userEmail}}</el-dropdown-item>
<el-dropdown-item command="updatePwd">修改密码</el-dropdown-item>
<el-dropdown-item command="logout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
<div class="wrapper">
<div class="main">
<router-view></router-view>
</div>
</div>
</div>
</div>
</template>
<script>
import TreeMenu from './TreeMenu.vue'
export default {
name: "home",
components:{TreeMenu},
data() {
return {
activeMenu: location.hash.slice(1),
isCollapse: false,
menuTree: [],
userInfo:this.$store.state.userInfo,
noticeCount:0
}
},
mounted() {
this.getNoticeCount()
this.getMenuList()
},
methods: {
toggleNav() {
this.isCollapse = !this.isCollapse
},
handleCommand(key) {
if (key === 'updatePwd') {
this.$message.success('操作成功')
this.$router.push('/updatePwd')
} else if (key === 'logout') {
this.$storage.clearAll()
this.$store.commit('saveUserInfo','')
this.userInfo = null
this.$router.push('/login')
}else if (key === 'user') {
this.$router.push('/user')
}
},
async getNoticeCount(){
const res = await this.$api.noticeCount()
this.noticeCount = res
},
async getMenuList(){
try {
const res = await this.$api.getMenuList()
this.menuTree = res
} catch (error) {
console.error(error);
}
},
}
}
</script>
<style lang="scss" scoped>
.basic-layout {
position: relative;
.nav {
position: fixed;
width: 200px;
height: 100vh;
background-color: #001529;
color: white;
overflow-y: auto;
overflow-x: hidden;
transition: width 0.3s;
.logo {
display: flex;
align-items: center;
font-size: 18px;
height: 50px;
img {
margin: 0 16px;
width: 32px;
height: 32px;
}
}
.nav-menu {
height: calc(100vh - 50px);
border-right: none;
}
&.fold {
width: 64px;
}
&.unfold {
width: 200px;
}
}
.content {
margin-left: 200px;
&.fold {
margin-left: 64px;
}
&.unfold {
margin-left: 200px;
}
.top-crumb {
height: 50px;
line-height: 50px;
display: flex;
justify-content: space-between;
border-bottom: 1px solid #ddd;
padding: 0 20px;
.top-crumb-left {
display: flex;
align-items: center;
.fold-menu {
cursor: pointer;
}
.bread {
margin-left: 10px;
}
}
.user-info {
.notice {
margin-right: 20px;
line-height: 25px;
}
.username-span {
cursor: pointer;
color: #4091ff;
}
}
}
.wrapper {
background: #eef0f3;
padding: 20px;
height: calc(100vh - 50px);
.main {
background-color: #fff;
height: 100%;
}
}
}
}
</style>
<template>
<template v-for="item in menuTree" :key="item._id">
<el-submenu v-if="item.children && item.children.length>0 && item.children[0].menuType == 1" :key="item._id" :index="item.path">
<template #title>
<i :class="item.icon"></i>
<span>{{item.menuName}}</span>
</template>
<tree-menu :menuTree="item.children"/>
</el-submenu>
<el-menu-item v-else-if="item.menuType == 1" :index="item.path" :key="item._id">{{item.menuName}}</el-menu-item>
</template>
</template>
<script>
export default {
name:'TreeMenu',
props:{
menuTree:{
type:Array,
default:()=>[]
}
}
}
</script>
<style>
</style>
import request from './../utils/request'
export default {
login(params) {
return request({
url: '/users/login',
method: 'post',
data:params
})
},
noticeCount(params) {
return request({
url: '/leave/count',
method: 'get',
data:{}
})
},
getMenuList(){
return request({
url: '/menu/list',
method: 'get',
data:{}
})
}
}
4.面包屑实现
<template>
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item v-for="(item, index) in breadList" :key="item.path">
<router-link to="/welcome" v-if="index == 0">{{
item.meta.title
}}</router-link>
<span v-else>{{ item.meta.title }}</span>
</el-breadcrumb-item>
</el-breadcrumb>
</template>
<script>
export default {
name: "BreadCrumb",
computed: {
breadList() {
return this.$route.matched;
},
},
};
</script>
<div class="bread">
<BreadCrumb />
</div>
5.补充知识点