Jelajahi Sumber

feat: 顶部菜单栏样式

ext.zhangbin71 2 minggu lalu
induk
melakukan
91dc24c788
1 mengubah file dengan 468 tambahan dan 287 penghapusan
  1. 468 287
      src/App.vue

+ 468 - 287
src/App.vue

@@ -1,84 +1,273 @@
+
 <template>
-  <div id="app" 
-  :class="{
-    'isHomePage': $route.path === '/' || $route.path === '/index',
-    vipHomePage: $route.path === '/member',
-    isScroll: appStore.isScroll,
-  }"
-   v-infinite-scroll="scrollLoad"
-   :infinite-scroll-disabled="infiniteDisabled"
-   infinite-scroll-distance="0"
-   :infinite-scroll-immediate="false"
-  >
+  <div id="app" class="bg-white text-slate-800 font-sans antialiased">
+    <!-- 背景装饰 -->
+    <div class="fixed top-0 left-0 w-full h-full overflow-hidden -z-10 pointer-events-none">
+      <div class="absolute top-[-20%] left-[-20%] w-[60%] h-[60%] bg-blue-100/30 rounded-full filter blur-3xl animate-pulse"></div>
+      <div class="absolute bottom-[-20%] right-[-20%] w-[60%] h-[60%] bg-pink-100/30 rounded-full filter blur-3xl animate-pulse animation-delay-4000"></div>
+    </div>
+
     <ElConfigProvider :locale="langStore.elLocale">
