line-gestao-frontend/src/app/pages/dashboard/dashboard.html

328 lines
12 KiB
HTML

<section class="dashboard-page">
<span class="page-blob blob-1" aria-hidden="true"></span>
<span class="page-blob blob-2" aria-hidden="true"></span>
<span class="page-blob blob-3" aria-hidden="true"></span>
<div class="container-dashboard">
<div class="page-head fade-in-up">
<div class="head-content">
<div class="badge-pill">
<i class="bi bi-grid-1x2-fill"></i> Visão Geral
</div>
<h1 class="page-title">Dashboard de Gestão de Linhas</h1>
<p class="page-subtitle">Painel operacional com foco em status, cobertura e histórico da base.</p>
</div>
<div class="head-actions">
<div class="status-indicator" *ngIf="loading">
<span class="spinner-border spinner-border-sm text-brand"></span>
<span>Atualizando dados...</span>
</div>
<div class="status-indicator error" *ngIf="!loading && errorMsg">
<i class="bi bi-exclamation-triangle-fill"></i> {{ errorMsg }}
</div>
<div class="last-update" *ngIf="!loading && !errorMsg">
<i class="bi bi-check2-circle"></i> Dados atualizados
</div>
</div>
</div>
<div class="hero-grid fade-in-up" [style.animation-delay]="'100ms'">
<div class="hero-card" *ngFor="let k of kpis; trackBy: trackByKpiKey">
<div class="hero-icon">
<i [class]="k.icon"></i>
</div>
<div class="hero-data">
<span class="hero-label">{{ k.title }}</span>
<span class="hero-value">{{ k.value }}</span>
<span class="hero-hint" *ngIf="k.hint">{{ k.hint }}</span>
</div>
</div>
</div>
<div class="context-title fade-in-up" [style.animation-delay]="'180ms'">
<h2>Página Geral</h2>
<p>Distribuição e saúde atual da base de linhas.</p>
</div>
<div class="dashboard-section fade-in-up" [style.animation-delay]="'220ms'">
<div class="section-top-row">
<div class="card-modern card-status">
<div class="card-header-clean">
<div class="header-icon brand"><i class="bi bi-pie-chart-fill"></i></div>
<div class="header-text">
<h3>Status da Base</h3>
<p>Distribuição atual das linhas</p>
</div>
</div>
<div class="card-body-split">
<div class="chart-wrapper-pie">
<canvas #chartStatusPie></canvas>
</div>
<div class="status-list">
<div class="status-item">
<span class="dot d-active"></span>
<span class="lbl">Ativas</span>
<span class="val">{{ statusResumo.ativos | number:'1.0-0' }}</span>
</div>
<div class="status-item">
<span class="dot d-reserve"></span>
<span class="lbl">Reservas</span>
<span class="val">{{ statusResumo.reservas | number:'1.0-0' }}</span>
</div>
<div class="status-item">
<span class="dot d-blocked"></span>
<span class="lbl">Bloq. (Perda/Roubo)</span>
<span class="val">{{ statusResumo.perdaRoubo | number:'1.0-0' }}</span>
</div>
<div class="status-item">
<span class="dot d-blocked-soft"></span>
<span class="lbl">Bloq. (120 dias)</span>
<span class="val">{{ statusResumo.bloq120 | number:'1.0-0' }}</span>
</div>
<div class="status-item total-row">
<span class="lbl">Total Geral</span>
<span class="val">{{ statusResumo.total | number:'1.0-0' }}</span>
</div>
</div>
</div>
</div>
<div class="card-modern card-adicionais">
<div class="card-header-clean">
<div class="header-icon blue"><i class="bi bi-diagram-3-fill"></i></div>
<div class="header-text">
<h3>Serviços Adicionais</h3>
<p>Comparativo de linhas com e sem adicionais (Geral)</p>
</div>
</div>
<div class="card-body-adicionais">
<div class="chart-wrapper-pie-sm">
<canvas #chartAdicionaisComparativo></canvas>
</div>
<div class="compare-list">
<div class="compare-item">
<span class="dot d-com-add"></span>
<span class="lbl">Com adicionais</span>
<span class="val">{{ adicionaisComparativo.com | number:'1.0-0' }}</span>
<span class="pct">{{ adicionaisComparativo.pctCom }}</span>
</div>
<div class="compare-item">
<span class="dot d-sem-add"></span>
<span class="lbl">Sem adicionais</span>
<span class="val">{{ adicionaisComparativo.sem | number:'1.0-0' }}</span>
<span class="pct">{{ adicionaisComparativo.pctSem }}</span>
</div>
<div class="compare-item total-row">
<span class="lbl">Total analisado</span>
<span class="val">{{ adicionaisComparativo.total | number:'1.0-0' }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="dashboard-section fade-in-up" [style.animation-delay]="'280ms'">
<div class="grid-halves">
<div class="card-modern">
<div class="card-header-clean">
<div class="header-icon warning"><i class="bi bi-shield-exclamation"></i></div>
<div class="header-text">
<h3>Vigência (Buckets)</h3>
<p>Status de vencimento atual</p>
</div>
</div>
<div class="chart-wrapper-pie">
<canvas #chartVigenciaSupervisao></canvas>
</div>
</div>
<div class="card-modern">
<div class="card-header-clean">
<div class="header-icon blue"><i class="bi bi-globe2"></i></div>
<div class="header-text">
<h3>Vivo Travel</h3>
<p>Linhas com e sem serviço ativo</p>
</div>
</div>
<div class="chart-wrapper-pie">
<canvas #chartTravelMundo></canvas>
</div>
</div>
</div>
<div class="grid-triples mt-3">
<div class="card-modern">
<div class="card-header-clean">
<div class="header-text">
<h3>Linhas por Franquia</h3>
<p>Distribuição da base por faixa de franquia</p>
</div>
</div>
<div class="chart-wrapper-bar compact">
<canvas #chartLinhasPorFranquia></canvas>
</div>
</div>
<div class="card-modern">
<div class="card-header-clean">
<div class="header-text">
<h3>Adicionais Pagos (Serviços)</h3>
<p>Quantidade de linhas por serviço adicional ativo</p>
</div>
</div>
<div class="chart-wrapper-bar compact">
<canvas #chartAdicionaisPagos></canvas>
</div>
</div>
<div class="card-modern">
<div class="card-header-clean">
<div class="header-text">
<h3>Tipo de Chip</h3>
<p>Quantidade de linhas e-SIM e SIMCARD</p>
</div>
</div>
<div class="chart-wrapper-pie">
<canvas #chartTipoChip></canvas>
</div>
</div>
</div>
</div>
<div class="context-title fade-in-up" [style.animation-delay]="'320ms'">
<h2>Página Resumo</h2>
<p>Indicadores do Resumo focados em quantidade e distribuição de linhas.</p>
</div>
<div class="dashboard-section fade-in-up" [style.animation-delay]="'360ms'">
<div class="card-modern full-width">
<div class="toolbar-header">
<div class="title-group">
<i class="bi bi-bar-chart-line text-brand"></i>
<div>
<h3>Resumo Operacional de Linhas</h3>
<p>Dados consolidados da página Resumo sem foco financeiro</p>
</div>
</div>
<div class="toolbar-controls">
<div class="control-group">
<label>Visualizar Top</label>
<select
[value]="resumoTopN"
(change)="resumoTopN = +($any($event.target).value); onResumoTopNChange()"
class="form-select-sm">
<option *ngFor="let size of resumoTopOptions" [value]="size">{{ size }}</option>
</select>
</div>
<div class="divider-v"></div>
<a class="btn-link" [routerLink]="['/resumo']" [queryParams]="{ tab: 'totais' }">Ver Página Resumo <i class="bi bi-arrow-right"></i></a>
</div>
</div>
<div class="card-body-grid">
<div class="loading-overlay" *ngIf="resumoLoading">
<div class="spinner-border text-brand" role="status"></div>
</div>
<div class="error-state" *ngIf="!resumoLoading && resumoError">
<i class="bi bi-exclamation-circle"></i>
<span>{{ resumoError }}</span>
</div>
<div class="analytics-grid" *ngIf="!resumoLoading && !resumoError">
<div class="mini-chart-card">
<h6>Top Clientes (Qtd. Linhas)</h6>
<div class="chart-area"><canvas #chartResumoTopClientes></canvas></div>
</div>
<div class="mini-chart-card">
<h6>Top Planos (Qtd. Linhas)</h6>
<div class="chart-area"><canvas #chartResumoTopPlanos></canvas></div>
</div>
<div class="mini-chart-card">
<h6>PF vs PJ (Qtd. Linhas)</h6>
<div class="chart-area"><canvas #chartResumoPfPjLinhas></canvas></div>
</div>
<div class="mini-chart-card">
<h6>Reserva por DDD</h6>
<div class="chart-area"><canvas #chartResumoReservaDdd></canvas></div>
</div>
<div class="mini-chart-card mini-metric-card">
<h6>DIFERENÇA PJ X PF</h6>
<div class="metric-stack">
<div class="metric-line">
<span>Valor Total Line</span>
<strong>{{ formatMoneySafe(resumoDiferencaPjPf.valorTotalLine) }}</strong>
</div>
<div class="metric-line">
<span>Lucro Total Line</span>
<strong>{{ formatMoneySafe(resumoDiferencaPjPf.lucroTotalLine) }}</strong>
</div>
<div class="metric-line">
<span>Qtd Linhas</span>
<strong>{{ formatInt(resumoDiferencaPjPf.qtdLinhas) }}</strong>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="context-title fade-in-up" [style.animation-delay]="'420ms'">
<h2>Histórico</h2>
<p>Séries mensais para acompanhamento contínuo de movimentações e vigência.</p>
</div>
<div class="dashboard-section fade-in-up" [style.animation-delay]="'460ms'">
<div class="history-grid">
<div class="card-modern">
<div class="card-header-clean">
<div class="header-text">
<h3>MUREG (12 Meses)</h3>
<p>Histórico mensal de mudanças de plano/aparelho</p>
</div>
</div>
<div class="chart-wrapper-bar compact-half">
<canvas #chartMureg12></canvas>
</div>
</div>
<div class="card-modern">
<div class="card-header-clean">
<div class="header-text">
<h3>Troca de Número (12 Meses)</h3>
<p>Histórico mensal de trocas realizadas</p>
</div>
</div>
<div class="chart-wrapper-bar compact-half">
<canvas #chartTroca12></canvas>
</div>
</div>
<div class="card-modern">
<div class="card-header-clean">
<div class="header-icon purple"><i class="bi bi-calendar2-check"></i></div>
<div class="header-text">
<h3>Vigência (Próx. 12 Meses)</h3>
<p>Contratos a encerrar por mês</p>
</div>
</div>
<div class="chart-wrapper-bar compact-half">
<canvas #chartVigenciaMesAno></canvas>
</div>
</div>
</div>
</div>
</div>
</section>