MIF_E31230680/resources/views/perbandingan_sub/index.blade.php

458 lines
27 KiB
PHP

@extends('layout.app')
@section('content')
@php
$saatyLabels = [
1 => 'Sama Penting (1)',
2 => 'Mendekati Sedikit Lebih Penting (2)',
3 => 'Sedikit Lebih Penting (3)',
4 => 'Mendekati Lebih Penting (4)',
5 => 'Lebih Penting (5)',
6 => 'Mendekati Sangat Penting (6)',
7 => 'Sangat Penting (7)',
8 => 'Mendekati Mutlak Penting (8)',
9 => 'Mutlak Lebih Penting (9)',
];
$bOptions = [
['val' => 1/2, 'lbl' => '1/2', 'name' => 'Mendekati Sedikit Lebih Penting (2)'],
['val' => 1/3, 'lbl' => '1/3', 'name' => 'Sedikit Lebih Penting (3)'],
['val' => 1/4, 'lbl' => '1/4', 'name' => 'Mendekati Lebih Penting (4)'],
['val' => 1/5, 'lbl' => '1/5', 'name' => 'Lebih Penting (5)'],
['val' => 1/6, 'lbl' => '1/6', 'name' => 'Mendekati Sangat Penting (6)'],
['val' => 1/7, 'lbl' => '1/7', 'name' => 'Sangat Penting (7)'],
['val' => 1/8, 'lbl' => '1/8', 'name' => 'Mendekati Mutlak Penting (8)'],
['val' => 1/9, 'lbl' => '1/9', 'name' => 'Mutlak Lebih Penting (9)'],
];
@endphp
<div class="page-header">
<ol class="breadcrumb">
<li class="breadcrumb-item">Home</li>
<li class="breadcrumb-item active">Perbandingan Sub-Kriteria</li>
</ol>
</div>
{{-- Notifikasi --}}
@if (session('success'))
<script>
setTimeout(() => {
Swal.fire('Berhasil!', "{{ session('success') }}", 'success')
}, 100);
</script>
@endif
@if (session('error'))
<script>
setTimeout(() => {
Swal.fire('Gagal!', "{{ session('error') }}", 'error')
}, 100);
</script>
@endif
<div class="row gutters">
{{-- PANEL PEMILIHAN KRITERIA --}}
<div class="col-12 mb-3">
<div class="card shadow-sm border-0">
<div class="card-body bg-light">
<form action="{{ route('perbandingansub.index') }}" method="GET" class="form-inline">
<label class="mr-3 font-weight-bold">Pilih Kriteria Induk:</label>
<select name="kriteria_id" id="selectKriteria" class="form-control select2 mr-3" onchange="this.form.submit()"
style="min-width: 300px;">
<option value="">-- Kembali ke Daftar Status --</option>
@foreach ($kriterias as $k)
<option value="{{ $k->id }}" {{ $selectedKriteriaId == $k->id ? 'selected' : '' }}>
{{ $k->kode }} - {{ $k->nama }}
</option>
@endforeach
</select>
@if ($selectedKriteriaId)
<a href="{{ route('perbandingansub.index') }}" class="btn btn-outline-secondary btn-sm mr-2">
<i class="icon-arrow-left"></i> Kembali
</a>
<a href="{{ route('perbandingansub.detail', ['kriteria_id' => $selectedKriteriaId]) }}"
class="btn btn-outline-info btn-sm font-weight-bold">
<i class="icon-info"></i> Detail Perhitungan
</a>
@endif
</form>
</div>
</div>
</div>
@if (!$selectedKriteriaId)
{{-- VIEW DASHBOARD STATUS (Jika Kriteria Belum Dipilih) --}}
<div class="col-12">
<div class="card shadow-sm border-0">
<div class="card-header bg-dark text-white">
<h6 class="mb-0 font-weight-bold"><i class="icon-list mr-2"></i> Daftar Status Perbandingan Sub-Kriteria</h6>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="table-light">
<tr>
<th class="pl-4">Kode</th>
<th>Nama Kriteria Induk</th>
<th class="text-center">Status Data</th>
<th class="text-center">Jumlah Pakar</th>
<th class="text-center">Aksi</th>
</tr>
</thead>
<tbody>
@foreach ($kriterias as $k)
@php
$checkData = \App\Models\PerbandinganSub::where('kriteria_id', $k->id);
$countPakar = $checkData->distinct('pakar_ke')->count();
@endphp
<tr>
<td class="pl-4"><span class="badge badge-info">{{ $k->kode }}</span></td>
<td class="font-weight-bold text-dark">{{ $k->nama }}</td>
<td class="text-center">
@if ($countPakar > 0)
<span class="badge badge-success px-3"><i class="icon-check"></i> Sudah Diisi</span>
@else
<span class="badge badge-danger px-3"><i class="icon-x"></i> Belum Diisi</span>
@endif
</td>
<td class="text-center font-weight-bold">{{ $countPakar }} Pakar</td>
<td class="text-center pr-4">
<div class="btn-group">
<a href="{{ route('perbandingansub.index', ['kriteria_id' => $k->id]) }}"
class="btn btn-primary btn-sm rounded-pill px-3 mr-1">
Pilih <i class="icon-chevron-right"></i>
</a>
@if ($countPakar > 0)
<a href="{{ route('perbandingansub.detail', ['kriteria_id' => $k->id]) }}"
class="btn btn-outline-info btn-sm rounded-pill"
title="Lihat Tahapan Rumus">
<i class="icon-info"></i>
</a>
@endif
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
@else
{{-- VIEW FORM INPUT SUB-KRITERIA --}}
<div class="col-xl-8 col-lg-8 col-md-12">
<div class="card shadow-sm border-0 h-100">
<div class="card-header bg-success text-white d-flex justify-content-between align-items-center">
<h5 class="mb-0"><i class="icon-shield mr-2"></i> Kuesioner Sub-Kriteria</h5>
<div>
<button type="button" class="btn btn-warning btn-sm font-weight-bold mr-2 shadow-sm"
onclick="unlockInput()"><i class="icon-lock-open"></i> Buka Akses</button>
<button type="button" class="btn btn-light btn-sm font-weight-bold shadow-sm" id="btnAddPakar">
<i class="icon-plus"></i> Pakar Baru
</button>
</div>
</div>
<div class="card-body">
<div id="lockOverlayMsg" class="alert alert-info py-2 small mb-3 text-center">
<i class="icon-info"></i> <strong>Akses Terkunci:</strong> PIN diperlukan untuk sub-kriteria
<b>{{ $kriterias->find($selectedKriteriaId)->nama }}</b>.
</div>
<ul class="nav nav-pills mb-4 bg-light p-2 rounded shadow-sm" id="pakarTab" role="tablist">
@foreach ($existingPakar as $index => $p)
<li class="nav-item">
<a class="nav-link {{ $index == 0 ? 'active' : '' }} font-weight-bold"
id="pakar{{ $p }}-tab" data-toggle="pill"
href="#pakar{{ $p }}" role="tab">Pakar {{ $p }}</a>
</li>
@endforeach
</ul>
<div class="tab-content" id="pakarTabContent">
@foreach ($existingPakar as $index => $pakar)
<div class="tab-pane fade {{ $index == 0 ? 'show active' : '' }}"
id="pakar{{ $pakar }}" role="tabpanel">
{{-- HEADER TAB & TOMBOL HAPUS (Ditambahkan) --}}
<div class="d-flex justify-content-between align-items-center mb-3">
<h6 class="font-weight-bold mb-0 text-success">Form Input Pakar {{ $pakar }}</h6>
@if ($pakar > 1)
<form action="{{ route('perbandingansub.hapus_pakar') }}" method="POST" id="deleteForm{{ $pakar }}">
@csrf
<input type="hidden" name="kriteria_id" value="{{ $selectedKriteriaId }}">
<input type="hidden" name="pakar_dihapus" value="{{ $pakar }}">
<button type="button" class="btn btn-outline-danger btn-sm" onclick="confirmDeletePakar({{ $pakar }})">
<i class="icon-trash"></i> Hapus Pakar {{ $pakar }}
</button>
</form>
@endif
</div>
<form action="{{ route('perbandingansub.simpan') }}" method="POST"
id="formPakar{{ $pakar }}" class="form-perbandingan">
@csrf
<input type="hidden" name="pakar_ke" value="{{ $pakar }}">
<input type="hidden" name="kriteria_id" value="{{ $selectedKriteriaId }}">
<input type="hidden" name="pin_rahasia" class="final-pin-input">
<div class="table-responsive border rounded"
style="max-height: 450px; overflow-y: auto;">
<table class="table table-hover align-middle mb-0">
<thead class="table-light sticky-top shadow-sm">
<tr>
<th class="py-3 px-4 text-dark">Sub Kiri</th>
<th width="350" class="text-center">Skala</th>
<th class="py-3 px-4 text-right text-dark">Sub Kanan</th>
</tr>
</thead>
<tbody>
@foreach ($pairs as $pair)
@php
$savedValue = $allData
->where('pakar_ke', $pakar)
->where('sub_kiri_id', $pair['kiri']->id)
->where('sub_kanan_id', $pair['kanan']->id)
->first()->nilai_skala ?? 1;
@endphp
<tr>
<td class="py-3 px-4 small">
<input type="hidden" name="sub_kiri_id[]" value="{{ $pair['kiri']->id }}">
<span class="badge badge-info mr-1">{{ $pair['kiri']->kode }}</span>
<b>{{ $pair['kiri']->nama_sub }}</b>
</td>
<td>
<select name="nilai_skala[]" class="form-control form-control-sm compare-input shadow-xs" disabled>
<option value="1" {{ $savedValue == 1 ? 'selected' : '' }}>1 - Sama Penting</option>
<optgroup label="Kiri Lebih Penting">
@foreach ($saatyLabels as $val => $label)
@if ($val > 1)
<option value="{{ $val }}" {{ $savedValue == $val ? 'selected' : '' }}>{{ $label }}</option>
@endif
@endforeach
</optgroup>
<optgroup label="Kanan Lebih Penting">
@foreach ($bOptions as $opt)
<option value="{{ $opt['val'] }}" {{ abs($savedValue - $opt['val']) < 0.01 ? 'selected' : '' }}>{{ $opt['lbl'] }} - {{ $opt['name'] }}</option>
@endforeach
</optgroup>
</select>
</td>
<td class="py-3 px-4 text-right small">
<input type="hidden" name="sub_kanan_id[]" value="{{ $pair['kanan']->id }}">
<b>{{ $pair['kanan']->nama_sub }}</b>
<span class="badge badge-info ml-1">{{ $pair['kanan']->kode }}</span>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="text-center mt-4">
<button type="button" class="btn btn-success btn-simpan px-5 font-weight-bold"
onclick="submitWithConfirm('formPakar{{ $pakar }}')" disabled>
<i class="icon-save"></i> Simpan Pakar {{ $pakar }}
</button>
</div>
</form>
</div>
@endforeach
</div>
</div>
</div>
</div>
{{-- PANEL BOBOT LOKAL --}}
<div class="col-xl-4 col-lg-4 col-md-12">
<div class="card shadow-sm border-0 border-top-info" style="border-top: 3px solid #17a2b8;">
<div class="card-header bg-white d-flex justify-content-between align-items-center">
<h5 class="mb-0 text-info font-weight-bold"><i class="icon-pie-chart"></i> Hasil Bobot Lokal</h5>
<a href="{{ route('perbandingansub.detail', ['kriteria_id' => $selectedKriteriaId]) }}"
class="btn btn-outline-info btn-xs rounded-pill" title="Lihat Cara Perhitungan">
<i class="icon-info"></i> Rumus
</a>
</div>
<div class="card-body">
@php $orderedSubs = $subKriterias->sortByDesc('bobot_lokal'); @endphp
@if ($subKriterias->sum('bobot_lokal') > 0)
<div class="alert alert-light border small text-center mb-4">
<b>Kriteria Induk:</b><br>{{ $kriterias->find($selectedKriteriaId)->nama }}
</div>
@foreach ($orderedSubs as $s)
<div class="mb-3">
<div class="d-flex justify-content-between align-items-center mb-1">
<span class="small font-weight-bold text-dark">{{ $s->kode }}</span>
<div class="text-right">
<span class="text-dark font-weight-bold small">{{ number_format($s->bobot_lokal, 4) }}</span>
<span class="badge badge-primary ml-1" style="font-size: 0.6rem;">{{ number_format($s->bobot_lokal * 100, 2) }}%</span>
</div>
</div>
<div class="progress" style="height: 6px; border-radius: 10px;">
<div class="progress-bar bg-info progress-bar-striped" style="width: {{ $s->bobot_lokal * 100 }}%"></div>
</div>
<div class="small text-muted mt-1" style="font-size: 0.7rem;">{{ $s->nama_sub }}</div>
</div>
@endforeach
<hr>
<a href="{{ route('perbandingansub.detail', ['kriteria_id' => $selectedKriteriaId]) }}"
class="btn btn-outline-primary btn-block btn-sm mb-2 font-weight-bold">
<i class="icon-layers"></i> Lihat Tahapan Perhitungan
</a>
<a href="{{ route('perbandingan.index') }}"
class="btn btn-outline-secondary btn-block btn-sm font-weight-bold">Bandingkan Kriteria Global</a>
@else
<div class="text-center py-5 text-muted small">Bobot belum tersedia untuk sub-kriteria ini.</div>
@endif
</div>
</div>
</div>
@endif
</div>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script>
let globalPin = "";
const validPin = "{{ $pinSistem }}";
async function unlockInput() {
const { value: pin } = await Swal.fire({
title: 'Verifikasi PIN',
input: 'password',
inputLabel: 'Masukkan PIN Pakar untuk Membuka Akses',
inputPlaceholder: 'PIN...',
showCancelButton: true,
confirmButtonColor: '#28a745',
});
if (pin) {
if (pin === validPin) {
globalPin = pin;
document.querySelectorAll('.compare-input').forEach(el => el.disabled = false);
document.querySelectorAll('.btn-simpan').forEach(el => el.disabled = false);
document.querySelectorAll('.final-pin-input').forEach(el => el.value = pin);
const msgBox = document.getElementById('lockOverlayMsg');
msgBox.className = "alert alert-success py-2 small mb-3 text-center";
msgBox.innerHTML = '<i class="icon-unlock"></i> <strong>Akses Terbuka:</strong> PIN terverifikasi. Silakan isi data.';
Swal.fire('Akses Dibuka!', 'PIN Benar. Silakan isi data perbandingan.', 'success');
} else {
Swal.fire('Akses Ditolak!', 'PIN yang Anda masukkan SALAH!', 'error');
}
}
}
// PERBAIKAN: Fungsi Submit yang Aman (Sama seperti Kriteria Utama)
async function submitWithConfirm(formId) {
if (!globalPin) {
Swal.fire('Terkunci!', 'Buka akses input dengan PIN terlebih dahulu.', 'error');
return;
}
const { value: confirmPin } = await Swal.fire({
title: 'Konfirmasi PIN',
text: "Masukkan PIN kembali untuk menyimpan data.",
input: 'password',
showCancelButton: true,
confirmButtonColor: '#28a745',
confirmButtonText: 'Verifikasi & Simpan'
});
if (confirmPin === globalPin) {
Swal.fire({
title: 'Memproses...',
text: 'Harap tunggu.',
allowOutsideClick: false,
didOpen: () => {
Swal.showLoading();
}
});
document.getElementById(formId).submit();
} else if (confirmPin) {
Swal.fire('Gagal!', 'PIN salah. Penyimpanan dibatalkan.', 'error');
}
}
function confirmDeletePakar(pakarNum) {
Swal.fire({
title: 'Apakah Anda yakin?',
text: `Seluruh data penilaian Pakar ${pakarNum} akan dihapus permanen!`,
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#3085d6',
confirmButtonText: 'Ya, Hapus!',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
Swal.fire({
title: 'Menghapus...',
allowOutsideClick: false,
didOpen: () => { Swal.showLoading(); }
});
document.getElementById('deleteForm' + pakarNum).submit();
}
});
}
// PERBAIKAN: Fungsi Tambah Pakar Dinamis + CSRF Token Fix
let btnAddPakar = document.getElementById('btnAddPakar');
if(btnAddPakar) {
btnAddPakar.addEventListener('click', function() {
let pakarTab = document.getElementById('pakarTab');
let pakarTabContent = document.getElementById('pakarTabContent');
let nextPakar = pakarTab.querySelectorAll('li').length + 1;
pakarTab.insertAdjacentHTML('beforeend',
`<li class="nav-item"><a class="nav-link font-weight-bold" id="pakar${nextPakar}-tab" data-toggle="pill" href="#pakar${nextPakar}" role="tab">Pakar ${nextPakar}</a></li>`
);
let firstPane = document.querySelector('.tab-pane');
let newPane = firstPane.cloneNode(true);
newPane.id = `pakar${nextPakar}`;
newPane.classList.remove('show', 'active');
// Tarik Token dan ID secara Real-time agar Anti-Error 419
let csrfToken = document.querySelector('input[name="_token"]').value;
let kriteriaId = document.getElementById('selectKriteria').value;
let headerDiv = newPane.querySelector('.d-flex.justify-content-between.align-items-center.mb-3');
headerDiv.innerHTML = `
<h6 class="font-weight-bold mb-0 text-success">Form Input Pakar ${nextPakar}</h6>
<form action="{{ route('perbandingansub.hapus_pakar') }}" method="POST" id="deleteForm${nextPakar}">
<input type="hidden" name="_token" value="${csrfToken}">
<input type="hidden" name="kriteria_id" value="${kriteriaId}">
<input type="hidden" name="pakar_dihapus" value="${nextPakar}">
<button type="button" class="btn btn-outline-danger btn-sm" onclick="confirmDeletePakar(${nextPakar})">
<i class="icon-trash"></i> Hapus Pakar ${nextPakar}
</button>
</form>
`;
let form = newPane.querySelector('form.form-perbandingan');
form.id = `formPakar${nextPakar}`;
newPane.querySelector('input[name="pakar_ke"]').value = nextPakar;
newPane.querySelector('.final-pin-input').value = globalPin;
newPane.querySelectorAll('select').forEach(s => {
s.value = "1";
s.disabled = (globalPin === "");
});
let btn = newPane.querySelector('.btn-simpan');
btn.innerHTML = `<i class="icon-save"></i> Simpan Pakar ${nextPakar}`;
btn.disabled = (globalPin === "");
btn.setAttribute('onclick', `submitWithConfirm('formPakar${nextPakar}')`);
pakarTabContent.appendChild(newPane);
$(`#pakar${nextPakar}-tab`).tab('show');
});
}
</script>
<style>
.compare-input:disabled { background-color: #f8f9fa; cursor: not-allowed; }
.sticky-top { position: sticky; top: 0; background: white; z-index: 10; }
.table-responsive::-webkit-scrollbar { width: 6px; }
.table-responsive::-webkit-scrollbar-thumb { background: #17a2b8; border-radius: 10px; }
</style>
@endsection