@php // Step type configuration — mirrors ColorManagement::STEP_TYPES $stepCfg = \App\Livewire\Planning\ColorManagement::STEP_TYPES; // Helper: render step badge inline $stepBadge = fn(string $tipo) => sprintf( '%s', $stepCfg[$tipo]['bg'] ?? '#f1f5f9', $stepCfg[$tipo]['fg'] ?? '#475569', $stepCfg[$tipo]['code'] ?? substr($tipo,0,3) ); $stepLabel = fn(string $tipo) => $stepCfg[$tipo]['label'] ?? $tipo; $stepIsHeat = fn(string $tipo) => $stepCfg[$tipo]['is_heat'] ?? false; $stepHasTemp = fn(string $tipo) => $stepCfg[$tipo]['has_temp'] ?? true; @endphp {{-- ── PAGE HEADER ─────────────────────────────────── --}} @if($section === 'curves') {{-- ══════════════════════════════════════════════════════════════ CURVES SECTION ══════════════════════════════════════════════════════════════ --}} @if($curvas->isEmpty())
📈
Sin curvas de tintura
Clic para crear la primera curva
@else
{{ $curvas->count() }} curva(s) · ● = paso con dosificación de químicos
@foreach($curvas as $curve) @php $dosingCount = $curve->steps->where('ventana_adicion', true)->count(); $totalMin = $curve->steps->sum(fn($s) => in_array($s->tipo,['CALENTAMIENTO','ENFRIAMIENTO']) && $s->gradiente_c_min > 0 ? abs($s->temp_final_c-$s->temp_inicio_c)/$s->gradiente_c_min : $s->tiempo_min ?? 0); $maxTemp = $curve->steps->max('temp_final_c'); $recipeCount = \App\Models\ProductionFormula::where('dye_curve_id', $curve->id)->count(); @endphp
{{ $curve->nombre }} {{ $curve->tipo_fibra }} @if($dosingCount > 0){{ $dosingCount }} dosif.@endif
⏱ ~{{ round($totalMin) }} min · 🌡 máx {{ $maxTemp }}°C · 🧪 {{ $recipeCount }} receta(s)
@if($curve->descripcion)
{{ $curve->descripcion }}
@endif
@foreach($curve->steps->sortBy('orden') as $step) @php $prefix = substr($step->tipo,0,3); $isHeat = in_array($step->tipo,['CALENTAMIENTO','ENFRIAMIENTO']); $dur = $isHeat && $step->gradiente_c_min>0 ? round(abs($step->temp_final_c-$step->temp_inicio_c)/$step->gradiente_c_min).'min' : ($step->tiempo_min.'min'); @endphp
{{ $step->orden }} {{ $prefix }} @if($step->ventana_adicion)
@else
@endif
{{ $step->temp_inicio_c }}°→{{ $step->temp_final_c }}°C @if($isHeat && $step->gradiente_c_min) · {{ $step->gradiente_c_min }}°/min@endif · {{ $dur }} @if($step->descripcion) — {{ $step->descripcion }}@endif
@endforeach
@endforeach @endif @elseif(!$selectedColorId) {{-- ══════════════════════════════════════════════════════════════ COLORS LIST / GRID ══════════════════════════════════════════════════════════════ --}}
{{ $colors->total() }}
Total colores
{{ $colors->where('active',true)->count() }}
Activos
{{ $colors->filter(fn($c)=>$c->labFormulas->where('status','Approved_in_Lab')->isNotEmpty())->count() }}
Lab aprobado
@if($viewMode === 'grid')
@forelse($colors as $color) @php $hex = $color->fallback_hex ?? $color->color_hex ?? '#6B7280'; $hA = $color->labFormulas->where('status','Approved_in_Lab')->isNotEmpty(); @endphp
{{ $color->code }}
{{ $color->name }}
@if($color->season){{ $color->season }}@else@endif @if($hA)✓ Lab @elseif($color->labFormulas->isNotEmpty())Borrador @elseSin fórmula@endif
@if($color->client)
{{ $color->client }}
@endif
@empty
No se encontraron colores.
@endforelse
@else
@forelse($colors as $color) @php $hex = $color->fallback_hex ?? $color->color_hex ?? '#6B7280'; @endphp
{{ $color->code }}
{{ $color->name }}
{{ $color->client ?: '—' }}
@if($color->season){{ $color->season }}@else@endif
{{ $color->articulo_id ?: '—' }}
@if($color->labFormulas->where('status','Approved_in_Lab')->isNotEmpty())✓ Lab @elseif($color->labFormulas->isNotEmpty())Borrador @elseSin fórmula@endif
@empty
No se encontraron colores.
@endforelse
@endif
{{ $colors->links() }}
@else {{-- ══════════════════════════════════════════════════════════════ COLOR DETAIL — 4-TAB VIEW ══════════════════════════════════════════════════════════════ --}} @php $ref = $color->reference_data ?? []; $hex = $color->fallback_hex ?? $color->color_hex ?? '#6B7280'; $hasRef = !empty($ref['l_star']); $activeRecipe = $recipes->firstWhere('status','Approved'); @endphp {{-- Color banner --}}
{{ $color->code }} — {{ $color->name }}
@if($color->client){{ $color->client }}@endif @if($color->season) · {{ $color->season }}@endif @if($color->articulo_id) · {{ $color->articulo_id }}@endif @if(!$color->active)INACTIVO@endif
@if(!empty($ref['tcx_code']))
Pantone TCX
{{ $ref['tcx_code'] }}
@endif @if($hasRef)
@foreach(['L*'=>$ref['l_star'],'a*'=>$ref['a_star']??0,'b*'=>$ref['b_star']??0] as $lbl=>$val)
{{ number_format($val,1) }}
{{ $lbl }}
@endforeach
@endif
{{-- Tabs --}}
{{-- ── TAB 1: INFO ─────────────────────────────────── --}} @if($activeTab === 'info')
Datos del Color
Identificación
@error('colorForm.code'){{ $message }}@enderror
Referencia de Color
@endif {{-- ── TAB 2: LAB TRIALS ───────────────────────────── --}} @if($activeTab === 'trials')

