testes/Modulos Angular/projects/idt_app/docs/router/DASHBOARD_DOCUMENTATION.md

20 KiB
Raw Blame History

📊 Dashboard ERP SAAS PraFrota

Sistema de Indicadores e KPIs para Gestão de Frota


🎯 Visão Geral

O Dashboard PraFrota é o centro de controle operacional que oferece visibilidade completa sobre a performance da frota, eficiência das rotas, custos operacionais e indicadores financeiros em tempo real.


📈 KPIs Estratégicos por Categoria

🚚 1. OPERACIONAL - Frota e Veículos

📊 KPIs Principais:

  • Taxa de Utilização da Frota

    • (Veículos em Operação / Total de Veículos) × 100
    • Meta: > 85%
    • Período: Tempo real, diário, mensal
  • Disponibilidade Operacional

    • (Veículos Disponíveis / Total de Veículos) × 100
    • Meta: > 90%
    • Exclui: Manutenção, acidentes, licenciamento
  • Tempo Médio de Inatividade

    • Média de horas paradas por veículo
    • Meta: < 2 horas/dia
    • Inclui: Manutenção preventiva/corretiva
  • Quilometragem por Veículo

    • KM rodados por período
    • Comparativo: Planejado vs Realizado
    • Análise de eficiência por modelo/ano

📊 Widgets Visuais:

interface FleetKPIs {
  totalVehicles: number;
  activeVehicles: number;
  maintenanceVehicles: number;
  availableVehicles: number;
  utilizationRate: number;
  averageKmPerVehicle: number;
  fuelEfficiencyAverage: number;
}

🛣️ 2. LOGÍSTICA - Rotas e Entregas

📊 KPIs Principais:

  • Taxa de Conclusão de Rotas

    • (Rotas Completadas / Total de Rotas) × 100
    • Meta: > 95%
    • Segmentação: Por tipo (First Mile, Line Haul, Last Mile)
  • Pontualidade de Entregas

    • (Entregas no Prazo / Total de Entregas) × 100
    • Meta: > 90%
    • SLA por tipo de cliente
  • Tempo Médio de Rota

    • Comparativo: Planejado vs Realizado
    • Análise por distância e tipo de carga
    • Identificação de gargalos
  • Taxa de Ocupação de Carga

    • (Peso/Volume Transportado / Capacidade Total) × 100
    • Meta: > 80%
    • Otimização de carregamento
  • Rotas em Atraso

    • Quantidade e percentual de rotas atrasadas
    • Tempo médio de atraso
    • Principais causas identificadas

📊 Widgets Visuais:

interface RoutesKPIs {
  totalRoutes: number;
  completedRoutes: number;
  inProgressRoutes: number;
  delayedRoutes: number;
  completionRate: number;
  onTimeDeliveryRate: number;
  averageRouteTime: number;
  loadUtilizationRate: number;
}

💰 3. FINANCEIRO - Custos e Receitas

📊 KPIs Principais:

  • Custo por Quilômetro

    • (Custos Totais / KM Rodados)
    • Segmentação: Combustível, manutenção, pneus, pedágio
    • Comparativo mensal e anual
  • Receita por Rota

    • Valor médio faturado por entrega
    • Margem de contribuição por tipo de rota
    • Análise de rentabilidade por cliente
  • ROI da Frota

    • (Receita - Custos) / Investimento × 100
    • Por veículo e por período
    • Análise de payback
  • Custo de Combustível

    • Consumo médio por veículo
    • Variação de preços por região
    • Eficiência energética
  • Custos de Manutenção

    • Preventiva vs Corretiva
    • Custo por veículo/km
    • Previsão de gastos

📊 Widgets Visuais:

interface FinancialKPIs {
  totalRevenue: number;
  totalCosts: number;
  profitMargin: number;
  costPerKm: number;
  revenuePerRoute: number;
  fuelCosts: number;
  maintenanceCosts: number;
  fleetROI: number;
}

👨‍💼 4. RECURSOS HUMANOS - Motoristas

