welcome.vue
<template>
<div class="welcome">
<div class="content">
<div class="sub-title">欢迎体验</div>
<div class="title">慕课通用后台管理系统</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>
home.vue
<template>
<div class="basic-layout">
<div :class="['nav-side', isCollapse ? 'fold' : 'unfold']">
<!-- 系统LOGO -->
<div class="logo">
<img src="./../assets/logo.png" />
<span>Manager</span>
</div>
<!-- 导航菜单 -->
<el-menu
:default-active="activeMenu"
background-color="#001529"
text-color="#fff"
router
:collapse="isCollapse"
class="nav-menu"
>
<tree-menu :userMenu="userMenu" />
</el-menu>
</div>
<div :class="['content-right', isCollapse ? 'fold' : 'unfold']">
<div class="nav-top">
<div class="nav-left">
<div class="menu-fold" @click="toggle">
<i class="el-icon-s-fold"></i>
</div>
<div class="bread">
<BreadCrumb />
</div>
</div>
<div class="user-info">
<el-badge
:is-dot="noticeCount > 0 ? true : false"
class="notice"
type="danger"
@click="$router.push('/audit/approve')"
>
<i class="el-icon-bell"></i>
</el-badge>
<el-dropdown @command="handleLogout">
<span class="user-link">
{{ userInfo.userName }}
<i class="el-icon--right"></i>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="email"
>邮箱:{{ userInfo.userEmail }}</el-dropdown-item
>
<el-dropdown-item command="logout">退出</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
<div class="wrapper">
<router-view></router-view>
</div>
</div>
</div>
</template>
<script>
import TreeMenu from "./TreeMenu.vue";
import BreadCrumb from "./BreadCrumb.vue";
export default {
name: "Home",
components: { TreeMenu, BreadCrumb },
data() {
return {
isCollapse: false,
userInfo: this.$store.state.userInfo,
noticeCount: 0,
userMenu: [],
activeMenu: location.hash.slice(1),
};
},
computed: {
noticeCount() {
return this.$store.state.noticeCount;
},
},
mounted() {
this.getNoticeCount();
this.getMenuList();
},
methods: {
toggle() {
this.isCollapse = !this.isCollapse;
},
handleLogout(key) {
if (key == "email") return;
this.$store.commit("saveUserInfo", "");
this.userInfo = {};
this.$router.push("/login");
},
async getNoticeCount() {
try {
const count = await this.$api.noticeCount();
this.$store.commit("saveNoticeCount", count);
} catch (error) {
console.error(error);
}
},
async getMenuList() {
try {
const { menuList, actionList } = await this.$api.getPermissionList();
this.$store.commit("saveMenuList", menuList);
this.$store.commit("saveActionList", actionList);
this.userMenu = menuList;
} catch (error) {
console.error(error);
}
},
},
};
</script>
<style lang="scss">
.basic-layout {
position: relative;
.nav-side {
position: fixed;
width: 200px;
height: 100vh;
background-color: #001529;
color: #fff;
overflow-y: auto;
transition: width 0.5s;
.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-right {
margin-left: 200px;
// 合并
&.fold {
margin-left: 64px;
}
// 展开
&.unfold {
margin-left: 200px;
}
.nav-top {
height: 50px;
line-height: 50px;
display: flex;
justify-content: space-between;
border-bottom: 1px solid #ddd;
padding: 0 20px;
.nav-left {
display: flex;
align-items: center;
.menu-fold {
margin-right: 15px;
font-size: 18px;
}
}
.user-info {
.notice {
line-height: 30px;
margin-right: 15px;
cursor: pointer;
}
.user-link {
cursor: pointer;
color: #409eff;
}
}
}
.wrapper {
background: #eef0f3;
padding: 20px;
height: calc(100vh - 50px);
.main-page {
background: #fff;
height: 100%;
}
}
}
}
</style>
/**
* api管理
*/
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: {},
mock: false
})
},
getMenuList(params) {
return request({
url: '/menu/list',
method: 'get',
data: params,
mock: false
})
},
template.vue
<template>
<template v-for="menu in userMenu">
<el-submenu
v-if="
menu.children &&
menu.children.length > 0 &&
menu.children[0].menuType == 1
"
:key="menu._id"
:index="menu.path"
>
<template #title>
<i :class="menu.icon"></i>
<span>{{ menu.menuName }}</span>
</template>
<tree-menu :userMenu="menu.children" />
</el-submenu>
<el-menu-item
v-else-if="menu.menuType == 1"
:index="menu.path"
:key="menu.id"
>{{ menu.menuName }}</el-menu-item
>
</template>
</template>
<script>
export default {
name: "TreeMenu",
props: {
userMenu: {
type: Array,
default() {
return [];
},
},
},
};
</script>
面包屑
<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>