feat: deliver RSchedule service login exams and elastic glass navigation
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import 'app_settings.dart';
|
||||
import 'course.dart';
|
||||
import 'semester.dart';
|
||||
import 'exam_schedule.dart';
|
||||
|
||||
class ImportMetadata {
|
||||
const ImportMetadata({
|
||||
@@ -18,6 +19,7 @@ class AppSnapshot {
|
||||
this.settings = const AppSettings(),
|
||||
List<Course> courses = const [],
|
||||
this.importMetadata,
|
||||
this.examSchedule,
|
||||
this.calendarCleanupPending = false,
|
||||
Map<String, String> calendarEventIds = const {},
|
||||
}) : courses = List.unmodifiable(courses),
|
||||
@@ -25,6 +27,7 @@ class AppSnapshot {
|
||||
final AppSettings settings;
|
||||
final List<Course> courses;
|
||||
final ImportMetadata? importMetadata;
|
||||
final ExamSchedule? examSchedule;
|
||||
final Map<String, String> calendarEventIds;
|
||||
final bool calendarCleanupPending;
|
||||
AppSnapshot copyWith({
|
||||
@@ -33,6 +36,8 @@ class AppSnapshot {
|
||||
ImportMetadata? importMetadata,
|
||||
Map<String, String>? calendarEventIds,
|
||||
bool clearMetadata = false,
|
||||
ExamSchedule? examSchedule,
|
||||
bool clearExams = false,
|
||||
bool? calendarCleanupPending,
|
||||
}) => AppSnapshot(
|
||||
settings: settings ?? this.settings,
|
||||
@@ -40,12 +45,14 @@ class AppSnapshot {
|
||||
importMetadata: clearMetadata
|
||||
? null
|
||||
: importMetadata ?? this.importMetadata,
|
||||
examSchedule: clearExams ? null : examSchedule ?? this.examSchedule,
|
||||
calendarEventIds: calendarEventIds ?? this.calendarEventIds,
|
||||
calendarCleanupPending:
|
||||
calendarCleanupPending ?? this.calendarCleanupPending,
|
||||
);
|
||||
Map<String, dynamic> toJson() => {
|
||||
'schemaVersion': 1,
|
||||
'examSchedule': examSchedule?.toJson(),
|
||||
'courses': courses.map((c) => c.toJson()).toList(),
|
||||
'settings': {
|
||||
'semester': settings.semester == null
|
||||
@@ -109,6 +116,11 @@ class AppSnapshot {
|
||||
);
|
||||
final metadata = json['importMetadata'];
|
||||
return AppSnapshot(
|
||||
examSchedule: json['examSchedule'] == null
|
||||
? null
|
||||
: ExamSchedule.fromJson(
|
||||
Map<String, dynamic>.from(json['examSchedule'] as Map),
|
||||
),
|
||||
calendarCleanupPending:
|
||||
(json['calendarCleanupPending'] ?? false) as bool,
|
||||
courses: values,
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
class ExamRecord {
|
||||
const ExamRecord({
|
||||
required this.code,
|
||||
required this.name,
|
||||
this.assessment = '',
|
||||
this.candidate = '',
|
||||
this.sequence = '',
|
||||
this.room = '',
|
||||
this.seat = '',
|
||||
this.time = '',
|
||||
});
|
||||
final String code, name, assessment, candidate, sequence, room, seat, time;
|
||||
Map<String, dynamic> toJson() => {
|
||||
'code': code,
|
||||
'name': name,
|
||||
'assessment': assessment,
|
||||
'candidate': candidate,
|
||||
'sequence': sequence,
|
||||
'room': room,
|
||||
'seat': seat,
|
||||
'time': time,
|
||||
};
|
||||
factory ExamRecord.fromJson(Map<String, dynamic> json) {
|
||||
String field(String key) {
|
||||
final value = json[key];
|
||||
if (value is! String || value.length > 1000) {
|
||||
throw const FormatException('考试信息无效');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
final record = ExamRecord(
|
||||
code: field('code'),
|
||||
name: field('name'),
|
||||
assessment: field('assessment'),
|
||||
candidate: field('candidate'),
|
||||
sequence: field('sequence'),
|
||||
room: field('room'),
|
||||
seat: field('seat'),
|
||||
time: field('time'),
|
||||
);
|
||||
if (record.code.isEmpty || record.name.isEmpty) {
|
||||
throw const FormatException('考试课程无效');
|
||||
}
|
||||
return record;
|
||||
}
|
||||
}
|
||||
|
||||
class ExamSchedule {
|
||||
ExamSchedule({
|
||||
required this.semesterLabel,
|
||||
required this.termId,
|
||||
required List<ExamRecord> records,
|
||||
}) : records = List.unmodifiable(records);
|
||||
final String semesterLabel, termId;
|
||||
final List<ExamRecord> records;
|
||||
Map<String, dynamic> toJson() => {
|
||||
'semesterLabel': semesterLabel,
|
||||
'termId': termId,
|
||||
'records': records.map((r) => r.toJson()).toList(),
|
||||
};
|
||||
factory ExamSchedule.fromJson(Map<String, dynamic> json) {
|
||||
final label = json['semesterLabel'],
|
||||
id = json['termId'],
|
||||
rows = json['records'];
|
||||
if (label is! String ||
|
||||
label.trim().isEmpty ||
|
||||
id is! String ||
|
||||
!RegExp(r'^\d+$').hasMatch(id) ||
|
||||
rows is! List ||
|
||||
rows.length > 500) {
|
||||
throw const FormatException('考试列表无效');
|
||||
}
|
||||
final records = rows
|
||||
.map((r) => ExamRecord.fromJson(Map<String, dynamic>.from(r as Map)))
|
||||
.toList();
|
||||
if (records.map((r) => r.code).toSet().length != records.length) {
|
||||
throw const FormatException('考试课程重复');
|
||||
}
|
||||
return ExamSchedule(semesterLabel: label, termId: id, records: records);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user