parent
c471f3c68b
commit
52a5d064a5
|
|
@ -0,0 +1,41 @@
|
|||
<script lang="ts" setup>
|
||||
import { useRoute } from "vue-router";
|
||||
import SidebarItem from "./SidebarItem.vue";
|
||||
import { useSettingsStore } from "@/store/modules/settings";
|
||||
import { useAppStore } from "@/store/modules/app";
|
||||
import variables from "@/styles/variables.module.scss";
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
const appStore = useAppStore();
|
||||
const currRoute = useRoute();
|
||||
const layout = computed(() => settingsStore.layout);
|
||||
const props = defineProps({
|
||||
menuList: {
|
||||
required: true,
|
||||
default: () => {
|
||||
return [];
|
||||
},
|
||||
type: Array<any>,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<el-menu
|
||||
:default-active="layout === 'top' ? '-' : currRoute.path"
|
||||
:collapse="!appStore.sidebar.opened"
|
||||
:background-color="variables.menuBg"
|
||||
:text-color="variables.menuText"
|
||||
:active-text-color="variables.menuActiveText"
|
||||
:unique-opened="false"
|
||||
:collapse-transition="false"
|
||||
:mode="layout === 'top' ? 'horizontal' : 'vertical'"
|
||||
>
|
||||
<sidebar-item
|
||||
v-for="route in menuList"
|
||||
:key="route.path"
|
||||
:item="route"
|
||||
:base-path="route.path"
|
||||
:is-collapse="!appStore.sidebar.opened"
|
||||
/>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
<script lang="ts" setup>
|
||||
import { usePermissionStore } from "@/store/modules/permission";
|
||||
import variables from "@/styles/variables.module.scss";
|
||||
import { useAppStore } from "@/store/modules/app";
|
||||
import { translateRouteTitleI18n } from "@/utils/i18n";
|
||||
const appStore = useAppStore();
|
||||
const tPath = ref();
|
||||
const selectMenu = (index: string) => {
|
||||
appStore.changeTopActive(index);
|
||||
};
|
||||
const permissionStore = usePermissionStore();
|
||||
const topMenu = ref<any[]>([]);
|
||||
onMounted(() => {
|
||||
topMenu.value = permissionStore.routes.filter((el) => !el.meta?.hidden);
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<el-scrollbar>
|
||||
<el-menu
|
||||
mode="horizontal"
|
||||
class="el-menu-demo"
|
||||
:default-active="tPath"
|
||||
:background-color="variables.menuBg"
|
||||
:text-color="variables.menuText"
|
||||
:active-text-color="variables.menuActiveText"
|
||||
@select="selectMenu"
|
||||
>
|
||||
<el-menu-item
|
||||
v-for="route in topMenu"
|
||||
:key="route.path"
|
||||
:index="route.path"
|
||||
>
|
||||
<template #title>
|
||||
<svg-icon
|
||||
v-if="route.meta && route.meta.icon"
|
||||
:icon-class="route.meta.icon"
|
||||
/>
|
||||
<span v-if="route.meta && route.meta.title">{{
|
||||
translateRouteTitleI18n(route.meta.title)
|
||||
}}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
<!-- <sidebar-item
|
||||
v-for="route in topMenu"
|
||||
:key="route.path"
|
||||
:item="route"
|
||||
:base-path="route.path"
|
||||
:is-collapse="false"
|
||||
/> -->
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
|
|
@ -1,18 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
import { useRoute } from "vue-router";
|
||||
import SidebarItem from "./SidebarItem.vue";
|
||||
import TopMenu from "./TopMenu.vue";
|
||||
import LeftMenu from "./LeftMenu.vue";
|
||||
import Logo from "./Logo.vue";
|
||||
|
||||
import { useSettingsStore } from "@/store/modules/settings";
|
||||
import { usePermissionStore } from "@/store/modules/permission";
|
||||
import { useAppStore } from "@/store/modules/app";
|
||||
import { storeToRefs } from "pinia";
|
||||
import variables from "@/styles/variables.module.scss";
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
const permissionStore = usePermissionStore();
|
||||
const appStore = useAppStore();
|
||||
const currRoute = useRoute();
|
||||
const { sidebarLogo } = storeToRefs(settingsStore);
|
||||
const layout = computed(() => settingsStore.layout);
|
||||
const showContent = ref(true);
|
||||
|
|
@ -28,41 +25,86 @@ watch(
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="{ 'has-logo': sidebarLogo }" class="menu-wrap">
|
||||
<div
|
||||
:class="{ 'has-logo': sidebarLogo }"
|
||||
class="menu-wrap"
|
||||
v-if="layout !== 'mix'"
|
||||
>
|
||||
<logo v-if="sidebarLogo" :collapse="!appStore.sidebar.opened" />
|
||||
<el-scrollbar v-if="showContent">
|
||||
<el-menu
|
||||
:default-active="layout === 'top' ? '-' : currRoute.path"
|
||||
:collapse="!appStore.sidebar.opened"
|
||||
:background-color="variables.menuBg"
|
||||
:text-color="variables.menuText"
|
||||
:active-text-color="variables.menuActiveText"
|
||||
:unique-opened="false"
|
||||
:collapse-transition="false"
|
||||
:mode="layout === 'top' ? 'horizontal' : 'vertical'"
|
||||
>
|
||||
<sidebar-item
|
||||
v-for="route in permissionStore.routes"
|
||||
:key="route.path"
|
||||
:item="route"
|
||||
:base-path="route.path"
|
||||
:is-collapse="!appStore.sidebar.opened"
|
||||
/>
|
||||
</el-menu>
|
||||
<LeftMenu :menu-list="permissionStore.routes" />
|
||||
</el-scrollbar>
|
||||
<NavRight v-if="layout === 'top'" />
|
||||
</div>
|
||||
<template v-else>
|
||||
<div :class="{ 'has-logo': sidebarLogo }" class="menu-wrap">
|
||||
<div class="header">
|
||||
<logo v-if="sidebarLogo" :collapse="!appStore.sidebar.opened" />
|
||||
<TopMenu />
|
||||
<NavRight />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
:deep(.setting-container) {
|
||||
.setting-item {
|
||||
color: #fff;
|
||||
|
||||
.svg-icon {
|
||||
margin-right: 0px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.isMix {
|
||||
.menu-wrap {
|
||||
width: 100% !important;
|
||||
height: 50px;
|
||||
background-color: $menuBg;
|
||||
|
||||
:deep(.header) {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
// 顶部模式全局变量修改
|
||||
--el-menu-item-height: 50px;
|
||||
|
||||
.logo-wrap {
|
||||
width: 210px;
|
||||
}
|
||||
|
||||
.el-menu {
|
||||
background-color: $menuBg;
|
||||
|
||||
.el-menu-item {
|
||||
color: $menuText;
|
||||
}
|
||||
}
|
||||
|
||||
.el-scrollbar {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.left-menu {
|
||||
display: inline-block;
|
||||
width: 210px;
|
||||
background-color: $menuBg;
|
||||
|
||||
:deep(.el-menu) {
|
||||
background-color: $menuBg;
|
||||
|
||||
.el-menu-item {
|
||||
color: $menuText;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
import Main from "./main.vue";
|
||||
import { computed, watchEffect } from "vue";
|
||||
import { useWindowSize } from "@vueuse/core";
|
||||
import { AppMain, Navbar, Settings, TagsView } from "./components/index";
|
||||
import Sidebar from "./components/Sidebar/index.vue";
|
||||
import RightPanel from "@/components/RightPanel/index.vue";
|
||||
import LeftMenu from "./components/Sidebar/LeftMenu.vue";
|
||||
|
||||
import { useAppStore } from "@/store/modules/app";
|
||||
import { useSettingsStore } from "@/store/modules/settings";
|
||||
|
||||
import { usePermissionStore } from "@/store/modules/permission";
|
||||
import { useRouter } from "vue-router";
|
||||
const permissionStore = usePermissionStore();
|
||||
const { width } = useWindowSize();
|
||||
|
||||
/**
|
||||
|
|
@ -22,9 +24,31 @@ const WIDTH = 992;
|
|||
const appStore = useAppStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const fixedHeader = computed(() => settingsStore.fixedHeader);
|
||||
const showTagsView = computed(() => settingsStore.tagsView);
|
||||
const showSettings = computed(() => settingsStore.showSettings);
|
||||
const activeTopMenu = computed(() => {
|
||||
return appStore.activeTopMenu;
|
||||
});
|
||||
// 混合模式左侧菜单
|
||||
const mixLeftMenu = ref<any[]>([]);
|
||||
const router = useRouter();
|
||||
watch(
|
||||
() => activeTopMenu.value,
|
||||
(newVal) => {
|
||||
permissionStore.routes.forEach((item) => {
|
||||
if (item.path === newVal) {
|
||||
mixLeftMenu.value = item.children || [];
|
||||
}
|
||||
});
|
||||
console.log(" mixLeftMenu.value ", mixLeftMenu.value);
|
||||
// if (mixLeftMenu.value.length) {
|
||||
// router.push({
|
||||
// path: mixLeftMenu.value[0].path,
|
||||
// });
|
||||
// }
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
const layout = computed(() => settingsStore.layout);
|
||||
|
||||
const classObj = computed(() => ({
|
||||
|
|
@ -33,6 +57,7 @@ const classObj = computed(() => ({
|
|||
withoutAnimation: appStore.sidebar.withoutAnimation,
|
||||
mobile: appStore.device === "mobile",
|
||||
isTop: layout.value === "top",
|
||||
isMix: layout.value === "mix",
|
||||
}));
|
||||
|
||||
watchEffect(() => {
|
||||
|
|
@ -66,21 +91,14 @@ function handleOutsideClick() {
|
|||
></div>
|
||||
|
||||
<Sidebar class="sidebar-container" />
|
||||
|
||||
<div :class="{ hasTagsView: showTagsView }" class="main-container">
|
||||
<div :class="{ 'fixed-header': fixedHeader }">
|
||||
<navbar v-if="layout !== 'top'" />
|
||||
<tags-view v-if="showTagsView" />
|
||||
<template v-if="layout === 'mix'">
|
||||
<div class="mix-wrap">
|
||||
<!-- :menu-list="mixLeftMenu -->
|
||||
<LeftMenu :menu-list="permissionStore.routes" />
|
||||
<Main />
|
||||
</div>
|
||||
|
||||
<!--主页面-->
|
||||
<app-main />
|
||||
|
||||
<!-- 设置面板 -->
|
||||
<RightPanel v-if="showSettings">
|
||||
<settings />
|
||||
</RightPanel>
|
||||
</div>
|
||||
</template>
|
||||
<Main v-else />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -155,4 +173,26 @@ function handleOutsideClick() {
|
|||
// 顶部模式全局变量修改
|
||||
--el-menu-item-height: 50px;
|
||||
}
|
||||
|
||||
.isMix {
|
||||
:deep(.main-container) {
|
||||
display: inline-block;
|
||||
width: calc(100% - 210px);
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.mix-wrap {
|
||||
display: flex;
|
||||
padding-top: 50px;
|
||||
|
||||
.el-menu {
|
||||
width: 210px;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
<script lang="ts" setup>
|
||||
import { computed, watchEffect } from "vue";
|
||||
import { useWindowSize } from "@vueuse/core";
|
||||
import { AppMain, Navbar, Settings, TagsView } from "./components/index";
|
||||
import RightPanel from "@/components/RightPanel/index.vue";
|
||||
|
||||
import { useAppStore } from "@/store/modules/app";
|
||||
import { useSettingsStore } from "@/store/modules/settings";
|
||||
const { width } = useWindowSize();
|
||||
|
||||
/**
|
||||
* 响应式布局容器固定宽度
|
||||
*
|
||||
* 大屏(>=1200px)
|
||||
* 中屏(>=992px)
|
||||
* 小屏(>=768px)
|
||||
*/
|
||||
const WIDTH = 992;
|
||||
|
||||
const appStore = useAppStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const fixedHeader = computed(() => settingsStore.fixedHeader);
|
||||
const showTagsView = computed(() => settingsStore.tagsView);
|
||||
const showSettings = computed(() => settingsStore.showSettings);
|
||||
const layout = computed(() => settingsStore.layout);
|
||||
|
||||
watchEffect(() => {
|
||||
if (width.value < WIDTH) {
|
||||
appStore.toggleDevice("mobile");
|
||||
appStore.closeSideBar(true);
|
||||
} else {
|
||||
appStore.toggleDevice("desktop");
|
||||
|
||||
if (width.value >= 1200) {
|
||||
//大屏
|
||||
appStore.openSideBar(true);
|
||||
} else {
|
||||
appStore.closeSideBar(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div :class="{ hasTagsView: showTagsView }" class="main-container">
|
||||
<div :class="{ 'fixed-header': fixedHeader }">
|
||||
<navbar v-if="layout === 'left'" />
|
||||
<tags-view v-if="showTagsView" />
|
||||
</div>
|
||||
<!--主页面-->
|
||||
<app-main />
|
||||
<!-- 设置面板 -->
|
||||
<RightPanel v-if="showSettings">
|
||||
<settings />
|
||||
</RightPanel>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -14,11 +14,12 @@ export const useAppStore = defineStore("app", () => {
|
|||
const language = useStorage("language", defaultSettings.language);
|
||||
|
||||
const sidebarStatus = useStorage("sidebarStatus", "closed");
|
||||
|
||||
const sidebar = reactive({
|
||||
opened: sidebarStatus.value !== "closed",
|
||||
withoutAnimation: false,
|
||||
});
|
||||
|
||||
const activeTopMenu = useStorage("activeTop", "");
|
||||
/**
|
||||
* 根据语言标识读取对应的语言包
|
||||
*/
|
||||
|
|
@ -68,18 +69,25 @@ export const useAppStore = defineStore("app", () => {
|
|||
function changeLanguage(val: string) {
|
||||
language.value = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* 混合模式顶部切换
|
||||
*/
|
||||
function changeTopActive(val: string) {
|
||||
activeTopMenu.value = val;
|
||||
}
|
||||
return {
|
||||
device,
|
||||
sidebar,
|
||||
language,
|
||||
locale,
|
||||
size,
|
||||
activeTopMenu,
|
||||
toggleDevice,
|
||||
changeSize,
|
||||
changeLanguage,
|
||||
toggleSidebar,
|
||||
closeSideBar,
|
||||
openSideBar,
|
||||
changeTopActive,
|
||||
};
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue