From 5d36e1f987ef21e44ded2e8a1d06c28094ec1e76 Mon Sep 17 00:00:00 2001
From: baoshiwei <baoshiwei@shlanbao.cn>
Date: 星期六, 19 四月 2025 12:39:47 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 zhitan-vue/src/components/TopNav/index.vue |  397 ++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 314 insertions(+), 83 deletions(-)

diff --git a/zhitan-vue/src/components/TopNav/index.vue b/zhitan-vue/src/components/TopNav/index.vue
index 52b40ea..774132d 100644
--- a/zhitan-vue/src/components/TopNav/index.vue
+++ b/zhitan-vue/src/components/TopNav/index.vue
@@ -1,35 +1,30 @@
 <template>
-  <el-menu
-    :default-active="activeMenu"
-    mode="horizontal"
-    @select="handleSelect"
-    :ellipsis="false"
-  >
-    <template v-for="(item, index) in topMenus">
-      <el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber">
-        <svg-icon
-        v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
-        :icon-class="item.meta.icon"/>
-        {{ item.meta.title }}
-      </el-menu-item>
-    </template>
-
-    <!-- 椤堕儴鑿滃崟瓒呭嚭鏁伴噺鎶樺彔 -->
-    <el-sub-menu :style="{'--theme': theme}" index="more" v-if="topMenus.length > visibleNumber">
-      <template #title>鏇村鑿滃崟</template>
-      <template v-for="(item, index) in topMenus">
-        <el-menu-item
-          :index="item.path"
-          :key="index"
-          v-if="index >= visibleNumber">
-        <svg-icon
-          v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
-          :icon-class="item.meta.icon"/>
-        {{ item.meta.title }}
-        </el-menu-item>
-      </template>
-    </el-sub-menu>
-  </el-menu>
+  <div class="top-nav-container">
+    <div class="scroll-arrow left-arrow" @click="scrollLeft" v-show="canScrollLeft">
+      <el-icon><arrow-left /></el-icon>
+    </div>
+    
+    <div class="menu-container" ref="menuContainer">
+      <el-menu
+        :default-active="activeMenu"
+        mode="horizontal"
+        @select="handleSelect"
+        :ellipsis="false"
+        class="top-menu"
+        :class="{ 'theme-dark': theme === 'dark' }"
+      >
+        <template v-for="(item, index) in topMenus" :key="index">
+          <el-menu-item :style="{'--theme': theme}" :index="item.path">
+            {{ item.meta.title }}
+          </el-menu-item>
+        </template>
+      </el-menu>
+    </div>
+    
+    <div class="scroll-arrow right-arrow" @click="scrollRight" v-show="canScrollRight">
+      <el-icon><arrow-right /></el-icon>
+    </div>
+  </div>
 </template>
 
 <script setup>
@@ -38,9 +33,13 @@
 import useAppStore from '@/store/modules/app'
 import useSettingsStore from '@/store/modules/settings'
 import usePermissionStore from '@/store/modules/permission'
+import { ArrowLeft, ArrowRight } from '@element-plus/icons-vue'
 
-// 椤堕儴鏍忓垵濮嬫暟
-const visibleNumber = ref(null);
+// 婊氬姩鐩稿叧
+const menuContainer = ref(null);
+const canScrollLeft = ref(false);
+const canScrollRight = ref(false);
+
 // 褰撳墠婵�娲昏彍鍗曠殑 index
 const currentIndex = ref(null);
 // 闅愯棌渚ц竟鏍忚矾鐢�
@@ -102,9 +101,13 @@
     const tmpPath = path.substring(1, path.length);
     activePath = "/" + tmpPath.substring(0, tmpPath.indexOf("/"));
     if (!route.meta.link) {
-        appStore.toggleSideBarHide(false);
+      appStore.toggleSideBarHide(false);
     }
-  } else if(!route.children) {
+  } else if (path === '/index' || path === '/') {
+    // 棣栭〉鏃堕殣钘忎晶杈规爮
+    activePath = path;
+    appStore.toggleSideBarHide(true);
+  } else if (!route.children) {
     activePath = path;
     appStore.toggleSideBarHide(true);
   }
@@ -112,36 +115,147 @@
   return activePath;
 })
 
