Perbaikan

This commit is contained in:
HANIF FEBRIANSYAH 2025-05-27 12:43:35 +07:00
parent d31dc31bce
commit 9bb045671f
10 changed files with 843 additions and 566 deletions

View File

@ -15,6 +15,90 @@ class HomeController extends Controller
{
public function index()
{
//
// Ambil semua sub kriteria dan relasinya dengan kriteria
$subKriteria = SubKriteria::with('kriteria')->get()->groupBy(function ($item) {
return $item->kriteria->nama_kriteria;
});
return view('landingpage.master', [
'subKriteria' => $subKriteria
]);
}
public function prosesRekomendasi(Request $request)
{
$sub_kriterias = $request->input('sub_kriteria'); // [kriteria_id => sub_kriteria_id]
if (!$sub_kriterias) {
return back()->with('error', 'Harap pilih semua preferensi terlebih dahulu.');
}
$selectedSubs = SubKriteria::whereIn('id', array_values($sub_kriterias))->get()->keyBy('id');
$allPakaian = Pakaian::with('subKriterias')->get();
// Step 1: Filter berdasarkan preferensi user
$filteredPakaian = $allPakaian->filter(function ($pakaian) use ($sub_kriterias, $selectedSubs) {
foreach ($sub_kriterias as $kriteria_id => $sub_id) {
if ($kriteria_id == 2) { // Harga (range)
$harga = $pakaian->harga;
$sub = $selectedSubs[$sub_id];
if ($harga < $sub->min_harga || $harga > $sub->max_harga) {
return false;
}
} elseif ($kriteria_id == 3) { // Jenis Pakaian (C3) WAJIB SAMA
$match = $pakaian->subKriterias->contains(function ($item) use ($kriteria_id, $sub_id) {
return $item->kriteria_id == $kriteria_id && $item->id == $sub_id;
});
if (!$match) return false;
} else {
// Untuk kriteria lain, cukup memiliki salah satu sub_kriteria
$match = $pakaian->subKriterias->where('kriteria_id', $kriteria_id)->isNotEmpty();
if (!$match) return false;
}
}
return true;
});
if ($filteredPakaian->isEmpty()) {
return back()->with('error', 'Tidak ada pakaian yang sesuai dengan preferensi Anda.');
}
// Step 2: Siapkan bobot & maksimum nilai
$kriterias = Kriteria::all()->keyBy('id');
$maxPerKriteria = [];
foreach ($kriterias as $kriteria_id => $kriteria) {
$maxPerKriteria[$kriteria_id] = SubKriteria::where('kriteria_id', $kriteria_id)->max('nilai') ?: 1;
}
// Step 3: Hitung skor SAW
$matrix = [];
foreach ($filteredPakaian as $pakaian) {
$score = 0;
foreach ($kriterias as $kriteria_id => $kriteria) {
$bobot = $kriteria->bobot;
$jenis = $kriteria->jenis;
// Ambil sub_kriteria tertinggi untuk kriteria ini
$subs = $pakaian->subKriterias->where('kriteria_id', $kriteria_id);
$sub = $subs->sortByDesc('nilai')->first();
if ($sub) {
$nilai = $sub->nilai;
$max = $maxPerKriteria[$kriteria_id];
$normal = $jenis == 'COST' ? ($nilai ? $max / $nilai : 0) : $nilai / $max;
$score += $normal * $bobot;
}
}
$matrix[] = [
'pakaian' => $pakaian,
'score' => round($score, 3),
];
}
$rekomendasi = collect($matrix)->sortByDesc('score')->values();
return view('landingpage.hasil', compact('rekomendasi'));
}
}

View File

