This commit is contained in:
ghozahimma65 2026-03-05 09:48:48 +07:00
parent f01d25f200
commit 885f55c0f5
11 changed files with 372 additions and 23 deletions

View File

@ -13,6 +13,68 @@
class GuruController extends Controller
{
// Input Rapot Guru Mobile
public function storeRapot(Request $request)
{
$request->validate([
'siswa_id' => 'required',
'semester' => 'required|string',
'tahun_ajaran' => 'required|string',
'nilai_aik' => 'required|string',
'nilai_budi_pekerti' => 'required|string',
'nilai_jati_diri' => 'required|string',
'nilai_literasi_steam' => 'required|string',
'nilai_kokurikuler' => 'required|string',
// 'catatan_guru' => 'nullable|string', // Admin Rapot model does not have catatan_guru
'tinggi_badan' => 'required|numeric',
'berat_badan' => 'required|numeric',
'lingkar_kepala' => 'required|numeric',
'sakit' => 'required|numeric',
'izin' => 'required|numeric',
'alpha' => 'required|numeric',
]);
try {
// Gunakan Model Rapot (sesuai Web Admin)
$rapot = new \App\Models\Rapot();
$rapot->siswa_id = $request->siswa_id;
$rapot->semester = $request->semester;
$rapot->tahun_ajaran = $request->tahun_ajaran;
$rapot->tanggal_rapot = now()->format('Y-m-d');
// Map ke kolom Model Rapot
$rapot->narasi_agama = $request->nilai_aik;
$rapot->narasi_budi_pekerti = $request->nilai_budi_pekerti;
$rapot->narasi_jati_diri = $request->nilai_jati_diri;
$rapot->narasi_literasi = $request->nilai_literasi_steam;
$rapot->narasi_kokurikuler = $request->nilai_kokurikuler;
$rapot->tinggi_badan = $request->tinggi_badan;
$rapot->berat_badan = $request->berat_badan;
$rapot->lingkar_kepala = $request->lingkar_kepala;
$rapot->sakit = $request->sakit;
$rapot->izin = $request->izin;
$rapot->alpha = $request->alpha;
// Default Guru name from logged in user if available
$rapot->nama_guru = auth()->user()->name ?? 'Guru PAUD';
$rapot->save();
return response()->json([
'success' => true,
'message' => 'Data Rapot berhasil disimpan',
'data' => $rapot
], 201);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'Gagal menyimpan rapot: ' . $e->getMessage()
], 500);
}
}
// 1. Input Catatan Anekdot
public function storeAnekdot(Request $request)
{
@ -91,21 +153,23 @@ public function storeCeklis(Request $request)
{
// Validasi disesuaikan dengan struktur tabel penilaian_ceklis kamu
$request->validate([
'siswa_id' => 'required|exists:siswas,id',
'tanggal' => 'required|date',
'indikator' => 'required|string',
'hasil' => 'required|in:BB,MB,BSH,BSB', // Validasi skala PAUD
'keterangan'=> 'nullable|string',
'siswa_id' => 'required|exists:siswas,id',
'tanggal' => 'required|date',
'aspek_perkembangan' => 'required|string',
'indikator' => 'required|string',
'hasil' => 'required|in:BB,MB,BSH,BSB', // Validasi skala PAUD
'keterangan' => 'nullable|string',
]);
// Simpan data ke database
$ceklis = PenilaianCeklis::create([
'siswa_id' => $request->siswa_id,
'guru_id' => $request->user()->id, // Ambil ID dari Guru yang login
'tanggal' => $request->tanggal,
'indikator' => $request->indikator,
'hasil' => $request->hasil,
'keterangan'=> $request->keterangan,
'siswa_id' => $request->siswa_id,
'guru_id' => $request->user()->id, // Ambil ID dari Guru yang login
'tanggal' => $request->tanggal,
'aspek_perkembangan' => $request->aspek_perkembangan,
'indikator' => $request->indikator,
'hasil' => $request->hasil,
'keterangan' => $request->keterangan,
]);
return response()->json([

View File

@ -60,17 +60,9 @@ public function getDashboard(Request $request)
$progressPerkembangan = [];
foreach ($aspekList as $aspek) {
// Filter ceklis yang nama indikatornya mengandung kata kunci aspek
// Karena nama indikator di database bisa bervariasi, kita buat mapping persentase sederhana
// Nilai: BM=25%, MB=50%, BSH=75%, BSB=100%
$ceklisAspek = $ceklis->filter(function($item) use ($aspek) {
// Di sistem riil, indikator harus punya relasi 'aspek'.
// Karena disini plain text, kita simulasi ambil rata-rata secara mock atau jika ada kategori.
// Disini kita akan buat dummy fallback atau mock calculation per siswa untuk UI Showcase.
return true;
})->random(min($ceklis->count(), 2));
// Murni kalkulasi berdasarkan data riil yang match aspeknya
$ceklisAspek = $ceklis->where('aspek_perkembangan', $aspek);
// Kalkulasi real-ish:
$totalScore = 0;
$count = 0;
foreach ($ceklisAspek as $c) {
@ -81,7 +73,8 @@ public function getDashboard(Request $request)
$count++;
}
$percentage = $count > 0 ? round($totalScore / $count) : 0; // fallback ke 0 jika blm ada nilai
// Murni kalkulasi berdasarkan data riil, 0 jika kosong
$percentage = $count > 0 ? round($totalScore / $count) : 0;
$progressPerkembangan[] = [
'aspek' => $aspek,
@ -89,6 +82,11 @@ public function getDashboard(Request $request)
];
}
// 5. Relasi data penjemputan terakhir
$penjemputanTerakhir = \App\Models\Penjemputan::where('siswa_id', $siswa->id)
->latest()
->first();
// Return Data
return response()->json([
'success' => true,
@ -98,10 +96,92 @@ public function getDashboard(Request $request)
'nis' => $siswa->nis,
'nama' => $siswa->nama_siswa,
'kelas' => $siswa->kelompok->nama_kelompok ?? '-',
'foto' => $siswa->foto ?? null,
],
'pengumuman' => $pengumuman,
'progress' => $progressPerkembangan
'progress' => $progressPerkembangan,
'penjemputan_terakhir' => $penjemputanTerakhir
]
], 200);
}
// --- KHUSUS WALI MURID: Riwayat Penilaian Anak Spesifik (PRIVASI) ---
public function getRiwayatAnak($id)
{
$user = Auth::user();
// 1. Dapatkan Profil Wali
$wali = WaliMurid::where('user_id', $user->id)->first();
if (!$wali) {
return response()->json(['success' => false, 'message' => 'Profil Wali Murid tidak ditemukan'], 404);
}
// 2. Pastikan Siswa yang diminta benar-benar anak dari wali ini (Keamanan Privasi)
$siswa = Siswa::where('id', $id)->where('wali_murid_id', $wali->id)->first();
if (!$siswa) {
return response()->json(['success' => false, 'message' => 'Anda tidak memiliki akses ke data siswa ini'], 403);
}
// 3. Ambil Semua Data Riwayat Khusus Anak Ini Saja
$anekdot = \App\Models\Anekdot::with('siswa')
->where('siswa_id', $siswa->id)
->latest()
->get();
$ceklis = PenilaianCeklis::with('siswa')
->where('siswa_id', $siswa->id)
->latest()
->get();
$karya = \App\Models\HasilKarya::with('siswa')
->where('siswa_id', $siswa->id)
->latest()
->get()
->map(function ($item) {
if ($item->foto) {
$item->foto_url = url('storage/' . $item->foto);
}
return $item;
});
return response()->json([
'status' => 'success',
'data' => [
'anekdot' => $anekdot,
'ceklis' => $ceklis,
'karya' => $karya
]
], 200);
}
// --- KHUSUS WALI MURID: Rapot Penilaian Anak (Semester) ---
public function getRapotAnak($id)
{
$user = Auth::user();
$wali = WaliMurid::where('user_id', $user->id)->first();
if (!$wali) {
return response()->json(['success' => false, 'message' => 'Profil Wali Murid tidak ditemukan'], 404);
}
$siswa = Siswa::where('id', $id)->where('wali_murid_id', $wali->id)->first();
if (!$siswa) {
return response()->json(['success' => false, 'message' => 'Anda tidak memiliki akses ke data siswa ini'], 403);
}
// Ambil SEMUA riwayat rapot untuk siswa ini
$rapots = \App\Models\Rapot::with('siswa')
->where('siswa_id', $siswa->id)
->orderBy('created_at', 'desc')
->get();
if ($rapots->isEmpty()) {
return response()->json(['status' => 'error', 'message' => 'Rapot belum tersedia'], 404);
}
return response()->json([
'status' => 'success',
'data' => $rapots
], 200);
}
}

