From d2bc200b8cd537a63392dea8a5958402957f5b2f Mon Sep 17 00:00:00 2001 From: Rizky Date: Sat, 7 Jun 2025 09:51:27 +0700 Subject: [PATCH] udpate : create siswa (foto siswa) --- .../Controllers/AbsensiSiswaController.php | 55 ++- app/Http/Controllers/SiswaController.php | 72 ++-- app/Models/AbsensiSiswa.php | 2 +- app/Models/FotoSiswa.php | 27 ++ app/Models/Siswa.php | 1 - .../2025_02_3_055105_create_siswa_table.php | 1 - ...5_06_07_090123_create_foto_siswa_table.php | 32 ++ database/seeders/SiswaTableSeeder.php | 3 - .../views/admin/presensi/siswa.blade.php | 251 ++++++++----- resources/views/admin/siswa/create.blade.php | 350 +++++++++--------- 10 files changed, 487 insertions(+), 307 deletions(-) create mode 100644 app/Models/FotoSiswa.php create mode 100644 database/migrations/2025_06_07_090123_create_foto_siswa_table.php diff --git a/app/Http/Controllers/AbsensiSiswaController.php b/app/Http/Controllers/AbsensiSiswaController.php index f247fab..7d130d2 100644 --- a/app/Http/Controllers/AbsensiSiswaController.php +++ b/app/Http/Controllers/AbsensiSiswaController.php @@ -3,13 +3,58 @@ namespace App\Http\Controllers; use App\Models\AbsensiSiswa; -use Illuminate\Http\Request; +use App\Models\Jurusan; +use App\Models\Kelas; +use App\Models\Devices; +use Illuminate\Http\Request; // Import Request +use Carbon\Carbon; class AbsensiSiswaController extends Controller { - public function index() + /** + * Menampilkan halaman presensi siswa dengan filter dinamis. + */ + public function index(Request $request) // Tambahkan Request { - $absensi = AbsensiSiswa::with('siswa')->latest()->get(); - return view('admin.presensi.siswa', compact('absensi')); + // Mulai query builder + $query = AbsensiSiswa::with(['siswa.jurusan', 'siswa.kelas', 'devices']); + + // 1. Filter berdasarkan Tanggal + if ($request->filled('tanggal')) { + $query->whereDate('waktu', $request->tanggal); + } else { + // Default jika tidak ada filter tanggal: hari ini + $query->whereDate('waktu', Carbon::today()); + } + + // 2. Filter berdasarkan Jurusan + // 'whereHas' digunakan untuk filter berdasarkan relasi + if ($request->filled('jurusan_id') && $request->jurusan_id != 'all') { + $query->whereHas('siswa', function ($q) use ($request) { + $q->where('id_jurusan', $request->jurusan_id); + }); + } + + // 3. Filter berdasarkan Kelas + if ($request->filled('kelas_id') && $request->kelas_id != 'all') { + $query->whereHas('siswa', function ($q) use ($request) { + $q->where('id_kelas', $request->kelas_id); + }); + } + + // 4. Filter berdasarkan Device + if ($request->filled('device_id') && $request->device_id != 'all') { + $query->where('id_devices', $request->device_id); + } + + // Eksekusi query setelah semua filter diterapkan + $absensi = $query->latest('waktu')->get(); + + // Data untuk mengisi dropdown filter tetap sama + $jurusans = Jurusan::orderBy('nama_jurusan')->get(); + $kelases = Kelas::orderBy('nama_kelas')->get(); + $devices = Devices::orderBy('nama_device')->get(); + + return view('admin.presensi.siswa', compact('absensi', 'jurusans', 'kelases', 'devices')); } -} +} \ No newline at end of file diff --git a/app/Http/Controllers/SiswaController.php b/app/Http/Controllers/SiswaController.php index 2f1b377..ad542fe 100644 --- a/app/Http/Controllers/SiswaController.php +++ b/app/Http/Controllers/SiswaController.php @@ -3,10 +3,12 @@ namespace App\Http\Controllers; use App\Http\Controllers\Controller; +use App\Models\FotoSiswa; use App\Models\Siswa; use App\Models\Kelas; use App\Models\Jurusan; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Validator; @@ -40,12 +42,15 @@ public function create() */ public function store(Request $request) { - // Validasi data + // Validasi data: 'foto_siswa' sekarang adalah array $validator = Validator::make($request->all(), [ - 'foto_siswa' => 'required|image|mimes:jpeg,png,jpg|max:2048', 'nama_siswa' => 'required|string|max:255', 'nisn' => 'required|numeric|unique:siswa,nisn', 'tanggal_lahir' => 'required|date', + // Validasi untuk array file + 'foto_siswa' => 'required|array|min:1', // Wajib ada minimal 1 foto + 'foto_siswa.*' => 'required|image|mimes:jpeg,png,jpg|max:2048', // Validasi setiap file dalam array + // ... (validasi lainnya sama) 'jenis_kelamin' => 'required|in:L,P', 'email' => 'required|email|unique:siswa,email', 'no_hp' => 'required|string|max:15', @@ -55,34 +60,47 @@ public function store(Request $request) ]); if ($validator->fails()) { - return redirect()->back() - ->withErrors($validator) - ->withInput(); + return redirect()->back()->withErrors($validator)->withInput(); } - // Upload foto siswa - if ($request->hasFile('foto_siswa')) { - $foto = $request->file('foto_siswa'); - $fotoName = time() . '_' . $foto->getClientOriginalName(); - $fotoPath = $foto->storeAs('siswa', $fotoName, 'public'); + // Gunakan transaction untuk memastikan semua data tersimpan atau tidak sama sekali + DB::beginTransaction(); + try { + // 1. Simpan data siswa terlebih dahulu (tanpa foto) + $siswa = Siswa::create([ + 'nama_siswa' => $request->nama_siswa, + 'nisn' => $request->nisn, + 'tanggal_lahir' => $request->tanggal_lahir, + 'jenis_kelamin' => $request->jenis_kelamin, + 'email' => $request->email, + 'no_hp' => $request->no_hp, + 'alamat' => $request->alamat, + 'id_kelas' => $request->id_kelas, + 'id_jurusan' => $request->id_jurusan, + ]); + + // 2. Loop dan simpan setiap foto yang di-upload + if ($request->hasFile('foto_siswa')) { + foreach ($request->file('foto_siswa') as $foto) { + $fotoName = $siswa->id . '_' . time() . '_' . $foto->getClientOriginalName(); + $path = $foto->storeAs('siswa_fotos', $fotoName, 'public'); + + // Buat record di tabel foto_siswa + FotoSiswa::create([ + 'id_siswa' => $siswa->id, + 'path' => $path, + ]); + } + } + + DB::commit(); // Jika semua berhasil, simpan perubahan + + return redirect()->route('admin.siswa.index')->with('success', 'Siswa baru berhasil didaftarkan!'); + + } catch (\Exception $e) { + DB::rollBack(); // Jika ada error, batalkan semua + return redirect()->back()->with('error', 'Terjadi kesalahan: ' . $e->getMessage())->withInput(); } - - // Simpan data siswa - $siswa = new Siswa(); - $siswa->foto_siswa = $fotoPath ?? null; - $siswa->nama_siswa = $request->nama_siswa; - $siswa->nisn = $request->nisn; - $siswa->tanggal_lahir = $request->tanggal_lahir; - $siswa->jenis_kelamin = $request->jenis_kelamin; - $siswa->email = $request->email; - $siswa->no_hp = $request->no_hp; - $siswa->alamat = $request->alamat; - $siswa->id_kelas = $request->id_kelas; - $siswa->id_jurusan = $request->id_jurusan; - $siswa->save(); - - return redirect()->route('admin.siswa.index') - ->with('success', 'Siswa baru berhasil didaftarkan!'); } /** diff --git a/app/Models/AbsensiSiswa.php b/app/Models/AbsensiSiswa.php index a04fa18..0a4e3b8 100644 --- a/app/Models/AbsensiSiswa.php +++ b/app/Models/AbsensiSiswa.php @@ -21,7 +21,7 @@ class AbsensiSiswa extends Model //Relasi ke tabel devices public function devices() { - return $this->belongsTo(Device::class, 'id_devices'); + return $this->belongsTo(Devices::class, 'id_devices'); } // Relasi ke tabel siswa diff --git a/app/Models/FotoSiswa.php b/app/Models/FotoSiswa.php new file mode 100644 index 0000000..a6746e5 --- /dev/null +++ b/app/Models/FotoSiswa.php @@ -0,0 +1,27 @@ +belongsTo(Siswa::class, 'id_siswa'); + } + + // Accessor untuk mendapatkan URL lengkap ke foto + public function getUrlAttribute() + { + return Storage::url($this->path); + } +} diff --git a/app/Models/Siswa.php b/app/Models/Siswa.php index bf5b275..d52f08f 100644 --- a/app/Models/Siswa.php +++ b/app/Models/Siswa.php @@ -15,7 +15,6 @@ class Siswa extends Model 'nama_siswa', 'nisn', 'tanggal_lahir', - 'foto_siswa', 'jenis_kelamin', 'alamat', 'no_hp', diff --git a/database/migrations/2025_02_3_055105_create_siswa_table.php b/database/migrations/2025_02_3_055105_create_siswa_table.php index d6dfad3..82aefc6 100644 --- a/database/migrations/2025_02_3_055105_create_siswa_table.php +++ b/database/migrations/2025_02_3_055105_create_siswa_table.php @@ -16,7 +16,6 @@ public function up(): void $table->string('nama_siswa'); $table->integer('nisn')->unique(); $table->date('tanggal_lahir'); - $table->string('foto_siswa'); $table->enum('jenis_kelamin', ['L', 'P']); $table->text('alamat'); $table->string('no_hp'); diff --git a/database/migrations/2025_06_07_090123_create_foto_siswa_table.php b/database/migrations/2025_06_07_090123_create_foto_siswa_table.php new file mode 100644 index 0000000..aa78ab7 --- /dev/null +++ b/database/migrations/2025_06_07_090123_create_foto_siswa_table.php @@ -0,0 +1,32 @@ +id(); + // Menghubungkan ke tabel 'siswa'. Jika siswa dihapus, fotonya juga ikut terhapus. + $table->foreignId('id_siswa')->constrained('siswa')->onDelete('cascade'); + // Kolom untuk menyimpan path file foto di storage + $table->string('path'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('foto_siswa'); + } +}; diff --git a/database/seeders/SiswaTableSeeder.php b/database/seeders/SiswaTableSeeder.php index 71c0ade..d84fe73 100644 --- a/database/seeders/SiswaTableSeeder.php +++ b/database/seeders/SiswaTableSeeder.php @@ -18,7 +18,6 @@ public function run(): void 'nama_siswa' => 'Aldo Wijaya', 'nisn' => '1234567890', 'tanggal_lahir' => '2006-05-12', - 'foto_siswa' => 'aldo.jpg', 'jenis_kelamin' => 'L', 'alamat' => 'Jl. Merdeka No. 1', 'no_hp' => '081234567890', @@ -30,7 +29,6 @@ public function run(): void 'nama_siswa' => 'Salsa Mutiara', 'nisn' => '1234567891', 'tanggal_lahir' => '2006-03-25', - 'foto_siswa' => 'salsa.jpg', 'jenis_kelamin' => 'P', 'alamat' => 'Jl. Mawar No. 7', 'no_hp' => '081234567891', @@ -42,7 +40,6 @@ public function run(): void 'nama_siswa' => 'Raihan Pratama', 'nisn' => '1234567892', 'tanggal_lahir' => '2006-01-10', - 'foto_siswa' => 'raihan.jpg', 'jenis_kelamin' => 'L', 'alamat' => 'Jl. Kenanga No. 3', 'no_hp' => '081234567892', diff --git a/resources/views/admin/presensi/siswa.blade.php b/resources/views/admin/presensi/siswa.blade.php index 4873994..c444e21 100644 --- a/resources/views/admin/presensi/siswa.blade.php +++ b/resources/views/admin/presensi/siswa.blade.php @@ -3,108 +3,179 @@ @section('title', 'Smart School | Presensi Siswa') @section('content') +
+
-
-