@ -2,9 +2,12 @@
namespace App\Http\Controllers;
use App\Models\Kriteria;
use App\Models\Pakaian;
use App\Models\Kriteria;
use App\Models\SubKriteria;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
class PakaianController extends Controller
{
@ -31,11 +34,14 @@ class PakaianController extends Controller
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
$kriterias = Kriteria::with('subKriteria')->get(); // load kriteria + sub_kriterias
return view('admin.pages.pakaian.create', compact('kriterias'));
}
/**
* Store a newly created resource in storage.
*/
@ -45,23 +51,44 @@ class PakaianController extends Controller
'nama_pakaian' => 'required|string|max:255',
'harga' => 'required|numeric',
'img' => 'nullable|image|max:2048',
'sub_kriterias' => 'array|nullable',
]);
$imgPath = null;
DB::beginTransaction();
try {
// Upload image jika ada
$path = null;
if ($request->hasFile('img')) {
$imgPath = $request->file('img')->store('uploads/pakaian', 'public');
$path = $request->file('img')->store('pakaian', 'public');
}
// Simpan pakaian
$pakaian = Pakaian::create([
'nama_pakaian' => $request->nama_pakaian,
'harga' => $request->harga,
'img' => $imgPath ? 'storage/' . $imgPath : null,
'img' => $path,
]);
// Simpan relasi subkriteria (many-to-many)
$pakaian->subKriterias()->sync($request->subkriterias);
// Simpan relasi sub kriteria
if ($request->filled('sub_kriterias')) {
$pakaian->subKriterias()->sync($request->sub_kriterias);
}
return redirect()->route('admin.pakaian.index')->with('success', 'Data pakaian berhasil ditambahkan.');
DB::commit();
return redirect()->route('admin.pakaian.index')->with('success', 'Pakaian berhasil ditambahkan.');
} catch (\Exception $e) {
// Rollback semua jika ada error
DB::rollBack();
// Hapus file yang sudah di-upload jika perlu
if ($path && Storage::disk('public')->exists($path)) {
Storage::disk('public')->delete($path);
}
return redirect()->back()->with('error', 'Gagal menambahkan pakaian: ' . $e->getMessage());
}
}
@ -76,42 +103,58 @@ class PakaianController extends Controller
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
public function edit($id)
{
//
$pakaian = Pakaian::with('subKriterias')->findOrFail($id);
$kriterias = Kriteria::with('subKriteria')->get();
return view('admin.pages.pakaian.edit', compact('pakaian', 'kriterias'));
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, $id)
{
$request->validate([
'nama_pakaian' => 'required|string|max:255',
'harga' => 'required|numeric|min:0',
'gambar' => 'nullable|image|mimes:jpeg,png,jpg|max:2048',
'harga' => 'required|numeric',
'img' => 'nullable|image|max:2048',
'sub_kriterias' => 'array|nullable',
]);
DB::beginTransaction();
try {
$pakaian = Pakaian::findOrFail($id);
$pakaian->nama_pakaian = $request->nama_pakaian;
$pakaian->harga = $request->harga;
$path = $pakaian->img;
// Jika upload gambar baru
if ($request->hasFile('gambar')) {
if ($pakaian->img && file_exists(public_path($pakaian->img))) {
unlink(public_path($pakaian->img));
// Update gambar jika ada file baru
if ($request->hasFile('img')) {
if ($path && Storage::disk('public')->exists($path)) {
Storage::disk('public')->delete($path);
}
$path = $request->file('img')->store('pakaian', 'public');
}
$file = $request->file('gambar');
$path = 'uploads/pakaian/';
$filename = time() . '_' . $file->getClientOriginalName();
$file->move(public_path($path), $filename);
$pakaian->img = $path . $filename;
$pakaian->update([
'nama_pakaian' => $request->nama_pakaian,
'harga' => $request->harga,
'img' => $path,
]);
// Update relasi sub_kriterias
$pakaian->subKriterias()->sync($request->sub_kriterias ?? []);
DB::commit();
return redirect()->route('admin.pakaian.index')->with('success', 'Pakaian berhasil diperbarui.');
} catch (\Exception $e) {
DB::rollBack();
if (isset($path) && $request->hasFile('img') && Storage::disk('public')->exists($path)) {
Storage::disk('public')->delete($path);
}
$pakaian->save();
return redirect()->back()->with('success', 'Data pakaian berhasil diperbarui!');
return redirect()->back()->with('error', 'Gagal memperbarui pakaian: ' . $e->getMessage());
}
}

View File

@ -16,7 +16,6 @@ return new class extends Migration
$table->foreignId('pakaian_id')->constrained()->onDelete('cascade');
$table->foreignId('sub_kriteria_id')->constrained()->onDelete('cascade');
$table->timestamps();
$table->unique(['pakaian_id', 'sub_kriteria_id']);
});
}

View File

