Explorar o código

调整网站布局

Shinohara Haruna hai 6 meses
pai
achega
64a7083bea

+ 8 - 8
smsb-plus-ui/src/assets/styles/variables.module.scss

@@ -1,14 +1,14 @@
 // 全局SCSS变量
 :root {
-  --menuBg: #304156;
-  --menuColor: #bfcbd9;
-  --menuActiveText: #f4f4f5;
-  --menuHover: #263445;
+  --menuBg: #ffffff;
+  --menuColor: #2f343a;
+  --menuActiveText: #404053;
+  --menuHover: #969696;
 
-  --subMenuBg: #1f2d3d;
+  --subMenuBg: #b3b3b3;
   --subMenuActiveText: #f4f4f5;
-  --subMenuHover: #001528;
-  --subMenuTitleHover: #293444;
+  --subMenuHover: #919191;
+  --subMenuTitleHover: #838383;
 
   --fixedHeaderBg: #ffffff;
   --tableHeaderBg: #f8f8f9;
@@ -43,7 +43,7 @@ html.dark {
   }
   // vxe-table 主题
   --vxe-font-color: #98989E;
-  --vxe-primary-color: #2C7ECF;
+  --vxe-primary-color: #5198e0;
   --vxe-icon-background-color: #98989E;
   --vxe-table-font-color: #98989E;
   --vxe-table-resizable-color: #95969a;

+ 15 - 7
smsb-plus-ui/src/components/TopNav/index.vue

@@ -112,10 +112,22 @@ const handleSelect = (key: string) => {
   currentIndex.value = key;
   const route = routers.value.find((item) => item.path === key);
   if (isHttp(key)) {
-    // http(s):// 路径新窗口打开
     window.open(key, '_blank');
-  } else if (!route || !route.children) {
-    // 没有子路由路径内部打开
+  } else if (route) {
+    // 一级菜单点击跳转
+    if (typeof route.redirect === 'string' && route.redirect !== 'noRedirect') {
+      router.push(route.redirect);
+    } else if (route.children && route.children.length > 0) {
+      const childPath = route.children[0].path;
+      router.push(childPath.startsWith('/') ? childPath : route.path + '/' + childPath);
+    } else {
+      router.push(route.path);
+    }
+    // 联动 sidebar
+    activeRoutes(key);
+    appStore.toggleSideBarHide(false);
+  } else {
+    // 其它情况保持原逻辑
     const routeMenu = childrenMenus.value.find((item) => item.path === key);
     if (routeMenu && routeMenu.query) {
       let query = JSON.parse(routeMenu.query);
@@ -124,10 +136,6 @@ const handleSelect = (key: string) => {
       router.push({ path: key });
     }
     appStore.toggleSideBarHide(true);
-  } else {
-    // 显示左侧联动菜单
-    activeRoutes(key);
-    appStore.toggleSideBarHide(false);
   }
 };
 

+ 2 - 2
smsb-plus-ui/src/lang/zh_CN.ts

@@ -13,11 +13,11 @@ export default {
     copyright: ''
   },
   navbar: {
-    full: '全屏',
+    // full: '全屏',
     language: '语言',
     dashboard: '首页',
     document: '项目文档',
-    message: '消息',
+    // message: '消息',
     layoutSize: '布局大小',
     selectTenant: '选择租户',
     layoutSetting: '布局设置',

+ 17 - 24
smsb-plus-ui/src/layout/components/Navbar.vue

@@ -1,35 +1,28 @@
 <template>
   <div class="navbar">
-    <hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggle-click="toggleSideBar" />
-    <breadcrumb v-if="!settingsStore.topNav" id="breadcrumb-container" class="breadcrumb-container" />
-    <top-nav v-if="settingsStore.topNav" id="topmenu-container" class="topmenu-container" />
+    <!-- <hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container"
+      @toggle-click="toggleSideBar" /> -->
+    <top-nav id="topmenu-container" class="topmenu-container" />
 
     <div class="right-menu flex align-center">
       <template v-if="appStore.device !== 'mobile'">
-        <el-select
-          v-if="userId === 1 && tenantEnabled"
-          v-model="companyName"
-          class="min-w-244px"
-          clearable
-          filterable
-          reserve-keyword
-          :placeholder="$t('navbar.selectTenant')"
-          @change="dynamicTenantEvent"
-          @clear="dynamicClearEvent"
-        >
-          <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option>
+        <el-select v-if="userId === 1 && tenantEnabled" v-model="companyName" class="min-w-244px" clearable filterable
+          reserve-keyword :placeholder="$t('navbar.selectTenant')" @change="dynamicTenantEvent"
+          @clear="dynamicClearEvent">
+          <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId">
+          </el-option>
           <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
         </el-select>
 
         <!-- <header-search id="header-search" class="right-menu-item" /> -->
         <search-menu ref="searchMenuRef" />
-        <el-tooltip content="搜索" effect="dark" placement="bottom">
+        <!-- <el-tooltip content="搜索" effect="dark" placement="bottom">
           <div class="right-menu-item hover-effect" @click="openSearchMenu">
             <svg-icon class-name="search-icon" icon-class="search" />
           </div>
-        </el-tooltip>
+        </el-tooltip> -->
         <!-- 消息 -->
-        <el-tooltip :content="$t('navbar.message')" effect="dark" placement="bottom">
+        <!-- <el-tooltip :content="$t('navbar.message')" effect="dark" placement="bottom">
           <div>
             <el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300" :persistent="false">
               <template #reference>
@@ -42,8 +35,8 @@
               </template>
             </el-popover>
           </div>
-        </el-tooltip>
-<!--        <el-tooltip content="Github" effect="dark" placement="bottom">
+        </el-tooltip> -->
+        <!--        <el-tooltip content="Github" effect="dark" placement="bottom">
           <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
         </el-tooltip>
 
@@ -51,15 +44,15 @@
           <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
         </el-tooltip>-->
 
-        <el-tooltip :content="$t('navbar.full')" effect="dark" placement="bottom">
+        <!-- <el-tooltip :content="$t('navbar.full')" effect="dark" placement="bottom">
           <screenfull id="screenfull" class="right-menu-item hover-effect" />
-        </el-tooltip>
+        </el-tooltip> -->
 
-<!--        <el-tooltip :content="$t('navbar.language')" effect="dark" placement="bottom">
+        <!--        <el-tooltip :content="$t('navbar.language')" effect="dark" placement="bottom">
           <lang-select id="lang-select" class="right-menu-item hover-effect" />
         </el-tooltip>-->
 
-<!--        <el-tooltip :content="$t('navbar.layoutSize')" effect="dark" placement="bottom">
+        <!--        <el-tooltip :content="$t('navbar.layoutSize')" effect="dark" placement="bottom">
           <size-select id="size-select" class="right-menu-item hover-effect" />
         </el-tooltip>-->
       </template>

+ 14 - 13
smsb-plus-ui/src/layout/components/Sidebar/index.vue

@@ -1,18 +1,9 @@
 <template>
-  <div :class="{ 'has-logo': showLogo }" :style="{ backgroundColor: bgColor }">
-    <logo v-if="showLogo" :collapse="isCollapse" />
+  <div class="sidebar-no-logo" :style="{ backgroundColor: bgColor }">
     <el-scrollbar :class="sideTheme" wrap-class="scrollbar-wrapper">
       <transition :enter-active-class="proxy?.animate.menuSearchAnimate.enter" mode="out-in">
-        <el-menu
-          :default-active="activeMenu"
-          :collapse="isCollapse"
-          :background-color="bgColor"
-          :text-color="textColor"
-          :unique-opened="true"
-          :active-text-color="theme"
-          :collapse-transition="false"
-          mode="vertical"
-        >
+        <el-menu :default-active="activeMenu" :collapse="isCollapse" :background-color="bgColor" :text-color="textColor"
+          :unique-opened="true" :active-text-color="theme" :collapse-transition="false" mode="vertical">
           <sidebar-item v-for="(r, index) in sidebarRouters" :key="r.path + index" :item="r" :base-path="r.path" />
         </el-menu>
       </transition>
@@ -35,7 +26,17 @@ const route = useRoute();
 const appStore = useAppStore();
 const settingsStore = useSettingsStore();
 const permissionStore = usePermissionStore();
-const sidebarRouters = computed<RouteRecordRaw[]>(() => permissionStore.getSidebarRoutes());
+// 只显示当前一级菜单下的二级菜单
+const topMenus = computed(() => permissionStore.getTopbarRoutes().filter(menu => menu.hidden !== true));
+const currentTopMenuPath = computed(() => {
+  // 取当前路由的一级菜单 path
+  const matched = route.matched?.[0];
+  return matched && matched.path !== '/' ? matched.path : (topMenus.value[0]?.path || '/');
+});
+const sidebarRouters = computed<RouteRecordRaw[]>(() => {
+  const topMenu = topMenus.value.find(menu => menu.path === currentTopMenuPath.value);
+  return topMenu && topMenu.children ? topMenu.children.filter(item => item.hidden !== true) : [];
+});
 const showLogo = computed(() => settingsStore.sidebarLogo);
 const sideTheme = computed(() => settingsStore.sideTheme);
 const theme = computed(() => settingsStore.theme);

+ 58 - 10
smsb-plus-ui/src/layout/index.vue

@@ -1,9 +1,29 @@
 <template>
   <div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme }">
     <div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
-    <side-bar v-if="!sidebar.hide" class="sidebar-container" />
-    <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
-      <!-- <el-scrollbar>
+    <div class="navbar-fixed-full">
+      <navbar ref="navbarRef" @set-layout="setLayout" />
+    </div>
+    <div class="layout-body">
+      <side-bar v-if="!sidebar.hide" class="sidebar-container no-logo" />
+      <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
+        <!-- <el-scrollbar>
+          <div :class="{ 'fixed-header': fixedHeader }">
+            <navbar ref="navbarRef" @setLayout="setLayout" />
+            <tags-view v-if="needTagsView" />
+          </div>
+          <app-main />
+          <settings ref="settingRef" />
+        </el-scrollbar> -->
+        <div :class="{ 'fixed-header': fixedHeader }">
+          <!-- navbar 已移至全宽顶部 -->
+          <!-- <tags-view v-if="needTagsView" /> -->
+        </div>
+        <app-main />
+        <settings ref="settingRef" />
+      </div>
+    </div>
+    <!-- <el-scrollbar>
         <div :class="{ 'fixed-header': fixedHeader }">
           <navbar ref="navbarRef" @setLayout="setLayout" />
           <tags-view v-if="needTagsView" />
@@ -11,13 +31,6 @@
         <app-main />
         <settings ref="settingRef" />
       </el-scrollbar> -->
-      <div :class="{ 'fixed-header': fixedHeader }">
-        <navbar ref="navbarRef" @set-layout="setLayout" />
-        <tags-view v-if="needTagsView" />
-      </div>
-      <app-main />
-      <settings ref="settingRef" />
-    </div>
   </div>
 </template>
 
@@ -89,6 +102,41 @@ const setLayout = () => {
 @import '@/assets/styles/mixin.scss';
 @import '@/assets/styles/variables.module.scss';
 
+.navbar-fixed-full {
+  width: 100vw;
+  left: 0;
+  top: 0;
+  position: fixed;
+  z-index: 100;
+  background: $fixed-header-bg;
+}
+
+.layout-body {
+  display: flex;
+  flex-direction: row;
+  width: 100vw;
+  margin-top: 50px;
+  /* 必须等于.navbar-fixed-full的高度,保证sidebar/main-container都在navbar下方 */
+  height: calc(100vh - 50px);
+  position: relative;
+  z-index: 1;
+}
+
+.sidebar-container.no-logo,
+.sidebar-no-logo {
+  padding-top: 0;
+  height: 100%;
+  min-height: 100%;
+}
+
+.main-container {
+  flex: 1 1 0;
+  width: 0;
+  min-width: 0;
+  height: 100%;
+  overflow: auto;
+}
+
 .app-wrapper {
   @include clearfix;
   position: relative;

+ 2 - 2
smsb-plus-ui/src/settings.ts

@@ -15,7 +15,7 @@ const setting: DefaultSettings = {
   /**
    * 是否系统布局配置
    */
-  showSettings: true,
+  showSettings: false,
 
   /**
    * 是否显示顶部导航
@@ -35,7 +35,7 @@ const setting: DefaultSettings = {
   /**
    * 是否显示logo
    */
-  sidebarLogo: true,
+  sidebarLogo: false,
 
   /**
    * 是否显示动态标题

+ 15 - 17
smsb-plus-ui/src/store/modules/app.ts

@@ -4,9 +4,9 @@ import enUS from 'element-plus/es/locale/lang/en';
 export const useAppStore = defineStore('app', () => {
   const sidebarStatus = useStorage('sidebarStatus', '1');
   const sidebar = reactive({
-    opened: sidebarStatus.value ? !!+sidebarStatus.value : true,
+    opened: true, // 始终展开
     withoutAnimation: false,
-    hide: false
+    hide: false   // 始终显示
   });
   const device = ref<string>('desktop');
   const size = useStorage<'large' | 'default' | 'small'>('size', 'default');
@@ -21,24 +21,21 @@ export const useAppStore = defineStore('app', () => {
     return languageObj[language.value];
   });
 
+  // 禁用折叠/展开 sidebar
   const toggleSideBar = (withoutAnimation: boolean) => {
-    if (sidebar.hide) {
-      return false;
-    }
-
-    sidebar.opened = !sidebar.opened;
-    sidebar.withoutAnimation = withoutAnimation;
-    if (sidebar.opened) {
-      sidebarStatus.value = '1';
-    } else {
-      sidebarStatus.value = '0';
-    }
+    // 不做任何事,sidebar 始终展开
+    sidebar.opened = true;
+    sidebar.hide = false;
+    sidebarStatus.value = '1';
+    sidebar.withoutAnimation = false;
   };
 
+  // 禁用关闭 sidebar
   const closeSideBar = ({ withoutAnimation }: any): void => {
-    sidebarStatus.value = '0';
-    sidebar.opened = false;
-    sidebar.withoutAnimation = withoutAnimation;
+    sidebar.opened = true;
+    sidebar.hide = false;
+    sidebarStatus.value = '1';
+    sidebar.withoutAnimation = false;
   };
   const toggleDevice = (d: string): void => {
     device.value = d;
@@ -46,8 +43,9 @@ export const useAppStore = defineStore('app', () => {
   const setSize = (s: 'large' | 'default' | 'small'): void => {
     size.value = s;
   };
+  // 禁用隐藏 sidebar
   const toggleSideBarHide = (status: boolean): void => {
-    sidebar.hide = status;
+    sidebar.hide = false;
   };
 
   const changeLanguage = (val: string): void => {