454 lines
21 KiB
PHP
454 lines
21 KiB
PHP
@extends('layouts.admin')
|
|
|
|
@section('title', 'Tambah Master Kriteria')
|
|
|
|
@section('content')
|
|
<div class="container-fluid px-4">
|
|
<style>
|
|
.breadcrumb {
|
|
background: transparent;
|
|
border-radius: 8px;
|
|
padding: 0;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.breadcrumb-item a {
|
|
color: #667eea;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.breadcrumb-item.active {
|
|
color: #764ba2;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.page-header {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
color: white;
|
|
padding: 2rem;
|
|
border-radius: 12px;
|
|
margin-bottom: 2rem;
|
|
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.15);
|
|
}
|
|
|
|
.page-header h2 {
|
|
font-size: 2rem;
|
|
font-weight: 700;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.form-card {
|
|
border: none;
|
|
border-radius: 12px;
|
|
box-shadow: 0 4px 15px rgba(0,0,0,0.08);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.section-header {
|
|
color: #667eea;
|
|
font-size: 1.1rem;
|
|
font-weight: 700;
|
|
padding-bottom: 1rem;
|
|
border-bottom: 2px solid #667eea;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.form-control:focus {
|
|
border-color: #667eea;
|
|
box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25);
|
|
}
|
|
|
|
.btn-submit {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
border: none;
|
|
color: white;
|
|
font-weight: 600;
|
|
padding: 0.75rem 1.75rem;
|
|
border-radius: 8px;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.btn-submit:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
|
|
color: white;
|
|
}
|
|
</style>
|
|
|
|
<!-- 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"><a href="{{ route('kriteria.index') }}">Master Kriteria SAW</a></li>
|
|
<li class="breadcrumb-item active">Tambah Data</li>
|
|
</ol>
|
|
</nav>
|
|
|
|
<!-- Page Header -->
|
|
<div class="page-header mb-4">
|
|
<h2 class="mb-2">
|
|
<i class="bi bi-plus-circle me-2"></i>Tambah Master Kriteria SAW
|
|
</h2>
|
|
<p class="mb-0 fs-6">Lengkapi formulir untuk menambahkan kriteria penilaian baru</p>
|
|
</div>
|
|
|
|
<!-- Form Card -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card form-card">
|
|
<div class="card-body p-4">
|
|
<form action="{{ route('kriteria.store') }}" method="POST" id="kriteriaForm">
|
|
@csrf
|
|
|
|
<!-- Informasi Kriteria Section -->
|
|
<div class="mb-4">
|
|
<h5 class="section-header">
|
|
<i class="bi bi-star me-2"></i>Informasi Kriteria
|
|
</h5>
|
|
|
|
<div class="row g-3">
|
|
<!-- Tipe Bisnis -->
|
|
<div class="col-md-12">
|
|
<label for="tipe_bisnis" class="form-label fw-semibold">
|
|
Tipe Bisnis <span class="text-danger">*</span>
|
|
</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text bg-light border-end-0">
|
|
<i class="bi bi-shop" style="color: #667eea;"></i>
|
|
</span>
|
|
<select
|
|
name="tipe_bisnis"
|
|
class="form-select border-start-0 @error('tipe_bisnis') is-invalid @enderror"
|
|
id="tipe_bisnis"
|
|
required
|
|
>
|
|
<option value="">-- Pilih Tipe Bisnis --</option>
|
|
<option value="kontrakan" {{ old('tipe_bisnis') == 'kontrakan' ? 'selected' : '' }}>
|
|
🏠 Kontrakan
|
|
</option>
|
|
<option value="laundry" {{ old('tipe_bisnis') == 'laundry' ? 'selected' : '' }}>
|
|
👕 Laundry
|
|
</option>
|
|
</select>
|
|
@error('tipe_bisnis')
|
|
<div class="invalid-feedback">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
<small class="text-muted">Pilih jenis bisnis untuk kriteria ini</small>
|
|
</div>
|
|
|
|
<!-- Nama Kriteria -->
|
|
<div class="col-md-12">
|
|
<label for="nama_kriteria" class="form-label fw-semibold">
|
|
Nama Kriteria <span class="text-danger">*</span>
|
|
</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text bg-light border-end-0">
|
|
<i class="bi bi-bookmark" style="color: #667eea;"></i>
|
|
</span>
|
|
<input
|
|
type="text"
|
|
name="nama_kriteria"
|
|
class="form-control border-start-0 @error('nama_kriteria') is-invalid @enderror"
|
|
id="nama_kriteria"
|
|
placeholder="Contoh: Harga Sewa, Jarak, Fasilitas"
|
|
value="{{ old('nama_kriteria') }}"
|
|
required
|
|
>
|
|
@error('nama_kriteria')
|
|
<div class="invalid-feedback">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
<small class="text-muted">Masukkan nama kriteria yang jelas dan spesifik</small>
|
|
</div>
|
|
|
|
<!-- Bobot -->
|
|
<div class="col-md-6">
|
|
<label for="bobot" class="form-label fw-semibold">
|
|
Bobot Default / Simulasi <span class="text-danger">*</span>
|
|
</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text bg-light border-end-0">
|
|
<i class="bi bi-speedometer" style="color: #667eea;"></i>
|
|
</span>
|
|
<input
|
|
type="number"
|
|
step="0.01"
|
|
name="bobot"
|
|
class="form-control border-start-0 @error('bobot') is-invalid @enderror"
|
|
id="bobot"
|
|
placeholder="0.25"
|
|
value="{{ old('bobot') }}"
|
|
min="0"
|
|
max="1"
|
|
required
|
|
>
|
|
@error('bobot')
|
|
<div class="invalid-feedback">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
<small class="text-muted">Bobot ini hanya digunakan sebagai bobot default/simulasi untuk validasi perhitungan di web. Bobot utama rekomendasi tetap dipilih oleh user melalui aplikasi mobile.</small>
|
|
</div>
|
|
|
|
<!-- Tipe -->
|
|
<div class="col-md-6">
|
|
<label for="tipe" class="form-label fw-semibold">
|
|
Tipe Kriteria <span class="text-danger">*</span>
|
|
</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text bg-light border-end-0">
|
|
<i class="bi bi-tags" style="color: #667eea;"></i>
|
|
</span>
|
|
<select
|
|
name="tipe"
|
|
class="form-select border-start-0 @error('tipe') is-invalid @enderror"
|
|
id="tipe"
|
|
required
|
|
>
|
|
<option value="">-- Pilih Tipe --</option>
|
|
<option value="Benefit" {{ old('tipe') == 'Benefit' ? 'selected' : '' }}>
|
|
⬆️ Benefit (Semakin tinggi semakin baik)
|
|
</option>
|
|
<option value="Cost" {{ old('tipe') == 'Cost' ? 'selected' : '' }}>
|
|
⬇️ Cost (Semakin rendah semakin baik)
|
|
</option>
|
|
</select>
|
|
@error('tipe')
|
|
<div class="invalid-feedback">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
<small class="text-muted" id="tipeHelp">Pilih tipe sesuai karakteristik kriteria</small>
|
|
</div>
|
|
|
|
<!-- Keterangan -->
|
|
<div class="col-md-12">
|
|
<label for="keterangan" class="form-label fw-semibold">
|
|
Keterangan <span class="text-muted">(Opsional)</span>
|
|
</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text bg-light border-end-0 align-items-start pt-2">
|
|
<i class="bi bi-chat-left-text text-secondary"></i>
|
|
</span>
|
|
<textarea
|
|
name="keterangan"
|
|
class="form-control border-start-0 @error('keterangan') is-invalid @enderror"
|
|
id="keterangan"
|
|
rows="3"
|
|
placeholder="Contoh: Kriteria untuk menilai harga sewa per bulan dalam rupiah"
|
|
>{{ old('keterangan') }}</textarea>
|
|
@error('keterangan')
|
|
<div class="invalid-feedback">{{ $message }}</div>
|
|
@enderror
|
|
</div>
|
|
<small class="text-muted">Deskripsi singkat tentang kriteria ini</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Preview Section -->
|
|
<div class="alert alert-light border mb-4" id="previewSection" style="display: none;">
|
|
<h6 class="fw-bold mb-3">
|
|
<i class="bi bi-eye text-primary me-2"></i>Preview Data
|
|
</h6>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<p class="mb-1"><small class="text-muted">Tipe Bisnis:</small> <span id="previewTipeBisnis" class="fw-semibold">-</span></p>
|
|
<p class="mb-1"><small class="text-muted">Nama Kriteria:</small> <span id="previewNama" class="fw-semibold">-</span></p>
|
|
<p class="mb-1"><small class="text-muted">Bobot:</small> <span id="previewBobot" class="fw-semibold">-</span></p>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<p class="mb-1"><small class="text-muted">Tipe:</small> <span id="previewTipe" class="fw-semibold">-</span></p>
|
|
<p class="mb-1"><small class="text-muted">Keterangan:</small> <span id="previewKeterangan" class="fw-semibold">-</span></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="d-flex gap-2 justify-content-end pt-3 border-top">
|
|
<a href="{{ route('kriteria.index') }}" class="btn btn-light px-4">
|
|
<i class="bi bi-arrow-left me-2"></i>Batal
|
|
</a>
|
|
<button type="submit" class="btn btn-primary px-4">
|
|
<i class="bi bi-check-circle me-2"></i>Simpan Data
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Info Cards -->
|
|
<div class="row mt-3 g-3">
|
|
<div class="col-lg-6">
|
|
<div class="card border-0 bg-success bg-opacity-10">
|
|
<div class="card-body">
|
|
<h6 class="fw-bold mb-2 text-success">
|
|
<i class="bi bi-arrow-up-circle me-2"></i>Kriteria Benefit
|
|
</h6>
|
|
<p class="mb-0 small text-muted">
|
|
Nilai yang lebih tinggi lebih disukai.
|
|
<br>Contoh: Fasilitas, Jumlah Kamar, Kecepatan Layanan
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-6">
|
|
<div class="card border-0 bg-danger bg-opacity-10">
|
|
<div class="card-body">
|
|
<h6 class="fw-bold mb-2 text-danger">
|
|
<i class="bi bi-arrow-down-circle me-2"></i>Kriteria Cost
|
|
</h6>
|
|
<p class="mb-0 small text-muted">
|
|
Nilai yang lebih rendah lebih disukai.
|
|
<br>Contoh: Harga, Jarak, Waktu Tempuh
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tips Card -->
|
|
<div class="card border-0 bg-light mt-3">
|
|
<div class="card-body">
|
|
<div class="d-flex">
|
|
<div class="me-3">
|
|
<i class="bi bi-lightbulb text-warning" style="font-size: 1.5rem;"></i>
|
|
</div>
|
|
<div>
|
|
<h6 class="fw-bold mb-2">Tips Menentukan Bobot:</h6>
|
|
<ul class="mb-0 small text-muted">
|
|
<li>Total bobot semua kriteria disarankan = 1 (atau 100%)</li>
|
|
<li>Berikan bobot lebih besar untuk kriteria yang lebih penting</li>
|
|
<li>Contoh: Jika ada 4 kriteria dengan kepentingan sama, bobot masing-masing = 0.25</li>
|
|
<li>Pastikan tidak ada kriteria dengan bobot 0</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- JavaScript untuk Live Preview & Helper -->
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const form = document.getElementById('kriteriaForm');
|
|
const previewSection = document.getElementById('previewSection');
|
|
|
|
// Live preview
|
|
const tipeBisnisSelect = document.getElementById('tipe_bisnis');
|
|
const namaInput = document.getElementById('nama_kriteria');
|
|
const bobotInput = document.getElementById('bobot');
|
|
const tipeSelect = document.getElementById('tipe');
|
|
const keteranganInput = document.getElementById('keterangan');
|
|
const tipeHelp = document.getElementById('tipeHelp');
|
|
|
|
function updatePreview() {
|
|
const tipeBisnis = tipeBisnisSelect.value;
|
|
const nama = namaInput.value;
|
|
const bobot = bobotInput.value;
|
|
const tipe = tipeSelect.value;
|
|
const keterangan = keteranganInput.value;
|
|
|
|
if (tipeBisnis || nama || bobot || tipe) {
|
|
previewSection.style.display = 'block';
|
|
|
|
let tipeBisnisText = '-';
|
|
if (tipeBisnis === 'kontrakan') {
|
|
tipeBisnisText = '🏠 Kontrakan';
|
|
} else if (tipeBisnis === 'laundry') {
|
|
tipeBisnisText = '👕 Laundry';
|
|
}
|
|
document.getElementById('previewTipeBisnis').textContent = tipeBisnisText;
|
|
|
|
document.getElementById('previewNama').textContent = nama || '-';
|
|
document.getElementById('previewBobot').textContent = bobot ? bobot + ' (atau ' + (parseFloat(bobot) * 100) + '%)' : '-';
|
|
|
|
let tipeBadge = '-';
|
|
if (tipe === 'Benefit') {
|
|
tipeBadge = '⬆️ Benefit';
|
|
} else if (tipe === 'Cost') {
|
|
tipeBadge = '⬇️ Cost';
|
|
}
|
|
document.getElementById('previewTipe').textContent = tipeBadge;
|
|
document.getElementById('previewKeterangan').textContent = keterangan || '-';
|
|
} else {
|
|
previewSection.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
// Update help text based on tipe selection
|
|
tipeSelect.addEventListener('change', function() {
|
|
if (this.value === 'Benefit') {
|
|
tipeHelp.innerHTML = '<strong>Benefit:</strong> Semakin tinggi nilai semakin baik (contoh: Fasilitas, Jumlah Kamar)';
|
|
tipeHelp.classList.remove('text-muted');
|
|
tipeHelp.classList.add('text-success');
|
|
} else if (this.value === 'Cost') {
|
|
tipeHelp.innerHTML = '<strong>Cost:</strong> Semakin rendah nilai semakin baik (contoh: Harga, Jarak)';
|
|
tipeHelp.classList.remove('text-muted');
|
|
tipeHelp.classList.add('text-danger');
|
|
} else {
|
|
tipeHelp.innerHTML = 'Pilih tipe sesuai karakteristik kriteria';
|
|
tipeHelp.classList.remove('text-success', 'text-danger');
|
|
tipeHelp.classList.add('text-muted');
|
|
}
|
|
updatePreview();
|
|
});
|
|
|
|
tipeBisnisSelect.addEventListener('change', updatePreview);
|
|
namaInput.addEventListener('input', updatePreview);
|
|
bobotInput.addEventListener('input', updatePreview);
|
|
keteranganInput.addEventListener('input', updatePreview);
|
|
|
|
// Validate bobot range
|
|
bobotInput.addEventListener('blur', function() {
|
|
const val = parseFloat(this.value);
|
|
if (val < 0) this.value = 0;
|
|
if (val > 1) this.value = 1;
|
|
});
|
|
|
|
// Form validation animation
|
|
form.addEventListener('submit', function(e) {
|
|
if (!form.checkValidity()) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
form.classList.add('was-validated');
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
.form-control:focus,
|
|
.form-select:focus {
|
|
border-color: #86b7fe;
|
|
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.15);
|
|
}
|
|
|
|
.input-group-text {
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.form-control:focus + .input-group-text,
|
|
.form-select:focus + .input-group-text,
|
|
.input-group:focus-within .input-group-text {
|
|
border-color: #86b7fe;
|
|
background-color: #e7f1ff;
|
|
}
|
|
|
|
.card {
|
|
transition: box-shadow 0.3s ease;
|
|
}
|
|
|
|
.was-validated .form-control:invalid,
|
|
.was-validated .form-select:invalid {
|
|
border-color: #dc3545;
|
|
}
|
|
|
|
.was-validated .form-control:valid,
|
|
.was-validated .form-select:valid {
|
|
border-color: #198754;
|
|
}
|
|
</style>
|
|
@endsection
|