@ -28,6 +28,7 @@
position: relative;
}
.bg-gradient-green {
background-color: #43a047 !important;
/* hijau medium */
@ -45,7 +46,6 @@
padding-top: 8px !important;
padding-bottom: 8px !important;
}
</style>
</head>
@ -93,7 +93,8 @@
<!-- Nav Item - Data Sub Kriteria (Collapse) -->
<li class="nav-item">
<a class="nav-link d-flex justify-content-between align-items-center {{ request()->is('admin/kriteria/subkriteria/*') ? '' : 'collapsed' }}"
href="#" data-bs-toggle="collapse" data-bs-target="#collapseSubkriteria" aria-expanded="{{ request()->is('admin/kriteria/subkriteria/*') ? 'true' : 'false' }}"
href="#" data-bs-toggle="collapse" data-bs-target="#collapseSubkriteria"
aria-expanded="{{ request()->is('admin/kriteria/subkriteria/*') ? 'true' : 'false' }}"
aria-controls="collapseSubkriteria" style="font-size: 0.9rem; padding: 0.5rem 1rem;">
<div>
<i class="bi bi-boxes me-2"></i>
@ -102,7 +103,8 @@
<i class="bi bi-chevron-down small"></i>
</a>
<div id="collapseSubkriteria" class="collapse {{ request()->is('admin/kriteria/subkriteria/*') ? 'show' : '' }}">
<div id="collapseSubkriteria"
class="collapse {{ request()->is('admin/kriteria/subkriteria/*') ? 'show' : '' }}">
<div class="bg-white ps-2 py-1 rounded-2">
@php
use App\Models\Kriteria;

View File

@ -0,0 +1,100 @@
@extends('admin.layouts.base')
@section('title', 'Tambah Pakaian')
@section('content')
<div class=" py-4">
<div class="card shadow-sm border-0 mx-auto">
<div class="card-header bg-success text-white d-flex align-items-center">
<i class="bi bi-plus-circle me-2 fs-5"></i>
<h5 class="mb-0">Tambah Pakaian</h5>
</div>
<div class="card-body">
<form action="{{ route('admin.pakaian.store') }}" method="POST" enctype="multipart/form-data">
@csrf
<div class="mb-3">
<label for="nama_pakaian" class="form-label fw-semibold">Nama Pakaian</label>
<input type="text" name="nama_pakaian" id="nama_pakaian" class="form-control" required>
</div>
<div class="mb-3">
<label for="harga" class="form-label fw-semibold">Harga</label>
<div class="input-group">
<span class="input-group-text">Rp</span>
<input type="number" name="harga" id="harga" class="form-control" required>
</div>
</div>
<div class="mb-3">
<label for="img" class="form-label fw-semibold">Upload Gambar</label>
<input type="file" name="img" id="img" class="form-control" accept="image/*">
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Pilih Sub Kriteria</label>
<div class="border rounded px-3 py-2" style="max-height: 300px; overflow-y: auto;">
@foreach ($kriterias as $kriteria)
<div class="mb-3">
<h6 class="text-primary">{{ $kriteria->nama_kriteria }}</h6>
@foreach ($kriteria->subKriteria as $sub)
<div class="form-check mb-2 ms-3">
<input class="form-check-input" type="checkbox" name="sub_kriterias[]"
value="{{ $sub->id }}" id="sub_{{ $sub->id }}"
data-kriteria="{{ $kriteria->nama_kriteria }}"
onclick="handleSingleChoice(this)">
<label class="form-check-label" for="sub_{{ $sub->id }}">
<strong>{{ $sub->nama_sub }}</strong>
@if ($kriteria->nama_kriteria === 'Harga')
<div class="text-muted small">
Min: Rp {{ number_format($sub->min_harga, 0, ',', '.') }},
Max: Rp {{ number_format($sub->max_harga, 0, ',', '.') }}
</div>
@else
<div class="text-muted small">Nilai: {{ $sub->nilai }}</div>
@endif
</label>
</div>
@endforeach
</div>
@endforeach
{{-- SCRIPT UNTUK MEMILIH 1 checkbox --}}
@push('scripts')
<script>
function handleSingleChoice(checkbox) {
const singleChoiceKriterias = ['Harga', 'Jenis Pakaian'];
const kriteria = checkbox.getAttribute('data-kriteria');
if (singleChoiceKriterias.includes(kriteria)) {
const checkboxes = document.querySelectorAll(`input[data-kriteria="${kriteria}"]`);
checkboxes.forEach(cb => {
if (cb !== checkbox) cb.checked = false;
});
}
}
</script>
@endpush
@stack('scripts')
</div>
</div>
<div class="d-flex justify-content-between pt-3">
<a href="{{ route('admin.pakaian.index') }}" class="btn btn-outline-secondary">
<i class="bi bi-arrow-left"></i> Batal
</a>
<button type="submit" class="btn btn-success">
<i class="bi bi-check-circle"></i> Simpan
</button>
</div>
</form>
</div>
</div>
</div>
@endsection