Intentos de laboratorio · ΔE automático @if(!$hasRef) ⚠ Sin L*a*b* de referencia@endif

@forelse($trials as $trial) @php $pf=$trial->pass_fail; $deCls=match($pf){'PASS'=>'pass','MARGINAL'=>'marginal','FAIL'=>'fail',default=>'nodata'}; $mx=$trial->items->max('concentration_owf')?:1; @endphp
{{ $trial->version_name }} {{ $trial->status==='Approved_in_Lab'?'✓ Aprobado Lab':'Borrador' }}
{{ $trial->delta_e!==null?'ΔE '.number_format($trial->delta_e,2):'—' }}
{{ $pf==='PASS'?'DENTRO DEL ESTÁNDAR':($pf==='MARGINAL'?'MARGINAL':($pf==='FAIL'?'FUERA':'Sin medición')) }}
@if($trial->read_l!==null)
L* {{ number_format($trial->read_l,2) }}
a* {{ number_format($trial->read_a,2) }}
b* {{ number_format($trial->read_b,2) }}
@endif
@foreach($trial->items as $fi)
{{ $fi->dyestuff?->name ?? '—' }}
{{ number_format($fi->concentration_owf,4) }}%
@endforeach @if($trial->trial_notes)
{{ $trial->trial_notes }}
@endif
@if($trial->status!=='Approved_in_Lab') @else@endif
@empty
🧫
Sin trials — clic para crear el primero
@endforelse @if($trials->isNotEmpty())
+
Nuevo Trial
@endif
@endif {{-- ── TAB 3: PRODUCTION FORMULA ───────────────────── --}} @if($activeTab === 'production')

