From c9ac266bd624a440ba66f4b82a9c5f206f17bdd1 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Thu, 16 Apr 2026 06:58:53 +0000 Subject: [PATCH] Autosave: 20260416-065856 --- application_detail.php | 11 + applications.php | 8 +- approved_school.php | 189 ++++++++++ assets/css/custom.css | 149 ++++++++ db/migrations/20260416_school_modules.sql | 70 ++++ includes/app.php | 400 ++++++++++++++++++++++ students.php | 303 ++++++++++++++++ teachers.php | 280 +++++++++++++++ 8 files changed, 1409 insertions(+), 1 deletion(-) create mode 100644 approved_school.php create mode 100644 db/migrations/20260416_school_modules.sql create mode 100644 students.php create mode 100644 teachers.php diff --git a/application_detail.php b/application_detail.php index b7631c1..8846f5c 100644 --- a/application_detail.php +++ b/application_detail.php @@ -40,6 +40,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($reviewErrors === []) { try { update_application_review($applicationId, $status, $adminNotes, $evaluationScore === false ? null : $evaluationScore); + if ($status === 'approved') { + set_flash('success', 'تم اعتماد المركز بنجاح، وهذه هي صفحة الهبوط الخاصة به بعد الموافقة.'); + header('Location: approved_school.php?id=' . urlencode((string) $applicationId)); + exit; + } set_flash('success', 'تم تحديث حالة الطلب وملاحظات التقييم بنجاح.'); header('Location: application_detail.php?id=' . urlencode((string) $applicationId)); exit; @@ -74,6 +79,9 @@ render_flash($flash);
الحالة الحالية
هذا الملف مخصص لاتخاذ القرار وتوثيق الملاحظات بدلاً من خلطه مع قائمة الطلبات.
+ + فتح صفحة المركز المعتمد + @@ -165,6 +173,9 @@ render_flash($flash);
+ + معاينة صفحة المركز + العودة إلى القائمة
diff --git a/applications.php b/applications.php index af59287..35456ea 100644 --- a/applications.php +++ b/applications.php @@ -111,7 +111,13 @@ render_flash($flash); - فتح الملف + + + صفحة المركز + + فتح الملف + + diff --git a/approved_school.php b/approved_school.php new file mode 100644 index 0000000..0744080 --- /dev/null +++ b/approved_school.php @@ -0,0 +1,189 @@ + 0 ? get_application($applicationId) : null; + +if (!$application) { + http_response_code(404); + render_page_start('صفحة المركز غير موجودة', 'approved', 'تعذر العثور على المركز المطلوب لعرض صفحة الهبوط بعد الاعتماد.'); + render_flash($flash); + ?> +
+
+
+
المركز غير موجود
+

تحقق من رقم الطلب أو ارجع إلى قائمة المراكز المعتمدة.

+ عرض المراكز المعتمدة +
+
+
+ = $startTs) { + $durationDays = (int) floor(($endTs - $startTs) / 86400) + 1; +} + +$pageTitle = $isApproved ? 'صفحة المركز المعتمد: ' . (string) $application['center_name'] : 'صفحة المركز بعد الاعتماد'; +$pageDescription = $isApproved + ? 'صفحة هبوط تشغيلية للمركز المعتمد تعرض الجاهزية، بيانات التواصل، والخطوات التالية بعد الموافقة.' + : 'هذه الصفحة تصبح متاحة بعد اعتماد طلب المركز من المشرف العام.'; + +render_page_start($pageTitle, 'approved', $pageDescription); +render_flash($flash); +?> +
+
+ +
+
+
+ هذه الصفحة تُفتح بعد الاعتماد فقط +

+

تم تجهيز صفحة الهبوط لهذا المركز، لكنها ستصبح الصفحة التشغيلية الرسمية فقط بعد تغيير الحالة إلى معتمد.

+
+ الحالة الحالية: + مرجع الطلب # +
+ +
+
+
+ +
+
+
+ مركز معتمد وجاهز للانطلاق +

+

هذه صفحة الهبوط الخاصة بالمركز بعد الاعتماد. يمكن استخدامها كنقطة دخول منظمة لبدء التشغيل، تجهيز التسجيل، ومشاركة المعلومات الأساسية مع فريق المدرسة.

+
+ + + من إلى +
+ +
+
+
+
ملخص الجاهزية
+ +
%درجة التقييم
+
+ +
+
مدير المركز
+
السعة المتوقعة طالب
+
مدة البرنامج 0 ? $durationDays : '—')) ?> يوم
+
+
+
+
+
+ +
+
حالة الاعتماد
معتمد
تمت الموافقة الرسمية على تشغيل هذا المركز.
+
المقاعد المتوقعة
الطاقة الاستيعابية المبدئية للتسجيل.
+
مدة البرنامج
0 ? $durationDays : '—')) ?>
عدد الأيام المخططة بين البداية والنهاية.
+
مرجع التشغيل
#
استخدم هذا الرقم في أي متابعة إدارية لاحقة.
+
+ +
+
+
+
+
+
نبذة المدرسة / المركز
+
الرسالة المختصرة التي تظهر مباشرة بعد الاعتماد لتلخيص هوية المركز وما يقدمه.
+
+
+