View File

@ -0,0 +1,107 @@
@extends('admin.layouts.base')
@section('title', 'Edit Pakaian')
@section('content')
<div class="py-4">
<div class="card shadow-sm border-0 mx-auto">
<div class="card-header bg-warning text-white d-flex align-items-center">
<i class="bi bi-pencil-square me-2 fs-5"></i>
<h5 class="mb-0">Edit Pakaian</h5>
</div>
<div class="card-body">
<form action="{{ route('admin.pakaian.update', $pakaian->id) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
<div class="mb-3">
<label class="form-label fw-semibold">Nama Pakaian</label>
<input type="text" name="nama_pakaian" class="form-control"
value="{{ old('nama_pakaian', $pakaian->nama_pakaian) }}" required>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Harga</label>
<div class="input-group">
<span class="input-group-text">Rp</span>
<input type="number" name="harga" class="form-control"
value="{{ old('harga', $pakaian->harga) }}" required>
</div>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Gambar Lama</label><br>
@if ($pakaian->img && Storage::disk('public')->exists($pakaian->img))
<img src="{{ asset('storage/' . $pakaian->img) }}" alt="Gambar Lama"
style="width: 100px; height: 100px; object-fit: cover;" class="border rounded">
@else
<p class="text-muted">Tidak ada gambar</p>
@endif
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Upload Gambar Baru</label>
<input type="file" name="img" class="form-control" accept="image/*">
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Pilih Sub Kriteria</label>
<div class="border rounded px-3 py-2" style="max-height: 300px; overflow-y: auto;">
@foreach ($kriterias as $kriteria)
<div class="mb-3">
<h6 class="text-primary">{{ $kriteria->nama_kriteria }}</h6>
@foreach ($kriteria->subKriteria as $sub)
<div class="form-check mb-2 ms-3">
<input class="form-check-input" type="checkbox" name="sub_kriterias[]"
value="{{ $sub->id }}" id="sub_{{ $sub->id }}"
data-kriteria="{{ $kriteria->nama_kriteria }}"
onclick="handleSingleChoice(this)"
{{ in_array($sub->id, $pakaian->subKriterias->pluck('id')->toArray()) ? 'checked' : '' }}>
<label class="form-check-label" for="sub_{{ $sub->id }}">
<strong>{{ $sub->nama_sub }}</strong>
@if ($kriteria->nama_kriteria === 'Harga')
<div class="text-muted small">
Min: Rp {{ number_format($sub->min_harga, 0, ',', '.') }},
Max: Rp {{ number_format($sub->max_harga, 0, ',', '.') }}
</div>
@else
<div class="text-muted small">Nilai: {{ $sub->nilai }}</div>
@endif
</label>
</div>
@endforeach
</div>
@endforeach
</div>
</div>
@push('scripts')
<script>
function handleSingleChoice(checkbox) {
const singleChoiceKriterias = ['Harga', 'Jenis Pakaian'];
const kriteria = checkbox.getAttribute('data-kriteria');
if (singleChoiceKriterias.includes(kriteria)) {
const checkboxes = document.querySelectorAll(`input[data-kriteria="${kriteria}"]`);
checkboxes.forEach(cb => {
if (cb !== checkbox) cb.checked = false;
});
}
}
</script>
@endpush
@stack('scripts')
<div class="d-flex justify-content-between pt-3">
<a href="{{ route('admin.pakaian.index') }}" class="btn btn-outline-secondary">
<i class="bi bi-arrow-left"></i> Batal
</a>
<button type="submit" class="btn btn-warning text-white">
<i class="bi bi-save"></i> Perbarui
</button>
</div>
</form>
</div>
</div>
</div>
@endsection

View File