-    <el-container style="min-height: 100vh;">
-      <el-header class="box_shadow_card">
-        <div class="header-content">
-          <div class="logo" @click="$router.push('/')">{{ $t('common.title') }}</div>
-          <el-menu :default-active="activeIndex"  ref="el_menu"
-          mode="horizontal" :ellipsis="false" class="meauList">
-            <el-menu-item index="1" @click="$router.push('/')">AI {{ $t('common.gongzuoliu') }}</el-menu-item>
-            <!-- <el-menu-item index="2" @click="$router.push('/my-learning')">工作流交易</el-menu-item> -->
-            <el-menu-item index="2" @click="goMyLearning">{{ $t('common.gongzuoliu_trade') }}</el-menu-item>
-            <el-menu-item index="3" @click="$router.push('/learning-system')">{{ $t('route.learning_system') }}</el-menu-item>
-            <el-menu-item index="4" @click=" goLearnNote">{{ $t('common.xuxibiji') }}</el-menu-item>
-            <el-menu-item index="5" @click="$router.push('/mibi-shop')">{{ $t('route.mibiShop') }}</el-menu-item>
-            <!-- <el-menu-item index="5" @click="$router.push('/my-learning')">米币商城</el-menu-item> -->
-          </el-menu>
-          <div class="header-right">
-            <el-avatar :size="32" :src="appStore.userInfo?.userAvatar || appStore.avatarDefault" />
-            <el-dropdown v-if="appStore.token">
-              <span class="el-dropdown-link">
-                {{ appStore.userInfo?.nickName || '用户' }}
-                <el-icon class="el-icon--right">
-                  <arrow-down />
-                </el-icon>
-              </span>
-              <template #dropdown>
-                <el-dropdown-menu>
-                  <el-dropdown-item @click="handleLogout">{{ $t('common.logout') }}</el-dropdown-item>
-                   <el-dropdown-item @click="toPersonal">{{ $t('personalCenter.personalCenter') }}</el-dropdown-item>
-                </el-dropdown-menu>
-              </template>
-            </el-dropdown>
-            <!-- 打开登录弹框 -->
-            <el-button type="text" @click="openLoginDialog" v-if="!appStore.token">{{ $t('common.login') }}</el-button>  
-            <LangSwitch />
+      <div class="min-h-screen flex flex-col">
+        <!-- Header -->
+        <header
+          ref="navRef"
+          class="sticky top-0 z-50 w-full transition-all duration-300"
+          :class="scrolled
+            ? 'bg-white/95 backdrop-blur-xl shadow-lg shadow-slate-200/50 border-b border-slate-200/40'
+            : 'bg-white/80 backdrop-blur-lg border-b border-slate-200/60'"
+        >
+          <!-- 顶部阅读进度条 -->
+          <div class="relative h-0.5 w-full bg-slate-100/60 overflow-hidden">
+            <div
+              class="absolute top-0 left-0 h-full bg-gradient-to-r from-blue-500 via-purple-500 via-pink-500 to-orange-400 transition-[width] duration-100 ease-out"
+              :style="{ width: readProgress + '%' }"
+            ></div>
+          </div>
+
+          <div class="max-w-screen-2xl mx-auto px-4 lg:px-8 w-full">
+            <div class="flex items-center h-16 gap-4">
+
+              <!-- Logo(左侧,flex-1让它占据左边空间)-->
+              <div class="flex-1 min-w-0">
+                <a href="/" @click.prevent="navigate('/')" class="flex items-center gap-2 group">
+                  <!-- Logo 图标 -->
+                  <div class="w-8 h-8 rounded-lg bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center shadow-md group-hover:shadow-blue-300/50 transition-shadow duration-300">
+                    <svg class="w-4 h-4 text-white" fill="currentColor" viewBox="0 0 24 24">
+                      <path d="M13 10V3L4 14h7v7l9-11h-7z"/>
+                    </svg>
+                  </div>
+                  <span class="text-xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-blue-500 to-pink-500 group-hover:from-blue-600 group-hover:to-purple-600 transition-all duration-300">
+                    {{ $t('common.title') }}
+                  </span>
+                </a>
+              </div>
+
+              <!-- Navigation(中间,flex-none不压缩)-->
+              <nav class="hidden md:flex items-center gap-0.5 whitespace-nowrap flex-none">
+                <template v-for="item in navigation" :key="item.name">
+                  <!-- 有子菜单的导航项 -->
+                  <div v-if="item.children" class="relative group">
+                    <button
+                      class="flex items-center gap-1 px-2.5 py-2 rounded-lg text-sm font-medium transition-all duration-200 whitespace-nowrap"
+                      :class="isActive(item.path)
+                        ? 'text-blue-600 bg-blue-50'
+                        : 'text-slate-600 hover:text-blue-500 hover:bg-slate-50'"
+                      @click="navigate(item.path)"
+                    >
+                      {{ $t(item.name) }}
+                      <svg class="w-3.5 h-3.5 transition-transform duration-200 group-hover:rotate-180" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
+                      </svg>
+                      <!-- 活跃下划线 -->
+                      <span v-if="isActive(item.path)" class="absolute bottom-0 left-3 right-3 h-0.5 bg-gradient-to-r from-blue-500 to-purple-500 rounded-full"></span>
+                    </button>
+                    <!-- 下拉子菜单 -->
+                    <div class="absolute top-full left-1/2 -translate-x-1/2 pt-2 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 translate-y-1 group-hover:translate-y-0">
+                      <div class="bg-white rounded-2xl shadow-xl shadow-slate-200/60 border border-slate-100 p-2 min-w-[200px]">
+                        <!-- 小三角 -->
+                        <div class="absolute -top-1.5 left-1/2 -translate-x-1/2 w-3 h-3 bg-white border-l border-t border-slate-100 rotate-45"></div>
+                        <a
+                          v-for="child in item.children"
+                          :key="child.name"
+                          href="#"
+                          @click.prevent="navigate(child.path)"
+                          class="flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm text-slate-600 hover:text-blue-600 hover:bg-blue-50 transition-all duration-150 group/item"
+                        >
+                          <span class="text-lg">{{ child.icon }}</span>
+                          <div>
+                            <div class="font-medium">{{ child.label }}</div>
+                            <div class="text-xs text-slate-400">{{ child.desc }}</div>
+                          </div>
+                        </a>
+                      </div>
+                    </div>
+                  </div>
+
+                  <!-- 普通导航项 -->
+                  <a
+                    v-else
+                    :href="item.href"
+                    class="relative px-2.5 py-2 rounded-lg text-sm font-medium transition-all duration-200 whitespace-nowrap"
+                    :class="isActive(item.path)
+                      ? 'text-blue-600 bg-blue-50'
+                      : 'text-slate-600 hover:text-blue-500 hover:bg-slate-50'"
+                    @click.prevent="navigate(item.path)"
+                  >
+                    {{ $t(item.name) }}
+                    <!-- 活跃下划线动画 -->
+                    <span
+                      class="absolute bottom-0 left-3 right-3 h-0.5 rounded-full transition-all duration-300"
+                      :class="isActive(item.path) ? 'bg-gradient-to-r from-blue-500 to-purple-500 opacity-100' : 'opacity-0'"
+                    ></span>
+                  </a>
+                </template>
+              </nav>
+
+              <!-- Mobile Menu Button -->
+              <button class="md:hidden flex items-center justify-center w-10 h-10 rounded-lg hover:bg-slate-100 transition-colors ml-auto"
+                      aria-label="菜单"
+                      @click="mobileMenuOpen = !mobileMenuOpen">
+                  <svg class="w-5 h-5 text-slate-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+                    <path v-if="!mobileMenuOpen" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
+                    <path v-else stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
+                  </svg>
+                </button>
+
+              <!-- User Menu(右侧,flex-1 justify-end)-->
+              <div class="hidden md:flex items-center gap-2 flex-1 justify-end">
+                <!-- 搜索图标按钮 -->
+                <button
+                  @click="searchOpen = !searchOpen"
+                  class="w-9 h-9 flex items-center justify-center rounded-lg text-slate-500 hover:text-blue-500 hover:bg-slate-100 transition-all duration-200"
+                  :aria-label="$t('common.search') || '搜索'"
+                >
+                  <svg class="w-4.5 h-4.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
+                    <circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/>
+                  </svg>
+                </button>
+
+                <!-- 通知图标 -->
+                <button
+                  class="relative w-9 h-9 flex items-center justify-center rounded-lg text-slate-500 hover:text-blue-500 hover:bg-slate-100 transition-all duration-200"
+                  aria-label="通知"
+                >
+                  <svg class="w-4.5 h-4.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
+                    <path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/>
+                  </svg>
+                  <!-- 红点 -->
+                  <span class="absolute top-1.5 right-1.5 w-2 h-2 bg-red-500 rounded-full ring-2 ring-white"></span>
+                </button>
+
+                <!-- 分割线 -->
+                <div class="w-px h-5 bg-slate-200 mx-1"></div>
+
+                <template v-if="appStore.token">
+                  <el-dropdown>
+                    <span class="flex items-center gap-2 cursor-pointer px-2 py-1.5 rounded-xl hover:bg-slate-50 transition-colors">
+                      <el-avatar :size="28" :src="appStore.userInfo?.userAvatar || appStore.avatarDefault" />
+                      <span class="text-sm font-medium text-slate-700">{{ appStore.userInfo?.nickName || '用户' }}</span>
+                      <el-icon class="el-icon--right text-slate-400"><arrow-down /></el-icon>
+                    </span>
+                    <template #dropdown>
+                      <el-dropdown-menu>
+                        <el-dropdown-item @click="toPersonal">{{ $t('personalCenter.personalCenter') }}</el-dropdown-item>
+                        <el-dropdown-item @click="handleLogout">{{ $t('common.logout') }}</el-dropdown-item>
+                      </el-dropdown-menu>
+                    </template>
+                  </el-dropdown>
+                </template>
+                <template v-else>
+                  <button
+                    @click="openLoginDialog"
+                    class="px-3 py-1.5 text-sm font-medium text-slate-600 hover:text-blue-500 hover:bg-slate-50 rounded-lg transition-all duration-200"
+                  >
+                    {{ $t('common.login') }}
+                  </button>
+                  <button
+                    @click="openLoginDialog"
+                    class="relative px-4 py-1.5 text-sm font-semibold text-white rounded-full overflow-hidden group transition-all duration-300 hover:shadow-lg hover:shadow-blue-300/40 hover:-translate-y-0.5"
+                  >
+                    <!-- 渐变背景 -->
+                    <span class="absolute inset-0 bg-gradient-to-r from-blue-500 to-purple-600 transition-all duration-300 group-hover:from-blue-600 group-hover:to-purple-700"></span>
+                    <!-- 光晕动效 -->
+                    <span class="absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity duration-300 bg-gradient-to-r from-transparent via-white/20 to-transparent -skew-x-12 translate-x-[-100%] group-hover:translate-x-[200%] transition-transform duration-700"></span>
+                    <span class="relative">注册</span>
+                  </button>
+                </template>
+                <LangSwitch />
+              </div>
+            </div>
+          </div>
+
+          <!-- 搜索框展开区域 -->
+          <Transition name="search-bar">
+            <div v-if="searchOpen" class="border-t border-slate-100 bg-white/98 backdrop-blur-xl">
+              <div class="max-w-screen-2xl mx-auto px-4 lg:px-8 py-3">
+                <div class="relative max-w-2xl mx-auto">
+                  <svg class="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
+                    <circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/>
+                  </svg>
+                  <input
+                    ref="searchInputRef"
+                    v-model="searchQuery"
+                    type="text"
+                    placeholder="搜索工作流、教程、功能..."
+                    class="w-full pl-11 pr-12 py-2.5 text-sm bg-slate-50 border border-slate-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500/30 focus:border-blue-400 transition-all"
+                    @keyup.enter="doSearch"
+                    @keyup.escape="searchOpen = false"
+                  />
+                  <button
+                    @click="searchOpen = false"
+                    class="absolute right-3 top-1/2 -translate-y-1/2 w-6 h-6 flex items-center justify-center rounded-md text-slate-400 hover:text-slate-600 hover:bg-slate-200 transition-colors"
+                  >
+                    <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
+                      <path d="M18 6 6 18M6 6l12 12"/>
+                    </svg>
+                  </button>
+                </div>
+              </div>
+            </div>
+          </Transition>
+
+          <!-- Mobile Menu -->
+          <Transition name="mobile-menu">
+            <div v-if="mobileMenuOpen" class="md:hidden border-t border-slate-200/60 bg-white/95 backdrop-blur-lg">
+              <div class="max-w-screen-2xl mx-auto px-4 lg:px-8 py-4 space-y-2">
+                <a v-for="item in navigation" :key="item.name" :href="item.href"
+                   class="block px-4 py-2.5 rounded-xl font-medium text-slate-600 hover:text-blue-500 hover:bg-blue-50 transition-all duration-200"
+                   :class="{ 'text-blue-600 bg-blue-50 font-semibold': isActive(item.path) }"
+                   @click.prevent="navigate(item.path); mobileMenuOpen = false">
+                  {{ $t(item.name) }}
+                </a>
+                <div class="pt-2 border-t border-slate-100 flex items-center gap-3">
+                  <template v-if="appStore.token">
+                    <button @click="toPersonal" class="flex-1 px-4 py-2 text-sm font-medium text-slate-700 bg-slate-100 rounded-xl hover:bg-slate-200 transition-colors">
+                      {{ $t('personalCenter.personalCenter') }}
+                    </button>
+                    <button @click="handleLogout" class="flex-1 px-4 py-2 text-sm font-medium text-red-600 bg-red-50 rounded-xl hover:bg-red-100 transition-colors">
+                      {{ $t('common.logout') }}
+                    </button>
+                  </template>
+                  <template v-else>
+                    <button @click="openLoginDialog; mobileMenuOpen = false" class="flex-1 px-4 py-2 text-sm font-medium text-slate-600 bg-slate-100 rounded-xl hover:bg-slate-200 transition-colors">
+                      {{ $t('common.login') }}
+                    </button>
+                    <button @click="openLoginDialog; mobileMenuOpen = false" class="flex-1 px-4 py-2 text-sm font-semibold text-white bg-gradient-to-r from-blue-500 to-purple-600 rounded-xl hover:from-blue-600 hover:to-purple-700 transition-all duration-200">
+                      注册
+                    </button>
+                  </template>
+                  <LangSwitch />
+                </div>
+              </div>
+            </div>
+          </Transition>
+        </header>
+
+        <!-- Main Content -->
+        <main class="flex-grow">
+          <router-view />
+        </main>
+
+        <!-- Footer -->
+        <footer class="bg-white border-t border-slate-100">
+          <div class="max-w-screen-2xl mx-auto px-6 py-8">
+            <div class="text-center text-sm text-slate-500">
+              <div class="flex justify-center items-center space-x-4 mb-4">
+                <a href="#" @click.prevent="router.push({name:'Agreement',query:{type:'service_agreement'}})" class="hover:text-blue-500 transition-colors">{{ $t('agreement.service_agreement') }}</a>
+                <span class="text-slate-300">|</span>
+                <a href="#" @click.prevent="router.push({name:'Agreement',query:{type:'privacy_policy'}})" class="hover:text-blue-500 transition-colors">{{ $t('agreement.privacy_policy') }}</a>
+              </div>
+              <div class="space-x-4">
+                <a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener noreferrer" class="hover:text-blue-500 transition-colors">粤ICP备2025364959号-1</a>
+                <span class="text-slate-300">|</span>
+                <span>广州暴米智能科技有限公司</span>
+              </div>
+            </div>
           </div>