Versiones de fórmula con curva de tintura · Una versión activa a la vez

@if($recipes->isEmpty())
🧪
Sin fórmulas de producción
@else
@foreach($recipes as $r) @endforeach
@php $viewing = $recipes->firstWhere('id',$viewingRecipeId) ?? $recipes->first(); @endphp @if($viewing) @php $pf = $viewing->productionFormula; $lf = $pf?->labFormula; $cur = $viewing->dyeCurve; // Group step chemicals by curve_step_id $chemByStep = $viewing->items->groupBy('curve_step_id'); @endphp
{{ $viewing->nombre }} {{ $viewing->status==='Approved'?'✓ Activa':($viewing->status==='Superseded'?'Archivada':'Borrador') }}
@if($viewing->status!=='Approved')@endif @if($viewing->status!=='Superseded')@endif 🖨
Trial base: {{ $lf?->version_name ?? '—' }}
Partida: {{ $pf?->partida ?? '—' }}
Versión: V.{{ $pf?->version_number ?? '—' }}
Curva: {{ $cur?->nombre ?? '—' }}
Rel. Baño: {{ $viewing->water_ratio }}:1
Emitido por: {{ $viewing->emitido_por ?: '—' }}
{{-- Full process: curve steps with chemicals interleaved --}} @if($cur && $cur->steps->isNotEmpty())
Proceso Completo — {{ $cur->nombre }} ({{ $cur->tipo_fibra }})
@foreach($cur->steps->sortBy('orden') as $step) @php $prefix = substr($step->tipo,0,3); $isHeat = in_array($step->tipo,['CALENTAMIENTO','ENFRIAMIENTO']); $dur = $isHeat && $step->gradiente_c_min>0 ? round(abs($step->temp_final_c-$step->temp_inicio_c)/$step->gradiente_c_min).'min ('.($step->gradiente_c_min.'°/min)') : ($step->tiempo_min.'min'); $chems = $chemByStep->get($step->id, collect()); @endphp
{{ $step->orden }}
{{ $step->tipo }} {{ $step->temp_inicio_c }}° → {{ $step->temp_final_c }}°C {{ $dur }} @if($step->ventana_adicion)● Dosificación@endif @if($step->descripcion)— {{ $step->descripcion }}@endif
@foreach($chems->sortBy('order_in_step') as $chem)
{{ $loop->iteration }}. {{ $chem->dyestuff?->name ?? '—' }} {{ number_format($chem->concentration,4) }} {{ $chem->uom==='g_l'?'g/L':'% owf' }} @if($chem->notes)— {{ $chem->notes }}@endif
@endforeach
@endforeach @elseif($viewing->items->isNotEmpty())
Químicos (sin curva asignada)
@foreach($viewing->items as $chem)
{{ $chem->dyestuff?->name ?? '—' }} {{ number_format($chem->concentration,4) }} {{ $chem->uom==='g_l'?'g/L':'% owf' }}
@endforeach @endif @if($viewing->notes)
{{ $viewing->notes }}
@endif
@endif @endif @endif {{-- ── TAB 4: ANALYSIS ─────────────────────────────── --}} @if($activeTab === 'analysis') {{-- ── Filter bar ── --}}
{{ count($checkedIds)>0?count($checkedIds).' en gráfico':'Graficando todos' }}
{{-- ── Stats cards ── --}} @if(!empty($analysisStats) && $analysisStats['n'] > 0) @php $tol = $color->customer_tolerance_de ?? 1.0; $pct = $analysisStats['pass_pct'] ?? null; $pctCol = $pct===null?'var(--text-sm)':($pct>=90?'var(--green)':($pct>=70?'var(--amber)':'var(--red)')); $deCol = isset($analysisStats['mean_de'])?($analysisStats['mean_de']<=$tol?'var(--green)':($analysisStats['mean_de']<=$tol*1.5?'var(--amber)':'var(--red)')):'var(--text-sm)'; @endphp
{{ $analysisStats['n'] }}
Mediciones
{{ $analysisStats['mean_de']!==null?number_format($analysisStats['mean_de'],3):'—' }}
ΔE Promedio
{{ $analysisStats['max_de']!==null?number_format($analysisStats['max_de'],3):'—' }}
ΔE Máximo
{{ $pct!==null?$pct.'%':'—' }}
Tasa Aprobado
{{ $analysisStats['sigma']!==null?number_format($analysisStats['sigma'],3):'—' }}
σ (Sigma)
@endif @if(empty($measurements))
Sin mediciones registradas para este color con los filtros activos.
@else {{-- ── Charts grid: scatter (left, tall) + trend/L* stacked (right) ── --}}
{{-- a*/b* scatter ── --}}
CIE a*/b* — Plano de Color (Δa* vs Δb*) @if($color->target_a !== null) Tol ΔE={{ number_format($color->customer_tolerance_de??1.0,2) }} @else Sin referencia L*a*b* @endif
● Batch ▲ Lab Trial ■ Aprobado ■ Marginal ■ Rechazado — Tolerancia   ·· Marginal
{{-- ΔE trend + L* trend stacked ── --}}
Tendencia ΔE
Tendencia L* (Luminosidad)
@if($color->target_l !== null)
— verde = L* objetivo ({{ number_format($color->target_l,2) }})
@endif
{{-- ── Formula suggestions ── --}} @if(!empty($formulaSuggestions))
⚡ Sugerencias para Ajuste de Fórmula {{ count($formulaSuggestions) }} observación{{ count($formulaSuggestions)>1?'es':'' }}
@foreach($formulaSuggestions as $tip)
@if($tip['axis']) {{ $tip['axis'] }} {{ $tip['value']>=0?'+':'' }}{{ number_format($tip['value'],2) }} @else ⚠ @endif {{ $tip['msg'] }}
@endforeach
Basado en el promedio de {{ count($measurements) }} lectura(s) seleccionadas. Confirmar ajuste en Lab Dip antes de aplicar en producción.
@endif {{-- ── Measurement table ── --}}
Mediciones Espectrofotométricas {{ count($measurements) }}
@foreach($measurements as $m) @php $de=$m['delta_e']; $tol2=$color->customer_tolerance_de??1.0; $isChk=in_array($m['key'],$checkedIds); $deCol=$de===null?'var(--gray-lt)':($de<=$tol2?'var(--green)':($de<=$tol2*1.5?'var(--amber)':'var(--red)')); $stBdg=match($m['status']){'Approved'=>'badge-green','Rejected'=>'badge-red','Marginal'=>'badge-amber','Customer_Override'=>'badge-blue',default=>'badge-gray'}; @endphp @endforeach
FuenteEtapaFecha L*a*b* ΔEEstado
{{ $m['source']==='batch'?'Batch':'Lab' }} {{ $m['label'] }} {{ $m['stage'] }} {{ $m['date'] }} {{ $m['L']!==null?number_format($m['L'],2):'—' }} {{ $m['a']!==null?number_format($m['a'],2):'—' }} {{ $m['b']!==null?number_format($m['b'],2):'—' }} {{ $de!==null?number_format($de,2):'—' }} {{ $m['status'] }}
@endif @endif @endif {{-- end $selectedColorId --}} {{-- ══════════════════════════════════════════════════════════════ MODALS ══════════════════════════════════════════════════════════════ --}} {{-- Color Modal --}} @if($showColorModal) @endif {{-- Trial Modal --}} @if($showTrialModal) @endif {{-- Recipe Modal (step-based chemicals) --}} @if($showRecipeModal) @endif {{-- Curve Modal (step builder) --}} @if($showCurveModal) @endif {{-- ══ Chart.js ══ --}} @push('scripts') @endpush