+
+ +
+
أسباب الجاهزية والاعتماد
+
+
+ ملف مكتمل +

تمت مراجعة البيانات الأساسية، المسؤول المباشر، وفترة التشغيل المقترحة قبل إصدار الاعتماد.

+
+
+ خطة تشغيل واضحة +

توجد سعة متوقعة وبرنامج زمني محدد يساعدان على بدء التسجيل وإسناد المهام بسرعة.

+
+
+ قابلية للإطلاق +

يمكن اعتماد هذه الصفحة كنقطة انتقال من المراجعة إلى الإدارة اليومية ثم التوسع لوحدات الطلاب والغياب والتقييم.

+
+
+
+ +
+
الخطوات التالية بعد الموافقة
+
+
+ 1) فتح التسجيل +

المرحلة التالية المنطقية أصبحت جاهزة الآن: يمكن فتح صفحة مستقلة لتسجيل الطلاب وربطها مباشرة بالمركز المعتمد.

+
+
+ 2) تجهيز الفريق +

صفحة الفريق أصبحت جاهزة الآن لإضافة المعلمين والمشرفين وربط أدوارهم التشغيلية مباشرة بالمركز المعتمد.

+
+
+ 3) متابعة التشغيل +

بعد الانطلاق يمكن توسيع هذه الصفحة لاحقاً بمؤشرات حضور يومية، تقييمات، وتنبيهات تشغيلية.