-        </div>
-      </el-header>
-      <!-- 固定头部占位 -->
-      <div style="height: 60px;"></div>
-      <div class="header-bj" v-if="$route.path === '/member'"></div>
-      <el-main class="container">
-        <router-view v-slot="{ Component }">
-          <component
-            :is="Component"
-            ref="routerChildRef" 
-          />
-        </router-view>
-      </el-main>
-      
-      <el-footer v-if="!['/index'].includes($route.path)">
-        <div class="footer-content" >
-          <p> 
-            <span class="cursor-pointer" @click="router.push({name:'Agreement',query:{type:'service_agreement'}})">
-              《{{ $t('agreement.service_agreement') }}》
-            </span>
-            <span class="gray999"> | </span>
-            <span class="cursor-pointer" @click="router.push({name:'Agreement',query:{type:'privacy_policy'}})">
-              《{{ $t('agreement.privacy_policy') }}》
-            </span> 
-            <span class="gray999"> | </span>
-            <span @click="openNewTab('https://beian.miit.gov.cn/')" class="cursor-pointer">粤ICP备2025364959号-1</span>
-            <span class="gray999"> | </span>
-            <span>广州暴米智能科技有限公司</span>
-          </p>
-        </div>
-      </el-footer>
-    </el-container>
-    <!-- 登录弹框组件 -->
-    <LoginDialog ref="loginDialogRef" @login-success="handleLoginSuccess" />
+        </footer>
+      </div>
+      <LoginDialog ref="loginDialogRef" @login-success="handleLoginSuccess" />
     </ElConfigProvider>
   </div>
 </template>
