276 lines
7.6 KiB
TypeScript
276 lines
7.6 KiB
TypeScript
import { Component, OnInit, ElementRef, ViewChild, ChangeDetectorRef, Inject, PLATFORM_ID } from '@angular/core';
|
|
import { CommonModule, isPlatformBrowser } from '@angular/common';
|
|
import { FormsModule } from '@angular/forms';
|
|
import { HttpErrorResponse } from '@angular/common/http';
|
|
|
|
import { CustomSelectComponent } from '../../components/custom-select/custom-select';
|
|
import { HistoricoService, AuditLogDto, AuditChangeType, HistoricoQuery } from '../../services/historico.service';
|
|
|
|
interface SelectOption {
|
|
value: string;
|
|
label: string;
|
|
}
|
|
|
|
@Component({
|
|
selector: 'app-historico',
|
|
standalone: true,
|
|
imports: [CommonModule, FormsModule, CustomSelectComponent],
|
|
templateUrl: './historico.html',
|
|
styleUrls: ['./historico.scss'],
|
|
})
|
|
export class Historico implements OnInit {
|
|
@ViewChild('successToast', { static: false }) successToast!: ElementRef;
|
|
|
|
logs: AuditLogDto[] = [];
|
|
loading = false;
|
|
error = false;
|
|
errorMsg = '';
|
|
toastMessage = '';
|
|
|
|
expandedLogId: string | null = null;
|
|
|
|
page = 1;
|
|
pageSize = 10;
|
|
pageSizeOptions = [10, 20, 50, 100];
|
|
total = 0;
|
|
|
|
filterPageName = '';
|
|
filterAction = '';
|
|
filterUserId = '';
|
|
filterSearch = '';
|
|
dateFrom = '';
|
|
dateTo = '';
|
|
|
|
readonly pageOptions: SelectOption[] = [
|
|
{ value: '', label: 'Todas as páginas' },
|
|
{ value: 'Geral', label: 'Geral' },
|
|
{ value: 'Mureg', label: 'Mureg' },
|
|
{ value: 'Faturamento', label: 'Faturamento' },
|
|
{ value: 'Parcelamentos', label: 'Parcelamentos' },
|
|
{ value: 'Dados e Usuários', label: 'Dados PF/PJ' },
|
|
{ value: 'Vigência', label: 'Vigência' },
|
|
{ value: 'Chips Virgens e Recebidos', label: 'Chips Virgens e Recebidos' },
|
|
{ value: 'Troca de número', label: 'Troca de número' },
|
|
];
|
|
|
|
readonly actionOptions: SelectOption[] = [
|
|
{ value: '', label: 'Todas as ações' },
|
|
{ value: 'CREATE', label: 'Criação' },
|
|
{ value: 'UPDATE', label: 'Atualização' },
|
|
{ value: 'DELETE', label: 'Exclusão' },
|
|
];
|
|
|
|
private searchTimer: any = null;
|
|
|
|
constructor(
|
|
private historicoService: HistoricoService,
|
|
private cdr: ChangeDetectorRef,
|
|
@Inject(PLATFORM_ID) private platformId: object
|
|
) {}
|
|
|
|
ngOnInit(): void {
|
|
this.fetch(1);
|
|
}
|
|
|
|
refresh(): void {
|
|
this.fetch(1);
|
|
}
|
|
|
|
applyFilters(): void {
|
|
this.page = 1;
|
|
this.fetch();
|
|
}
|
|
|
|
clearFilters(): void {
|
|
this.filterPageName = '';
|
|
this.filterAction = '';
|
|
this.filterUserId = '';
|
|
this.filterSearch = '';
|
|
this.dateFrom = '';
|
|
this.dateTo = '';
|
|
this.page = 1;
|
|
this.fetch();
|
|
}
|
|
|
|
clearSearch(): void {
|
|
this.filterSearch = '';
|
|
this.page = 1;
|
|
this.fetch();
|
|
}
|
|
|
|
onSearchChange(): void {
|
|
if (this.searchTimer) clearTimeout(this.searchTimer);
|
|
this.searchTimer = setTimeout(() => {
|
|
this.page = 1;
|
|
this.fetch();
|
|
}, 300);
|
|
}
|
|
|
|
onPageSizeChange(): void {
|
|
this.page = 1;
|
|
this.fetch();
|
|
}
|
|
|
|
goToPage(p: number): void {
|
|
this.page = Math.max(1, Math.min(this.totalPages, p));
|
|
this.fetch();
|
|
}
|
|
|
|
get totalPages(): number {
|
|
return Math.ceil((this.total || 0) / this.pageSize) || 1;
|
|
}
|
|
|
|
get pageNumbers(): number[] {
|
|
const total = this.totalPages;
|
|
const current = this.page;
|
|
const max = 5;
|
|
let start = Math.max(1, current - 2);
|
|
let end = Math.min(total, start + (max - 1));
|
|
start = Math.max(1, end - (max - 1));
|
|
|
|
const pages: number[] = [];
|
|
for (let i = start; i <= end; i++) pages.push(i);
|
|
return pages;
|
|
}
|
|
|
|
get pageStart(): number {
|
|
return this.total === 0 ? 0 : (this.page - 1) * this.pageSize + 1;
|
|
}
|
|
|
|
get pageEnd(): number {
|
|
if (this.total === 0) return 0;
|
|
return Math.min(this.page * this.pageSize, this.total);
|
|
}
|
|
|
|
toggleDetails(log: AuditLogDto, event?: Event): void {
|
|
if (event) event.stopPropagation();
|
|
this.expandedLogId = this.expandedLogId === log.id ? null : log.id;
|
|
}
|
|
|
|
formatDateTime(value?: string | null): string {
|
|
if (!value) return '-';
|
|
const d = new Date(value);
|
|
if (isNaN(d.getTime())) return '-';
|
|
return d.toLocaleString('pt-BR');
|
|
}
|
|
|
|
displayUserName(log: AuditLogDto): string {
|
|
const name = (log.userName || '').trim();
|
|
return name ? name : 'SISTEMA';
|
|
}
|
|
|
|
displayEntity(log: AuditLogDto): string {
|
|
const label = (log.entityLabel || '').trim();
|
|
if (label) return label;
|
|
return log.entityName || '-';
|
|
}
|
|
|
|
formatAction(action?: string | null): string {
|
|
const value = (action || '').toUpperCase();
|
|
if (!value) return '-';
|
|
if (value === 'CREATE') return 'Criação';
|
|
if (value === 'UPDATE') return 'Atualização';
|
|
if (value === 'DELETE') return 'Exclusão';
|
|
return 'Outro';
|
|
}
|
|
|
|
actionClass(action?: string | null): string {
|
|
const value = (action || '').toUpperCase();
|
|
if (value === 'CREATE') return 'action-create';
|
|
if (value === 'UPDATE') return 'action-update';
|
|
if (value === 'DELETE') return 'action-delete';
|
|
return 'action-default';
|
|
}
|
|
|
|
changeTypeLabel(type?: AuditChangeType | string | null): string {
|
|
if (!type) return 'Alterado';
|
|
if (type === 'added') return 'Adicionado';
|
|
if (type === 'removed') return 'Removido';
|
|
return 'Alterado';
|
|
}
|
|
|
|
changeTypeClass(type?: AuditChangeType | string | null): string {
|
|
if (type === 'added') return 'change-added';
|
|
if (type === 'removed') return 'change-removed';
|
|
if (type === 'modified') return 'change-modified';
|
|
return 'change-modified';
|
|
}
|
|
|
|
formatChangeValue(value?: string | null): string {
|
|
if (value === undefined || value === null || value === '') return '-';
|
|
return String(value);
|
|
}
|
|
|
|
trackByLog(_: number, log: AuditLogDto): string {
|
|
return log.id;
|
|
}
|
|
|
|
trackByField(_: number, change: { field: string }): string {
|
|
return change.field;
|
|
}
|
|
|
|
private fetch(goToPage?: number): void {
|
|
if (goToPage) this.page = goToPage;
|
|
this.loading = true;
|
|
this.error = false;
|
|
this.errorMsg = '';
|
|
this.expandedLogId = null;
|
|
|
|
const query: HistoricoQuery = {
|
|
page: this.page,
|
|
pageSize: this.pageSize,
|
|
pageName: this.filterPageName || undefined,
|
|
action: this.filterAction || undefined,
|
|
userId: this.filterUserId?.trim() || undefined,
|
|
search: this.filterSearch?.trim() || undefined,
|
|
dateFrom: this.toIsoDate(this.dateFrom, false) || undefined,
|
|
dateTo: this.toIsoDate(this.dateTo, true) || undefined,
|
|
};
|
|
|
|
this.historicoService.list(query).subscribe({
|
|
next: (res) => {
|
|
this.logs = res.items || [];
|
|
this.total = res.total || 0;
|
|
this.page = res.page || this.page;
|
|
this.pageSize = res.pageSize || this.pageSize;
|
|
this.loading = false;
|
|
},
|
|
error: (err: HttpErrorResponse) => {
|
|
this.error = true;
|
|
if (err?.status === 403) {
|
|
this.errorMsg = 'Acesso restrito.';
|
|
} else {
|
|
this.errorMsg = 'Erro ao carregar histórico. Tente novamente.';
|
|
}
|
|
this.loading = false;
|
|
},
|
|
});
|
|
}
|
|
|
|
private toIsoDate(value: string, endOfDay: boolean): string | null {
|
|
if (!value) return null;
|
|
const time = endOfDay ? '23:59:59' : '00:00:00';
|
|
const date = new Date(`${value}T${time}`);
|
|
if (isNaN(date.getTime())) return null;
|
|
return date.toISOString();
|
|
}
|
|
|
|
private async showToast(message: string) {
|
|
if (!isPlatformBrowser(this.platformId)) return;
|
|
this.toastMessage = message;
|
|
this.cdr.detectChanges();
|
|
if (!this.successToast?.nativeElement) return;
|
|
|
|
try {
|
|
const bs = await import('bootstrap');
|
|
const toastInstance = bs.Toast.getOrCreateInstance(this.successToast.nativeElement, {
|
|
autohide: true,
|
|
delay: 3000
|
|
});
|
|
toastInstance.show();
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
}
|
|
}
|