📊 KPIs Principais:

  • Produtividade por Motorista

    • Entregas realizadas por período
    • KM rodados por motorista
    • Tempo de trabalho efetivo
  • Taxa de Acidentes

    • (Acidentes / KM Rodados) × 1.000.000
    • Custo médio por acidente
    • Análise de causas principais
  • Pontuação de Condução

    • Score baseado em telemetria
    • Velocidade, frenagem, aceleração
    • Ranking de motoristas
  • Horas Extras

    • Percentual sobre horas normais
    • Custo adicional de HE
    • Planejamento vs realizado

📊 Widgets Visuais:

interface DriversKPIs {
  totalDrivers: number;
  activeDrivers: number;
  averageProductivity: number;
  accidentRate: number;
  averageDrivingScore: number;
  overtimeHours: number;
  trainingCompliance: number;
}

🎨 Layout do Dashboard

📱 Estrutura Responsiva (4 Colunas → 2 → 1)

.dashboard-container {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  padding: 20px;

  @media (max-width: 1200px) {
    grid-template-columns: repeat(2, 1fr);
  }

  @media (max-width: 768px) {
    grid-template-columns: 1fr;
  }
}

🎯 Seções do Dashboard

1. Header com Resumo Executivo

<div class="executive-summary">
  <div class="kpi-card highlight">
    <h3>Frota Ativa</h3>
    <div class="value">{{ activeFleetCount }}/{{ totalFleetCount }}</div>
    <div class="trend" [ngClass]="getTrendClass('fleet')">
      <i class="fas fa-arrow-up"></i> +5.2%
    </div>
  </div>
  
  <div class="kpi-card highlight">
    <h3>Rotas Hoje</h3>
    <div class="value">{{ todayRoutesCompleted }}/{{ todayRoutesTotal }}</div>
    <div class="progress-bar">
      <div class="progress" [style.width.%]="todayCompletionRate"></div>
    </div>
  </div>
  
  <div class="kpi-card highlight">
    <h3>Receita Mensal</h3>
    <div class="value">{{ monthlyRevenue | currency:'BRL' }}</div>
    <div class="target">Meta: {{ monthlyTarget | currency:'BRL' }}</div>
  </div>
</div>

2. Gráficos Operacionais

<div class="charts-section">
  <!-- Utilização da Frota - Donut Chart -->
  <div class="chart-card">
    <h4>Utilização da Frota</h4>
    <canvas #fleetUtilizationChart></canvas>
    <div class="chart-legend">
      <span class="legend-item active">Em Operação ({{ activeVehicles }})</span>
      <span class="legend-item maintenance">Manutenção ({{ maintenanceVehicles }})</span>
      <span class="legend-item idle">Parados ({{ idleVehicles }})</span>
    </div>
  </div>

  <!-- Performance de Rotas - Line Chart -->
  <div class="chart-card">
    <h4>Performance de Rotas (7 dias)</h4>
    <canvas #routesPerformanceChart></canvas>
  </div>

  <!-- Custos por Categoria - Bar Chart -->
  <div class="chart-card">
    <h4>Custos Operacionais</h4>
    <canvas #costsBreakdownChart></canvas>
  </div>

  <!-- Mapa de Rotas Ativas -->
  <div class="chart-card map-card">
    <h4>Rotas Ativas</h4>
    <div class="map-container">
      <google-map
        [center]="mapCenter"
        [zoom]="mapZoom"
        [options]="mapOptions">
        <map-marker
          *ngFor="let route of activeRoutes"
          [position]="route.currentLocation"
          [options]="getMarkerOptions(route)">
        </map-marker>
      </google-map>
    </div>
  </div>
</div>

3. Tabelas de Dados

<div class="data-tables-section">
  <!-- Top 5 Motoristas -->
  <div class="table-card">
    <h4>Top Motoristas (Produtividade)</h4>
    <table class="performance-table">
      <thead>
        <tr>
          <th>Motorista</th>
          <th>Entregas</th>
          <th>KM</th>
          <th>Score</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let driver of topDrivers">
          <td>{{ driver.name }}</td>
          <td>{{ driver.deliveries }}</td>
          <td>{{ driver.kilometers }}</td>
          <td>
            <span class="score-badge" [ngClass]="getScoreClass(driver.score)">
              {{ driver.score }}
            </span>
          </td>
        </tr>
      </tbody>
    </table>
  </div>

  <!-- Rotas Críticas -->
  <div class="table-card">
    <h4>Rotas em Atraso</h4>
    <table class="critical-routes-table">
      <thead>
        <tr>
          <th>Rota</th>
          <th>Motorista</th>
          <th>Destino</th>
          <th>Atraso</th>
          <th>Ação</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let route of delayedRoutes" class="delayed-row">
          <td>{{ route.routeNumber }}</td>
          <td>{{ route.driverName }}</td>
          <td>{{ route.destination }}</td>
          <td class="delay-time">{{ route.delayMinutes }}min</td>
          <td>
            <button class="btn btn-sm btn-warning" (click)="contactDriver(route)">
              <i class="fas fa-phone"></i>
            </button>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</div>

