|
|
@@ -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',
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
}
|