+
+
+
+
+ + +
+ +
+
+exec($sql); + } + } + + $done = true; +} + +function seed_school_module_demo_data(PDO $pdo): void +{ + $approvedId = (int) $pdo->query("SELECT id FROM center_applications WHERE status = 'approved' ORDER BY id ASC LIMIT 1")->fetchColumn(); + if ($approvedId <= 0) { + return; + } + + $studentCount = (int) $pdo->query('SELECT COUNT(*) FROM school_students')->fetchColumn(); + if ($studentCount === 0) { + $studentRows = [ + ['ST-301', 'أحمد بن سالم الحارثي', 'طالب', 'الصف السابع', 'سالم الحارثي', '0501112233', '2013-03-11', 'active', 'مسجل في مسار القرآن والابتكار.'], + ['ST-302', 'مريم بنت ناصر الكندية', 'طالبة', 'الصف الثامن', 'ناصر الكندي', '0502223344', '2012-11-05', 'active', 'بحاجة إلى متابعة في الأنشطة العلمية.'], + ['ST-303', 'سيف بن راشد المقبالي', 'طالب', 'الصف السادس', 'راشد المقبالي', '0503334455', '2014-01-22', 'waiting', 'بانتظار تأكيد المقعد بعد مراجعة السعة.'], + ]; + + $studentStmt = $pdo->prepare( + 'INSERT INTO school_students ( + center_application_id, student_code, full_name, gender, grade_level, + guardian_name, guardian_phone, birth_date, enrollment_status, notes, + created_at, updated_at + ) VALUES ( + :center_application_id, :student_code, :full_name, :gender, :grade_level, + :guardian_name, :guardian_phone, :birth_date, :enrollment_status, :notes, + NOW(), NOW() + )' + ); + + foreach ($studentRows as $row) { + $studentStmt->execute([ + ':center_application_id' => $approvedId, + ':student_code' => $row[0], + ':full_name' => $row[1], + ':gender' => $row[2], + ':grade_level' => $row[3], + ':guardian_name' => $row[4], + ':guardian_phone' => $row[5], + ':birth_date' => $row[6], + ':enrollment_status' => $row[7], + ':notes' => $row[8], + ]); + } + } + + $teacherCount = (int) $pdo->query('SELECT COUNT(*) FROM school_teachers')->fetchColumn(); + if ($teacherCount === 0) { + $teacherRows = [ + ['أ. هدى بنت راشد المعمرية', 'مشرفة أكاديمية', 'اللغة العربية والقرآن', '0504445566', 'huda.muamari@example.com', 'active', 'تقود خطة الإشراف الأكاديمي لهذا الموسم.'], + ['أ. مازن بن سعيد البلوشي', 'منسق أنشطة', 'الأنشطة العلمية والابتكار', '0505556677', 'mazin.balushi@example.com', 'active', 'مسؤول عن الربط بين الأنشطة الصفية والفعاليات الأسبوعية.'], + ['أ. عائشة بنت خالد السعدية', 'معلمة', 'الرياضيات والمهارات الرقمية', '0506667788', 'aisha.saadiya@example.com', 'pending', 'بانتظار استكمال جدولها النهائي قبل التفعيل الكامل.'], + ]; + + $teacherStmt = $pdo->prepare( + 'INSERT INTO school_teachers ( + center_application_id, full_name, role_title, specialization, + phone, email, employment_status, notes, + created_at, updated_at + ) VALUES ( + :center_application_id, :full_name, :role_title, :specialization, + :phone, :email, :employment_status, :notes, + NOW(), NOW() + )' + ); + + foreach ($teacherRows as $row) { + $teacherStmt->execute([ + ':center_application_id' => $approvedId, + ':full_name' => $row[0], + ':role_title' => $row[1], + ':specialization' => $row[2], + ':phone' => $row[3], + ':email' => $row[4], + ':employment_status' => $row[5], + ':notes' => $row[6], + ]); + } + } +} + function seed_center_application_demo_data(PDO $pdo): void { $count = (int) $pdo->query('SELECT COUNT(*) FROM center_applications')->fetchColumn(); @@ -376,6 +474,306 @@ function latest_applications(int $limit = 5): array return $stmt->fetchAll(); } +function student_defaults(): array +{ + return [ + 'student_code' => '', + 'full_name' => '', + 'gender' => '', + 'grade_level' => '', + 'guardian_name' => '', + 'guardian_phone' => '', + 'birth_date' => '', + 'enrollment_status' => 'active', + 'notes' => '', + ]; +} + +function student_gender_options(): array +{ + return ['طالب', 'طالبة']; +} + +function student_grade_options(): array +{ + return [ + 'الصف الرابع', + 'الصف الخامس', + 'الصف السادس', + 'الصف السابع', + 'الصف الثامن', + 'الصف التاسع', + 'الصف العاشر', + 'الصف الحادي عشر', + 'الصف الثاني عشر', + ]; +} + +function student_enrollment_status_map(): array +{ + return [ + 'active' => ['label' => 'مسجل', 'class' => 'status-approved'], + 'waiting' => ['label' => 'قائمة انتظار', 'class' => 'status-review'], + 'withdrawn' => ['label' => 'منسحب', 'class' => 'status-muted'], + ]; +} + +function student_enrollment_status_badge(string $status): string +{ + $map = student_enrollment_status_map(); + $meta = $map[$status] ?? ['label' => 'غير محدد', 'class' => 'status-muted']; + return '' . e($meta['label']) . ''; +} + +function validate_student_input(array $input): array +{ + $data = student_defaults(); + foreach ($data as $key => $_value) { + $limit = $key === 'notes' ? 1000 : ($key === 'student_code' ? 60 : 190); + $data[$key] = clean_text((string) ($input[$key] ?? ''), $limit); + } + + $errors = []; + + if ($data['student_code'] === '') { + $errors['student_code'] = 'يرجى إدخال الرقم أو الكود المرجعي للطالب.'; + } + if ($data['full_name'] === '') { + $errors['full_name'] = 'يرجى إدخال اسم الطالب أو الطالبة.'; + } + if (!in_array($data['gender'], student_gender_options(), true)) { + $errors['gender'] = 'يرجى تحديد النوع.'; + } + if (!in_array($data['grade_level'], student_grade_options(), true)) { + $errors['grade_level'] = 'يرجى اختيار الصف الدراسي.'; + } + if ($data['guardian_name'] === '') { + $errors['guardian_name'] = 'يرجى إدخال اسم ولي الأمر.'; + } + if ($data['guardian_phone'] === '' || strlen($data['guardian_phone']) < 7) { + $errors['guardian_phone'] = 'يرجى إدخال رقم هاتف صحيح لولي الأمر.'; + } + + $birthDate = clean_text((string) ($input['birth_date'] ?? ''), 20); + $data['birth_date'] = $birthDate; + if ($birthDate !== '' && strtotime($birthDate) === false) { + $errors['birth_date'] = 'يرجى إدخال تاريخ ميلاد صحيح أو تركه فارغاً.'; + } + + $statusMap = student_enrollment_status_map(); + if (!array_key_exists($data['enrollment_status'], $statusMap)) { + $errors['enrollment_status'] = 'يرجى اختيار حالة تسجيل صحيحة.'; + } + + return [$data, $errors]; +} + +function create_student(int $centerApplicationId, array $data): int +{ + $pdo = db_connection(); + $stmt = $pdo->prepare( + 'INSERT INTO school_students ( + center_application_id, student_code, full_name, gender, grade_level, + guardian_name, guardian_phone, birth_date, enrollment_status, notes, + created_at, updated_at + ) VALUES ( + :center_application_id, :student_code, :full_name, :gender, :grade_level, + :guardian_name, :guardian_phone, :birth_date, :enrollment_status, :notes, + NOW(), NOW() + )' + ); + + $stmt->bindValue(':center_application_id', $centerApplicationId, PDO::PARAM_INT); + $stmt->bindValue(':student_code', $data['student_code'], PDO::PARAM_STR); + $stmt->bindValue(':full_name', $data['full_name'], PDO::PARAM_STR); + $stmt->bindValue(':gender', $data['gender'], PDO::PARAM_STR); + $stmt->bindValue(':grade_level', $data['grade_level'], PDO::PARAM_STR); + $stmt->bindValue(':guardian_name', $data['guardian_name'], PDO::PARAM_STR); + $stmt->bindValue(':guardian_phone', $data['guardian_phone'], PDO::PARAM_STR); + $stmt->bindValue(':birth_date', $data['birth_date'] !== '' ? $data['birth_date'] : null, $data['birth_date'] !== '' ? PDO::PARAM_STR : PDO::PARAM_NULL); + $stmt->bindValue(':enrollment_status', $data['enrollment_status'], PDO::PARAM_STR); + $stmt->bindValue(':notes', $data['notes'] !== '' ? $data['notes'] : null, $data['notes'] !== '' ? PDO::PARAM_STR : PDO::PARAM_NULL); + $stmt->execute(); + + return (int) $pdo->lastInsertId(); +} + +function list_school_students(int $centerApplicationId): array +{ + $pdo = db_connection(); + $stmt = $pdo->prepare('SELECT * FROM school_students WHERE center_application_id = :center_application_id ORDER BY created_at DESC, id DESC'); + $stmt->bindValue(':center_application_id', $centerApplicationId, PDO::PARAM_INT); + $stmt->execute(); + return $stmt->fetchAll(); +} + +function school_student_metrics(int $centerApplicationId): array +{ + $pdo = db_connection(); + $stmt = $pdo->prepare( + "SELECT + COUNT(*) AS total, + COALESCE(SUM(gender = 'طالب'), 0) AS boys, + COALESCE(SUM(gender = 'طالبة'), 0) AS girls, + COALESCE(SUM(enrollment_status = 'active'), 0) AS active_count, + COALESCE(SUM(enrollment_status = 'waiting'), 0) AS waiting_count, + COALESCE(SUM(enrollment_status = 'withdrawn'), 0) AS withdrawn_count + FROM school_students + WHERE center_application_id = :center_application_id" + ); + $stmt->bindValue(':center_application_id', $centerApplicationId, PDO::PARAM_INT); + $stmt->execute(); + $row = $stmt->fetch() ?: []; + + return [ + 'total' => (int) ($row['total'] ?? 0), + 'boys' => (int) ($row['boys'] ?? 0), + 'girls' => (int) ($row['girls'] ?? 0), + 'active' => (int) ($row['active_count'] ?? 0), + 'waiting' => (int) ($row['waiting_count'] ?? 0), + 'withdrawn' => (int) ($row['withdrawn_count'] ?? 0), + ]; +} + + +function teacher_defaults(): array +{ + return [ + 'full_name' => '', + 'role_title' => '', + 'specialization' => '', + 'phone' => '', + 'email' => '', + 'employment_status' => 'active', + 'notes' => '', + ]; +} + +function teacher_role_options(): array +{ + return [ + 'معلم', + 'معلمة', + 'مشرف أكاديمي', + 'مشرفة أكاديمية', + 'منسق أنشطة', + 'مسؤول متابعة', + 'إداري', + ]; +} + +function teacher_employment_status_map(): array +{ + return [ + 'active' => ['label' => 'مفعل', 'class' => 'status-approved'], + 'pending' => ['label' => 'بانتظار التفعيل', 'class' => 'status-review'], + 'inactive' => ['label' => 'غير مفعل', 'class' => 'status-muted'], + ]; +} + +function teacher_employment_status_badge(string $status): string +{ + $map = teacher_employment_status_map(); + $meta = $map[$status] ?? ['label' => 'غير محدد', 'class' => 'status-muted']; + return '' . e($meta['label']) . ''; +} + +function validate_teacher_input(array $input): array +{ + $data = teacher_defaults(); + foreach ($data as $key => $_value) { + $limit = $key === 'notes' ? 1000 : 190; + $data[$key] = clean_text((string) ($input[$key] ?? ''), $limit); + } + + $errors = []; + + if ($data['full_name'] === '') { + $errors['full_name'] = 'يرجى إدخال اسم عضو الفريق.'; + } + if (!in_array($data['role_title'], teacher_role_options(), true)) { + $errors['role_title'] = 'يرجى اختيار الدور الوظيفي.'; + } + if ($data['phone'] !== '' && strlen($data['phone']) < 7) { + $errors['phone'] = 'أدخل رقم هاتف صحيحاً أو اتركه فارغاً.'; + } + if ($data['email'] !== '' && !filter_var($data['email'], FILTER_VALIDATE_EMAIL)) { + $errors['email'] = 'أدخل بريداً إلكترونياً صحيحاً أو اتركه فارغاً.'; + } + + $statusMap = teacher_employment_status_map(); + if (!array_key_exists($data['employment_status'], $statusMap)) { + $errors['employment_status'] = 'يرجى اختيار حالة توظيف صحيحة.'; + } + + return [$data, $errors]; +} + +function create_teacher(int $centerApplicationId, array $data): int +{ + $pdo = db_connection(); + $stmt = $pdo->prepare( + 'INSERT INTO school_teachers ( + center_application_id, full_name, role_title, specialization, + phone, email, employment_status, notes, + created_at, updated_at + ) VALUES ( + :center_application_id, :full_name, :role_title, :specialization, + :phone, :email, :employment_status, :notes, + NOW(), NOW() + )' + ); + + $stmt->bindValue(':center_application_id', $centerApplicationId, PDO::PARAM_INT); + $stmt->bindValue(':full_name', $data['full_name'], PDO::PARAM_STR); + $stmt->bindValue(':role_title', $data['role_title'], PDO::PARAM_STR); + $stmt->bindValue(':specialization', $data['specialization'] !== '' ? $data['specialization'] : null, $data['specialization'] !== '' ? PDO::PARAM_STR : PDO::PARAM_NULL); + $stmt->bindValue(':phone', $data['phone'] !== '' ? $data['phone'] : null, $data['phone'] !== '' ? PDO::PARAM_STR : PDO::PARAM_NULL); + $stmt->bindValue(':email', $data['email'] !== '' ? $data['email'] : null, $data['email'] !== '' ? PDO::PARAM_STR : PDO::PARAM_NULL); + $stmt->bindValue(':employment_status', $data['employment_status'], PDO::PARAM_STR); + $stmt->bindValue(':notes', $data['notes'] !== '' ? $data['notes'] : null, $data['notes'] !== '' ? PDO::PARAM_STR : PDO::PARAM_NULL); + $stmt->execute(); + + return (int) $pdo->lastInsertId(); +} + +function list_school_teachers(int $centerApplicationId): array +{ + $pdo = db_connection(); + $stmt = $pdo->prepare('SELECT * FROM school_teachers WHERE center_application_id = :center_application_id ORDER BY created_at DESC, id DESC'); + $stmt->bindValue(':center_application_id', $centerApplicationId, PDO::PARAM_INT); + $stmt->execute(); + return $stmt->fetchAll(); +} + +function school_teacher_metrics(int $centerApplicationId): array +{ + $pdo = db_connection(); + $stmt = $pdo->prepare( + "SELECT + COUNT(*) AS total, + COALESCE(SUM(employment_status = 'active'), 0) AS active_count, + COALESCE(SUM(employment_status = 'pending'), 0) AS pending_count, + COALESCE(SUM(employment_status = 'inactive'), 0) AS inactive_count, + COALESCE(SUM(email IS NOT NULL AND email <> ''), 0) AS email_ready_count, + COALESCE(SUM(role_title LIKE '%مشرف%'), 0) AS supervisors_count + FROM school_teachers + WHERE center_application_id = :center_application_id" + ); + $stmt->bindValue(':center_application_id', $centerApplicationId, PDO::PARAM_INT); + $stmt->execute(); + $row = $stmt->fetch() ?: []; + + return [ + 'total' => (int) ($row['total'] ?? 0), + 'active' => (int) ($row['active_count'] ?? 0), + 'pending' => (int) ($row['pending_count'] ?? 0), + 'inactive' => (int) ($row['inactive_count'] ?? 0), + 'email_ready' => (int) ($row['email_ready_count'] ?? 0), + 'supervisors' => (int) ($row['supervisors_count'] ?? 0), + ]; +} + function render_page_start(string $pageTitle, string $active = 'home', string $pageDescription = ''): void { $projectName = project_name(); @@ -426,6 +824,7 @@ function render_page_start(string $pageTitle, string $active = 'home', string $p +
@@ -479,6 +878,7 @@ function render_page_end(): void لوحة القيادة إنشاء طلب جديد استعراض جميع الطلبات + المراكز المعتمدة هيكل النظام فحص الحالة
diff --git a/students.php b/students.php new file mode 100644 index 0000000..95cfc3e --- /dev/null +++ b/students.php @@ -0,0 +1,303 @@ + 0 ? get_application($applicationId) : null; +$isApprovedSchool = $application && (string) $application['status'] === 'approved'; +$values = student_defaults(); +$errors = []; + +if ($_SERVER['REQUEST_METHOD'] === 'POST' && $application) { + [$values, $errors] = validate_student_input($_POST); + + if (!$isApprovedSchool) { + $errors['form'] = 'لا يمكن فتح تسجيل الطلاب قبل اعتماد المركز.'; + } + + if ($errors === []) { + try { + create_student((int) $application['id'], $values); + set_flash('success', 'تم تسجيل الطالب بنجاح وإضافته إلى كشف المدرسة.'); + header('Location: students.php?id=' . urlencode((string) $application['id'])); + exit; + } catch (PDOException $exception) { + $duplicateCode = isset($exception->errorInfo[1]) && (int) $exception->errorInfo[1] === 1062; + if ($duplicateCode) { + $errors['student_code'] = 'هذا الكود مستخدم مسبقاً داخل نفس المدرسة.'; + } else { + $errors['form'] = 'تعذر حفظ بيانات الطالب حالياً. يرجى المحاولة مرة أخرى.'; + } + } catch (Throwable $exception) { + $errors['form'] = 'تعذر حفظ بيانات الطالب حالياً. يرجى المحاولة مرة أخرى.'; + } + } +} + +$students = $isApprovedSchool ? list_school_students((int) $application['id']) : []; +$metrics = $isApprovedSchool ? school_student_metrics((int) $application['id']) : [ + 'total' => 0, + 'boys' => 0, + 'girls' => 0, + 'active' => 0, + 'waiting' => 0, + 'withdrawn' => 0, +]; + +$expectedCapacity = $application ? (int) ($application['expected_students'] ?? 0) : 0; +$remainingSeats = max(0, $expectedCapacity - $metrics['total']); +$pageTitle = $application ? 'تسجيل الطلاب: ' . (string) $application['center_name'] : 'تسجيل الطلاب'; +$pageDescription = 'صفحة مستقلة لتسجيل الطلاب وإدارة كشف المدرسة بعد الاعتماد، مع فصل واضح بين النموذج والكشف والجاهزية التشغيلية.'; + +if (!$application) { + http_response_code(404); +} + +render_page_start($pageTitle, 'approved', $pageDescription); +render_flash($flash); +?> +
+
+ +
+
المدرسة غير موجودة
+

تحقق من رابط المدرسة أو ارجع إلى قائمة المراكز المعتمدة.

+ المراكز المعتمدة +
+ +
+
+
+ التسجيل يبدأ بعد الاعتماد +

+

هذه الصفحة جاهزة، لكن فتح سجل الطلاب مرتبط بتحويل حالة المركز إلى معتمد أولاً حتى يبقى التسلسل الإداري منظمًا.

+
+ الحالة الحالية: + المدينة: +
+ +
+
+
+ +
+
+
+ صفحة مستقلة لتسجيل الطلاب +

سجل الطلاب —

+

هذا هو أول موديول تشغيلي بعد اعتماد المدرسة. هنا يتم إدخال بيانات الطلاب في صفحة منفصلة وواضحة، مع كشف جاهز للمراجعة دون خلطه مع بقية وظائف المدرسة.

+
+ + السعة المعتمدة طالب + المقاعد المتبقية +
+ +
+
+
+
ملخص التسجيل
+
+
إجمالي الطلاب
+
طلاب مؤكدون
+
قائمة الانتظار
+
+
+

تم شغل من أصل مقعد متوقع حتى الآن.

+
+
+
+
+ +
+
+ + + +
+ +
+
+
+
+
كشف المدرسة
+
الطلاب المسجلون حالياً في هذه المدرسة فقط.
+
+ طلاب / طالبات +
+ +
+
إجمالي القيد طالب
+
حالات نشطة طالب مؤكد
+
مقاعد متاحة مقعد متبقٍ
+
+ + +
+
لا يوجد طلاب مسجلون بعد
+

ابدأ من نموذج التسجيل في الجانب الأيمن لإضافة أول طالب إلى كشف المدرسة.

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
الكودالطالبالصفولي الأمرالهاتفالحالةالتسجيل
+ + + + + +
+
+ +
+ +
+
سياق المدرسة
+
+
مدير المركز
+
فترة التشغيل
+
الفئة المستهدفة
+
البريد الرسمي
+
+
+
+
+ +
+
+ diff --git a/teachers.php b/teachers.php new file mode 100644 index 0000000..66ea2a8 --- /dev/null +++ b/teachers.php @@ -0,0 +1,280 @@ + 0 ? get_application($applicationId) : null; +$isApprovedSchool = $application && (string) $application['status'] === 'approved'; +$values = teacher_defaults(); +$errors = []; + +if ($_SERVER['REQUEST_METHOD'] === 'POST' && $application) { + [$values, $errors] = validate_teacher_input($_POST); + + if (!$isApprovedSchool) { + $errors['form'] = 'لا يمكن فتح صفحة المعلمين قبل اعتماد المركز.'; + } + + if ($errors === []) { + try { + create_teacher((int) $application['id'], $values); + set_flash('success', 'تمت إضافة عضو الفريق بنجاح إلى سجل المدرسة.'); + header('Location: teachers.php?id=' . urlencode((string) $application['id'])); + exit; + } catch (Throwable $exception) { + $errors['form'] = 'تعذر حفظ بيانات عضو الفريق حالياً. يرجى المحاولة مرة أخرى.'; + } + } +} + +$teachers = $isApprovedSchool ? list_school_teachers((int) $application['id']) : []; +$metrics = $isApprovedSchool ? school_teacher_metrics((int) $application['id']) : [ + 'total' => 0, + 'active' => 0, + 'pending' => 0, + 'inactive' => 0, + 'email_ready' => 0, + 'supervisors' => 0, +]; + +$studentMetrics = $isApprovedSchool ? school_student_metrics((int) $application['id']) : [ + 'total' => 0, + 'active' => 0, + 'waiting' => 0, + 'withdrawn' => 0, + 'boys' => 0, + 'girls' => 0, +]; + +$pageTitle = $application ? 'فريق المعلمين: ' . (string) $application['center_name'] : 'فريق المعلمين'; +$pageDescription = 'صفحة مستقلة لإدارة المعلمين والمشرفين بعد اعتماد المدرسة، مع فصل واضح بين إضافة الكادر وكشف الفريق ومؤشرات الجاهزية.'; + +if (!$application) { + http_response_code(404); +} + +render_page_start($pageTitle, 'approved', $pageDescription); +render_flash($flash); +?> +
+
+ +
+
المدرسة غير موجودة
+

تحقق من رابط المدرسة أو ارجع إلى قائمة المراكز المعتمدة.

+ المراكز المعتمدة +
+ +
+
+
+ الفريق يُفعّل بعد الاعتماد +

+

تم تجهيز صفحة المعلمين، لكن فتح سجل الفريق مرتبط بتحويل حالة المركز إلى معتمد أولاً حتى يبدأ التشغيل وفق الترتيب الإداري الصحيح.

+
+ الحالة الحالية: + المدينة: +
+ +
+
+
+ +
+
+
+ صفحة مستقلة لإدارة الفريق التعليمي +

فريق المدرسة —

+

بعد فتح سجل الطلاب، هذه هي الصفحة المنطقية التالية لبناء الكادر. يمكن هنا إضافة المعلمين والمشرفين والكوادر المساندة مع عزل واضح بين النموذج وكشف الفريق.

+
+ + أعضاء مفعلون + أدوار إشرافية +
+ +
+
+
+
ملخص الفريق
+
+
إجمالي الكادر عضو
+
جاهزون للتواصل ببريد موثق
+
الطلاب النشطون طالب/طالبة
+
+

وجود سجل واضح للمعلمين يسهّل لاحقاً ربط الحصص، التقييمات، والمتابعة اليومية لكل مدرسة معتمدة.

+
+
+
+
+ +
+
إجمالي الفريق
عدد أعضاء الكادر المسجلين لهذا المركز.
+
مفعلون
جاهزون للبدء الفعلي ضمن الخطة التشغيلية.
+
بانتظار التفعيل
يحتاجون استكمال الجدول أو الموافقة النهائية.
+
أدوار إشرافية
أعضاء في أدوار إشرافية أو قيادية.
+
+ +
+
+ + + +
+ +
+
+
+
+
كشف الفريق التعليمي
+
جميع المعلمين والمشرفين المرتبطين بهذا المركز فقط.
+
+ بريد جاهز / بانتظار التفعيل +
+ +
+
إجمالي الفريق عضو
+
أدوار قيادية إشرافي
+
مع الطلاب النشطين طالب/طالبة
+
+ + +
+
لا يوجد أعضاء فريق مسجلون بعد
+

ابدأ من النموذج في الجانب الأيمن لإضافة أول معلم أو مشرف إلى سجل المدرسة.

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
الاسمالدورالتخصصالتواصلالحالةالإضافة
+ + + + + +
+
+ +
+ +
+
سياق المدرسة
+
+
مدير المركز
+
الطاقة الاستيعابية طالب
+
قيد الطلاب الحالي طالب/طالبة
+
البريد الرسمي
+
+ +
+
+
+ +
+
+