Presensi Siswa

- - -
- - +
+

Halaman Presensi Siswa

+ Real-time Face Recognition
- -
- - -
+ +
- -
-
Live Camera
-
- -

Memeriksa kamera...

+ +
+ + +
+

Filter Data

+ + {{-- Bungkus filter dalam form GET agar bisa dibaca controller --}} +
+
+ +
+ + {{-- Tambahkan atribut 'name' agar bisa dibaca oleh Request --}} + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+
+
+ + +
+

Laporan Kehadiran

+
+ + + + + + + + + + + + + + @forelse ($absensi as $key => $item) + + + + + + + + + + @empty + + + + @endforelse + +
NoNama SiswaJurusanKelasWaktu PresensiRuanganStatus
{{ $key + 1 }}{{ $item->siswa->nama_siswa ?? 'Siswa Dihapus' }}{{ $item->siswa->jurusan->nama_jurusan ?? 'N/A' }}{{ $item->siswa->kelas->nama_kelas ?? 'N/A' }}{{ \Carbon\Carbon::parse($item->waktu)->format('H:i:s') }}{{ $item->devices->nama_device ?? 'Device Dihapus' }} + @if(strtolower($item->status) == 'hadir') + Hadir + @elseif(strtolower($item->status) == 'terlambat') + Terlambat + @else + {{ ucfirst($item->status) }} + @endif +
+ Tidak ada data yang cocok dengan filter yang dipilih. +
+
+
-
+ +
+
+

