Skip to content

Commit

Permalink
feat: 加上菜单侧边栏和左侧模式
Browse files Browse the repository at this point in the history
  • Loading branch information
yuntian001 committed Nov 5, 2023
1 parent 279a93c commit 63e83c6
Show file tree
Hide file tree
Showing 15 changed files with 289 additions and 42 deletions.
105 changes: 104 additions & 1 deletion src/components/meSettingMenu.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
<template>
<el-drawer v-model="setting.showSettingMenu" :title="$t('项目配置')" size="300px" append-to-body>
<el-form label-position="left" label-width="170px">
<el-form class="content" label-position="left" label-width="170px">
<div class="title">
<div class="title-content">{{ $t('布局') }}</div>
</div>
<div class="info" :style="{ '--primaryColor': themeConfig.primaryColor }">
<div
class="layout-base layout-left"
:class="{ active: themeConfig.menuType === 'sidebar' }"
:title="$t('左侧菜单模式')"
@click="themeConfig.menuType = 'sidebar'"
></div>
<div
class="layout-base layout-top"
:class="{ active: themeConfig.menuType === 'top' }"
:title="$t('顶部菜单混合模式')"
@click="themeConfig.menuType = 'top'"
></div>
</div>
<div class="title">
<div class="title-content">{{ $t('配置') }}</div>
</div>
<el-form-item :label="$t('主题色')">
<el-color-picker v-model="themeConfig.primaryColor" :predefine="predefinePrimaryColors" />
</el-form-item>
Expand Down Expand Up @@ -79,4 +99,87 @@ const clear = () => {
setting.clearCache();
userStore.logOut();
};
const activeColor = computed(() => themeConfig.value.primaryColor);
</script>
<style lang="scss" scoped>
.content {
margin-top: -32px;
.title {
display: block;
height: 1px;
width: 100%;
margin: 24px 0;
border-top: 1px var(--el-border-color) var(--el-border-style);
position: relative;
.title-content {
position: absolute;
background-color: var(--el-bg-color);
padding: 0 20px;
font-weight: 500;
color: var(--el-text-color-primary);
font-size: 14px;
left: 50%;
transform: translate(-50%) translateY(-50%);
}
}
.info {
display: flex;
justify-content: center;
.layout-base {
width: 50px;
height: 50px;
border-radius: 5px;
position: relative;
background: #e5e7eb;
border: 1px solid #e5e7eb;
margin-right: 15px;
cursor: pointer;
}
.active {
border: 2px solid var(--primaryColor) !important;
}
.layout-left::before {
content: '';
background-color: #000;
position: absolute;
left: 0;
width: 10px;
top: 0;
bottom: 0;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
.layout-left::after {
content: '';
background-color: #fff;
position: absolute;
left: 10px;
right: 0;
top: 0;
height: 10px;
border-top-right-radius: 5px;
}
.layout-top::before {
content: '';
background-color: #000;
position: absolute;
left: 0;
width: 10px;
top: 10px;
bottom: 0;
border-bottom-left-radius: 5px;
}
.layout-top::after {
content: '';
background-color: #fff;
position: absolute;
left: 0;
right: 0;
top: 0;
height: 10px;
border-top-right-radius: 5px;
border-top-left-radius: 5px;
}
}
}
</style>
2 changes: 1 addition & 1 deletion src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import loginConfig from './login';
import themeConfig from './theme';
const settingKey = 'me-config';
const settingConfig = {
version: '1.0.3', //版本当版本改变时会清空localStorage和sessionStorage
version: '1.0.4', //版本当版本改变时会清空localStorage和sessionStorage
openKeepAlive: true, // 是否开启KeepAlive缓存
menuMode: MenuModeEnum.STATIC, // 菜单模式
};
Expand Down
1 change: 1 addition & 0 deletions src/config/theme.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { SizeEnum } from '@/dict/configEnum';
export default {
primaryColor: '#409eff', // 主题颜色
menuType: 'sidebar' as 'top' | 'sidebar', //菜单模式,顶部模式/侧边栏模式
menuBg: '#1d1e1f', // 菜单背景颜色
menuWidth: '200px', // 菜单展开宽度
menuCollapse: true, // 菜单是否折叠
Expand Down
19 changes: 19 additions & 0 deletions src/layout/components/expand.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<template>
<div>
<mel-icon-expand v-if="themeConfig.menuCollapse" class="fold-expand pointer" @click="setMenuCollapse">
</mel-icon-expand>
<mel-icon-fold v-else class="fold-expand pointer" @click="setMenuCollapse"></mel-icon-fold>
</div>
</template>

<script setup lang="ts" name="Expand">
import { useSettingStore } from '@/store';
const { themeConfig } = storeToRefs(useSettingStore());
const setMenuCollapse = () => {
themeConfig.value.menuCollapse = !themeConfig.value.menuCollapse;
};
</script>
<style lang="scss" scoped>
.expand {
}
</style>
1 change: 1 addition & 0 deletions src/layout/components/header/components/tagBar/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ watch(route, () => {
height: $header-tag-height;
display: flex;
align-items: center;
background-color: var(--el-bg-color);
.is-disabled {
color: var(--el-disabled-text-color) !important;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
<template>
<el-space class="left">
<div></div>
<mel-icon-expand v-if="themeConfig.menuCollapse" class="fold-expand pointer" @click="setMenuCollapse">
</mel-icon-expand>
<mel-icon-fold v-else class="fold-expand pointer" @click="setMenuCollapse"></mel-icon-fold>
<Expand></Expand>
<el-scrollbar
v-if="!globalStore.isMobile && themeConfig.breadcrumb"
:min-size="10"
Expand All @@ -24,11 +22,9 @@
import { mitter, event } from '@/event';
import { useSettingStore, useGlobalStore, useRouteStore } from '@/store';
import { RouteLocationNormalized, RouteRecordRaw } from 'vue-router';
import Expand from '@/layout/components/expand.vue';
const { themeConfig } = storeToRefs(useSettingStore());
const globalStore = useGlobalStore();
const setMenuCollapse = () => {
themeConfig.value.menuCollapse = !themeConfig.value.menuCollapse;
};
const breadcrumbList = ref([] as Pick<RouteRecordRaw, 'name' | 'path' | 'meta' | 'redirect'>[]);
const route = useRoute();
const { routes } = storeToRefs(useRouteStore());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<template>
<el-menu class="menu" :default-active="activeMenu" mode="horizontal">
<layout-menu-item
v-for="item in menus"
:key="item.path"
:no-child="true"
:item="item"
:collapse="themeConfig.menuCollapse"
/>
</el-menu>
</template>

<script setup lang="ts" name="TopMenu">
const { themeConfig } = storeToRefs(useSettingStore());
import { useRouteStore, useSettingStore } from '@/store';
const routeStore = useRouteStore();
const route = useRoute();
const menus = computed(() => {
return routeStore.routes; //.map(item=>Object.assign({},item,{children:[]}));
});
const activeMenu = computed(() => {
return route.meta.menuIndex?.[0] + '';
});
</script>
<style lang="scss" scoped>
.top-menu {
}
</style>
12 changes: 11 additions & 1 deletion src/layout/components/header/components/topBar/index.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
<template>
<div class="top-bar">
<Left></Left>
<Title v-if="menuType === 'top'"></Title>
<Left v-else></Left>
<top-menu v-if="menuType === 'top'"></top-menu>
<Right></Right>
</div>
</template>

<script setup lang="ts" name="TopBar">
import { useSettingStore } from '@/store';
import Left from './components/left.vue';
import Right from './components/right/index.vue';
import TopMenu from './components/topMenu.vue';
import Title from '@/layout/components/title.vue';
const { menuType } = storeToRefs(useSettingStore());
</script>
<style lang="scss" scoped>
.top-bar {
Expand All @@ -16,5 +22,9 @@ import Right from './components/right/index.vue';
align-items: center;
justify-content: space-between;
border-bottom: 1px solid var(--el-border-color);
overflow: hidden;
.menu {
flex: 1;
}
}
</style>
1 change: 0 additions & 1 deletion src/layout/components/header/index.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<template>
<div class="layout-header">
<top-bar v-if="themeConfig.topBar"></top-bar>
<tag-bar v-if="themeConfig.tagBar"></tag-bar>
</div>
</template>
<script setup lang="ts" name="LayoutHeader">
Expand Down
47 changes: 40 additions & 7 deletions src/layout/components/menu/components/menuItem.vue
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
<template>
<template v-if="menu">
<el-sub-menu v-if="menu.children?.length" :index="menu.path">
<el-sub-menu v-if="menu.children?.length && !noChild" :index="menu.path">
<template v-if="menu.meta" #title>
<component :is="menu.meta!.icon" v-if="menu.meta!.icon" />
<div v-show="collapse" v-else class="icon-text">{{ $t(menu.meta.title).slice(0, 1) }}</div>
<span class="menu">{{ $t(menu.meta!.title!) }}</span>
</template>
<layout-menu-item v-for="child in menu.children" :key="child.path" :item="child"></layout-menu-item>
</el-sub-menu>
<template v-else>
<component
:is="menu.meta?.isLink ? 'a' : 'routerLink'"
:is="truePathMenu!.meta?.isLink ? 'a' : 'routerLink'"
v-if="menu.meta && menu.meta.title"
:href="menu.path"
:to="menu.path"
:href="truePathMenu!.path"
:to="truePathMenu!.path"
>
<el-menu-item :index="menu.path" :title="$t(menu.meta.title)">
<el-menu-item :index="noChild ? item.meta?.menuIndex?.toString() : menu.path" :title="$t(menu.meta.title)">
<component :is="menu.meta.icon" v-if="menu.meta.icon" />
<div v-show="collapse" v-else class="icon-text">{{ $t(menu.meta.title).slice(0, 1) }}</div>
<template #title>
<span class="menu">{{ $t(menu.meta.title) }}</span>
</template>
Expand All @@ -26,8 +28,10 @@
</template>

<script setup lang="ts" name="MenuItem">
import { useRouteStore, useSettingStore } from '@/store';
import { RouteRecordRaw } from 'vue-router';
const props = defineProps<{ item: RouteRecordRaw }>();
const routeStore = useRouteStore();
const props = defineProps<{ item: RouteRecordRaw; noChild?: boolean; collapse?: boolean }>();
const menu = ref<RouteRecordRaw>();
const getMenu = (item: RouteRecordRaw): RouteRecordRaw => {
if (!item.children?.length) {
Expand All @@ -40,7 +44,36 @@ const getMenu = (item: RouteRecordRaw): RouteRecordRaw => {
}
return res;
};
const truePathMenu = ref<RouteRecordRaw>();
if (!props.item.meta?.hideMenu) {
menu.value = getMenu(props.item);
truePathMenu.value = menu.value = getMenu(props.item);
}
if (props.noChild) {
const firstChildrenMenu: (children: RouteRecordRaw[]) => RouteRecordRaw | undefined = (
children: RouteRecordRaw[],
) => {
for (let i = 0; i < children.length; i++) {
if (!children[i].meta?.hideMenu) {
return children[i];
}
if (children[i].children) {
const item = firstChildrenMenu(children[i].children!);
if (item) {
return item;
}
}
return undefined;
}
};
if (menu.value?.children?.length) {
truePathMenu.value = firstChildrenMenu(menu.value.children) ?? menu.value;
}
routeStore.childsRoutes[props.item!.meta!.menuIndex![0]] = menu.value?.children ?? [];
}
</script>
<style lang="scss" scoped>
.icon-text {
width: 1em;
text-align: center;
}
</style>
Loading

0 comments on commit 63e83c6

Please sign in to comment.