guoziyun 9 ماه پیش
والد
کامیت
7e99aebc3a

+ 1 - 1
oms/public/app/index.html

@@ -9,5 +9,5 @@
   <style>body,html{width:100%;height:100%}*,:after,:before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}body{margin:0;color:#000000d9;font-size:14px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-variant:tabular-nums;line-height:1.5715;background-color:#fff;font-feature-settings:"tnum"}html{--antd-wave-shadow-color:#1890ff;--scroll-bar:0}</style><link rel="stylesheet" href="styles-LXBSU6DF.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles-LXBSU6DF.css"></noscript></head>
   <body>
     <app-root></app-root>
-  <script src="polyfills-B6TNHZQ6.js" type="module"></script><script src="main-T7FKSNCQ.js" type="module"></script></body>
+  <script src="polyfills-B6TNHZQ6.js" type="module"></script><script src="main-4VR4ZTQB.js" type="module"></script></body>
 </html>

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
oms/public/app/main-4VR4ZTQB.js


+ 1 - 0
oms/src/models/messageRecordModel.ts

@@ -50,6 +50,7 @@ const messageRecordSchema = new Schema<IMessageRecord>(
     title: {
       type: String,
       required: true,
+      index: true,
     },
     // 已经确定了具体语言的消息内容,必须
     content: {

+ 485 - 0
omsapp/src/app/layouts/admin-layout.component copy.ts

@@ -0,0 +1,485 @@
+import {
+  Component,
+  OnInit,
+  OnDestroy,
+  ViewChild,
+  ElementRef,
+  AfterViewInit,
+} from '@angular/core';
+import {
+  Router,
+  RouterOutlet,
+  RouterModule,
+  NavigationEnd,
+} from '@angular/router';
+import { CommonModule } from '@angular/common';
+import { filter, Subscription } from 'rxjs';
+
+// 导入 NG-ZORRO 模块
+import { NzLayoutModule } from 'ng-zorro-antd/layout';
+import { NzMenuModule } from 'ng-zorro-antd/menu';
+import { NzIconModule } from 'ng-zorro-antd/icon';
+import { NzButtonModule } from 'ng-zorro-antd/button';
+import { NzTabsModule } from 'ng-zorro-antd/tabs';
+import { AuthService } from '../services/auth.service';
+
+interface TabItem {
+  title: string;
+  path: string;
+}
+
+@Component({
+  selector: 'app-main-layout',
+  template: `
+    <nz-layout class="app-layout">
+      <!-- 侧边栏(保持不变) -->
+      <nz-sider
+        class="menu-sidebar"
+        nzCollapsible
+        nzTheme="dark"
+        [nzCollapsedWidth]="64"
+        nzWidth="216px"
+        [(nzCollapsed)]="isCollapsed"
+        [nzTrigger]="null"
+      >
+        <div class="menu-sidebar-inner">
+          <div class="sidebar-logo">
+            <a href="https://ng.ant.design/" target="_blank">
+              <img src="https://ng.ant.design/assets/img/logo.svg" alt="logo" />
+              <h1>OMS</h1>
+            </a>
+          </div>
+          <ul nz-menu nzTheme="dark" nzMode="inline" class="menu">
+            <li
+              nz-menu-item
+              [routerLink]="['/dashboard']"
+              [nzSelected]="activePath === '/dashboard'"
+            >
+              <span nz-icon nzType="dashboard"></span>
+              <span>Dashboard</span>
+            </li>
+            <li
+              nz-menu-item
+              [routerLink]="['/user']"
+              [nzSelected]="activePath === '/user'"
+            >
+              <span nz-icon nzType="team"></span>
+              <span>用户管理</span>
+            </li>
+            <li nz-submenu nzTitle="消息系统" nzIcon="message">
+              <ul>
+                <li
+                  nz-menu-item
+                  [routerLink]="['/message-activity']"
+                  [nzSelected]="activePath === '/message-activity'"
+                >
+                  <span nz-icon nzType="notification"></span>
+                  <span>消息通知</span>
+                </li>
+                <li
+                  nz-menu-item
+                  [routerLink]="['/message-record']"
+                  [nzSelected]="activePath === '/message-record'"
+                >
+                  <span nz-icon nzType="send"></span>
+                  <span>推送记录</span>
+                </li>
+                <li
+                  nz-menu-item
+                  [routerLink]="['/message-template']"
+                  [nzSelected]="activePath === '/message-template'"
+                >
+                  <span nz-icon nzType="cluster"></span>
+                  <span>消息模板</span>
+                </li>
+              </ul>
+            </li>
+          </ul>
+        </div>
+      </nz-sider>
+
+      <!-- 主内容区域 -->
+      <nz-layout>
+        <!-- 顶部导航栏:核心修复区域 -->
+        <nz-header class="header">
+          <!-- 顶部容器:使用flex确保子元素同行 -->
+          <div class="header-container">
+            <!-- 1. 折叠按钮:固定宽度,不压缩 -->
+            <div class="header-trigger-wrapper">
+              <span class="header-trigger" (click)="isCollapsed = !isCollapsed">
+                <i
+                  class="trigger"
+                  nz-icon
+                  [nzType]="isCollapsed ? 'menu-unfold' : 'menu-fold'"
+                ></i>
+              </span>
+            </div>
+
+            <!-- 2. Tab标签页:占满中间剩余空间,溢出时可滚动 -->
+            <div class="tab-container">
+              <div class="tabs-wrapper" #tabsWrapper>
+                <nz-tabs
+                  [nzSelectedIndex]="getTabIndex(activePath)"
+                  nzType="card"
+                  nzHideAll
+                  nzSize="small"
+                  (nzSelectedIndexChange)="selectTab(openTabs[$event]?.path)"
+                >
+                  <nz-tab
+                    *ngFor="let tab of openTabs; let i = index"
+                    [nzTitle]="titleTemplate"
+                  >
+                    <ng-template #titleTemplate>
+                      <span class="tab-title" (click)="selectTab(tab.path)">{{
+                        tab.title
+                      }}</span>
+                      <i
+                        nz-icon
+                        nzType="close"
+                        class="close-icon"
+                        (click)="
+                          closeTab(tab.path, i); $event.stopPropagation()
+                        "
+                      ></i>
+                    </ng-template>
+                  </nz-tab>
+                </nz-tabs>
+              </div>
+            </div>
+
+            <!-- 3. Admin菜单:固定在右侧,不压缩 -->
+            <div class="user-menu-wrapper">
+              <ul nz-menu nzTheme="light" nzMode="horizontal" class="user-menu">
+                <li nz-submenu nzTitle="Admin" nzIcon="user">
+                  <ul>
+                    <li nz-menu-item>个人设置</li>
+                    <li nz-menu-item (click)="logout()">退出登录</li>
+                  </ul>
+                </li>
+              </ul>
+            </div>
+          </div>
+        </nz-header>
+
+        <!-- 内容区域(保持不变) -->
+        <nz-content>
+          <div class="inner-content" #content>
+            <router-outlet></router-outlet>
+          </div>
+        </nz-content>
+      </nz-layout>
+    </nz-layout>
+  `,
+  styles: [
+    `
+      :host {
+        display: flex;
+        text-rendering: optimizeLegibility;
+        -webkit-font-smoothing: antialiased;
+        -moz-osx-font-smoothing: grayscale;
+      }
+
+      .app-layout {
+        min-height: 100vh;
+        display: flex;
+      }
+
+      /* 侧边栏样式(保持不变) */
+      .menu-sidebar {
+        position: relative;
+        z-index: 1001;
+        min-height: 100vh;
+        box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35);
+        background: #001529;
+      }
+
+      .menu-sidebar-inner {
+        position: sticky;
+        height: 100vh;
+        top: 0;
+        left: 0;
+        display: flex;
+        flex-direction: column;
+        background: #001529;
+      }
+
+      .menu {
+        flex: 1;
+        overflow-y: auto;
+        padding-bottom: 20px;
+      }
+
+      .sidebar-logo {
+        height: 64px;
+        padding-left: 14px;
+        overflow: hidden;
+        line-height: 64px;
+      }
+
+      .sidebar-logo img {
+        display: inline-block;
+        height: 32px;
+        width: 32px;
+        vertical-align: middle;
+      }
+
+      .sidebar-logo h1 {
+        display: inline-block;
+        margin: 0 0 0 20px;
+        color: #fff;
+        font-weight: 600;
+        font-size: 14px;
+        vertical-align: middle;
+      }
+
+      /* 顶部导航栏核心修复样式 */
+      .header {
+        padding: 0;
+        width: 100%;
+        z-index: 1000;
+        /* 固定顶部高度,避免元素挤压换行 */
+        height: 64px;
+      }
+
+      /* 顶部容器:flex布局确保子元素同行 */
+      .header-container {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        height: 100%;
+        padding: 0 8px;
+        background: #fff;
+        box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
+      }
+
+      /* 1. 折叠按钮容器:固定宽度,不压缩 */
+      .header-trigger-wrapper {
+        width: 64px; /* 与折叠按钮点击区域匹配 */
+        display: flex;
+        align-items: center;
+        justify-content: center;
+      }
+
+      .header-trigger {
+        height: 100%;
+        width: 100%;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        cursor: pointer;
+        transition: all 0.3s;
+      }
+
+      .trigger:hover {
+        color: #1890ff;
+      }
+
+      /* 2. Tab标签页容器:占满中间空间,溢出时横向滚动 */
+      .tab-container {
+        flex: 1; /* 关键:占满剩余宽度 */
+        margin: 0 8px;
+        height: 100%;
+        display: flex;
+        align-items: center;
+        overflow: hidden; /* 隐藏超出容器的内容 */
+      }
+
+      .tabs-wrapper {
+        width: 100%;
+        height: 100%;
+        overflow-x: auto; /* 横向滚动 */
+        white-space: nowrap; /* 禁止Tab换行 */
+        /* 隐藏滚动条,保持美观 */
+        scrollbar-width: none;
+        -ms-overflow-style: none;
+      }
+
+      .tabs-wrapper::-webkit-scrollbar {
+        display: none;
+      }
+
+      /* 优化Tab样式,确保垂直居中 */
+      :host ::ng-deep .ant-tabs-card {
+        height: 100%;
+        display: flex;
+        flex-direction: column;
+      }
+
+      :host ::ng-deep .ant-tabs-card .ant-tabs-card-bar {
+        border-bottom: none;
+        flex-shrink: 0; /* 禁止Tab栏被压缩 */
+      }
+
+      :host ::ng-deep .ant-tabs-card .ant-tabs-tab {
+        height: 36px;
+        line-height: 36px;
+        margin-top: 8px; /* 与顶部保持间距 */
+      }
+
+      /* 3. Admin菜单容器:固定宽度,不压缩 */
+      .user-menu-wrapper {
+        width: 120px; /* 与Admin菜单宽度匹配 */
+        display: flex;
+        align-items: center;
+        justify-content: center;
+      }
+
+      .user-menu {
+        width: 100%;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+      }
+
+      /* 内容区域样式(保持不变) */
+      nz-content {
+        margin: 0;
+        background-color: white;
+      }
+
+      .inner-content {
+        padding: 24px;
+        background: #fff;
+        min-height: calc(100vh - 64px);
+      }
+
+      /* Tab标签页细节样式 */
+      .tab-title {
+        cursor: pointer;
+      }
+
+      .close-icon {
+        margin-left: 8px;
+        font-size: 12px;
+        color: rgba(0, 0, 0, 0.45);
+        cursor: pointer;
+      }
+
+      .close-icon:hover {
+        color: #f5222d;
+      }
+    `,
+  ],
+  standalone: true,
+  imports: [
+    CommonModule,
+    RouterOutlet,
+    RouterModule,
+    NzLayoutModule,
+    NzMenuModule,
+    NzIconModule,
+    NzButtonModule,
+    NzTabsModule,
+  ],
+})
+export class MainLayoutComponent implements OnInit, OnDestroy, AfterViewInit {
+  @ViewChild('tabsWrapper') tabsWrapper!: ElementRef<HTMLDivElement>;
+  @ViewChild('content') content!: ElementRef;
+
+  isCollapsed = true;
+  openTabs: TabItem[] = [];
+  activePath: string | null = null;
+  private routerSubscription!: Subscription;
+
+  private routeTitleMap: { [key: string]: string } = {
+    '/dashboard': '数据看板',
+    '/user': '用户管理',
+    '/message-activity': '消息通知',
+    '/message-record': '推送记录',
+    '/message-template': '消息模板',
+  };
+
+  constructor(private router: Router, private authService: AuthService) {}
+
+  ngOnInit(): void {
+    // 监听路由变化,更新标签页
+    this.routerSubscription = this.router.events
+      .pipe(filter((event) => event instanceof NavigationEnd))
+      .subscribe((event: NavigationEnd) => {
+        const path = event.urlAfterRedirects.split('?')[0];
+        this.activePath = path;
+
+        // 新增未打开的标签页
+        if (!this.openTabs.some((tab) => tab.path === path)) {
+          const title = this.routeTitleMap[path] || '新页面';
+          this.openTabs.push({ title, path });
+        }
+      });
+
+    // 初始化当前路由标签页
+    this.activePath = this.router.url.split('?')[0];
+    if (
+      this.activePath &&
+      !this.openTabs.some((tab) => tab.path === this.activePath)
+    ) {
+      const title = this.routeTitleMap[this.activePath] || '新页面';
+      this.openTabs.push({ title, path: this.activePath });
+    }
+  }
+
+  ngAfterViewInit(): void {
+    this.scrollToActiveTab();
+  }
+
+  ngOnDestroy(): void {
+    if (this.routerSubscription) {
+      this.routerSubscription.unsubscribe();
+    }
+  }
+
+  // 获取当前标签页索引
+  getTabIndex(path: string | null): number {
+    return path ? this.openTabs.findIndex((tab) => tab.path === path) : -1;
+  }
+
+  // 切换标签页
+  selectTab(path: string | undefined): void {
+    if (path && this.activePath !== path) {
+      this.router.navigateByUrl(path);
+    }
+  }
+
+  // 关闭标签页
+  closeTab(path: string, index: number): void {
+    if (this.openTabs.length <= 1) return;
+
+    this.openTabs = this.openTabs.filter((tab) => tab.path !== path);
+
+    // 若关闭当前激活标签页,跳转至前一个标签页
+    if (this.activePath === path) {
+      const newIndex = Math.max(0, index - 1);
+      this.router.navigateByUrl(this.openTabs[newIndex].path);
+    }
+  }
+
+  // 退出登录
+  logout(): void {
+    this.authService.logout();
+    this.router.navigate(['/login']);
+  }
+
+  // 滚动标签页(左右滚动)
+  scrollTabs(direction: 'left' | 'right'): void {
+    const wrapper = this.tabsWrapper.nativeElement;
+    wrapper.scrollBy({
+      left: direction === 'left' ? -150 : 150,
+      behavior: 'smooth',
+    });
+  }
+
+  // 滚动到当前激活标签页
+  private scrollToActiveTab(): void {
+    if (!this.tabsWrapper) return;
+
+    const activeTab = this.tabsWrapper.nativeElement.querySelector(
+      '.ant-tabs-tab-active'
+    );
+    if (activeTab) {
+      activeTab.scrollIntoView({
+        behavior: 'smooth',
+        block: 'nearest',
+        inline: 'center',
+      });
+    }
+  }
+}

+ 255 - 212
omsapp/src/app/layouts/main-layout.component.ts

@@ -1,5 +1,3 @@
-// src/app/layouts/main-layout.component.ts
-
 import {
   Component,
   OnInit,
@@ -13,7 +11,6 @@ import {
   RouterOutlet,
   RouterModule,
   NavigationEnd,
-  ActivatedRoute,
 } from '@angular/router';
 import { CommonModule } from '@angular/common';
 import { filter, Subscription } from 'rxjs';
@@ -36,92 +33,95 @@ interface TabItem {
   template: `
     <nz-layout class="app-layout">
       <nz-sider
+        class="menu-sidebar"
         nzCollapsible
-        nzBreakpoint="lg"
+        nzTheme="dark"
+        [nzCollapsedWidth]="64"
+        nzWidth="216px"
         [(nzCollapsed)]="isCollapsed"
         [nzTrigger]="null"
       >
-        <div class="logo">
-          <img src="https://ng.ant.design/assets/img/logo.svg" alt="logo" />
-          @if (!isCollapsed) {
-          <h1>OMS</h1>
-          }
+        <div class="menu-sidebar-inner">
+          <div class="sidebar-logo">
+            <a href="https://ng.ant.design/" target="_blank">
+              <img src="https://ng.ant.design/assets/img/logo.svg" alt="logo" />
+              <h1>OMS</h1>
+            </a>
+          </div>
+          <ul nz-menu nzTheme="dark" nzMode="inline" class="menu">
+            <!-- 路由到控制台页面 -->
+            <li
+              nz-menu-item
+              [routerLink]="['/dashboard']"
+              [routerLinkActive]="['ant-menu-item-selected']"
+              [nzSelected]="activePath === '/dashboard'"
+            >
+              <span nz-icon nzType="dashboard"></span>
+              <span>Dashboard</span>
+            </li>
+            <li
+              nz-menu-item
+              [routerLink]="['/user']"
+              [routerLinkActive]="['ant-menu-item-selected']"
+              [nzSelected]="activePath === '/user'"
+            >
+              <span nz-icon nzType="team"></span>
+              <span>用户管理</span>
+            </li>
+            <li nz-submenu nzTitle="消息系统" nzIcon="message">
+              <ul>
+                <li
+                  nz-menu-item
+                  [routerLink]="['/message-activity']"
+                  [routerLinkActive]="['ant-menu-item-selected']"
+                  [nzSelected]="activePath === '/message-activity'"
+                >
+                  <span nz-icon nzType="notification"></span>
+                  <span>消息通知</span>
+                </li>
+                <li
+                  nz-menu-item
+                  [routerLink]="['/message-record']"
+                  [routerLinkActive]="['ant-menu-item-selected']"
+                  [nzSelected]="activePath === '/message-record'"
+                >
+                  <span nz-icon nzType="send"></span>
+                  <span>推送记录</span>
+                </li>
+                <li
+                  nz-menu-item
+                  [routerLink]="['/message-template']"
+                  [routerLinkActive]="['ant-menu-item-selected']"
+                  [nzSelected]="activePath === '/message-template'"
+                >
+                  <span nz-icon nzType="cluster"></span>
+                  <span>消息模板</span>
+                </li>
+              </ul>
+            </li>
+          </ul>
         </div>
-        <ul nz-menu nzTheme="dark" nzMode="inline">
-          <!-- 路由到控制台页面 -->
-          <li
-            nz-menu-item
-            [routerLink]="['/dashboard']"
-            [routerLinkActive]="['ant-menu-item-selected']"
-            [nzSelected]="activePath === '/dashboard'"
-          >
-            <span nz-icon nzType="dashboard"></span>
-            <span>Dashboard</span>
-          </li>
-          <li
-            nz-menu-item
-            [routerLink]="['/user']"
-            [routerLinkActive]="['ant-menu-item-selected']"
-            [nzSelected]="activePath === '/user'"
-          >
-            <span nz-icon nzType="team"></span>
-            <span>用户管理</span>
-          </li>
-          <li nz-submenu nzTitle="消息系统" nzIcon="message">
-            <ul>
-              <li
-                nz-menu-item
-                [routerLink]="['/message-activity']"
-                [routerLinkActive]="['ant-menu-item-selected']"
-                [nzSelected]="activePath === '/message-activity'"
-              >
-                <span nz-icon nzType="notification"></span>
-                <span>消息通知</span>
-              </li>
-              <li
-                nz-menu-item
-                [routerLink]="['/message-record']"
-                [routerLinkActive]="['ant-menu-item-selected']"
-                [nzSelected]="activePath === '/message-record'"
-              >
-                <span nz-icon nzType="send"></span>
-                <span>推送记录</span>
-              </li>
-              <li
-                nz-menu-item
-                [routerLink]="['/message-template']"
-                [routerLinkActive]="['ant-menu-item-selected']"
-                [nzSelected]="activePath === '/message-template'"
-              >
-                <span nz-icon nzType="cluster"></span>
-                <span>消息模板</span>
-              </li>
-            </ul>
-          </li>
-        </ul>
       </nz-sider>
 
+      <!-- 主内容区域 -->
       <nz-layout>
-        <nz-header>
-          <div class="header-left">
-            <span
-              class="trigger"
-              nz-icon
-              [nzType]="isCollapsed ? 'menu-unfold' : 'menu-fold'"
-              (click)="isCollapsed = !isCollapsed"
-            ></span>
-
-            <!-- 新增的标签页容器和滑动按钮 -->
+        <!-- 顶部导航栏:核心修复区域 -->
+        <nz-header class="header">
+          <!-- 顶部容器:使用flex确保子元素同行 -->
+          <div class="header-container">
+            <!-- 1. 折叠按钮:固定宽度,不压缩 -->
+            <div class="header-trigger-wrapper">
+              <span class="header-trigger" (click)="isCollapsed = !isCollapsed">
+                <i
+                  class="trigger"
+                  nz-icon
+                  [nzType]="isCollapsed ? 'menu-unfold' : 'menu-fold'"
+                ></i>
+              </span>
+            </div>
+
+            <!-- 2. Tab标签页:占满中间剩余空间,溢出时可滚动 -->
             <div class="tab-container">
-              <button
-                nz-button
-                nzType="text"
-                nzSize="small"
-                class="scroll-btn"
-                (click)="scrollTabs('left')"
-              >
-                <span nz-icon nzType="left"></span>
-              </button>
               <div class="tabs-wrapper" #tabsWrapper>
                 <nz-tabs
                   [nzSelectedIndex]="getTabIndex(activePath)"
@@ -135,9 +135,9 @@ interface TabItem {
                     [nzTitle]="titleTemplate"
                   >
                     <ng-template #titleTemplate>
-                      <span class="tab-title" (click)="selectTab(tab.path)">
-                        {{ tab.title }}
-                      </span>
+                      <span class="tab-title" (click)="selectTab(tab.path)">{{
+                        tab.title
+                      }}</span>
                       <i
                         nz-icon
                         nzType="close"
@@ -160,20 +160,24 @@ interface TabItem {
                 <span nz-icon nzType="right"></span>
               </button>
             </div>
-          </div>
-          <ul nz-menu nzTheme="light" nzMode="horizontal" class="header-right">
-            <li nz-submenu nzTitle="Admin">
-              <ul>
-                <li nz-menu-item>个人设置</li>
-                <li nz-menu-item (click)="logout()">退出登录</li>
+
+            <!-- 3. Admin菜单:固定在右侧,不压缩 -->
+            <div class="user-menu-wrapper">
+              <ul nz-menu nzTheme="light" nzMode="horizontal" class="user-menu">
+                <li nz-submenu nzTitle="Admin" nzIcon="user">
+                  <ul>
+                    <li nz-menu-item>个人设置</li>
+                    <li nz-menu-item (click)="logout()">退出登录</li>
+                  </ul>
+                </li>
               </ul>
-            </li>
-          </ul>
+            </div>
+          </div>
         </nz-header>
 
+        <!-- 内容区域(保持不变) -->
         <nz-content>
-          <div class="inner-content">
-            <!-- 唯一且正确放置的路由出口,用于显示页面内容 -->
+          <div class="inner-content" #content>
             <router-outlet></router-outlet>
           </div>
         </nz-content>
@@ -182,151 +186,192 @@ interface TabItem {
   `,
   styles: [
     `
+      :host {
+        display: flex;
+        text-rendering: optimizeLegibility;
+        -webkit-font-smoothing: antialiased;
+        -moz-osx-font-smoothing: grayscale;
+      }
+
       .app-layout {
         min-height: 100vh;
+        display: flex;
       }
 
-      .logo {
-        height: 32px;
-        background: rgba(255, 255, 255, 0.2);
-        margin: 16px;
+      /* 侧边栏样式(保持不变) */
+      .menu-sidebar {
+        position: relative;
+        z-index: 1001;
+        min-height: 100vh;
+        box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35);
+        background: #001529;
+      }
+
+      .menu-sidebar-inner {
+        position: sticky;
+        height: 100vh;
+        top: 0;
+        left: 0;
         display: flex;
-        align-items: center;
-        justify-content: center;
+        flex-direction: column;
+        background: #001529;
       }
 
-      .logo img {
+      .menu {
+        flex: 1;
+        overflow-y: auto;
+        padding-bottom: 20px;
+      }
+
+      /* 侧边栏Logo */
+      .sidebar-logo {
+        height: 64px;
+        padding-left: 14px;
+        overflow: hidden;
+        line-height: 64px;
+      }
+
+      .sidebar-logo img {
+        display: inline-block;
         height: 32px;
+        width: 32px;
+        vertical-align: middle;
       }
 
-      .logo h1 {
-        color: white;
-        font-size: 16px;
-        margin: 0 0 0 12px;
-        transition: all 0.2s;
+      .sidebar-logo h1 {
+        display: inline-block;
+        margin: 0 0 0 20px;
+        color: #fff;
+        font-weight: 600;
+        font-size: 14px;
+        vertical-align: middle;
       }
 
-      nz-header {
-        background: #fff;
+      /* 顶部导航栏核心修复样式 */
+      .header {
         padding: 0;
+        width: 100%;
+        z-index: 1000;
+        /* 固定顶部高度,避免元素挤压换行 */
+        height: 64px;
+      }
+
+      /* 顶部容器:flex布局确保子元素同行 */
+      .header-container {
         display: flex;
-        justify-content: space-between;
         align-items: center;
+        justify-content: space-between;
+        height: 100%;
+        padding: 0 8px;
+        background: #fff;
         box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
-        position: sticky;
-        top: 0;
-        z-index: 100;
       }
 
-      .header-left {
+      /* 1. 折叠按钮容器:固定宽度,不压缩 */
+      .header-trigger-wrapper {
+        width: 64px; /* 与折叠按钮点击区域匹配 */
         display: flex;
         align-items: center;
-        flex-grow: 1;
-        overflow: hidden;
+        justify-content: center;
       }
 
-      .header-left .trigger {
-        padding: 0 24px;
-        font-size: 18px;
+      .header-trigger {
+        height: 100%;
+        width: 100%;
+        display: flex;
+        align-items: center;
+        justify-content: center;
         cursor: pointer;
-        transition: color 0.3s;
+        transition: all 0.3s;
       }
 
-      .header-left .trigger:hover {
+      .trigger:hover {
         color: #1890ff;
       }
 
-      .header-right {
+      /* 2. Tab标签页容器:占满中间空间,溢出时横向滚动 */
+      .tab-container {
+        flex: 1; /* 关键:占满剩余宽度 */
+        margin: 0 8px;
+        height: 100%;
         display: flex;
         align-items: center;
-        margin-right: 24px;
+        overflow: hidden; /* 隐藏超出容器的内容 */
       }
 
-      nz-content {
-        // margin: 24px 16px 0;
-        background: #fff;
-        overflow: initial;
+      .tabs-wrapper {
+        width: 100%;
+        height: 100%;
+        overflow-x: auto; /* 横向滚动 */
+        white-space: nowrap; /* 禁止Tab换行 */
+        /* 隐藏滚动条,保持美观 */
+        scrollbar-width: none;
+        -ms-overflow-style: none;
       }
 
-      .inner-content {
-        padding: 24px;
-        // background: #f0f2f5;
-        background: #fff;
-        min-height: 360px;
+      .tabs-wrapper::-webkit-scrollbar {
+        display: none;
       }
 
-      /* Tabs 样式 */
-      .tab-container {
+      /* 优化Tab样式,确保垂直居中 */
+      :host ::ng-deep .ant-tabs-card {
+        height: 100%;
         display: flex;
-        align-items: center;
-        flex: 1;
-        margin-left: 10px;
-        height: 64px;
-        overflow: hidden;
+        flex-direction: column;
       }
 
-      .tabs-wrapper {
-        flex: 1;
-        overflow-x: hidden;
-        white-space: nowrap;
+      :host ::ng-deep .ant-tabs-card .ant-tabs-card-bar {
+        border-bottom: none;
+        flex-shrink: 0; /* 禁止Tab栏被压缩 */
       }
 
-      nz-tabset {
-        margin-bottom: -16px;
+      :host ::ng-deep .ant-tabs-card .ant-tabs-tab {
+        height: 36px;
+        line-height: 36px;
+        margin-top: 8px; /* 与顶部保持间距 */
       }
 
-      :host ::ng-deep .ant-tabs-card-bar {
-        border-bottom: 0;
+      /* 3. Admin菜单容器:固定宽度,不压缩 */
+      .user-menu-wrapper {
+        width: 120px; /* 与Admin菜单宽度匹配 */
+        display: flex;
+        align-items: center;
+        justify-content: center;
       }
 
-      :host ::ng-deep .ant-tabs-card-bar .ant-tabs-nav-container {
-        height: 40px;
+      .user-menu {
+        width: 100%;
         display: flex;
         align-items: center;
+        justify-content: center;
       }
 
-      :host ::ng-deep .ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab {
-        background: #f0f2f5;
-        border-color: #f0f2f5;
-        margin-right: 2px;
-        height: 32px;
-        line-height: 32px;
-        padding: 0 16px;
-        border-radius: 4px 4px 0 0;
+      /* 内容区域样式(保持不变) */
+      nz-content {
+        margin: 0;
+        background-color: white;
       }
 
-      :host ::ng-deep .ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab-active {
+      .inner-content {
+        padding: 24px;
         background: #fff;
-        border-bottom: 1px solid #fff;
+        min-height: calc(100vh - 64px);
       }
 
-      :host
-        ::ng-deep
-        .ant-tabs-card
-        .ant-tabs-card-bar
-        .ant-tabs-tab
-        .close-icon {
-        margin-left: 8px;
-        font-size: 12px;
-        color: rgba(0, 0, 0, 0.45);
-        transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
-      }
-
-      :host
-        ::ng-deep
-        .ant-tabs-card
-        .ant-tabs-card-bar
-        .ant-tabs-tab
-        .close-icon:hover {
-        color: #1890ff;
+      /* Tab标签页细节样式 */
+      .tab-title {
+        cursor: pointer;
       }
 
-      .scroll-btn {
+      .close-icon {
+        margin-left: 8px;
+        font-size: 12px;
         color: rgba(0, 0, 0, 0.45);
+        cursor: pointer;
       }
 
-      .tab-title {
-        cursor: pointer;
+      .close-icon:hover {
+        color: #f5222d;
       }
     `,
   ],
@@ -344,8 +389,9 @@ interface TabItem {
 })
 export class MainLayoutComponent implements OnInit, OnDestroy, AfterViewInit {
   @ViewChild('tabsWrapper') tabsWrapper!: ElementRef<HTMLDivElement>;
+  @ViewChild('content') content!: ElementRef;
 
-  isCollapsed = false;
+  isCollapsed = true;
   openTabs: TabItem[] = [];
   activePath: string | null = null;
   private routerSubscription!: Subscription;
@@ -361,18 +407,21 @@ export class MainLayoutComponent implements OnInit, OnDestroy, AfterViewInit {
   constructor(private router: Router, private authService: AuthService) {}
 
   ngOnInit(): void {
+    // 监听路由变化,更新标签页
     this.routerSubscription = this.router.events
       .pipe(filter((event) => event instanceof NavigationEnd))
       .subscribe((event: NavigationEnd) => {
         const path = event.urlAfterRedirects.split('?')[0];
         this.activePath = path;
 
+        // 新增未打开的标签页
         if (!this.openTabs.some((tab) => tab.path === path)) {
           const title = this.routeTitleMap[path] || '新页面';
           this.openTabs.push({ title, path });
         }
       });
 
+    // 初始化当前路由标签页
     this.activePath = this.router.url.split('?')[0];
     if (
       this.activePath &&
@@ -393,65 +442,59 @@ export class MainLayoutComponent implements OnInit, OnDestroy, AfterViewInit {
     }
   }
 
+  // 获取当前标签页索引
   getTabIndex(path: string | null): number {
     return path ? this.openTabs.findIndex((tab) => tab.path === path) : -1;
   }
 
-  // 修复了类型不兼容问题:现在该方法可以安全地处理 undefined
+  // 切换标签页
   selectTab(path: string | undefined): void {
     if (path && this.activePath !== path) {
       this.router.navigateByUrl(path);
     }
   }
 
+  // 关闭标签页
   closeTab(path: string, index: number): void {
-    if (this.openTabs.length <= 1) {
-      return;
-    }
+    if (this.openTabs.length <= 1) return;
 
     this.openTabs = this.openTabs.filter((tab) => tab.path !== path);
 
+    // 若关闭当前激活标签页,跳转至前一个标签页
     if (this.activePath === path) {
-      let newActivePath = '';
-      if (this.openTabs.length > 0) {
-        const newIndex = Math.max(0, index - 1);
-        newActivePath = this.openTabs[newIndex].path;
-      }
-      if (newActivePath) {
-        this.router.navigateByUrl(newActivePath);
-      } else {
-        this.router.navigate(['/dashboard']);
-      }
+      const newIndex = Math.max(0, index - 1);
+      this.router.navigateByUrl(this.openTabs[newIndex].path);
     }
   }
 
+  // 退出登录
   logout(): void {
     this.authService.logout();
     this.router.navigate(['/login']);
   }
 
+  // 滚动标签页(左右滚动)
   scrollTabs(direction: 'left' | 'right'): void {
-    const scrollAmount = 100;
-    const tabsContainer = this.tabsWrapper.nativeElement;
-    if (direction === 'left') {
-      tabsContainer.scrollLeft -= scrollAmount;
-    } else {
-      tabsContainer.scrollLeft += scrollAmount;
-    }
+    const wrapper = this.tabsWrapper.nativeElement;
+    wrapper.scrollBy({
+      left: direction === 'left' ? -150 : 150,
+      behavior: 'smooth',
+    });
   }
 
+  // 滚动到当前激活标签页
   private scrollToActiveTab(): void {
-    if (this.tabsWrapper) {
-      const activeTabElement = this.tabsWrapper.nativeElement.querySelector(
-        '.ant-tabs-tab-active'
-      ) as HTMLElement;
-      if (activeTabElement) {
-        activeTabElement.scrollIntoView({
-          behavior: 'smooth',
-          block: 'nearest',
-          inline: 'center',
-        });
-      }
+    if (!this.tabsWrapper) return;
+
+    const activeTab = this.tabsWrapper.nativeElement.querySelector(
+      '.ant-tabs-tab-active'
+    );
+    if (activeTab) {
+      activeTab.scrollIntoView({
+        behavior: 'smooth',
+        block: 'nearest',
+        inline: 'center',
+      });
     }
   }
 }

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است