@@ -86,255 +275,247 @@
 <script setup>
 import { logout } from '@/api/auth.js'
 import LoginDialog from './components/LoginDialog.vue'
-import { computed,ref,onMounted, provide, watch, nextTick,onUnmounted } from 'vue'
+import { computed, ref, onMounted, onUnmounted, provide, watch, nextTick } from 'vue'
 import LangSwitch from './components/LangSwitch.vue'
 import { ElConfigProvider, ElMessage } from 'element-plus'
 import { useRoute, useRouter } from 'vue-router'
-import { openNewTab, isLogin } from '@/utils/util.js'
-import { debounce } from 'lodash';
-// 在Pinia安装后再设置初始语言
+import { isLogin } from '@/utils/util.js'
 import { useLangStore } from '@/pinia/langStore'
 import { useAppStore } from '@/pinia/appStore'
-const langStore = useLangStore();
-const appStore = useAppStore();
-$i18n.global.locale.value = langStore.currentLang
-import { useI18n } from 'vue-i18n' 
-const { t } = useI18n() 
-// 动态更新页面标题
-langStore.updateDynamicTitle()
-
-
+import { useI18n } from 'vue-i18n'
 
+const langStore = useLangStore()
+const appStore = useAppStore()
 const route = useRoute()
 const router = useRouter()
