<template> <div class="ns-nav-content"> <div class="ns-nav"> <div class="ns-nav-head"> <h4 v-if="!sideMenus.backTo" class="ns-nav-title">{{ sideMenus.title }}</h4> <a-button v-else class="ns-nav-back" type="link" @click="navigation(sideMenus.backTo as any)"> <template #icon> <left-outlined /> </template> 返回 </a-button> </div> <a-menu v-model:selectedKeys="selectedKeys" :open-keys="openKeys" class="nav-menu" mode="inline"> <template v-for="menu in menus"> <a-sub-menu v-if="menu.submenus && menu.ifShow" :key="menu.name"> <template #title>{{ menu.label }}</template> <template v-for="subMenu in menu.submenus" :key="subMenu.name"> <a-menu-item v-if="subMenu.ifShow" :class="{ 'nav-current': currentRouter(subMenu.url) }"> <router-link :class="{ 'nav-sub-current': currentRouter(subMenu.url) }" :to="{ name: subMenu.name }" active-class="nav-sub-current" class="nav-sub-item" @click="navChange()"> <span>{{ subMenu.label }}</span> </router-link> </a-menu-item> </template> </a-sub-menu> <a-menu-item v-else :key="menu.name" :class="{ 'nav-current': currentRouter(menu.url) }" v-if="menu.ifShow"> <router-link :class="{ 'nav-sub-current': currentRouter(menu.url) }" :to="{ name: menu.name }" active-class="nav-sub-current" class="nav-sub-item" @click="navChange()"> <span>{{ menu.label }}</span> </router-link> </a-menu-item> </template> </a-menu> </div> <div class="ns-content"> <router-view /> </div> </div> <!-- <router-view /> --> </template> <script lang="ts"> import { computed, defineComponent, ref, unref, watch } from 'vue'; import { useRoute, useRouter } from 'vue-router'; import { ModuleRes, SideMenu, SideMenuItem } from '/nerv-lib/paas/store/modules/config-service'; import { LeftOutlined } from '@ant-design/icons-vue'; import { authorizationService } from '/nerv-lib/paas'; import { cloneDeep, isFunction } from 'lodash-es'; export default defineComponent({ name: 'NsNavContent', components: { LeftOutlined, }, setup() { const router = useRouter(); const route = useRoute(); if (!route?.meta?.sideMenus) { console.error(route.name, ' has not meta.sideMenus'); } const authService = authorizationService(); const modulesRes = authService.ModulesRes; const appInfo = cloneDeep( modulesRes.find((item) => item.app === authService.getApp()), ) as ModuleRes; // console.log('modulesRes', modulesRes); // console.log('appInfo', appInfo); const menus = ref<any[]>([]); const selectedKeys = ref<any[]>([]); const openKeys = ref<any[]>([]); const sideMenus = computed(() => { // console.log(route, 'rou我是te'); return cloneDeep(route?.meta?.sideMenus as SideMenu); }); const menuNameList = computed(() => { return unref(sideMenus).menus.map((item) => item.name); }); const projectName = computed(() => route.params.projectName as string); const moduleName = computed(() => route.matched[0].name as string); const fullPath = computed(() => route.fullPath); const currentRouter = (val: any) => { return unref(fullPath).includes(val); }; function getMenuItem(name: string): SideMenuItem | undefined { const menu = unref(sideMenus).menus.find((item) => item.name === name); if ( menu && authService.checkPermission( unref(moduleName), menu.name as string, undefined, unref(projectName), ) ) { if (isFunction(menu.ifShow)) { menu.ifShow = menu.ifShow({ route, authService }) || false; } else { menu.ifShow = true; } return menu; } return undefined; } function navChange() { Object.keys(sessionStorage).forEach((key) => { const tableSession = JSON.parse(sessionStorage[key] || '{}'); if ( tableSession && tableSession.name && unref(menuNameList).includes(tableSession.name) ) { delete sessionStorage[key]; } }); } function navigation(url: string) { navChange(); selectedKeys.value = []; router.push({ name: url }); } watch( [route, sideMenus], () => { if (unref(sideMenus).root) { const _menus: SideMenuItem[] = []; appInfo?.menus.forEach((item: any) => { const menu = unref(sideMenus).menus.find((item1) => item1.name === item.name); // console.log(menu, 'menu'); if (item.isDir) { const _item: SideMenuItem = { name: item.name, label: item.label, submenus: [], module: '', url: '', }; let open = false; item.submenus.forEach((subItem: any) => { const _subItem = getMenuItem(subItem.name); _subItem && _item.submenus && _item.submenus.push(_subItem); if (route.fullPath.includes(subItem.url || subItem.path)) { selectedKeys.value = [subItem.name]; // 通过输入路由匹配到文件夹下的菜单,一开始须手动加入 open = true; } }); if (open) unref(openKeys).push(item.name); // const {if} if ( authService.checkPermission( unref(moduleName), _item.name, undefined, unref(projectName), ) ) { if (menu && isFunction(menu.ifShow)) { _item.ifShow = menu.ifShow({ route, authService }) || false; } else { _item.ifShow = true; } _menus.push(_item); } } else { const _item = getMenuItem(item.name); !!_item && _menus.push(_item); } }); menus.value = _menus; } else { const _menus: SideMenuItem[] = []; unref(sideMenus).menus.forEach((menuItem: SideMenuItem) => { const openPermission = authService.checkPermission( menuItem.app || unref(moduleName), menuItem.bindView || menuItem.name, undefined, unref(projectName), ) || menuItem.openPermission; const _menusItem = { ...menuItem, }; if (isFunction(menuItem.ifShow)) { _menusItem.ifShow = menuItem.ifShow({ route, authService }) || false; } else { _menusItem.ifShow = true; } if (openPermission) _menus.push(_menusItem); }); menus.value = unref(sideMenus).menus.filter((menuItem: SideMenuItem) => { return ( authService.checkPermission( menuItem.app || unref(moduleName), menuItem.bindView || menuItem.name, undefined, unref(projectName), ) || menuItem.openPermission ); }); menus.value = _menus; } if (route.name === unref(sideMenus).name && unref(menus).length > 0) { router.push({ name: unref(menus)[0].name, query: route.query }); } }, { immediate: true }, ); console.log('route', route); return { currentRouter, navChange, navigation, menus, openKeys, selectedKeys, sideMenus, }; }, }); </script> <style lang="less" scoped> .ns-nav-content { display: flex; height: 100%; .ns-nav { float: left; overflow: auto; width: 150px; min-width: 150px; background: @layout-sider-background !important; background-size: cover; .ns-nav-head { padding: 0 16px; width: 100%; height: 56px; line-height: 56px; :deep(.ant-btn) { padding: 0 !important; width: 100%; text-align: left; > .anticon + span, .ant-btn > span + .anticon { margin-left: 0; } } .ns-nav-title { font-weight: bold; } .ns-nav-back { padding: 0; } } .ns-nav-item { color: #212529; display: inline-block; box-sizing: border-box; width: 100%; height: 48px; line-height: 48px; &:hover { background-color: #fff; } } .ns-nav-current { background-color: #fff !important; color: @link-color !important; } } :deep(.ant-menu) { background-color: unset; .ant-menu-item { background-color: unset; margin-top: 0; &.nav-current, &:hover { background-color: #fff; a { color: @link-color; } } &::after { border-right: none; } &.ant-menu-item-selected::after { border-right: none; } } } .ns-content { width: 100%; min-width: 650px; background-color: #ffffff; overflow: auto; } } </style>