MIF_E31222313/app/Http/Controllers/DashboardController.php

401 lines
15 KiB
PHP

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\SesiKuis;
use App\Models\JawabanKuis;
use App\Models\HasilSaw;
use App\Models\DetailSaw;
use App\Models\Kurikulum;
use App\Models\Kriteria;
use App\Models\Subkriteria;
use App\Models\OpsiSubkriteria;
use App\Models\Alternatif;
use App\Models\Crip;
use App\Models\Siswa;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Models\SystemSetting;
class DashboardController extends Controller
{
public function index(Request $request)
{
$user = Auth::user();
$siswa = Siswa::where('user_id', $user->id)->first();
$kurikulums = Kurikulum::all();
// Ambil kriterias untuk kurikulum pertama secara default
// Ini akan diganti saat user memilih kurikulum
$kriterias = Kriteria::with('subkriterias.opsisubkriterias')
->where('kurikulum_id', $kurikulums->first()->id ?? null)
->get();
// Ambil riwayat perhitungan user
$sesikuisquery = SesiKuis::with(['kurikulum', 'hasilsaw.alternatif'])
->where('user_id', $user->id)
->orderBy('created_at', 'desc');
$hasilitems = HasilSaw::with(['alternatif.mapels', 'alternatif.kurikulum'])
->where('sesi_kuis_id', $request->sesi_id)
->orderBy('peringkat')
->get();
// Filter riwayat jika ada
if ($request->filled('kurikulum_id')) {
$sesikuisquery->where('kurikulum_id', $request->kurikulum_id);
}
if ($request->filled('tanggal')) {
$sesikuisquery->whereDate('created_at', $request->tanggal);
}
$sesikuis = $sesikuisquery->get();
// Cek apakah user pernah melakukan perhitungan sebelumnya
$showHistory = $sesikuis->isNotEmpty();
// Default: tidak ada hasil yang ditampilkan
$hasilsaw = null;
$hasilitems = collect();
// Jika ada parameter sesi_id, tampilkan hasil perhitungan spesifik
if ($request->has('sesi_id')) {
$hasilsaw = SesiKuis::with('kurikulum')->findOrFail($request->sesi_id);
$hasilitems = HasilSaw::with('alternatif')
->where('sesi_kuis_id', $request->sesi_id)
->orderBy('peringkat')
->get();
}
// Cek apakah perhitungan dibuka oleh admin
$quizAccessStatus = SystemSetting::isPerhitunganOpen();
return view('dashboard', compact(
'siswa',
'kurikulums',
'kriterias',
'sesikuis',
'hasilsaw',
'hasilitems',
'showHistory',
'quizAccessStatus'
));
}
/**
* Mendapatkan kriteria berdasarkan kurikulum
*/
public function getKriteriaByKurikulum(Request $request)
{
$kriterias = Kriteria::with('subkriterias.opsisubkriterias')
->where('kurikulum_id', $request->kurikulum_id)
->get();
return response()->json($kriterias);
}
/**
* Menampilkan hasil spesifik
*/
public function lihatHasil($sesiId)
{
// Validasi kepemilikan data
$user = Auth::user();
$sesikuis = SesiKuis::where('id', $sesiId)
->where('user_id', $user->id)
->firstOrFail();
// Redirect ke dashboard dengan parameter sesi_id
return redirect()->route('dashboard', ['sesi_id' => $sesiId]);
}
/**
* Menghapus riwayat perhitungan
*/
public function hapusRiwayat($sesiId)
{
// Validasi kepemilikan data
$user = Auth::user();
$sesikuis = SesiKuis::where('id', $sesiId)
->where('user_id', $user->id)
->firstOrFail();
// Hapus data terkait
DB::beginTransaction();
try {
// Hapus hasil SAW
HasilSaw::where('sesi_kuis_id', $sesiId)->delete();
// Hapus jawaban
JawabanKuis::where('sesi_kuis_id', $sesiId)->delete();
// Hapus sesi kuis
$sesikuis->delete();
DB::commit();
return redirect()->route('dashboard', ['#riwayat'])->with('success', 'Riwayat berhasil dihapus!');
} catch (\Exception $e) {
DB::rollBack();
return redirect()->back()->with('error', 'Gagal menghapus data: ' . $e->getMessage());
}
}
public function submitpenilaian(Request $request)
{
// 1. Validasi input
$request->validate([
'kurikulum_id' => 'required|exists:kurikulums,id',
'nama' => 'required|string|max:255',
'sekolah' => 'required|string|max:255',
'kelas' => 'required|string|max:50',
'jawaban' => 'required|array'
]);
$user = Auth::user();
// 2. Buat sesi kuis baru
$sesikuis = SesiKuis::create([
'user_id' => $user->id,
'kurikulum_id' => $request->kurikulum_id,
'nama' => $request->nama,
'sekolah' => $request->sekolah,
'kelas' => $request->kelas,
]);
// 3. Simpan semua jawaban pengguna
foreach ($request->jawaban as $subkriteria_id => $opsi_dipilih) {
JawabanKuis::create([
'sesi_kuis_id' => $sesikuis->id,
'subkriteria_id' => $subkriteria_id,
'opsi_dipilih' => $opsi_dipilih
]);
}
// 4. HITUNG SAW - Bagian ini yang melakukan perhitungan
$this->hitungSAW($sesikuis);
// 5. Mark session as completed
$sesikuis->selesai_pada = now();
$sesikuis->save();
// Cek jika request adalah AJAX
if ($request->ajax() || $request->wantsJson()) {
// Load relasi yang diperlukan untuk response JSON
$sesikuis->load([
'kurikulum',
'hasilsaw.alternatif',
'hasilsaw' => function($query) {
$query->orderBy('peringkat');
}
]);
return response()->json([
'success' => true,
'hasil' => [
'nama' => $sesikuis->nama,
'sekolah' => $sesikuis->sekolah,
'kelas' => $sesikuis->kelas,
'kurikulum_nama' => $sesikuis->kurikulum->nama,
'tanggal' => $sesikuis->created_at->format('d F Y, H:i'),
'top3' => $sesikuis->hasilsaw->take(3)->map(function($item) {
return [
'peringkat' => $item->peringkat,
'nama' => $item->alternatif->nama,
'skor' => $item->skor_normalisasi,
'deskripsi' => $item->alternatif->deskripsi ?? 'Tidak ada deskripsi',
'total_skor' => $item->total_skor
];
}),
'all' => $sesikuis->hasilsaw->map(function($item) {
return [
'peringkat' => $item->peringkat,
'nama' => $item->alternatif->nama,
'total_skor' => $item->total_skor,
'skor' => $item->skor_normalisasi
];
})
]
]);
}
return redirect()->route('dashboard')
->with('success', 'Penilaian berhasil diselesaikan!')
->with('hasil_id', $sesikuis->id);
}
public function hitungSAW(SesiKuis $sesikuis)
{
// Ambil data yang diperlukan
$alternatifs = Alternatif::where('kurikulum_id', $sesikuis->kurikulum_id)->get();
$jawabankuis = $sesikuis->jawabankuis->keyBy('subkriteria_id');
// Array untuk menyimpan nilai awal dan nilai max/min
$nilaiAwal = [];
$maxNilaiKriteria = [];
$minNilaiKriteria = [];
// LANGKAH 1: Hitung nilai rata-rata per kriteria untuk setiap alternatif
foreach ($alternatifs as $alternatif) {
$nilaiAwal[$alternatif->id] = [];
foreach ($sesikuis->kurikulum->kriterias as $kriteria) {
$total_nilai_subkriteria = 0;
$jumlah_subkriteria_dijawab = 0;
// Hitung nilai untuk setiap subkriteria (soal) dalam kriteria ini
foreach ($kriteria->subkriterias as $subkriteria) {
if (isset($jawabankuis[$subkriteria->id])) {
$opsi_dipilih = $jawabankuis[$subkriteria->id]->opsi_dipilih;
$opsisubkriteria = OpsiSubkriteria::where('subkriteria_id', $subkriteria->id)
->where('alternatif_id', $alternatif->id)
->where('opsi', $opsi_dipilih)
->with('crips')
->first();
if ($opsisubkriteria && $opsisubkriteria->crips) {
$nilai_subkriteria = $opsisubkriteria->crips->nilai;
$total_nilai_subkriteria += $nilai_subkriteria;
$jumlah_subkriteria_dijawab++;
}
}
}
// Hitung rata-rata per kriteria
$nilai_kriteria = ($jumlah_subkriteria_dijawab > 0) ?
($total_nilai_subkriteria / $jumlah_subkriteria_dijawab) : 0;
// Simpan nilai kriteria untuk alternatif ini
$nilaiAwal[$alternatif->id][$kriteria->id] = $nilai_kriteria;
// Update nilai max dan min untuk kriteria ini
if (!isset($maxNilaiKriteria[$kriteria->id]) || $nilai_kriteria > $maxNilaiKriteria[$kriteria->id]) {
$maxNilaiKriteria[$kriteria->id] = $nilai_kriteria;
}
if (!isset($minNilaiKriteria[$kriteria->id]) || $nilai_kriteria < $minNilaiKriteria[$kriteria->id]) {
$minNilaiKriteria[$kriteria->id] = $nilai_kriteria;
}
}
}
// LANGKAH 2: Normalisasi dan hitung skor total
$skorAlternatif = [];
foreach ($alternatifs as $alternatif) {
$skorAlternatif[$alternatif->id] = [
'total_skor' => 0,
'kriteria_normalisasi' => [],
'kriteria_skor' => []
];
foreach ($sesikuis->kurikulum->kriterias as $kriteria) {
$nilai = $nilaiAwal[$alternatif->id][$kriteria->id];
$max = $maxNilaiKriteria[$kriteria->id];
$min = $minNilaiKriteria[$kriteria->id];
// Normalisasi berdasarkan tipe kriteria
$jenis_kriteria = strtolower($kriteria->tipe ?? 'benefit');
if ($max == $min) {
// Jika semua nilai sama, berikan nilai normalisasi 1.0
$nilai_normalisasi = 1.0;
} else {
if ($jenis_kriteria === 'benefit') {
// Untuk kriteria benefit: Rij = Xij / Max{Xij}
$nilai_normalisasi = ($max > 0) ? ($nilai / $max) : 0;
} else {
// Untuk kriteria cost: Rij = Min{Xij} / Xij
$nilai_normalisasi = ($nilai > 0) ? ($min / $nilai) : 0;
}
}
// Kalikan dengan bobot kriteria
$bobot = floatval($kriteria->bobot);
$skor_dengan_bobot = $nilai_normalisasi * $bobot;
// Simpan nilai normalisasi dan skor mentah
$skorAlternatif[$alternatif->id]['kriteria_normalisasi'][$kriteria->id] = $nilai_normalisasi;
$skorAlternatif[$alternatif->id]['kriteria_skor'][$kriteria->id] = $nilai;
// Tambahkan ke skor total
$skorAlternatif[$alternatif->id]['total_skor'] += $skor_dengan_bobot;
}
// Round total skor di akhir
$skorAlternatif[$alternatif->id]['total_skor'] = round($skorAlternatif[$alternatif->id]['total_skor'], 6);
}
// LANGKAH 3: Urutkan berdasarkan skor (ranking)
uasort($skorAlternatif, function($a, $b) {
return $b['total_skor'] <=> $a['total_skor'];
});
// LANGKAH 4: Simpan hasil ke database
$ranking = 1;
foreach ($skorAlternatif as $alternatif_id => $skorData) {
$hasilsaw = HasilSaw::create([
'sesi_kuis_id' => $sesikuis->id,
'alternatif_id' => $alternatif_id,
'total_skor' => $skorData['total_skor'],
'skor_normalisasi' => $skorData['total_skor'],
'peringkat' => $ranking++
]);
// Simpan detail SAW
$this->simpanDetailSAW($hasilsaw, $sesikuis, $skorData['kriteria_skor'], $skorData['kriteria_normalisasi']);
}
}
public function simpanDetailSAW(HasilSaw $hasilsaw, SesiKuis $sesikuis, array $kriteria_skor, array $kriteria_normalisasi)
{
$jawabankuis = $sesikuis->jawabankuis->keyBy('subkriteria_id');
foreach ($kriteria_skor as $kriteria_id => $skor_rata_rata) {
$kriteria = Kriteria::find($kriteria_id);
$nilai_normalisasi_kriteria = $kriteria_normalisasi[$kriteria_id];
$skor_akhir_kriteria = $nilai_normalisasi_kriteria * $kriteria->bobot;
// Cari subkriteria pertama yang dijawab sebagai representasi
$subkriteria_representatif = null;
$opsi_subkriteria_representatif = null;
foreach ($kriteria->subkriterias as $subkriteria) {
if (isset($jawabankuis[$subkriteria->id])) {
$opsi_dipilih = $jawabankuis[$subkriteria->id]->opsi_dipilih;
$opsisubkriteria = OpsiSubkriteria::where('subkriteria_id', $subkriteria->id)
->where('alternatif_id', $hasilsaw->alternatif_id)
->where('opsi', $opsi_dipilih)
->with('crips')
->first();
if ($opsisubkriteria && $opsisubkriteria->crips) {
$subkriteria_representatif = $subkriteria->id;
$opsi_subkriteria_representatif = $opsisubkriteria->id;
break;
}
}
}
// Simpan jika ada subkriteria representatif
if ($subkriteria_representatif) {
DetailSaw::create([
'hasil_saw_id' => $hasilsaw->id,
'kriteria_id' => $kriteria_id,
'subkriteria_id' => $subkriteria_representatif,
'opsi_subkriteria_id' => $opsi_subkriteria_representatif,
'nilai_normalisasi' => $nilai_normalisasi_kriteria,
'nilai_bobot' => $kriteria->bobot,
'skor_akhir' => round($skor_akhir_kriteria, 6)
]);
}
}
}
}