zhangwencui
2026-06-18 e38c0656952f70552170fc4ee72420b0c741919e
src/layout/index.vue
@@ -5,13 +5,28 @@
    <div v-if="device === 'mobile' && sidebar.opened"
         class="drawer-bg"
         @click="handleClickOutside" />
    <sidebar v-if="!sidebar.hide"
    <div :class="{ 'fixed-header': fixedHeader }"
         class="top-header">
      <navbar @setLayout="setLayout" />
    </div>
    <sidebar v-if="!sidebar.hide && (!settingsStore.topNav || device === 'mobile')"
             class="sidebar-container" />
    <div :class="{ hasTagsView: showTagsView, sidebarHide: sidebar.hide }"
         class="main-container main-layout">
      <div :class="{ 'fixed-header': fixedHeader, 'with-tags': showTagsView }">
        <navbar @setLayout="setLayout" />
      <div v-if="showTagsView"
           class="tags-view-wrapper"
           :class="{ 'fixed-tags-view': fixedHeader }">
        <tags-view />
      </div>
      <div class="breadcrumb-wrapper"
           :class="{ 'fixed-breadcrumb': fixedHeader }">
        <hamburger v-if="!sidebar.hide && (!settingsStore.topNav || device === 'mobile')"
                   id="hamburger-container"
                   :is-active="sidebar.opened"
                   class="hamburger-container"
                   @toggleClick="toggleSideBar" />
        <breadcrumb id="breadcrumb-container"
                    class="breadcrumb-container" />
      </div>
      <app-main />
      <settings ref="settingRef" />
@@ -25,6 +40,8 @@
  import { useRoute } from "vue-router";
  import Sidebar from "./components/Sidebar/index.vue";
  import { AppMain, Navbar, Settings, TagsView } from "./components";
  import Breadcrumb from "@/components/Breadcrumb";
  import Hamburger from "@/components/Hamburger";
  import AIChatSidebar from "@/components/AIChatSidebar/index.vue";
  import defaultSettings from "@/settings";
@@ -34,17 +51,16 @@
  import useTagsViewStore from "@/store/modules/tagsView";
  const settingsStore = useSettingsStore();
  const appStore = useAppStore();
  const tagsViewStore = useTagsViewStore();
  const userStore = useUserStore();
  const route = useRoute();
  const theme = computed(() => settingsStore.theme);
  const sideTheme = computed(() => settingsStore.sideTheme);
  const sidebar = computed(() => useAppStore().sidebar);
  const device = computed(() => useAppStore().device);
  const sidebar = computed(() => appStore.sidebar);
  const device = computed(() => appStore.device);
  const needTagsView = computed(() => settingsStore.tagsView);
  const showTagsView = computed(
    () => needTagsView.value && tagsViewStore.visitedViews.length > 1
  );
  const showTagsView = computed(() => needTagsView.value);
  const fixedHeader = computed(() => settingsStore.fixedHeader);
  const aiEnabled = computed(() => Number(userStore.aiEnabled) === 1);
  const showGlobalAiChat = computed(() => {
@@ -68,22 +84,35 @@
    () => device.value,
    () => {
      if (device.value === "mobile" && sidebar.value.opened) {
        useAppStore().closeSideBar({ withoutAnimation: false });
        appStore.closeSideBar({ withoutAnimation: false });
      }
    }
  );
  watchEffect(() => {
    if (width.value - 1 < WIDTH) {
      useAppStore().toggleDevice("mobile");
      useAppStore().closeSideBar({ withoutAnimation: true });
      appStore.toggleDevice("mobile");
      appStore.closeSideBar({ withoutAnimation: true });
    } else {
      useAppStore().toggleDevice("desktop");
      appStore.toggleDevice("desktop");
    }
  });
  watchEffect(() => {
    if (settingsStore.topNav && device.value !== "mobile") {
      appStore.toggleSideBarHide(true);
      appStore.closeSideBar({ withoutAnimation: true });
    } else {
      appStore.toggleSideBarHide(false);
    }
  });
  function handleClickOutside() {
    useAppStore().closeSideBar({ withoutAnimation: false });
    appStore.closeSideBar({ withoutAnimation: false });
  }
  function toggleSideBar() {
    appStore.toggleSideBar();
  }
  const settingRef = ref(null);
@@ -113,8 +142,18 @@
    width: 100%;
    top: 0;
    height: 100%;
    position: absolute;
    z-index: 999;
    position: fixed;
    z-index: 1003;
  }
  .top-header {
    width: 100%;
    z-index: 1002;
  }
  .top-header.fixed-header {
    position: sticky;
    top: 0;
  }
  .main-layout {
@@ -123,26 +162,86 @@
    transition: margin-left 0.25s ease;
    display: flex;
    flex-direction: column;
    padding: 0;
  }
  .fixed-header {
    position: sticky;
    top: 0;
    z-index: var(--layout-header-z);
  .breadcrumb-wrapper {
    width: 100%;
    padding: 0;
    background: #fff;
    padding: 10px 24px;
    background: transparent;
    display: flex;
    flex-direction: column;
    gap: 2px; // 在 Navbar 和 TagsView 之间增加极小的空隙
    align-items: center;
    gap: 12px;
  }
  .fixed-header.with-tags {
    padding-bottom: 4px; // 底部留出一点距离,不要直接贴着主体内容
  .hamburger-container {
    height: 32px;
    width: 32px;
    border-radius: var(--radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-secondary);
    cursor: pointer;
    transition: all 0.2s ease;
    flex-shrink: 0;
    &:hover {
      background: rgba(0, 0, 0, 0.05);
      color: var(--el-color-primary);
    }
  }
  .hideSidebar .fixed-header {
  .breadcrumb-container {
    min-width: 0;
    :deep(.el-breadcrumb__inner) {
      color: var(--text-secondary) !important;
      opacity: 0.85;
      &:hover {
        color: var(--el-color-primary) !important;
        opacity: 1;
      }
      a {
        color: inherit !important;
        font-weight: 500 !important;
      }
    }
    :deep(.no-redirect) {
      color: var(--text-primary) !important;
      font-weight: 600 !important;
      opacity: 1;
    }
    :deep(.el-breadcrumb__separator) {
      color: var(--text-tertiary);
      opacity: 0.5;
    }
  }
  .fixed-breadcrumb {
    position: sticky;
    top: var(--topbar-height);
    z-index: calc(var(--layout-header-z) - 1);
    background: var(--app-bg);
  }
  .hasTagsView {
    .fixed-breadcrumb {
      top: calc(var(--topbar-height) + var(--tagsbar-height));
    }
  }
  .tags-view-wrapper.fixed-tags-view {
    position: sticky;
    top: var(--topbar-height);
    z-index: calc(var(--layout-header-z) - 1);
    background: var(--app-bg);
  }
  .hideSidebar .breadcrumb-wrapper {
    width: 100%;
  }
@@ -150,9 +249,8 @@
    margin-left: var(--sidebar-collapsed-width);
  }
  .mobile .fixed-header {
  .mobile .top-header.fixed-header {
    width: 100%;
    padding: 8px 10px 0;
  }
  .mobile .main-layout,