Files
rutero/route-planner/src/app/private/home/planning-kpis/planning-kpis.component.html
T

100 lines
5.2 KiB
HTML

<div class="kpis-panel">
<div class="kpis-heading">
<div>
<h2 class="section-title">Indicadores de planificación</h2>
<p class="kpis-subtitle">Resumen total de la planificación actual</p>
</div>
<div class="kpis-actions">
<span class="kpis-status" *ngIf="hasData"><i class="pi pi-check-circle"></i> Datos disponibles</span>
<button type="button" class="export-button" *ngIf="hasData" (click)="exportPlanning()"><i class="pi pi-download"></i> Descargar XLSX</button>
</div>
</div>
<div class="kpi-grid">
<article class="kpi-card kpi-primary">
<div class="kpi-icon"><i class="pi pi-map-marker"></i></div>
<div><span class="kpi-label">PDVs totales</span><strong>{{ summary.totalPdvs }}</strong><small>en la planificación</small></div>
</article>
<article class="kpi-card kpi-success">
<div class="kpi-icon"><i class="pi pi-check"></i></div>
<div><span class="kpi-label">PDVs asignados</span><strong>{{ summary.assignedPdvs }}</strong><small>{{ summary.coverage | number:'1.1-1' }}% de cobertura</small></div>
</article>
<article class="kpi-card kpi-warning">
<div class="kpi-icon"><i class="pi pi-exclamation-triangle"></i></div>
<div><span class="kpi-label">Sin asignar</span><strong>{{ summary.unassignedPdvs }}</strong><small>requieren revisión</small></div>
</article>
<article class="kpi-card kpi-blue">
<div class="kpi-icon"><i class="pi pi-users"></i></div>
<div><span class="kpi-label">Usuarios activos</span><strong>{{ summary.users }}</strong><small>{{ summary.days }} días planificados</small></div>
</article>
<article class="kpi-card kpi-orange">
<div class="kpi-icon"><i class="pi pi-compass"></i></div>
<div><span class="kpi-label">Distancia total</span><strong>{{ summary.totalDistance | number:'1.0-1' }} <em>km</em></strong><small>{{ summary.averageDistance | number:'1.0-1' }} km promedio por ruta</small></div>
</article>
<article class="kpi-card kpi-blue">
<div class="kpi-icon"><i class="pi pi-clock"></i></div>
<div><span class="kpi-label">Desplazamiento total</span><strong>{{ summary.totalTravelHours | number:'1.0-1' }} <em>h</em></strong><small>{{ summary.averageTravelHours | number:'1.0-1' }} h promedio por ruta</small></div>
</article>
</div>
<div class="kpi-grid operational-grid" *ngIf="hasData">
<article class="kpi-card kpi-success">
<div class="kpi-icon"><i class="pi pi-briefcase"></i></div>
<div><span class="kpi-label">Carga de trabajo</span><strong>{{ summary.totalWorkHours | number:'1.0-1' }} <em>h</em></strong><small>horas de trabajo planificadas</small></div>
</article>
<article class="kpi-card kpi-blue">
<div class="kpi-icon"><i class="pi pi-chart-line"></i></div>
<div><span class="kpi-label">Utilización promedio</span><strong>{{ summary.averageUtilization | number:'1.0-1' }}<em>%</em></strong><small>carga frente a disponibilidad</small></div>
</article>
<article class="kpi-card kpi-primary">
<div class="kpi-icon"><i class="pi pi-sitemap"></i></div>
<div><span class="kpi-label">Rutas por usuario</span><strong>{{ summary.averageRoutesPerUser | number:'1.0-1' }}</strong><small>promedio de asignaciones</small></div>
</article>
<article class="kpi-card kpi-warning">
<div class="kpi-icon"><i class="pi pi-arrows-h"></i></div>
<div><span class="kpi-label">Brecha de balance</span><strong>{{ summary.assignmentBalance }}</strong><small>diferencia entre mayor y menor carga</small></div>
</article>
</div>
<div class="user-load-card" *ngIf="userLoads.length">
<h3><i class="pi pi-users"></i> Balance de carga por usuario</h3>
<div class="user-load-table-wrap">
<table class="user-load-table">
<thead>
<tr><th>Usuario</th><th>Rutas</th><th>Distancia</th><th>Trabajo</th><th>Utilización</th></tr>
</thead>
<tbody>
<tr *ngFor="let load of userLoads" [class.load-over-capacity]="load.status === 'over-capacity'">
<td>{{ load.name }}</td>
<td>{{ load.routes }}</td>
<td>{{ load.distance | number:'1.0-1' }} km</td>
<td>{{ load.workHours | number:'1.0-1' }} h</td>
<td>
<div class="utilization-cell" [ngClass]="utilizationClass(load)">
<span>{{ load.utilization | number:'1.0-1' }}%</span>
<span class="capacity-warning" *ngIf="load.status === 'over-capacity'" [title]="load.alertMessage" aria-label="Alerta de capacidad">⚠️</span>
<span class="utilization-bar" [title]="load.alertMessage"><span [style.width.%]="barWidth(load.utilization)"></span></span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="reasons-card" *ngIf="reasons.length">
<h3><i class="pi pi-list"></i> Motivos de PDVs sin asignar</h3>
<div class="reason-list">
<div class="reason-row" *ngFor="let item of reasons">
<span>{{ item.reason }}</span>
<strong>{{ item.count }}</strong>
</div>
</div>
</div>
<div class="kpis-empty" *ngIf="!hasData">
<i class="pi pi-chart-bar"></i>
<span>Carga una planificación para visualizar sus indicadores.</span>
</div>
</div>