View File

@ -19,4 +19,9 @@ class HasilKarya extends Model
'deskripsi_foto', // Pastikan ini sama persis dengan DB
'analisis_capaian'
];
public function siswa()
{
return $this->belongsTo(Siswa::class);
}
}

View File

@ -15,6 +15,7 @@ class PenilaianCeklis extends Model
protected $fillable = [
'siswa_id',
'guru_id',
'aspek_perkembangan', // Kolom aspek_perkembangan
'indikator', // Sekarang sudah jadi teks
'tanggal',
'hasil', // Ingat, di database kamu namanya 'hasil'

View File

@ -0,0 +1,40 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class PenilaianRapot extends Model
{
protected $table = 'penilaian_rapots';
protected $fillable = [
'siswa_id',
'semester',
'tahun_ajaran',
'catatan_guru',
'nama_guru',
'nilai_aspek',
'nilai_aik',
'nilai_budi_pekerti',
'nilai_jati_diri',
'nilai_literasi_steam',
'nilai_kokurikuler',
'tinggi_badan',
'berat_badan',
'lingkar_kepala',
'sakit',
'izin',
'alpha',
'file_pdf',
];
protected $casts = [
'nilai_aspek' => 'array',
];
public function siswa()
{
return $this->belongsTo(Siswa::class);
}
}

View File

@ -0,0 +1,28 @@
<?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
{
Schema::table('penilaian_ceklis', function (Blueprint $table) {
$table->string('aspek_perkembangan')->nullable()->after('siswa_id'); // Atau diletakkan setelah guru_id/tanggal
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('penilaian_ceklis', function (Blueprint $table) {
$table->dropColumn('aspek_perkembangan');
});
}
};

View File

@ -0,0 +1,33 @@
<?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
{
Schema::create('penilaian_rapots', function (Blueprint $table) {
$table->id();
$table->foreignId('siswa_id')->constrained('siswas')->onDelete('cascade');
$table->string('semester');
$table->string('tahun_ajaran');
$table->text('catatan_guru')->nullable();
$table->string('nama_guru')->nullable();
$table->json('nilai_aspek'); // Untuk menyimpan skor 6 aspek PAUD
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('penilaian_rapots');
}
};

View File

@ -0,0 +1,47 @@
<?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
{
Schema::table('penilaian_rapots', function (Blueprint $table) {
$table->text('nilai_aik')->nullable();
$table->text('nilai_budi_pekerti')->nullable();
$table->text('nilai_jati_diri')->nullable();
$table->text('nilai_literasi_steam')->nullable();
$table->text('nilai_kokurikuler')->nullable();
$table->integer('tinggi_badan')->nullable();
$table->integer('berat_badan')->nullable();
$table->integer('lingkar_kepala')->nullable();
$table->integer('sakit')->nullable();
$table->integer('izin')->nullable();
$table->integer('alpha')->nullable();
$table->string('file_pdf')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('penilaian_rapots', function (Blueprint $table) {
$table->dropColumn([
'nilai_aik', 'nilai_budi_pekerti', 'nilai_jati_diri',
'nilai_literasi_steam', 'nilai_kokurikuler',
'tinggi_badan', 'berat_badan', 'lingkar_kepala',
'sakit', 'izin', 'alpha', 'file_pdf'
]);
});
}
};

View File

@ -49,6 +49,8 @@
// --- KHUSUS WALI MURID ---
Route::get('/wali/dashboard', [WaliController::class, 'getDashboard']);
Route::get('/wali/riwayat-anak/{id}', [WaliController::class, 'getRiwayatAnak']);
Route::get('/wali/rapot-anak/{id}', [WaliController::class, 'getRapotAnak']);
// --- KHUSUS GURU (Input Data) ---
// Nanti kalau Guru login di HP untuk input data:
@ -59,6 +61,7 @@
Route::post('/guru/karya', [GuruController::class, 'storeKarya']);
Route::post('/guru/penjemputan', [GuruController::class, 'storePenjemputan']);
Route::post('/guru/ceklis', [GuruController::class, 'storeCeklis']);
Route::post('/guru/rapot', [GuruController::class, 'storeRapot']);
// RUTE PENJEMPUTAN BARU
Route::post('/penjemputan', [PenjemputanController::class, 'store']);

22
tinker_seeder.php Normal file
View File

@ -0,0 +1,22 @@
<?php
$siswas = App\Models\Siswa::all();
foreach($siswas as $siswa) {
App\Models\PenilaianRapot::updateOrCreate(
['siswa_id' => $siswa->id],
[
'semester' => 'Genap',
'tahun_ajaran' => '2025/2026',
'catatan_guru' => 'Ananda sangat interaktif, kreatif, dan mandiri selama di kelas. Pertahankan prestasinya!',
'nama_guru' => 'Siti Aminah, S.Pd',
'nilai_aspek' => [
'Agama' => 'BSB',
'Fisik' => 'BSB',
'Kognitif' => 'BSH',
'Bahasa' => 'MB',
'SosEm' => 'BSB',
'Seni' => 'BSB'
]
]
);
}
echo "DB_RAPOT_SEEDED\n";

26
tinker_seeder_2.php Normal file
View File

@ -0,0 +1,26 @@
<?php
$siswas = App\Models\Siswa::all();
foreach($siswas as $siswa) {
App\Models\PenilaianRapot::updateOrCreate(
['siswa_id' => $siswa->id],
[
'semester' => 'Genap',
'tahun_ajaran' => '2025/2026',
'catatan_guru' => 'Ananda sangat berkembang...',
'nama_guru' => 'Siti Aminah, S.Pd',
'nilai_aik' => 'Alhamdulillah, ananda sudah mampu menghafal doa harian dengan baik.',
'nilai_budi_pekerti' => 'Ananda menunjukkan sikap santun dan peduli pada teman sebayanya.',
'nilai_jati_diri' => 'Berkembang dengan kemandirian yang tinggi saat bermain.',
'nilai_literasi_steam' => 'Menunjukkan ketertarikan luar biasa pada balok susun dan warna.',
'nilai_kokurikuler' => 'Sangat aktif dalam kegiatan seni budaya tari daerah.',
'tinggi_badan' => 110,
'berat_badan' => 18,
'lingkar_kepala' => 50,
'sakit' => 1,
'izin' => 0,
'alpha' => 0,
'file_pdf' => 'rapot/dummy_rapot.pdf'
]
);
}
echo "DB_NEW_RAPOT_SEEDED\n";