validate([ 'pasien_id' => 'required|exists:pasien,id' ]); $pasien = Pasien::findOrFail($request->pasien_id); $gejalaList = explode(',', strtolower($pasien->gejala ?? '')); $gejalaList = array_map('trim', $gejalaList); if (empty($gejalaList) || in_array('tidak ada keluhan', $gejalaList)) { return redirect()->back() ->with('error', 'Pasien tidak memiliki gejala gastritis.'); } $kalori_harian = $this->hitungKaloriHarian($pasien); $makanans = Makanan::query(); if (in_array('nyeri lambung', $gejalaList)) { $makanans = $makanans->where('kandungan_lemak', '<=', 7); } if (in_array('mual', $gejalaList)) { $makanans = $makanans ->where('kandungan_serat', '<=', 4) ->whereIn('tekstur', ['lunak', 'sedang']); } else { $makanans = $makanans ->whereIn('tekstur', ['lunak', 'sedang']); } $makanans = $makanans->get(); if ($makanans->isEmpty()) { return redirect()->back() ->with('error', 'Tidak ada makanan yang sesuai.'); } $hasil = $this->hitungSAW( $makanans, $gejalaList, $pasien->aktivitas_harian, $kalori_harian, $pasien->jenis_kelamin ); if (empty($hasil)) { return redirect()->back() ->with('error', 'Perhitungan SAW gagal.'); } usort($hasil, fn($a, $b) => $b['skor'] <=> $a['skor']); $terbaik = $hasil[0]; $hasil = array_slice($hasil, 0, 10); $jumlah_porsi = 1; if ($pasien->berat_badan >= 70 || $pasien->aktivitas_harian == 'Berat') { $ukuran_porsi = 'Mangkuk Sedang'; } else { $ukuran_porsi = 'Mangkuk Kecil'; } if ($pasien->aktivitas_harian == 'Berat') { $frekuensi_makan = '3x makan utama + 3x snack'; } elseif ($pasien->aktivitas_harian == 'Sedang') { $frekuensi_makan = '3x makan utama + 2-3x snack'; } else { $frekuensi_makan = '3x makan utama + 2x snack'; } $hasil_json = array_map(function ($item) use ($jumlah_porsi, $ukuran_porsi, $frekuensi_makan) { return [ 'id' => $item['makanan']->id ?? null, 'nama_makanan' => $item['nama_makanan'] ?? '-', 'tekstur' => $item['tekstur'] ?? '-', 'porsi_saji' => $item['porsi_saji'] ?? '-', 'jumlah_porsi' => $jumlah_porsi, 'ukuran_porsi' => $ukuran_porsi, 'frekuensi_makan' => $frekuensi_makan, 'cara_pengolahan' => $item['cara_pengolahan'] ?? '-', 'alternatif_serupa' => $item['alternatif_serupa'] ?? '-', 'komposisi_makanan' => $item['komposisi_makanan'] ?? '-', 'karbohidrat' => $item['karbohidrat'] ?? 0, 'lemak' => $item['lemak'] ?? 0, 'serat' => $item['serat'] ?? 0, 'kalori' => $item['kalori'] ?? 0, 'protein' => $item['protein'] ?? 0, 'skor' => round($item['skor'], 4) ]; }, $hasil); Laporan::create([ 'pasien_id' => $pasien->id, 'nama_pasien' => $pasien->nama, 'gejala' => $pasien->gejala, 'aktivitas_harian' => $pasien->aktivitas_harian, 'berat_badan' => $pasien->berat_badan, 'tinggi_badan' => $pasien->tinggi_badan, 'umur' => $pasien->umur, 'jenis_kelamin' => $pasien->jenis_kelamin, 'makanan_rekomendasi' => $terbaik['makanan']->nama_makanan, 'nilai_saw' => round($terbaik['skor'], 4), 'hasil_json' => json_encode($hasil_json), 'kebutuhan_kalori' => round($kalori_harian), 'jumlah_porsi' => $jumlah_porsi, 'ukuran_porsi' => $ukuran_porsi, 'frekuensi_makan' => $frekuensi_makan ]); return redirect() ->route('laporan.index') ->with('success', 'Rekomendasi berhasil'); } private function hitungKaloriHarian($pasien) { if ($pasien->jenis_kelamin == 'Laki-laki') { $bmr = 66 + (13.7 * $pasien->berat_badan) + (5 * $pasien->tinggi_badan) - (6.8 * $pasien->umur); } else { $bmr = 655 + (9.6 * $pasien->berat_badan) + (1.8 * $pasien->tinggi_badan) - (4.7 * $pasien->umur); } $faktor = [ 'Ringan' => 1.2, 'Sedang' => 1.55, 'Berat' => 1.9 ]; return $bmr * ($faktor[$pasien->aktivitas_harian] ?? 1.2); } private function hitungSAW($makanans, $gejalaList, $aktivitas, $kalori_harian, $jenis_kelamin) { $bobot = $this->tentukanBobot($gejalaList, $aktivitas); $max_protein = max($makanans->max('protein'), 1); $max_karbo = max($makanans->max('karbohidrat'), 1); $hasil = []; foreach ($makanans as $makanan) { $n_protein = ($makanan->protein / $max_protein) * 0.85; $n_karbo = ($makanan->karbohidrat / $max_karbo) * 0.85; if ($aktivitas == 'Berat') { $ideal_kalori = $kalori_harian * 0.12; } elseif ($aktivitas == 'Sedang') { $ideal_kalori = $kalori_harian * 0.09; } else { $ideal_kalori = $kalori_harian * 0.06; } if (in_array('mual', $gejalaList)) { $ideal_kalori *= 0.90; } $ideal_kalori = max($ideal_kalori, 1); $selisih = abs($makanan->kalori - $ideal_kalori); $n_kalori = 1 / (1 + ($selisih / $ideal_kalori)); $n_kalori *= 0.80; // ========================= // PENYESUAIAN ENERGI BERDASARKAN JENIS KELAMIN // ========================= if ($jenis_kelamin == 'Laki-laki') { if ($makanan->kalori >= ($ideal_kalori * 0.60)) { $n_kalori *= 1.10; } if ($makanan->protein >= 5) { $n_protein *= 1.08; } if ($makanan->karbohidrat >= 30) { $n_karbo *= 1.05; } } else { if ($makanan->kalori > ($ideal_kalori * 0.95)) { $n_kalori *= 0.96; } } if ($aktivitas == 'Ringan') { if ($makanan->kalori > ($ideal_kalori * 1.80)) { $n_kalori *= 0.35; $n_karbo *= 0.75; } elseif ($makanan->kalori > ($ideal_kalori * 1.35)) { $n_kalori *= 0.55; $n_karbo *= 0.85; } } if ($aktivitas == 'Sedang') { if ($makanan->kalori > ($ideal_kalori * 1.90)) { $n_kalori *= 0.60; $n_karbo *= 0.85; } } if ($aktivitas == 'Berat') { if ($makanan->kalori >= ($ideal_kalori * 0.80)) { $n_kalori *= 1.12; } if ($makanan->protein >= 5) { $n_protein *= 1.12; } if ($makanan->karbohidrat >= 30) { $n_karbo *= 1.08; } } $n_protein = min($n_protein, 1); $n_karbo = min($n_karbo, 1); $n_kalori = min($n_kalori, 1); if ($makanan->kandungan_lemak <= 2) { $n_lemak = 0.90; } elseif ($makanan->kandungan_lemak <= 4) { $n_lemak = 0.78; } elseif ($makanan->kandungan_lemak <= 6) { $n_lemak = 0.60; } else { $n_lemak = 0.40; } if ($jenis_kelamin != 'Laki-laki' && $makanan->kandungan_lemak > 4) { $n_lemak *= 0.92; } if ($makanan->kandungan_serat <= 1) { $n_serat = 0.90; } elseif ($makanan->kandungan_serat <= 2) { $n_serat = 0.78; } elseif ($makanan->kandungan_serat <= 4) { $n_serat = 0.60; } else { $n_serat = 0.40; } $n_tekstur = match (strtolower($makanan->tekstur)) { 'lunak' => 0.90, 'sedang' => 0.70, default => 0.40 }; if (in_array('mual', $gejalaList)) { if ($makanan->kandungan_lemak > 5) { $n_lemak *= 0.70; } if ($makanan->kandungan_serat > 2) { $n_serat *= 0.75; } if (strtolower($makanan->tekstur) != 'lunak') { $n_tekstur *= 0.85; } } if (in_array('nyeri lambung', $gejalaList)) { if ($makanan->kandungan_serat > 3) { $n_serat *= 0.60; } if ($makanan->kandungan_lemak > 5) { $n_lemak *= 0.75; } } $skor = ($n_protein * $bobot['protein']) + ($n_lemak * $bobot['lemak']) + ($n_karbo * $bobot['karbohidrat']) + ($n_serat * $bobot['serat']) + ($n_kalori * $bobot['kalori']) + ($n_tekstur * $bobot['tekstur']); $faktorAktivitasSkor = match ($aktivitas) { 'Ringan' => 0.92, 'Sedang' => 1.00, 'Berat' => 1.10, default => 1.00 }; $skor = $skor * $faktorAktivitasSkor; // ========================= // PENYESUAIAN SKOR AKHIR BERDASARKAN KEBUTUHAN ENERGI // ========================= if ($jenis_kelamin == 'Laki-laki') { $skor *= match ($aktivitas) { 'Ringan' => 1.02, 'Sedang' => 1.03, 'Berat' => 1.04, default => 1.02 }; } else { $skor *= 0.98; } $skor = min($skor, 1); $hasil[] = [ 'makanan' => $makanan, 'nama_makanan' => $makanan->nama_makanan, 'protein' => $makanan->protein, 'lemak' => $makanan->kandungan_lemak, 'karbohidrat' => $makanan->karbohidrat, 'serat' => $makanan->kandungan_serat, 'kalori' => $makanan->kalori, 'tekstur' => $makanan->tekstur, 'porsi_saji' => $makanan->porsi_saji, 'cara_pengolahan' => $makanan->cara_pengolahan, 'alternatif_serupa' => $makanan->alternatif_serupa, 'komposisi_makanan' => $makanan->komposisi_makanan, 'skor' => round($skor, 4) ]; } return $hasil; } private function tentukanBobot($gejalaList, $aktivitas) { if (in_array('mual', $gejalaList)) { if ($aktivitas == 'Berat') { return [ 'tekstur' => 0.18, 'serat' => 0.14, 'lemak' => 0.17, 'karbohidrat' => 0.21, 'protein' => 0.13, 'kalori' => 0.17 ]; } if ($aktivitas == 'Sedang') { return [ 'tekstur' => 0.25, 'serat' => 0.16, 'lemak' => 0.18, 'karbohidrat' => 0.18, 'protein' => 0.10, 'kalori' => 0.13 ]; } return [ 'tekstur' => 0.45, 'serat' => 0.22, 'lemak' => 0.18, 'karbohidrat' => 0.07, 'protein' => 0.05, 'kalori' => 0.03 ]; } if ($aktivitas == 'Berat') { return [ 'lemak' => 0.20, 'tekstur' => 0.16, 'serat' => 0.10, 'protein' => 0.16, 'karbohidrat' => 0.18, 'kalori' => 0.20 ]; } if ($aktivitas == 'Sedang') { return [ 'lemak' => 0.30, 'tekstur' => 0.24, 'serat' => 0.14, 'protein' => 0.12, 'karbohidrat' => 0.12, 'kalori' => 0.08 ]; } return [ 'lemak' => 0.36, 'tekstur' => 0.27, 'serat' => 0.16, 'protein' => 0.09, 'karbohidrat' => 0.07, 'kalori' => 0.05 ]; } }