-function setVisibleNumber() {
-  const width = document.body.getBoundingClientRect().width / 3;
-  visibleNumber.value = parseInt(width / 85);
+function updateScrollButtons() {
+  if (!menuContainer.value) return;
+  
+  const container = menuContainer.value;
+  canScrollLeft.value = container.scrollLeft > 10;
+  canScrollRight.value = container.scrollLeft < (container.scrollWidth - container.clientWidth - 10);
+}
+
+function scrollLeft() {
+  if (!menuContainer.value) return;
+  menuContainer.value.scrollBy({ left: -200, behavior: 'smooth' });
+  setTimeout(updateScrollButtons, 300);
+}
+
+function scrollRight() {
+  if (!menuContainer.value) return;
+  menuContainer.value.scrollBy({ left: 200, behavior: 'smooth' });
+  setTimeout(updateScrollButtons, 300);
+}
+
+/**
+ * 鏌ユ壘鏈�娣卞眰鐨勫瓙鑿滃崟锛堝彾瀛愯妭鐐癸級
+ * 閫掑綊鏌ユ壘绗竴涓病鏈塩hildren鐨勫瓙鑿滃崟
+ */
+function findDeepestLeafMenu(route) {
+  if (!route) return null;
+  
+  // 濡傛灉娌℃湁瀛愯彍鍗曟垨瀛愯彍鍗曚负绌猴紝鍒欒繑鍥炲綋鍓嶈矾鐢�
+  if (!route.children || route.children.length === 0) {
+    return route;
+  }
+  
+  // 鎵惧埌绗竴涓潪闅愯棌鐨勫瓙鑿滃崟
+  const firstVisibleChild = route.children.find(child => !child.hidden);
+  if (!firstVisibleChild) {
+    return route; // 濡傛灉鎵�鏈夊瓙鑿滃崟閮芥槸闅愯棌鐨勶紝杩斿洖褰撳墠璺敱
+  }
+  
+  // 閫掑綊鏌ユ壘杩欎釜瀛愯彍鍗曠殑鏈�娣卞眰瀛愯彍鍗�
+  return findDeepestLeafMenu(firstVisibleChild);
 }
 
 function handleSelect(key, keyPath) {
   currentIndex.value = key;
   const route = routers.value.find(item => item.path === key);
+  
   if (isHttp(key)) {
     // http(s):// 璺緞鏂扮獥鍙f墦寮�
     window.open(key, "_blank");
-  } else if (!route || !route.children) {
-    // 娌℃湁瀛愯矾鐢辫矾寰勫唴閮ㄦ墦寮�
+    return;
+  } 
+  
+ 
+  
+  // 妫�鏌ユ槸鍚︽湁瀛愯矾鐢�
+  if (route && route.children && route.children.length > 0) {
+    // 鏈夊瓙璺敱锛屾樉绀轰晶杈规爮
+    activeRoutes(key);
+    
+    // 鎸夌収姝g‘鐨勮矾寰勬瀯寤哄眰绾э紝杩欓噷鏄壒娈婂鐞�
+    let targetPath = key; // 浠庡綋鍓嶇偣鍑荤殑鑿滃崟璺緞寮�濮�
+    let targetQuery = null;
+    let currentNode = route;
+    let pathSegments = [];
+    
+    // 褰撳墠璺緞鏄涓�娈�
+    pathSegments.push(currentNode.path);
+    
+    // 閫愬眰娣诲姞瀛愯矾寰�
+    while (currentNode.children && currentNode.children.length > 0) {
+      const firstChild = currentNode.children.find(child => !child.hidden);
+      if (!firstChild) break;
+      
+      // 璺宠繃ParentView绫诲瀷鐨勪腑闂磋妭鐐癸紝鐩存帴浣跨敤鍏跺瓙鑺傜偣鐨刾ath
+      if (firstChild.component === 'ParentView' || firstChild.component.name === 'ParentView') {
+        currentNode = firstChild;
+        pathSegments.push(firstChild.path);
+        continue;
+      }
+      
+      // 鏅�氳妭鐐瑰鐞�
+      currentNode = firstChild;
+      // 濡傛灉璺緞涓嶆槸浠�/寮�澶达紝鍒欐坊鍔犲埌璺緞鐗囨涓�
+      if (!firstChild.path.startsWith('/')) {
+        pathSegments.push(firstChild.path);
+      } else {
+        // 濡傛灉鏄粷瀵硅矾寰勶紝鍒欐浛鎹箣鍓嶆墍鏈夎矾寰�
+        pathSegments = [firstChild.path];
+      }
+      
+      targetQuery = firstChild.query;
+      
+      // 濡傛灉鍒拌揪鍙跺瓙鑺傜偣锛堟病鏈夊瓙鑺傜偣锛夛紝鍒欑粨鏉熸煡鎵�
+      if (!firstChild.children || firstChild.children.length === 0) {
+        break;
+      }
+    }
+    
+    // 鏋勫缓鏈�缁堣矾寰�
+    if (pathSegments.length > 0) {
+      // 濡傛灉绗竴娈典笉鏄互/寮�澶达紝娣诲姞/
+      if (!pathSegments[0].startsWith('/')) {
+        pathSegments[0] = '/' + pathSegments[0];
+      }
+      
+      // 缁勫悎璺緞 - 鎶婃暟缁勪腑鎵�鏈夎矾寰勬嫾鎺ヨ捣鏉ワ紝濡傛灉鏌愭鍖呭惈瀹屾暣璺緞锛堜互/寮�澶达級鍒欎粠璇ユ閲嶆柊寮�濮�
+      targetPath = pathSegments.reduce((fullPath, segment, index) => {
+        if (segment.startsWith('/')) {
+          return segment;
+        } else if (index === 0) {
+          return segment;
+        } else {
+          return `${fullPath}/${segment}`;
+        }
+      });
+    }
+    
+    // 瀵艰埅鍒扮洰鏍囪矾鐢�
+    if (targetQuery) {
+      router.push({ path: targetPath, query: targetQuery });
+    } else {
+      router.push({ path: targetPath });
+    }
+  } else {
+    // 娌℃湁瀛愯矾鐢憋紝闅愯棌渚ц竟鏍�
     const routeMenu = childrenMenus.value.find(item => item.path === key);
     if (routeMenu && routeMenu.query) {
-      let query = JSON.parse(routeMenu.query);
-      router.push({ path: key, query: query });
+      // query 宸茬粡鍦� permission.js 涓澶勭悊涓哄璞★紝鏃犻渶鍐嶆瑙f瀽
+      router.push({ path: key, query: routeMenu.query });
     } else {
       router.push({ path: key });
     }
     appStore.toggleSideBarHide(true);
-  } else {
-    // 鏄剧ず宸︿晶鑱斿姩鑿滃崟
-    activeRoutes(key);
-    appStore.toggleSideBarHide(false);
   }
 }
 
 function activeRoutes(key) {
   let routes = [];
+ 
+  
+  // 鏌ユ壘鍖归厤鐨勮矾鐢�
   if (childrenMenus.value && childrenMenus.value.length > 0) {
     childrenMenus.value.map((item) => {
       if (key == item.parentPath || (key == "index" && "" == item.path)) {
@@ -149,66 +263,183 @@
       }
     });
   }
+  
   if(routes.length > 0) {
+    // 鏈夊瓙璺敱锛屽垯鏄剧ず渚ц竟鏍�
     permissionStore.setSidebarRouters(routes);
+    appStore.toggleSideBarHide(false);
   } else {
+    // 娌℃湁瀛愯矾鐢憋紝闅愯棌渚ц竟鏍�
     appStore.toggleSideBarHide(true);
   }
   return routes;
 }
 
 onMounted(() => {
-  window.addEventListener('resize', setVisibleNumber)
-})
-onBeforeUnmount(() => {
-  window.removeEventListener('resize', setVisibleNumber)
+  // 鏍规嵁褰撳墠璺敱鍐冲畾鏄惁鏄剧ず渚ц竟鏍忥紝鑰屼笉鏄洿鎺ラ殣钘�
+  const currentPath = route.path;
+  if (currentPath === '/index' || currentPath === '/') {
+    // 濡傛灉褰撳墠鏄椤碉紝鑷姩璺宠浆鍒扮涓�涓姩鎬佽矾鐢�
+    if (topMenus.value.length > 0) {
+      const firstRoute = topMenus.value[0];
+      handleSelect(firstRoute.path);
+    }
+  } else {
+    // 妫�鏌ュ綋鍓嶈矾鐢辨槸鍚﹂渶瑕佹樉绀轰晶杈规爮
+    const routeConfig = routers.value.find(item => currentPath.startsWith(item.path) && item.path !== '/');
+    if (routeConfig && routeConfig.children && routeConfig.children.length > 0) {
+      // 鏈夊瓙鑿滃崟锛屾樉绀轰晶杈规爮
+      activeRoutes(routeConfig.path);
+      appStore.toggleSideBarHide(false);
+    } else {
+      // 鏃犲瓙鑿滃崟锛屽彲浠ラ殣钘忎晶杈规爮
+      appStore.toggleSideBarHide(true);
+    }
+  }
+  
+  // 鐩戝惉婊氬姩鐘舵��
+  if (menuContainer.value) {
+    menuContainer.value.addEventListener('scroll', updateScrollButtons);
+    nextTick(() => {
+      updateScrollButtons();
+    });
+  }
+  
+  window.addEventListener('resize', () => {
+    updateScrollButtons();
+  });
 })
 
-onMounted(() => {
-  setVisibleNumber()
+onBeforeUnmount(() => {
+  if (menuContainer.value) {
+    menuContainer.value.removeEventListener('scroll', updateScrollButtons);
+  }
+  window.removeEventListener('resize', updateScrollButtons);
 })
 </script>
 
 <style lang="scss">
-.topmenu-container.el-menu--horizontal > .el-menu-item {
-  float: left;
-  height: 50px !important;
-  line-height: 50px !important;
-  color: #999093 !important;
-  padding: 0 5px !important;
-  margin: 0 10px !important;
+.top-nav-container {
+  display: flex;
+  align-items: center;
+  flex: 1;
+  position: relative;
+  height: 60px;
+  overflow: hidden;
+  padding: 0 40px; /* Increase padding for arrows */
+  
+  .scroll-arrow {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: 28px;
+    height: 28px;
+    background: rgba(255, 255, 255, 0.2);
+    border-radius: 50%;
+    cursor: pointer;
+    color: #ffffff;
+    z-index: 20;
+    opacity: 0;
+    transition: opacity 0.3s;
+    position: absolute;
+    box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
+    
+    &:hover {
+      background: rgba(255, 255, 255, 0.3);
+    }
+    
+    &.left-arrow {
+      left: 8px;
+    }
+    
+    &.right-arrow {
+      right: 8px;
+    }
+  }
+  
+  &:hover {
+    .scroll-arrow {
+      opacity: 1;
+    }
+  }
+  
+  .menu-container {
+    width: 100%;
+    height: 100%;
+    overflow-x: auto;
+    overflow-y: hidden;
+    scrollbar-width: none; /* Firefox */
+    -ms-overflow-style: none; /* IE and Edge */
+    
+    &::-webkit-scrollbar {
+      display: none; /* Chrome, Safari, Opera */
+    }
+  }
 }
 
-.topmenu-container.el-menu--horizontal > .el-menu-item.is-active, .el-menu--horizontal > .el-sub-menu.is-active .el-submenu__title {
-  border-bottom: 2px solid #{'var(--theme)'} !important;
-  color: #303133;
+.top-menu {
+  height: 60px;
+  border-bottom: none !important;
+  white-space: nowrap;
+  background: transparent !important;
+  
+  &.theme-dark {
+    background: #002866 !important;
+  }
 }
 
-/* sub-menu item */
-.topmenu-container.el-menu--horizontal > .el-sub-menu .el-sub-menu__title {
-  float: left;
-  height: 50px !important;
-  line-height: 50px !important;
-  color: #999093 !important;
-  padding: 0 5px !important;
-  margin: 0 10px !important;
-}
-
-/* 鑳屾櫙鑹查殣钘� */
-.topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus, .topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover, .topmenu-container.el-menu--horizontal>.el-submenu .el-submenu__title:hover {
-  background-color: #ffffff !important;
+.el-menu--horizontal {
+  border-bottom: none !important;
+  
+  > .el-menu-item {
+    display: inline-block;
+    float: none;
+    height: 60px !important;
+    line-height: 60px !important;
+    color: #ffffff !important;
+    padding: 0 20px !important;
+    margin: 0 !important;
+    border-bottom: none !important;
+    position: relative;
+    font-size: 16px;
+    
+    &.is-active {
+      background-color: transparent !important;
+      color: #ffffff !important;
+      font-weight: bold;
+      
+      &::after {
+        content: '';
+        position: absolute;
+        bottom: 10px;
+        left: 50%;
+        transform: translateX(-50%);
+        width: calc(100% - 40px);
+        height: 2px;
+        background-color: #ffffff;
+      }
+    }
+    
+    &:hover {
+      background-color: rgba(255, 255, 255, 0.1) !important;
+      color: #ffffff !important;
+    }
+  }
 }
 
 /* 鍥炬爣鍙抽棿璺� */
-.topmenu-container .svg-icon {
-  margin-right: 4px;
+.svg-icon {
+  margin-right: 8px;
+  color: #ffffff;
 }
 
-/* topmenu more arrow */
-.topmenu-container .el-sub-menu .el-sub-menu__icon-arrow {
-  position: static;
-  vertical-align: middle;
-  margin-left: 8px;
-  margin-top: 0px;
+/* 棣栭〉鎸夐挳鏍峰紡 */
+.el-menu-item:first-child {
+  margin-left: 0 !important;
+  font-weight: bold;
+  
+  .svg-icon {
+    font-size: 18px;
+  }
 }
 </style>

--
Gitblit v1.9.3