szczegóły zestawu (aggregates.show). * * Szczegół zestawu = istniejący ekran agregatu (site201det był jego duplikatem), * więc nie powielamy - kierujemy do aggregates.show?pump=X&engine=Y. */ class AggregateSelectionController extends Controller { public function __construct(private readonly PumpService $pumps) {} public function index(Request $request) { $qIn = $request->query('q'); $hIn = $request->query('h'); $q = $this->toFloat($qIn); $h = $this->toFloat($hIn); $searched = $q !== null && $q > 0; $matches = $searched ? $this->pumps->matchingAggregates($q, $h) : collect(); [$rows, $chart] = $matches->isNotEmpty() ? [$this->buildRows($matches), $this->buildChart($matches)] : [collect(), null]; return view('catalog.aggregate-selection.index', [ 'q' => $qIn, // surowe (do ponownego wyświetlenia w polu) 'h' => $hIn, 'qVal' => $q, // liczbowe (do nagłówka Q_sz) 'rows' => $rows, 'chart' => $chart, 'searched' => $searched, ]); } /** * Rozwija dopasowane pompy na wiersze pompa+silnik. Silniki pompy wg mocy * (ENG_POWER) - jak legacy. leftJoin: pompa bez silnika wciąż daje 1 wiersz. */ private function buildRows($matches) { $engines = DB::connection('softspm')->table('seg_pump_engine_rel as r') ->leftJoin('seg_engines as e', 'e.ENG_ID', '=', 'r.RPE_ENG_ID') ->whereIn('r.RPE_PUP_ID', $matches->pluck('pump.PUP_ID')->all()) ->orderBy('e.ENG_POWER') ->select('r.RPE_PUP_ID', 'e.ENG_ID', 'e.ENG_NAME', 'e.ENG_POWER', 'e.ENG_VOLTAGE') ->get() ->groupBy('RPE_PUP_ID'); $rows = collect(); $lp = 1; foreach ($matches as $m) { $pumpEngines = $engines->get($m->pump->PUP_ID) ?: collect([null]); foreach ($pumpEngines as $e) { $rows->push((object) [ 'lp' => $lp++, 'pump_id' => $m->pump->PUP_ID, 'pump_name' => $m->pump->PUP_NAME, 'engine_id' => $e->ENG_ID ?? null, 'engine_name' => $e->ENG_NAME ?? null, 'q_n' => $m->pump->PUP_Q_N, 'h_val' => $m->h_val, 'eta_val' => $m->eta_val, 'power' => $e->ENG_POWER ?? null, 'voltage' => $e->ENG_VOLTAGE ?? null, ]); } } return $rows; } /** * Dane wykresu nałożonych krzywych H (wspólne osie). xMax = najszersza * krzywa, yMax = najwyższa (zaokrąglona w górę do 10, jak legacy). */ private function buildChart($matches): ?array { $curves = $matches->filter(fn ($m) => $m->plot) ->map(fn ($m) => ['name' => $m->pump->PUP_NAME, 'plot' => $m->plot]) ->values(); if ($curves->isEmpty()) { return null; } return [ 'curves' => $curves, 'xMax' => (float) $curves->max(fn ($c) => $c['plot']['xMax']), 'yMax' => max(10.0, ceil($curves->max(fn ($c) => $c['plot']['yMax']) / 10) * 10), ]; } /** Pole tekstowe -> float (przecinek dziesiętny), puste -> null. */ private function toFloat($v): ?float { if ($v === null || trim((string) $v) === '') { return null; } return (float) str_replace(',', '.', (string) $v); } }