271 lines
8.5 KiB
Dart
271 lines
8.5 KiB
Dart
import 'dart:convert';
|
|
|
|
/// Directorate Model (المظلة المركزية: مديرية الثقافة العسكرية)
|
|
class DirectorateOverview {
|
|
final String code;
|
|
final String name;
|
|
final String commanderName;
|
|
final int totalSchools;
|
|
final int totalStudents;
|
|
final int totalTeachers;
|
|
final double annualContractValue;
|
|
final int recordedLessonsMonth;
|
|
final double complianceRate;
|
|
final double aiAverageScore;
|
|
final int activeUnifiedExams;
|
|
|
|
DirectorateOverview({
|
|
required this.code,
|
|
required this.name,
|
|
required this.commanderName,
|
|
required this.totalSchools,
|
|
required this.totalStudents,
|
|
required this.totalTeachers,
|
|
required this.annualContractValue,
|
|
required this.recordedLessonsMonth,
|
|
required this.complianceRate,
|
|
required this.aiAverageScore,
|
|
required this.activeUnifiedExams,
|
|
});
|
|
|
|
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,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// School Item Model (المدرسة التابعة وتصنيف الوزن)
|
|
class SchoolItem {
|
|
final int id;
|
|
final String code;
|
|
final String name;
|
|
final String governorate;
|
|
final String weightTier; // tier_a_small, tier_b_medium, tier_c_large
|
|
final int studentCount;
|
|
final int teacherCount;
|
|
final double compliance;
|
|
final String status; // excellent, good, warning_under_quota
|
|
final double annualFee;
|
|
|
|
SchoolItem({
|
|
required this.id,
|
|
required this.code,
|
|
required this.name,
|
|
required this.governorate,
|
|
required this.weightTier,
|
|
required this.studentCount,
|
|
required this.teacherCount,
|
|
required this.compliance,
|
|
required this.status,
|
|
required this.annualFee,
|
|
});
|
|
|
|
String get weightTierArabic {
|
|
switch (weightTier) {
|
|
case 'tier_a_small':
|
|
return 'الفئة (أ) - صغيرة/نائية';
|
|
case 'tier_c_large':
|
|
return 'الفئة (ج) - كبرى/مركزية';
|
|
case 'tier_b_medium':
|
|
default:
|
|
return 'الفئة (ب) - قياسية';
|
|
}
|
|
}
|
|
|
|
factory SchoolItem.fromJson(Map<String, dynamic> json) {
|
|
return 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,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Teacher Item Model (المعلم ومؤشر دورية الأسبوعين)
|
|
class TeacherItem {
|
|
final int id;
|
|
final String name;
|
|
final String subject;
|
|
final String grade;
|
|
final String quotaStatus; // completed, pending, overdue
|
|
final String lastLesson;
|
|
final double aiScore;
|
|
final String recordedAt;
|
|
|
|
TeacherItem({
|
|
required this.id,
|
|
required this.name,
|
|
required this.subject,
|
|
required this.grade,
|
|
required this.quotaStatus,
|
|
required this.lastLesson,
|
|
required this.aiScore,
|
|
required this.recordedAt,
|
|
});
|
|
|
|
bool get isCompleted => quotaStatus == 'completed';
|
|
|
|
factory TeacherItem.fromJson(Map<String, dynamic> json) {
|
|
return TeacherItem(
|
|
id: json['id'] ?? 0,
|
|
name: json['name'] ?? '',
|
|
subject: json['subject'] ?? '',
|
|
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'] ?? 'مؤخراً',
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Recorded Classroom Lesson Result (نتيجة فحص الحصة المرئية)
|
|
class RecordedLessonResult {
|
|
final String lessonUuid;
|
|
final String teacherName;
|
|
final String subject;
|
|
final String lessonTitle;
|
|
final double fileSizeMb;
|
|
final int durationMinutes;
|
|
final double aiAlignmentScore;
|
|
final String teacherTalkRatio;
|
|
final String status;
|
|
final String reportSummary;
|
|
final List<Map<String, String>> socraticCheckpoints;
|
|
|
|
RecordedLessonResult({
|
|
required this.lessonUuid,
|
|
required this.teacherName,
|
|
required this.subject,
|
|
required this.lessonTitle,
|
|
required this.fileSizeMb,
|
|
required this.durationMinutes,
|
|
required this.aiAlignmentScore,
|
|
required this.teacherTalkRatio,
|
|
required this.status,
|
|
required this.reportSummary,
|
|
required this.socraticCheckpoints,
|
|
});
|
|
|
|
factory RecordedLessonResult.fromJson(Map<String, dynamic> json) {
|
|
var rawCheckpoints = json['socratic_checkpoints'] as List<dynamic>? ?? [];
|
|
List<Map<String, String>> checkpoints = rawCheckpoints.map((c) {
|
|
if (c is Map) {
|
|
return {
|
|
'timestamp': c['timestamp']?.toString() ?? '',
|
|
'question': c['question']?.toString() ?? '',
|
|
'objective': c['objective']?.toString() ?? '',
|
|
};
|
|
}
|
|
return <String, String>{};
|
|
}).toList();
|
|
|
|
return RecordedLessonResult(
|
|
lessonUuid: json['lesson_uuid'] ?? '',
|
|
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'] ?? 'تم الاعتماد بنجاح',
|
|
socraticCheckpoints: checkpoints,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Unified Exam Model (الامتحان الموحد)
|
|
class UnifiedExamModel {
|
|
final String id;
|
|
final String title;
|
|
final String subject;
|
|
final String gradeLevel;
|
|
final String scheduledTime;
|
|
final int durationMinutes;
|
|
final bool pushedToLab;
|
|
final String status;
|
|
final List<String> forms;
|
|
final Map<String, dynamic> antiCheating;
|
|
|
|
UnifiedExamModel({
|
|
required this.id,
|
|
required this.title,
|
|
required this.subject,
|
|
required this.gradeLevel,
|
|
required this.scheduledTime,
|
|
required this.durationMinutes,
|
|
required this.pushedToLab,
|
|
required this.status,
|
|
required this.forms,
|
|
required this.antiCheating,
|
|
});
|
|
|
|
factory UnifiedExamModel.fromJson(Map<String, dynamic> json) {
|
|
return UnifiedExamModel(
|
|
id: json['id'] ?? '',
|
|
title: json['title'] ?? '',
|
|
subject: json['subject'] ?? '',
|
|
gradeLevel: json['grade_level'] ?? '',
|
|
scheduledTime: json['scheduled_time'] ?? '',
|
|
durationMinutes: json['duration_minutes'] ?? 60,
|
|
pushedToLab: json['pushed_to_lab'] == true,
|
|
status: json['status'] ?? 'scheduled',
|
|
forms: (json['forms'] as List<dynamic>?)?.map((e) => e.toString()).toList() ?? ['نموذج أ', 'نموذج ب'],
|
|
antiCheating: json['anti_cheating'] as Map<String, dynamic>? ?? {},
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Exam Anomaly Alert Model (تنبيهات الشذوذ الإحصائي والغش)
|
|
class ExamAnomalyAlert {
|
|
final String id;
|
|
final String type; // speed_impossible, error_clustering, performance_leap
|
|
final String schoolName;
|
|
final String subject;
|
|
final String description;
|
|
final String severity;
|
|
final String timestamp;
|
|
|
|
ExamAnomalyAlert({
|
|
required this.id,
|
|
required this.type,
|
|
required this.schoolName,
|
|
required this.subject,
|
|
required this.description,
|
|
required this.severity,
|
|
required this.timestamp,
|
|
});
|
|
|
|
factory ExamAnomalyAlert.fromJson(Map<String, dynamic> json) {
|
|
return ExamAnomalyAlert(
|
|
id: json['id'] ?? '',
|
|
type: json['type'] ?? 'speed_impossible',
|
|
schoolName: json['school_name'] ?? '',
|
|
subject: json['subject'] ?? '',
|
|
description: json['description'] ?? '',
|
|
severity: json['severity'] ?? 'medium',
|
|
timestamp: json['timestamp'] ?? '',
|
|
);
|
|
}
|
|
}
|