Update Saqel Platform: 2026-09-08 13:43:36

This commit is contained in:
Hamza-Ayed
2026-09-08 13:43:36 +03:00
parent 0f424062fe
commit bb37b31cab
76 changed files with 3617 additions and 3059 deletions
@@ -28,17 +28,17 @@ class DirectorateOverview {
factory DirectorateOverview.fromJson(Map<String, dynamic> json) {
return DirectorateOverview(
code: json['code'] ?? 'MC-JOR',
name: json['name'] ?? 'مديرية التربية والتعليم والثقافة العسكرية',
commanderName: json['commander_name'] ?? 'مدير التعليم والثقافة العسكرية',
totalSchools: json['total_schools'] ?? 43,
totalStudents: json['total_students'] ?? 19350,
totalTeachers: json['total_teachers'] ?? 812,
annualContractValue: (json['annual_contract_value'] as num?)?.toDouble() ?? 20000.0,
recordedLessonsMonth: json['recorded_lessons_month'] ?? 1420,
complianceRate: (json['compliance_rate'] as num?)?.toDouble() ?? 94.5,
aiAverageScore: (json['ai_average_score'] as num?)?.toDouble() ?? 91.8,
activeUnifiedExams: json['active_unified_exams'] ?? 2,
code: json['code']?.toString() ?? '',
name: json['name']?.toString() ?? '',
commanderName: json['commander_name']?.toString() ?? '',
totalSchools: (json['total_schools'] as num?)?.toInt() ?? 0,
totalStudents: (json['total_students'] as num?)?.toInt() ?? 0,
totalTeachers: (json['total_teachers'] as num?)?.toInt() ?? 0,
annualContractValue: (json['annual_contract_value'] as num?)?.toDouble() ?? 0,
recordedLessonsMonth: (json['recorded_lessons_month'] as num?)?.toInt() ?? 0,
complianceRate: (json['compliance_rate'] as num?)?.toDouble() ?? 0,
aiAverageScore: (json['ai_average_score'] as num?)?.toDouble() ?? 0,
activeUnifiedExams: (json['active_unified_exams'] as num?)?.toInt() ?? 0,
);
}
}
@@ -86,17 +86,79 @@ class SchoolItem {
id: json['id'] ?? 0,
code: json['code'] ?? '',
name: json['name'] ?? '',
governorate: json['governorate'] ?? 'العاصمة',
weightTier: json['weight_tier'] ?? 'tier_b_medium',
studentCount: json['student_count'] ?? 450,
teacherCount: json['teacher_count'] ?? 24,
compliance: (json['compliance'] as num?)?.toDouble() ?? 90.0,
status: json['status'] ?? 'good',
annualFee: (json['annual_fee'] as num?)?.toDouble() ?? 450.0,
governorate: json['governorate']?.toString() ?? '',
weightTier: json['weight_tier']?.toString() ?? '',
studentCount: (json['student_count'] as num?)?.toInt() ?? 0,
teacherCount: (json['teacher_count'] as num?)?.toInt() ?? 0,
compliance: (json['compliance'] as num?)?.toDouble() ?? 0,
status: json['status']?.toString() ?? 'unknown',
annualFee: (json['annual_fee'] as num?)?.toDouble() ?? 0,
);
}
}
/// Detailed school data used by the principal and supervisor dashboards.
class SchoolDetail {
final int id;
final String name;
final String governorate;
final int studentCount;
final int teacherCount;
final String weightTier;
final String directorName;
final String biweeklyCycle;
final String cycleProgress;
const SchoolDetail({
required this.id,
required this.name,
required this.governorate,
required this.studentCount,
required this.teacherCount,
required this.weightTier,
required this.directorName,
required this.biweeklyCycle,
required this.cycleProgress,
});
factory SchoolDetail.fromJson(Map<String, dynamic> json) => SchoolDetail(
id: (json['id'] as num?)?.toInt() ?? 0,
name: json['name']?.toString() ?? '',
governorate: json['governorate']?.toString() ?? '',
studentCount: (json['student_count'] as num?)?.toInt() ?? 0,
teacherCount: (json['teacher_count'] as num?)?.toInt() ?? 0,
weightTier: json['weight_tier']?.toString() ?? '',
directorName: json['director_name']?.toString() ?? '',
biweeklyCycle: json['biweekly_cycle']?.toString() ?? '',
cycleProgress: json['cycle_progress']?.toString() ?? '',
);
}
/// A real computer-lab resource returned by the school dashboard API.
class ComputerLabItem {
final int id;
final String name;
final int deviceCount;
final int onlineDevices;
final String status;
const ComputerLabItem({
required this.id,
required this.name,
required this.deviceCount,
required this.onlineDevices,
required this.status,
});
factory ComputerLabItem.fromJson(Map<String, dynamic> json) => ComputerLabItem(
id: (json['id'] as num?)?.toInt() ?? 0,
name: json['name']?.toString() ?? '',
deviceCount: (json['device_count'] as num?)?.toInt() ?? 0,
onlineDevices: (json['online_devices'] as num?)?.toInt() ?? 0,
status: json['status']?.toString() ?? 'unknown',
);
}
/// Teacher Item Model (المعلم ومؤشر دورية الأسبوعين)
class TeacherItem {
final int id;
@@ -129,8 +191,8 @@ class TeacherItem {
grade: json['grade'] ?? '',
quotaStatus: json['quota_status'] ?? 'pending',
lastLesson: json['last_lesson'] ?? '',
aiScore: (json['ai_score'] as num?)?.toDouble() ?? 90.0,
recordedAt: json['recorded_at'] ?? 'مؤخراً',
aiScore: (json['ai_score'] as num?)?.toDouble() ?? 0,
recordedAt: json['recorded_at']?.toString() ?? '',
);
}
}
@@ -181,12 +243,12 @@ class RecordedLessonResult {
teacherName: json['teacher_name'] ?? '',
subject: json['subject'] ?? '',
lessonTitle: json['lesson_title'] ?? '',
fileSizeMb: (json['file_size_mb'] as num?)?.toDouble() ?? 350.0,
durationMinutes: json['duration_minutes'] ?? 45,
aiAlignmentScore: (json['ai_alignment_score'] as num?)?.toDouble() ?? 92.0,
teacherTalkRatio: json['teacher_talk_ratio'] ?? '60%',
status: json['status'] ?? 'approved_official',
reportSummary: json['report_summary'] ?? 'تم الاعتماد بنجاح',
fileSizeMb: (json['file_size_mb'] as num?)?.toDouble() ?? 0,
durationMinutes: (json['duration_minutes'] as num?)?.toInt() ?? 0,
aiAlignmentScore: (json['ai_alignment_score'] as num?)?.toDouble() ?? 0,
teacherTalkRatio: json['teacher_talk_ratio']?.toString() ?? '',
status: json['status']?.toString() ?? 'unknown',
reportSummary: json['report_summary']?.toString() ?? '',
socraticCheckpoints: checkpoints,
);
}
@@ -21,20 +21,28 @@ class DirectorateRepository {
/// Record field lesson observation
Future<Map<String, dynamic>> recordLesson({
required int schoolId,
required String teacherName,
required int teacherId,
required String subject,
required String gradeLevel,
required String topic,
required double score,
required String notes,
required String filePath,
required String fileName,
}) async {
return await DirectorateApiService.recordFieldObservation(
final result = await DirectorateApiService.recordLesson(
schoolId: schoolId,
teacherName: teacherName,
teacherId: teacherId,
subject: subject,
topic: topic,
score: score,
notes: notes,
gradeLevel: gradeLevel,
lessonTitle: topic,
durationMinutes: 0,
filePath: filePath,
fileName: fileName,
);
return {
'status': 'success',
'school_id': schoolId,
'data': result,
};
}
/// Push unified exam to computer lab
@@ -44,12 +52,15 @@ class DirectorateRepository {
required String labName,
required int deviceCount,
}) async {
return await DirectorateApiService.pushExamToLab(
schoolId: schoolId,
examTitle: examTitle,
labName: labName,
deviceCount: deviceCount,
);
final examId = int.tryParse(examTitle);
if (examId == null) throw StateError('معرف الامتحان يجب أن يكون رقمياً.');
final pushed = await DirectorateApiService.pushExamToLab(examId: examId, schoolId: schoolId);
return {
'status': pushed ? 'success' : 'error',
'school_id': schoolId,
'lab_name': labName,
'device_count': deviceCount,
};
}
/// Evaluate session integrity
@@ -57,10 +68,12 @@ class DirectorateRepository {
required int sessionId,
required String schoolCode,
}) async {
return await DirectorateApiService.evaluateSessionIntegrity(
sessionId: sessionId,
schoolCode: schoolCode,
);
final result = await DirectorateApiService.evaluateExamSessionIntegrity();
return {
...result,
'session_id': sessionId,
'school_code': schoolCode,
};
}
/// Dispatch reports to parents via WhatsApp
@@ -68,9 +81,7 @@ class DirectorateRepository {
required int schoolId,
required String grade,
}) async {
return await DirectorateApiService.dispatchParentReports(
schoolId: schoolId,
grade: grade,
);
final result = await DirectorateApiService.dispatchParentReports(schoolId: schoolId);
return {...result, 'grade': grade};
}
}