[web-app] ng-alain模版工程初始化
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
import { ChangeDetectionStrategy, Component, HostListener } from '@angular/core';
|
||||
import { NzMessageService } from 'ng-zorro-antd/message';
|
||||
import { NzModalService } from 'ng-zorro-antd/modal';
|
||||
|
||||
@Component({
|
||||
selector: 'header-clear-storage',
|
||||
template: `
|
||||
<i nz-icon nzType="tool"></i>
|
||||
{{ 'menu.clear.local.storage' | i18n }}
|
||||
`,
|
||||
host: {
|
||||
'[class.d-block]': 'true'
|
||||
},
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class HeaderClearStorageComponent {
|
||||
constructor(private modalSrv: NzModalService, private messageSrv: NzMessageService) {}
|
||||
|
||||
@HostListener('click')
|
||||
_click(): void {
|
||||
this.modalSrv.confirm({
|
||||
nzTitle: 'Make sure clear all local storage?',
|
||||
nzOnOk: () => {
|
||||
localStorage.clear();
|
||||
this.messageSrv.success('Clear Finished!');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
32
web-app/src/app/layout/basic/widgets/fullscreen.component.ts
Normal file
32
web-app/src/app/layout/basic/widgets/fullscreen.component.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { ChangeDetectionStrategy, Component, HostListener } from '@angular/core';
|
||||
import * as screenfull from 'screenfull';
|
||||
|
||||
@Component({
|
||||
selector: 'header-fullscreen',
|
||||
template: `
|
||||
<i nz-icon [nzType]="status ? 'fullscreen-exit' : 'fullscreen'"></i>
|
||||
{{ (status ? 'menu.fullscreen.exit' : 'menu.fullscreen') | i18n }}
|
||||
`,
|
||||
host: {
|
||||
'[class.d-block]': 'true'
|
||||
},
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class HeaderFullScreenComponent {
|
||||
status = false;
|
||||
private get sf(): screenfull.Screenfull {
|
||||
return screenfull as screenfull.Screenfull;
|
||||
}
|
||||
|
||||
@HostListener('window:resize')
|
||||
_resize(): void {
|
||||
this.status = this.sf.isFullscreen;
|
||||
}
|
||||
|
||||
@HostListener('click')
|
||||
_click(): void {
|
||||
if (this.sf.isEnabled) {
|
||||
this.sf.toggle();
|
||||
}
|
||||
}
|
||||
}
|
||||
54
web-app/src/app/layout/basic/widgets/i18n.component.ts
Normal file
54
web-app/src/app/layout/basic/widgets/i18n.component.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, Inject, Input } from '@angular/core';
|
||||
import { I18NService } from '@core';
|
||||
import { ALAIN_I18N_TOKEN, SettingsService } from '@delon/theme';
|
||||
import { BooleanInput, InputBoolean } from '@delon/util/decorator';
|
||||
|
||||
@Component({
|
||||
selector: 'header-i18n',
|
||||
template: `
|
||||
<div *ngIf="showLangText" nz-dropdown [nzDropdownMenu]="langMenu" nzPlacement="bottomRight">
|
||||
<i nz-icon nzType="global"></i>
|
||||
{{ 'menu.lang' | i18n }}
|
||||
<i nz-icon nzType="down"></i>
|
||||
</div>
|
||||
<i *ngIf="!showLangText" nz-dropdown [nzDropdownMenu]="langMenu" nzPlacement="bottomRight" nz-icon nzType="global"></i>
|
||||
<nz-dropdown-menu #langMenu="nzDropdownMenu">
|
||||
<ul nz-menu>
|
||||
<li nz-menu-item *ngFor="let item of langs" [nzSelected]="item.code === curLangCode" (click)="change(item.code)">
|
||||
<span role="img" [attr.aria-label]="item.text" class="pr-xs">{{ item.abbr }}</span>
|
||||
{{ item.text }}
|
||||
</li>
|
||||
</ul>
|
||||
</nz-dropdown-menu>
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class HeaderI18nComponent {
|
||||
static ngAcceptInputType_showLangText: BooleanInput;
|
||||
/** Whether to display language text */
|
||||
@Input() @InputBoolean() showLangText = true;
|
||||
|
||||
get langs(): Array<{ code: string; text: string; abbr: string }> {
|
||||
return this.i18n.getLangs();
|
||||
}
|
||||
|
||||
get curLangCode(): string {
|
||||
return this.settings.layout.lang;
|
||||
}
|
||||
|
||||
constructor(private settings: SettingsService, @Inject(ALAIN_I18N_TOKEN) private i18n: I18NService, @Inject(DOCUMENT) private doc: any) {}
|
||||
|
||||
change(lang: string): void {
|
||||
const spinEl = this.doc.createElement('div');
|
||||
spinEl.setAttribute('class', `page-loading ant-spin ant-spin-lg ant-spin-spinning`);
|
||||
spinEl.innerHTML = `<span class="ant-spin-dot ant-spin-dot-spin"><i></i><i></i><i></i><i></i></span>`;
|
||||
this.doc.body.appendChild(spinEl);
|
||||
|
||||
this.i18n.loadLangData(lang).subscribe(res => {
|
||||
this.i18n.use(lang, res);
|
||||
this.settings.setLayout('lang', lang);
|
||||
setTimeout(() => this.doc.location.reload());
|
||||
});
|
||||
}
|
||||
}
|
||||
108
web-app/src/app/layout/basic/widgets/search.component.ts
Normal file
108
web-app/src/app/layout/basic/widgets/search.component.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import {
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
HostBinding,
|
||||
Input,
|
||||
OnDestroy,
|
||||
Output
|
||||
} from '@angular/core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'header-search',
|
||||
template: `
|
||||
<nz-input-group [nzPrefix]="iconTpl" [nzSuffix]="loadingTpl">
|
||||
<ng-template #iconTpl>
|
||||
<i nz-icon [nzType]="focus ? 'arrow-down' : 'search'"></i>
|
||||
</ng-template>
|
||||
<ng-template #loadingTpl>
|
||||
<i *ngIf="loading" nz-icon nzType="loading"></i>
|
||||
</ng-template>
|
||||
<input
|
||||
type="text"
|
||||
nz-input
|
||||
[(ngModel)]="q"
|
||||
[nzAutocomplete]="auto"
|
||||
(input)="search($event)"
|
||||
(focus)="qFocus()"
|
||||
(blur)="qBlur()"
|
||||
[attr.placeholder]="'menu.search.placeholder' | i18n"
|
||||
/>
|
||||
</nz-input-group>
|
||||
<nz-autocomplete nzBackfill #auto>
|
||||
<nz-auto-option *ngFor="let i of options" [nzValue]="i">{{ i }}</nz-auto-option>
|
||||
</nz-autocomplete>
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class HeaderSearchComponent implements AfterViewInit, OnDestroy {
|
||||
q = '';
|
||||
qIpt: HTMLInputElement | null = null;
|
||||
options: string[] = [];
|
||||
search$ = new BehaviorSubject('');
|
||||
loading = false;
|
||||
|
||||
@HostBinding('class.alain-default__search-focus')
|
||||
focus = false;
|
||||
@HostBinding('class.alain-default__search-toggled')
|
||||
searchToggled = false;
|
||||
|
||||
@Input()
|
||||
set toggleChange(value: boolean) {
|
||||
if (typeof value === 'undefined') {
|
||||
return;
|
||||
}
|
||||
this.searchToggled = value;
|
||||
this.focus = value;
|
||||
if (value) {
|
||||
setTimeout(() => this.qIpt!.focus());
|
||||
}
|
||||
}
|
||||
@Output() readonly toggleChangeChange = new EventEmitter<boolean>();
|
||||
|
||||
constructor(private el: ElementRef<HTMLElement>, private cdr: ChangeDetectorRef) {}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.qIpt = this.el.nativeElement.querySelector('.ant-input') as HTMLInputElement;
|
||||
this.search$
|
||||
.pipe(
|
||||
debounceTime(500),
|
||||
distinctUntilChanged(),
|
||||
tap({
|
||||
complete: () => {
|
||||
this.loading = true;
|
||||
}
|
||||
})
|
||||
)
|
||||
.subscribe(value => {
|
||||
this.options = value ? [value, value + value, value + value + value] : [];
|
||||
this.loading = false;
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
}
|
||||
|
||||
qFocus(): void {
|
||||
this.focus = true;
|
||||
}
|
||||
|
||||
qBlur(): void {
|
||||
this.focus = false;
|
||||
this.searchToggled = false;
|
||||
this.options.length = 0;
|
||||
this.toggleChangeChange.emit(false);
|
||||
}
|
||||
|
||||
search(ev: Event): void {
|
||||
this.search$.next((ev.target as HTMLInputElement).value);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.search$.complete();
|
||||
this.search$.unsubscribe();
|
||||
}
|
||||
}
|
||||
48
web-app/src/app/layout/basic/widgets/user.component.ts
Normal file
48
web-app/src/app/layout/basic/widgets/user.component.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { DA_SERVICE_TOKEN, ITokenService } from '@delon/auth';
|
||||
import { SettingsService, User } from '@delon/theme';
|
||||
|
||||
@Component({
|
||||
selector: 'header-user',
|
||||
template: `
|
||||
<div class="alain-default__nav-item d-flex align-items-center px-sm" nz-dropdown nzPlacement="bottomRight" [nzDropdownMenu]="userMenu">
|
||||
<nz-avatar [nzSrc]="user.avatar" nzSize="small" class="mr-sm"></nz-avatar>
|
||||
{{ user.name }}
|
||||
</div>
|
||||
<nz-dropdown-menu #userMenu="nzDropdownMenu">
|
||||
<div nz-menu class="width-sm">
|
||||
<div nz-menu-item routerLink="/pro/account/center">
|
||||
<i nz-icon nzType="user" class="mr-sm"></i>
|
||||
{{ 'menu.account.center' | i18n }}
|
||||
</div>
|
||||
<div nz-menu-item routerLink="/pro/account/settings">
|
||||
<i nz-icon nzType="setting" class="mr-sm"></i>
|
||||
{{ 'menu.account.settings' | i18n }}
|
||||
</div>
|
||||
<div nz-menu-item routerLink="/exception/trigger">
|
||||
<i nz-icon nzType="close-circle" class="mr-sm"></i>
|
||||
{{ 'menu.account.trigger' | i18n }}
|
||||
</div>
|
||||
<li nz-menu-divider></li>
|
||||
<div nz-menu-item (click)="logout()">
|
||||
<i nz-icon nzType="logout" class="mr-sm"></i>
|
||||
{{ 'menu.account.logout' | i18n }}
|
||||
</div>
|
||||
</div>
|
||||
</nz-dropdown-menu>
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class HeaderUserComponent {
|
||||
get user(): User {
|
||||
return this.settings.user;
|
||||
}
|
||||
|
||||
constructor(private settings: SettingsService, private router: Router, @Inject(DA_SERVICE_TOKEN) private tokenService: ITokenService) {}
|
||||
|
||||
logout(): void {
|
||||
this.tokenService.clear();
|
||||
this.router.navigateByUrl(this.tokenService.login_url!);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user