4. Alertas e Notificações

<div class="alerts-section">
  <div class="alert-card" *ngFor="let alert of criticalAlerts" 
       [ngClass]="'alert-' + alert.severity">
    <div class="alert-icon">
      <i class="fas" [ngClass]="getAlertIcon(alert.type)"></i>
    </div>
    <div class="alert-content">
      <h5>{{ alert.title }}</h5>
      <p>{{ alert.message }}</p>
      <small>{{ alert.timestamp | date:'dd/MM/yyyy HH:mm' }}</small>
    </div>
    <div class="alert-actions">
      <button class="btn btn-sm btn-primary" (click)="resolveAlert(alert)">
        Resolver
      </button>
    </div>
  </div>
</div>

🔧 Implementação Técnica

📊 Dashboard Component

@Component({
  selector: 'app-dashboard',
  standalone: true,
  imports: [CommonModule, GoogleMapsModule, NgChartsModule],
  templateUrl: './dashboard.component.html',
  styleUrl: './dashboard.component.scss'
})
export class DashboardComponent implements OnInit, OnDestroy {
  // KPIs Data
  fleetKPIs: FleetKPIs = {};
  routesKPIs: RoutesKPIs = {};
  financialKPIs: FinancialKPIs = {};
  driversKPIs: DriversKPIs = {};

  // Charts Data
  fleetUtilizationData: ChartData = {};
  routesPerformanceData: ChartData = {};
  costsBreakdownData: ChartData = {};

  // Tables Data
  topDrivers: Driver[] = [];
  delayedRoutes: Route[] = [];
  criticalAlerts: Alert[] = [];

  // Real-time Updates
  private updateInterval: any;
  private websocketConnection: WebSocketSubject<any>;

  constructor(
    private dashboardService: DashboardService,
    private websocketService: WebSocketService,
    private cdr: ChangeDetectorRef
  ) {}

  ngOnInit() {
    this.loadDashboardData();
    this.setupRealTimeUpdates();
    this.startPeriodicUpdates();
  }

  ngOnDestroy() {
    if (this.updateInterval) {
      clearInterval(this.updateInterval);
    }
    this.websocketConnection?.complete();
  }

  private loadDashboardData() {
    forkJoin({
      fleet: this.dashboardService.getFleetKPIs(),
      routes: this.dashboardService.getRoutesKPIs(),
      financial: this.dashboardService.getFinancialKPIs(),
      drivers: this.dashboardService.getDriversKPIs(),
      alerts: this.dashboardService.getCriticalAlerts()
    }).subscribe({
      next: (data) => {
        this.fleetKPIs = data.fleet;
        this.routesKPIs = data.routes;
        this.financialKPIs = data.financial;
        this.driversKPIs = data.drivers;
        this.criticalAlerts = data.alerts;
        
        this.updateCharts();
        this.cdr.detectChanges();
      },
      error: (error) => {
        console.error('Erro ao carregar dashboard:', error);
        this.loadFallbackData();
      }
    });
  }

  private setupRealTimeUpdates() {
    this.websocketConnection = this.websocketService.connect('/dashboard-updates');
    
    this.websocketConnection.subscribe({
      next: (update) => {
        this.handleRealTimeUpdate(update);
      },
      error: (error) => {
        console.error('WebSocket error:', error);
      }
    });
  }

  private handleRealTimeUpdate(update: any) {
    switch (update.type) {
      case 'ROUTE_STATUS_CHANGE':
        this.updateRouteStatus(update.data);
        break;
      case 'VEHICLE_STATUS_CHANGE':
        this.updateVehicleStatus(update.data);
        break;
      case 'NEW_ALERT':
        this.addAlert(update.data);
        break;
      case 'KPI_UPDATE':
        this.updateKPIs(update.data);
        break;
    }
    this.cdr.detectChanges();
  }

