perubahan besar-besaran
This commit is contained in:
parent
6c2629aad5
commit
e8c1e4bbad
|
@ -43,11 +43,15 @@ public function admindash()
|
|||
|
||||
// USER
|
||||
public function datauser(){
|
||||
$users = User::with('role')->get(); // Eager load the role relationship
|
||||
$users = User::whereHas('role', function ($query) {
|
||||
$query->where('name', 'user');
|
||||
})->with('role')->get();
|
||||
|
||||
return view('admin.datauser.datauser', compact('users'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function edituser(User $user){
|
||||
// Ambil semua role dari tabel roles
|
||||
$roles = Role::pluck('name', 'id'); // Mengambil nama dan id role
|
||||
|
|
|
@ -12,6 +12,15 @@
|
|||
use App\Models\JenisMakanan;
|
||||
use App\Http\Requests\JenisMakananRequest;
|
||||
use App\Http\Requests\UpdateJenisMakananRequest;
|
||||
use App\Models\Komponen;
|
||||
// use App\Http\Requests\JenisMakananRequest;
|
||||
// use App\Http\Requests\UpdateJenisMakananRequest;
|
||||
use App\Models\WaktuMakan;
|
||||
// use App\Http\Requests\JenisMakananRequest;
|
||||
// use App\Http\Requests\UpdateJenisMakananRequest;
|
||||
use App\Models\MakananKomponenWaktu;
|
||||
// use App\Http\Requests\JenisMakananRequest;
|
||||
// use App\Http\Requests\UpdateJenisMakananRequest;
|
||||
|
||||
class MakananController extends Controller
|
||||
{
|
||||
|
@ -96,8 +105,6 @@ public function deletemakanan(Makanan $makanan) {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
public function kategori(){
|
||||
$kategoris = Kategori::all();
|
||||
return view('admin.kategori.kategori', compact('kategoris'));
|
||||
|
@ -127,11 +134,6 @@ public function deletekategori(Kategori $kategori) {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public function jenismakanan()
|
||||
{
|
||||
$jenis_makanans = JenisMakanan::all();
|
||||
|
@ -167,4 +169,162 @@ public function deletejenismakanan(JenisMakanan $jenis)
|
|||
$jenis->delete();
|
||||
return redirect()->route('jenismakanan')->with('success', 'Jenis makanan berhasil dihapus');
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function komponen(){
|
||||
$komponens = Komponen::all();
|
||||
return view('admin.komponen.komponen', compact('komponens'));
|
||||
}
|
||||
public function editkomponen(Komponen $komponen){
|
||||
return view('admin.komponen.editkomponen', compact('komponen'));
|
||||
}
|
||||
public function tambahkomponen(){
|
||||
return view('admin.komponen.tambahkomponen');
|
||||
}
|
||||
// public function storekomponen(KategoriRequest $request){
|
||||
// $validatedData = $request->validated();
|
||||
// Kategori::create($validatedData);
|
||||
// return redirect()->route('kategori');
|
||||
// }
|
||||
// public function updatekategori(UpdateKategoriRequest $request, Kategori $kategori)
|
||||
// {
|
||||
// $validatedData = $request->validated();
|
||||
// $kategori->update($validatedData);
|
||||
// return redirect()->route('kategori');
|
||||
// }
|
||||
|
||||
public function deletekomponen(Komponen $komponen) {
|
||||
$komponen->delete();
|
||||
return redirect()->route('komponen')->with('success', 'user deleted successfully');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public function waktumakan(){
|
||||
$waktu_makans = WaktuMakan::all();
|
||||
return view('admin.waktumakan.waktumakan', compact('waktu_makans'));
|
||||
}
|
||||
public function editwaktumakan(WaktuMakan $waktumakan){
|
||||
return view('admin.waktumakan.editwaktumakan', compact('waktumakan'));
|
||||
}
|
||||
public function tambahwaktumakan(){
|
||||
return view('admin.waktumakan.tambahwaktumakan');
|
||||
}
|
||||
// public function storekomponen(KategoriRequest $request){
|
||||
// $validatedData = $request->validated();
|
||||
// Kategori::create($validatedData);
|
||||
// return redirect()->route('kategori');
|
||||
// }
|
||||
// public function updatekategori(UpdateKategoriRequest $request, Kategori $kategori)
|
||||
// {
|
||||
// $validatedData = $request->validated();
|
||||
// $kategori->update($validatedData);
|
||||
// return redirect()->route('kategori');
|
||||
// }
|
||||
|
||||
public function deletewaktumakan(WaktuMakan $waktumakan) {
|
||||
$waktumakan->delete();
|
||||
return redirect()->route('waktumakan')->with('success', 'user deleted successfully');
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$query = MakananKomponenWaktu::with(['makanan', 'komponen', 'waktuMakan']);
|
||||
|
||||
if ($request->komponen_id) {
|
||||
$query->where('komponen_id', $request->komponen_id);
|
||||
}
|
||||
|
||||
if ($request->waktu_makan_id) {
|
||||
$query->where('waktu_makan_id', $request->waktu_makan_id);
|
||||
}
|
||||
|
||||
$relasis = $query->get();
|
||||
$makanans = Makanan::all();
|
||||
$komponens = Komponen::all();
|
||||
$waktuMakans = WaktuMakan::all();
|
||||
|
||||
return view('admin.relasi.relasi', compact('relasis', 'makanans', 'komponens', 'waktuMakans'));
|
||||
}
|
||||
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'makanan_id' => 'required|exists:makanans,id',
|
||||
'komponen_id' => 'required|exists:komponens,id',
|
||||
'waktu_makan_id' => 'required|exists:waktu_makans,id',
|
||||
]);
|
||||
|
||||
// Cegah duplikasi
|
||||
$exists = MakananKomponenWaktu::where([
|
||||
'makanan_id' => $request->makanan_id,
|
||||
'komponen_id' => $request->komponen_id,
|
||||
'waktu_makan_id' => $request->waktu_makan_id
|
||||
])->exists();
|
||||
|
||||
if (!$exists) {
|
||||
MakananKomponenWaktu::create($request->only(['makanan_id', 'komponen_id', 'waktu_makan_id']));
|
||||
return redirect()->back()->with('success', 'Relasi berhasil ditambahkan.');
|
||||
} else {
|
||||
return redirect()->back()->with('error', 'Relasi sudah ada.');
|
||||
}
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$relasi = MakananKomponenWaktu::findOrFail($id);
|
||||
$makanans = Makanan::all();
|
||||
$komponens = Komponen::all();
|
||||
$waktuMakans = WaktuMakan::all();
|
||||
|
||||
return view('admin.relasi.edit', compact('relasi', 'makanans', 'komponens', 'waktuMakans'));
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$request->validate([
|
||||
'makanan_id' => 'required|exists:makanans,id',
|
||||
'komponen_id' => 'required|exists:komponens,id',
|
||||
'waktu_makan_id' => 'required|exists:waktu_makans,id',
|
||||
]);
|
||||
|
||||
$relasi = MakananKomponenWaktu::findOrFail($id);
|
||||
|
||||
// Cek apakah ada duplikasi selain record yang sedang diupdate
|
||||
$exists = MakananKomponenWaktu::where('id', '!=', $id)
|
||||
->where('makanan_id', $request->makanan_id)
|
||||
->where('komponen_id', $request->komponen_id)
|
||||
->where('waktu_makan_id', $request->waktu_makan_id)
|
||||
->exists();
|
||||
|
||||
if ($exists) {
|
||||
return redirect()->back()->with('error', 'Relasi sudah ada.');
|
||||
}
|
||||
|
||||
$relasi->update([
|
||||
'makanan_id' => $request->makanan_id,
|
||||
'komponen_id' => $request->komponen_id,
|
||||
'waktu_makan_id' => $request->waktu_makan_id,
|
||||
]);
|
||||
|
||||
return redirect()->route('relasi')->with('success', 'Relasi berhasil diperbarui.');
|
||||
}
|
||||
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
$relasi = MakananKomponenWaktu::findOrFail($id);
|
||||
$relasi->delete();
|
||||
|
||||
return redirect()->back()->with('success', 'Relasi berhasil dihapus.');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\WaktuMakan;
|
||||
use App\Models\Komponen;
|
||||
use App\Models\Makanan;
|
||||
use App\Models\PengecualianMakanan;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class PengecualianController extends Controller
|
||||
{
|
||||
//
|
||||
public function form()
|
||||
{
|
||||
$waktuMakans = WaktuMakan::all();
|
||||
$komponens = Komponen::all();
|
||||
$makanans = Makanan::all(); // Atau filter berdasarkan waktu & komponen tertentu
|
||||
|
||||
return view('pengecualian.form', compact('waktuMakans', 'komponens', 'makanans'));
|
||||
}
|
||||
|
||||
public function simpan(Request $request)
|
||||
{
|
||||
foreach ($request->pengecualian as $makananId) {
|
||||
PengecualianMakanan::updateOrCreate([
|
||||
'user_id' => Auth::id(),
|
||||
'makanan_id' => $makananId,
|
||||
'waktu_makan_id' => $request->waktu_makan_id,
|
||||
'komponen_id' => $request->komponen_id,
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()->route('pengecualian.form')->with('success', 'Pengecualian berhasil disimpan!');
|
||||
}
|
||||
|
||||
}
|
|
@ -27,7 +27,6 @@ public function prosesSementara(Request $request)
|
|||
$kriterias = Kriteria::all();
|
||||
$nilai = [];
|
||||
|
||||
// Hapus data lama (opsional, jika ingin reset)
|
||||
foreach ($kriterias as $baris) {
|
||||
foreach ($kriterias as $kolom) {
|
||||
if ($baris->id != $kolom->id) {
|
||||
|
@ -39,7 +38,6 @@ public function prosesSementara(Request $request)
|
|||
}
|
||||
}
|
||||
|
||||
// Membuat matriks perbandingan dan menyimpannya ke session dan DB
|
||||
foreach ($kriterias as $baris) {
|
||||
foreach ($kriterias as $kolom) {
|
||||
if ($baris->id == $kolom->id) {
|
||||
|
@ -87,7 +85,6 @@ public function hasilNormalisasi()
|
|||
return redirect()->route('perbandingan')->with('error', 'Data perbandingan belum tersedia.');
|
||||
}
|
||||
|
||||
// Hitung jumlah per kolom
|
||||
$jumlahKolom = [];
|
||||
foreach ($kriterias as $kriteria) {
|
||||
$id = $kriteria->id;
|
||||
|
@ -97,7 +94,6 @@ public function hasilNormalisasi()
|
|||
}
|
||||
}
|
||||
|
||||
// Normalisasi
|
||||
$normalisasi = [];
|
||||
foreach ($kriterias as $baris) {
|
||||
$row = [];
|
||||
|
@ -107,13 +103,11 @@ public function hasilNormalisasi()
|
|||
$normalisasi[] = $row;
|
||||
}
|
||||
|
||||
// Hitung bobot
|
||||
$bobot = [];
|
||||
foreach ($normalisasi as $baris) {
|
||||
$bobot[] = array_sum($baris) / count($baris);
|
||||
}
|
||||
|
||||
// Simpan bobot ke database dan session
|
||||
foreach ($bobot as $index => $value) {
|
||||
BobotKriteria::updateOrCreate(
|
||||
['kriteria_id' => $kriterias[$index]->id],
|
||||
|
@ -129,17 +123,4 @@ public function hasilNormalisasi()
|
|||
'bobot' => $bobot
|
||||
]);
|
||||
}
|
||||
|
||||
public function perbandinganAlternatif()
|
||||
{
|
||||
$kriterias = Kriteria::all();
|
||||
$alternatifs = Makanan::all();
|
||||
$bobot = Session::get('bobot_kriteria');
|
||||
|
||||
if (!$bobot) {
|
||||
return redirect()->route('hasil.normalisasi')->with('error', 'Bobot kriteria belum tersedia.');
|
||||
}
|
||||
|
||||
return view('admin.alternatif.perbandingan', compact('kriterias', 'alternatifs', 'bobot'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,105 +8,131 @@
|
|||
use App\Models\BobotKriteria;
|
||||
use App\Models\SkorMakanan;
|
||||
use App\Models\Rekomendasi;
|
||||
use Illuminate\Support\Facades\Auth; // pastikan ini ada di atas
|
||||
use App\Models\WaktuMakan;
|
||||
use App\Models\Komponen;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class RekomendasiController extends Controller
|
||||
{
|
||||
//
|
||||
public function hitungDanSimpan()
|
||||
public function hitungDanSimpanOtomatis()
|
||||
{
|
||||
$idAlternatif = session('alternatifs_dipilih');
|
||||
|
||||
if (!$idAlternatif || count($idAlternatif) < 2) {
|
||||
return redirect()->route('alternatif.pilih')->with('error', 'Alternatif belum dipilih atau kurang dari dua.');
|
||||
}
|
||||
|
||||
$alternatifs = Makanan::whereIn('id', $idAlternatif)->get();
|
||||
$kriterias = Kriteria::all();
|
||||
$bobotKriterias = BobotKriteria::pluck('bobot', 'kriteria_id');
|
||||
$defaultBobots = BobotKriteria::pluck('bobot', 'kriteria_id');
|
||||
$waktuMakans = WaktuMakan::all();
|
||||
$komponens = Komponen::all();
|
||||
|
||||
foreach ($alternatifs as $alternatif) {
|
||||
$nilaiAkhir = 0;
|
||||
SkorMakanan::truncate();
|
||||
Rekomendasi::where('user_id', Auth::id())->delete();
|
||||
|
||||
foreach ($waktuMakans as $waktu) {
|
||||
// Ambil preferensi bobot kriteria untuk waktu makan ini
|
||||
$preferensiBobot = \App\Models\PreferensiWaktuKriteria::where('waktu_makan_id', $waktu->id)
|
||||
->pluck('bobot', 'kriteria_id');
|
||||
|
||||
foreach ($komponens as $komponen) {
|
||||
$makanans = Makanan::whereHas('komponenWaktu', function ($query) use ($komponen, $waktu) {
|
||||
$query->where('komponen_id', $komponen->id)
|
||||
->where('waktu_makan_id', $waktu->id);
|
||||
})->get();
|
||||
|
||||
if ($makanans->isEmpty()) continue;
|
||||
|
||||
$total = [
|
||||
'lemak' => $makanans->sum('lemak') ?: 1,
|
||||
'natrium' => $makanans->sum('natrium') ?: 1,
|
||||
'energi' => $makanans->sum('energi') ?: 1,
|
||||
'karbohidrat' => $makanans->sum('karbohidrat') ?: 1,
|
||||
];
|
||||
|
||||
foreach ($makanans as $makanan) {
|
||||
$skor = 0;
|
||||
|
||||
foreach ($kriterias as $kriteria) {
|
||||
$bobotKriteria = $bobotKriterias[$kriteria->id] ?? 0;
|
||||
$bobotAlternatif = SkorMakanan::where('kriteria_id', $kriteria->id)
|
||||
->where('makanan_id', $alternatif->id)
|
||||
->value('nilai') ?? 0;
|
||||
$attr = strtolower($kriteria->nama);
|
||||
$nilai = $makanan->$attr ?? 0;
|
||||
|
||||
$nilaiAkhir += $bobotKriteria * $bobotAlternatif;
|
||||
}
|
||||
// Normalisasi
|
||||
$normalized = in_array($attr, ['lemak', 'natrium'])
|
||||
? 1 - ($nilai / $total[$attr])
|
||||
: $nilai / $total[$attr];
|
||||
|
||||
Rekomendasi::updateOrCreate(
|
||||
['makanan_id' => $alternatif->id, 'user_id' => Auth::id()],
|
||||
[
|
||||
'nilai_akhir' => $nilaiAkhir,
|
||||
'tanggal_rekomendasi' => now()->toDateString()
|
||||
]
|
||||
);
|
||||
}
|
||||
// Gunakan preferensi waktu jika ada, jika tidak fallback
|
||||
$bobot = $preferensiBobot[$kriteria->id] ?? $defaultBobots[$kriteria->id] ?? 0;
|
||||
|
||||
return redirect()->route('rekomendasi.hasil')->with('success', 'Rekomendasi berhasil dihitung dan disimpan.');
|
||||
}
|
||||
$skor += $normalized * $bobot;
|
||||
|
||||
|
||||
// 2. Tampilkan hasil rekomendasi
|
||||
public function tampil()
|
||||
{
|
||||
// 1. Ambil & kelompokkan data
|
||||
$rekomendasiByDate = Rekomendasi::with('makanan')
|
||||
->where('nilai_akhir', '>', 0)
|
||||
->orderByDesc('tanggal_rekomendasi') // terbaru di depan carousel
|
||||
->orderByDesc('nilai_akhir') // ranking per tanggal
|
||||
->get()
|
||||
->groupBy('tanggal_rekomendasi'); // hasil: Collection keyed by yyyy-mm-dd
|
||||
|
||||
// 2. Daftar tanggal unik untuk dropdown hapus
|
||||
$tanggalList = $rekomendasiByDate->keys(); // Collection of dates
|
||||
|
||||
// 3. Kirim ke view
|
||||
return view('admin.rekomendasi', [
|
||||
'rekomendasiByDate' => $rekomendasiByDate,
|
||||
'tanggalList' => $tanggalList,
|
||||
SkorMakanan::updateOrCreate([
|
||||
'kriteria_id' => $kriteria->id,
|
||||
'makanan_id' => $makanan->id,
|
||||
], [
|
||||
'nilai' => $normalized
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function kirimKeUser($userId)
|
||||
{
|
||||
$adminId = Auth::id();
|
||||
|
||||
$dataAdmin = Rekomendasi::where('user_id', $adminId)->get();
|
||||
|
||||
foreach ($dataAdmin as $item) {
|
||||
// Simpan nilai akhir ke rekomendasi
|
||||
Rekomendasi::updateOrCreate(
|
||||
['user_id' => $userId, 'makanan_id' => $item->makanan_id],
|
||||
[
|
||||
'nilai_akhir' => $item->nilai_akhir,
|
||||
'user_id' => Auth::id(),
|
||||
'makanan_id' => $makanan->id,
|
||||
'komponen_id' => $komponen->id,
|
||||
'waktu_makan_id' => $waktu->id,
|
||||
],
|
||||
[
|
||||
'nilai_akhir' => $skor,
|
||||
'tanggal_rekomendasi' => now(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return redirect()->back()->with('success', 'Hasil rekomendasi berhasil dikirim ke user.');
|
||||
}
|
||||
|
||||
public function hapusSemua(Request $request)
|
||||
{
|
||||
$tanggal = $request->input('tanggal_rekomendasi');
|
||||
|
||||
if (!$tanggal) {
|
||||
return redirect()->back()->with('error', 'Tanggal rekomendasi harus dipilih.');
|
||||
}
|
||||
}
|
||||
|
||||
// Hapus data berdasarkan tanggal_rekomendasi
|
||||
Rekomendasi::where('tanggal_rekomendasi', $tanggal)->delete();
|
||||
|
||||
return redirect()->back()->with('success', 'Data rekomendasi untuk tanggal ' . $tanggal . ' berhasil dihapus.');
|
||||
return redirect()->route('rekomendasi.hasil')->with('success', 'Rekomendasi berhasil dihitung dengan bobot preferensi waktu.');
|
||||
}
|
||||
|
||||
|
||||
public function tampilHasil()
|
||||
{
|
||||
$rekomendasi = Rekomendasi::with('makanan', 'komponen', 'waktuMakan')
|
||||
->where('user_id', Auth::id())
|
||||
// ->whereDate('tanggal_rekomendasi', now())
|
||||
->get();
|
||||
|
||||
// Urutan komponen manual
|
||||
$urutanKomponen = ['karbohidrat', 'protein', 'sayur', 'buah', 'susu'];
|
||||
|
||||
// Hitung total nilai_akhir per waktu & komponen
|
||||
$totalPerGroup = [];
|
||||
foreach ($rekomendasi as $r) {
|
||||
$waktu = strtolower($r->waktuMakan->nama);
|
||||
$komponen = strtolower($r->komponen->nama);
|
||||
$totalPerGroup[$waktu][$komponen] = ($totalPerGroup[$waktu][$komponen] ?? 0) + $r->nilai_akhir;
|
||||
}
|
||||
|
||||
// Group dan sort data
|
||||
$rekomendasiGrouped = $rekomendasi
|
||||
->groupBy([
|
||||
fn($item) => strtolower($item->waktuMakan->nama),
|
||||
fn($item) => strtolower($item->komponen->nama),
|
||||
]);
|
||||
|
||||
foreach ($rekomendasiGrouped as $waktu => $komponens) {
|
||||
$sorted = collect();
|
||||
foreach ($urutanKomponen as $target) {
|
||||
if ($komponens->has($target)) {
|
||||
// Tambahkan properti persentase ke setiap item
|
||||
$komponens[$target]->each(function ($item) use ($totalPerGroup, $waktu, $target) {
|
||||
$total = $totalPerGroup[$waktu][$target] ?: 1;
|
||||
$item->persentase = ($item->nilai_akhir / $total) * 100;
|
||||
});
|
||||
|
||||
$sorted[$target] = $komponens[$target]->sortByDesc('nilai_akhir');
|
||||
}
|
||||
}
|
||||
$rekomendasiGrouped[$waktu] = $sorted;
|
||||
}
|
||||
|
||||
return view('admin.rekomendasi', ['rekomendasi' => $rekomendasiGrouped]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
use App\Models\Makanan; // pastikan model di-import
|
||||
use App\Models\JenisMakanan;
|
||||
use App\Models\Kategori;
|
||||
use App\Models\RekomendasiAhli;
|
||||
use App\Models\WaktuMakan;
|
||||
use Illuminate\Support\Facades\Auth; // pastikan ini ada di atas
|
||||
|
||||
class UserController extends Controller
|
||||
|
@ -86,32 +88,34 @@ public function userdata(Request $request)
|
|||
|
||||
|
||||
|
||||
public function userresult(Request $request)
|
||||
public function userresult()
|
||||
{
|
||||
$tanggal = $request->input('tanggal');
|
||||
$rekomendasi = \App\Models\RekomendasiAhli::with('komponen', 'waktuMakan')
|
||||
->get()
|
||||
->groupBy([
|
||||
fn($item) => $item->waktu_makan_id,
|
||||
fn($item) => strtolower($item->komponen->nama),
|
||||
]);
|
||||
|
||||
$rekomendasi = Rekomendasi::with('makanan')
|
||||
->when($tanggal, function ($query) use ($tanggal) {
|
||||
$query->whereDate('tanggal_rekomendasi', $tanggal);
|
||||
})
|
||||
$waktuMakans = \App\Models\WaktuMakan::all()->keyBy('id');
|
||||
|
||||
// Ambil alternatif dari tabel rekomendasis
|
||||
$alternatifGrouped = \App\Models\Rekomendasi::with('makanan')
|
||||
->where('nilai_akhir', '>', 0)
|
||||
->orderByDesc('nilai_akhir')
|
||||
->get();
|
||||
->get()
|
||||
->groupBy(fn($item) => $item->waktu_makan_id . '-' . $item->komponen_id);
|
||||
|
||||
$totalNilaiAkhir = $rekomendasi->sum('nilai_akhir');
|
||||
|
||||
// Ambil daftar tanggal unik dari database
|
||||
$listTanggal = Rekomendasi::select('tanggal_rekomendasi')
|
||||
->distinct()
|
||||
->orderBy('tanggal_rekomendasi', 'desc')
|
||||
->pluck('tanggal_rekomendasi');
|
||||
|
||||
return view('user.userresult', compact('rekomendasi', 'totalNilaiAkhir', 'tanggal', 'listTanggal'));
|
||||
return view('user.userresult', compact('rekomendasi', 'waktuMakans', 'alternatifGrouped'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
// ambil data berdasarkan $id atau bisa juga switch/case
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Komponen extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = ['nama'];
|
||||
|
||||
public function makananKomponenWaktu()
|
||||
{
|
||||
return $this->hasMany(MakananKomponenWaktu::class);
|
||||
}
|
||||
|
||||
public function makanans()
|
||||
{
|
||||
return $this->belongsToMany(Makanan::class, 'makanan_komponen_waktu')
|
||||
->withPivot('waktu_makan_id')
|
||||
->withTimestamps();
|
||||
}
|
||||
}
|
|
@ -43,4 +43,25 @@ public function rekomendasi()
|
|||
{
|
||||
return $this->hasMany(Rekomendasi::class);
|
||||
}
|
||||
|
||||
public function komponenWaktu()
|
||||
{
|
||||
return $this->hasMany(MakananKomponenWaktu::class);
|
||||
}
|
||||
|
||||
public function komponens()
|
||||
{
|
||||
return $this->belongsToMany(Komponen::class, 'makanan_komponen_waktu')
|
||||
->withPivot('waktu_makan_id')
|
||||
->withTimestamps();
|
||||
}
|
||||
|
||||
public function waktuMakans()
|
||||
{
|
||||
return $this->belongsToMany(WaktuMakan::class, 'makanan_komponen_waktu')
|
||||
->withPivot('komponen_id')
|
||||
->withTimestamps();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class MakananKomponenWaktu extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'makanan_komponen_waktu';
|
||||
|
||||
protected $fillable = ['makanan_id', 'komponen_id', 'waktu_makan_id'];
|
||||
|
||||
public function makanan()
|
||||
{
|
||||
return $this->belongsTo(Makanan::class);
|
||||
}
|
||||
|
||||
public function komponen()
|
||||
{
|
||||
return $this->belongsTo(Komponen::class);
|
||||
}
|
||||
|
||||
public function waktuMakan()
|
||||
{
|
||||
return $this->belongsTo(WaktuMakan::class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class PengecualianMakanan extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
protected $fillable = ['user_id', 'makanan_id', 'waktu_makan_id', 'komponen_id'];
|
||||
|
||||
public function makanan() {
|
||||
return $this->belongsTo(Makanan::class);
|
||||
}
|
||||
|
||||
public function waktuMakan() {
|
||||
return $this->belongsTo(WaktuMakan::class);
|
||||
}
|
||||
|
||||
public function komponen() {
|
||||
return $this->belongsTo(Komponen::class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class PreferensiWaktuKriteria extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'preferensi_waktu_kriteria';
|
||||
|
||||
protected $fillable = [
|
||||
'waktu_makan_id',
|
||||
'kriteria_id',
|
||||
'bobot',
|
||||
];
|
||||
|
||||
/**
|
||||
* Relasi ke model WaktuMakan
|
||||
*/
|
||||
public function waktuMakan()
|
||||
{
|
||||
return $this->belongsTo(WaktuMakan::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Relasi ke model Kriteria
|
||||
*/
|
||||
public function kriteria()
|
||||
{
|
||||
return $this->belongsTo(Kriteria::class);
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ class Rekomendasi extends Model
|
|||
{
|
||||
use HasFactory;
|
||||
public $timestamps = false;
|
||||
protected $fillable = ['user_id', 'makanan_id', 'nilai_akhir', 'tanggal_rekomendasi'];
|
||||
protected $fillable = ['user_id', 'makanan_id', 'komponen_id', 'waktu_makan_id', 'nilai_akhir', 'tanggal_rekomendasi'];
|
||||
|
||||
public function user()
|
||||
{
|
||||
|
@ -20,4 +20,15 @@ public function makanan()
|
|||
{
|
||||
return $this->belongsTo(Makanan::class);
|
||||
}
|
||||
|
||||
|
||||
public function komponen()
|
||||
{
|
||||
return $this->belongsTo(Komponen::class);
|
||||
}
|
||||
|
||||
public function waktuMakan()
|
||||
{
|
||||
return $this->belongsTo(WaktuMakan::class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class RekomendasiAhli extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'rekomendasi_ahli';
|
||||
|
||||
protected $fillable = [
|
||||
'makanan_id',
|
||||
'waktu_makan_id',
|
||||
'komponen_id',
|
||||
'catatan',
|
||||
];
|
||||
|
||||
// Relasi ke makanan
|
||||
public function makanan()
|
||||
{
|
||||
return $this->belongsTo(Makanan::class);
|
||||
}
|
||||
|
||||
// Relasi ke waktu makan
|
||||
public function waktuMakan()
|
||||
{
|
||||
return $this->belongsTo(WaktuMakan::class);
|
||||
}
|
||||
|
||||
// Relasi ke komponen
|
||||
public function komponen()
|
||||
{
|
||||
return $this->belongsTo(Komponen::class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class WaktuMakan extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'waktu_makans'; // custom table name
|
||||
|
||||
protected $fillable = ['nama', 'keterangan'];
|
||||
|
||||
public function makananKomponenWaktu()
|
||||
{
|
||||
return $this->hasMany(MakananKomponenWaktu::class);
|
||||
}
|
||||
|
||||
public function makanans()
|
||||
{
|
||||
return $this->belongsToMany(Makanan::class, 'makanan_komponen_waktu')
|
||||
->withPivot('komponen_id')
|
||||
->withTimestamps();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('komponens', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('nama');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('komponens');
|
||||
}
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('waktu_makans', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('nama');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('waktu_makans');
|
||||
}
|
||||
};
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('makanan_komponen_waktu', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('makanan_id')->constrained('makanans')->onDelete('cascade');
|
||||
$table->foreignId('komponen_id')->constrained('komponens')->onDelete('cascade');
|
||||
$table->foreignId('waktu_makan_id')->constrained('waktu_makans')->onDelete('cascade');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('makanan_komponen_waktu');
|
||||
}
|
||||
};
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('rekomendasis', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('rekomendasis', 'komponen_id')) {
|
||||
$table->foreignId('komponen_id')->after('makanan_id')->constrained('komponens')->cascadeOnDelete();
|
||||
}
|
||||
|
||||
if (!Schema::hasColumn('rekomendasis', 'waktu_makan_id')) {
|
||||
$table->foreignId('waktu_makan_id')->after('komponen_id')->constrained('waktu_makans')->cascadeOnDelete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('rekomendasis', function (Blueprint $table) {
|
||||
$table->dropForeign(['komponen_id']);
|
||||
$table->dropForeign(['waktu_makan_id']);
|
||||
$table->dropColumn(['komponen_id', 'waktu_makan_id']);
|
||||
});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('rekomendasi_ahli', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('makanan_id');
|
||||
$table->unsignedBigInteger('waktu_makan_id');
|
||||
$table->unsignedBigInteger('komponen_id');
|
||||
$table->text('catatan')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
// Foreign Keys
|
||||
$table->foreign('makanan_id')->references('id')->on('makanans')->onDelete('cascade');
|
||||
$table->foreign('waktu_makan_id')->references('id')->on('waktu_makans')->onDelete('cascade');
|
||||
$table->foreign('komponen_id')->references('id')->on('komponens')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('rekomendasi_ahli');
|
||||
}
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('waktu_makans', function (Blueprint $table) {
|
||||
$table->string('keterangan')->nullable()->after('nama');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('waktu_makans', function (Blueprint $table) {
|
||||
$table->dropColumn('keterangan');
|
||||
});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
// Hapus foreign key dan ubah tipe kolom
|
||||
Schema::table('rekomendasi_ahli', function (Blueprint $table) {
|
||||
$table->dropForeign(['makanan_id']);
|
||||
});
|
||||
|
||||
// Ubah kolom menjadi text (rename lalu tambahkan kembali)
|
||||
Schema::table('rekomendasi_ahli', function (Blueprint $table) {
|
||||
$table->dropColumn('makanan_id');
|
||||
});
|
||||
|
||||
Schema::table('rekomendasi_ahli', function (Blueprint $table) {
|
||||
$table->text('makanan_id')->after('id');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// Revert: ubah kembali ke foreign key integer
|
||||
Schema::table('rekomendasi_ahli', function (Blueprint $table) {
|
||||
$table->dropColumn('makanan_id');
|
||||
});
|
||||
|
||||
Schema::table('rekomendasi_ahli', function (Blueprint $table) {
|
||||
$table->foreignId('makanan_id')->constrained('makanans')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
try {
|
||||
DB::statement('ALTER TABLE rekomendasi_ahli DROP FOREIGN KEY rekomendasi_ahli_makanan_id_foreign');
|
||||
} catch (\Throwable $e) {
|
||||
// Abaikan jika FK tidak ada
|
||||
}
|
||||
|
||||
// 2. Hapus kolom makanan_id jika masih ada
|
||||
if (Schema::hasColumn('rekomendasi_ahli', 'makanan_id')) {
|
||||
Schema::table('rekomendasi_ahli', function (Blueprint $table) {
|
||||
$table->dropColumn('makanan_id');
|
||||
});
|
||||
}
|
||||
|
||||
// 3. Tambahkan nama_makanan hanya jika belum ada
|
||||
if (!Schema::hasColumn('rekomendasi_ahli', 'nama_makanan')) {
|
||||
Schema::table('rekomendasi_ahli', function (Blueprint $table) {
|
||||
$table->text('nama_makanan')->after('id');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
// Revert ke kondisi sebelumnya
|
||||
Schema::table('rekomendasi_ahli', function (Blueprint $table) {
|
||||
$table->dropColumn('nama_makanan');
|
||||
$table->unsignedBigInteger('makanan_id')->nullable();
|
||||
$table->foreign('makanan_id')->references('id')->on('makanans')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('preferensi_waktu_kriteria', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('waktu_makan_id')->constrained()->onDelete('cascade');
|
||||
$table->foreignId('kriteria_id')->constrained()->onDelete('cascade');
|
||||
$table->float('bobot'); // nilai 0–1
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('preferensi_waktu_kriteria');
|
||||
}
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('pengecualian_makanans', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->onDelete('cascade');
|
||||
$table->foreignId('makanan_id')->constrained('makanans')->onDelete('cascade');
|
||||
$table->foreignId('waktu_makan_id')->constrained('waktu_makans')->onDelete('cascade');
|
||||
$table->foreignId('komponen_id')->constrained('komponens')->onDelete('cascade');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('pengecualian_makanans');
|
||||
}
|
||||
};
|
|
@ -80,7 +80,6 @@ class="form-check-input mt-1 alternatif-checkbox"
|
|||
id="alt{{ $makanan->id }}"
|
||||
style="transform: scale(1.2);"
|
||||
>
|
||||
|
||||
<label class="form-check-label ms-2 w-100" for="alt{{ $makanan->id }}">
|
||||
<h6 class="fw-bold mb-1">{{ $makanan->nama }}</h6>
|
||||
<ul class="list-unstyled small text-muted mb-0">
|
||||
|
@ -95,15 +94,13 @@ class="form-check-input mt-1 alternatif-checkbox"
|
|||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
<button type="submit" class="btn btn-success btn-lg px-4 mt-3" id="submitBtn" disabled>
|
||||
<i class="bi bi-arrow-right-circle-fill me-1"></i> Lanjutkan
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
</form>
|
||||
<hr class="my-4">
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
@extends('layout.app')
|
||||
@section('content')
|
||||
<div class="pagetitle">
|
||||
<h1>Data komponen</h1>
|
||||
<nav>
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="{{ route('admindash') }}">Home</a></li>
|
||||
<li class="breadcrumb-item active"><a href="{{ route('komponen') }}"> komponen</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div><!-- End Page Title -->
|
||||
|
||||
<section class="section">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title mb-2">Data komponen</h5>
|
||||
{{-- <div class="text-center">
|
||||
<a href="{{ route('tambahkomponen') }}" class="btn btn-primary">Tambah</a>
|
||||
</div> --}}
|
||||
</div>
|
||||
|
||||
<!-- Table with stripped rows -->
|
||||
<table class="table datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">No</th>
|
||||
<th class="text-center">Name</th>
|
||||
<th class="text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($komponens as $kmpn)
|
||||
<tr>
|
||||
<td class="text-center">{{ $loop->iteration }}</td>
|
||||
<td class="text-center">{{ $kmpn->nama }}</td>
|
||||
<td class="text-center">
|
||||
{{-- <a href="{{ route('edituser', $usr->id) }}" class="btn btn-sm btn-warning">Edit</a>
|
||||
<form action="{{ route('deleteuser', $usr->id) }}" method="POST" class="d-inline delete-form">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-sm btn-danger delete-button">Hapus</button>
|
||||
</form> --}}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- End Table with stripped rows -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@endsection
|
|
@ -14,14 +14,22 @@
|
|||
<section class="section profile">
|
||||
<div class="row">
|
||||
<!-- Kartu info ringkas -->
|
||||
<div class="col-xl-4">
|
||||
<div class="card">
|
||||
<div class="card-body pt-4 text-center">
|
||||
<h2>{{ $user->name }}</h2>
|
||||
<h5 class="text-muted mb-0">{{ $user->role->name ?? '-' }}</h5>
|
||||
<div class="col-lg-4">
|
||||
<div class="card border-0 shadow-sm text-center p-4 rounded-4">
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-center">
|
||||
<div class="rounded-circle bg-white shadow p-4 d-flex align-items-center justify-content-center" style="width: 100px; height: 100px;">
|
||||
<i class="bi bi-person-fill text-primary fs-1"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="fw-semibold mb-1">{{ $user->name }}</h5>
|
||||
<p class="text-muted mb-2">{{ $user->email }}</p>
|
||||
<span class="badge rounded-pill bg-primary">
|
||||
<i class="bi bi-award me-1"></i> {{ ucfirst($user->role->name ?? 'user') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tabs -->
|
||||
<div class="col-xl-8">
|
||||
|
|
|
@ -8,16 +8,16 @@
|
|||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="{{ route('admindash') }}">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ route('perbandingan') }}">Perbandingan Kriteria</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ route('hasil.normalisasi') }}">Normalisasi Kriteria</a></li>
|
||||
<li class="breadcrumb-item active">Normalisasi Kriteria</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div><!-- End Page Title -->
|
||||
</div>
|
||||
|
||||
<section class="section">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
|
||||
<!-- Form Input Normalisasi -->
|
||||
<!-- Matriks Normalisasi -->
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title mb-4">Normalisasi Matriks</h5>
|
||||
|
@ -36,9 +36,7 @@
|
|||
<tr>
|
||||
<th>{{ $baris->nama }}</th>
|
||||
@foreach ($kriterias as $j => $kolom)
|
||||
<td>
|
||||
{{ number_format($normalisasi[$i][$j], 4) }}
|
||||
</td>
|
||||
<td>{{ number_format($normalisasi[$i][$j], 4) }}</td>
|
||||
@endforeach
|
||||
</tr>
|
||||
@endforeach
|
||||
|
@ -48,7 +46,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tabel Bobot Kriteria -->
|
||||
<!-- Bobot Kriteria -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Bobot Kriteria</h5>
|
||||
|
@ -73,12 +71,11 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tindakan Selanjutnya -->
|
||||
<div class="text-end mt-3">
|
||||
<form method="GET" action="{{ route('alternatif.pilih') }}">
|
||||
@csrf
|
||||
<button type="submit" class="btn btn-success">Lanjut ke Perbandingan Alternatif</button>
|
||||
</form>
|
||||
<!-- Tombol Proses Otomatis -->
|
||||
<div class="text-end mt-4">
|
||||
<a href="{{ route('rekomendasi.hitung.otomatis') }}" class="btn btn-success btn-lg">
|
||||
<i class="bi bi-lightning-fill me-1"></i> Proses Rekomendasi Otomatis
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -1,135 +1,102 @@
|
|||
@extends('layout.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container mt-4">
|
||||
<div class="pagetitle">
|
||||
<h1>🏆 Ranking Rekomendasi Makanan</h1>
|
||||
<nav>
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="{{ route('admindash') }}">Home</a></li>
|
||||
<li class="breadcrumb-item active">Hasil Rekomendasi</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
{{-- Judul halaman --}}
|
||||
<div class="text-center mb-4">
|
||||
<h2 class="fw-bold">📊 Hasil Rekomendasi Makanan</h2>
|
||||
<p class="text-muted">Berikut adalah peringkat makanan berdasarkan hasil perhitungan AHP.</p>
|
||||
</div>
|
||||
<section class="section">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
|
||||
{{-- Flash success --}}
|
||||
@if(session('success'))
|
||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||
{{ session('success') }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
<div class="alert alert-success shadow-sm rounded-3">
|
||||
<i class="bi bi-check-circle me-2"></i> {{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- ===================== CAROUSEL ===================== --}}
|
||||
<div id="rekomendasiCarousel"
|
||||
class="carousel slide"
|
||||
data-bs-touch="true"
|
||||
data-bs-ride="carousel"
|
||||
data-bs-interval="7000"> {{-- non-auto slide, user geser manual --}}
|
||||
<div class="carousel-inner">
|
||||
@forelse ($rekomendasi as $waktu => $komponens)
|
||||
<div class="card shadow-lg border-start border-4 border-success mt-4">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title fw-bold text-success mb-4">
|
||||
🍽️ Menu {{ ucfirst($waktu) }}
|
||||
</h4>
|
||||
|
||||
@foreach($rekomendasiByDate as $tanggal => $items)
|
||||
<div class="carousel-item {{ $loop->first ? 'active' : '' }}">
|
||||
<div class="card shadow rounded">
|
||||
<div class="card-header bg-success text-white text-center">
|
||||
<h5 class="mb-0">
|
||||
Rekomendasi
|
||||
{{ \Carbon\Carbon::parse($tanggal)->translatedFormat('d F Y') }}
|
||||
@foreach ($komponens as $komponen => $items)
|
||||
@php
|
||||
$utama = $items->first();
|
||||
$alternatif = $items->skip(1)->take(4)->values(); // top 5 total
|
||||
@endphp
|
||||
|
||||
<div class="mb-4">
|
||||
<h5 class="text-primary fw-semibold">
|
||||
📌 {{ ucfirst($komponen) }}
|
||||
</h5>
|
||||
</div>
|
||||
|
||||
<div class="card-body p-0">
|
||||
<table class="table table-hover mb-0 text-center">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th style="width: 15%">🏅 Peringkat</th>
|
||||
<th>🍽️ Nama Makanan</th>
|
||||
<th style="width: 25%">📈 Nilai Akhir</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($items as $index => $item)
|
||||
<tr>
|
||||
<td>
|
||||
<span class="badge bg-primary fs-6">
|
||||
{{ $index + 1 }}
|
||||
<div class="border rounded-3 p-3 bg-light shadow-sm mb-2 d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
🌟 <strong>{{ $utama->makanan->nama }}</strong>
|
||||
</div>
|
||||
<span class="badge bg-success rounded-pill">
|
||||
{{ number_format($utama->persentase, 2) }}%
|
||||
</span>
|
||||
</td>
|
||||
<td class="fw-semibold">{{ $item->makanan->nama }}</td>
|
||||
<td>{{ number_format($item->nilai_akhir, 4) }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
|
||||
{{-- Navigasi kiri / kanan --}}
|
||||
<button class="carousel-control-prev" type="button"
|
||||
data-bs-target="#rekomendasiCarousel" data-bs-slide="prev">
|
||||
<span class="carousel-control-prev-icon"></span>
|
||||
<span class="visually-hidden">Previous</span>
|
||||
</button>
|
||||
<button class="carousel-control-next" type="button"
|
||||
data-bs-target="#rekomendasiCarousel" data-bs-slide="next">
|
||||
<span class="carousel-control-next-icon"></span>
|
||||
<span class="visually-hidden">Next</span>
|
||||
@if ($alternatif->count() > 0)
|
||||
<button class="btn btn-sm btn-outline-primary toggle-btn mb-2"
|
||||
type="button"
|
||||
data-target="#alt-{{ $waktu }}-{{ $komponen }}">
|
||||
🔁 Lihat Alternatif
|
||||
</button>
|
||||
|
||||
{{-- Indikator (bulatan) --}}
|
||||
<div class="carousel-indicators position-relative mt-3">
|
||||
@foreach($rekomendasiByDate as $tanggal => $items)
|
||||
<button type="button"
|
||||
data-bs-target="#rekomendasiCarousel"
|
||||
data-bs-slide-to="{{ $loop->index }}"
|
||||
class="{{ $loop->first ? 'active' : '' }}"
|
||||
aria-label="Slide {{ $loop->iteration }}"></button>
|
||||
<ol id="alt-{{ $waktu }}-{{ $komponen }}"
|
||||
class="list-group list-group-numbered shadow-sm d-none">
|
||||
@foreach ($alternatif as $index => $alt)
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
@if($index == 0) 🥈 @elseif($index == 1) 🥉 @else 🔹 @endif
|
||||
<strong>{{ $alt->makanan->nama }}</strong>
|
||||
</div>
|
||||
<span class="badge bg-secondary rounded-pill">
|
||||
{{ number_format($alt->persentase, 2) }}%
|
||||
</span>
|
||||
</li>
|
||||
@endforeach
|
||||
</ol>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
{{-- ================== AKHIR CAROUSEL ================== --}}
|
||||
|
||||
{{-- Tombol kirim hasil --}}
|
||||
<div class="mt-4 text-end">
|
||||
<form action="{{ route('rekomendasi.kirim', ['user' => 2]) }}"
|
||||
method="POST"
|
||||
onsubmit="return confirm('Yakin ingin mengirim hasil ini ke user?')">
|
||||
@csrf
|
||||
<button type="submit" class="btn btn-success">
|
||||
📤 Kirim Hasil ke User
|
||||
</button>
|
||||
</form>
|
||||
@empty
|
||||
<div class="alert alert-warning mt-4">
|
||||
<i class="bi bi-exclamation-circle me-2"></i> Tidak ada data rekomendasi tersedia untuk hari ini.
|
||||
</div>
|
||||
@endforelse
|
||||
|
||||
{{-- Form hapus per tanggal --}}
|
||||
<div class="mt-3 text-end">
|
||||
<form action="{{ route('rekomendasi.hapusSemua') }}"
|
||||
method="POST"
|
||||
class="d-inline-flex align-items-center gap-2">
|
||||
@csrf
|
||||
<label class="mb-0 fw-semibold" for="tanggal_rekomendasi">
|
||||
Pilih Tanggal Rekomendasi:
|
||||
</label>
|
||||
<select name="tanggal_rekomendasi" id="tanggal_rekomendasi" required class="form-select w-auto">
|
||||
<option value="">-- Pilih Tanggal --</option>
|
||||
@foreach ($tanggalList as $tgl)
|
||||
<option value="{{ $tgl }}">
|
||||
{{ \Carbon\Carbon::parse($tgl)->format('d M Y') }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<button type="submit" class="btn btn-danger">
|
||||
Hapus Data
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{{-- Tombol kembali --}}
|
||||
<div class="text-end mt-4">
|
||||
<a href="{{ route('alternatif.pilih') }}" class="btn btn-outline-secondary">
|
||||
🔙 Kembali ke Pemilihan Alternatif
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
document.querySelectorAll('.toggle-btn').forEach(button => {
|
||||
button.addEventListener('click', function () {
|
||||
const target = document.querySelector(this.dataset.target);
|
||||
target.classList.toggle('d-none');
|
||||
this.textContent = target.classList.contains('d-none')
|
||||
? '🔁 Lihat Alternatif'
|
||||
: '🔼 Sembunyikan Alternatif';
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
@extends('layout.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<h2 class="mb-4">Edit Relasi</h2>
|
||||
|
||||
@if(session('error'))
|
||||
<div class="alert alert-danger">{{ session('error') }}</div>
|
||||
@endif
|
||||
|
||||
<form method="POST" action="{{ route('relasi.update', $relasi->id) }}">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label for="makanan_id">Makanan</label>
|
||||
<select name="makanan_id" class="form-control">
|
||||
@foreach($makanans as $makanan)
|
||||
<option value="{{ $makanan->id }}" {{ $relasi->makanan_id == $makanan->id ? 'selected' : '' }}>
|
||||
{{ $makanan->nama }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label for="komponen_id">Komponen</label>
|
||||
<select name="komponen_id" class="form-control">
|
||||
@foreach($komponens as $komponen)
|
||||
<option value="{{ $komponen->id }}" {{ $relasi->komponen_id == $komponen->id ? 'selected' : '' }}>
|
||||
{{ $komponen->nama }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label for="waktu_makan_id">Waktu Makan</label>
|
||||
<select name="waktu_makan_id" class="form-control">
|
||||
@foreach($waktuMakans as $waktu)
|
||||
<option value="{{ $waktu->id }}" {{ $relasi->waktu_makan_id == $waktu->id ? 'selected' : '' }}>
|
||||
{{ $waktu->nama }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-success">Simpan Perubahan</button>
|
||||
<a href="{{ route('relasi') }}" class="btn btn-secondary">Batal</a>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
|
@ -0,0 +1,143 @@
|
|||
@extends('layout.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<h2 class="mb-4">Tambah Relasi Makanan - Komponen - Waktu Makan</h2>
|
||||
|
||||
@if(session('success'))
|
||||
<div class="alert alert-success">{{ session('success') }}</div>
|
||||
@elseif(session('error'))
|
||||
<div class="alert alert-danger">{{ session('error') }}</div>
|
||||
@endif
|
||||
|
||||
<form method="POST" action="{{ route('relasi.store') }}" class="mb-4">
|
||||
@csrf
|
||||
<div class="form-group mb-2">
|
||||
<label for="makanan_id">Makanan</label>
|
||||
<select name="makanan_id" class="form-control">
|
||||
@foreach($makanans as $makanan)
|
||||
<option value="{{ $makanan->id }}">{{ $makanan->nama }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-2">
|
||||
<label for="komponen_id">Komponen</label>
|
||||
<select name="komponen_id" class="form-control">
|
||||
@foreach($komponens as $komponen)
|
||||
<option value="{{ $komponen->id }}">{{ $komponen->nama }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-3">
|
||||
<label for="waktu_makan_id">Waktu Makan</label>
|
||||
<select name="waktu_makan_id" class="form-control">
|
||||
@foreach($waktuMakans as $waktu)
|
||||
<option value="{{ $waktu->id }}">{{ $waktu->nama }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Simpan Relasi</button>
|
||||
</form>
|
||||
|
||||
<section class="section">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Filter Relasi</h5>
|
||||
|
||||
<form method="GET" action="{{ route('relasi') }}" class="row g-3 align-items-end mb-4">
|
||||
<div class="col-md-4">
|
||||
<label for="komponen_id" class="form-label">Filter Komponen</label>
|
||||
<select name="komponen_id" class="form-select">
|
||||
<option value="">-- Semua Komponen --</option>
|
||||
@foreach($komponens as $komponen)
|
||||
<option value="{{ $komponen->id }}" {{ request('komponen_id') == $komponen->id ? 'selected' : '' }}>
|
||||
{{ $komponen->nama }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label for="waktu_makan_id" class="form-label">Filter Waktu Makan</label>
|
||||
<select name="waktu_makan_id" class="form-select">
|
||||
<option value="">-- Semua Waktu Makan --</option>
|
||||
@foreach($waktuMakans as $waktu)
|
||||
<option value="{{ $waktu->id }}" {{ request('waktu_makan_id') == $waktu->id ? 'selected' : '' }}>
|
||||
{{ $waktu->nama }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<button type="submit" class="btn btn-primary">Terapkan Filter</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<h5 class="card-title mb-0">Data Relasi Tersimpan</h5>
|
||||
</div>
|
||||
|
||||
<!-- Table with stripped rows -->
|
||||
<table class="table datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">No</th>
|
||||
<th class="text-center">Makanan</th>
|
||||
<th class="text-center">Komponen</th>
|
||||
<th class="text-center">Waktu Makanan</th>
|
||||
<th class="text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($relasis as $relasi)
|
||||
<tr>
|
||||
<td class="text-center">{{ $loop->iteration }}</td>
|
||||
<td class="text-center">{{ $relasi->makanan->nama }}</td>
|
||||
<td class="text-center">{{ $relasi->komponen->nama }}</td>
|
||||
<td class="text-center">{{ $relasi->waktuMakan->nama }}</td>
|
||||
<td class="text-center">
|
||||
<a href="{{ route('relasi.edit', $relasi->id) }}" class="btn btn-warning btn-sm" title="Edit">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<form action="{{ route('relasi.destroy', $relasi->id) }}" method="POST" onsubmit="return confirm('Yakin ingin menghapus?');" style="display:inline;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button class="btn btn-danger btn-sm" title="Hapus">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
|
||||
{{-- <td class="text-center">
|
||||
<form action="{{ route('relasi.destroy', $relasi->id) }}" method="POST" onsubmit="return confirm('Yakin ingin menghapus?');" style="display:inline;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button class="btn btn-danger btn-sm" title="Hapus">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
</form>
|
||||
</td> --}}
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- End Table -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
@endsection
|
|
@ -0,0 +1,57 @@
|
|||
@extends('layout.app')
|
||||
@section('content')
|
||||
<div class="pagetitle">
|
||||
<h1>Data waktu makan</h1>
|
||||
<nav>
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="{{ route('admindash') }}">Home</a></li>
|
||||
<li class="breadcrumb-item active"><a href="{{ route('waktumakan') }}"> waktumakan</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div><!-- End Page Title -->
|
||||
|
||||
<section class="section">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title mb-2">Data komponen</h5>
|
||||
{{-- <div class="text-center">
|
||||
<a href="{{ route('tambahkomponen') }}" class="btn btn-primary">Tambah</a>
|
||||
</div> --}}
|
||||
</div>
|
||||
|
||||
<!-- Table with stripped rows -->
|
||||
<table class="table datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">No</th>
|
||||
<th class="text-center">Name</th>
|
||||
<th class="text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($waktu_makans as $wm)
|
||||
<tr>
|
||||
<td class="text-center">{{ $loop->iteration }}</td>
|
||||
<td class="text-center">{{ $wm ->nama }}</td>
|
||||
<td class="text-center">
|
||||
{{-- <a href="{{ route('edituser', $usr->id) }}" class="btn btn-sm btn-warning">Edit</a>
|
||||
<form action="{{ route('deleteuser', $usr->id) }}" method="POST" class="d-inline delete-form">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-sm btn-danger delete-button">Hapus</button>
|
||||
</form> --}}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- End Table with stripped rows -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@endsection
|
|
@ -12,6 +12,8 @@
|
|||
<!-- Favicons -->
|
||||
<link rel ="icon" type="image" href="{{ asset('logo/baru/dutdut.png') }}">
|
||||
<link rel ="icon" type="image" href ="{{ asset('logo/baru/dutdut.png') }}">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
|
||||
|
||||
|
||||
|
||||
<!-- Google Fonts -->
|
||||
|
@ -29,6 +31,7 @@
|
|||
<link href="{{ asset('assets/vendor/remixicon/remixicon.css') }}" rel="stylesheet">
|
||||
<link href="{{ asset('assets/vendor/simple-datatables/style.css') }}" rel="stylesheet">
|
||||
|
||||
|
||||
<!-- Template Main CSS File -->
|
||||
<link href="{{ asset('assets/css/style.css') }}" rel="stylesheet">
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<div class="copyright">
|
||||
{{-- © Copyright <strong><span>NiceAdmin</span></strong>. All Rights Reserved --}}
|
||||
© Copyright <strong><span>HeartChoice</span></strong>. All Rights Reserved
|
||||
</div>
|
||||
<div class="credits">
|
||||
<!-- All the links in the footer should remain intact. -->
|
||||
<!-- You can delete the links only if you purchased the pro version. -->
|
||||
<!-- Licensing information: https://bootstrapmade.com/license/ -->
|
||||
<!-- Purchase the pro version with working PHP/AJAX contact form: https://bootstrapmade.com/nice-admin-bootstrap-admin-html-template/ -->
|
||||
{{-- Designed by <a href="https://bootstrapmade.com/">BootstrapMade</a> --}}
|
||||
Designed by <a href="https://bootstrapmade.com/">BootstrapMade</a>
|
||||
</div>
|
||||
|
|
|
@ -10,6 +10,14 @@
|
|||
<li class="nav-heading">Pages</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ request()->routeIs('datauser') ? '' : 'collapsed' }}" href="{{ route('datauser') }}">
|
||||
<i class="ri-admin-line"></i>
|
||||
<span>User</span>
|
||||
</a>
|
||||
</li><!-- End Profile Page Nav -->
|
||||
|
||||
|
||||
{{-- <li class="nav-item">
|
||||
<a class="nav-link {{ request()->routeIs(['tables-general', 'tables-data']) ? '' : 'collapsed' }}" data-bs-target="#users-nav" data-bs-toggle="collapse" href="#">
|
||||
<i class="ri-admin-line"></i><span>User</span><i class="bi bi-chevron-down ms-auto"></i>
|
||||
</a>
|
||||
|
@ -20,14 +28,9 @@
|
|||
<span>Role</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="nav-link {{ request()->routeIs('datauser') ? '' : 'collapsed' }}" href="{{ route('datauser') }}">
|
||||
<i class="ri-store-2-line"></i>
|
||||
<span>User</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
</li> --}}
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ request()->routeIs(['tables-general', 'tables-data']) ? '' : 'collapsed' }}" data-bs-target="#foods-nav" data-bs-toggle="collapse" href="#">
|
||||
|
@ -52,6 +55,24 @@
|
|||
<span>Data Makanan</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="nav-link {{ request()->routeIs('komponen') ? '' : 'collapsed' }}" href="{{ route('komponen') }}">
|
||||
<i class="ri-store-2-line"></i>
|
||||
<span>Data komponen</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="nav-link {{ request()->routeIs('waktumakan') ? '' : 'collapsed' }}" href="{{ route('waktumakan') }}">
|
||||
<i class="ri-store-2-line"></i>
|
||||
<span>waktu makan</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="nav-link {{ request()->routeIs('relasi') ? '' : 'collapsed' }}" href="{{ route('relasi') }}">
|
||||
<i class="ri-store-2-line"></i>
|
||||
<span>relasi</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
|
|
@ -3,99 +3,115 @@
|
|||
@section('content')
|
||||
<div class="container-xxl py-5">
|
||||
<div class="container">
|
||||
<div class="text-center mx-auto mb-5 wow fadeInUp" data-wow-delay="0.1s" style="max-width: 600px;">
|
||||
<p class="d-inline-block border rounded-pill py-1 px-4 bg-primary text-white">Hasil Rekomendasi AHP</p>
|
||||
<h1 class="mb-3">Rekomendasi Menu Makanan Terbaik untuk Anda</h1>
|
||||
<p class="text-muted">Berikut adalah hasil akhir dari perhitungan berdasarkan metode AHP. Nilai akhir menunjukkan tingkat kesesuaian berdasarkan kriteria yang telah di pilih.</p>
|
||||
|
||||
<form method="GET" action="{{ route('userresult') }}" class="row g-3 mb-4 justify-content-center">
|
||||
<div class="col-md-auto">
|
||||
<select name="tanggal" class="form-select" onchange="this.form.submit()">
|
||||
<option value="">-- Pilih Tanggal Rekomendasi --</option>
|
||||
@foreach ($listTanggal as $tgl)
|
||||
<option value="{{ $tgl }}" {{ request('tanggal') == $tgl ? 'selected' : '' }}>
|
||||
{{ \Carbon\Carbon::parse($tgl)->translatedFormat('d F Y') }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-auto">
|
||||
<a href="{{ route('userresult') }}" class="btn btn-secondary">Reset</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
<div class="text-center mx-auto mb-5" style="max-width: 700px;">
|
||||
<p class="d-inline-block border rounded-pill py-1 px-4 bg-primary text-white">Hasil Rekomendasi Ahli</p>
|
||||
<h1 class="mb-3">Menu Makanan Terbaik dari Ahli Gizi</h1>
|
||||
<p class="text-muted">Ditampilkan berdasarkan panduan ahli gizi untuk penderita penyakit jantung.</p>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive wow fadeInUp" data-wow-delay="0.2s">
|
||||
<table class="table align-middle table-hover shadow-sm">
|
||||
<thead class="table-dark text-center">
|
||||
<tr>
|
||||
<th>Peringkat</th>
|
||||
<th>Nama Makanan</th>
|
||||
<th>Nilai Akhir</th>
|
||||
<th>Persentase</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($rekomendasi->sortByDesc('nilai_akhir')->values() as $index => $rekom)
|
||||
<tr>
|
||||
<td class="text-center">
|
||||
<span class="badge bg-success fs-6">{{ $index + 1 }}</span>
|
||||
</td>
|
||||
<td class="fw-semibold">{{ $rekom->makanan->nama }}</td>
|
||||
<td class="text-center">{{ number_format($rekom->nilai_akhir, 4) }}</td>
|
||||
<td style="min-width: 150px;">
|
||||
@forelse ($rekomendasi as $waktu => $komponens)
|
||||
<div class="card shadow-sm border-start border-4 border-primary mb-5">
|
||||
<div class="card-body">
|
||||
<h4 class="text-primary fw-bold mb-2">
|
||||
🍽️ Menu {{ $waktuMakans[$waktu]->nama ?? ucfirst($waktu) }}
|
||||
</h4>
|
||||
@if($waktuMakans[$waktu]?->keterangan)
|
||||
<p class="text-muted fst-italic mb-3">
|
||||
🕒 {{ $waktuMakans[$waktu]->keterangan }}
|
||||
</p>
|
||||
@endif
|
||||
|
||||
<div class="d-flex overflow-auto gap-4 pb-2" style="scroll-snap-type: x mandatory;">
|
||||
@foreach ($komponens as $komponen => $items)
|
||||
@php
|
||||
$persentase = ($totalNilaiAkhir > 0) ? ($rekom->nilai_akhir / $totalNilaiAkhir) * 100 : 0;
|
||||
@endphp
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="progress flex-grow-1 me-2" style="height: 20px;">
|
||||
<div class="progress-bar bg-info" role="progressbar"
|
||||
style="width: {{ $persentase }}%;"
|
||||
aria-valuenow="{{ $persentase }}" aria-valuemin="0" aria-valuemax="100">
|
||||
</div>
|
||||
</div>
|
||||
<small class="fw-semibold text-dark" style="width: 50px;">{{ number_format($persentase, 2) }}%</small>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a class="btn btn-outline-primary btn-sm" data-bs-toggle="modal" data-bs-target="#detailModal{{ $index }}">
|
||||
<i class="fa fa-info-circle me-1"></i> Detail
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
$utama = $items->first();
|
||||
$utamaNama = $utama->nama_makanan ?? '-';
|
||||
$utamaPersen = 100;
|
||||
$modalId = 'modal-' . Str::slug($waktu . '-' . $komponen);
|
||||
|
||||
@foreach ($rekomendasi as $index => $rekom)
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="detailModal{{ $index }}" tabindex="-1" aria-labelledby="detailModalLabel{{ $index }}" aria-hidden="true">
|
||||
// Ambil alternatif dari tabel rekomendasis
|
||||
$alternatifKey = $waktu . '-' . $utama->komponen_id;
|
||||
$alternatifList = $alternatifGrouped[$alternatifKey] ?? collect();
|
||||
@endphp
|
||||
|
||||
<div class="card shadow-sm p-3 bg-light" style="min-width: 300px; scroll-snap-align: start;">
|
||||
<h6 class="fw-bold text-secondary mb-2">{{ ucfirst($komponen) }}</h6>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<span>🌟 <strong>{{ $utamaNama }}</strong></span>
|
||||
<span class="badge bg-success">{{ number_format($utamaPersen, 2) }}%</span>
|
||||
</div>
|
||||
|
||||
<div class="progress mb-2" style="height: 16px;">
|
||||
<div class="progress-bar bg-info" role="progressbar"
|
||||
style="width: {{ $utamaPersen }}%;"
|
||||
aria-valuenow="{{ $utamaPersen }}" aria-valuemin="0" aria-valuemax="100">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($alternatifList->count() > 0)
|
||||
<button class="btn btn-sm btn-outline-primary w-100 mt-2"
|
||||
data-bs-toggle="modal" data-bs-target="#{{ $modalId }}">
|
||||
🔁 Lihat Alternatif
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Modal Alternatif -->
|
||||
<div class="modal fade" id="{{ $modalId }}" tabindex="-1" aria-labelledby="{{ $modalId }}Label" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-content shadow">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="detailModalLabel{{ $index }}">Detail Makanan: {{ $rekom->makanan->nama }}</h5>
|
||||
<h5 class="modal-title">Alternatif untuk {{ ucfirst($komponen) }} ({{ $waktuMakans[$waktu]->nama }})</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Tutup"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item"><strong>Lemak:</strong> {{ $rekom->makanan->lemak }} g</li>
|
||||
<li class="list-group-item"><strong>Natrium:</strong> {{ $rekom->makanan->natrium }} mg</li>
|
||||
<li class="list-group-item"><strong>Energi:</strong> {{ $rekom->makanan->energi }} kal</li>
|
||||
<li class="list-group-item"><strong>Karbohidrat:</strong> {{ $rekom->makanan->karbohidrat }} g</li>
|
||||
</ul>
|
||||
@foreach ($alternatifList->sortByDesc('nilai_akhir')->take(4) as $index => $alt)
|
||||
@php $persen = $alt->nilai_akhir * 100; @endphp
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<span>
|
||||
@if ($index == 0) 🥈 @elseif ($index == 1) 🥉 @else 🔹 @endif
|
||||
{{ $alt->makanan->nama }}
|
||||
</span>
|
||||
<span class="badge bg-secondary">{{ number_format($persen, 2) }}%</span>
|
||||
</div>
|
||||
<div class="progress mb-2" style="height: 14px;">
|
||||
<div class="progress-bar bg-secondary" role="progressbar"
|
||||
style="width: {{ $persen }}%;"
|
||||
aria-valuenow="{{ $persen }}" aria-valuemin="0" aria-valuemax="100">
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Tutup</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- End Modal -->
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div class="alert alert-warning text-center">
|
||||
<i class="fa fa-exclamation-circle me-2"></i> Tidak ada hasil rekomendasi ahli tersedia saat ini.
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
@endsection
|
||||
|
||||
@push('styles')
|
||||
<style>
|
||||
.card-carousel::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.card-carousel {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
use App\Http\Controllers\RegisterController;
|
||||
use App\Http\Controllers\RekomendasiController;
|
||||
use App\Http\Controllers\ProfileController;
|
||||
use App\Http\Controllers\MenuAHPController;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -85,6 +86,32 @@
|
|||
Route::delete('/makanan/{makanan}', [MakananController::class, 'deletemakanan'])->name('deletemakanan');
|
||||
Route::get('/tambahmakanan', [MakananController::class, 'tambahmakanan'])->name('tambahmakanan');
|
||||
Route::post('/makanan/storemakanan', [MakananController::class, 'storemakanan'])->name('makanan.storemakanan');
|
||||
|
||||
|
||||
|
||||
// Routes untuk komponen
|
||||
Route::get('/komponen', [MakananController::class, 'komponen'])->name('komponen');
|
||||
Route::get('/editkomponen/{komponen}/editkomponen', [MakananController::class, 'editkomponen'])->name('editkomponen');
|
||||
Route::put('/komponen/{komponen}', [MakananController::class, 'updatekomponen'])->name('updatekomponen');
|
||||
Route::delete('/komponen/{komponen}', [MakananController::class, 'deletekomponen'])->name('deletekomponen');
|
||||
Route::get('/tambahkomponen', [MakananController::class, 'tambahkomponen'])->name('tambahkomponen');
|
||||
Route::post('/komponen/storekomponen', [MakananController::class, 'storekomponen'])->name('makanan.storekomponen');
|
||||
|
||||
|
||||
// Routes untuk waktu makan
|
||||
Route::get('/waktumakan', [MakananController::class, 'waktumakan'])->name('waktumakan');
|
||||
Route::get('/editwaktumakan/{waktumakan}/editwaktumakan', [MakananController::class, 'editwaktumakan'])->name('editwaktumakan');
|
||||
Route::put('/waktumakan/{waktumakan}', [MakananController::class, 'updatewaktumakan'])->name('updatewaktumakan');
|
||||
Route::delete('/waktumakan/{waktumakan}', [MakananController::class, 'deletewaktumakan'])->name('deletewaktumakan');
|
||||
Route::get('/tambahwaktumakan', [MakananController::class, 'tambahwaktumakan'])->name('tambahwaktumakan');
|
||||
Route::post('/waktumakan/storewaktumakan', [MakananController::class, 'storewaktumakan'])->name('makanan.storewaktumakan');
|
||||
|
||||
Route::get('/relasi', [MakananController::class, 'index'])->name('relasi');
|
||||
Route::post('/relasi/storerelasi', [MakananController::class, 'store'])->name('relasi.store');
|
||||
Route::delete('/relasi/{relasi}', [MakananController::class, 'destroy'])->name('relasi.destroy');
|
||||
Route::get('/relasi/{id}/edit', [MakananController::class, 'edit'])->name('relasi.edit');
|
||||
Route::put('/relasi/{id}', [MakananController::class, 'update'])->name('relasi.update');
|
||||
|
||||
});
|
||||
|
||||
// Routes untuk kriteria
|
||||
|
@ -117,10 +144,8 @@
|
|||
Route::post('/alternatif/simpan-normalisasi', [AlternatifController::class, 'simpanNormalisasi'])->name('alternatif.simpanNormalisasi');
|
||||
|
||||
// Routes untuk rekomendasi
|
||||
Route::get('/rekomendasi/proses', [RekomendasiController::class, 'hitungDanSimpan'])->name('rekomendasi.proses');
|
||||
Route::get('/rekomendasi/hasil', [RekomendasiController::class, 'tampil'])->name('rekomendasi.hasil');
|
||||
Route::post('/rekomendasi/kirim/{user}', [RekomendasiController::class, 'kirimKeUser'])->name('rekomendasi.kirim');
|
||||
Route::delete('/rekomendasi/hapus', [RekomendasiController::class, 'hapusSemua'])->name('rekomendasi.hapusSemua');
|
||||
Route::get('/rekomendasi/hitung-otomatis', [RekomendasiController::class, 'hitungDanSimpanOtomatis'])->name('rekomendasi.hitung.otomatis');
|
||||
Route::get('/rekomendasi/hasil', [RekomendasiController::class, 'tampilHasil'])->name('rekomendasi.hasil');
|
||||
|
||||
|
||||
});
|
||||
|
@ -129,6 +154,7 @@
|
|||
|
||||
|
||||
|
||||
|
||||
// User Routes (Hanya bisa diakses oleh User)
|
||||
Route::middleware(['cekrole:user'])->group(function () {
|
||||
Route::get('/userdash', [UserController::class, 'userdash'])->name('userdash');
|
||||
|
|
Loading…
Reference in New Issue