{{-- ── Tabs ────────────────────────────────────────────────────── --}}
@foreach(['pipeline'=>'🔄 Pipeline WIP', 'toc'=>'🎯 Restricciones (ToC)', 'oee'=>'⚙️ OEE', 'throughput'=>'📈 Throughput', 'recommendations'=>'💡 Recomendaciones'] as $tab=>$label) @endforeach
{{-- ════════════════════════════════════════════════════════════ --}} {{-- TAB: Pipeline WIP --}} {{-- ════════════════════════════════════════════════════════════ --}} @if($activeTab === 'pipeline')
Estado del pipeline de producción
WIP (Work in Process) acumulado en cada etapa — el nodo más cargado es la restricción
{{-- DBR legend --}}
OK (≤2 unidades)
Monitorear (3-5)
Alerta (6-8)
Restricción (>8)
{{-- Pipeline flow --}} @php function pipeClass(int $n): string { return match(true) { $n > 8 => 'pipe-critical', $n > 5 => 'pipe-warning', $n > 2 => 'pipe-monitor', default => 'pipe-ok', }; } @endphp
@php $pipeStages = [ ['icon'=>'⏳','label'=>'Cola Tintura', 'wip'=> $wip['plan'], 'sub'=>'batches PLAN'], ['icon'=>'🎨','label'=>'Tintura Activa','wip'=> $wip['proceso'], 'sub'=>'batches PROCESO'], ['icon'=>'🔬','label'=>'QC Pendiente', 'wip'=> $wip['qcPending'], 'sub'=>'evaluación color'], ['icon'=>'⚠️','label'=>'Fuera Estándar','wip'=> $wip['qcOos'], 'sub'=>'OOS + matiz'], ['icon'=>'🔄','label'=>'Retrabajo', 'wip'=> $wip['rework'], 'sub'=>'2ª+ generación'], ['icon'=>'✨','label'=>'Acabado', 'wip'=> $wip['finishingQ'] + $wip['finishingAct'], 'sub'=>'PLAN + activos'], ['icon'=>'👁️','label'=>'Inspección', 'wip'=> $wip['inspQ'], 'sub'=>'pendientes'], ['icon'=>'📦','label'=>'Empaque', 'wip'=> $wip['packingQ'], 'sub'=>'pendientes'], ]; @endphp @foreach($pipeStages as $s)
{{ $s['icon'] }}
{{ $s['label'] }}
{{ $s['wip'] }}
{{ $s['sub'] }}
@endforeach
{{-- Little's Law explanation --}}
Ley de Little — Teoría de Restricciones
Lead Time = WIP ÷ Throughput Rate
La etapa con el WIP más alto está determinando el lead time de todo el sistema. Para reducir el tiempo total de producción sin invertir en más capacidad, elimina el WIP acumulado en la restricción — no en las etapas que fluyen libremente.
{{-- Summary cards --}}
@php $totalWip = $wip['plan'] + $wip['proceso'] + $wip['qcPending'] + $wip['qcOos'] + $wip['rework'] + $wip['finishingQ'] + $wip['finishingAct'] + $wip['inspQ'] + $wip['packingQ']; @endphp
WIP Total
{{ $totalWip }}
unidades en planta
Completados ({{ $days }}d)
{{ $batchStats['total'] }}
batches terminados
FPY Color
{{ $batchStats['total'] > 0 ? round($batchStats['firstPass']/$batchStats['total']*100) : '—' }}%
aprobado 1er intento
Rechazo
{{ $batchStats['total'] > 0 ? round($batchStats['rejected']/$batchStats['total']*100) : '—' }}%
batches rechazados
@endif {{-- ════════════════════════════════════════════════════════════ --}} {{-- TAB: Theory of Constraints --}} {{-- ════════════════════════════════════════════════════════════ --}} @if($activeTab === 'toc')
Identificación y ranking de restricciones
Puntuación = WIP × Tiempo de ciclo promedio (Ley de Little). La restricción #1 limita el throughput de todo el sistema.
{{-- Constraint highlight --}} @if(isset($tocStages[0]) && $tocStages[0]['score'] > 0) @php $c = $tocStages[0]; @endphp
{{ $c['icon'] }}
🎯 Restricción del sistema (5 pasos ToC: Paso 1)
{{ $c['label'] }}
{{ $c['description'] }}
WIP{{ $c['wip'] }}
Ciclo{{ $c['cycle_min'] }}m
Espera estimada{{ $c['wait_hours'] }}h
PASO 2: EXPLOTAR
@endif {{-- Stage ranking table --}}
@foreach($tocStages as $i => $s) @endforeach
# Etapa WIP Ciclo Prom. Espera Est. Puntuación ToC Estado
#{{ $i+1 }}
{{ $s['icon'] }}
{{ $s['label'] }}
{{ $s['table'] }}
{{ $s['wip'] }} {{ $s['cycle_min'] > 60 ? round($s['cycle_min']/60,1).'h' : $s['cycle_min'].'m' }} {{ $s['wait_hours'] > 0 ? $s['wait_hours'].'h' : '—' }}
{{ $s['rel_score'] }}%
{{ match($s['status']){'critical'=>'Crítico','warning'=>'Alerta','monitor'=>'Monitorear',default=>'OK'} }}
{{-- Cycle times from process executions --}} @if(count($cycleTimes) > 0)
Tiempos de ciclo reales (últimos {{ $days }}d)
@foreach($cycleTimes as $type => $ct)
{{ $ct['label'] }}
{{ $ct['avg_min'] }}m avg {{ $ct['count'] }} muestras
{{ $ct['min_min'] }}m – {{ $ct['max_min'] }}m
@endforeach
@endif @endif {{-- ════════════════════════════════════════════════════════════ --}} {{-- TAB: OEE --}} {{-- ════════════════════════════════════════════════════════════ --}} @if($activeTab === 'oee')
OEE por máquina de tintura
OEE = Disponibilidad × Rendimiento × Calidad · Clase mundial ≥ 85% · Mínimo aceptable 65%
@if(count($oeeData) === 0)
⚙️
No hay máquinas de tintura configuradas
Agrega máquinas en Gestión de Máquinas.
@else {{-- OEE reference bar --}}
Escala OEE:
0%
50%
65%
85%+
@foreach($oeeData as $m) @php $oeeColor = match(true) { $m['oee'] === null => '#94a3b8', $m['oee'] >= 85 => '#16a34a', $m['oee'] >= 65 => '#d97706', default => '#ef4444', }; $r = 22; $circ = 2 * M_PI * $r; function oeeArc(float|null $pct, float $circ): string { if ($pct === null) return ''; $fill = round(($pct / 100) * $circ, 2); return "stroke-dasharray:{$fill} {$circ}; stroke-dashoffset:0;"; } @endphp
{{ $m['name'] }}
{{ $m['code'] }} · {{ $m['total_batches'] }} batches ({{ $days }}d)
@if($m['oee'] !== null)
{{ $m['oee'] }}%
OEE
@else
Sin datos
@endif
@if($m['total_batches'] > 0) {{-- OEE gauge breakdown --}}
@foreach([ ['Disp.','availability','#3b82f6'], ['Rend.','performance','#f59e0b'], ['Cal.','quality','#22c55e'], ['OEE','oee',$oeeColor], ] as [$lbl, $key, $color])
@php $val = $m[$key]; @endphp @if($val !== null) @endif
{{ $m[$key] !== null ? $m[$key].'%' : '—' }}
{{ $lbl }}
@endforeach
Paro registrado
{{ $m['downtime_hours'] }}h
Throughput/día
{{ $m['throughput_day'] }} batches
FPY
{{ $m['fpy'] !== null ? $m['fpy'].'%' : '—' }}
Ciclo prom.
{{ $m['avg_cycle_hours'] > 0 ? $m['avg_cycle_hours'].'h' : '—' }}
@if($m['oee'] !== null)
@endif @else
Sin batches en el período ({{ $days }}d)
@endif
@endforeach
{{-- OEE definitions --}}
@foreach([ ['Disponibilidad','(Tiempo planif. − Paro) / Tiempo planif.','Tiempo efectivo que la máquina estuvo disponible para producir. Se pierde por mantenimiento, averías, cambios de formato.'], ['Rendimiento','Producción real / Capacidad teórica','Velocidad efectiva vs. velocidad máxima. Se pierde por micro-paros, velocidad reducida.'], ['Calidad (FPY)','Batches aprobados / Total batches','Fracción de producción que cumple especificaciones en primer intento. Retrabajo y rechazo destruyen este componente.'], ] as [$title, $formula, $desc])
{{ $title }}
{{ $formula }}
{{ $desc }}
@endforeach
@endif @endif {{-- ════════════════════════════════════════════════════════════ --}} {{-- TAB: Throughput Trend --}} {{-- ════════════════════════════════════════════════════════════ --}} @if($activeTab === 'throughput')
Throughput diario — últimos {{ $days }} días
Producción completada por día. El objetivo es un flujo estable sin picos de acumulación.
@php $dailyBatches = $trend['dailyBatches']; $dailyExecs = $trend['dailyExecs']; $maxBatch = max(array_column($dailyBatches, 'total') + [0]); $maxExec = max(array_column($dailyExecs, 'total') + [0]); $maxY = max($maxBatch, $maxExec, 1); $displayed = array_slice($dailyBatches, -30); $displayedEx = array_slice($dailyExecs, -30); @endphp {{-- Batch throughput chart --}}
Batches completados por día
Aprobado
Retrabajo
Rechazado
@foreach($displayed as $day) @php $total = max($day['total'], 0); $maxH = 100; $scale = $maxY > 0 ? $maxH / $maxY : 1; $hApp = round(max($day['approved'] - $day['rework'] - $day['rejected'], 0) * $scale); $hRew = round($day['rework'] * $scale); $hRej = round($day['rejected'] * $scale); $hEmpty = $maxH - $hApp - $hRew - $hRej; @endphp
@if($hRej > 0)
@endif @if($hRew > 0)
@endif @if($hApp > 0)
@endif
{{ $day['label'] }}
@endforeach @if(empty($displayed))
Sin datos en el período
@endif
{{-- Process execution throughput --}} @if(count($displayedEx) > 0 && max(array_column($displayedEx, 'total')) > 0)
Ejecuciones de proceso completadas por día
Acabado
Inspección
Empaque
@foreach($displayedEx as $day) @php $maxH = 100; $mxEx = max(array_column($displayedEx, 'total') + [1]); $scale = $maxH / $mxEx; $hFin = round($day['finishing'] * $scale); $hIns = round($day['inspection'] * $scale); $hPack = round($day['packing'] * $scale); $hEmp = $maxH - $hFin - $hIns - $hPack; @endphp
@if($hPack > 0)
@endif @if($hIns > 0)
@endif @if($hFin > 0)
@endif
{{ $day['label'] }}
@endforeach
@endif {{-- FPY waterfall --}} @if($fpyData['total'] > 0)
Flujo de calidad — cascada de decisión ({{ $days }}d)
{{ $fpyData['total'] }}
Total completados
→
{{ $fpyData['firstPass'] }}
Aprobado 1er paso
+
{{ $fpyData['reworkOk'] }}
Aprobado retrabajo
+
{{ $fpyData['rejected'] }}
Rechazado
+
{{ $fpyData['oos'] }}
OOS pendiente
FPY (First-Pass Yield): {{ round($fpyData['firstPass']/$fpyData['total']*100) }}%  ·  Rendimiento Global: {{ round($fpyData['approved']/$fpyData['total']*100) }}%  ·  Rechazo: {{ round($fpyData['rejected']/$fpyData['total']*100) }}%
@endif @endif {{-- ════════════════════════════════════════════════════════════ --}} {{-- TAB: Recommendations --}} {{-- ════════════════════════════════════════════════════════════ --}} @if($activeTab === 'recommendations')
Recomendaciones basadas en análisis
Ordenadas por prioridad · Generadas automáticamente a partir de los datos de producción
@if(count($recommendations) === 0)
✅
Sistema en buen estado
No se detectaron restricciones críticas en el período analizado.
@else {{-- 5 Steps summary --}}
@foreach([ [1,'Identificar','La restricción del sistema'], [2,'Explotar','Máximo rendimiento de la restricción'], [3,'Subordinar','Todo lo demás sigue el ritmo de la restricción'], [4,'Elevar','Si sigue siendo restricción, aumentar capacidad'], [5,'Repetir','Encontrar la nueva restricción'], ] as [$n,$title,$desc])
Paso {{ $n }}
{{ $title }}
{{ $desc }}
@endforeach
@foreach($recommendations as $rec)
{{ $rec['icon'] }} @if($rec['step']) PASO {{ $rec['step'] }} @endif {{ $rec['title'] }} {{ match($rec['priority']){'critical'=>'Crítico','high'=>'Alto','medium'=>'Medio',default=>'Bajo'} }}
{{ $rec['body'] }}
💡 Acción: {{ $rec['action'] }}
@endforeach
@endif @endif
{{-- end .page --}}