layout.component.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import { DOCUMENT } from '@angular/common';
  2. import { Component, ContentChildren, ElementRef, Inject, Input, OnDestroy, OnInit, QueryList, Renderer2, TemplateRef } from '@angular/core';
  3. import { NavigationCancel, NavigationEnd, NavigationError, RouteConfigLoadEnd, RouteConfigLoadStart, Router, Event } from '@angular/router';
  4. import { SettingsService } from '@delon/theme';
  5. import { updateHostClass } from '@delon/util/browser';
  6. import type { NzSafeAny } from 'ng-zorro-antd/core/types';
  7. import { NzMessageService } from 'ng-zorro-antd/message';
  8. import { Subject } from 'rxjs';
  9. import { takeUntil } from 'rxjs/operators';
  10. import { LayoutDefaultHeaderItemComponent } from './layout-header-item.component';
  11. import { LayoutDefaultOptions } from './types';
  12. @Component({
  13. selector: 'layout-default',
  14. exportAs: 'layoutDefault',
  15. template: `
  16. <div class="alain-default__progress-bar" *ngIf="isFetching"></div>
  17. <layout-default-header [options]="options" [items]="headerItems"></layout-default-header>
  18. <!--menu-->
  19. <div id="mainMenu" nzTheme="dark" style="background: #001529;" class="alain-default__fixed">
  20. <!--<ng-container *ngTemplateOutlet="asideUser"></ng-container>-->
  21. <ng-container *ngTemplateOutlet="nav"></ng-container>
  22. <layout-default-nav *ngIf="!nav" class="d-block" style="margin-top: 64px; width:80%"></layout-default-nav>
  23. </div>
  24. <section class="alain-default__content">
  25. <ng-container *ngTemplateOutlet="content"></ng-container>
  26. <ng-content></ng-content>
  27. </section>
  28. `
  29. })
  30. export class LayoutDefaultComponent implements OnInit, OnDestroy {
  31. @ContentChildren(LayoutDefaultHeaderItemComponent, { descendants: false })
  32. headerItems!: QueryList<LayoutDefaultHeaderItemComponent>;
  33. @Input() options!: LayoutDefaultOptions;
  34. @Input() asideUser: TemplateRef<void> | null = null;
  35. @Input() nav: TemplateRef<void> | null = null;
  36. @Input() content: TemplateRef<void> | null = null;
  37. @Input() customError?: string | null;
  38. private destroy$ = new Subject<void>();
  39. isFetching = false;
  40. constructor(
  41. router: Router,
  42. private msgSrv: NzMessageService,
  43. private settings: SettingsService,
  44. private el: ElementRef,
  45. private renderer: Renderer2,
  46. @Inject(DOCUMENT) private doc: NzSafeAny
  47. ) {
  48. router.events.pipe(takeUntil(this.destroy$)).subscribe(ev => this.processEv(ev));
  49. }
  50. processEv(ev: Event): void {
  51. if (!this.isFetching && ev instanceof RouteConfigLoadStart) {
  52. this.isFetching = true;
  53. }
  54. if (ev instanceof NavigationError || ev instanceof NavigationCancel) {
  55. this.isFetching = false;
  56. const err = this.customError === null ? null : this.customError ?? `Could not load ${ev.url} route`;
  57. if (err && ev instanceof NavigationError) {
  58. this.msgSrv.error(err, { nzDuration: 1000 * 3 });
  59. }
  60. return;
  61. }
  62. if (!(ev instanceof NavigationEnd || ev instanceof RouteConfigLoadEnd)) {
  63. return;
  64. }
  65. if (this.isFetching) {
  66. setTimeout(() => {
  67. this.isFetching = false;
  68. }, 100);
  69. }
  70. }
  71. private setClass(): void {
  72. const { el, doc, renderer, settings } = this;
  73. const layout = settings.layout;
  74. updateHostClass(el.nativeElement, renderer, {
  75. ['alain-default']: true,
  76. [`alain-default__fixed`]: layout['fixed'],
  77. [`alain-default__collapsed`]: layout.collapsed,
  78. [`alain-default__hide-aside`]: this.options!.hideAside
  79. });
  80. doc.body.classList[layout.colorWeak ? 'add' : 'remove']('color-weak');
  81. }
  82. ngOnInit(): void {
  83. this.options = {
  84. logoExpanded: `./assets/logo-full.svg`,
  85. logoCollapsed: `./assets/logo.svg`,
  86. logoLink: `/`,
  87. hideAside: false,
  88. ...this.options
  89. };
  90. const { settings, destroy$ } = this;
  91. settings.notify.pipe(takeUntil(destroy$)).subscribe(() => this.setClass());
  92. this.setClass();
  93. }
  94. ngOnDestroy(): void {
  95. this.destroy$.next();
  96. this.destroy$.complete();
  97. }
  98. }