feat: deliver RSchedule service login exams and elastic glass navigation
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:html/parser.dart' as html;
|
||||
|
||||
import '../../domain/exam_schedule.dart';
|
||||
|
||||
class SchoolExamAdapter {
|
||||
static ExamSchedule extract(String content) {
|
||||
try {
|
||||
if (utf8.encode(content).length > 2 * 1024 * 1024) {
|
||||
throw const FormatException();
|
||||
}
|
||||
final document = html.parse(content);
|
||||
final selected = document.querySelector('#xqbh option[selected]');
|
||||
final term = selected?.attributes['value'];
|
||||
final table = document.querySelector('#sample-table-1');
|
||||
const headers = [
|
||||
'id',
|
||||
'序号',
|
||||
'学号',
|
||||
'姓名',
|
||||
'课程代码',
|
||||
'课程名称',
|
||||
'考核方式',
|
||||
'考生编号',
|
||||
'考场顺序号',
|
||||
'考场',
|
||||
'座位号',
|
||||
'考试时间',
|
||||
];
|
||||
if (selected == null ||
|
||||
term == null ||
|
||||
table == null ||
|
||||
!RegExp(r'^\d+$').hasMatch(term)) {
|
||||
throw const FormatException();
|
||||
}
|
||||
final rows = table.querySelectorAll('tr');
|
||||
if (rows.isEmpty || rows.first.children.length != headers.length) {
|
||||
throw const FormatException();
|
||||
}
|
||||
for (var i = 0; i < headers.length; i++) {
|
||||
if (rows.first.children[i].text.trim() != headers[i]) {
|
||||
throw const FormatException();
|
||||
}
|
||||
}
|
||||
final records = <ExamRecord>[];
|
||||
var explicitlyEmpty = false;
|
||||
for (final row in rows.skip(1)) {
|
||||
// DataTables can insert a single explicit no-data placeholder.
|
||||
if (row.children.length == 1 &&
|
||||
row.children.first.attributes['colspan'] == '12' &&
|
||||
const [
|
||||
'没有数据',
|
||||
'暂无数据',
|
||||
'无数据',
|
||||
'No data available in table',
|
||||
].contains(row.text.trim())) {
|
||||
explicitlyEmpty = true;
|
||||
continue;
|
||||
}
|
||||
if (row.children.length != 12 ||
|
||||
row.querySelector('script,style') != null) {
|
||||
throw const FormatException();
|
||||
}
|
||||
final cells = row.children.map((c) => c.text.trim()).toList();
|
||||
records.add(
|
||||
ExamRecord(
|
||||
code: cells[4],
|
||||
name: cells[5],
|
||||
assessment: cells[6],
|
||||
candidate: cells[7],
|
||||
sequence: cells[8],
|
||||
room: cells[9],
|
||||
seat: cells[10],
|
||||
time: cells[11],
|
||||
),
|
||||
);
|
||||
}
|
||||
if (records.isEmpty && !explicitlyEmpty) throw const FormatException();
|
||||
return ExamSchedule.fromJson(
|
||||
ExamSchedule(
|
||||
semesterLabel: selected.text.trim(),
|
||||
termId: term,
|
||||
records: records,
|
||||
).toJson(),
|
||||
);
|
||||
} catch (_) {
|
||||
throw const FormatException('未识别到完整的考试查询表,已有考试信息保持不变。');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user