  private startPeriodicUpdates() {
    // Atualizar dados a cada 5 minutos
    this.updateInterval = setInterval(() => {
      this.loadDashboardData();
    }, 5 * 60 * 1000);
  }

  // Métodos de utilidade
  getTrendClass(kpi: string): string {
    // Lógica para determinar se trend é positivo/negativo
    return 'trend-positive'; // ou 'trend-negative'
  }

  getScoreClass(score: number): string {
    if (score >= 90) return 'score-excellent';
    if (score >= 80) return 'score-good';
    if (score >= 70) return 'score-average';
    return 'score-poor';
  }

  getAlertIcon(type: string): string {
    const icons = {
      'MAINTENANCE': 'fa-wrench',
      'DELAY': 'fa-clock',
      'ACCIDENT': 'fa-exclamation-triangle',
      'FUEL': 'fa-gas-pump',
      'ROUTE': 'fa-route'
    };
    return icons[type] || 'fa-info-circle';
  }

  // Ações do usuário
  contactDriver(route: Route) {
    // Implementar contato com motorista
  }

  resolveAlert(alert: Alert) {
    // Implementar resolução de alerta
  }

  refreshData() {
    this.loadDashboardData();
  }
}

📊 Dashboard Service

@Injectable({
  providedIn: 'root'
})
export class DashboardService {
  private apiUrl = `${environment.apiUrl}/dashboard`;

  constructor(private http: HttpClient) {}

  getFleetKPIs(): Observable<FleetKPIs> {
    return this.http.get<FleetKPIs>(`${this.apiUrl}/fleet-kpis`);
  }

  getRoutesKPIs(): Observable<RoutesKPIs> {
    return this.http.get<RoutesKPIs>(`${this.apiUrl}/routes-kpis`);
  }

  getFinancialKPIs(): Observable<FinancialKPIs> {
    return this.http.get<FinancialKPIs>(`${this.apiUrl}/financial-kpis`);
  }

  getDriversKPIs(): Observable<DriversKPIs> {
    return this.http.get<DriversKPIs>(`${this.apiUrl}/drivers-kpis`);
  }

  getCriticalAlerts(): Observable<Alert[]> {
    return this.http.get<Alert[]>(`${this.apiUrl}/alerts`);
  }

  // Dados históricos para gráficos
  getHistoricalData(period: string): Observable<any> {
    return this.http.get(`${this.apiUrl}/historical/${period}`);
  }
}

📊 Dados Mockados para Desenvolvimento

🎯 KPIs Mock Data

{
  "fleetKPIs": {
    "totalVehicles": 45,
    "activeVehicles": 38,
    "maintenanceVehicles": 4,
    "availableVehicles": 3,
    "utilizationRate": 84.4,
    "averageKmPerVehicle": 287.5,
    "fuelEfficiencyAverage": 8.2
  },
  "routesKPIs": {
    "totalRoutes": 156,
    "completedRoutes": 142,
    "inProgressRoutes": 12,
    "delayedRoutes": 2,
    "completionRate": 91.0,
    "onTimeDeliveryRate": 87.2,
    "averageRouteTime": 4.7,
    "loadUtilizationRate": 78.9
  },
  "financialKPIs": {
    "totalRevenue": 487650.00,
    "totalCosts": 312420.00,
    "profitMargin": 35.9,
    "costPerKm": 2.85,
    "revenuePerRoute": 3126.28,
    "fuelCosts": 89450.00,
    "maintenanceCosts": 45780.00,
    "fleetROI": 24.7
  },
  "driversKPIs": {
    "totalDrivers": 52,
    "activeDrivers": 38,
    "averageProductivity": 8.7,
    "accidentRate": 0.12,
    "averageDrivingScore": 82.5,
    "overtimeHours": 156.5,
    "trainingCompliance": 94.2
  }
}

🎨 Estilos CSS

