mirror of
https://gitee.com/lab1024/smart-admin.git
synced 2025-11-13 14:13:47 +08:00
v1.0.4
This commit is contained in:
443
smart-admin-web/src/components/main/main.vue
Normal file
443
smart-admin-web/src/components/main/main.vue
Normal file
@@ -0,0 +1,443 @@
|
||||
<template>
|
||||
<Layout class="main" style="height: 100%">
|
||||
<Sider
|
||||
:collapsed-width="60"
|
||||
:style="{overflow: 'hidden'}"
|
||||
:width="256"
|
||||
class="left-sider"
|
||||
collapsible
|
||||
hide-trigger
|
||||
v-model="collapsed"
|
||||
>
|
||||
<SideMenu
|
||||
:active-name="$route.name"
|
||||
:collapsed="collapsed"
|
||||
:menu-list="menuList"
|
||||
@on-select="turnToPage"
|
||||
accordion
|
||||
ref="sideMenu"
|
||||
>
|
||||
<!-- 需要放在菜单上面的内容,如Logo,写在side-menu标签内部,如下 -->
|
||||
<div :class="{'collapsed':collapsed}" class="logo-con">
|
||||
<img :src="maxLogo" key="max-logo" v-show="!collapsed" />
|
||||
<img :src="minLogo" key="min-logo" v-show="collapsed" />
|
||||
</div>
|
||||
<div :class="{'collapsed':collapsed}" class="search-bar">
|
||||
<div class="search-box">
|
||||
<Input placeholder="搜索" v-model="searchKeyWord">
|
||||
<Icon @click="collapsed=false" slot="prefix" type="ios-search" />
|
||||
</Input>
|
||||
<div class="searchMenu" v-if="searchKeyWord">
|
||||
<ul>
|
||||
<li
|
||||
:key="index"
|
||||
@click="toRoute(item.name)"
|
||||
v-for="(item, index) in searchListResult"
|
||||
>{{item.title}}</li>
|
||||
<li
|
||||
@click="searchKeyWord = ''"
|
||||
class="noData"
|
||||
v-if="searchListResult.length == 0"
|
||||
>未检索到数据</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SideMenu>
|
||||
</Sider>
|
||||
<Layout>
|
||||
<Header class="header-con">
|
||||
<HeaderBar :collapsed="collapsed" @on-coll-change="handleCollapsedChange">
|
||||
<User :message-unread-count="unreadCount" />
|
||||
<language
|
||||
:lang="local"
|
||||
@on-lang-change="setLocal"
|
||||
style="margin-right: 10px;"
|
||||
v-if="$config.useI18n"
|
||||
/>
|
||||
<Notice />
|
||||
<Fullscreen style="margin-right: 10px;" v-model="isFullscreen" />
|
||||
</HeaderBar>
|
||||
</Header>
|
||||
<Content class="main-content-con">
|
||||
<Layout class="main-layout-con">
|
||||
<div class="tag-nav-wrapper">
|
||||
<TagsNav
|
||||
:list="tagNavList"
|
||||
:value="$route"
|
||||
@input="handleClick"
|
||||
@on-close="handleCloseTag"
|
||||
/>
|
||||
</div>
|
||||
<Content class="content-wrapper">
|
||||
<transition mode="out-in" name="fade-transform">
|
||||
<keep-alive :include="keepAliveIncludes">
|
||||
<router-view :key="key" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
<ABackTop :bottom="80" :height="100" :right="50" container=".content-wrapper"></ABackTop>
|
||||
</Content>
|
||||
</Layout>
|
||||
</Content>
|
||||
</Layout>
|
||||
</Layout>
|
||||
</template>
|
||||
<script>
|
||||
import ABackTop from './components/a-back-top';
|
||||
import SideMenu from './components/side-menu';
|
||||
import HeaderBar from './components/header-bar';
|
||||
import TagsNav from './components/tags-nav';
|
||||
import Notice from './components/notice/notice';
|
||||
import User from './components/user';
|
||||
import Fullscreen from './components/fullscreen';
|
||||
import Language from './components/language';
|
||||
import { mapMutations, mapActions, mapGetters } from 'vuex';
|
||||
import { getNewTagList, routeEqual, getShowMenu } from '@/lib/menu-func';
|
||||
import { routers } from '@/router/routers';
|
||||
import minLogo from '@/assets/images/logo-min.png';
|
||||
import maxLogo from '@/assets/images/logo.png';
|
||||
import { loginApi } from '@/api/login';
|
||||
import './main.less';
|
||||
export default {
|
||||
name: 'Main',
|
||||
components: {
|
||||
SideMenu,
|
||||
HeaderBar,
|
||||
Notice,
|
||||
Language,
|
||||
TagsNav,
|
||||
Fullscreen,
|
||||
User,
|
||||
ABackTop
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 是否折叠
|
||||
collapsed: false,
|
||||
minLogo,
|
||||
maxLogo,
|
||||
// 是否全屏
|
||||
isFullscreen: false,
|
||||
// 缓存的路由:
|
||||
includes: [],
|
||||
searchKeyWord: '',
|
||||
searchList: [],
|
||||
searchListResult: [],
|
||||
menuList: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['errorCount', 'userMenuPrivilege']),
|
||||
tagNavList() {
|
||||
return this.$store.state.app.tagNavList;
|
||||
},
|
||||
tagRouter() {
|
||||
return this.$store.state.app.tagRouter;
|
||||
},
|
||||
keepAliveIncludes() {
|
||||
return this.$store.state.app.keepAliveIncludes;
|
||||
},
|
||||
cacheList() {
|
||||
const list = [
|
||||
'ParentView',
|
||||
...(this.tagNavList.length
|
||||
? this.tagNavList
|
||||
.filter(item => !(item.meta && item.meta.noKeepAlive))
|
||||
.map(item => item.name)
|
||||
: [])
|
||||
];
|
||||
return list;
|
||||
},
|
||||
local() {
|
||||
return this.$store.state.app.local;
|
||||
},
|
||||
hasReadErrorPage() {
|
||||
return this.$store.state.app.hasReadErrorPage;
|
||||
},
|
||||
unreadCount() {
|
||||
return this.$store.state.user.unreadCount;
|
||||
},
|
||||
key() {
|
||||
return this.$route.name;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
searchKeyWord(val) {
|
||||
if (val) {
|
||||
this.searchListResult = this.searchList.filter(
|
||||
item => item.title.indexOf(val) >= 0
|
||||
);
|
||||
}
|
||||
},
|
||||
$route(newRoute) {
|
||||
const { name, query, params, meta } = newRoute;
|
||||
this.addTag({
|
||||
route: {
|
||||
name,
|
||||
query,
|
||||
params,
|
||||
meta
|
||||
},
|
||||
type: 'push'
|
||||
});
|
||||
this.setBreadCrumb(newRoute);
|
||||
// this.pushKeepAliveIncludes(newRoute);
|
||||
this.setTagNavList(getNewTagList(this.tagNavList, newRoute));
|
||||
this.$refs.sideMenu.updateOpenName(newRoute.name);
|
||||
// 如果param参数 存在 noKeepAlive切位true
|
||||
let isParamNoKeepAlive = params && params.noKeepAlive === true;
|
||||
// 如果query参数 存在 noKeepAlive切位true
|
||||
let isQueryNoKeepAlive = query && query.noKeepAlive === true;
|
||||
// 如果router meta 存在 noKeepAlive
|
||||
let isMetaNoKeepAlive = meta && meta.noKeepAlive === true;
|
||||
//如果存在noKeepAlive且已经缓存了,需要去掉
|
||||
if (isParamNoKeepAlive || isMetaNoKeepAlive || isQueryNoKeepAlive) {
|
||||
// 去掉keep-alive
|
||||
this.deleteKeepAliveIncludes(name);
|
||||
return;
|
||||
}
|
||||
//默认缓存住所有
|
||||
this.pushKeepAliveIncludes(name);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
/**
|
||||
* @description 初始化设置面包屑导航和标签导航
|
||||
*/
|
||||
this.setTagNavList();
|
||||
this.setHomeRoute(routers);
|
||||
this.setCollapsed();
|
||||
this.setBreadCrumb(this.$route);
|
||||
//初始化左侧菜单
|
||||
this.initSideMenu();
|
||||
const { name, params, query, meta } = this.$route;
|
||||
this.addTag({
|
||||
route: {
|
||||
name,
|
||||
params,
|
||||
query,
|
||||
meta
|
||||
}
|
||||
});
|
||||
|
||||
// 设置初始语言
|
||||
this.setLocal(this.$i18n.locale);
|
||||
// 如果当前打开页面不在标签栏中,跳到homeName页
|
||||
if (!this.tagNavList.find(item => item.name === this.$route.name)) {
|
||||
this.$router.push({
|
||||
name: this.$config.homeName
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations([
|
||||
'setBreadCrumb',
|
||||
'setTagNavList',
|
||||
'pushKeepAliveIncludes',
|
||||
'clearKeepAliveIncludes',
|
||||
'deleteKeepAliveIncludes',
|
||||
'deleteOtherKeepAliveIncludes',
|
||||
'addTag',
|
||||
'setLocal',
|
||||
'setHomeRoute',
|
||||
'closeTag'
|
||||
]),
|
||||
...mapActions(['handleLogin']),
|
||||
|
||||
initSideMenu() {
|
||||
//如果是登录跳转过来
|
||||
if (this.$store.state.user.isUpdatePrivilege) {
|
||||
this.$Spin.show();
|
||||
this.buildMenuTree();
|
||||
this.$refs.sideMenu.updateActiveName(this.$route.name);
|
||||
this.$Spin.hide();
|
||||
} else {
|
||||
//如果页面刷新,需要重新获取权限
|
||||
(async () => {
|
||||
this.$Spin.show();
|
||||
let sessionResult = await loginApi.getSession();
|
||||
//设置权限
|
||||
this.$store.commit(
|
||||
'setUserPrivilege',
|
||||
sessionResult.data.privilegeList
|
||||
);
|
||||
this.buildMenuTree();
|
||||
//刷新以后手动更新左侧菜单打开和选中
|
||||
this.$refs.sideMenu.updateActiveName(this.$route.name);
|
||||
this.$Spin.hide();
|
||||
})();
|
||||
}
|
||||
},
|
||||
buildMenuTree() {
|
||||
let privilegeTree = [];
|
||||
for (const router of routers) {
|
||||
//过滤非菜单
|
||||
if (!router.meta.hideInMenu) {
|
||||
//判断是否有权限
|
||||
if (
|
||||
this.$store.state.user.privilegeMenuKeyList.indexOf(router.name) !==
|
||||
-1
|
||||
) {
|
||||
let menu = {
|
||||
name: router.name,
|
||||
meta: router.meta,
|
||||
icon: _.isUndefined(router.meta.icon) ? '' : router.meta.icon,
|
||||
children: []
|
||||
};
|
||||
privilegeTree.push(menu);
|
||||
//存在孩子节点,开始递归
|
||||
if (router.children && router.children.length > 0) {
|
||||
this.recursion(router.children, menu);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.menuList = privilegeTree;
|
||||
},
|
||||
|
||||
recursion(children, parentMenu) {
|
||||
for (const router of children) {
|
||||
//过滤非菜单
|
||||
if (!router.meta.hideInMenu) {
|
||||
let menu = {
|
||||
name: router.name,
|
||||
meta: router.meta,
|
||||
icon: _.isUndefined(router.meta.icon) ? '' : router.meta.icon,
|
||||
children: []
|
||||
};
|
||||
this.searchList.push({
|
||||
name: router.name,
|
||||
title: router.meta.title
|
||||
});
|
||||
parentMenu.children.push(menu);
|
||||
//存在孩子节点,开始递归
|
||||
if (router.children && router.children.length > 0) {
|
||||
this.recursion(router.children, menu);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// 自适应左侧导航宽度
|
||||
setCollapsed() {
|
||||
let setWidth = () => {
|
||||
let width = document.body.offsetWidth;
|
||||
if (width < 1340) {
|
||||
this.collapsed = true;
|
||||
} else {
|
||||
this.collapsed = false;
|
||||
}
|
||||
};
|
||||
setWidth();
|
||||
window.onresize = () => setWidth();
|
||||
},
|
||||
turnToPage(route) {
|
||||
let { name, params, query } = {};
|
||||
if (typeof route === 'string') name = route;
|
||||
else {
|
||||
name = route.name;
|
||||
params = route.params;
|
||||
query = route.query;
|
||||
}
|
||||
if (name.indexOf('isTurnByHref_') > -1) {
|
||||
window.open(name.split('_')[1]);
|
||||
return;
|
||||
}
|
||||
this.$router.push({
|
||||
name,
|
||||
params,
|
||||
query
|
||||
});
|
||||
},
|
||||
handleCollapsedChange(state) {
|
||||
this.collapsed = state;
|
||||
},
|
||||
handleCloseTag(res, type, route) {
|
||||
let keepRouter = route ? route.name : null;
|
||||
if (type !== 'others') {
|
||||
if (type === 'all') {
|
||||
this.turnToPage(this.$config.homeName);
|
||||
this.clearKeepAliveIncludes(this.$config.homeName);
|
||||
} else {
|
||||
//如果是关闭单个tag,则从keepAliveIncludes将关闭的那个移除掉
|
||||
this.deleteKeepAliveIncludes(route.name);
|
||||
if (routeEqual(this.$route, route)) {
|
||||
this.closeTag(route);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 如果是关闭其他(others),则只会保留本页面和home页面
|
||||
this.deleteOtherKeepAliveIncludes(this.$route.name);
|
||||
}
|
||||
this.setTagNavList(res);
|
||||
},
|
||||
handleClick(item) {
|
||||
this.turnToPage(item);
|
||||
},
|
||||
// 跳转路由
|
||||
toRoute(name) {
|
||||
this.$router.push({ name });
|
||||
this.searchKeyWord = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
/*fade*/
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.28s;
|
||||
}
|
||||
|
||||
.fade-enter,
|
||||
.fade-leave-active {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/*fade-transform*/
|
||||
.fade-transform-leave-active,
|
||||
.fade-transform-enter-active {
|
||||
transition: all 0.5s;
|
||||
}
|
||||
.fade-transform-enter {
|
||||
opacity: 0;
|
||||
transform: translateX(-30px);
|
||||
}
|
||||
.fade-transform-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(30px);
|
||||
}
|
||||
|
||||
.search-box {
|
||||
position: relative;
|
||||
z-index: 999;
|
||||
.searchMenu {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
width: 100%;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 3px;
|
||||
padding-left: 20px;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
font-size: 12px;
|
||||
left: 0;
|
||||
margin-top: 1px;
|
||||
ul,
|
||||
li {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
}
|
||||
li {
|
||||
line-height: 28px;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: #3399ff;
|
||||
}
|
||||
&.noData {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user