-const el_menu = ref(null);
+const { t } = useI18n()
 
-// 登录弹框引用
-const loginDialogRef = ref(null)
+// 移动端菜单状态
+const mobileMenuOpen = ref(false)
+
+// 滚动状态
+const scrolled = ref(false)
+
+// 阅读进度条
+const readProgress = ref(0)
+
+// 导航栏 ref,用于动态设置 --nav-height CSS 变量
+const navRef = ref(null)
+
+let resizeObserver = null
+let navResizeObserver = null
+
+const updateNavHeight = () => {
+  if (navRef.value) {
+    const h = navRef.value.offsetHeight
+    document.documentElement.style.setProperty('--nav-height', h + 'px')
+  }
+}
+
+const calcProgress = () => {
+  const scrollTop = window.scrollY || document.documentElement.scrollTop
+  // 可滚动总高度 = 文档总高度 - 视口高度
+  const docHeight = Math.max(
+    document.body.scrollHeight,
+    document.documentElement.scrollHeight,
+    document.body.offsetHeight,
+    document.documentElement.offsetHeight
+  )
+  const winHeight = window.innerHeight
+  const scrollable = docHeight - winHeight
+  if (scrollable <= 0) {
+    readProgress.value = 100
+    return
+  }
+  readProgress.value = Math.min(100, Math.round((scrollTop / scrollable) * 1000) / 10)
+}
+
+const handleScroll = () => {
+  scrolled.value = window.scrollY > 20
+  calcProgress()
+}
+
+onMounted(() => {
+  window.addEventListener('scroll', handleScroll, { passive: true })
+  // 监听页面高度变化(懒加载、动态内容等)
+  resizeObserver = new ResizeObserver(() => {
+    calcProgress()
+  })
+  resizeObserver.observe(document.body)
+  calcProgress()
+  // 动态设置导航栏高度 CSS 变量
+  updateNavHeight()
+  navResizeObserver = new ResizeObserver(updateNavHeight)
+  if (navRef.value) navResizeObserver.observe(navRef.value)
+})
+onUnmounted(() => {
+  window.removeEventListener('scroll', handleScroll)
+  resizeObserver?.disconnect()
+  navResizeObserver?.disconnect()
+})
+
+// 路由切换时重置进度条
+watch(() => route.path, () => {
+  readProgress.value = 0
+  // 等待新页面渲染完成后重新计算
+  nextTick(() => calcProgress())
+})
+
+// 搜索状态
+const searchOpen = ref(false)
+const searchQuery = ref('')
+const searchInputRef = ref(null)
+
+watch(searchOpen, async (val) => {
+  if (val) {
+    await nextTick()
+    searchInputRef.value?.focus()
+  }
+})
 
