E-Learning Gamifikasi SMKN 1 Tapen
|
|
@ -7,16 +7,43 @@
|
|||
use App\Models\Kelas;
|
||||
use App\Models\Mapel;
|
||||
use App\Models\Challenge;
|
||||
use App\Models\Leaderboard;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class AdminController extends Controller {
|
||||
public function dashboard(){
|
||||
$totalGuru = Guru::count();
|
||||
$totalGuru = Guru::count();
|
||||
$totalSiswa = Siswa::count();
|
||||
$totalKelas = Kelas::count();
|
||||
$totalMapel = Mapel::count();
|
||||
$chartData = Kelas::withCount('siswa')->get();
|
||||
$chartData = Kelas::withCount('siswa')->get();
|
||||
$latestChallenges = Challenge::latest()->take(3)->get();
|
||||
return view('admin.dashboard', compact('totalGuru','totalSiswa','totalKelas','totalMapel','chartData','latestChallenges'));
|
||||
|
||||
// Leaderboard top 10
|
||||
$leaderboard = Leaderboard::with(['siswa', 'kelas'])
|
||||
->orderBy('total_exp', 'desc')
|
||||
->take(10)
|
||||
->get()
|
||||
->map(function ($lb, $i) {
|
||||
return [
|
||||
'ranking' => $i + 1,
|
||||
'nama' => optional($lb->siswa)->nama ?? '-',
|
||||
'kelas' => optional($lb->kelas)->nama_kelas ?? '-',
|
||||
'total_exp' => $lb->total_exp,
|
||||
'foto' => optional($lb->siswa)->foto_profil,
|
||||
'semester' => $lb->semester,
|
||||
'tahun' => $lb->tahun_ajaran,
|
||||
];
|
||||
});
|
||||
|
||||
$firstLb = Leaderboard::orderBy('total_exp', 'desc')->first();
|
||||
$semester = $firstLb->semester ?? '-';
|
||||
$tahunAjaran = $firstLb->tahun_ajaran ?? '-';
|
||||
|
||||
return view('admin.dashboard', compact(
|
||||
'totalGuru','totalSiswa','totalKelas','totalMapel',
|
||||
'chartData','latestChallenges',
|
||||
'leaderboard','semester','tahunAjaran'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,188 +4,48 @@
|
|||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Challenge;
|
||||
use App\Models\SoalChallenge;
|
||||
use App\Models\Kelas;
|
||||
use App\Models\Badge;
|
||||
use App\Models\PesertaChallenge;
|
||||
use App\Models\Guru;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ChallengeController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$query = Challenge::with(['kelas', 'soal'])
|
||||
->withCount('soal');
|
||||
{
|
||||
$query = Challenge::with(['guru', 'kelas'])
|
||||
->withCount('soal as soal_count');
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$query->where('judul_challenge', 'like', '%' . $request->search . '%');
|
||||
}
|
||||
|
||||
$challenges = $query->orderBy('created_at', 'desc')
|
||||
->paginate(10)
|
||||
->appends($request->all());
|
||||
|
||||
$kelas = Kelas::orderBy('tingkat')->orderBy('nama_kelas')->get();
|
||||
$badges = Badge::all();
|
||||
|
||||
return view('admin.challenge.index', compact('challenges', 'kelas', 'badges'));
|
||||
// Filter by guru
|
||||
if ($request->filled('id_guru')) {
|
||||
$query->where('id_guru', $request->id_guru);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'judul_challenge' => 'required|string|max:200',
|
||||
'deskripsi' => 'nullable|string',
|
||||
'exp' => 'required|integer|min:0',
|
||||
'tenggat_waktu' => 'required|date|after:now',
|
||||
'durasi_pengerjaan' => 'required|integer|min:1|max:360',
|
||||
'id_kelas' => 'required|array|min:1',
|
||||
'id_kelas.*' => 'exists:kelas,id_kelas',
|
||||
// Soal
|
||||
'pertanyaan' => 'required|array|min:1',
|
||||
'pertanyaan.*' => 'required|string',
|
||||
'opsi_a.*' => 'required|string',
|
||||
'opsi_b.*' => 'required|string',
|
||||
'opsi_c.*' => 'required|string',
|
||||
'opsi_d.*' => 'required|string',
|
||||
'jawaban_benar.*' => 'required|in:A,B,C,D',
|
||||
'exp_per_soal.*' => 'required|integer|min:0',
|
||||
], [
|
||||
'tenggat_waktu.after' => 'Tenggat waktu harus lebih dari sekarang.',
|
||||
'pertanyaan.required' => 'Minimal harus ada 1 soal.',
|
||||
'id_kelas.required' => 'Pilih minimal 1 kelas.',
|
||||
]);
|
||||
|
||||
DB::transaction(function () use ($request) {
|
||||
$admin = Auth::guard('admin')->user();
|
||||
|
||||
$challenge = Challenge::create([
|
||||
'id_admin' => $admin->id_admin,
|
||||
'judul_challenge' => $request->judul_challenge,
|
||||
'deskripsi' => $request->deskripsi,
|
||||
'exp' => $request->exp,
|
||||
'id_badge' => $request->id_badge,
|
||||
'tenggat_waktu' => $request->tenggat_waktu,
|
||||
'durasi_pengerjaan' => $request->durasi_pengerjaan,
|
||||
]);
|
||||
|
||||
// Attach ke kelas
|
||||
$challenge->kelas()->sync($request->id_kelas);
|
||||
|
||||
$challenge->soal()->delete();
|
||||
|
||||
// Simpan soal
|
||||
foreach ($request->pertanyaan as $i => $pertanyaan) {
|
||||
SoalChallenge::create([
|
||||
'id_challenge' => $challenge->id_challenge,
|
||||
'pertanyaan' => $pertanyaan,
|
||||
'opsi_a' => $request->opsi_a[$i],
|
||||
'opsi_b' => $request->opsi_b[$i],
|
||||
'opsi_c' => $request->opsi_c[$i],
|
||||
'opsi_d' => $request->opsi_d[$i],
|
||||
'jawaban_benar' => $request->jawaban_benar[$i],
|
||||
'exp_per_soal' => $request->exp_per_soal[$i],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
return redirect()->route('admin.challenge.index')
|
||||
->with('success', 'Challenge berhasil dibuat!');
|
||||
// Search judul
|
||||
if ($request->filled('search')) {
|
||||
$query->where('judul_challenge', 'like', '%' . $request->search . '%');
|
||||
}
|
||||
|
||||
$challenges = $query->latest()
|
||||
->paginate(10)
|
||||
->appends($request->all()); // ganti withQueryString() → appends()
|
||||
|
||||
$guruList = Guru::orderBy('nama')->get(); // ambil semua guru, pakai model import
|
||||
|
||||
return view('admin.challenge.index', compact('challenges', 'guruList'));
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
$challenge = Challenge::with(['kelas', 'soal'])->findOrFail($id);
|
||||
$challenge = Challenge::with(['kelas', 'soal', 'guru', 'peserta.siswa'])
|
||||
->findOrFail($id);
|
||||
|
||||
return view('admin.challenge.show', compact('challenge'));
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$challenge = Challenge::with(['kelas', 'soal'])->findOrFail($id);
|
||||
$kelas = Kelas::orderBy('tingkat')->orderBy('nama_kelas')->get();
|
||||
$badges = Badge::all();
|
||||
return view('admin.challenge.edit', compact('challenge', 'kelas', 'badges'));
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$challenge = Challenge::findOrFail($id);
|
||||
|
||||
$request->validate([
|
||||
'judul_challenge' => 'required|string|max:200',
|
||||
'deskripsi' => 'nullable|string',
|
||||
'exp' => 'required|integer|min:0',
|
||||
'tenggat_waktu' => 'required|date',
|
||||
'durasi_pengerjaan' => 'required|integer|min:1|max:360',
|
||||
'id_kelas' => 'required|array|min:1',
|
||||
'id_kelas.*' => 'exists:kelas,id_kelas',
|
||||
'pertanyaan' => 'required|array|min:1',
|
||||
'pertanyaan.*' => 'required|string',
|
||||
'opsi_a.*' => 'required|string',
|
||||
'opsi_b.*' => 'required|string',
|
||||
'opsi_c.*' => 'required|string',
|
||||
'opsi_d.*' => 'required|string',
|
||||
'jawaban_benar.*' => 'required|in:A,B,C,D',
|
||||
'exp_per_soal.*' => 'required|integer|min:0',
|
||||
]);
|
||||
|
||||
DB::transaction(function () use ($request, $challenge) {
|
||||
$challenge->update([
|
||||
'judul_challenge' => $request->judul_challenge,
|
||||
'deskripsi' => $request->deskripsi,
|
||||
'exp' => $request->exp,
|
||||
'id_badge' => $request->id_badge,
|
||||
'tenggat_waktu' => $request->tenggat_waktu,
|
||||
'durasi_pengerjaan' => $request->durasi_pengerjaan,
|
||||
]);
|
||||
|
||||
$challenge->kelas()->sync($request->id_kelas);
|
||||
|
||||
// Hapus soal lama, insert ulang
|
||||
SoalChallenge::where('id_challenge', $challenge->id_challenge)->delete();
|
||||
|
||||
foreach ($request->pertanyaan as $i => $pertanyaan) {
|
||||
SoalChallenge::create([
|
||||
'id_challenge' => $challenge->id_challenge,
|
||||
'pertanyaan' => $pertanyaan,
|
||||
'opsi_a' => $request->opsi_a[$i],
|
||||
'opsi_b' => $request->opsi_b[$i],
|
||||
'opsi_c' => $request->opsi_c[$i],
|
||||
'opsi_d' => $request->opsi_d[$i],
|
||||
'jawaban_benar' => $request->jawaban_benar[$i],
|
||||
'exp_per_soal' => $request->exp_per_soal[$i],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
return redirect()->route('admin.challenge.index')
|
||||
->with('success', 'Challenge berhasil diupdate!');
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
Challenge::findOrFail($id)->delete();
|
||||
|
||||
return redirect()->route('admin.challenge.index')
|
||||
->with('success', 'Challenge berhasil dihapus.');
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX — return data challenge untuk modal edit
|
||||
*/
|
||||
public function editData($id)
|
||||
{
|
||||
$challenge = Challenge::with(['kelas', 'soal'])->findOrFail($id);
|
||||
|
||||
return response()->json([
|
||||
'judul_challenge' => $challenge->judul_challenge,
|
||||
'deskripsi' => $challenge->deskripsi,
|
||||
'exp' => $challenge->exp,
|
||||
'tenggat_waktu' => $challenge->tenggat_waktu,
|
||||
'durasi_pengerjaan' => $challenge->durasi_pengerjaan,
|
||||
'kelas' => $challenge->kelas->pluck('id_kelas'),
|
||||
'soal' => $challenge->soal,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -161,10 +161,22 @@ public function downloadPdf(Request $request)
|
|||
}
|
||||
$gurus = $query->get();
|
||||
|
||||
$pdf = Pdf::loadView('admin.guru.pdf', compact('gurus'))
|
||||
->setPaper('a4', 'landscape');
|
||||
// Override DomPDF options langsung
|
||||
$options = new \Dompdf\Options();
|
||||
$options->setChroot(base_path('public'));
|
||||
$options->setIsRemoteEnabled(true);
|
||||
|
||||
return $pdf->download('daftar-guru-' . date('Ymd') . '.pdf');
|
||||
$dompdf = new \Dompdf\Dompdf($options);
|
||||
|
||||
$html = view('admin.guru.pdf', compact('gurus'))->render();
|
||||
$dompdf->loadHtml($html);
|
||||
$dompdf->setPaper('A4', 'landscape');
|
||||
$dompdf->render();
|
||||
|
||||
return response($dompdf->output(), 200, [
|
||||
'Content-Type' => 'application/pdf',
|
||||
'Content-Disposition' => 'attachment; filename="daftar-guru-' . date('Ymd') . '.pdf"',
|
||||
]);
|
||||
}
|
||||
|
||||
public function downloadExcel(Request $request)
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ public function destroy($id_kelas)
|
|||
->with('success', 'Data kelas berhasil dihapus!');
|
||||
}
|
||||
|
||||
public function downloadPdf(Request $request)
|
||||
public function downloadPdf(Request $request)
|
||||
{
|
||||
$query = Kelas::query();
|
||||
if ($request->filled('search')) {
|
||||
|
|
@ -99,11 +99,20 @@ public function downloadPdf(Request $request)
|
|||
->orWhere('id_kelas', 'like', "%$search%");
|
||||
}
|
||||
$kelass = $query->get();
|
||||
|
||||
$pdf = Pdf::loadView('admin.kelas.pdf', compact('kelass'))
|
||||
->setPaper('a4', 'portrait');
|
||||
|
||||
return $pdf->download('daftar-kelas-' . date('Ymd') . '.pdf');
|
||||
|
||||
$options = new \Dompdf\Options();
|
||||
$options->setChroot(base_path('public'));
|
||||
$options->setIsRemoteEnabled(true);
|
||||
|
||||
$dompdf = new \Dompdf\Dompdf($options);
|
||||
$dompdf->loadHtml(view('admin.kelas.pdf', compact('kelass'))->render());
|
||||
$dompdf->setPaper('A4', 'portrait');
|
||||
$dompdf->render();
|
||||
|
||||
return response($dompdf->output(), 200, [
|
||||
'Content-Type' => 'application/pdf',
|
||||
'Content-Disposition' => 'attachment; filename="daftar-kelas-' . date('Ymd') . '.pdf"',
|
||||
]);
|
||||
}
|
||||
|
||||
public function downloadExcel(Request $request)
|
||||
|
|
|
|||
|
|
@ -7,9 +7,72 @@
|
|||
use App\Models\Kelas;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class LeaderboardController extends Controller
|
||||
{
|
||||
private function hitungExpSiswa(\App\Models\Siswa $s, Carbon $now): int
|
||||
{
|
||||
// ── 1. EXP dari challenge ─────────────────────────────────────────
|
||||
$expChallenge = 0;
|
||||
$pesertaList = DB::table('peserta_challenges')
|
||||
->where('id_siswa', $s->id_siswa)
|
||||
->get();
|
||||
|
||||
foreach ($pesertaList as $peserta) {
|
||||
$jawaban = json_decode($peserta->jawaban, true) ?? [];
|
||||
$soalList = DB::table('soal_challenge')
|
||||
->where('id_challenge', $peserta->id_challenge)
|
||||
->get();
|
||||
|
||||
foreach ($soalList as $soal) {
|
||||
$jwb = $jawaban[$soal->id_soal] ?? null;
|
||||
if ($jwb && strtoupper($jwb) === strtoupper($soal->jawaban_benar)) {
|
||||
$expChallenge += 1; // +1 per soal benar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── 2. EXP dari tugas ─────────────────────────────────────────────
|
||||
$semuaTugasIdKelas = DB::table('tugas')
|
||||
->join('mengajars', 'tugas.id_mengajar', '=', 'mengajars.id_mengajar')
|
||||
->where('mengajars.id_kelas', $s->id_kelas)
|
||||
->select('tugas.id_tugas', 'tugas.deadline')
|
||||
->get();
|
||||
|
||||
$expTugas = 0;
|
||||
foreach ($semuaTugasIdKelas as $tugas) {
|
||||
$deadline = Carbon::parse($tugas->deadline);
|
||||
$pengumpulan = DB::table('pengumpulan_tugas')
|
||||
->where('id_tugas', $tugas->id_tugas)
|
||||
->where('id_siswa', $s->id_siswa)
|
||||
->first();
|
||||
|
||||
if ($pengumpulan && $pengumpulan->lampiran_tugas !== null) {
|
||||
$tanggalSubmit = Carbon::parse($pengumpulan->tanggal_submit);
|
||||
|
||||
if ($tanggalSubmit->lessThanOrEqualTo($deadline)) {
|
||||
$expTugas += 10; // Tepat waktu → +10
|
||||
} else {
|
||||
$hariTerlambat = $deadline->diffInDays($tanggalSubmit); // ← dibalik
|
||||
|
||||
if ($hariTerlambat <= 1) {
|
||||
$expTugas += 5; // Terlambat ≤ 1 hari → +5
|
||||
} elseif ($hariTerlambat <= 3) {
|
||||
$expTugas += 1; // Terlambat 2-3 hari → +3
|
||||
} else {
|
||||
$expTugas -= 5; // Lewat grace period > 3 hari → dianggap tidak kumpul
|
||||
}
|
||||
}
|
||||
} elseif ($now->greaterThan($deadline)) {
|
||||
// Tidak kumpul sama sekali & deadline lewat → -5
|
||||
$expTugas -= 5;
|
||||
}
|
||||
}
|
||||
|
||||
return max(0, $expChallenge + $expTugas);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$now = Carbon::now();
|
||||
|
|
@ -17,35 +80,38 @@ public function index(Request $request)
|
|||
$tahunAjaran = $request->input('tahun_ajaran', $now->month >= 7
|
||||
? $now->year . '/' . ($now->year + 1)
|
||||
: ($now->year - 1) . '/' . $now->year);
|
||||
$idKelas = $request->input('id_kelas');
|
||||
$idKelas = $request->input('id_kelas');
|
||||
|
||||
$kelasList = Kelas::orderBy('tingkat')->orderBy('nama_kelas')->get();
|
||||
|
||||
$query = Leaderboard::with(['siswa', 'kelas'])
|
||||
->where('semester', $semester)
|
||||
->where('tahun_ajaran', $tahunAjaran);
|
||||
|
||||
if ($idKelas) {
|
||||
$query->where('id_kelas', $idKelas);
|
||||
}
|
||||
|
||||
$leaderboard = $query->orderBy('total_exp', 'desc')->get()
|
||||
->map(function ($item, $i) {
|
||||
return [
|
||||
'ranking' => $i + 1,
|
||||
'nama' => optional($item->siswa)->nama ?? '-',
|
||||
'nisn' => optional($item->siswa)->nisn ?? '-',
|
||||
'nama_kelas' => optional($item->kelas)->nama_kelas ?? '-',
|
||||
'exp' => $item->total_exp,
|
||||
];
|
||||
});
|
||||
|
||||
// Tahun ajaran list untuk dropdown (5 tahun ke belakang)
|
||||
$tahunList = [];
|
||||
for ($y = $now->year; $y >= $now->year - 4; $y--) {
|
||||
$tahunList[] = $y . '/' . ($y + 1);
|
||||
}
|
||||
|
||||
$query = \App\Models\Siswa::with('kelas');
|
||||
if ($idKelas) {
|
||||
$query->where('id_kelas', $idKelas);
|
||||
}
|
||||
$semuaSiswa = $query->get();
|
||||
|
||||
$leaderboard = $semuaSiswa->map(function ($s) use ($now) {
|
||||
return [
|
||||
'id_siswa' => $s->id_siswa,
|
||||
'nama' => $s->nama,
|
||||
'nisn' => $s->nisn,
|
||||
'foto_profil' => $s->foto_profil,
|
||||
'nama_kelas' => $s->kelas->nama_kelas ?? '-',
|
||||
'exp' => $this->hitungExpSiswa($s, $now),
|
||||
];
|
||||
})
|
||||
->sortByDesc('exp')
|
||||
->values()
|
||||
->map(function ($item, $i) {
|
||||
$item['ranking'] = $i + 1;
|
||||
return $item;
|
||||
});
|
||||
|
||||
return view('admin.leaderboard.index', compact(
|
||||
'leaderboard', 'kelasList', 'semester', 'tahunAjaran', 'idKelas', 'tahunList'
|
||||
));
|
||||
|
|
|
|||
|
|
@ -33,6 +33,11 @@ public function loginAdmin(Request $request)
|
|||
])->withInput($request->except('password'));
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest:admin')->only(['showLoginForm', 'loginAdmin']);
|
||||
}
|
||||
|
||||
public function logout(Request $request)
|
||||
{
|
||||
Auth::guard('admin')->logout();
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ public function destroy($id)
|
|||
->with('success', 'Data mata pelajaran berhasil dihapus!');
|
||||
}
|
||||
|
||||
public function downloadPdf(Request $request)
|
||||
public function downloadPdf(Request $request)
|
||||
{
|
||||
$query = Mapel::with('kelas');
|
||||
if ($request->filled('search')) {
|
||||
|
|
@ -145,11 +145,20 @@ public function downloadPdf(Request $request)
|
|||
});
|
||||
}
|
||||
$mapels = $query->get();
|
||||
|
||||
$pdf = Pdf::loadView('admin.mapel.pdf', compact('mapels'))
|
||||
->setPaper('a4', 'portrait');
|
||||
|
||||
return $pdf->download('daftar-mapel-' . date('Ymd') . '.pdf');
|
||||
|
||||
$options = new \Dompdf\Options();
|
||||
$options->setChroot(base_path('public'));
|
||||
$options->setIsRemoteEnabled(true);
|
||||
|
||||
$dompdf = new \Dompdf\Dompdf($options);
|
||||
$dompdf->loadHtml(view('admin.mapel.pdf', compact('mapels'))->render());
|
||||
$dompdf->setPaper('A4', 'portrait');
|
||||
$dompdf->render();
|
||||
|
||||
return response($dompdf->output(), 200, [
|
||||
'Content-Type' => 'application/pdf',
|
||||
'Content-Disposition' => 'attachment; filename="daftar-mapel-' . date('Ymd') . '.pdf"',
|
||||
]);
|
||||
}
|
||||
|
||||
public function downloadExcel(Request $request)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Materi;
|
||||
use App\Models\Tugas;
|
||||
use App\Models\PesertaChallenge;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class NotifikasiController extends Controller
|
||||
|
|
@ -41,7 +42,23 @@ public function index()
|
|||
'time_raw'=> $t->created_at->toIso8601String(),
|
||||
]);
|
||||
|
||||
$notifications = $materiBaru->concat($tugasBaru)
|
||||
// Siswa yang mengumpulkan challenge
|
||||
$challengeKumpul = PesertaChallenge::with(['siswa', 'challenge'])
|
||||
->where('waktu_submit', '>=', $since)
|
||||
->orderBy('waktu_submit', 'desc')
|
||||
->get()
|
||||
->map(fn($p) => [
|
||||
'type' => 'challenge',
|
||||
'title' => 'Challenge Dikumpulkan',
|
||||
'message' => optional($p->siswa)->nama . ' mengumpulkan challenge',
|
||||
'sub' => optional($p->challenge)->judul_challenge ?? '-',
|
||||
'time' => Carbon::parse($p->waktu_submit)->diffForHumans(),
|
||||
'time_raw'=> Carbon::parse($p->waktu_submit)->toIso8601String(),
|
||||
]);
|
||||
|
||||
$notifications = $materiBaru
|
||||
->concat($tugasBaru)
|
||||
->concat($challengeKumpul)
|
||||
->sortByDesc('time_raw')
|
||||
->values();
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
|
|
@ -16,47 +17,45 @@ public function edit()
|
|||
return view('admin.profile.edit', compact('admin'));
|
||||
}
|
||||
|
||||
public function updateAjax(Request $request)
|
||||
{
|
||||
$admin = Auth::guard('admin')->user();
|
||||
public function updateAjax(Request $request)
|
||||
{
|
||||
$admin = Auth::guard('admin')->user();
|
||||
|
||||
$request->validate([
|
||||
'username' => 'required|string|max:100|unique:admins,username,' . $admin->id_admin . ',id_admin',
|
||||
'password' => 'nullable|min:6|confirmed',
|
||||
'password_confirmation' => 'nullable',
|
||||
'foto_profil' => 'nullable|image|mimes:jpg,jpeg,png,webp|max:2048',
|
||||
], [
|
||||
'username.required' => 'Username wajib diisi.',
|
||||
'username.unique' => 'Username sudah digunakan.',
|
||||
'password.min' => 'Password minimal 6 karakter.',
|
||||
'password.confirmed' => 'Konfirmasi password tidak cocok.',
|
||||
'foto_profil.image' => 'File harus berupa gambar.',
|
||||
'foto_profil.max' => 'Ukuran foto maksimal 2MB.',
|
||||
]);
|
||||
$request->validate([
|
||||
'password' => 'nullable|min:6|confirmed',
|
||||
'password_confirmation' => 'nullable',
|
||||
'foto_profil' => 'nullable|image|mimes:jpg,jpeg,png,webp|max:2048',
|
||||
], [
|
||||
'password.min' => 'Password minimal 6 karakter.',
|
||||
'password.confirmed' => 'Konfirmasi password tidak cocok.',
|
||||
'foto_profil.image' => 'File harus berupa gambar.',
|
||||
'foto_profil.max' => 'Ukuran foto maksimal 2MB.',
|
||||
]);
|
||||
|
||||
$data = ['username' => $request->username];
|
||||
$data = [];
|
||||
$fotoUrl = null;
|
||||
|
||||
if ($request->filled('password')) {
|
||||
$data['password'] = Hash::make($request->password);
|
||||
}
|
||||
|
||||
$fotoUrl = null;
|
||||
if ($request->hasFile('foto_profil')) {
|
||||
if ($admin->foto_profil && Storage::disk('public')->exists($admin->foto_profil)) {
|
||||
Storage::disk('public')->delete($admin->foto_profil);
|
||||
}
|
||||
$path = $request->file('foto_profil')->store('foto_profil/admin', 'public');
|
||||
$data['foto_profil'] = $path;
|
||||
$fotoUrl = Storage::url($path);
|
||||
}
|
||||
|
||||
$admin->update($data);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Profil berhasil diperbarui!',
|
||||
'foto_url' => $fotoUrl ?? ($admin->foto_profil ? Storage::url($admin->foto_profil) : null),
|
||||
'username' => $admin->fresh()->username,
|
||||
]);
|
||||
if ($request->filled('password')) {
|
||||
$data['password'] = Hash::make($request->password);
|
||||
}
|
||||
|
||||
if ($request->hasFile('foto_profil')) {
|
||||
if ($admin->foto_profil && Storage::disk('public')->exists($admin->foto_profil)) {
|
||||
Storage::disk('public')->delete($admin->foto_profil);
|
||||
}
|
||||
$path = $request->file('foto_profil')->store('foto_profil/admin', 'public');
|
||||
$data['foto_profil'] = $path;
|
||||
$fotoUrl = '/E31230356/storage/app/public/' . $path;
|
||||
}
|
||||
|
||||
if (!empty($data)) {
|
||||
$admin->update($data);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Profil berhasil diperbarui!',
|
||||
'foto_url' => $fotoUrl ?? ($admin->foto_profil ? '/E31230356/storage/app/public/' . $admin->foto_profil : null),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
use App\Models\Kelas;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Barryvdh\DomPDF\Facade\Pdf;
|
||||
|
||||
class SiswaController extends Controller
|
||||
|
|
@ -15,25 +16,21 @@ public function index(Request $request)
|
|||
{
|
||||
$query = Siswa::with('kelas');
|
||||
|
||||
// SEARCH
|
||||
if ($request->has('search')) {
|
||||
if ($request->filled('search')) {
|
||||
$search = $request->search;
|
||||
$query->where('nama', 'like', "%$search%")
|
||||
$query->where(function($q) use ($search) {
|
||||
$q->where('nama', 'like', "%$search%")
|
||||
->orWhere('nisn', 'like', "%$search%");
|
||||
});
|
||||
}
|
||||
|
||||
// FILTER BY KELAS
|
||||
if ($request->has('filter_kelas') && $request->filter_kelas != '') {
|
||||
if ($request->filled('filter_kelas')) {
|
||||
$query->where('id_kelas', $request->filter_kelas);
|
||||
}
|
||||
|
||||
// SHOW PER PAGE
|
||||
$perPage = $request->get('perPage', 10);
|
||||
|
||||
$siswas = $query->paginate($perPage)->appends($request->all());
|
||||
|
||||
// Ambil semua kelas untuk dropdown filter
|
||||
$kelass = Kelas::orderBy('tingkat')->orderBy('nama_kelas')->get();
|
||||
$siswas = $query->paginate($perPage)->appends($request->all());
|
||||
$kelass = Kelas::orderBy('tingkat')->orderBy('nama_kelas')->get();
|
||||
|
||||
return view('admin.siswa.index', compact('siswas', 'kelass'));
|
||||
}
|
||||
|
|
@ -41,31 +38,31 @@ public function index(Request $request)
|
|||
public function store(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'nisn' => 'required|string|max:20|unique:siswas,nisn',
|
||||
'nama' => 'required|string|max:100',
|
||||
'tempat_lahir' => 'required|string|max:50',
|
||||
'nisn' => 'required|string|max:20|unique:siswas,nisn',
|
||||
'nama' => 'required|string|max:100',
|
||||
'tempat_lahir' => 'required|string|max:50',
|
||||
'tanggal_lahir' => 'required|date',
|
||||
'id_kelas' => 'required|exists:kelas,id_kelas',
|
||||
'password' => 'required|string|min:6',
|
||||
'id_kelas' => 'required|exists:kelas,id_kelas',
|
||||
'password' => 'required|string|min:6',
|
||||
], [
|
||||
'nisn.required' => 'NISN wajib diisi',
|
||||
'nisn.unique' => 'NISN sudah terdaftar',
|
||||
'nama.required' => 'Nama wajib diisi',
|
||||
'tempat_lahir.required' => 'Tempat lahir wajib diisi',
|
||||
'nisn.required' => 'NISN wajib diisi',
|
||||
'nisn.unique' => 'NISN sudah terdaftar',
|
||||
'nama.required' => 'Nama wajib diisi',
|
||||
'tempat_lahir.required' => 'Tempat lahir wajib diisi',
|
||||
'tanggal_lahir.required' => 'Tanggal lahir wajib diisi',
|
||||
'id_kelas.required' => 'Kelas wajib dipilih',
|
||||
'id_kelas.exists' => 'Kelas tidak valid',
|
||||
'password.required' => 'Password wajib diisi',
|
||||
'password.min' => 'Password minimal 6 karakter',
|
||||
'id_kelas.required' => 'Kelas wajib dipilih',
|
||||
'id_kelas.exists' => 'Kelas tidak valid',
|
||||
'password.required' => 'Password wajib diisi',
|
||||
'password.min' => 'Password minimal 6 karakter',
|
||||
]);
|
||||
|
||||
Siswa::create([
|
||||
'nisn' => $validated['nisn'],
|
||||
'nama' => $validated['nama'],
|
||||
'tempat_lahir' => $validated['tempat_lahir'],
|
||||
'nisn' => $validated['nisn'],
|
||||
'nama' => $validated['nama'],
|
||||
'tempat_lahir' => $validated['tempat_lahir'],
|
||||
'tanggal_lahir' => $validated['tanggal_lahir'],
|
||||
'id_kelas' => $validated['id_kelas'],
|
||||
'password' => Hash::make($validated['password']),
|
||||
'id_kelas' => $validated['id_kelas'],
|
||||
'password' => Hash::make($validated['password']),
|
||||
]);
|
||||
|
||||
return redirect()->route('admin.siswa.index')
|
||||
|
|
@ -76,28 +73,45 @@ public function update(Request $request, $id)
|
|||
{
|
||||
$siswa = Siswa::findOrFail($id);
|
||||
|
||||
$validated = $request->validate([
|
||||
'nama' => 'required|string|max:100',
|
||||
'tempat_lahir' => 'required|string|max:50',
|
||||
$validator = Validator::make($request->all(), [
|
||||
'nama' => 'required|string|max:100',
|
||||
'tempat_lahir' => 'required|string|max:50',
|
||||
'tanggal_lahir' => 'required|date',
|
||||
'id_kelas' => 'required|exists:kelas,id_kelas',
|
||||
'password' => 'nullable|string|min:6',
|
||||
'id_kelas' => 'required|exists:kelas,id_kelas',
|
||||
'password' => 'nullable|string|min:6',
|
||||
], [
|
||||
'nama.required' => 'Nama wajib diisi',
|
||||
'tempat_lahir.required' => 'Tempat lahir wajib diisi',
|
||||
'nama.required' => 'Nama wajib diisi',
|
||||
'tempat_lahir.required' => 'Tempat lahir wajib diisi',
|
||||
'tanggal_lahir.required' => 'Tanggal lahir wajib diisi',
|
||||
'id_kelas.required' => 'Kelas wajib dipilih',
|
||||
'id_kelas.exists' => 'Kelas tidak valid',
|
||||
'password.min' => 'Password minimal 6 karakter',
|
||||
'id_kelas.required' => 'Kelas wajib dipilih',
|
||||
'id_kelas.exists' => 'Kelas tidak valid',
|
||||
'password.min' => 'Password minimal 6 karakter',
|
||||
]);
|
||||
|
||||
$siswa->nama = $validated['nama'];
|
||||
$siswa->tempat_lahir = $validated['tempat_lahir'];
|
||||
$siswa->tanggal_lahir = $validated['tanggal_lahir'];
|
||||
$siswa->id_kelas = $validated['id_kelas'];
|
||||
if ($validator->fails()) {
|
||||
return redirect()->back()
|
||||
->withErrors($validator)
|
||||
->withInput()
|
||||
->with('error_from', 'edit')
|
||||
// Simpan data siswa yang sedang diedit ke session
|
||||
// supaya JavaScript bisa mengisi form edit secara otomatis
|
||||
->with('edit_siswa', [
|
||||
'id_siswa' => $siswa->id_siswa,
|
||||
'nisn' => $siswa->nisn,
|
||||
'nama' => $request->nama ?? $siswa->nama,
|
||||
'tempat_lahir' => $request->tempat_lahir ?? $siswa->tempat_lahir,
|
||||
'tanggal_lahir' => $request->tanggal_lahir ?? $siswa->tanggal_lahir,
|
||||
'id_kelas' => $request->id_kelas ?? $siswa->id_kelas,
|
||||
]);
|
||||
}
|
||||
|
||||
$siswa->nama = $request->nama;
|
||||
$siswa->tempat_lahir = $request->tempat_lahir;
|
||||
$siswa->tanggal_lahir = $request->tanggal_lahir;
|
||||
$siswa->id_kelas = $request->id_kelas;
|
||||
|
||||
if ($request->filled('password')) {
|
||||
$siswa->password = Hash::make($validated['password']);
|
||||
$siswa->password = Hash::make($request->password);
|
||||
}
|
||||
|
||||
$siswa->save();
|
||||
|
|
@ -116,60 +130,69 @@ public function destroy($id)
|
|||
}
|
||||
|
||||
public function downloadPdf(Request $request)
|
||||
{
|
||||
$query = Siswa::with('kelas');
|
||||
if ($request->filled('search')) {
|
||||
$search = $request->search;
|
||||
$query->where('nama', 'like', "%$search%")
|
||||
->orWhere('nisn', 'like', "%$search%");
|
||||
}
|
||||
if ($request->filled('filter_kelas')) {
|
||||
$query->where('id_kelas', $request->filter_kelas);
|
||||
}
|
||||
$siswas = $query->get();
|
||||
|
||||
$pdf = Pdf::loadView('admin.siswa.pdf', compact('siswas'))
|
||||
->setPaper('a4', 'landscape');
|
||||
|
||||
return $pdf->download('daftar-siswa-' . date('Ymd') . '.pdf');
|
||||
}
|
||||
|
||||
public function downloadExcel(Request $request)
|
||||
{
|
||||
$query = Siswa::with('kelas');
|
||||
if ($request->filled('search')) {
|
||||
$search = $request->search;
|
||||
$query->where('nama', 'like', "%$search%")
|
||||
->orWhere('nisn', 'like', "%$search%");
|
||||
}
|
||||
if ($request->filled('filter_kelas')) {
|
||||
$query->where('id_kelas', $request->filter_kelas);
|
||||
}
|
||||
$siswas = $query->get();
|
||||
|
||||
$filename = 'daftar-siswa-' . date('Ymd') . '.csv';
|
||||
$headers = [
|
||||
'Content-Type' => 'text/csv',
|
||||
'Content-Disposition' => "attachment; filename=\"$filename\"",
|
||||
];
|
||||
|
||||
$callback = function () use ($siswas) {
|
||||
$file = fopen('php://output', 'w');
|
||||
fprintf($file, chr(0xEF).chr(0xBB).chr(0xBF));
|
||||
fputcsv($file, ['No', 'NISN', 'Nama', 'Tempat Lahir', 'Tanggal Lahir', 'Kelas']);
|
||||
foreach ($siswas as $i => $siswa) {
|
||||
fputcsv($file, [
|
||||
$i + 1,
|
||||
$siswa->nisn,
|
||||
$siswa->nama,
|
||||
$siswa->tempat_lahir,
|
||||
\Carbon\Carbon::parse($siswa->tanggal_lahir)->format('d M Y'),
|
||||
$siswa->kelas->tingkat . ' - ' . $siswa->kelas->nama_kelas,
|
||||
]);
|
||||
{
|
||||
$query = Siswa::with('kelas');
|
||||
if ($request->filled('search')) {
|
||||
$search = $request->search;
|
||||
$query->where('nama', 'like', "%$search%")
|
||||
->orWhere('nisn', 'like', "%$search%");
|
||||
}
|
||||
fclose($file);
|
||||
};
|
||||
if ($request->filled('filter_kelas')) {
|
||||
$query->where('id_kelas', $request->filter_kelas);
|
||||
}
|
||||
$siswas = $query->get();
|
||||
|
||||
return response()->stream($callback, 200, $headers);
|
||||
}
|
||||
$options = new \Dompdf\Options();
|
||||
$options->setChroot(base_path('public'));
|
||||
$options->setIsRemoteEnabled(true);
|
||||
|
||||
$dompdf = new \Dompdf\Dompdf($options);
|
||||
$dompdf->loadHtml(view('admin.siswa.pdf', compact('siswas'))->render());
|
||||
$dompdf->setPaper('A4', 'landscape');
|
||||
$dompdf->render();
|
||||
|
||||
return response($dompdf->output(), 200, [
|
||||
'Content-Type' => 'application/pdf',
|
||||
'Content-Disposition' => 'attachment; filename="daftar-siswa-' . date('Ymd') . '.pdf"',
|
||||
]);
|
||||
}
|
||||
|
||||
public function downloadExcel(Request $request)
|
||||
{
|
||||
$query = Siswa::with('kelas');
|
||||
if ($request->filled('search')) {
|
||||
$search = $request->search;
|
||||
$query->where('nama', 'like', "%$search%")
|
||||
->orWhere('nisn', 'like', "%$search%");
|
||||
}
|
||||
if ($request->filled('filter_kelas')) {
|
||||
$query->where('id_kelas', $request->filter_kelas);
|
||||
}
|
||||
$siswas = $query->get();
|
||||
|
||||
$filename = 'daftar-siswa-' . date('Ymd') . '.csv';
|
||||
$headers = [
|
||||
'Content-Type' => 'text/csv',
|
||||
'Content-Disposition' => "attachment; filename=\"$filename\"",
|
||||
];
|
||||
|
||||
$callback = function () use ($siswas) {
|
||||
$file = fopen('php://output', 'w');
|
||||
fprintf($file, chr(0xEF).chr(0xBB).chr(0xBF));
|
||||
fputcsv($file, ['No', 'NISN', 'Nama', 'Tempat Lahir', 'Tanggal Lahir', 'Kelas']);
|
||||
foreach ($siswas as $i => $siswa) {
|
||||
fputcsv($file, [
|
||||
$i + 1,
|
||||
$siswa->nisn,
|
||||
$siswa->nama,
|
||||
$siswa->tempat_lahir,
|
||||
\Carbon\Carbon::parse($siswa->tanggal_lahir)->format('d M Y'),
|
||||
$siswa->kelas->tingkat . ' - ' . $siswa->kelas->nama_kelas,
|
||||
]);
|
||||
}
|
||||
fclose($file);
|
||||
};
|
||||
|
||||
return response()->stream($callback, 200, $headers);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,190 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Guru;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Challenge;
|
||||
use App\Models\SoalChallenge;
|
||||
use App\Models\Kelas;
|
||||
use App\Models\Badge;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ChallengeController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$guru = Auth::guard('guru')->user();
|
||||
|
||||
$query = Challenge::with(['kelas', 'soal'])
|
||||
->withCount('soal')
|
||||
->where('id_guru', $guru->id_guru);
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$query->where('judul_challenge', 'like', '%' . $request->search . '%');
|
||||
}
|
||||
|
||||
$challenges = $query->orderBy('created_at', 'desc')
|
||||
->paginate(10)
|
||||
->appends($request->all());
|
||||
|
||||
$kelas = Kelas::orderBy('tingkat')->orderBy('nama_kelas')->get();
|
||||
$badges = Badge::all();
|
||||
|
||||
return view('guru.challenge.index', compact('challenges', 'kelas', 'badges'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'judul_challenge' => 'required|string|max:200',
|
||||
'deskripsi' => 'nullable|string',
|
||||
'tenggat_waktu' => 'required|date|after:now',
|
||||
'durasi_pengerjaan' => 'required|integer|min:1|max:360',
|
||||
'id_kelas' => 'required|array|min:1',
|
||||
'id_kelas.*' => 'exists:kelas,id_kelas',
|
||||
'pertanyaan' => 'required|array|min:1',
|
||||
'pertanyaan.*' => 'required|string',
|
||||
'opsi_a.*' => 'required|string',
|
||||
'opsi_b.*' => 'required|string',
|
||||
'opsi_c.*' => 'required|string',
|
||||
'opsi_d.*' => 'required|string',
|
||||
'jawaban_benar.*' => 'required|in:A,B,C,D',
|
||||
], [
|
||||
'tenggat_waktu.after' => 'Tenggat waktu harus lebih dari sekarang.',
|
||||
'pertanyaan.required' => 'Minimal harus ada 1 soal.',
|
||||
'id_kelas.required' => 'Pilih minimal 1 kelas.',
|
||||
]);
|
||||
|
||||
DB::transaction(function () use ($request) {
|
||||
$guru = Auth::guard('guru')->user();
|
||||
|
||||
$challenge = Challenge::create([
|
||||
'id_guru' => $guru->id_guru,
|
||||
'judul_challenge' => $request->judul_challenge,
|
||||
'deskripsi' => $request->deskripsi,
|
||||
'id_badge' => $request->id_badge,
|
||||
'tenggat_waktu' => $request->tenggat_waktu,
|
||||
'durasi_pengerjaan' => $request->durasi_pengerjaan,
|
||||
]);
|
||||
|
||||
$challenge->kelas()->sync($request->id_kelas);
|
||||
|
||||
foreach ($request->pertanyaan as $i => $pertanyaan) {
|
||||
SoalChallenge::create([
|
||||
'id_challenge' => $challenge->id_challenge,
|
||||
'pertanyaan' => $pertanyaan,
|
||||
'opsi_a' => $request->opsi_a[$i],
|
||||
'opsi_b' => $request->opsi_b[$i],
|
||||
'opsi_c' => $request->opsi_c[$i],
|
||||
'opsi_d' => $request->opsi_d[$i],
|
||||
'jawaban_benar' => $request->jawaban_benar[$i],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
return redirect()->route('guru.challenge.index')
|
||||
->with('success', 'Challenge berhasil dibuat!');
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
$guru = Auth::guard('guru')->user();
|
||||
$challenge = Challenge::with(['kelas', 'soal'])
|
||||
->where('id_guru', $guru->id_guru)
|
||||
->findOrFail($id);
|
||||
|
||||
return view('guru.challenge.show', compact('challenge'));
|
||||
}
|
||||
|
||||
public function edit($id)
|
||||
{
|
||||
$guru = Auth::guard('guru')->user();
|
||||
$challenge = Challenge::with(['kelas', 'soal'])
|
||||
->where('id_guru', $guru->id_guru)
|
||||
->findOrFail($id);
|
||||
|
||||
$kelas = Kelas::orderBy('tingkat')->orderBy('nama_kelas')->get();
|
||||
$badges = Badge::all();
|
||||
|
||||
return view('guru.challenge.edit', compact('challenge', 'kelas', 'badges'));
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$guru = Auth::guard('guru')->user();
|
||||
$challenge = Challenge::where('id_guru', $guru->id_guru)->findOrFail($id);
|
||||
|
||||
$request->validate([
|
||||
'judul_challenge' => 'required|string|max:200',
|
||||
'deskripsi' => 'nullable|string',
|
||||
'tenggat_waktu' => 'required|date',
|
||||
'durasi_pengerjaan' => 'required|integer|min:1|max:360',
|
||||
'id_kelas' => 'required|array|min:1',
|
||||
'id_kelas.*' => 'exists:kelas,id_kelas',
|
||||
'pertanyaan' => 'required|array|min:1',
|
||||
'pertanyaan.*' => 'required|string',
|
||||
'opsi_a.*' => 'required|string',
|
||||
'opsi_b.*' => 'required|string',
|
||||
'opsi_c.*' => 'required|string',
|
||||
'opsi_d.*' => 'required|string',
|
||||
'jawaban_benar.*' => 'required|in:A,B,C,D',
|
||||
]);
|
||||
|
||||
DB::transaction(function () use ($request, $challenge) {
|
||||
$challenge->update([
|
||||
'judul_challenge' => $request->judul_challenge,
|
||||
'deskripsi' => $request->deskripsi,
|
||||
'id_badge' => $request->id_badge,
|
||||
'tenggat_waktu' => $request->tenggat_waktu,
|
||||
'durasi_pengerjaan' => $request->durasi_pengerjaan,
|
||||
]);
|
||||
|
||||
$challenge->kelas()->sync($request->id_kelas);
|
||||
|
||||
SoalChallenge::where('id_challenge', $challenge->id_challenge)->delete();
|
||||
|
||||
foreach ($request->pertanyaan as $i => $pertanyaan) {
|
||||
SoalChallenge::create([
|
||||
'id_challenge' => $challenge->id_challenge,
|
||||
'pertanyaan' => $pertanyaan,
|
||||
'opsi_a' => $request->opsi_a[$i],
|
||||
'opsi_b' => $request->opsi_b[$i],
|
||||
'opsi_c' => $request->opsi_c[$i],
|
||||
'opsi_d' => $request->opsi_d[$i],
|
||||
'jawaban_benar' => $request->jawaban_benar[$i],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
return redirect()->route('guru.challenge.index')
|
||||
->with('success', 'Challenge berhasil diupdate!');
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
$guru = Auth::guard('guru')->user();
|
||||
Challenge::where('id_guru', $guru->id_guru)->findOrFail($id)->delete();
|
||||
|
||||
return redirect()->route('guru.challenge.index')
|
||||
->with('success', 'Challenge berhasil dihapus.');
|
||||
}
|
||||
|
||||
public function editData($id)
|
||||
{
|
||||
$guru = Auth::guard('guru')->user();
|
||||
$challenge = Challenge::with(['kelas', 'soal'])
|
||||
->where('id_guru', $guru->id_guru)
|
||||
->findOrFail($id);
|
||||
|
||||
return response()->json([
|
||||
'judul_challenge' => $challenge->judul_challenge,
|
||||
'deskripsi' => $challenge->deskripsi,
|
||||
'tenggat_waktu' => $challenge->tenggat_waktu,
|
||||
'durasi_pengerjaan' => $challenge->durasi_pengerjaan,
|
||||
'kelas' => $challenge->kelas->pluck('id_kelas'),
|
||||
'soal' => $challenge->soal,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,9 @@
|
|||
use App\Models\Mengajar;
|
||||
use App\Models\Siswa;
|
||||
use App\Models\Tugas;
|
||||
use App\Models\Leaderboard;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
|
|
@ -21,42 +23,85 @@ public function index()
|
|||
$totalMapel = Mengajar::where('id_guru', $guru->id_guru)
|
||||
->distinct('id_mapel')->count('id_mapel');
|
||||
|
||||
$kelasIds = Mengajar::where('id_guru', $guru->id_guru)
|
||||
->pluck('id_kelas')->unique();
|
||||
$kelasIds = Mengajar::where('id_guru', $guru->id_guru)
|
||||
->pluck('id_kelas')->unique()->values()->toArray(); // fix: toArray()
|
||||
|
||||
$totalSiswa = Siswa::whereIn('id_kelas', $kelasIds)->count();
|
||||
|
||||
// Chart: pengumpulan tugas per tugas (6 tugas terbaru)
|
||||
$idMengajars = Mengajar::where('id_guru', $guru->id_guru)->pluck('id_mengajar');
|
||||
// ── Chart: Grouped Bar ──
|
||||
// Tampilkan semua kombinasi mapel-kelas meskipun belum ada pengumpulan
|
||||
$mengajars = Mengajar::with([
|
||||
'mapel',
|
||||
'kelas',
|
||||
'tugas.pengumpulanTugas' // relasi sudah ditambahkan di model
|
||||
])->where('id_guru', $guru->id_guru)->get();
|
||||
|
||||
$tugasList = Tugas::with(['mengajar.mapel', 'pengumpulanTugas'])
|
||||
->whereIn('id_mengajar', $idMengajars)
|
||||
->latest()->take(6)->get();
|
||||
$chartLabels = [];
|
||||
$chartTepat = [];
|
||||
$chartTerlambat = [];
|
||||
|
||||
$chartLabels = [];
|
||||
$chartSudah = [];
|
||||
$chartBelum = [];
|
||||
foreach ($mengajars as $m) {
|
||||
$namaMapel = optional($m->mapel)->nama_mapel ?? 'Mapel';
|
||||
$namaKelas = optional($m->kelas)->nama_kelas ?? 'Kelas';
|
||||
$labelPendek = (strlen($namaMapel) > 12
|
||||
? substr($namaMapel, 0, 12) . '…'
|
||||
: $namaMapel) . ' · ' . $namaKelas;
|
||||
|
||||
foreach ($tugasList as $tugas) {
|
||||
$namaMapel = optional($tugas->mengajar->mapel)->nama_mapel ?? 'Mapel';
|
||||
$chartLabels[] = strlen($namaMapel) > 14 ? substr($namaMapel, 0, 14) . '…' : $namaMapel;
|
||||
$sudah = $tugas->pengumpulanTugas->count();
|
||||
$chartSudah[] = $sudah;
|
||||
$chartBelum[] = max(0, $totalSiswa - $sudah);
|
||||
$tepat = 0;
|
||||
$terlambat = 0;
|
||||
|
||||
foreach ($m->tugas as $tugas) {
|
||||
foreach ($tugas->pengumpulanTugas as $p) {
|
||||
if ($p->status === 'dikumpulkan') $tepat++;
|
||||
elseif ($p->status === 'terlambat') $terlambat++;
|
||||
}
|
||||
}
|
||||
|
||||
// Selalu push meskipun tepat=0 dan terlambat=0
|
||||
$chartLabels[] = $labelPendek;
|
||||
$chartTepat[] = $tepat;
|
||||
$chartTerlambat[] = $terlambat;
|
||||
}
|
||||
|
||||
// ── Leaderboard ──
|
||||
$leaderboard = Leaderboard::with(['siswa', 'kelas'])
|
||||
->whereIn('id_kelas', $kelasIds) // fix: sudah jadi array
|
||||
->orderBy('total_exp', 'desc')
|
||||
->take(10)
|
||||
->get()
|
||||
->map(function ($lb, $i) {
|
||||
return [
|
||||
'ranking' => $i + 1,
|
||||
'nama' => optional($lb->siswa)->nama ?? '-',
|
||||
'kelas' => optional($lb->kelas)->nama_kelas ?? '-',
|
||||
'total_exp' => $lb->total_exp,
|
||||
'foto' => optional($lb->siswa)->foto_profil,
|
||||
'semester' => $lb->semester,
|
||||
'tahun' => $lb->tahun_ajaran,
|
||||
];
|
||||
});
|
||||
|
||||
$firstLb = Leaderboard::whereIn('id_kelas', $kelasIds)
|
||||
->orderBy('total_exp', 'desc')->first();
|
||||
$semester = $firstLb->semester ?? '-';
|
||||
$tahunAjaran = $firstLb->tahun_ajaran ?? '-';
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$totalKelas = 0;
|
||||
$totalMapel = 0;
|
||||
$totalSiswa = 0;
|
||||
$chartLabels = [];
|
||||
$chartSudah = [];
|
||||
$chartBelum = [];
|
||||
$totalKelas = 0;
|
||||
$totalMapel = 0;
|
||||
$totalSiswa = 0;
|
||||
$chartLabels = [];
|
||||
$chartTepat = [];
|
||||
$chartTerlambat = [];
|
||||
$leaderboard = collect();
|
||||
$semester = '-';
|
||||
$tahunAjaran = '-';
|
||||
}
|
||||
|
||||
return view('guru.dashboard', compact(
|
||||
'totalKelas', 'totalMapel', 'totalSiswa',
|
||||
'chartLabels', 'chartSudah', 'chartBelum'
|
||||
'chartLabels', 'chartTepat', 'chartTerlambat',
|
||||
'leaderboard', 'semester', 'tahunAjaran'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -3,15 +3,79 @@
|
|||
namespace App\Http\Controllers\Guru;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Leaderboard;
|
||||
use App\Models\Kelas;
|
||||
use App\Models\Mengajar;
|
||||
use App\Models\Siswa;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class LeaderboardController extends Controller
|
||||
{
|
||||
private function hitungExpSiswa(int $idSiswa, int $idKelas): int
|
||||
{
|
||||
$now = Carbon::now();
|
||||
|
||||
// ── 1. EXP dari challenge ─────────────────────────────────────────
|
||||
$expChallenge = 0;
|
||||
$pesertaList = DB::table('peserta_challenges')
|
||||
->where('id_siswa', $idSiswa)
|
||||
->get();
|
||||
|
||||
foreach ($pesertaList as $peserta) {
|
||||
$jawaban = json_decode($peserta->jawaban, true) ?? [];
|
||||
$soalList = DB::table('soal_challenge')
|
||||
->where('id_challenge', $peserta->id_challenge)
|
||||
->get();
|
||||
|
||||
foreach ($soalList as $soal) {
|
||||
$jwb = $jawaban[$soal->id_soal] ?? null;
|
||||
if ($jwb && strtoupper($jwb) === strtoupper($soal->jawaban_benar)) {
|
||||
$expChallenge += 1; // +1 per soal benar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── 2. EXP dari tugas ─────────────────────────────────────────────
|
||||
$tugasList = DB::table('tugas')
|
||||
->join('mengajars', 'tugas.id_mengajar', '=', 'mengajars.id_mengajar')
|
||||
->where('mengajars.id_kelas', $idKelas)
|
||||
->select('tugas.id_tugas', 'tugas.deadline')
|
||||
->get();
|
||||
|
||||
$expTugas = 0;
|
||||
foreach ($tugasList as $tugas) {
|
||||
$deadline = Carbon::parse($tugas->deadline);
|
||||
$pengumpulan = DB::table('pengumpulan_tugas')
|
||||
->where('id_tugas', $tugas->id_tugas)
|
||||
->where('id_siswa', $idSiswa)
|
||||
->first();
|
||||
|
||||
if ($pengumpulan && $pengumpulan->lampiran_tugas !== null) {
|
||||
$tanggalSubmit = Carbon::parse($pengumpulan->tanggal_submit);
|
||||
if ($tanggalSubmit->lessThanOrEqualTo($deadline)) {
|
||||
$expTugas += 10; // Tepat waktu → +10
|
||||
} else {
|
||||
$hariTerlambat = $deadline->diffInDays($tanggalSubmit); // ← dibalik
|
||||
|
||||
if ($hariTerlambat <= 1) {
|
||||
$expTugas += 5; // Terlambat ≤ 1 hari → +5
|
||||
} elseif ($hariTerlambat <= 3) {
|
||||
$expTugas += 1; // Terlambat 2-3 hari → +3
|
||||
} else {
|
||||
$expTugas -= 5; // Lewat grace period > 3 hari → dianggap tidak kumpul
|
||||
}
|
||||
}
|
||||
} elseif ($now->greaterThan($deadline)) {
|
||||
// Tidak kumpul sama sekali & deadline lewat → -5
|
||||
$expTugas -= 5;
|
||||
}
|
||||
}
|
||||
|
||||
return max(0, $expChallenge + $expTugas);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \App\Models\Guru $guru */
|
||||
|
|
@ -23,14 +87,12 @@ public function index(Request $request)
|
|||
? $now->year . '/' . ($now->year + 1)
|
||||
: ($now->year - 1) . '/' . $now->year);
|
||||
|
||||
// Kelas yang diajar guru ini
|
||||
$idKelasList = Mengajar::where('id_guru', $guru->id_guru)
|
||||
->pluck('id_kelas')
|
||||
->unique()
|
||||
->toArray();
|
||||
|
||||
$idKelas = $request->input('id_kelas', $idKelasList[0] ?? null);
|
||||
|
||||
$idKelas = $request->input('id_kelas', $idKelasList[0] ?? null);
|
||||
$kelasList = Kelas::whereIn('id_kelas', $idKelasList)
|
||||
->orderBy('tingkat')->orderBy('nama_kelas')
|
||||
->get();
|
||||
|
|
@ -38,21 +100,24 @@ public function index(Request $request)
|
|||
$leaderboard = collect();
|
||||
|
||||
if ($idKelas) {
|
||||
$leaderboard = Leaderboard::with(['siswa', 'kelas'])
|
||||
->where('id_kelas', $idKelas)
|
||||
->where('semester', $semester)
|
||||
->where('tahun_ajaran', $tahunAjaran)
|
||||
->orderBy('total_exp', 'desc')
|
||||
->get()
|
||||
->map(function ($item, $i) {
|
||||
return [
|
||||
'ranking' => $i + 1,
|
||||
'nama' => optional($item->siswa)->nama ?? '-',
|
||||
'nisn' => optional($item->siswa)->nisn ?? '-',
|
||||
'nama_kelas' => optional($item->kelas)->nama_kelas ?? '-',
|
||||
'exp' => $item->total_exp,
|
||||
];
|
||||
});
|
||||
$semuaSiswa = Siswa::where('id_kelas', $idKelas)->get();
|
||||
|
||||
$leaderboard = $semuaSiswa->map(function ($s) {
|
||||
return [
|
||||
'id_siswa' => $s->id_siswa,
|
||||
'nama' => $s->nama,
|
||||
'nisn' => $s->nisn,
|
||||
'foto_profil' => $s->foto_profil,
|
||||
'nama_kelas' => $s->kelas->nama_kelas ?? '-',
|
||||
'exp' => $this->hitungExpSiswa($s->id_siswa, $s->id_kelas),
|
||||
];
|
||||
})
|
||||
->sortByDesc('exp')
|
||||
->values()
|
||||
->map(function ($item, $i) {
|
||||
$item['ranking'] = $i + 1;
|
||||
return $item;
|
||||
});
|
||||
}
|
||||
|
||||
$tahunList = [];
|
||||
|
|
|
|||
|
|
@ -122,6 +122,59 @@ public function historyMateri()
|
|||
return view('guru.materi.history', compact('materiList'));
|
||||
}
|
||||
|
||||
public function editMateri($id)
|
||||
{
|
||||
$guru = Auth::guard('guru')->user();
|
||||
|
||||
$idMengajars = Mengajar::where('id_guru', $guru->id_guru)->pluck('id_mengajar');
|
||||
|
||||
$materi = Materi::whereIn('id_mengajar', $idMengajars)
|
||||
->where('id_materi', $id)
|
||||
->firstOrFail();
|
||||
|
||||
$mengajars = Mengajar::with(['mapel', 'kelas'])
|
||||
->where('id_guru', $guru->id_guru)
|
||||
->get();
|
||||
|
||||
return view('guru.materi.edit', compact('materi', 'mengajars'));
|
||||
}
|
||||
|
||||
public function updateMateri(Request $request, $id)
|
||||
{
|
||||
$guru = Auth::guard('guru')->user();
|
||||
$idMengajars = Mengajar::where('id_guru', $guru->id_guru)->pluck('id_mengajar');
|
||||
|
||||
$materi = Materi::whereIn('id_mengajar', $idMengajars)
|
||||
->where('id_materi', $id)
|
||||
->firstOrFail();
|
||||
|
||||
$request->validate([
|
||||
// id_mengajar TIDAK divalidate karena tidak ada di form edit
|
||||
'judul_materi' => 'required|string|max:200',
|
||||
'deskripsi' => 'nullable|string',
|
||||
'lampiran_materi' => 'nullable|file|mimes:pdf,doc,docx,jpg,jpeg,png,ppt,pptx|max:10240',
|
||||
], [
|
||||
'lampiran_materi.mimes' => 'Format file: pdf, doc, docx, jpg, png, ppt, pptx.',
|
||||
'lampiran_materi.max' => 'Ukuran file maksimal 10MB.',
|
||||
]);
|
||||
|
||||
if ($request->hasFile('lampiran_materi')) {
|
||||
if ($materi->lampiran_materi && \Storage::disk('public')->exists($materi->lampiran_materi)) {
|
||||
\Storage::disk('public')->delete($materi->lampiran_materi);
|
||||
}
|
||||
$file = $request->file('lampiran_materi');
|
||||
$filename = 'materi_' . $guru->id_guru . '_' . time() . '.' . $file->getClientOriginalExtension();
|
||||
$materi->lampiran_materi = $file->storeAs('materi', $filename, 'public');
|
||||
}
|
||||
|
||||
// id_mengajar TIDAK diupdate — kelas asal tetap
|
||||
$materi->judul_materi = $request->judul_materi;
|
||||
$materi->deskripsi = $request->deskripsi;
|
||||
$materi->save();
|
||||
|
||||
return redirect()->route('guru.materi.history')
|
||||
->with('success', 'Materi berhasil diperbarui.');
|
||||
}
|
||||
/**
|
||||
* Hapus materi
|
||||
*/
|
||||
|
|
@ -184,6 +237,58 @@ public function detailTugas($id)
|
|||
return view('guru.tugas.detail', compact('tugas'));
|
||||
}
|
||||
|
||||
public function editTugas($id)
|
||||
{
|
||||
$guru = Auth::guard('guru')->user();
|
||||
$idMengajars = Mengajar::where('id_guru', $guru->id_guru)->pluck('id_mengajar');
|
||||
|
||||
$tugas = Tugas::whereIn('id_mengajar', $idMengajars)
|
||||
->where('id_tugas', $id)
|
||||
->firstOrFail();
|
||||
|
||||
$mengajars = Mengajar::with(['mapel', 'kelas'])
|
||||
->where('id_guru', $guru->id_guru)
|
||||
->get();
|
||||
|
||||
return view('guru.tugas.edit', compact('tugas', 'mengajars'));
|
||||
}
|
||||
|
||||
public function updateTugas(Request $request, $id)
|
||||
{
|
||||
$guru = Auth::guard('guru')->user();
|
||||
$idMengajars = Mengajar::where('id_guru', $guru->id_guru)->pluck('id_mengajar');
|
||||
|
||||
$tugas = Tugas::whereIn('id_mengajar', $idMengajars)
|
||||
->where('id_tugas', $id)
|
||||
->firstOrFail();
|
||||
|
||||
$request->validate([
|
||||
'judul_tugas' => 'required|string|max:200',
|
||||
'keterangan' => 'nullable|string',
|
||||
'deadline' => 'required|date', // ← hapus after:now biar edit deadline lama tetap bisa
|
||||
'lampiran_tugas' => 'nullable|file|max:10240',
|
||||
], [
|
||||
'lampiran_tugas.max' => 'Ukuran file maksimal 10MB.',
|
||||
]);
|
||||
|
||||
if ($request->hasFile('lampiran_tugas')) {
|
||||
if ($tugas->lampiran && \Storage::disk('public')->exists($tugas->lampiran)) {
|
||||
\Storage::disk('public')->delete($tugas->lampiran);
|
||||
}
|
||||
$file = $request->file('lampiran_tugas');
|
||||
$filename = 'tugas_' . $guru->id_guru . '_' . time() . '.' . $file->getClientOriginalExtension();
|
||||
$tugas->lampiran = $file->storeAs('tugas', $filename, 'public');
|
||||
}
|
||||
|
||||
$tugas->judul_tugas = $request->judul_tugas;
|
||||
$tugas->keterangan = $request->keterangan;
|
||||
$tugas->deadline = $request->deadline;
|
||||
$tugas->save();
|
||||
|
||||
return redirect()->route('guru.tugas.history')
|
||||
->with('success', 'Tugas berhasil diperbarui.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Hapus tugas
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ public function updateAjax(Request $request)
|
|||
}
|
||||
$path = $request->file('foto_profil')->store('foto_profil/guru', 'public');
|
||||
$data['foto_profil'] = $path;
|
||||
$fotoUrl = Storage::url($path);
|
||||
$fotoUrl = '/E31230356/storage/app/public/' . $path; // ← diubah
|
||||
}
|
||||
|
||||
if (!empty($data)) {
|
||||
|
|
@ -48,7 +48,7 @@ public function updateAjax(Request $request)
|
|||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Profil berhasil diperbarui!',
|
||||
'foto_url' => $fotoUrl ?? ($guru->foto_profil ? Storage::url($guru->foto_profil) : null),
|
||||
'foto_url' => $fotoUrl ?? ($guru->foto_profil ? '/E31230356/storage/app/public/' . $guru->foto_profil : null), // ← diubah
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -93,14 +93,19 @@ public function submit(Request $request, $id_challenge)
|
|||
}
|
||||
|
||||
$jawaban = $request->input('jawaban', []);
|
||||
$totalExp = 0;
|
||||
$jawabanJson = [];
|
||||
|
||||
// =============================================
|
||||
// PERUBAHAN: +1 poin per soal yang dijawab BENAR
|
||||
// (tidak lagi pakai exp_per_soal dari database)
|
||||
// =============================================
|
||||
$totalExp = 0;
|
||||
foreach ($challenge->soal as $soal) {
|
||||
$jwb = $jawaban[$soal->id_soal] ?? null;
|
||||
$jawabanJson[$soal->id_soal] = $jwb;
|
||||
|
||||
if ($jwb && strtoupper($jwb) === strtoupper($soal->jawaban_benar)) {
|
||||
$totalExp += $soal->exp_per_soal;
|
||||
$totalExp += 1; // +1 poin per soal benar
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -110,7 +115,7 @@ public function submit(Request $request, $id_challenge)
|
|||
? $now->year . '/' . ($now->year + 1)
|
||||
: ($now->year - 1) . '/' . $now->year;
|
||||
|
||||
// Snapshot badge sebelum submit — untuk deteksi badge baru
|
||||
// Snapshot badge sebelum submit
|
||||
$badgeSebelum = SiswaBadge::where('id_siswa', $siswa->id_siswa)
|
||||
->pluck('id_badge')
|
||||
->toArray();
|
||||
|
|
@ -137,6 +142,7 @@ public function submit(Request $request, $id_challenge)
|
|||
|
||||
$lb->increment('total_exp', $totalExp);
|
||||
|
||||
// Update ranking semua siswa di kelas ini
|
||||
Leaderboard::where('id_kelas', $siswa->id_kelas)
|
||||
->where('semester', $semester)
|
||||
->where('tahun_ajaran', $tahunAjaran)
|
||||
|
|
@ -148,14 +154,13 @@ public function submit(Request $request, $id_challenge)
|
|||
// Cek & berikan badge challenge
|
||||
app(BadgeService::class)->checkChallengeBadges($siswa->id_siswa);
|
||||
|
||||
// Deteksi badge yang baru didapat (selisih sebelum & sesudah)
|
||||
// Deteksi badge baru
|
||||
$badgeSesudah = SiswaBadge::where('id_siswa', $siswa->id_siswa)
|
||||
->pluck('id_badge')
|
||||
->toArray();
|
||||
|
||||
$idBadgeBaru = array_diff($badgeSesudah, $badgeSebelum);
|
||||
|
||||
// Simpan ke session agar bisa ditampilkan di halaman hasil
|
||||
if (!empty($idBadgeBaru)) {
|
||||
$badgeBaru = Badge::whereIn('id_badge', $idBadgeBaru)->get();
|
||||
session()->flash('badge_baru', $badgeBaru);
|
||||
|
|
@ -185,7 +190,6 @@ public function hasil($id_challenge)
|
|||
$totalSoal = $challenge->soal->count();
|
||||
$persentase = $totalSoal > 0 ? round(($benar / $totalSoal) * 100) : 0;
|
||||
|
||||
// Ambil badge baru dari session (hanya ada jika baru saja submit)
|
||||
$badgeBaru = session('badge_baru', collect());
|
||||
|
||||
return view('siswa.challenge.hasil', compact(
|
||||
|
|
|
|||
|
|
@ -25,8 +25,7 @@ public function index()
|
|||
/** @var \App\Models\Siswa $siswa */
|
||||
$siswa = Auth::guard('siswa')->user();
|
||||
|
||||
// tugas
|
||||
|
||||
// Tugas pending (belum dikumpulkan, belum lewat deadline)
|
||||
$sudahDikumpulkan = PengumpulanTugas::where('id_siswa', $siswa->id_siswa)
|
||||
->pluck('id_tugas');
|
||||
|
||||
|
|
@ -49,40 +48,35 @@ public function index()
|
|||
$namaMapel = optional(optional($tugas->mengajar)->mapel)->nama_mapel ?? '-';
|
||||
|
||||
$tugasList[$tgl][] = [
|
||||
'id_tugas' => $tugas->id_tugas, // tambah ini
|
||||
'jam' => Carbon::parse($tugas->deadline)->format('H.i'),
|
||||
'nama' => $tugas->judul_tugas,
|
||||
'mapel' => 'Belum · ' . $namaMapel,
|
||||
'id_tugas' => $tugas->id_tugas,
|
||||
'jam' => Carbon::parse($tugas->deadline)->format('H.i'),
|
||||
'nama' => $tugas->judul_tugas,
|
||||
'mapel' => 'Belum · ' . $namaMapel,
|
||||
];
|
||||
}
|
||||
|
||||
// challenge mingguan
|
||||
|
||||
$startMinggu = Carbon::now()->startOfWeek();
|
||||
$endMinggu = Carbon::now()->endOfWeek();
|
||||
|
||||
// Challenge untuk kelas siswa yang masih aktif minggu ini
|
||||
$challengeTotal = Challenge::whereHas('kelas', function ($q) use ($siswa) {
|
||||
$q->where('challenge_kelas.id_kelas', $siswa->id_kelas);
|
||||
// Progress bar tugas (semua tugas dari guru untuk kelas ini)
|
||||
$tugasTotal = Tugas::whereHas('mengajar', function ($q) use ($siswa) {
|
||||
$q->where('id_kelas', $siswa->id_kelas);
|
||||
})
|
||||
->where('tenggat_waktu', '>=', Carbon::now())
|
||||
->whereBetween('created_at', [$startMinggu, $endMinggu])
|
||||
->where('deadline', '>=', Carbon::now())
|
||||
->count();
|
||||
|
||||
// Challenge yang sudah selesai dikerjakan siswa minggu ini
|
||||
$challengeDone = PesertaChallenge::where('id_siswa', $siswa->id_siswa)
|
||||
->where('status', 'selesai')
|
||||
->whereBetween('waktu_submit', [$startMinggu, $endMinggu])
|
||||
$tugasDikumpulkan = PengumpulanTugas::where('id_siswa', $siswa->id_siswa)
|
||||
->whereIn('id_tugas', Tugas::whereHas('mengajar', function ($q) use ($siswa) {
|
||||
$q->where('id_kelas', $siswa->id_kelas);
|
||||
})->where('deadline', '>=', Carbon::now())->pluck('id_tugas'))
|
||||
->count();
|
||||
|
||||
// mascot
|
||||
|
||||
// Mascot
|
||||
$startMinggu = Carbon::now()->startOfWeek();
|
||||
$endMinggu = Carbon::now()->endOfWeek();
|
||||
$tugasSelesai = PengumpulanTugas::where('id_siswa', $siswa->id_siswa)
|
||||
->whereIn('status', ['dikumpulkan', 'terlambat'])
|
||||
->whereBetween('tanggal_submit', [$startMinggu, $endMinggu])
|
||||
->count();
|
||||
|
||||
// leaderboard
|
||||
// Leaderboard
|
||||
$leaderboardRaw = Leaderboard::with('siswa')
|
||||
->where('id_kelas', $siswa->id_kelas)
|
||||
->orderBy('total_exp', 'desc')
|
||||
|
|
@ -99,8 +93,8 @@ public function index()
|
|||
|
||||
return view('siswa.dashboard', compact(
|
||||
'tugasList',
|
||||
'challengeDone',
|
||||
'challengeTotal',
|
||||
'tugasTotal',
|
||||
'tugasDikumpulkan',
|
||||
'tugasSelesai',
|
||||
'leaderboard',
|
||||
));
|
||||
|
|
|
|||
|
|
@ -4,15 +4,102 @@
|
|||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Leaderboard;
|
||||
use App\Models\Siswa;
|
||||
use App\Models\SiswaBadge;
|
||||
use App\Services\BadgeService;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class LeaderboardController extends Controller
|
||||
{
|
||||
private function getData()
|
||||
/**
|
||||
* Hitung total EXP siswa secara dinamis langsung dari database.
|
||||
*
|
||||
* Formula:
|
||||
* + 1 poin per soal benar di setiap challenge
|
||||
* +10 poin per tugas yang dikumpulkan tepat waktu
|
||||
* + 5 poin per tugas yang terlambat < 1 hari (grace period)
|
||||
* + 3 poin per tugas yang terlambat 2–3 hari
|
||||
* - 5 poin per tugas yang terlambat > 3 hari
|
||||
* - 5 poin per tugas yang tidak dikumpulkan sama sekali (setelah deadline)
|
||||
*/
|
||||
private function hitungExpSiswa(int $idSiswa, int $idKelas): int
|
||||
{
|
||||
$now = Carbon::now();
|
||||
|
||||
// ── 1. EXP dari challenge (soal yang dijawab benar) ──────────────
|
||||
$expChallenge = 0;
|
||||
|
||||
$pesertaList = DB::table('peserta_challenges')
|
||||
->where('id_siswa', $idSiswa)
|
||||
->get();
|
||||
|
||||
foreach ($pesertaList as $peserta) {
|
||||
$jawaban = json_decode($peserta->jawaban, true) ?? [];
|
||||
$soalList = DB::table('soal_challenge')
|
||||
->where('id_challenge', $peserta->id_challenge)
|
||||
->get();
|
||||
|
||||
foreach ($soalList as $soal) {
|
||||
$jwb = $jawaban[$soal->id_soal] ?? null;
|
||||
if ($jwb && strtoupper($jwb) === strtoupper($soal->jawaban_benar)) {
|
||||
$expChallenge += 1; // +1 per soal benar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── 2. EXP dari tugas ────────────────────────────────────────────
|
||||
$semuaTugasIdKelas = DB::table('tugas')
|
||||
->join('mengajars', 'tugas.id_mengajar', '=', 'mengajars.id_mengajar')
|
||||
->where('mengajars.id_kelas', $idKelas)
|
||||
->select('tugas.id_tugas', 'tugas.deadline')
|
||||
->get();
|
||||
|
||||
$expTugas = 0;
|
||||
|
||||
foreach ($semuaTugasIdKelas as $tugas) {
|
||||
$deadline = Carbon::parse($tugas->deadline);
|
||||
$pengumpulan = DB::table('pengumpulan_tugas')
|
||||
->where('id_tugas', $tugas->id_tugas)
|
||||
->where('id_siswa', $idSiswa)
|
||||
->first();
|
||||
|
||||
if ($pengumpulan && $pengumpulan->lampiran_tugas !== null) {
|
||||
$tanggalSubmit = Carbon::parse($pengumpulan->tanggal_submit);
|
||||
|
||||
if ($tanggalSubmit->lessThanOrEqualTo($deadline)) {
|
||||
$expTugas += 10; // Tepat waktu → +10
|
||||
} else {
|
||||
$hariTerlambat = $deadline->diffInDays($tanggalSubmit); // ← dibalik
|
||||
|
||||
if ($hariTerlambat <= 1) {
|
||||
$expTugas += 5; // Terlambat ≤ 1 hari → +5
|
||||
} elseif ($hariTerlambat <= 3) {
|
||||
$expTugas += 1; // Terlambat 2-3 hari → +3
|
||||
} else {
|
||||
$expTugas -= 5; // Lewat grace period > 3 hari → dianggap tidak kumpul
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Belum mengumpulkan file sama sekali
|
||||
if ($now->greaterThan($deadline)) {
|
||||
// Deadline sudah lewat → penalti -5
|
||||
$expTugas -= 5;
|
||||
}
|
||||
// Deadline belum lewat → tidak ada penalti, tidak ada poin
|
||||
}
|
||||
}
|
||||
|
||||
// Total EXP tidak bisa negatif
|
||||
return max(0, $expChallenge + $expTugas);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ambil data leaderboard dengan EXP yang dihitung dinamis.
|
||||
*/
|
||||
private function getData(): array
|
||||
{
|
||||
$siswa = Auth::guard('siswa')->user();
|
||||
|
||||
|
|
@ -22,24 +109,42 @@ private function getData()
|
|||
? $now->year . '/' . ($now->year + 1)
|
||||
: ($now->year - 1) . '/' . $now->year;
|
||||
|
||||
$leaderboard = Leaderboard::with('siswa')
|
||||
->where('id_kelas', $siswa->id_kelas)
|
||||
->where('semester', $semester)
|
||||
->where('tahun_ajaran', $tahunAjaran)
|
||||
->orderBy('total_exp', 'desc')
|
||||
->get()
|
||||
->map(function ($item, $i) {
|
||||
$fotoProfil = optional($item->siswa)->foto_profil;
|
||||
return [
|
||||
'ranking' => $i + 1,
|
||||
'nama' => optional($item->siswa)->nama ?? '-',
|
||||
'nisn' => optional($item->siswa)->nisn ?? '-',
|
||||
'exp' => $item->total_exp,
|
||||
'id_siswa' => $item->id_siswa,
|
||||
'foto_profil' => $fotoProfil,
|
||||
'foto_url' => $fotoProfil ? Storage::url($fotoProfil) : null,
|
||||
];
|
||||
});
|
||||
// Ambil semua siswa di kelas yang sama
|
||||
$semuaSiswa = Siswa::where('id_kelas', $siswa->id_kelas)->get();
|
||||
|
||||
// Hitung EXP tiap siswa secara dinamis
|
||||
$leaderboard = $semuaSiswa->map(function ($s) {
|
||||
return [
|
||||
'id_siswa' => $s->id_siswa,
|
||||
'nama' => $s->nama,
|
||||
'nisn' => $s->nisn,
|
||||
'foto_profil' => $s->foto_profil,
|
||||
'foto_url' => $s->foto_profil ? Storage::url($s->foto_profil) : null,
|
||||
'exp' => $this->hitungExpSiswa($s->id_siswa, $s->id_kelas),
|
||||
];
|
||||
})
|
||||
->sortByDesc('exp')
|
||||
->values()
|
||||
->map(function ($item, $i) {
|
||||
$item['ranking'] = $i + 1;
|
||||
return $item;
|
||||
});
|
||||
|
||||
// Sinkronisasi ke tabel leaderboards agar badge bisa dicek
|
||||
foreach ($leaderboard as $item) {
|
||||
Leaderboard::updateOrCreate(
|
||||
[
|
||||
'id_siswa' => $item['id_siswa'],
|
||||
'id_kelas' => $siswa->id_kelas,
|
||||
'semester' => $semester,
|
||||
'tahun_ajaran' => $tahunAjaran,
|
||||
],
|
||||
[
|
||||
'total_exp' => $item['exp'],
|
||||
'ranking' => $item['ranking'],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$myRank = $leaderboard->firstWhere('id_siswa', $siswa->id_siswa);
|
||||
|
||||
|
|
@ -55,22 +160,18 @@ public function index()
|
|||
|
||||
/**
|
||||
* Endpoint JSON untuk polling real-time.
|
||||
* Mengevaluasi badge leaderboard siswa, lalu return badge yang dimiliki
|
||||
* saat ini agar JS bisa mendeteksi badge baru via localStorage.
|
||||
*/
|
||||
public function json()
|
||||
{
|
||||
$data = $this->getData();
|
||||
$siswa = $data['siswa'];
|
||||
|
||||
// Evaluasi badge leaderboard (grant/revoke)
|
||||
// Evaluasi badge leaderboard berdasarkan data terbaru
|
||||
app(BadgeService::class)->checkLeaderboardBadges(
|
||||
$siswa->id_siswa,
|
||||
$siswa->id_kelas
|
||||
);
|
||||
|
||||
// Ambil semua badge leaderboard yang dimiliki siswa saat ini
|
||||
// beserta detail badge (icon, nama, deskripsi) untuk ditampilkan di pop-up
|
||||
$badgeSiswa = SiswaBadge::with('badge')
|
||||
->where('id_siswa', $siswa->id_siswa)
|
||||
->whereHas('badge', fn($q) => $q->whereIn('syarat', ['leaderboard_top5', 'leaderboard_top1']))
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Http\Controllers\Siswa;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Challenge;
|
||||
use App\Models\Materi;
|
||||
use App\Models\Tugas;
|
||||
use App\Models\Mengajar;
|
||||
|
|
@ -48,7 +49,23 @@ public function index()
|
|||
'time_raw'=> $t->created_at->toIso8601String(),
|
||||
]);
|
||||
|
||||
$notifications = $materiBaru->concat($tugasBaru)
|
||||
// Challenge baru untuk kelas siswa
|
||||
$challengeBaru = Challenge::whereHas('kelas', fn($q) =>
|
||||
$q->where('challenge_kelas.id_kelas', $siswa->id_kelas))
|
||||
->where('created_at', '>=', $since)
|
||||
->orderBy('created_at', 'desc')
|
||||
->get()
|
||||
->map(fn($c) => [
|
||||
'type' => 'challenge',
|
||||
'title' => 'Challenge Baru!',
|
||||
'message' => $c->judul_challenge,
|
||||
'time' => $c->created_at->diffForHumans(),
|
||||
'time_raw'=> $c->created_at->toIso8601String(),
|
||||
]);
|
||||
|
||||
$notifications = $materiBaru
|
||||
->concat($tugasBaru)
|
||||
->concat($challengeBaru)
|
||||
->sortByDesc('time_raw')
|
||||
->values();
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public function updateAjax(Request $request)
|
|||
}
|
||||
$path = $request->file('foto_profil')->store('foto_profil/siswa', 'public');
|
||||
$data['foto_profil'] = $path;
|
||||
$fotoUrl = Storage::url($path);
|
||||
$fotoUrl = '/E31230356/storage/app/public/' . $path;
|
||||
}
|
||||
|
||||
if (!empty($data)) {
|
||||
|
|
@ -71,7 +71,7 @@ public function updateAjax(Request $request)
|
|||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Profil berhasil diperbarui!',
|
||||
'foto_url' => $fotoUrl ?? ($siswa->foto_profil ? Storage::url($siswa->foto_profil) : null),
|
||||
'foto_url' => $fotoUrl ?? ($siswa->foto_profil ? '/E31230356/storage/app/public/' . $siswa->foto_profil : null),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,13 +4,14 @@
|
|||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Badge;
|
||||
use App\Models\PengumpulanTugas;
|
||||
use App\Models\SiswaBadge;
|
||||
use App\Services\BadgeService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Carbon\Carbon;
|
||||
use App\Models\Tugas;
|
||||
use App\Models\PengumpulanTugas;
|
||||
|
||||
class TugasController extends Controller
|
||||
{
|
||||
|
|
@ -19,9 +20,6 @@ public function __construct()
|
|||
$this->middleware('auth:siswa');
|
||||
}
|
||||
|
||||
/**
|
||||
* Daftar semua tugas untuk kelas siswa
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$siswa = Auth::guard('siswa')->user();
|
||||
|
|
@ -33,18 +31,23 @@ public function index()
|
|||
->orderBy('deadline', 'asc')
|
||||
->get();
|
||||
|
||||
$tugasList = $semuaTugas->map(function ($tugas) use ($siswa) {
|
||||
$now = Carbon::now();
|
||||
|
||||
$tugasList = $semuaTugas->map(function ($tugas) use ($siswa, $now) {
|
||||
$pengumpulan = PengumpulanTugas::where('id_tugas', $tugas->id_tugas)
|
||||
->where('id_siswa', $siswa->id_siswa)
|
||||
->first();
|
||||
|
||||
$now = Carbon::now();
|
||||
$deadline = Carbon::parse($tugas->deadline);
|
||||
|
||||
if ($pengumpulan) {
|
||||
$status = $pengumpulan->status;
|
||||
if ($pengumpulan && $pengumpulan->lampiran_tugas !== null) {
|
||||
$status = $pengumpulan->tanggal_submit && Carbon::parse($pengumpulan->tanggal_submit)->lessThanOrEqualTo($deadline)
|
||||
? 'dikumpulkan'
|
||||
: 'terlambat';
|
||||
$sudahKumpul = true;
|
||||
} else {
|
||||
$status = $now->greaterThan($deadline) ? 'terlambat' : 'belum';
|
||||
$status = $now->greaterThan($deadline) ? 'terlambat' : 'belum';
|
||||
$sudahKumpul = false;
|
||||
}
|
||||
|
||||
return [
|
||||
|
|
@ -55,7 +58,7 @@ public function index()
|
|||
'nama_mapel' => optional(optional($tugas->mengajar)->mapel)->nama_mapel ?? '-',
|
||||
'nama_guru' => optional(optional($tugas->mengajar)->guru)->nama ?? '-',
|
||||
'status' => $status,
|
||||
'sudah_kumpul' => !is_null($pengumpulan),
|
||||
'sudah_kumpul' => $sudahKumpul,
|
||||
'lampiran' => $pengumpulan?->lampiran_tugas,
|
||||
'exp' => $pengumpulan?->exp ?? 0,
|
||||
'file_tugas' => $tugas->lampiran,
|
||||
|
|
@ -69,9 +72,6 @@ public function index()
|
|||
return view('siswa.tugas.index', compact('tugasBelum', 'tugasTerlambat', 'tugasSelesai'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Detail tugas + form submit
|
||||
*/
|
||||
public function show($id_tugas)
|
||||
{
|
||||
$siswa = Auth::guard('siswa')->user();
|
||||
|
|
@ -87,14 +87,18 @@ public function show($id_tugas)
|
|||
->where('id_siswa', $siswa->id_siswa)
|
||||
->first();
|
||||
|
||||
$sudahKumpul = !is_null($pengumpulan);
|
||||
$sudahKumpul = $pengumpulan && $pengumpulan->lampiran_tugas !== null;
|
||||
$terlambat = Carbon::now()->greaterThan(Carbon::parse($tugas->deadline));
|
||||
|
||||
return view('siswa.tugas.show', compact('tugas', 'pengumpulan', 'sudahKumpul', 'terlambat'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit / upload jawaban tugas
|
||||
* Submit tugas.
|
||||
*
|
||||
* EXP tidak lagi diupdate ke leaderboard di sini.
|
||||
* EXP dihitung dinamis di LeaderboardController::hitungExpSiswa()
|
||||
* berdasarkan tanggal_submit vs deadline secara real-time.
|
||||
*/
|
||||
public function submit(Request $request, $id_tugas)
|
||||
{
|
||||
|
|
@ -116,6 +120,7 @@ public function submit(Request $request, $id_tugas)
|
|||
|
||||
$sudahAda = PengumpulanTugas::where('id_tugas', $id_tugas)
|
||||
->where('id_siswa', $siswa->id_siswa)
|
||||
->whereNotNull('lampiran_tugas')
|
||||
->exists();
|
||||
|
||||
if ($sudahAda) {
|
||||
|
|
@ -126,45 +131,75 @@ public function submit(Request $request, $id_tugas)
|
|||
$filename = 'tugas_' . $siswa->id_siswa . '_' . $id_tugas . '_' . time() . '.' . $file->getClientOriginalExtension();
|
||||
$path = $file->storeAs('pengumpulan_tugas', $filename, 'public');
|
||||
|
||||
$now = Carbon::now();
|
||||
$deadline = Carbon::parse($tugas->deadline);
|
||||
$status = $now->greaterThan($deadline) ? 'terlambat' : 'dikumpulkan';
|
||||
$now = Carbon::now();
|
||||
$deadline = Carbon::parse($tugas->deadline);
|
||||
$terlambat = $now->greaterThan($deadline);
|
||||
$status = $terlambat ? 'terlambat' : 'dikumpulkan';
|
||||
|
||||
PengumpulanTugas::create([
|
||||
'id_tugas' => $id_tugas,
|
||||
'id_siswa' => $siswa->id_siswa,
|
||||
'lampiran_tugas' => $path,
|
||||
'tanggal_submit' => $now,
|
||||
'exp' => 0,
|
||||
'status' => $status,
|
||||
]);
|
||||
|
||||
// Cek & berikan badge tugas hanya jika tepat waktu
|
||||
if ($status === 'dikumpulkan') {
|
||||
// Snapshot badge sebelum pengecekan
|
||||
$badgeSebelum = SiswaBadge::where('id_siswa', $siswa->id_siswa)
|
||||
->pluck('id_badge')
|
||||
->toArray();
|
||||
PengumpulanTugas::updateOrCreate(
|
||||
['id_tugas' => $id_tugas, 'id_siswa' => $siswa->id_siswa],
|
||||
[
|
||||
'lampiran_tugas' => $path,
|
||||
'tanggal_submit' => $now,
|
||||
'exp' => $terlambat ? -5 : 10, // catatan saja, tidak dipakai di leaderboard
|
||||
'status' => $status,
|
||||
]
|
||||
);
|
||||
|
||||
if (!$terlambat) {
|
||||
$badgeSebelum = SiswaBadge::where('id_siswa', $siswa->id_siswa)->pluck('id_badge')->toArray();
|
||||
app(BadgeService::class)->checkTugasBadges($siswa->id_siswa);
|
||||
|
||||
// Deteksi badge yang baru didapat
|
||||
$badgeSesudah = SiswaBadge::where('id_siswa', $siswa->id_siswa)
|
||||
->pluck('id_badge')
|
||||
->toArray();
|
||||
|
||||
$idBadgeBaru = array_diff($badgeSesudah, $badgeSebelum);
|
||||
|
||||
$badgeSesudah = SiswaBadge::where('id_siswa', $siswa->id_siswa)->pluck('id_badge')->toArray();
|
||||
$idBadgeBaru = array_diff($badgeSesudah, $badgeSebelum);
|
||||
if (!empty($idBadgeBaru)) {
|
||||
$badgeBaru = Badge::whereIn('id_badge', $idBadgeBaru)->get();
|
||||
session()->flash('badge_baru', $badgeBaru);
|
||||
session()->flash('badge_baru', Badge::whereIn('id_badge', $idBadgeBaru)->get());
|
||||
}
|
||||
}
|
||||
|
||||
$pesan = $status === 'terlambat'
|
||||
? 'Tugas berhasil dikumpulkan (terlambat).'
|
||||
: 'Tugas berhasil dikumpulkan! 🎉';
|
||||
$pesan = $terlambat
|
||||
? 'Tugas berhasil dikumpulkan (terlambat). Kamu mendapat penalti -5 poin. 😔'
|
||||
: 'Tugas berhasil dikumpulkan! Kamu mendapat +10 poin! 🎉';
|
||||
|
||||
return redirect()->route('siswa.tugas.index')->with('success', $pesan);
|
||||
}
|
||||
|
||||
public function gantiFile(Request $request, $id_tugas)
|
||||
{
|
||||
$siswa = Auth::guard('siswa')->user();
|
||||
|
||||
$request->validate([
|
||||
'lampiran_tugas' => 'required|file|mimes:pdf,doc,docx,jpg,jpeg,png|max:5120',
|
||||
]);
|
||||
|
||||
$tugas = Tugas::whereHas('mengajar', function ($q) use ($siswa) {
|
||||
$q->where('id_kelas', $siswa->id_kelas);
|
||||
})
|
||||
->where('id_tugas', $id_tugas)
|
||||
->firstOrFail();
|
||||
|
||||
if (Carbon::now()->greaterThan(Carbon::parse($tugas->deadline))) {
|
||||
return back()->with('error_ganti', 'Deadline sudah lewat, file tidak dapat diganti.');
|
||||
}
|
||||
|
||||
$pengumpulan = PengumpulanTugas::where('id_tugas', $id_tugas)
|
||||
->where('id_siswa', $siswa->id_siswa)
|
||||
->firstOrFail();
|
||||
|
||||
if ($pengumpulan->lampiran_tugas) {
|
||||
Storage::disk('public')->delete($pengumpulan->lampiran_tugas);
|
||||
}
|
||||
|
||||
$file = $request->file('lampiran_tugas');
|
||||
$filename = 'tugas_' . $siswa->id_siswa . '_' . $id_tugas . '_' . time() . '.' . $file->getClientOriginalExtension();
|
||||
$path = $file->storeAs('pengumpulan_tugas', $filename, 'public');
|
||||
|
||||
$pengumpulan->update([
|
||||
'lampiran_tugas' => $path,
|
||||
'tanggal_submit' => Carbon::now(),
|
||||
'status' => 'dikumpulkan',
|
||||
'exp' => 10,
|
||||
]);
|
||||
|
||||
return back()->with('success', 'File jawaban berhasil diganti! ✅');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class AdminAuthenticate
|
||||
{
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (!Auth::guard('admin')->check()) {
|
||||
return redirect()->route('admin.login');
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use App\Models\Guru;
|
||||
use App\Models\PesertaChallenge;
|
||||
|
||||
class Challenge extends Model
|
||||
{
|
||||
|
|
@ -14,7 +16,7 @@ class Challenge extends Model
|
|||
protected $primaryKey = 'id_challenge';
|
||||
|
||||
protected $fillable = [
|
||||
'id_admin',
|
||||
'id_guru',
|
||||
'judul_challenge',
|
||||
'deskripsi',
|
||||
'exp',
|
||||
|
|
@ -41,4 +43,14 @@ public function soal()
|
|||
return $this->hasMany(SoalChallenge::class, 'id_challenge');
|
||||
}
|
||||
|
||||
public function peserta()
|
||||
{
|
||||
return $this->hasMany(PesertaChallenge::class, 'id_challenge');
|
||||
}
|
||||
|
||||
public function guru()
|
||||
{
|
||||
return $this->belongsTo(Guru::class, 'id_guru', 'id_guru');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -9,25 +9,35 @@ class Guru extends Authenticatable
|
|||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'gurus';
|
||||
protected $table = 'gurus';
|
||||
protected $primaryKey = 'id_guru';
|
||||
public $incrementing = true;
|
||||
protected $keyType = 'int';
|
||||
public $incrementing = true;
|
||||
protected $keyType = 'int';
|
||||
|
||||
protected $fillable = [
|
||||
'nip',
|
||||
'nama',
|
||||
'password',
|
||||
'foto_profil'
|
||||
'foto_profil',
|
||||
'remember_token',
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
'password',
|
||||
'remember_token',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'password' => 'hashed',
|
||||
];
|
||||
|
||||
// Relasi ke Mengajar
|
||||
public function mengajars()
|
||||
{
|
||||
return $this->hasMany(Mengajar::class, 'id_guru', 'id_guru');
|
||||
}
|
||||
}
|
||||
public function challenges()
|
||||
|
||||
{
|
||||
return $this->hasMany(Challenge::class, 'id_guru', 'id_guru');
|
||||
}
|
||||
}
|
||||
|
|
@ -35,4 +35,10 @@ public function kelas()
|
|||
{
|
||||
return $this->belongsTo(Kelas::class, 'id_kelas', 'id_kelas');
|
||||
}
|
||||
|
||||
// Relasi ke Tugas
|
||||
public function tugas()
|
||||
{
|
||||
return $this->hasMany(Tugas::class, 'id_mengajar', 'id_mengajar');
|
||||
}
|
||||
}
|
||||
|
|
@ -15,5 +15,6 @@ public function register(): void
|
|||
public function boot(): void
|
||||
{
|
||||
Paginator::defaultView('vendor.pagination.bootstrap-5');
|
||||
app()->usePublicPath(base_path('public'));
|
||||
}
|
||||
}
|
||||
|
|
@ -14,15 +14,14 @@ class BadgeService
|
|||
{
|
||||
/**
|
||||
* Syarat (kolom `syarat` di tabel badges) yang dikenali sistem.
|
||||
* Nilai ini harus sama persis dengan isi kolom `syarat` di DB.
|
||||
*
|
||||
* CHALLENGE
|
||||
* challenge_1 → selesaikan 1 challenge
|
||||
* challenge_3 → selesaikan 3 challenge
|
||||
*
|
||||
* TUGAS
|
||||
* tugas_1 → kumpulkan 1 tugas (tepat waktu)
|
||||
* tugas_3 → kumpulkan 3 tugas (tepat waktu)
|
||||
* tugas_1 → kumpulkan 1 tugas tepat waktu (tanggal_submit ≤ deadline)
|
||||
* tugas_3 → kumpulkan 3 tugas tepat waktu (tanggal_submit ≤ deadline)
|
||||
*
|
||||
* LEADERBOARD (dicek & dicabut secara real-time)
|
||||
* leaderboard_top5 → masuk top 5 leaderboard kelas aktif
|
||||
|
|
@ -35,7 +34,6 @@ class BadgeService
|
|||
|
||||
/**
|
||||
* Dipanggil setelah siswa submit challenge.
|
||||
* Mengecek & memberikan badge challenge.
|
||||
*/
|
||||
public function checkChallengeBadges(int $idSiswa): void
|
||||
{
|
||||
|
|
@ -49,24 +47,28 @@ public function checkChallengeBadges(int $idSiswa): void
|
|||
|
||||
/**
|
||||
* Dipanggil setelah siswa submit tugas.
|
||||
* Mengecek & memberikan badge tugas (hanya status 'dikumpulkan' / tepat waktu).
|
||||
* Badge hanya diberikan jika tugas dikumpulkan TEPAT WAKTU
|
||||
* (tanggal_submit ≤ deadline tugas).
|
||||
*/
|
||||
public function checkTugasBadges(int $idSiswa): void
|
||||
{
|
||||
$jumlahKumpul = PengumpulanTugas::where('id_siswa', $idSiswa)
|
||||
->where('status', 'dikumpulkan')
|
||||
// Join pengumpulan_tugas dengan tugas untuk membandingkan
|
||||
// tanggal_submit dengan deadline secara langsung di DB.
|
||||
$jumlahTepatWaktu = DB::table('pengumpulan_tugas')
|
||||
->join('tugas', 'pengumpulan_tugas.id_tugas', '=', 'tugas.id_tugas')
|
||||
->where('pengumpulan_tugas.id_siswa', $idSiswa)
|
||||
->whereNotNull('pengumpulan_tugas.lampiran_tugas')
|
||||
->whereColumn('pengumpulan_tugas.tanggal_submit', '<=', 'tugas.deadline')
|
||||
->count();
|
||||
|
||||
$this->grantIfEligible($idSiswa, 'tugas_1', $jumlahKumpul >= 1);
|
||||
$this->grantIfEligible($idSiswa, 'tugas_3', $jumlahKumpul >= 3);
|
||||
$this->grantIfEligible($idSiswa, 'tugas_1', $jumlahTepatWaktu >= 1);
|
||||
$this->grantIfEligible($idSiswa, 'tugas_3', $jumlahTepatWaktu >= 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dipanggil dari endpoint JSON leaderboard (polling real-time).
|
||||
* Badge leaderboard DICABUT jika siswa tidak lagi memenuhi syarat,
|
||||
* dan DIBERIKAN KEMBALI jika kembali memenuhi syarat.
|
||||
*
|
||||
* Hanya leaderboard semester & tahun ajaran aktif yang dievaluasi.
|
||||
*/
|
||||
public function checkLeaderboardBadges(int $idSiswa, int $idKelas): void
|
||||
{
|
||||
|
|
@ -80,11 +82,9 @@ public function checkLeaderboardBadges(int $idSiswa, int $idKelas): void
|
|||
|
||||
$ranking = $lb?->ranking ?? 0;
|
||||
|
||||
// top5: ranking 1-5, top1: hanya ranking 1
|
||||
$isTop5 = $ranking >= 1 && $ranking <= 5;
|
||||
$isTop1 = $ranking === 1;
|
||||
|
||||
// Untuk badge leaderboard: grant jika eligible, revoke jika tidak
|
||||
$this->grantOrRevoke($idSiswa, 'leaderboard_top5', $isTop5);
|
||||
$this->grantOrRevoke($idSiswa, 'leaderboard_top1', $isTop1);
|
||||
}
|
||||
|
|
@ -105,10 +105,9 @@ private function grantIfEligible(int $idSiswa, string $syarat, bool $eligible):
|
|||
|
||||
$badge = Badge::where('syarat', $syarat)->first();
|
||||
if (!$badge) {
|
||||
return; // badge belum di-seed di DB, skip
|
||||
return;
|
||||
}
|
||||
|
||||
// Idempoten: cek dulu sebelum insert
|
||||
$sudahPunya = SiswaBadge::where('id_siswa', $idSiswa)
|
||||
->where('id_badge', $badge->id_badge)
|
||||
->exists();
|
||||
|
|
@ -138,22 +137,18 @@ private function grantOrRevoke(int $idSiswa, string $syarat, bool $eligible): vo
|
|||
->first();
|
||||
|
||||
if ($eligible && !$record) {
|
||||
// Berikan badge
|
||||
SiswaBadge::create([
|
||||
'id_siswa' => $idSiswa,
|
||||
'id_badge' => $badge->id_badge,
|
||||
'tanggal_diberikan' => Carbon::now(),
|
||||
]);
|
||||
} elseif (!$eligible && $record) {
|
||||
// Cabut badge
|
||||
$record->delete();
|
||||
}
|
||||
// Jika sudah punya & masih eligible, atau tidak punya & tidak eligible → tidak perlu apa-apa
|
||||
}
|
||||
|
||||
/**
|
||||
* Mengembalikan [semester, tahun_ajaran] berdasarkan tanggal sekarang,
|
||||
* konsisten dengan logika di ChallengeController.
|
||||
* Mengembalikan [semester, tahun_ajaran] berdasarkan tanggal sekarang.
|
||||
*/
|
||||
private function semesterAktif(): array
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,8 +10,10 @@
|
|||
commands: __DIR__.'/../routes/console.php',
|
||||
health: '/up',
|
||||
)
|
||||
->withMiddleware(function (Middleware $middleware): void {
|
||||
//
|
||||
->withMiddleware(function (Middleware $middleware) {
|
||||
$middleware->alias([
|
||||
'admin.auth' => \App\Http\Middleware\AdminAuthenticate::class,
|
||||
]);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions): void {
|
||||
//
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"resources/css/app.css": {
|
||||
"file": "assets/app-Cv_tjT6n.css",
|
||||
"src": "resources/css/app.css",
|
||||
"isEntry": true,
|
||||
"names": [
|
||||
"app.css"
|
||||
]
|
||||
},
|
||||
"resources/js/app.js": {
|
||||
"file": "assets/app-CXDpL9bK.js",
|
||||
"name": "app",
|
||||
"src": "resources/js/app.js",
|
||||
"isEntry": true
|
||||
}
|
||||
}
|
||||
|
|
@ -65,7 +65,7 @@
|
|||
|
|
||||
*/
|
||||
|
||||
'timezone' => 'UTC',
|
||||
'timezone' => 'Asia/Jakarta',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -0,0 +1,301 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Settings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Set some default values. It is possible to add all defines that can be set
|
||||
| in dompdf_config.inc.php. You can also override the entire config file.
|
||||
|
|
||||
*/
|
||||
'show_warnings' => false, // Throw an Exception on warnings from dompdf
|
||||
|
||||
'public_path' => base_path('public'),
|
||||
|
||||
/*
|
||||
* Dejavu Sans font is missing glyphs for converted entities, turn it off if you need to show € and £.
|
||||
*/
|
||||
'convert_entities' => true,
|
||||
|
||||
'options' => [
|
||||
/**
|
||||
* The location of the DOMPDF font directory
|
||||
*
|
||||
* The location of the directory where DOMPDF will store fonts and font metrics
|
||||
* Note: This directory must exist and be writable by the webserver process.
|
||||
* *Please note the trailing slash.*
|
||||
*
|
||||
* Notes regarding fonts:
|
||||
* Additional .afm font metrics can be added by executing load_font.php from command line.
|
||||
*
|
||||
* Only the original "Base 14 fonts" are present on all pdf viewers. Additional fonts must
|
||||
* be embedded in the pdf file or the PDF may not display correctly. This can significantly
|
||||
* increase file size unless font subsetting is enabled. Before embedding a font please
|
||||
* review your rights under the font license.
|
||||
*
|
||||
* Any font specification in the source HTML is translated to the closest font available
|
||||
* in the font directory.
|
||||
*
|
||||
* The pdf standard "Base 14 fonts" are:
|
||||
* Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique,
|
||||
* Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique,
|
||||
* Times-Roman, Times-Bold, Times-BoldItalic, Times-Italic,
|
||||
* Symbol, ZapfDingbats.
|
||||
*/
|
||||
'font_dir' => storage_path('fonts'), // advised by dompdf (https://github.com/dompdf/dompdf/pull/782)
|
||||
|
||||
/**
|
||||
* The location of the DOMPDF font cache directory
|
||||
*
|
||||
* This directory contains the cached font metrics for the fonts used by DOMPDF.
|
||||
* This directory can be the same as DOMPDF_FONT_DIR
|
||||
*
|
||||
* Note: This directory must exist and be writable by the webserver process.
|
||||
*/
|
||||
'font_cache' => storage_path('fonts'),
|
||||
|
||||
/**
|
||||
* The location of a temporary directory.
|
||||
*
|
||||
* The directory specified must be writeable by the webserver process.
|
||||
* The temporary directory is required to download remote images and when
|
||||
* using the PDFLib back end.
|
||||
*/
|
||||
'temp_dir' => sys_get_temp_dir(),
|
||||
|
||||
/**
|
||||
* ==== IMPORTANT ====
|
||||
*
|
||||
* dompdf's "chroot": Prevents dompdf from accessing system files or other
|
||||
* files on the webserver. All local files opened by dompdf must be in a
|
||||
* subdirectory of this directory. DO NOT set it to '/' since this could
|
||||
* allow an attacker to use dompdf to read any files on the server. This
|
||||
* should be an absolute path.
|
||||
* This is only checked on command line call by dompdf.php, but not by
|
||||
* direct class use like:
|
||||
* $dompdf = new DOMPDF(); $dompdf->load_html($htmldata); $dompdf->render(); $pdfdata = $dompdf->output();
|
||||
*/
|
||||
'chroot' => realpath(base_path()),
|
||||
|
||||
/**
|
||||
* Protocol whitelist
|
||||
*
|
||||
* Protocols and PHP wrappers allowed in URIs, and the validation rules
|
||||
* that determine if a resouce may be loaded. Full support is not guaranteed
|
||||
* for the protocols/wrappers specified
|
||||
* by this array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
'allowed_protocols' => [
|
||||
'data://' => ['rules' => []],
|
||||
'file://' => ['rules' => []],
|
||||
'http://' => ['rules' => []],
|
||||
'https://' => ['rules' => []],
|
||||
],
|
||||
|
||||
/**
|
||||
* Operational artifact (log files, temporary files) path validation
|
||||
*/
|
||||
'artifactPathValidation' => null,
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
'log_output_file' => null,
|
||||
|
||||
/**
|
||||
* Whether to enable font subsetting or not.
|
||||
*/
|
||||
'enable_font_subsetting' => false,
|
||||
|
||||
/**
|
||||
* The PDF rendering backend to use
|
||||
*
|
||||
* Valid settings are 'PDFLib', 'CPDF' (the bundled R&OS PDF class), 'GD' and
|
||||
* 'auto'. 'auto' will look for PDFLib and use it if found, or if not it will
|
||||
* fall back on CPDF. 'GD' renders PDFs to graphic files.
|
||||
* {@link * Canvas_Factory} ultimately determines which rendering class to
|
||||
* instantiate based on this setting.
|
||||
*
|
||||
* Both PDFLib & CPDF rendering backends provide sufficient rendering
|
||||
* capabilities for dompdf, however additional features (e.g. object,
|
||||
* image and font support, etc.) differ between backends. Please see
|
||||
* {@link PDFLib_Adapter} for more information on the PDFLib backend
|
||||
* and {@link CPDF_Adapter} and lib/class.pdf.php for more information
|
||||
* on CPDF. Also see the documentation for each backend at the links
|
||||
* below.
|
||||
*
|
||||
* The GD rendering backend is a little different than PDFLib and
|
||||
* CPDF. Several features of CPDF and PDFLib are not supported or do
|
||||
* not make any sense when creating image files. For example,
|
||||
* multiple pages are not supported, nor are PDF 'objects'. Have a
|
||||
* look at {@link GD_Adapter} for more information. GD support is
|
||||
* experimental, so use it at your own risk.
|
||||
*
|
||||
* @link http://www.pdflib.com
|
||||
* @link http://www.ros.co.nz/pdf
|
||||
* @link http://www.php.net/image
|
||||
*/
|
||||
'pdf_backend' => 'CPDF',
|
||||
|
||||
/**
|
||||
* html target media view which should be rendered into pdf.
|
||||
* List of types and parsing rules for future extensions:
|
||||
* http://www.w3.org/TR/REC-html40/types.html
|
||||
* screen, tty, tv, projection, handheld, print, braille, aural, all
|
||||
* Note: aural is deprecated in CSS 2.1 because it is replaced by speech in CSS 3.
|
||||
* Note, even though the generated pdf file is intended for print output,
|
||||
* the desired content might be different (e.g. screen or projection view of html file).
|
||||
* Therefore allow specification of content here.
|
||||
*/
|
||||
'default_media_type' => 'screen',
|
||||
|
||||
/**
|
||||
* The default paper size.
|
||||
*
|
||||
* North America standard is "letter"; other countries generally "a4"
|
||||
*
|
||||
* @see CPDF_Adapter::PAPER_SIZES for valid sizes ('letter', 'legal', 'A4', etc.)
|
||||
*/
|
||||
'default_paper_size' => 'a4',
|
||||
|
||||
/**
|
||||
* The default paper orientation.
|
||||
*
|
||||
* The orientation of the page (portrait or landscape).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
'default_paper_orientation' => 'portrait',
|
||||
|
||||
/**
|
||||
* The default font family
|
||||
*
|
||||
* Used if no suitable fonts can be found. This must exist in the font folder.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
'default_font' => 'serif',
|
||||
|
||||
/**
|
||||
* Image DPI setting
|
||||
*
|
||||
* This setting determines the default DPI setting for images and fonts. The
|
||||
* DPI may be overridden for inline images by explictly setting the
|
||||
* image's width & height style attributes (i.e. if the image's native
|
||||
* width is 600 pixels and you specify the image's width as 72 points,
|
||||
* the image will have a DPI of 600 in the rendered PDF. The DPI of
|
||||
* background images can not be overridden and is controlled entirely
|
||||
* via this parameter.
|
||||
*
|
||||
* For the purposes of DOMPDF, pixels per inch (PPI) = dots per inch (DPI).
|
||||
* If a size in html is given as px (or without unit as image size),
|
||||
* this tells the corresponding size in pt.
|
||||
* This adjusts the relative sizes to be similar to the rendering of the
|
||||
* html page in a reference browser.
|
||||
*
|
||||
* In pdf, always 1 pt = 1/72 inch
|
||||
*
|
||||
* Rendering resolution of various browsers in px per inch:
|
||||
* Windows Firefox and Internet Explorer:
|
||||
* SystemControl->Display properties->FontResolution: Default:96, largefonts:120, custom:?
|
||||
* Linux Firefox:
|
||||
* about:config *resolution: Default:96
|
||||
* (xorg screen dimension in mm and Desktop font dpi settings are ignored)
|
||||
*
|
||||
* Take care about extra font/image zoom factor of browser.
|
||||
*
|
||||
* In images, <img> size in pixel attribute, img css style, are overriding
|
||||
* the real image dimension in px for rendering.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
'dpi' => 96,
|
||||
|
||||
/**
|
||||
* Enable embedded PHP
|
||||
*
|
||||
* If this setting is set to true then DOMPDF will automatically evaluate embedded PHP contained
|
||||
* within <script type="text/php"> ... </script> tags.
|
||||
*
|
||||
* ==== IMPORTANT ==== Enabling this for documents you do not trust (e.g. arbitrary remote html pages)
|
||||
* is a security risk.
|
||||
* Embedded scripts are run with the same level of system access available to dompdf.
|
||||
* Set this option to false (recommended) if you wish to process untrusted documents.
|
||||
* This setting may increase the risk of system exploit.
|
||||
* Do not change this settings without understanding the consequences.
|
||||
* Additional documentation is available on the dompdf wiki at:
|
||||
* https://github.com/dompdf/dompdf/wiki
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
'enable_php' => false,
|
||||
|
||||
/**
|
||||
* Enable inline JavaScript
|
||||
*
|
||||
* If this setting is set to true then DOMPDF will automatically insert JavaScript code contained
|
||||
* within <script type="text/javascript"> ... </script> tags as written into the PDF.
|
||||
* NOTE: This is PDF-based JavaScript to be executed by the PDF viewer,
|
||||
* not browser-based JavaScript executed by Dompdf.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
'enable_javascript' => true,
|
||||
|
||||
/**
|
||||
* Enable remote file access
|
||||
*
|
||||
* If this setting is set to true, DOMPDF will access remote sites for
|
||||
* images and CSS files as required.
|
||||
*
|
||||
* ==== IMPORTANT ====
|
||||
* This can be a security risk, in particular in combination with isPhpEnabled and
|
||||
* allowing remote html code to be passed to $dompdf = new DOMPDF(); $dompdf->load_html(...);
|
||||
* This allows anonymous users to download legally doubtful internet content which on
|
||||
* tracing back appears to being downloaded by your server, or allows malicious php code
|
||||
* in remote html pages to be executed by your server with your account privileges.
|
||||
*
|
||||
* This setting may increase the risk of system exploit. Do not change
|
||||
* this settings without understanding the consequences. Additional
|
||||
* documentation is available on the dompdf wiki at:
|
||||
* https://github.com/dompdf/dompdf/wiki
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
'enable_remote' => false,
|
||||
|
||||
/**
|
||||
* List of allowed remote hosts
|
||||
*
|
||||
* Each value of the array must be a valid hostname.
|
||||
*
|
||||
* This will be used to filter which resources can be loaded in combination with
|
||||
* isRemoteEnabled. If enable_remote is FALSE, then this will have no effect.
|
||||
*
|
||||
* Leave to NULL to allow any remote host.
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
'allowed_remote_hosts' => null,
|
||||
|
||||
/**
|
||||
* A ratio applied to the fonts height to be more like browsers' line height
|
||||
*/
|
||||
'font_height_ratio' => 1.1,
|
||||
|
||||
/**
|
||||
* Use the HTML5 Lib parser
|
||||
*
|
||||
* @deprecated This feature is now always on in dompdf 2.x
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
'enable_html5_parser' => true,
|
||||
],
|
||||
|
||||
];
|
||||
|
|
@ -8,6 +8,74 @@
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════
|
||||
CSS VARIABLES — default: SISWA (biru)
|
||||
══════════════════════════════════════════════ */
|
||||
:root {
|
||||
--blob1: rgba(100, 180, 255, 0.12);
|
||||
--blob2: rgba(120, 80, 255, 0.1);
|
||||
--badge-dot: #69f0ae;
|
||||
--role-color: #1a5fb8;
|
||||
--underline-from: #60b4ff;
|
||||
--underline-to: #a78bfa;
|
||||
--submit-from: #2b8ef3;
|
||||
--submit-to: #1a7ae0;
|
||||
--submit-shadow: rgba(43, 142, 243, 0.35);
|
||||
--submit-shadow-hover: rgba(43, 142, 243, 0.45);
|
||||
--check-color: #2b8ef3;
|
||||
--focus-border: #2b8ef3;
|
||||
--focus-shadow: rgba(43, 142, 243, 0.12);
|
||||
--link-color: #1a5fb8;
|
||||
--link-hover-bg: #e8f4ff;
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════
|
||||
GURU — Hijau (sesuai portal landing page)
|
||||
Referensi: .pc-green / .bp-green / #accent2
|
||||
══════════════════════════════════════════════ */
|
||||
body.login-guru {
|
||||
--blob1: rgba(34, 197, 94, 0.14);
|
||||
--blob2: rgba(134, 239, 172, 0.12);
|
||||
--badge-dot: #4ade80;
|
||||
--role-color: #15803d;
|
||||
--underline-from: #22c55e;
|
||||
--underline-to: #86efac;
|
||||
--submit-from: #22c55e;
|
||||
--submit-to: #16a34a;
|
||||
--submit-shadow: rgba(34, 197, 94, 0.35);
|
||||
--submit-shadow-hover: rgba(34, 197, 94, 0.45);
|
||||
--check-color: #22c55e;
|
||||
--focus-border: #22c55e;
|
||||
--focus-shadow: rgba(34, 197, 94, 0.12);
|
||||
--link-color: #15803d;
|
||||
--link-hover-bg: #f0fdf4;
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════
|
||||
ADMIN — Orange (sesuai portal landing page)
|
||||
Referensi: .pc-orange / .bp-orange / #accent1
|
||||
══════════════════════════════════════════════ */
|
||||
body.login-admin {
|
||||
--blob1: rgba(249, 115, 22, 0.14);
|
||||
--blob2: rgba(251, 146, 60, 0.12);
|
||||
--badge-dot: #fb923c;
|
||||
--role-color: #c2410c;
|
||||
--underline-from: #f97316;
|
||||
--underline-to: #fdba74;
|
||||
--submit-from: #f97316;
|
||||
--submit-to: #ea580c;
|
||||
--submit-shadow: rgba(249, 115, 22, 0.35);
|
||||
--submit-shadow-hover: rgba(249, 115, 22, 0.45);
|
||||
--check-color: #f97316;
|
||||
--focus-border: #f97316;
|
||||
--focus-shadow: rgba(249, 115, 22, 0.12);
|
||||
--link-color: #c2410c;
|
||||
--link-hover-bg: #fff7ed;
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════
|
||||
BASE — background SISWA (biru navy)
|
||||
══════════════════════════════════════════════ */
|
||||
body {
|
||||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
min-height: 100vh;
|
||||
|
|
@ -26,12 +94,41 @@ body {
|
|||
justify-content: center;
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════
|
||||
GURU — background hijau tua yang dalam & padu
|
||||
Nada: forest / emerald, lebih kaya dari sekadar gelap
|
||||
══════════════════════════════════════════════ */
|
||||
body.login-guru {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
#052e16 0%,
|
||||
#064e2a 30%,
|
||||
#166534 60%,
|
||||
#065f2d 85%,
|
||||
#052e16 100%
|
||||
) !important;
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════
|
||||
ADMIN — background oranye tua yang hangat & padu
|
||||
Nada: ember / mahogany, lebih kaya & tidak terlalu merah
|
||||
══════════════════════════════════════════════ */
|
||||
body.login-admin {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
#431407 0%,
|
||||
#6b2109 30%,
|
||||
#9a3412 60%,
|
||||
#7c2d12 85%,
|
||||
#431407 100%
|
||||
) !important;
|
||||
}
|
||||
|
||||
/* ── DECORATIVE SHAPES ── */
|
||||
.shape {
|
||||
position: fixed;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.shape-1 {
|
||||
width: 320px;
|
||||
height: 320px;
|
||||
|
|
@ -41,7 +138,6 @@ .shape-1 {
|
|||
left: 80px;
|
||||
transform: rotate(20deg);
|
||||
}
|
||||
|
||||
.shape-2 {
|
||||
width: 220px;
|
||||
height: 220px;
|
||||
|
|
@ -51,7 +147,6 @@ .shape-2 {
|
|||
left: 260px;
|
||||
transform: rotate(-15deg);
|
||||
}
|
||||
|
||||
.shape-3 {
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
|
|
@ -61,7 +156,6 @@ .shape-3 {
|
|||
right: 320px;
|
||||
transform: rotate(30deg);
|
||||
}
|
||||
|
||||
.shape-4 {
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
|
|
@ -71,7 +165,6 @@ .shape-4 {
|
|||
right: -80px;
|
||||
transform: rotate(12deg);
|
||||
}
|
||||
|
||||
.shape-5 {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
|
|
@ -88,24 +181,22 @@ .blob {
|
|||
pointer-events: none;
|
||||
filter: blur(80px);
|
||||
}
|
||||
|
||||
.blob-1 {
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
background: rgba(100, 180, 255, 0.12);
|
||||
background: var(--blob1);
|
||||
top: -200px;
|
||||
left: -100px;
|
||||
}
|
||||
|
||||
.blob-2 {
|
||||
width: 350px;
|
||||
height: 350px;
|
||||
background: rgba(120, 80, 255, 0.1);
|
||||
background: var(--blob2);
|
||||
bottom: -100px;
|
||||
right: 200px;
|
||||
}
|
||||
|
||||
/* ── MAIN LAYOUT ── */
|
||||
/* ── LAYOUT ── */
|
||||
.page-wrap {
|
||||
width: 100%;
|
||||
max-width: 1100px;
|
||||
|
|
@ -137,7 +228,6 @@ .school-tag {
|
|||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.school-tag::before {
|
||||
content: "";
|
||||
display: block;
|
||||
|
|
@ -158,7 +248,6 @@ .left-logo {
|
|||
justify-content: center;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.left-logo img {
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
|
|
@ -175,7 +264,6 @@ .left-welcome {
|
|||
letter-spacing: -1px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.left-welcome span {
|
||||
display: block;
|
||||
color: rgba(255, 255, 255, 0.35);
|
||||
|
|
@ -216,7 +304,6 @@ .btn-learn {
|
|||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.btn-learn:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
|
@ -235,6 +322,24 @@ .form-card {
|
|||
color: #1a1a2e;
|
||||
}
|
||||
|
||||
/* GURU — card putih kehijauan lembut */
|
||||
body.login-guru .form-card {
|
||||
background: #f0fdf4;
|
||||
border-color: rgba(134, 239, 172, 0.35);
|
||||
box-shadow:
|
||||
0 32px 64px rgba(0, 0, 0, 0.22),
|
||||
0 0 0 1px rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
|
||||
/* ADMIN — card putih keoranyean lembut */
|
||||
body.login-admin .form-card {
|
||||
background: #fff7ed;
|
||||
border-color: rgba(253, 186, 116, 0.35);
|
||||
box-shadow:
|
||||
0 32px 64px rgba(0, 0, 0, 0.22),
|
||||
0 0 0 1px rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
|
||||
.card-title-wrap {
|
||||
text-align: center;
|
||||
margin-bottom: 28px;
|
||||
|
|
@ -251,19 +356,27 @@ .role-badge {
|
|||
padding: 5px 14px;
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
color: #5b3fc0;
|
||||
color: var(--role-color);
|
||||
letter-spacing: 1.5px;
|
||||
text-transform: uppercase;
|
||||
font-family: "Sora", sans-serif;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
body.login-guru .role-badge {
|
||||
border-color: rgba(134, 239, 172, 0.45);
|
||||
}
|
||||
|
||||
body.login-admin .role-badge {
|
||||
border-color: rgba(253, 186, 116, 0.45);
|
||||
}
|
||||
|
||||
.badge-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: #69f0ae;
|
||||
box-shadow: 0 0 6px #69f0ae;
|
||||
background: var(--badge-dot);
|
||||
box-shadow: 0 0 6px var(--badge-dot);
|
||||
}
|
||||
|
||||
.card-title {
|
||||
|
|
@ -279,7 +392,11 @@ .title-underline {
|
|||
display: inline-block;
|
||||
width: 36px;
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, #60b4ff, #a78bfa);
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
var(--underline-from),
|
||||
var(--underline-to)
|
||||
);
|
||||
border-radius: 99px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
|
@ -288,7 +405,6 @@ .title-underline {
|
|||
.field-group {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.field-label {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
|
|
@ -296,13 +412,11 @@ .field-label {
|
|||
color: #4a5568;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
.field-wrap {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.field-wrap .field-input {
|
||||
padding-right: 44px;
|
||||
}
|
||||
|
|
@ -321,15 +435,22 @@ .field-input {
|
|||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
body.login-guru .field-input {
|
||||
border-color: #bbf7d0;
|
||||
}
|
||||
body.login-admin .field-input {
|
||||
border-color: #fed7aa;
|
||||
}
|
||||
|
||||
.field-input::placeholder {
|
||||
color: #bbb5cc;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.field-input:focus {
|
||||
border-color: #7c5cbf;
|
||||
border-color: var(--focus-border);
|
||||
background: white;
|
||||
box-shadow: 0 0 0 3px rgba(124, 92, 191, 0.1);
|
||||
box-shadow: 0 0 0 3px var(--focus-shadow);
|
||||
}
|
||||
|
||||
.toggle-password {
|
||||
|
|
@ -342,7 +463,6 @@ .toggle-password {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.eye-icon {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
|
|
@ -350,7 +470,6 @@ .eye-icon {
|
|||
pointer-events: none;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.toggle-password:hover .eye-icon {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
|
@ -375,10 +494,16 @@ .remember-check {
|
|||
position: relative;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
body.login-guru .remember-check {
|
||||
border-color: #86efac;
|
||||
}
|
||||
body.login-admin .remember-check {
|
||||
border-color: #fdba74;
|
||||
}
|
||||
|
||||
.remember-check:checked {
|
||||
background: #7c5cbf;
|
||||
border-color: #7c5cbf;
|
||||
background: var(--check-color);
|
||||
border-color: var(--check-color);
|
||||
}
|
||||
|
||||
.remember-check:checked::after {
|
||||
|
|
@ -393,7 +518,6 @@ .remember-check:checked::after {
|
|||
border-left: none;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.remember-text {
|
||||
font-size: 13px;
|
||||
color: #6b7280;
|
||||
|
|
@ -405,7 +529,7 @@ .remember-text {
|
|||
/* ── SUBMIT BUTTON ── */
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
background: linear-gradient(135deg, #7c5cbf, #5b3fc0);
|
||||
background: linear-gradient(135deg, #2b8ef3, #1a7ae0);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
|
|
@ -415,25 +539,47 @@ .submit-btn {
|
|||
font-family: "Plus Jakarta Sans", sans-serif;
|
||||
cursor: pointer;
|
||||
transition: all 0.25s;
|
||||
box-shadow: 0 8px 24px rgba(91, 63, 192, 0.3);
|
||||
box-shadow: 0 8px 24px rgba(43, 142, 243, 0.35);
|
||||
letter-spacing: 0.3px;
|
||||
}
|
||||
|
||||
.submit-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 12px 30px rgba(91, 63, 192, 0.4);
|
||||
box-shadow: 0 12px 30px rgba(43, 142, 243, 0.45);
|
||||
}
|
||||
|
||||
.submit-btn:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* GURU — tombol hijau */
|
||||
body.login-guru .submit-btn {
|
||||
background: linear-gradient(135deg, #22c55e, #16a34a);
|
||||
box-shadow: 0 8px 24px rgba(34, 197, 94, 0.35);
|
||||
}
|
||||
body.login-guru .submit-btn:hover {
|
||||
box-shadow: 0 12px 30px rgba(34, 197, 94, 0.45);
|
||||
}
|
||||
|
||||
/* ADMIN — tombol orange */
|
||||
body.login-admin .submit-btn {
|
||||
background: linear-gradient(135deg, #f97316, #ea580c);
|
||||
box-shadow: 0 8px 24px rgba(249, 115, 22, 0.35);
|
||||
}
|
||||
body.login-admin .submit-btn:hover {
|
||||
box-shadow: 0 12px 30px rgba(249, 115, 22, 0.45);
|
||||
}
|
||||
|
||||
/* ── DIVIDER ── */
|
||||
.card-divider {
|
||||
border: none;
|
||||
border-top: 1px solid #ede9fb;
|
||||
margin: 20px 0 16px;
|
||||
}
|
||||
body.login-guru .card-divider {
|
||||
border-top-color: #bbf7d0;
|
||||
}
|
||||
body.login-admin .card-divider {
|
||||
border-top-color: #fed7aa;
|
||||
}
|
||||
|
||||
/* ── OTHER PORTALS ── */
|
||||
.other-portals {
|
||||
|
|
@ -445,9 +591,8 @@ .other-portals {
|
|||
justify-content: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.other-portals a {
|
||||
color: #5b3fc0;
|
||||
color: var(--link-color);
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
padding: 5px 12px;
|
||||
|
|
@ -455,9 +600,8 @@ .other-portals a {
|
|||
font-size: 15px;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.other-portals a:hover {
|
||||
background: #ede9fb;
|
||||
background: var(--link-hover-bg);
|
||||
}
|
||||
|
||||
/* ── TOAST ── */
|
||||
|
|
@ -475,7 +619,6 @@ .toast-error {
|
|||
toastIn 0.3s ease both,
|
||||
toastOut 0.4s ease 3.5s forwards;
|
||||
}
|
||||
|
||||
@keyframes toastIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
|
|
@ -508,7 +651,6 @@ .back-link {
|
|||
transition: color 0.2s;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.back-link:hover {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Guru;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class GuruSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$gurus = [
|
||||
['nip' => '2343762663300043', 'nama' => 'Barizatul Kamilah'],
|
||||
['nip' => '2635762664200062', 'nama' => 'Beny Setiawan'],
|
||||
['nip' => '2460770671130082', 'nama' => 'Hasan'],
|
||||
['nip' => '6535747649200022', 'nama' => 'Fibrian Kartika Nuswanto'],
|
||||
['nip' => '8637774675130152', 'nama' => 'Andy Nur Rachman'],
|
||||
['nip' => '4447762663130173', 'nama' => 'Edi Hariyanto'],
|
||||
['nip' => '3739766667130182', 'nama' => 'Fitriyah Arizkiyanti'],
|
||||
['nip' => '4743763664300082', 'nama' => 'Uswatun Hasanah'],
|
||||
['nip' => '6433772673230272', 'nama' => 'Alvi Hidayati'],
|
||||
['nip' => '9651770671130122', 'nama' => 'Haris Nurtanio'],
|
||||
['nip' => '8152760661300073', 'nama' => 'Firlya Citra Kurniawati'],
|
||||
['nip' => '1957769670130032', 'nama' => 'Ahmad Timbul Sholeh'],
|
||||
['nip' => '1949759659200002', 'nama' => 'Muhammad Sudarmaji'],
|
||||
['nip' => '3044771672130253', 'nama' => 'Vishal Rahmat Dharmawan'],
|
||||
['nip' => '5641769670230172', 'nama' => 'Ayu Ridhawati'],
|
||||
['nip' => '8558757658200002', 'nama' => 'Adi Sumantri'],
|
||||
['nip' => '4944762664200052', 'nama' => 'Sutin Rofikah'],
|
||||
['nip' => '0043764665130213', 'nama' => 'Suwarno Arieska'],
|
||||
['nip' => '8955757659300062', 'nama' => 'Ratnaningtyas Trisnasanti'],
|
||||
];
|
||||
|
||||
foreach ($gurus as $guru) {
|
||||
Guru::create([
|
||||
'nip' => $guru['nip'],
|
||||
'nama' => $guru['nama'],
|
||||
'password' => Hash::make('password'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Siswa;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class SiswaSeeder1 extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$siswas = [
|
||||
['nisn' => '0092118525', 'nama' => 'Andika Pranata', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '0094253436', 'nama' => 'Andra Sattiawan', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '0092333773', 'nama' => 'Aryo Mahesa Tegar Hermawan', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '0071760338', 'nama' => 'Dafid Anjasmara', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '0091809817', 'nama' => 'Dirga Duwi Kusuma', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '0095281507', 'nama' => 'Elena Risky Ananta', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '0107707867', 'nama' => 'Fitriatul Jannah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '0104289644', 'nama' => 'Michkel Stevano Afftafian', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '0088998591', 'nama' => 'MOCH. Fido Haris Avian Kafabi', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '0095338610', 'nama' => 'Mohammad Aril Fatoni', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '0099906862', 'nama' => 'Mohammad Felan Madali', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '0107699211', 'nama' => 'Mohammad Vicky Safarudin Nisar', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '0098431453', 'nama' => 'Muhammad Ardiansyah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '0097601928', 'nama' => 'Muhammad Fiki Ardiyanto', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '3107025595', 'nama' => 'Muhammad Haikal', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '0089936758', 'nama' => 'Muhammad Kamil', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '3105815399', 'nama' => 'Panji Permana Putra', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '0091910408', 'nama' => 'Rizki Bachtiar Nadiansyah Ataullah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '0099891074', 'nama' => 'Rofal Ardiyansyah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 1],
|
||||
['nisn' => '0095014424', 'nama' => 'Ahmad Yali', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0099370321', 'nama' => 'Ana Septian Nuraini Fajrih', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0103667815', 'nama' => 'Andini Arifatul Hasana', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0091939551', 'nama' => 'Arkan Sakti Nusantara', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0117055954', 'nama' => 'Bela Ananda', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0099568560', 'nama' => 'Dewi Nur Arika', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0108033407', 'nama' => 'Dinda Febriani', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0083728858', 'nama' => 'Ella Nuryanti', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '3095151919', 'nama' => 'Enisa', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0108283354', 'nama' => 'Fina Ferianti', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0095581495', 'nama' => 'Gabriel Ubaydillah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '3098215305', 'nama' => 'Halimatul Azkiah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0106567109', 'nama' => 'Innani Fajariyah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0092219128', 'nama' => 'Kevin Ananda Pratama', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0098856597', 'nama' => 'Keysha Queen Salsabila', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0101865258', 'nama' => 'Lailatun Nasilah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0094527645', 'nama' => 'Ludfia Ayu Lestari', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0102553007', 'nama' => 'Maulia Feby Fajriyanti', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '3090856561', 'nama' => 'Meilandari Putri', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0092397923', 'nama' => 'Muchammad Jaka Firmansyah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0092084214', 'nama' => 'Nurul Aulia Ul Hasanah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0109110353', 'nama' => 'Qurrotul Aini', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0084601470', 'nama' => 'Saiful Rohman', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0106960081', 'nama' => 'Selawati', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '3092586488', 'nama' => 'Sitti Nasila', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0105183313', 'nama' => 'Valent Editya Maulana', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 2],
|
||||
['nisn' => '0091977438', 'nama' => 'Abdul Muavi', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0082929164', 'nama' => 'Abimanyu Restu Darmawan', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
];
|
||||
|
||||
foreach ($siswas as $siswa) {
|
||||
Siswa::create([
|
||||
'nisn' => $siswa['nisn'],
|
||||
'nama' => $siswa['nama'],
|
||||
'tempat_lahir' => $siswa['tempat_lahir'],
|
||||
'tanggal_lahir' => $siswa['tanggal_lahir'],
|
||||
'id_kelas' => $siswa['id_kelas'],
|
||||
'password' => Hash::make('dummy'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Siswa;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class SiswaSeeder2 extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$siswas = [
|
||||
['nisn' => '0091379890', 'nama' => 'Auli Maulidiya Khair', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0084775056', 'nama' => 'Balqies Nurcahyani', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0078290039', 'nama' => 'Bima Ramando Fitriah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0086803610', 'nama' => 'Bramasta Baramuli Manulang', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0099480755', 'nama' => 'Desta Bramasta Finzhando', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0099455196', 'nama' => 'Desty Alika Gusman', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0085225993', 'nama' => 'Diaz Dwi Putra Maulana', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0084181311', 'nama' => 'Moh Aldi Yansah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0087864310', 'nama' => 'Mohammad Raihan Alfarezi Ramadan', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0096867243', 'nama' => 'Mohammad Rendi Hardiansah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0085980153', 'nama' => 'Muhammad Kevin Ardiansah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0092255148', 'nama' => 'Muhammad Khalid Al Mahbubillah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0081831303', 'nama' => 'Muhammad Naufal Arif Ardiyansah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0096212311', 'nama' => 'Muhammad Noer Alief', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0093508530', 'nama' => 'Muhammad Randy', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0089492385', 'nama' => 'Raihan Azammi', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0084546336', 'nama' => 'Reztanza Tunggal Pragasta', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0086792897', 'nama' => 'Sri Quratul Aini', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0089736250', 'nama' => 'Teguh Raka Saputra', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 3],
|
||||
['nisn' => '0082223414', 'nama' => 'Afrizal Malik Haromain', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0084044726', 'nama' => 'Aisyah Oktafia', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '3091019404', 'nama' => 'Alfa Nuril Hasanah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0095563022', 'nama' => 'Aprilia Suci Andini', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0096938889', 'nama' => 'Aruni Alfa Zulfikar', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0095427183', 'nama' => 'Fheby Isni Wagina', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0088298252', 'nama' => 'Halimatus Sadiya', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0084144682', 'nama' => 'Khofifah Dwi Ningsih', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0096432735', 'nama' => 'Kholifatun Nabilah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0089220766', 'nama' => 'Lina Hikmatul Maulana', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0082068509', 'nama' => 'Mochammad Farrel Raihan Firdaus', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0061008438', 'nama' => 'Mohammad Anggi', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0098849761', 'nama' => 'Mohammad Arif Saifurrahman', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '3087033551', 'nama' => 'Mohammad Faisal Sefti Andika', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0086748054', 'nama' => 'Muhammad Bayu Purnama Putra', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0096262155', 'nama' => 'Muhammad Izil Karim', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0095339031', 'nama' => 'Muhammad Maulana Riskianto', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0085951656', 'nama' => 'Muhammad Novan Abdurahman', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0085808002', 'nama' => 'Muhammad Ridlo Rofius Syan', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0098590833', 'nama' => 'Nafiqotul Riskiyah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0084753667', 'nama' => 'Nila Septi Ramadani', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0087109093', 'nama' => 'Oktafia Fitri Ramadani', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0071526400', 'nama' => 'Putri Wulandari', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0086502762', 'nama' => 'Rahmad Dwi Ramadhani', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '3072074045', 'nama' => 'Siti Rofik Atul Amalia', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0071345906', 'nama' => 'Suryani', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0095924117', 'nama' => 'Velani Egilika Elsa Putri', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0099036913', 'nama' => 'Vita Febri Virgiyanti', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
];
|
||||
|
||||
foreach ($siswas as $siswa) {
|
||||
Siswa::create([
|
||||
'nisn' => $siswa['nisn'],
|
||||
'nama' => $siswa['nama'],
|
||||
'tempat_lahir' => $siswa['tempat_lahir'],
|
||||
'tanggal_lahir' => $siswa['tanggal_lahir'],
|
||||
'id_kelas' => $siswa['id_kelas'],
|
||||
'password' => Hash::make('dummy'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Siswa;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class SiswaSeeder3 extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$siswas = [
|
||||
['nisn' => '0087804840', 'nama' => 'Zaky Rahmad Romadhon', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 4],
|
||||
['nisn' => '0089349277', 'nama' => 'Abdul Abi Muit', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '0085016633', 'nama' => 'Achmad Rifaldyn', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '0072334482', 'nama' => 'Alan Okvan Prasetyo', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '3082900200', 'nama' => 'Bagas Dwi Adiansyah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '0067011212', 'nama' => 'Dwi Alfian Maulana', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '0085892435', 'nama' => 'Maulana Malik Ibrohim', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '0072928557', 'nama' => 'Mohammad Ramadhani Nasrollah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '0078577984', 'nama' => 'Mohammad Roni Hardiyanto', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '0087456391', 'nama' => 'Mohammad Sobri', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '0089852561', 'nama' => 'Mohammad Yusuf', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '0083326995', 'nama' => 'Muhammad Ainur Rizki', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '0088090959', 'nama' => 'Muhammad Erik Saputra', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '0073155064', 'nama' => 'Muhammad Fikrul Ilmi', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '0082286825', 'nama' => 'Muhammad Giovanni Irsyad Daffa', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '0142201337', 'nama' => 'Muhammad Niki', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '0064715822', 'nama' => 'Reno Saputra', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '0073090750', 'nama' => 'Rici Candra', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '0075636251', 'nama' => 'Triyan Saiful Hidayah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '0089983035', 'nama' => 'Yusril Andika', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 5],
|
||||
['nisn' => '0086002173', 'nama' => 'Aditya Rizky Maulana', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0088596027', 'nama' => 'Ahmad Alfarizi', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0072890707', 'nama' => 'Ahmad Farisi', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0082953576', 'nama' => 'Alvin Kurniawan', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0078134661', 'nama' => 'Atikah Faizah Lailatus Saadah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0075610319', 'nama' => 'Barneth Ajib', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0074835788', 'nama' => 'Candra Ardiansyah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0078383354', 'nama' => 'Citra Megawati', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0079070926', 'nama' => 'Desti Kiki Amelia', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0073492593', 'nama' => 'Desy Arisanty', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0078177505', 'nama' => 'Dwi Rohmatun Naysila', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0086141267', 'nama' => 'Dymas Pratama Soeprapto', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0085573222', 'nama' => 'Herfina', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0067256961', 'nama' => 'Husnan Mutawakkil Ridwan', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0082153364', 'nama' => 'Masturoh', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0077401869', 'nama' => 'Miftahul Arifin', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0081945314', 'nama' => 'Muhammad Adam Septian', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0073353544', 'nama' => 'Muhammad Haris Maksum', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0072499877', 'nama' => 'Muhammad Taufiqur Rohim', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0077906903', 'nama' => 'Naora Octa Cantika', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0072860449', 'nama' => 'Nurul Amera', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0076195649', 'nama' => 'Rasya Luluk Rahmawati', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0072695717', 'nama' => 'Raudatus Sarifah', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0073232486', 'nama' => 'Sefina Dwi Arisandi', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0071174401', 'nama' => 'Siti Fatmiati', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0088603747', 'nama' => 'Siti Maimuna', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
['nisn' => '0082235835', 'nama' => 'Suci Susanti', 'tempat_lahir' => '-', 'tanggal_lahir' => '2000-01-01', 'id_kelas' => 6],
|
||||
];
|
||||
|
||||
foreach ($siswas as $siswa) {
|
||||
Siswa::create([
|
||||
'nisn' => $siswa['nisn'],
|
||||
'nama' => $siswa['nama'],
|
||||
'tempat_lahir' => $siswa['tempat_lahir'],
|
||||
'tanggal_lahir' => $siswa['tanggal_lahir'],
|
||||
'id_kelas' => $siswa['id_kelas'],
|
||||
'password' => Hash::make('dummy'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 517 B After Width: | Height: | Size: 517 B |
|
Before Width: | Height: | Size: 347 B After Width: | Height: | Size: 347 B |
|
Before Width: | Height: | Size: 373 B After Width: | Height: | Size: 373 B |
|
Before Width: | Height: | Size: 333 B After Width: | Height: | Size: 333 B |
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 126 KiB |
|
Before Width: | Height: | Size: 137 KiB After Width: | Height: | Size: 137 KiB |
|
After Width: | Height: | Size: 982 KiB |
|
Before Width: | Height: | Size: 159 KiB After Width: | Height: | Size: 159 KiB |
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 140 KiB |
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
|
After Width: | Height: | Size: 871 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 679 B After Width: | Height: | Size: 679 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 847 B After Width: | Height: | Size: 847 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 982 B After Width: | Height: | Size: 982 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 786 B After Width: | Height: | Size: 786 B |
|
Before Width: | Height: | Size: 882 B After Width: | Height: | Size: 882 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 695 B After Width: | Height: | Size: 695 B |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 918 B After Width: | Height: | Size: 918 B |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 297 B After Width: | Height: | Size: 297 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 939 B After Width: | Height: | Size: 939 B |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |