feat: endpoint statistik pelanggaran wali (kategori, jenis, tren 6 bulan)

This commit is contained in:
Novy San87
2026-08-06 12:52:25 +07:00
parent 86950060fc
commit 1b49270c4a
2 changed files with 75 additions and 0 deletions
@@ -266,6 +266,80 @@ class ParentStudentController extends Controller
]); ]);
} }
/**
* Statistik pelanggaran putra/putri (per kategori, jenis, tren bulanan).
*/
public function violationsStats(Request $request, Student $student): JsonResponse
{
$hasLink = ParentStudent::where('user_id', $request->user()->id)
->where('student_id', $student->id)
->where('status', 'active')
->exists();
abort_unless($hasLink, 403, 'Putra/putri belum tertaut aktif.');
$violations = $student->violations()
->with('violationType.category')
->get();
$totalCount = $violations->count();
$totalPoints = (int) $student->total_points;
// Per kategori (Ringan/Sedang/Berat)
$categories = $violations
->groupBy(fn ($v) => $v->violationType?->category?->id ?? 0)
->map(function ($items, $catId) {
$cat = $items->first()->violationType?->category;
return [
'name' => $cat?->name ?? 'Lainnya',
'color' => $cat?->color ?? '#94a3b8',
'count' => $items->count(),
'points' => (int) $items->sum('points'),
];
})
->values()
->sortByDesc('count')
->values();
// Jenis pelanggaran teratas
$topTypes = $violations
->groupBy(fn ($v) => $v->violation_type_id)
->map(function ($items) {
return [
'name' => $items->first()->violationType?->name ?? 'Lainnya',
'count' => $items->count(),
'points' => (int) $items->sum('points'),
];
})
->values()
->sortByDesc('count')
->take(5)
->values();
// Tren 6 bulan terakhir
$monthly = [];
for ($i = 5; $i >= 0; $i--) {
$m = now()->subMonths($i);
$key = $m->format('Y-m');
$monthly[] = [
'month' => $key,
'month_number' => (int) $m->format('n'),
'count' => $violations
->filter(fn ($v) => $v->violation_date?->format('Y-m') === $key)
->count(),
];
}
return response()->json([
'total_count' => $totalCount,
'total_points' => $totalPoints,
'categories' => $categories,
'top_types' => $topTypes,
'monthly' => $monthly,
]);
}
/** /**
* Tautkan anak tambahan (kakak/adik) ke akun wali. * Tautkan anak tambahan (kakak/adik) ke akun wali.
*/ */
+1
View File
@@ -38,6 +38,7 @@ Route::middleware('auth:sanctum')->prefix('parent')->group(function () {
Route::get('/students/{student}/schedule', [ParentStudentController::class, 'schedule'])->name('api.parent.students.schedule'); Route::get('/students/{student}/schedule', [ParentStudentController::class, 'schedule'])->name('api.parent.students.schedule');
Route::get('/students/{student}/attendance', [ParentStudentController::class, 'attendance'])->name('api.parent.students.attendance'); Route::get('/students/{student}/attendance', [ParentStudentController::class, 'attendance'])->name('api.parent.students.attendance');
Route::get('/students/{student}/points-history', [ParentStudentController::class, 'pointsHistory'])->name('api.parent.students.points-history'); Route::get('/students/{student}/points-history', [ParentStudentController::class, 'pointsHistory'])->name('api.parent.students.points-history');
Route::get('/students/{student}/violations-stats', [ParentStudentController::class, 'violationsStats'])->name('api.parent.students.violations-stats');
// Notifikasi & perangkat // Notifikasi & perangkat
Route::get('/notifications', [ParentNotificationController::class, 'index'])->name('api.parent.notifications'); Route::get('/notifications', [ParentNotificationController::class, 'index'])->name('api.parent.notifications');