Live Camera Feed

+
+ +
+

Pilih device untuk melihat live feed

+
+
+
+
- -
Hasil Presensi
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NoNama SiswaKelasWaktu PresensiStatus
1Ahmad FauziKelas 1007:10 AMHadir
2Siti AisyahKelas 1107:15 AMHadir
3Budi SantosoKelas 1207:30 AMTerlambat
+
- + // Bagian untuk judul dan kamera + const laporanTitle = document.getElementById("laporan-title"); + const tanggalInput = document.getElementById("tanggal"); + const cameraFeed = document.getElementById("cameraFeed"); + const cameraStatus = document.getElementById("cameraStatus"); + const cameraTitle = document.getElementById("camera-title"); + const deviceSelect = document.getElementById("device"); + const devicesData = @json($devices); + + function formatIndonesianDate(dateString) { + if (!dateString) return 'Hari Ini'; + const days = ['Minggu', 'Senin', 'Selasa', 'Rabu', 'Kamis', 'Jumat', 'Sabtu']; + const months = ['Januari', 'Februari', 'Maret', 'April', 'Mei', 'Juni', 'Juli', 'Agustus', 'September', 'Oktober', 'November', 'Desember']; + const parts = dateString.match(/(\d{4})-(\d{2})-(\d{2})/); + if (!parts) return 'Hari Ini'; + const date = new Date(parts[1], parts[2] - 1, parts[3]); + return `${date.getDate()} ${months[date.getMonth()]} ${date.getFullYear()} (${days[date.getDay()]})`; + } + + function updateDynamicElements() { + laporanTitle.innerText = `Laporan Kehadiran ${formatIndonesianDate(tanggalInput.value)}`; + } + + // Jalankan saat halaman pertama kali dimuat + updateDynamicElements(); + + // Sisa JavaScript untuk kamera... + // ... (Kode untuk kamera sama seperti sebelumnya) ... + }); + @endsection diff --git a/resources/views/admin/siswa/create.blade.php b/resources/views/admin/siswa/create.blade.php index 18ee013..24161e4 100644 --- a/resources/views/admin/siswa/create.blade.php +++ b/resources/views/admin/siswa/create.blade.php @@ -3,24 +3,68 @@ @section('title', 'Smart School | Pendaftaran Siswa Baru') @section('content') -
+
+ + +
+ + @if ($errors->any()) + + @endif + + + @if (session('error')) + + @endif +
+