@ -11,7 +11,8 @@
}
.btn-biru {
background-color: #007bff; /* biru Bootstrap */
background-color: #007bff;
/* biru Bootstrap */
color: white;
border: none;
padding: 6px 16px;
@ -73,10 +74,10 @@
<h6 class="m-0 font-weight-bold" style="color: #064E3B;">
<i class="bi bi-table"></i> Daftar Data Pakaian
</h6>
<button type="button" class="btn" style="background-color: #064E3B; color: white;" data-bs-toggle="modal"
data-bs-target="#modalTambah">
<a href="{{ route('admin.pakaian.create') }}" class="btn" style="background-color: #064E3B; color: white;">
<i></i> Tambah Data
</button>
</a>
</div>
<div class="card-body">
@ -99,7 +100,8 @@
<div class="d-flex align-items-center" style="gap: 10px;">
<input type="text" name="search" value="{{ request('search') }}"
class="form-control form-control-sm" placeholder="Cari nama pakaian...">
<button type="submit" class="btn btn-success btn-sm" style="background-color: #14532d; border-color: #14532d;">
<button type="submit" class="btn btn-success btn-sm"
style="background-color: #14532d; border-color: #14532d;">
Cari
</button>
</div>
@ -122,7 +124,8 @@
<td>{{ $loop->iteration }}</td>
<td>
@if ($item->img)
<img src="{{ asset($item->img) }}" alt="Gambar" style="width: 100px; height: 100px;">
<img src="{{ asset('storage/' . $item->img) }}" alt="Gambar"
style="width: 100px; height: 100px;">
@else
<span class="text-muted">Tidak ada gambar</span>
@endif
@ -130,18 +133,23 @@
<td>{{ $item->nama_pakaian }}</td>
<td>Rp{{ number_format($item->harga, 0, ',', '.') }}</td>
<td>
<button type="button" class="btn btn-info btn-sm" data-bs-toggle="modal" data-bs-target="#infoModal{{ $item->id }}">
<button type="button" class="btn btn-info btn-sm" data-bs-toggle="modal"
data-bs-target="#infoModal{{ $item->id }}">
<i class="bi bi-info-circle"></i>
</button>
<a href="#" class="btn btn-warning btn-sm edit-button" data-id="{{ $item->id }}" data-bs-toggle="modal" data-bs-target="#modalEdit{{ $item->id }}">
<a href="{{ route('admin.pakaian.edit', $item->id) }}" class="btn btn-warning btn-sm">
<i class="bi bi-pencil-square"></i>
</a>
<button type="button" class="btn btn-danger btn-sm btn-delete" data-id="{{ $item->id }}" data-nama="{{ $item->nama_pakaian }}">
<button type="button" class="btn btn-danger btn-sm btn-delete"
data-id="{{ $item->id }}" data-nama="{{ $item->nama_pakaian }}">
<i class="bi bi-trash"></i>
</button>
<!-- Form Hapus (disembunyikan) -->
<form id="delete-form-{{ $item->id }}" action="{{ route('admin.pakaian.destroy', $item->id) }}" method="POST" style="display: none;">
<form id="delete-form-{{ $item->id }}"
action="{{ route('admin.pakaian.destroy', $item->id) }}" method="POST"
style="display: none;">
@csrf
@method('DELETE')
</form>
@ -162,8 +170,7 @@
<h5 class="modal-title" id="infoModalLabel{{ $item->id }}">
Detail Subkriteria - {{ $item->nama_pakaian }}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"
aria-label="Close"></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<table class="table table-bordered">
@ -196,8 +203,7 @@
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary"
data-bs-dismiss="modal">Tutup</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Tutup</button>
</div>
</div>
</div>
@ -209,52 +215,7 @@
{{ $alternatif->appends(request()->query())->links('vendor.pagination.bootstrap-5') }}
</div>
<!-- Modal Tambah Data Pakaian -->
<div class="modal fade" id="modalTambah" tabindex="-1" aria-labelledby="modalTambahLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered"> <!-- Centered vertically -->
<div class="modal-content rounded-3 shadow-sm border-0">
<!-- Header -->
<div class="modal-header border-bottom-0">
<h5 class="modal-title fw-semibold" id="modalTambahLabel">
<i class="bi bi-plus-circle me-1"></i> Tambah Pakaian
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Tutup"></button>
</div>
<!-- Body -->
<div class="modal-body pt-0">
<form action="{{ route('admin.pakaian.store') }}" method="POST" enctype="multipart/form-data">
@csrf
<div class="mb-3">
<label for="nama_pakaian" class="form-label">Nama Pakaian</label>
<input type="text" class="form-control" name="nama_pakaian" required>
</div>
<div class="mb-3">
<label for="harga" class="form-label">Harga</label>
<input type="number" class="form-control" name="harga" required>
</div>
<div class="mb-3">
<label for="img" class="form-label">Upload Gambar</label>
<input type="file" class="form-control" name="img" accept="image/*">
</div>
<!-- Footer Buttons -->
<div class="modal-footer border-top-0 d-flex justify-content-end gap-2 pt-0">
<button type="button" class="btn" style="background-color: #90ee90; color: black; border-radius: 5px; padding: 6px 20px;" data-bs-dismiss="modal">
<i></i> Batal
</button>
<button type="submit" class="btn" style="background-color: #064e3b; color: white; border-radius: 5px; padding: 6px 20px;">
<i></i> Simpan
</button>
</div>
</form>
</div>
</div>
</div>
</div>
@foreach ($alternatif as $item)
<!-- Modal Edit -->
@ -264,7 +225,8 @@
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalEdit{{ $item->id }}">Edit Data Pakaian</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="btn-close" data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<form method="POST" action="{{ route('admin.pakaian.update', $item->id) }}"
@ -275,7 +237,8 @@
<div class="modal-body">
<!-- Nama Pakaian -->
<div class="mb-3">
<label for="edit_nama_pakaian{{ $item->id }}" class="form-label">Nama Pakaian</label>
<label for="edit_nama_pakaian{{ $item->id }}" class="form-label">Nama
Pakaian</label>
<input type="text" class="form-control" id="edit_nama_pakaian{{ $item->id }}"
name="nama_pakaian" value="{{ $item->nama_pakaian }}" required>
</div>
@ -296,8 +259,9 @@
<!-- Preview Gambar Lama -->
<div class="mb-3">
<label class="form-label">Gambar Lama:</label><br>
<img src="{{ asset($item->img) }}" alt="Gambar Lama"
<img src="{{ asset('storage/' . $item->img) }}" alt="Gambar Lama"
style="width: 100px; height: 100px; object-fit: cover;" class="border rounded">
</div>
</div>

View File

@ -0,0 +1,69 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hasil Rekomendasi</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="{{ asset('css/bootstrap.min.css') }}" rel="stylesheet">
<style>
body {
background-color: #f8f9fa;
}
.card {
border-radius: 1rem;
overflow: hidden;
}
.card-img {
object-fit: cover;
height: 100%;
}
.card-body h5 {
font-weight: 600;
}
.card-body p {
margin-bottom: 0.5rem;
}
</style>
</head>
<body>
<div class="container py-5">
<h2 class="text-center mb-4 fw-bold">Hasil Rekomendasi Pakaian</h2>
@if ($rekomendasi->isEmpty())
<div class="alert alert-warning text-center">
Tidak ada pakaian yang cocok dengan preferensimu.
</div>
@else
@foreach ($rekomendasi as $item)
<div class="card mb-4 shadow-sm">
<div class="row g-0">
<div class="col-md-4">
<img src="{{ asset('storage/' . $item['pakaian']->img) }}" class="img-fluid card-img"
alt="Gambar {{ $item['pakaian']->nama_pakaian }}">
</div>
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title">{{ $item['pakaian']->nama_pakaian }}</h5>
<p class="card-text">Harga: <strong>Rp
{{ number_format($item['pakaian']->harga, 0, ',', '.') }}</strong></p>
<p class="card-text">Skor Kecocokan: <span
class="badge bg-primary">{{ number_format($item['score'], 3) }}</span></p>
</div>
</div>
</div>
</div>
@endforeach
@endif
</div>
<script src="{{ asset('js/bootstrap.bundle.min.js') }}"></script>
</body>
</html>

View File

@ -1,147 +1,65 @@
<section class="py-5" id="pilihpakaian">
<div class="bg-holder d-none d-sm-block" style="background-image:url(assets/img/illustrations/bg.png);background-position:top left;background-size:225px 755px;margin-top:-17.5rem;"></div>
<div class="container my-5">
<form action="{{ route('proses.rekomendasi') }}" method="POST">
<form method="POST" action="{{ route('proses.rekomendasi') }}">
@csrf
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="text-center mb-4">
<h5 class="fw-bold fs-3 fs-lg-5 lh-sm">Pilih Pakaian Anda</h5>
<p class="text-muted">Untuk mendapatkan rekomendasi pakaian yang paling sesuai dengan gaya dan kebutuhan Anda, silakan isi beberapa pertanyaan berikut.</p>
<p class="text-muted">Untuk mendapatkan rekomendasi pakaian yang sesuai dengan preferensi Anda.
</p>
</div>
<div class="card shadow-lg border-0 rounded-4">
<div class="card-body p-5 bg-light">
<!-- Progress Bar -->
<div class="progress mb-4">
<div class="progress-bar bg-primary" role="progressbar" style="width: 20%;" id="progressBar"></div>
<div class="progress-bar bg-primary" role="progressbar" style="width: 20%;"
id="progressBar"></div>
</div>
<!-- STEP 1 -->
<div class="step active" id="step-1">
<h5 class="fw-bold mb-3">Pilih jenis acara yang akan kamu hadiri...</h5>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="acara1" value="Formal" name="jenis_acara">
<label class="form-check-label" for="acara1">Formal</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="acara2" value="NonFormal" name="jenis_acara">
<label class="form-check-label" for="acara2">Non Formal</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="acara3" value="Casual" name="jenis_acara">
<label class="form-check-label" for="acara3">Casual</label>
</div>
<button type="button" class="btn btn-primary" onclick="nextStep()">Selanjutnya</button>
</div>
@php
$steps = [
'Jenis Pakaian' => $subKriteria['Jenis Pakaian'] ?? [],
'Harga' => $subKriteria['Harga'] ?? [],
'Jenis Acara' => $subKriteria['Jenis Acara'] ?? [],
'Warna Pakaian' => $subKriteria['Warna Pakaian'] ?? [],
'Cuaca Acara' => $subKriteria['Cuaca Acara'] ?? [],
'Lokasi Acara' => $subKriteria['Lokasi Acara'] ?? [],
];
$stepIndex = 1;
@endphp
<!-- STEP 2 -->
<div class="step" id="step-2">
<h5 class="fw-bold mb-3">Tentukan rentang harga pakaian...</h5>
@foreach ($steps as $label => $subs)
<div class="step {{ $stepIndex === 1 ? 'active' : '' }}" id="step-{{ $stepIndex }}">
<h5 class="fw-bold mb-3">Pilih {{ strtolower($label) }}...</h5>
@foreach ($subs as $sub)
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="harga1" value="80000-100000" name="harga">
<label class="form-check-label" for="harga1">Rp80.000 - 100.000</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="harga2" value="101000-150000" name="harga">
<label class="form-check-label" for="harga2">Rp101.000 - 150.000</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="harga3" value="151000-200000" name="harga">
<label class="form-check-label" for="harga3">Rp151.000 - 200.000</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="harga4" value="201000-300000" name="harga">
<label class="form-check-label" for="harga4">Rp201.000 - 300.000</label>
</div>
<button type="button" class="btn btn-secondary me-2" onclick="prevStep()">Kembali</button>
<button type="button" class="btn btn-primary" onclick="nextStep()">Selanjutnya</button>
<input class="form-check-input" type="radio" id="sub_{{ $sub->id }}"
value="{{ $sub->id }}"
name="sub_kriteria[{{ $sub->kriteria_id }}]">
<label class="form-check-label" for="sub_{{ $sub->id }}">
{{ $sub->nama_sub }}
</label>
</div>
@endforeach
<!-- STEP 3 -->
<div class="step" id="step-3">
<h5 class="fw-bold mb-3">Pilih jenis pakaian...</h5>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="pakaian1" value="Dress" name="jenis_pakaian">
<label class="form-check-label" for="pakaian1">Dress</label>
<div class="mt-3">
@if ($stepIndex > 1)
<button type="button" class="btn btn-secondary me-2"
onclick="prevStep()">Kembali</button>
@endif
@if ($stepIndex < count($steps))
<button type="button" class="btn btn-primary"
onclick="nextStep()">Selanjutnya</button>
@else
<button type="submit">Lihat Rekomendasi</button>
@endif
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="pakaian2" value="Blouse" name="jenis_pakaian">
<label class="form-check-label" for="pakaian2">Blouse</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="pakaian3" value="Cardigan" name="jenis_pakaian">
<label class="form-check-label" for="pakaian3">Cardigan</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="pakaian4" value="Rok" name="jenis_pakaian">
<label class="form-check-label" for="pakaian4">Rok</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="pakaian5" value="Celana" name="jenis_pakaian">
<label class="form-check-label" for="pakaian5">Celana</label>
</div>
<button type="button" class="btn btn-secondary me-2" onclick="prevStep()">Kembali</button>
<button type="button" class="btn btn-primary" onclick="nextStep()">Selanjutnya</button>
</div>
<!-- STEP 4 -->
<div class="step" id="step-4">
<h5 class="fw-bold mb-3">Pilih warna pakaian...</h5>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="warna1" value="Dingin" name="warna">
<label class="form-check-label" for="warna1">Warna Dingin</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="warna2" value="Panas" name="warna">
<label class="form-check-label" for="warna2">Warna Panas</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="warna3" value="Netral" name="warna">
<label class="form-check-label" for="warna3">Warna Netral</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="warna4" value="Lembut" name="warna">
<label class="form-check-label" for="warna4">Warna Lembut</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="warna5" value="Pastel" name="warna">
<label class="form-check-label" for="warna5">Warna Pastel</label>
</div>
<button type="button" class="btn btn-secondary me-2" onclick="prevStep()">Kembali</button>
<button type="button" class="btn btn-primary" onclick="nextStep()">Selanjutnya</button>
</div>
<!-- STEP 5 -->
<div class="step" id="step-5">
<h5 class="fw-bold mb-3">Pilih kondisi cuaca...</h5>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="cuaca1" value="Cerah" name="cuaca">
<label class="form-check-label" for="cuaca1">Cerah</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="cuaca2" value="Berawan" name="cuaca">
<label class="form-check-label" for="cuaca2">Berawan</label>
</div>
<button type="button" class="btn btn-secondary me-2" onclick="prevStep()">Kembali</button>
<button type="button" class="btn btn-primary" onclick="nextStep()">Selanjutnya</button>
</div>
<!-- STEP 6 -->
<div class="step" id="step-6">
<h5 class="fw-bold mb-3">Pilih lokasi acara...</h5>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="lokasi1" value="Indoor" name="lokasi">
<label class="form-check-label" for="lokasi1">Indoor</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="lokasi2" value="Outdoor" name="lokasi">
<label class="form-check-label" for="lokasi2">Outdoor</label>
</div>
<button type="button" class="btn btn-secondary me-2" onclick="prevStep()">Kembali</button>
<button type="submit" class="btn btn-success">Hasil Rekomendasi</button>
</div>
@php $stepIndex++; @endphp
@endforeach
</div>
</div>
@ -150,9 +68,10 @@
</form>
</div>
<!-- Script Multi-Step -->
<script>
let currentStep = 1;
const totalSteps = 6;
const totalSteps = {{ count($steps) }};
function showStep(step) {
for (let i = 1; i <= totalSteps; i++) {
@ -167,7 +86,7 @@
const isAnswered = Array.from(radios).some(radio => radio.checked);
if (!isAnswered) {
alert("Silakan isi pertanyaan ini terlebih dahulu.");
alert("Silakan pilih salah satu opsi terlebih dahulu.");
return;
}
@ -191,6 +110,4 @@
showStep(currentStep);
</script>
<div id="hasil-rekomendasi" style="margin-top: 20px;"></div>
</section>

View File

@ -27,17 +27,9 @@ use App\Http\Controllers\Admin\ResetPasswordController;
Route::get('/', [HomeController::class, 'index'])->name('home');
Route::post('/proses-rekomendasi', [HomeController::class, 'simpankuisionerdanrekomendasi'])->name('proses.rekomendasi');
Route::post('/proses-rekomendasi', [HomeController::class, 'prosesRekomendasi'])->name('proses.rekomendasi');
// // Jika user sudah login, arahkan ke dashboard
// Route::get('/dashboard', function () {
// if (!Auth::check()) {
// return redirect()->route('login');
// }
// return view('admin.pages.dashboard.index');
// })->name('dashboard');
// Login & Register Routes
Route::get('/login', [AuthController::class, 'showLogin'])->name('login');
Route::post('/login', [AuthController::class, 'login']);
@ -66,8 +58,8 @@ Route::prefix('admin')->middleware(['auth'])->as('admin.')->group(function () {
Route::resource('kriteria', KriteriaController::class);
Route::resource('subkriteria', SubkriteriaController::class);
Route::get('kriteria/subkriteria/{nama_kriteria}', [SubKriteriaShowController::class, 'indexShow'])->name('kriteria.subkriteria.index');
Route::resource('pakaian', PakaianController::class);
Route::resource('penilaian', PenilaianController::class);
Route::resource('user', UserController::class);
});