401 lines
15 KiB
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)
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
} |