535 lines
21 KiB
PHP
535 lines
21 KiB
PHP
@extends('layouts.app')
|
|
@section('title', 'Politeknik Negeri Jember - Manajemen Kriteria')
|
|
@section('topbar', 'Data Kriteria')
|
|
@section('css')
|
|
|
|
<link href="{{ asset('vendor/datatables/dataTables.bootstrap4.min.css') }}" rel="stylesheet">
|
|
<link href="{{ asset('vendor/fontawesome-free/css/all.min.css') }}" rel="stylesheet">
|
|
<style>
|
|
:root {
|
|
--primary:rgb(0, 122, 153);
|
|
--secondary: #858796;
|
|
--success: #1cc88a;
|
|
--danger: #e74a3b;
|
|
--warning: #f6c23e;
|
|
--light: #f8f9fc;
|
|
}
|
|
|
|
.card {
|
|
border: none;
|
|
border-radius: 0.5rem;
|
|
box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15);
|
|
transition: all 0.3s;
|
|
}
|
|
|
|
.card:hover {
|
|
box-shadow: 0 0.5rem 2rem 0 rgba(58, 59, 69, 0.2);
|
|
}
|
|
|
|
.card-header {
|
|
background-color: var(--primary);
|
|
color: white;
|
|
border-radius: 0.5rem 0.5rem 0 0 !important;
|
|
padding: 1rem 1.5rem;
|
|
}
|
|
|
|
.btn-circle {
|
|
width: 35px;
|
|
height: 35px;
|
|
border-radius: 50%;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin: 0 3px;
|
|
transition: all 0.3s;
|
|
}
|
|
|
|
.btn-circle:hover {
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.form-control {
|
|
border-radius: 0.35rem;
|
|
padding: 0.75rem 1rem;
|
|
border: 1px solid #d1d3e2;
|
|
}
|
|
|
|
.form-control:focus {
|
|
border-color: var(--primary);
|
|
box-shadow: 0 0 0 0.2rem rgba(78, 115, 223, 0.25);
|
|
}
|
|
|
|
.badge-benefit {
|
|
background-color: rgba(28, 200, 138, 0.2);
|
|
color: var(--success);
|
|
}
|
|
|
|
.badge-cost {
|
|
background-color: rgba(231, 74, 59, 0.2);
|
|
color: var(--danger);
|
|
}
|
|
|
|
.table {
|
|
border-collapse: separate;
|
|
border-spacing: 0 0.75rem;
|
|
}
|
|
|
|
.table thead th {
|
|
border: none;
|
|
background-color: #f8f9fc;
|
|
color: #5a5c69;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
font-size: 0.75rem;
|
|
}
|
|
|
|
.table tbody tr {
|
|
background-color: white;
|
|
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
|
transition: all 0.3s;
|
|
}
|
|
|
|
.table tbody tr:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.table tbody td {
|
|
vertical-align: middle;
|
|
border-top: none;
|
|
padding: 1rem;
|
|
}
|
|
|
|
.table tbody td:first-child {
|
|
border-radius: 0.35rem 0 0 0.35rem;
|
|
}
|
|
|
|
.table tbody td:last-child {
|
|
border-radius: 0 0.35rem 0.35rem 0;
|
|
}
|
|
|
|
.pagination .page-item.active .page-link {
|
|
background-color: var(--primary);
|
|
border-color: var(--primary);
|
|
}
|
|
|
|
.pagination .page-link {
|
|
color: var(--primary);
|
|
}
|
|
|
|
.invalid-feedback {
|
|
display: block;
|
|
margin-top: 0.25rem;
|
|
font-size: 0.875rem;
|
|
color: var(--danger);
|
|
}
|
|
|
|
.is-invalid {
|
|
border-color: var(--danger) !important;
|
|
}
|
|
|
|
.alert {
|
|
border-radius: 0.35rem;
|
|
border: none;
|
|
}
|
|
|
|
.download-btn {
|
|
transition: all 0.3s;
|
|
}
|
|
|
|
.download-btn:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.1);
|
|
}
|
|
</style>
|
|
@endsection
|
|
|
|
@php
|
|
use App\Models\Kriteria;
|
|
@endphp
|
|
@section('content')
|
|
<div class="container-fluid">
|
|
<!-- Error Alert -->
|
|
@if (session('error'))
|
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
|
<div class="d-flex align-items-center">
|
|
<i class="fas fa-exclamation-circle mr-3"></i>
|
|
<div>
|
|
<strong>Error!</strong> {{ session('error') }}
|
|
</div>
|
|
</div>
|
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
@endif
|
|
|
|
<div class="row">
|
|
<!-- Form Tambah Kriteria -->
|
|
<div class="col-lg-4">
|
|
<div class="card mb-4">
|
|
<div class="card-header d-flex flex-row align-items-center justify-content-between">
|
|
<h6 class="m-0 font-weight-bold text-white">
|
|
<i class="fas fa-plus-circle mr-2"></i>Tambah Kriteria
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<!-- Notifikasi Total Bobot -->
|
|
<div class="alert alert-warning d-flex align-items-center" role="alert">
|
|
<i class="fas fa-info-circle mr-2"></i>
|
|
<div>
|
|
<strong>Perhatian:</strong> Total bobot seluruh kriteria harus berjumlah <strong>1</strong>.
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Notifikasi sukses --}}
|
|
@if (session('success'))
|
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
|
<i class="fas fa-check-circle mr-2"></i> {{ session('success') }}
|
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
|
<span>×</span>
|
|
</button>
|
|
</div>
|
|
@endif
|
|
|
|
{{-- Notifikasi warning --}}
|
|
@if (session('warning'))
|
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
|
<i class="fas fa-exclamation-circle mr-2"></i> {!! session('warning') !!}
|
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
|
<span>×</span>
|
|
</button>
|
|
</div>
|
|
@endif
|
|
|
|
<form id="kriteriaForm" action="{{ route('kriteria.store') }}" method="post">
|
|
@csrf
|
|
<div class="form-group">
|
|
<label for="nama_kriteria" class="font-weight-bold">Nama Kriteria</label>
|
|
<div class="input-group">
|
|
<div class="input-group-prepend">
|
|
<span class="input-group-text bg-light">
|
|
<i class="fas fa-tag text-primary"></i>
|
|
</span>
|
|
</div>
|
|
<input type="text" class="form-control" name="nama_kriteria"
|
|
value="{{ old('nama_kriteria') }}"
|
|
placeholder="Masukkan nama kriteria"
|
|
required>
|
|
@if($errors->has('nama_kriteria'))
|
|
<div class="invalid-feedback d-block">{{ $errors->first('nama_kriteria') }}</div>
|
|
@endif
|
|
</div>
|
|
<div class="invalid-feedback"></div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="attribut" class="font-weight-bold">Attribut Kriteria</label>
|
|
<div class="input-group">
|
|
<div class="input-group-prepend">
|
|
<span class="input-group-text bg-light">
|
|
<i class="fas fa-chart-line text-primary"></i>
|
|
</span>
|
|
</div>
|
|
<select name="attribut" class="form-control py-2" required>
|
|
<option value="benefit" {{ old('attribut') == 'benefit' ? 'selected' : '' }}>benefit</option>
|
|
<option value="cost" {{ old('attribut') == 'cost' ? 'selected' : '' }}>cost</option>
|
|
</select>
|
|
</div>
|
|
<div class="invalid-feedback"></div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="bobot" class="font-weight-bold">Bobot Kriteria (0-1)</label>
|
|
<div class="input-group">
|
|
<div class="input-group-prepend">
|
|
<span class="input-group-text bg-light">
|
|
<i class="fas fa-balance-scale text-primary"></i>
|
|
</span>
|
|
</div>
|
|
<input type="number" step="0.01" min="0" max="1"
|
|
class="form-control" name="bobot" id="bobotInput"
|
|
value="{{ old('bobot') }}"
|
|
placeholder="0.00 - 1.00"
|
|
required>
|
|
</div>
|
|
<div class="invalid-feedback"></div>
|
|
<small id="bobotInfo" class="form-text text-muted mt-1"></small>
|
|
</div>
|
|
|
|
<div class="form-group text-right mt-4">
|
|
<button type="reset" class="btn btn-outline-secondary mr-2" id="resetBtn">
|
|
<i class="fas fa-redo mr-2"></i>Reset
|
|
</button>
|
|
|
|
<button type="submit" class="btn btn-primary px-4" id="saveButton">
|
|
<i class="fas fa-save mr-2"></i>Simpan
|
|
</button>
|
|
</div>
|
|
<input type="hidden" name="confirmed" id="confirmed" value="0">
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tabel List Kriteria -->
|
|
<div class="col-lg-8">
|
|
<div class="card mb-4">
|
|
<div class="card-header d-flex flex-row align-items-center justify-content-between">
|
|
<h6 class="m-0 font-weight-bold text-white">
|
|
<i class="fas fa-list-alt mr-2"></i>Daftar Kriteria
|
|
</h6>
|
|
<a href="{{ url('kriteria/download/pdf') }}" class="btn btn-light download-btn">
|
|
<i class="fas fa-file-pdf mr-2"></i>Download PDF
|
|
</a>
|
|
</div>
|
|
<div class="card-body">
|
|
{{-- Notifikasi Total Bobot --}}
|
|
<div class="mb-3">
|
|
@php
|
|
$totalBobot = round(Kriteria::sum('bobot'), 4);
|
|
$diff = 1 - $totalBobot;
|
|
@endphp
|
|
|
|
@if ($totalBobot < 1)
|
|
<div class="alert alert-warning mt-3">
|
|
⚠️ Total Bobot Saat Ini: <strong>{{ number_format($totalBobot, 2) }}</strong><br>
|
|
Total bobot masih kurang sebesar <strong>{{ number_format(abs($diff), 2) }}</strong>.
|
|
</div>
|
|
@elseif ($totalBobot > 1)
|
|
<div class="alert alert-danger mt-3">
|
|
❌ Total Bobot Saat Ini: <strong>{{ number_format($totalBobot, 2) }}</strong><br>
|
|
Total bobot melebihi batas maksimal. Kelebihan sebesar <strong>{{ number_format(abs($diff), 2) }}</strong>.
|
|
</div>
|
|
@else
|
|
<div class="alert alert-success mt-3">
|
|
✅ Total Bobot Sudah Tepat: <strong>{{ $totalBobot }}</strong>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table" id="DataTable">
|
|
<thead>
|
|
<tr>
|
|
<th width="5%">No</th>
|
|
<th>Nama Kriteria</th>
|
|
<th width="15%">Attribut</th>
|
|
<th width="15%">Bobot</th>
|
|
<th width="15%">Aksi</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@php $no = 1; @endphp
|
|
@foreach ($kriteria as $row)
|
|
<tr>
|
|
<td class="text-center">{{ $no++ }}</td>
|
|
<td>{{ $row->nama_kriteria }}</td>
|
|
<td>
|
|
<span class="badge badge-pill {{ $row->attribut == 'benefit' ? 'badge-benefit' : 'badge-cost' }}">
|
|
{{ ucfirst($row->attribut) }}
|
|
</span>
|
|
</td>
|
|
<td>{{ number_format($row->bobot, 2) }}</td>
|
|
<td class="text-center">
|
|
<a href="{{ route('kriteria.edit', $row->id) }}"
|
|
class="btn btn-circle btn-warning"
|
|
data-toggle="tooltip"
|
|
title="Edit">
|
|
<i class="fas fa-edit"></i>
|
|
</a>
|
|
<button class="btn btn-circle btn-danger delete-btn"
|
|
data-id="{{ $row->id }}"
|
|
data-url="{{ route('kriteria.destroy', $row->id) }}"
|
|
title="Hapus">
|
|
<i class="fas fa-trash-alt"></i>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endsection
|
|
|
|
@section('js')
|
|
<!-- Page level plugins -->
|
|
<script src="{{ asset('vendor/jquery/jquery.min.js') }}"></script>
|
|
<script src="{{ asset('vendor/bootstrap/js/bootstrap.bundle.min.js') }}"></script>
|
|
<script src="{{ asset('vendor/datatables/jquery.dataTables.min.js') }}"></script>
|
|
<script src="{{ asset('vendor/datatables/dataTables.bootstrap4.min.js') }}"></script>
|
|
<script src="{{ asset('js/sweetalert.js') }}"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
|
|
|
<script>
|
|
$(document).ready(function () {
|
|
let currentTotal = {{ $totalBobot ?? 0 }};
|
|
let isConfirmed = false;
|
|
|
|
// Validasi ketika input bobot berubah
|
|
$('#bobotInput').on('input', function () {
|
|
const newBobot = parseFloat($(this).val()) || 0;
|
|
const total = currentTotal + newBobot;
|
|
const roundedTotal = parseFloat(total.toFixed(2));
|
|
|
|
let message = '';
|
|
if (roundedTotal > 1) {
|
|
message = `⚠️ Total bobot akan menjadi ${roundedTotal} (melebihi 1)`;
|
|
$('#bobotInfo').removeClass().addClass('form-text text-danger').text(message);
|
|
} else if (roundedTotal < 1) {
|
|
message = `⚠️ Total bobot akan menjadi ${roundedTotal} (belum 1)`;
|
|
$('#bobotInfo').removeClass().addClass('form-text text-warning').text(message);
|
|
} else {
|
|
message = `✅ Total bobot akan menjadi 1 (tepat)`;
|
|
$('#bobotInfo').removeClass().addClass('form-text text-success').text(message);
|
|
}
|
|
});
|
|
|
|
// Reset form
|
|
$('button[type="reset"]').on('click', function () {
|
|
$('#kriteriaForm')[0].reset();
|
|
$('#bobotInfo').text('').removeClass();
|
|
isConfirmed = false;
|
|
});
|
|
|
|
// Handler submit form
|
|
$('#kriteriaForm').on('submit', function (e) {
|
|
if (isConfirmed) return true;
|
|
|
|
e.preventDefault();
|
|
const newBobot = parseFloat($('#bobotInput').val()) || 0;
|
|
const total = parseFloat((currentTotal + newBobot).toFixed(2));
|
|
|
|
if (total > 1 || total < 1) {
|
|
let pesan = total > 1
|
|
? `Total bobot akan menjadi <strong>${total.toFixed(2)}</strong> (melebihi 1)`
|
|
: `Total bobot akan menjadi <strong>${total.toFixed(2)}</strong> (kurang dari 1)`;
|
|
|
|
|
|
Swal.fire({
|
|
title: 'Konfirmasi Total Bobot',
|
|
html: pesan + '<br>Apakah Anda yakin ingin menyimpan?',
|
|
icon: 'warning',
|
|
showCancelButton: true,
|
|
confirmButtonText: 'Ya, simpan!',
|
|
cancelButtonText: 'Batal',
|
|
confirmButtonColor: '#1cc88a',
|
|
cancelButtonColor: '#e74a3b'
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
isConfirmed = true;
|
|
$('#confirmed').val(1);
|
|
$('#kriteriaForm')[0].submit();
|
|
}
|
|
});
|
|
} else {
|
|
// Total bobot sudah tepat, langsung submit
|
|
isConfirmed = true;
|
|
$('#confirmed').val(1);
|
|
this.submit();
|
|
}
|
|
});
|
|
|
|
// Inisialisasi DataTable
|
|
var table = $('#DataTable').DataTable({
|
|
paging: false,
|
|
searching: true,
|
|
ordering: true,
|
|
info: false,
|
|
language: {
|
|
search: "Cari:",
|
|
zeroRecords: "Tidak ada data yang ditemukan",
|
|
infoEmpty: "Tidak ada data yang tersedia",
|
|
},
|
|
drawCallback: function () {
|
|
initNavbarDropdown();
|
|
}
|
|
});
|
|
|
|
// Navbar Dropdown
|
|
function initNavbarDropdown() {
|
|
$(document).off('click.navbarDropdown');
|
|
|
|
$(document).on('click.navbarDropdown', '.dropdown-toggle', function (e) {
|
|
e.preventDefault();
|
|
e.stopImmediatePropagation();
|
|
|
|
var $dropdown = $(this).closest('.dropdown');
|
|
var isShown = $dropdown.hasClass('show');
|
|
|
|
$('.dropdown').removeClass('show');
|
|
$('.dropdown-menu').removeClass('show');
|
|
|
|
if (!isShown) {
|
|
$dropdown.addClass('show');
|
|
$dropdown.find('.dropdown-menu').addClass('show');
|
|
}
|
|
return false;
|
|
});
|
|
|
|
$(document).on('click.navbarDropdown', function (e) {
|
|
if (!$(e.target).closest('.dropdown').length) {
|
|
$('.dropdown').removeClass('show');
|
|
$('.dropdown-menu').removeClass('show');
|
|
}
|
|
});
|
|
}
|
|
|
|
initNavbarDropdown();
|
|
|
|
// Delete handler
|
|
$('.delete-btn').click(function (e) {
|
|
e.preventDefault();
|
|
const url = $(this).data('url');
|
|
|
|
Swal.fire({
|
|
title: 'Apakah Anda yakin?',
|
|
text: "Data yang dihapus tidak bisa dikembalikan!",
|
|
icon: 'warning',
|
|
showCancelButton: true,
|
|
confirmButtonColor: '#d33',
|
|
cancelButtonColor: '#3085d6',
|
|
confirmButtonText: 'Ya, hapus!',
|
|
cancelButtonText: 'Batal'
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
$.ajax({
|
|
url: url,
|
|
type: 'POST',
|
|
data: {
|
|
'_method': 'DELETE',
|
|
'_token': '{{ csrf_token() }}'
|
|
},
|
|
success: function (response) {
|
|
Swal.fire({
|
|
title: 'Terhapus!',
|
|
text: 'Data berhasil dihapus.',
|
|
icon: 'success',
|
|
timer: 1500,
|
|
showConfirmButton: false
|
|
}).then(() => {
|
|
location.reload();
|
|
});
|
|
},
|
|
error: function (xhr) {
|
|
Swal.fire({
|
|
title: 'Gagal!',
|
|
text: 'Terjadi kesalahan saat menghapus data.',
|
|
icon: 'error',
|
|
confirmButtonText: 'OK'
|
|
});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
@endsection |