148 lines
4.5 KiB
Dart
148 lines
4.5 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'school_identity.dart';
|
|
import 'school_term.dart';
|
|
|
|
class ExamRecord {
|
|
const ExamRecord({
|
|
required this.code,
|
|
required this.name,
|
|
this.assessment = '',
|
|
this.candidate = '',
|
|
this.sequence = '',
|
|
this.room = '',
|
|
this.seat = '',
|
|
this.time = '',
|
|
this.date = '',
|
|
this.status = '',
|
|
this.notes = '',
|
|
this.examTypeId,
|
|
});
|
|
final String code, name, assessment, candidate, sequence, room, seat, time;
|
|
final String date, status, notes;
|
|
final int? examTypeId;
|
|
String get undergraduateKey =>
|
|
jsonEncode([examTypeId, code, date, time, room, seat]);
|
|
Map<String, dynamic> toJson() => {
|
|
'code': code,
|
|
'name': name,
|
|
'assessment': assessment,
|
|
'candidate': candidate,
|
|
'sequence': sequence,
|
|
'room': room,
|
|
'seat': seat,
|
|
'time': time,
|
|
'date': date,
|
|
'status': status,
|
|
'notes': notes,
|
|
'examTypeId': examTypeId,
|
|
};
|
|
factory ExamRecord.fromJson(Map<String, dynamic> json) {
|
|
String field(String key, {bool optional = false}) {
|
|
final value = optional && !json.containsKey(key) ? '' : json[key];
|
|
if (value is! String || value.length > 1000) {
|
|
throw const FormatException('考试信息无效');
|
|
}
|
|
return value;
|
|
}
|
|
|
|
final typeId = json['examTypeId'];
|
|
if (typeId != null && (typeId is! int || typeId < 1 || typeId > 3)) {
|
|
throw const FormatException('考试类型无效');
|
|
}
|
|
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'),
|
|
date: field('date', optional: true),
|
|
status: field('status', optional: true),
|
|
notes: field('notes', optional: true),
|
|
examTypeId: typeId as int?,
|
|
);
|
|
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,
|
|
this.school = SupportedSchool.uestcGraduate,
|
|
Set<int> requestedExamTypes = const {},
|
|
}) : records = List.unmodifiable(records),
|
|
requestedExamTypes = Set.unmodifiable(requestedExamTypes);
|
|
final String semesterLabel, termId;
|
|
final List<ExamRecord> records;
|
|
final SupportedSchool school;
|
|
final Set<int> requestedExamTypes;
|
|
Map<String, dynamic> toJson() => {
|
|
'semesterLabel': semesterLabel,
|
|
'termId': termId,
|
|
'records': records.map((r) => r.toJson()).toList(),
|
|
'schoolId': school.id,
|
|
'requestedExamTypes': requestedExamTypes.toList()..sort(),
|
|
};
|
|
factory ExamSchedule.fromJson(Map<String, dynamic> json) {
|
|
try {
|
|
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();
|
|
final school = json['schoolId'] == null
|
|
? SupportedSchool.uestcGraduate
|
|
: SupportedSchool.fromId(json['schoolId'] as String);
|
|
final rawTypes = json['requestedExamTypes'] ?? <int>[];
|
|
if (rawTypes is! List ||
|
|
rawTypes.any((t) => t is! int || t < 1 || t > 3)) {
|
|
throw const FormatException('考试类型无效');
|
|
}
|
|
final types = rawTypes.cast<int>().toSet();
|
|
SchoolTerm(int.parse(id), school: school);
|
|
if (school == SupportedSchool.uestcUndergraduate &&
|
|
(types.isEmpty ||
|
|
records.any((r) => !types.contains(r.examTypeId)))) {
|
|
throw const FormatException('本科考试类型无效');
|
|
}
|
|
if (records
|
|
.map(
|
|
(r) => school == SupportedSchool.uestcGraduate
|
|
? r.code
|
|
: r.undergraduateKey,
|
|
)
|
|
.toSet()
|
|
.length !=
|
|
records.length) {
|
|
throw const FormatException('考试课程重复');
|
|
}
|
|
return ExamSchedule(
|
|
semesterLabel: label,
|
|
termId: id,
|
|
records: records,
|
|
school: school,
|
|
requestedExamTypes: types,
|
|
);
|
|
} catch (_) {
|
|
throw const FormatException('考试列表无效');
|
|
}
|
|
}
|
|
}
|