feat: model undergraduate schools terms and exam queries

This commit is contained in:
Codex
2026-10-14 23:14:48 +08:00
parent 3f28e0a1b6
commit 48367b8273
8 changed files with 176 additions and 27 deletions
+14 -2
View File
@@ -3,6 +3,7 @@ import 'course.dart';
import 'semester.dart';
import 'exam_schedule.dart';
import 'school_term.dart';
import 'school_identity.dart';
class ImportMetadata {
const ImportMetadata({
@@ -23,9 +24,12 @@ class AppSnapshot {
this.examSchedule,
SchoolTerm? schoolTerm,
this.calendarCleanupPending = false,
SupportedSchool? selectedSchool,
Map<String, String> calendarEventIds = const {},
}) : settings = settings ?? AppSettings(),
schoolTerm = schoolTerm ?? _legacyTerm(courses, examSchedule),
selectedSchool = selectedSchool ?? schoolTerm?.school ??
_legacyTerm(courses, examSchedule)?.school ?? examSchedule?.school,
courses = List.unmodifiable(courses),
calendarEventIds = Map.unmodifiable(calendarEventIds);
final AppSettings settings;
@@ -35,6 +39,7 @@ class AppSnapshot {
final SchoolTerm? schoolTerm;
final Map<String, String> calendarEventIds;
final bool calendarCleanupPending;
final SupportedSchool? selectedSchool;
static SchoolTerm? _legacyTerm(List<Course> courses, ExamSchedule? exams) {
final ids = courses
.map(
@@ -42,7 +47,7 @@ class AppSnapshot {
)
.whereType<String>()
.toSet();
if (exams != null) ids.add(exams.termId);
if (exams?.school == SupportedSchool.uestcGraduate) ids.add(exams!.termId);
if (ids.length != 1) return null;
final id = int.tryParse(ids.single);
return id != null && id >= 1 && id <= 9999 ? SchoolTerm(id) : null;
@@ -58,6 +63,7 @@ class AppSnapshot {
bool clearExams = false,
SchoolTerm? schoolTerm,
bool? calendarCleanupPending,
SupportedSchool? selectedSchool,
}) => AppSnapshot(
settings: settings ?? this.settings,
courses: courses ?? this.courses,
@@ -69,11 +75,13 @@ class AppSnapshot {
calendarEventIds: calendarEventIds ?? this.calendarEventIds,
calendarCleanupPending:
calendarCleanupPending ?? this.calendarCleanupPending,
selectedSchool:selectedSchool ?? this.selectedSchool,
);
Map<String, dynamic> toJson() => {
'schemaVersion': 1,
'examSchedule': examSchedule?.toJson(),
'schoolTerm': schoolTerm?.toJson(),
'selectedSchoolId':selectedSchool?.id,
'courses': courses.map((c) => c.toJson()).toList(),
'settings': {
'semester': settings.semester == null
@@ -144,7 +152,8 @@ class AppSnapshot {
totalWeeks: sem['totalWeeks'] as int,
);
final metadata = json['importMetadata'];
return AppSnapshot(
final snapshot = AppSnapshot(
selectedSchool:json['selectedSchoolId']==null ? null : SupportedSchool.fromId(json['selectedSchoolId'] as String),
schoolTerm: json['schoolTerm'] == null
? null
: SchoolTerm.fromJson(
@@ -181,6 +190,9 @@ class AppSnapshot {
(k, v) => MapEntry(k as String, v as String),
),
);
if(snapshot.schoolTerm?.school != SupportedSchool.uestcUndergraduate &&
values.any((c)=>c.endPeriod>11)) throw const FormatException('第12节需要本科课表来源');
return snapshot;
} catch (_) {
throw const FormatException('保存文件内容无效,未覆盖已有数据');
}