MIF_E31230069/spk_kontrakan/resources/views/rekomendasi/index.blade.php

387 lines
18 KiB
PHP

@extends('layouts.app')
@section('title', 'Sistem Rekomendasi Kontrakan')
@section('content')
<div class="container-fluid">
<!-- Breadcrumb -->
<nav aria-label="breadcrumb" class="mb-4">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{{ route('dashboard') }}">Dashboard</a></li>
<li class="breadcrumb-item active">Sistem Rekomendasi</li>
</ol>
</nav>
<!-- Header -->
<div class="row mb-4">
<div class="col-12">
<div class="card border-0 shadow-sm" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);">
<div class="card-body text-white text-center py-5">
<h2 class="mb-2"><i class="bi bi-award me-2"></i>Sistem Rekomendasi Kontrakan</h2>
<p class="mb-0 opacity-75">Temukan kontrakan terbaik sesuai prioritas Anda menggunakan Metode SAW</p>
</div>
</div>
</div>
</div>
<!-- Info Alert -->
@if($kontrakans->isEmpty())
<div class="alert alert-warning" role="alert">
<i class="bi bi-exclamation-triangle me-2"></i>
<strong>Peringatan!</strong> Belum ada data kontrakan. Silakan tambahkan data kontrakan terlebih dahulu.
</div>
@endif
<!-- Errors -->
@if($errors->any())
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<i class="bi bi-x-circle me-2"></i>
<strong>Error!</strong>
<ul class="mb-0 mt-2">
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
@endif
<!-- Main Card -->
<div class="card border-0 shadow-sm">
<div class="card-body p-4">
<!-- Info Box -->
<div class="alert alert-info border-0 mb-4">
<i class="bi bi-info-circle me-2"></i>
<strong>Cara Kerja:</strong> Pilih cara yang sesuai untuk Anda. Sistem akan menampilkan bobot yang digunakan untuk transparansi perhitungan.
</div>
<form action="{{ route('rekomendasi.hitung') }}" method="POST" id="bobotForm">
@csrf
<!-- Mode Selection -->
<div class="row g-3 mb-4">
<div class="col-md-6">
<div class="mode-card" onclick="selectMode('preset')" id="mode-preset">
<div class="card border-2 h-100 cursor-pointer">
<div class="card-body text-center p-4">
<div class="display-4 mb-3">🎯</div>
<h5 class="card-title">Gunakan Profil</h5>
<p class="card-text text-muted">Pilih profil sesuai kebutuhan Anda. Cocok untuk pemula.</p>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="mode-card" onclick="selectMode('manual')" id="mode-manual">
<div class="card border-2 h-100 cursor-pointer">
<div class="card-body text-center p-4">
<div class="display-4 mb-3">⚙️</div>
<h5 class="card-title">Atur Manual</h5>
<p class="card-text text-muted">Sesuaikan prioritas sendiri. Untuk user advanced.</p>
</div>
</div>
</div>
</div>
</div>
<!-- Preset Section -->
<div id="preset-section" class="mb-4">
<h5 class="mb-3"><i class="bi bi-bookmark-star me-2"></i>Pilih Profil Sesuai Kebutuhan</h5>
<div class="row g-3">
<div class="col-md-3 col-sm-6">
<div class="preset-card" onclick="selectPreset('mahasiswa')" id="preset-mahasiswa">
<div class="card h-100 text-center">
<div class="card-body">
<div class="fs-2 mb-2">🎓</div>
<h6 class="card-title">Mahasiswa</h6>
<p class="card-text small text-muted">Prioritas harga terjangkau</p>
</div>
</div>
</div>
</div>
<div class="col-md-3 col-sm-6">
<div class="preset-card" onclick="selectPreset('pekerja')" id="preset-pekerja">
<div class="card h-100 text-center">
<div class="card-body">
<div class="fs-2 mb-2">💼</div>
<h6 class="card-title">Pekerja</h6>
<p class="card-text small text-muted">Prioritas jarak dekat</p>
</div>
</div>
</div>
</div>
<div class="col-md-3 col-sm-6">
<div class="preset-card" onclick="selectPreset('keluarga')" id="preset-keluarga">
<div class="card h-100 text-center">
<div class="card-body">
<div class="fs-2 mb-2">👨‍👩‍👧</div>
<h6 class="card-title">Keluarga</h6>
<p class="card-text small text-muted">Prioritas kamar banyak</p>
</div>
</div>
</div>
</div>
<div class="col-md-3 col-sm-6">
<div class="preset-card" onclick="selectPreset('balanced')" id="preset-balanced">
<div class="card h-100 text-center">
<div class="card-body">
<div class="fs-2 mb-2">⚖️</div>
<h6 class="card-title">Seimbang</h6>
<p class="card-text small text-muted">Semua aspek berimbang</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Manual Section -->
<div id="manual-section" class="mb-4" style="display:none;">
<h5 class="mb-3"><i class="bi bi-sliders me-2"></i>Atur Prioritas Manual</h5>
<!-- Harga -->
<div class="mb-4">
<div class="d-flex justify-content-between mb-2">
<label class="form-label fw-bold">💰 Harga</label>
<span class="badge bg-primary fs-6" id="val_harga">35%</span>
</div>
<input type="range" class="form-range" id="slider_harga" min="10" max="70" value="35" oninput="adjustSliders('harga')">
<div class="d-flex justify-content-between small text-muted">
<span>Min: 10%</span>
<span>Semakin murah semakin baik</span>
<span>Max: 70%</span>
</div>
</div>
<!-- Jarak -->
<div class="mb-4">
<div class="d-flex justify-content-between mb-2">
<label class="form-label fw-bold">📍 Jarak</label>
<span class="badge bg-primary fs-6" id="val_jarak">25%</span>
</div>
<input type="range" class="form-range" id="slider_jarak" min="10" max="70" value="25" oninput="adjustSliders('jarak')">
<div class="d-flex justify-content-between small text-muted">
<span>Min: 10%</span>
<span>Semakin dekat semakin baik</span>
<span>Max: 70%</span>
</div>
</div>
<!-- Kamar -->
<div class="mb-4">
<div class="d-flex justify-content-between mb-2">
<label class="form-label fw-bold">🚪 Jumlah Kamar</label>
<span class="badge bg-primary fs-6" id="val_kamar">20%</span>
</div>
<input type="range" class="form-range" id="slider_kamar" min="10" max="70" value="20" oninput="adjustSliders('kamar')">
<div class="d-flex justify-content-between small text-muted">
<span>Min: 10%</span>
<span>Semakin banyak semakin baik</span>
<span>Max: 70%</span>
</div>
</div>
<!-- Fasilitas -->
<div class="mb-4">
<div class="d-flex justify-content-between mb-2">
<label class="form-label fw-bold"> Fasilitas</label>
<span class="badge bg-primary fs-6" id="val_fasilitas">20%</span>
</div>
<input type="range" class="form-range" id="slider_fasilitas" min="10" max="70" value="20" oninput="adjustSliders('fasilitas')">
<div class="d-flex justify-content-between small text-muted">
<span>Min: 10%</span>
<span>Semakin lengkap semakin baik</span>
<span>Max: 70%</span>
</div>
</div>
</div>
<!-- Bobot Display (Always Visible) -->
<div class="card border-0" style="background: linear-gradient(135deg, #e7f3ff 0%, #d4edff 100%);">
<div class="card-body">
<h5 class="text-center mb-4">📊 Bobot yang Akan Digunakan</h5>
<div class="row g-3 text-center">
<div class="col-6 col-md-3">
<div class="bg-white rounded p-3">
<div class="small text-muted mb-1">💰 Harga</div>
<div class="fs-3 fw-bold text-primary" id="display_harga">35%</div>
</div>
</div>
<div class="col-6 col-md-3">
<div class="bg-white rounded p-3">
<div class="small text-muted mb-1">📍 Jarak</div>
<div class="fs-3 fw-bold text-primary" id="display_jarak">25%</div>
</div>
</div>
<div class="col-6 col-md-3">
<div class="bg-white rounded p-3">
<div class="small text-muted mb-1">🚪 Kamar</div>
<div class="fs-3 fw-bold text-primary" id="display_kamar">20%</div>
</div>
</div>
<div class="col-6 col-md-3">
<div class="bg-white rounded p-3">
<div class="small text-muted mb-1"> Fasilitas</div>
<div class="fs-3 fw-bold text-primary" id="display_fasilitas">20%</div>
</div>
</div>
</div>
<div class="text-center mt-3">
<h4 class="text-success mb-0">Total: <span id="total">100</span>% </h4>
</div>
</div>
</div>
<!-- Hidden Inputs -->
<input type="hidden" name="bobot_harga" id="input_harga" value="35">
<input type="hidden" name="bobot_jarak" id="input_jarak" value="25">
<input type="hidden" name="bobot_kamar" id="input_kamar" value="20">
<input type="hidden" name="bobot_fasilitas" id="input_fasilitas" value="20">
<input type="hidden" name="mode" id="input_mode" value="preset">
<input type="hidden" name="preset_type" id="input_preset" value="">
<!-- Submit Button -->
<div class="d-grid gap-2 mt-4">
<button type="submit" class="btn btn-lg" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white;" {{ $kontrakans->isEmpty() ? 'disabled' : '' }}>
<i class="bi bi-calculator me-2"></i>Hitung Rekomendasi Terbaik
</button>
</div>
</form>
</div>
</div>
</div>
<style>
.mode-card .card, .preset-card .card {
cursor: pointer;
transition: all 0.3s;
}
.mode-card .card:hover, .preset-card .card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 20px rgba(0,0,0,0.15);
}
.mode-card.active .card {
border-color: #667eea !important;
background: linear-gradient(135deg, #e7f3ff 0%, #d4edff 100%);
}
.preset-card.selected .card {
border-color: #28a745 !important;
background: linear-gradient(135deg, #d4edda 0%, #c3e6cb 100%);
}
.form-range::-webkit-slider-thumb {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.form-range::-moz-range-thumb {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
</style>
@endsection
@section('scripts')
<script>
const MIN_BOBOT = 10;
const MAX_BOBOT = 70;
const KRITERIA = ['harga', 'jarak', 'kamar', 'fasilitas'];
let currentMode = 'preset';
// Mode Selection
function selectMode(mode) {
currentMode = mode;
document.querySelectorAll('.mode-card').forEach(el => el.classList.remove('active'));
document.getElementById('mode-' + mode).classList.add('active');
document.getElementById('preset-section').style.display = mode === 'preset' ? 'block' : 'none';
document.getElementById('manual-section').style.display = mode === 'manual' ? 'block' : 'none';
document.getElementById('input_mode').value = mode;
}
// Preset Selection
function selectPreset(type) {
document.querySelectorAll('.preset-card').forEach(el => el.classList.remove('selected'));
document.getElementById('preset-' + type).classList.add('selected');
document.getElementById('input_preset').value = type;
let bobot = {};
switch(type) {
case 'mahasiswa': bobot = {harga: 50, jarak: 20, kamar: 15, fasilitas: 15}; break;
case 'pekerja': bobot = {harga: 20, jarak: 50, kamar: 15, fasilitas: 15}; break;
case 'keluarga': bobot = {harga: 25, jarak: 15, kamar: 45, fasilitas: 15}; break;
case 'balanced': default: bobot = {harga: 35, jarak: 25, kamar: 20, fasilitas: 20}; break;
}
KRITERIA.forEach(k => document.getElementById('slider_' + k).value = bobot[k]);
updateDisplay();
}
// Manual Slider Adjustment
function adjustSliders(changed) {
let changedValue = parseInt(document.getElementById('slider_' + changed).value);
if (changedValue < MIN_BOBOT) changedValue = MIN_BOBOT;
if (changedValue > MAX_BOBOT) changedValue = MAX_BOBOT;
document.getElementById('slider_' + changed).value = changedValue;
const values = {};
KRITERIA.forEach(k => values[k] = parseInt(document.getElementById('slider_' + k).value));
let total = Object.values(values).reduce((a, b) => a + b, 0);
if (total !== 100) {
const diff = total - 100;
const others = KRITERIA.filter(k => k !== changed);
const otherTotal = others.reduce((sum, k) => sum + values[k], 0);
if (otherTotal > 0) {
let distributed = 0;
others.forEach((k, index) => {
const proportion = values[k] / otherTotal;
let reduction = Math.round(diff * proportion);
if (index === others.length - 1) reduction = diff - distributed;
let newVal = values[k] - reduction;
if (newVal < MIN_BOBOT) newVal = MIN_BOBOT;
if (newVal > MAX_BOBOT) newVal = MAX_BOBOT;
document.getElementById('slider_' + k).value = newVal;
distributed += reduction;
});
}
}
updateDisplay();
}
// Update Display
function updateDisplay() {
let total = 0;
KRITERIA.forEach(k => {
const value = parseInt(document.getElementById('slider_' + k).value);
total += value;
document.getElementById('val_' + k).textContent = value + '%';
document.getElementById('display_' + k).textContent = value + '%';
document.getElementById('input_' + k).value = value;
});
document.getElementById('total').textContent = total;
}
// Form Validation
document.getElementById('bobotForm').addEventListener('submit', function(e) {
if (currentMode === 'preset' && !document.getElementById('input_preset').value) {
e.preventDefault();
Swal.fire({icon: 'warning', title: 'Perhatian', text: 'Silakan pilih profil terlebih dahulu!'});
return false;
}
let total = 0;
KRITERIA.forEach(k => total += parseInt(document.getElementById('input_' + k).value));
if (total !== 100) {
e.preventDefault();
Swal.fire({icon: 'error', title: 'Error', text: `Total bobot harus 100%! Sekarang: ${total}%`});
return false;
}
});
// Initialize
selectPreset('balanced');
updateDisplay();
</script>
@endsection