blob: 7fd108fb887aec7dbb6736731f04fc41a66e54d1 [file] [log] [blame]
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnInit, OnDestroy } from '@angular/core';
import { Router } from '@angular/router';
import { I18NService } from '@core';
import { ALAIN_I18N_TOKEN } from '@delon/theme';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzNotificationService } from 'ng-zorro-antd/notification';
import { finalize } from 'rxjs/operators';
import { Mute } from '../../../pojo/Mute';
import { AlertSoundService } from '../../../service/alert-sound.service';
import { AlertService } from '../../../service/alert.service';
import { GeneralConfigService } from '../../../service/general-config.service';
@Component({
selector: 'header-notify',
template: `
<div style="display: flex; align-items: center;">
<ng-template #badgeTpl>
<nz-badge [nzCount]="count" ngClass="alain-default__nav-item" [nzStyle]="{ 'box-shadow': 'none' }">
<i nz-icon nzType="bell" ngClass="alain-default__nav-item-icon"></i>
</nz-badge>
</ng-template>
@if (data!.length <= 0) {
<ng-template [ngTemplateOutlet]="badgeTpl" />
} @else {
<div
nz-dropdown
(nzVisibleChange)="onPopoverVisibleChange($event)"
[(nzVisible)]="popoverVisible"
nzTrigger="click"
nzPlacement="bottomRight"
nzOverlayClassName="header-dropdown notice-icon"
[nzDropdownMenu]="noticeMenu"
>
<ng-template [ngTemplateOutlet]="badgeTpl" />
</div>
}
<nz-badge ngClass="alain-default__nav-item" [nzStyle]="{ 'box-shadow': 'none' }">
<i
nz-icon
[nzType]="mute.mute ? 'muted' : 'sound'"
ngClass="alain-default__nav-item-icon"
(click)="toggleMute($event)"
nz-tooltip
[nzTooltipTitle]="'common.mute' | i18n"
></i>
</nz-badge>
</div>
<nz-dropdown-menu #noticeMenu="nzDropdownMenu">
@if (data[0].title) {
<div class="ant-modal-title" style="line-height: 44px; text-align: center;">{{ data[0].title }}</div>
}
<nz-spin [nzSpinning]="loading" [nzDelay]="0">
@if (data[0].list && data[0].list.length > 0) {
<ng-template [ngTemplateOutlet]="listTpl" />
} @else {
<div class="notice-icon__notfound">
@if (data[0].emptyImage) {
<img class="notice-icon__notfound-img" [attr.src]="data[0].emptyImage" alt="not found" />
}
<p>
<ng-container *nzStringTemplateOutlet="data[0].emptyText">
{{ data[0].emptyText }}
</ng-container>
</p>
</div>
}
</nz-spin>
<div style="display: flex; align-items: center; border-top: 1px solid #f0f0f0;">
<div class="notice-icon__clear" style="flex: 1; border-top: none;" (click)="onClearAllAlerts()">{{ data[0].clearText }} </div>
<nz-divider nzType="vertical"></nz-divider>
<div class="notice-icon__clear" style="flex: 1; border-top: none;" (click)="gotoAlertCenter()">{{ data[0].enterText }} </div>
</div>
</nz-dropdown-menu>
<ng-template #listTpl>
<nz-list [nzDataSource]="data[0].list" [nzRenderItem]="item">
<ng-template #item let-item>
<nz-list-item [class.notice-icon__item-read]="item.read">
<nz-list-item-meta [nzTitle]="nzTitle" [nzDescription]="nzDescription" [nzAvatar]="item.avatar">
<ng-template #nzTitle>
<ng-container *nzStringTemplateOutlet="item.title; context: { $implicit: item }">
<a (click)="gotoDetail(item.monitorId)">{{ item.title }}</a>
</ng-container>
@if (item.extra) {
<div class="notice-icon__item-extra">
<nz-tag [nzColor]="item.color">{{ item.extra }}</nz-tag>
</div>
}
</ng-template>
<ng-template #nzDescription>
@if (item.description) {
<div class="notice-icon__item-desc">
<ng-container *nzStringTemplateOutlet="item.description; context: { $implicit: item }">
{{ item.description }}
</ng-container>
</div>
} @if (item.datetime) {
<div class="notice-icon__item-time">{{ item.datetime }}</div>
}
</ng-template>
</nz-list-item-meta>
@if (item.status !== 3) {
<ul nz-list-item-actions>
<button
nz-button
nzType="primary"
(click)="onMarkReadOneAlert(item.id)"
nz-tooltip
[nzTooltipTitle]="'alert.center.deal' | i18n"
>
<i nz-icon nzType="down-circle" nzTheme="outline"></i>
</button>
</ul>
}
</nz-list-item>
</ng-template>
</nz-list>
</ng-template>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class HeaderNotifyComponent implements OnInit, OnDestroy {
data: any[] = [
{
title: this.i18nSvc.fanyi('dashboard.alerts.title-no'),
list: [],
emptyText: this.i18nSvc.fanyi('dashboard.alerts.no'),
emptyImage: '/assets/img/empty-full.svg',
enterText: this.i18nSvc.fanyi('dashboard.alerts.enter'),
clearText: this.i18nSvc.fanyi('alert.center.clear')
}
];
count = 0;
loading = false;
popoverVisible = false;
refreshInterval: any;
private previousCount = 0;
mute!: Mute;
constructor(
private router: Router,
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService,
private notifySvc: NzNotificationService,
private configSvc: GeneralConfigService,
private alertSvc: AlertService,
private modal: NzModalService,
private cdr: ChangeDetectorRef,
private alertSound: AlertSoundService
) {}
ngOnInit(): void {
let muteInit$ = this.configSvc
.getGeneralConfig('mute')
.pipe(
finalize(() => {
muteInit$.unsubscribe();
})
)
.subscribe(
message => {
if (message.code === 0) {
this.mute = message.data;
} else {
console.warn(message.msg);
}
},
error => {
console.error(error);
}
);
this.loadData();
this.refreshInterval = setInterval(() => {
this.loadData();
}, 10000); // every 10 seconds refresh the tabs
}
ngOnDestroy() {
if (this.refreshInterval) {
clearInterval(this.refreshInterval);
}
}
onPopoverVisibleChange(visible: boolean): void {
if (visible) {
this.loadData();
}
}
updateNoticeData(notices: any[]): any[] {
const data = this.data.slice();
data.forEach(i => (i.list = []));
notices.forEach(item => {
data[0].list.push({ ...item });
});
return data;
}
loadData(): void {
if (this.loading) {
return;
}
this.loading = true;
let loadAlerts$ = this.alertSvc
.loadAlerts(0, undefined, undefined, 0, 5)
.pipe(
finalize(() => {
loadAlerts$.unsubscribe();
this.loading = false;
})
)
.subscribe(
message => {
if (message.code === 0) {
let page = message.data;
let alerts = page.content;
if (alerts == undefined) {
return;
}
let list: any[] = [];
alerts.forEach(alert => {
let item = {
id: alert.id,
monitorId: alert.tags?.monitorId,
avatar: '/assets/img/notification.svg',
title: `${alert.tags?.monitorName}--${this.i18nSvc.fanyi(`alert.priority.${alert.priority}`)}`,
datetime: new Date(alert.lastAlarmTime).toLocaleString(),
color: 'blue',
status: alert.status,
type: this.i18nSvc.fanyi('dashboard.alerts.title-no')
};
list.push(item);
});
this.data = this.updateNoticeData(list);
if (page.totalElements > this.previousCount && !this.mute.mute) {
this.alertSound.playAlertSound(this.i18nSvc.currentLang);
}
this.previousCount = page.totalElements;
this.count = page.totalElements;
} else {
console.warn(message.msg);
}
this.cdr.detectChanges();
},
error => {
console.error(error);
}
);
}
updateAlertsStatus(alertIds: Set<number>, status: number) {
const markAlertsStatus$ = this.alertSvc.applyAlertsStatus(alertIds, status).subscribe(
message => {
markAlertsStatus$.unsubscribe();
if (message.code === 0) {
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.mark-success'), '');
this.loadData();
} else {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.mark-fail'), message.msg);
}
},
error => {
markAlertsStatus$.unsubscribe();
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.mark-fail'), error.msg);
}
);
}
onMarkReadOneAlert(alertId: number) {
let alerts = new Set<number>();
alerts.add(alertId);
this.updateAlertsStatus(alerts, 3);
}
clearAllAlerts() {
const deleteAlerts$ = this.alertSvc.clearAlerts().subscribe(
message => {
deleteAlerts$.unsubscribe();
if (message.code === 0) {
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.clear-success'), '');
this.previousCount = 0;
this.loadData();
} else {
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.clear-fail'), message.msg);
}
},
error => {
deleteAlerts$.unsubscribe();
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.clear-fail'), error.msg);
}
);
}
onClearAllAlerts() {
this.modal.confirm({
nzTitle: this.i18nSvc.fanyi('alert.center.confirm.clear-all'),
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
nzOkDanger: true,
nzOkType: 'primary',
nzClosable: false,
nzOnOk: () => this.clearAllAlerts()
});
}
gotoAlertCenter(): void {
this.popoverVisible = false;
this.router.navigateByUrl(`/alert/center`);
}
gotoDetail(monitorId: number): void {
this.popoverVisible = false;
this.router.navigateByUrl(`/monitors/${monitorId}`);
}
toggleMute(event: MouseEvent): void {
event.stopPropagation();
this.mute.mute = !this.mute.mute;
this.configSvc.saveGeneralConfig(this.mute, 'mute');
this.cdr.markForCheck();
}
}