.dashboard-container {
  padding: 20px;
  background: #f8f9fa;
  min-height: 100vh;

  .executive-summary {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 16px;
    margin-bottom: 24px;

    .kpi-card {
      background: white;
      border-radius: 8px;
      padding: 20px;
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
      border-left: 4px solid #007bff;

      &.highlight {
        border-left-color: #28a745;
      }

      h3 {
        font-size: 14px;
        color: #6c757d;
        margin-bottom: 8px;
        text-transform: uppercase;
      }

      .value {
        font-size: 28px;
        font-weight: bold;
        color: #212529;
        margin-bottom: 8px;
      }

      .trend {
        font-size: 12px;
        font-weight: 500;

        &.trend-positive {
          color: #28a745;
        }

        &.trend-negative {
          color: #dc3545;
        }
      }

      .progress-bar {
        width: 100%;
        height: 6px;
        background: #e9ecef;
        border-radius: 3px;
        overflow: hidden;

        .progress {
          height: 100%;
          background: #28a745;
          transition: width 0.3s ease;
        }
      }
    }
  }

  .charts-section {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
    gap: 16px;
    margin-bottom: 24px;

    .chart-card {
      background: white;
      border-radius: 8px;
      padding: 20px;
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);

      h4 {
        margin-bottom: 16px;
        color: #212529;
      }

      &.map-card {
        .map-container {
          height: 300px;
          border-radius: 4px;
          overflow: hidden;
        }
      }
    }
  }

  .data-tables-section {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
    gap: 16px;
    margin-bottom: 24px;

    .table-card {
      background: white;
      border-radius: 8px;
      padding: 20px;
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);

      table {
        width: 100%;
        border-collapse: collapse;

        th, td {
          padding: 12px 8px;
          text-align: left;
          border-bottom: 1px solid #e9ecef;
        }

        th {
          background: #f8f9fa;
          font-weight: 600;
          color: #495057;
        }

        .score-badge {
          padding: 4px 8px;
          border-radius: 12px;
          font-size: 12px;
          font-weight: 500;

          &.score-excellent {
            background: #d4edda;
            color: #155724;
          }

          &.score-good {
            background: #cce5ff;
            color: #004085;
          }

          &.score-average {
            background: #fff3cd;
            color: #856404;
          }

          &.score-poor {
            background: #f8d7da;
            color: #721c24;
          }
        }

        .delayed-row {
          background: #fff3cd;

          .delay-time {
            color: #856404;
            font-weight: 600;
          }
        }
      }
    }
  }

  .alerts-section {
    .alert-card {
      background: white;
      border-radius: 8px;
      padding: 16px;
      margin-bottom: 12px;
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
      display: flex;
      align-items: center;
      gap: 16px;

      &.alert-critical {
        border-left: 4px solid #dc3545;
      }

      &.alert-warning {
        border-left: 4px solid #ffc107;
      }

      &.alert-info {
        border-left: 4px solid #17a2b8;
      }

      .alert-icon {
        font-size: 24px;
        color: #6c757d;
      }

      .alert-content {
        flex: 1;

        h5 {
          margin-bottom: 4px;
          color: #212529;
        }

        p {
          margin-bottom: 4px;
          color: #6c757d;
        }

        small {
          color: #adb5bd;
        }
      }
    }
  }
}

// Responsividade
@media (max-width: 768px) {
  .dashboard-container {
    padding: 12px;

    .charts-section,
    .data-tables-section {
      grid-template-columns: 1fr;
    }

    .executive-summary {
      grid-template-columns: 1fr;
    }
  }
}

🚀 Próximos Passos

1. Implementação por Fases

  • Fase 1: KPIs básicos + gráficos simples
  • Fase 2: Mapa em tempo real + alertas
  • Fase 3: Machine Learning para previsões
  • Fase 4: Dashboards personalizáveis por usuário

2. Integrações Necessárias

  • WebSocket para dados em tempo real
  • Google Maps API para visualização
  • Chart.js ou D3.js para gráficos
  • Push notifications para alertas críticos

3. Otimizações de Performance

  • Cache de dados com TTL
  • Lazy loading de componentes
  • Paginação server-side
  • Compressão de dados WebSocket

📱 Configuração no Sidebar

// Adicionar ao menu principal
{
  id: 'dashboard',
  label: 'Dashboard',
  icon: 'fa-tachometer-alt',
  route: '/dashboard',
  order: 1, // Primeiro item do menu
  permissions: ['DASHBOARD_VIEW']
}

Este dashboard fornece uma visão 360° da operação, permitindo tomada de decisões baseada em dados e monitoramento proativo da performance da frota. 📊