-//监听showLoginDialog变化
-watch(() => appStore.showLoginDialog, (newVal, oldVal) => {
-  if(newVal){
-    openLoginDialog();
+const doSearch = () => {
+  if (searchQuery.value.trim()) {
+    router.push({ path: '/', query: { q: searchQuery.value.trim() } })
+    searchOpen.value = false
+    searchQuery.value = ''
   }
+}
+
+// Update i18n locale and dynamic title
+watch(() => langStore.currentLang, () => {
+  langStore.updateDynamicTitle()
+})
+
+const navigation = ref([
+  {
+    name: 'common.gongzuoliu',
+    href: '#',
+    path: '/',
+    children: [
+      { path: '/', icon: '🔍', label: '工作流搜索', desc: '搜索 10,000+ 工作流模板' },
+      { path: '/workflow-trade', icon: '💼', label: '工作流交易', desc: '发布或承接定制需求' },
+    ]
+  },
+  { name: 'common.gongzuoliu_trade', href: '#', path: '/workflow-trade' },
+  {
+    name: 'route.learning_system',
+    href: '#',
+    path: '/learning-system',
+    children: [
+      { path: '/learning-system', icon: '🎓', label: '学习教程', desc: '系统化 AI 工作流课程' },
+      { path: '/learn-note', icon: '📝', label: '学习笔记', desc: '记录你的学习心得' },
+    ]
+  },
+  { name: 'common.xuxibiji', href: '#', path: '/learn-note' },
+  { name: 'route.mibiShop', href: '#', path: '/mibi-shop' },
+])
+// navigation 配置与参考图一致:工作流(下拉) > 工作流交易 > 学习教程(下拉) > 学习笔记 > 米币商城
+
+const isActive = (path) => {
+  if (path === '/') return route.path === '/' || route.path === '/index'
+  return route.path.startsWith(path)
+}
+
+const navigate = (path) => {
+  if (['/learn-note'].includes(path) && !isLogin({ callback: openLoginDialog, t })) {
+    return
+  }
+  router.push(path)
+  mobileMenuOpen.value = false
+}
+
+const loginDialogRef = ref(null)
+
+watch(() => appStore.showLoginDialog, (newVal) => {
+  if (newVal) openLoginDialog()
 })
 
 onMounted(() => {
-  appStore.USERINFO();
+  appStore.USERINFO()
 })
 
-// 打开登录弹框
 const openLoginDialog = () => {
-  loginDialogRef.value?.open();
+  loginDialogRef.value?.open()
 }
-// 处理登录成功
+
 const handleLoginSuccess = () => {
-  console.log('登录成功')
 }
-//
-function goMyLearning() {
-  router.push('/workflow-trade')
-};
-const goLearnNote = () => {
-  if (!isLogin({ callback: openLoginDialog, t })) {
-    el_menu.value.updateActiveIndex (activeIndex.value);
-    return; // 如果未登录则不执行跳转,也不激活菜单
-  }
-  router.push('/learn-note');
-}
-// 将 activeIndex 改为响应式,并根据当前路由动态计算
-const activeIndex = computed(() => {
-  console.log('route.path',route.path)
-  if (route.path === '/index') return '1'
-  if (route.path.startsWith('/workflow-trade')) {
-    return '2'
-  }
-  if (route.path.startsWith('/learning-system')) {
-    return '3'
-  }
-  if (route.path.startsWith('/learn-note')) {
-    // 如果用户未登录,不应该显示此菜单为激活状态
-    if (!appStore.token) return null; // 或者返回上一个有效菜单
-    return '4';
-  }
-  if (route.path.startsWith('/mibi-shop')) {
-    return '5'
-  }
-  if (route.path.startsWith('/personal-center')) {
-    return null
-  }
-  return null // 默认返回首页
-});
-// 去个人中心
+
 const toPersonal = () => {
   router.push('/personal-center/wallet')
-};
+}
 
-// 处理注销
 const handleLogout = () => {
   logout().then(() => {
     appStore.LOGOUT()
     ElMessage.success(t('login.logoutSuccess'))
     router.push('/')
   })
-};
-
-//监听页面是否滚动
-// 使用防抖优化滚动监听
-const handleScroll = debounce(() => {
-  appStore.isScroll = window.scrollY > 0;
-}, 10);
+}
 
-// 监听滚动事件
-window.addEventListener('scroll', handleScroll);
+provide('openLoginDialog', openLoginDialog)
 
-// 组件卸载时移除事件监听
-onUnmounted(() => {
-  window.removeEventListener('scroll', handleScroll);
-});
-
-
-provide('openLoginDialog', openLoginDialog);
-
-// 无限滚动加载
-const routerChildRef = ref(null);
-// 是否在加载中,防止多次触发 loadMore
-const isLoadingMore = ref(false);
-// 当前路由是否需要开启无限滚动(比如只有列表页开启)
-const isInfiniteScrollPage = computed(() => {
-  // 按需添加需要无限滚动的路由前缀
-  if (route.path.startsWith('/index')) return true;
-  if (route.path.startsWith('/learning-system')) return true;
-  if (route.path.startsWith('/learn-note')) return true;
-  if (route.path.startsWith('/workflow-trade')) return true;
-  return false;
-});
-// 控制 v-infinite-scroll 的禁用状态
-const infiniteDisabled = computed(() => {
-  return !isInfiniteScrollPage.value || isLoadingMore.value;
-});
-
-const scrollLoad = () => {
-  if (infiniteDisabled.value) return;
-  const routerChild = routerChildRef.value;
-  if (!routerChild || typeof routerChild.loadMore !== 'function') return;
-
-  isLoadingMore.value = true;
-  // 兼容 loadMore 返回 Promise 或同步函数两种情况
-  const res = routerChild.loadMore();
-  if (res && typeof res.then === 'function') {
-    res.finally(() => {
-      isLoadingMore.value = false;
-    });
-  } else {
-    isLoadingMore.value = false;
-  }
-};
+const routerChildRef = ref(null)
 </script>
 
-<style lang="scss">
-#app {
-  font-family: Avenir, Helvetica, Arial, sans-serif;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-  color: #2c3e50;
-  &.isHomePage {
-    background: url('@/assets/imgs/bg.png') no-repeat center center fixed;
-    background-size: 100% 100%;
-  }
-  &.vipHomePage {
-     background: #FBF4F0;
-  }
+<style>
+/* 页面切换过渡动画 */
+.page-enter-active,
+.page-leave-active {
+  transition: opacity 0.2s ease, transform 0.2s ease;
 }
-.isHomePage{
-  .el-header {
-    background: url('@/assets/imgs/bg-header.png') no-repeat;
-    background-size: 100% 100%;
-  }
+
+.page-enter-from {
+  opacity: 0;
+  transform: translateY(8px);
 }
-.vipHomePage {
-  .el-header {
-    background: rgba(255,255,255,0.5);
-  }
-  &.isScroll {
-    .el-header {
-      // background: url('@/assets/imgs/bg-header_2.png') no-repeat;
-      background: #FCEDDA;
-    }
-  }
+
+.page-leave-to {
+  opacity: 0;
+  transform: translateY(-8px);
 }
 
-.el-header {
-  background: url('@/assets/imgs/bg-header_2.png') no-repeat;
-  background-size: 100% 100%;
- 
-  color: #333;
-  line-height: 60px;
-  // border-bottom: 1px solid #eee;
-  position: fixed;
-  top: 0;
-  left: 0;
-  right: 0;
-  z-index: 1000;
-  padding: 0;
-  
-  .header-content {
-    max-width: 1430px;
-    width: 80%;
-    min-width: 1430px;
-    margin: 0 auto;
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    
-    .logo {
-      min-width: 220px;
-      font-size: 24px;
-      font-weight: bold;
-      cursor: pointer;
-    }
-    .meauList{
-      &.el-menu{
-        background-color: transparent;
-      }
-      .el-menu--horizontal.el-menu{
-        border-bottom: none;
-      }
-      .el-menu-item{
-        font-size: 16px;
-      }
-    }
-    
-    .header-right {
-      // margin-right: 30px;
-      display: flex;
-      align-items: center; /* 垂直居中 */
-      gap: 10px;
-    }
-  }
+/* 移动端菜单过渡动画 */
+.mobile-menu-enter-active,
+.mobile-menu-leave-active {
+  transition: opacity 0.2s ease, max-height 0.3s ease;
+  max-height: 400px;
+  overflow: hidden;
 }
-.header-bj {
-  top: 0;
-  width: 100%;
-  height: 463px;
-  background: url('/src/assets/imgs/header-bj@2x.png') no-repeat;
-  background-size: cover;
-  position: fixed;
+
+.mobile-menu-enter-from,
+.mobile-menu-leave-to {
+  opacity: 0;
+  max-height: 0;
 }
 
-.el-footer {
-  color: #666;
-  text-align: center;
-  padding: 20px 0;
-  
-  .footer-content {
-    font-size: 14px;
-    max-width: 1200px;
-    margin: 0 auto;
-  }
+/* 搜索栏过渡动画 */
+.search-bar-enter-active,
+.search-bar-leave-active {
+  transition: opacity 0.2s ease, max-height 0.25s ease;
+  max-height: 80px;
+  overflow: hidden;
+}
+
+.search-bar-enter-from,
+.search-bar-leave-to {
+  opacity: 0;
+  max-height: 0;
+}
+
+/* 背景动画延迟 */
+.animation-delay-4000 {
+  animation-delay: 4s;
+}
+
+/* 注册按钮光晕动效 */
+.register-btn-shine {
+  animation: shine 3s infinite;
 }
 
-.el-main {
-  padding: 0;
+@keyframes shine {
+  0% { transform: translateX(-100%) skewX(-12deg); }
+  20% { transform: translateX(200%) skewX(-12deg); }
+  100% { transform: translateX(200%) skewX(-12deg); }
 }
-</style>
+</style>