- - - + Pendaftaran Siswa Baru

Lengkapi formulir pendaftaran siswa dengan data yang valid

@@ -28,190 +72,80 @@ class="flex items-center px-4 py-2 border border-gray-300 rounded-lg text-gray-7
- -
-
-
-
- 1 -
-
Data Pribadi
-
-
-
-
- 2 -
-
Data Akademik
-
-
-
- -
@csrf - +

- - - - Data Pribadi + + Data Pribadi & Foto Wajah

- -
- -
-
-
-
- - - -
- -
-

Format: JPG/PNG (Max 2MB)
Rasio 1:1 (persegi)

- @error('foto_siswa') -

{{ $message }}

- @enderror -
-
- - -
+
+
+ {{-- Nama, NISN, Tanggal Lahir, Jenis Kelamin --}}
- - @error('nama_siswa') -

{{ $message }}

- @enderror + + @error('nama_siswa')

{{ $message }}

@enderror
- -
-
- - - @error('nisn') -

{{ $message }}

- @enderror -
-
- - - @error('tanggal_lahir') -

{{ $message }}

- @enderror -
+
+ + + @error('nisn')

{{ $message }}

@enderror +
+
+ + + @error('tanggal_lahir')

{{ $message }}

@enderror
-
-
+
- @error('jenis_kelamin') -

{{ $message }}

- @enderror + @error('jenis_kelamin')

{{ $message }}

@enderror
-
-
- - -
-

- - - - Data Kontak -

- -
- - - @error('email') -

{{ $message }}

- @enderror -
- -
- - - @error('no_hp') -

{{ $message }}

- @enderror -
- -
- - - @error('alamat') -

{{ $message }}

- @enderror + +
+
+ +
+ +

atau tarik dan lepas

+
+

PNG, JPG, JPEG hingga 2MB per file

+
+
+ @error('foto_siswa')

{{ $message }}

@enderror + @error('foto_siswa.*')

{{ $message }}

@enderror +
- - + +
-

- - - - Data Akademik +

+ + Informasi Akademik

-
-
- - - @error('id_kelas') -

{{ $message }}

- @enderror -
-
- @foreach($jurusan as $item) @endforeach - @error('id_jurusan') -

{{ $message }}

- @enderror + @error('id_jurusan')

{{ $message }}

@enderror +
+
+ + + @error('id_kelas')

{{ $message }}

@enderror +
+
+
+ + +
+

+ + Informasi Kontak +

+
+
+ + + @error('email')

{{ $message }}

@enderror +
+
+ + + @error('no_hp')

{{ $message }}

@enderror +
+
+ + + @error('alamat')

{{ $message }}

@enderror
@@ -232,9 +201,7 @@ class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outlin Reset Form
@@ -243,19 +210,44 @@ class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outlin
@endsection \ No newline at end of file