From b8a94e45084ed941db3441596b5d75aa2cc31944 Mon Sep 17 00:00:00 2001 From: Dwi Swandhana Date: Sat, 21 Feb 2026 06:26:45 +0700 Subject: [PATCH] update --- .../Controllers/BiorepositoryController.php | 32 +++--- .../views/admin/biorepository.blade.php | 104 ++++++++++-------- 2 files changed, 77 insertions(+), 59 deletions(-) diff --git a/htdocs/app/Http/Controllers/BiorepositoryController.php b/htdocs/app/Http/Controllers/BiorepositoryController.php index 09b3e81c..da1fdde2 100644 --- a/htdocs/app/Http/Controllers/BiorepositoryController.php +++ b/htdocs/app/Http/Controllers/BiorepositoryController.php @@ -30,7 +30,7 @@ class BiorepositoryController extends Controller $data['cabinets'] = BioCabinet::with([ 'racks' => function ($query) { - $query->orderBy('level', 'ASC')->orderBy('rack_number', 'ASC'); + $query->orderBy('rack_number', 'ASC')->orderBy('code', 'ASC'); }, 'racks.specimens' => function ($query) { $query->orderBy('stored_at', 'ASC'); @@ -79,10 +79,8 @@ class BiorepositoryController extends Controller 'cabinet_id' => 'required|exists:bio_cabinets,id', 'code' => 'required|max:50', 'name' => 'required|max:150', - 'level' => 'required|integer|min:1', - 'rack_number' => 'required|integer|min:1', - 'box_number' => 'required|integer|min:1', - 'capacity' => 'required|integer|min:1', + 'level' => 'required|integer|min:4|max:6', + 'capacity' => 'required|integer|min:16|max:20', 'notes' => 'nullable', ]); @@ -98,13 +96,15 @@ class BiorepositoryController extends Controller return back()->withErrors(['code' => 'Kode rack sudah dipakai pada lemari ini.'])->withInput(); } + $nextRackNumber = ((int) BioRack::where('cabinet_id', $request->input('cabinet_id'))->max('rack_number')) + 1; + BioRack::create([ 'cabinet_id' => $request->input('cabinet_id'), 'code' => $request->input('code'), 'name' => $request->input('name'), 'level' => $request->input('level'), - 'rack_number' => $request->input('rack_number'), - 'box_number' => $request->input('box_number'), + 'rack_number' => $nextRackNumber, + 'box_number' => 1, 'capacity' => $request->input('capacity'), 'notes' => $request->input('notes'), ]); @@ -135,22 +135,26 @@ class BiorepositoryController extends Controller $expectedRackNo = $rack->rack_number ?: $rack->id; $expectedBoxNo = $rack->box_number ?: 1; - if ((int) $request->input('shelfnomor') !== (int) $rack->level || - (int) $request->input('raknomor') !== (int) $expectedRackNo || + if ((int) $request->input('raknomor') !== (int) $expectedRackNo || (int) $request->input('boxnomor') !== (int) $expectedBoxNo) { return back()->withErrors(['slotnomor' => 'Posisi slot tidak sesuai dengan konfigurasi rack.'])->withInput(); } - if ((int) $request->input('slotnomor') > (int) $rack->capacity) { - return back()->withErrors(['slotnomor' => 'Slot melebihi kapasitas rack.'])->withInput(); + if ((int) $request->input('shelfnomor') < 1 || (int) $request->input('shelfnomor') > (int) $rack->level) { + return back()->withErrors(['shelfnomor' => 'Shelf melebihi konfigurasi rack.'])->withInput(); + } + + if ((int) $request->input('tubenomor') < 1 || (int) $request->input('tubenomor') > (int) $rack->capacity) { + return back()->withErrors(['tubenomor' => 'Nomor tube melebihi kapasitas box pada shelf ini.'])->withInput(); } $slotTaken = BioSpecimen::where('rack_id', $rack->id) - ->where('slot_number', $request->input('slotnomor')) + ->where('shelf_number', $request->input('shelfnomor')) + ->where('tube_number', $request->input('tubenomor')) ->exists(); if ($slotTaken) { - return back()->withErrors(['slotnomor' => 'Slot ini sudah terisi spesimen.'])->withInput(); + return back()->withErrors(['tubenomor' => 'Posisi tube pada shelf ini sudah terisi spesimen.'])->withInput(); } $atccByUser = strtoupper(preg_replace('/[^A-Za-z0-9]/', '', Session::get('nama', 'UNKNOWN'))); @@ -182,7 +186,7 @@ class BiorepositoryController extends Controller 'category_storage' => $request->input('kategorisimpan'), 'shelf_number' => $request->input('shelfnomor'), 'rack_number' => $request->input('raknomor'), - 'slot_number' => $request->input('slotnomor'), + 'slot_number' => $request->input('shelfnomor'), 'box_number' => $request->input('boxnomor'), 'tube_number' => $request->input('tubenomor'), 'bacteria_name' => $request->input('nmbakteri'), diff --git a/htdocs/resources/views/admin/biorepository.blade.php b/htdocs/resources/views/admin/biorepository.blade.php index 8d7bbcd1..c720787c 100644 --- a/htdocs/resources/views/admin/biorepository.blade.php +++ b/htdocs/resources/views/admin/biorepository.blade.php @@ -34,6 +34,19 @@ gap: 6px; margin-top: 10px; } + .shelf-section { + border: 1px dashed #bfd3e8; + border-radius: 8px; + padding: 8px; + margin-top: 8px; + background: #fbfdff; + } + .tube-grid { + display: grid; + grid-template-columns: repeat(10, minmax(24px, 1fr)); + gap: 5px; + margin-top: 8px; + } .slot-btn { border: 1px solid #bfd3e8; background: #f4f9ff; @@ -150,8 +163,8 @@
Belum ada data spesimen.
@endif -

Visualisasi Lemari, Rack, dan Slot

-

Klik slot berwarna biru untuk mengisi spesimen. Slot merah artinya sudah terisi.

+

Visualisasi Lemari, Rack, Shelf, Box, dan Tube

+

Klik nomor tube berwarna biru untuk mengisi spesimen. Tube merah artinya sudah terisi.

@forelse($cabinets as $cabinet)
@@ -159,39 +172,47 @@
@forelse($cabinet->racks as $rack) @php - $slotMap = []; + $tubeMap = []; foreach ($rack->specimens as $item) { - if ($item->slot_number) { - $slotMap[$item->slot_number] = $item; + if ($item->shelf_number && $item->tube_number) { + $tubeMap[$item->shelf_number.'-'.$item->tube_number] = $item; } } - $capacity = (int) $rack->capacity; + $shelfCount = (int) $rack->level; + $tubeCapacity = (int) $rack->capacity; @endphp
{{ $rack->code }} - {{ $rack->name }}
-
Shelf {{ $rack->level }} | Rack {{ $rack->rack_number ?? $rack->id }} | Box {{ $rack->box_number ?? 1 }}
-
Slot: {{ $capacity }} | Terisi: {{ $rack->specimens->count() }}
+
Rack No {{ $rack->rack_number ?? $rack->id }} | Total Shelf {{ $shelfCount }} | 1 Box per Shelf | Tube per Box {{ $tubeCapacity }}
+
Terisi: {{ $rack->specimens->count() }}
- @if($capacity > 0) -
- @for($i = 1; $i <= $capacity; $i++) - @if(isset($slotMap[$i])) -
{{ $i }}
- @else - - @endif - @endfor -
+ @if($shelfCount > 0 && $tubeCapacity > 0) + @for($shelf = 1; $shelf <= $shelfCount; $shelf++) +
+
Shelf {{ $shelf }} - Box 1 (Tube 1-{{ $tubeCapacity }})
+
+ @for($tube = 1; $tube <= $tubeCapacity; $tube++) + @php $tubeKey = $shelf.'-'.$tube; @endphp + @if(isset($tubeMap[$tubeKey])) +
{{ $tube }}
+ @else + + @endif + @endfor +
+
+ @endfor @else -
Kapasitas slot belum diatur.
+
Konfigurasi rack belum lengkap.
@endif
@empty @@ -343,23 +364,16 @@
-
- - +
+ +
-
- - -
-
- - -
-
- - +
+ +
+ Rack number dibuat otomatis oleh sistem. Struktur: 1 rack memiliki 4-6 shelf, setiap shelf memiliki 1 box, setiap box 16-20 tube.
- +
- +
- +
@@ -474,7 +488,7 @@ $('#raknomor').val($(this).data('rackno')); $('#slotnomor').val($(this).data('slot')); $('#boxnomor').val($(this).data('box')); - $('#tubenomor').val(''); + $('#tubenomor').val($(this).data('tube')); buildSampleCodePreview(); $('#modalIsiSlot').modal('show'); });