Update Saqel Platform: 2026-09-12 13:38:49

This commit is contained in:
Hamza-Ayed
2026-09-12 13:38:49 +03:00
parent 1f31369893
commit f4d4f02853
34 changed files with 9136 additions and 386 deletions
+73 -2
View File
@@ -126,7 +126,22 @@ class GuardianController
[$studentId]
)['cnt'] ?? 0;
// 4. Forensic Weakness Log (Recent exam attempts with AI diagnostic)
// 4. Real Error Notebook metrics from student_error_notebook
$errorStats = Database::selectOne(
"SELECT
COUNT(*) as total_errors,
COALESCE(SUM(CASE WHEN status = 'mastered' THEN 1 ELSE 0 END), 0) as mastered_count,
COALESCE(SUM(CASE WHEN status != 'mastered' THEN 1 ELSE 0 END), 0) as pending_count
FROM student_error_notebook
WHERE student_id = ?",
[$studentId]
);
$totalErrors = (int)($errorStats['total_errors'] ?? 0);
$masteredErrors = (int)($errorStats['mastered_count'] ?? 0);
$pendingErrors = (int)($errorStats['pending_count'] ?? 0);
$errorMasteryPercentage = $totalErrors > 0 ? round(($masteredErrors / $totalErrors) * 100, 1) : 100.0;
// 5. Forensic Weakness Log (Recent exam attempts with AI diagnostic)
$diagnosticLogs = Database::select(
"SELECT ea.percentage, ea.status, ea.weak_topics_json, ea.ai_diagnostic_report, ea.completed_at, e.title as exam_title, e.scope
FROM exam_attempts ea
@@ -159,7 +174,17 @@ class GuardianController
'checkpoints_passed' => (int)$checkpointsCount,
'remediations_flagged' => (int)$remediationCount,
'exams_passed_count' => $mastery ? (int)$mastery['exams_passed_count'] : 0,
'exams_total_count' => $mastery ? (int)$mastery['exams_total_count'] : 0
'exams_total_count' => $mastery ? (int)$mastery['exams_total_count'] : 0,
'error_notebook' => [
'total_errors' => $totalErrors,
'mastered_count' => $masteredErrors,
'pending_count' => $pendingErrors,
'mastery_percentage' => $errorMasteryPercentage,
],
'errors_total' => $totalErrors,
'errors_mastered' => $masteredErrors,
'errors_pending' => $pendingErrors,
'errors_mastery_rate' => $errorMasteryPercentage,
],
'diagnostics' => $diagnosticLogs
];
@@ -173,6 +198,52 @@ class GuardianController
]);
}
/**
* Get Child's Error Notebook for Guardian inspection
* GET /api/guardian/children/{id}/error-notebook
*/
public function getChildErrorNotebook(Request $request, Response $response): void
{
$guardianId = (int)$request->user_id;
$studentId = (int)$request->getParam('id');
// Verify guardian link and analytical authorization
$linked = Database::selectOne(
"SELECT id FROM guardian_students WHERE guardian_id = ? AND student_id = ? AND can_view_analytics = 1 LIMIT 1",
[$guardianId, $studentId]
);
if (!$linked) {
$response->status(403)->json(['status' => 'error', 'message' => 'غير مصرح بالوصول إلى دفتر أخطاء هذا الطالب']);
return;
}
$items = Database::select(
"SELECT * FROM student_error_notebook WHERE student_id = ? ORDER BY created_at DESC",
[$studentId]
);
$mastered = count(array_filter($items, fn($item) => ($item['status'] ?? '') === 'mastered'));
$total = count($items);
$bySubject = [];
foreach ($items as $item) {
$name = (string)($item['subject_name'] ?? '');
if ($name !== '') $bySubject[$name] = ($bySubject[$name] ?? 0) + 1;
}
$response->json([
'status' => 'success',
'data' => [
'summary' => [
'total_errors' => $total,
'mastered_count' => $mastered,
'pending_count' => $total - $mastered,
'mastery_percentage' => $total > 0 ? round(($mastered / $total) * 100, 1) : 100.0,
'by_subject' => $bySubject,
],
'items' => $items,
],
]);
}
private function maskNationalId(string $storedValue): string
{
if ($storedValue === '') {