feat: integrate undergraduate school workflows and period twelve
This commit is contained in:
@@ -6,12 +6,20 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import '../../app/app_controller.dart';
|
||||
import '../../app/app_theme.dart';
|
||||
import '../school/school_exam_adapter.dart';
|
||||
import '../../data/exam_file_import.dart';
|
||||
import '../../domain/school_identity.dart';
|
||||
import '../../domain/undergraduate_exam_query.dart';
|
||||
|
||||
class ExamsPage extends StatelessWidget {
|
||||
const ExamsPage({super.key, required this.controller, required this.onSync});
|
||||
const ExamsPage({
|
||||
super.key,
|
||||
required this.controller,
|
||||
required this.onSync,
|
||||
this.onQueryOptions,
|
||||
});
|
||||
final AppController controller;
|
||||
final VoidCallback onSync;
|
||||
final VoidCallback? onQueryOptions;
|
||||
Future<void> _import(BuildContext context) async {
|
||||
try {
|
||||
final file = await FilePicker.pickFile(
|
||||
@@ -28,7 +36,7 @@ class ExamsPage extends StatelessWidget {
|
||||
}
|
||||
bytes.add(chunk);
|
||||
}
|
||||
final draft = SchoolExamAdapter.extract(utf8.decode(bytes.takeBytes()));
|
||||
final draft = ExamFileImport.parse(utf8.decode(bytes.takeBytes()));
|
||||
if (!context.mounted) return;
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
@@ -95,6 +103,12 @@ class ExamsPage extends StatelessWidget {
|
||||
onPressed: onSync,
|
||||
icon: const Icon(Icons.sync_rounded),
|
||||
),
|
||||
if (onQueryOptions != null)
|
||||
IconButton(
|
||||
tooltip: '查询选项',
|
||||
onPressed: onQueryOptions,
|
||||
icon: const Icon(Icons.tune_rounded),
|
||||
),
|
||||
IconButton(
|
||||
tooltip: '导入考试 HTML',
|
||||
onPressed: () => _import(context),
|
||||
@@ -132,11 +146,21 @@ class ExamsPage extends StatelessWidget {
|
||||
),
|
||||
] else ...[
|
||||
Text(
|
||||
'${schedule.semesterLabel} · ${schedule.records.length} 门课程',
|
||||
'${schedule.school.label} · ${schedule.semesterLabel} · ${schedule.records.length} 条考试',
|
||||
style: TextStyle(fontSize: 13, color: ink.withValues(alpha: 0.55)),
|
||||
),
|
||||
const SizedBox(height: 18),
|
||||
if (schedule.records.isEmpty) const Text('该学期暂无考试课程'),
|
||||
if (schedule.school == SupportedSchool.uestcUndergraduate)
|
||||
Text(
|
||||
'查询类型:${UndergraduateExamQuery.fromSchedule(schedule)!.orderedTypes.map((t) => t.label).join('、')}',
|
||||
style: const TextStyle(fontSize: 12),
|
||||
),
|
||||
if (schedule.records.isEmpty)
|
||||
Text(
|
||||
schedule.school == SupportedSchool.uestcUndergraduate
|
||||
? '所选考试类型暂未安排'
|
||||
: '该学期暂无考试课程',
|
||||
),
|
||||
for (final exam in schedule.records)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 14),
|
||||
@@ -152,9 +176,25 @@ class ExamsPage extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
if (exam.date.isNotEmpty)
|
||||
_field(Icons.calendar_today_rounded, '考试日期', exam.date),
|
||||
_field(Icons.schedule_rounded, '考试时间', exam.time),
|
||||
_field(Icons.location_on_outlined, '考场', exam.room),
|
||||
_field(Icons.event_seat_outlined, '座位号', exam.seat),
|
||||
if (exam.examTypeId != null)
|
||||
_field(
|
||||
Icons.category_outlined,
|
||||
'考试类型',
|
||||
UndergraduateExamType.fromId(exam.examTypeId!).label,
|
||||
),
|
||||
if (exam.status.isNotEmpty)
|
||||
_field(
|
||||
Icons.assignment_turned_in_outlined,
|
||||
'考试情况',
|
||||
exam.status,
|
||||
),
|
||||
if (exam.notes.isNotEmpty)
|
||||
_field(Icons.info_outline_rounded, '说明', exam.notes),
|
||||
if (exam.assessment.isNotEmpty)
|
||||
_field(
|
||||
Icons.assignment_outlined,
|
||||
|
||||
@@ -506,6 +506,25 @@ class SchoolSession extends ChangeNotifier {
|
||||
return future.whenComplete(() => _logoutFuture = null);
|
||||
}
|
||||
|
||||
void invalidateAuthentication() {
|
||||
_openSerial++;
|
||||
_pageGeneration++;
|
||||
_reader.invalidate();
|
||||
_flow.reset();
|
||||
_poll?.cancel();
|
||||
_timeout?.cancel();
|
||||
_readingActive = false;
|
||||
_routeClosed = true;
|
||||
hasOpened = false;
|
||||
pendingDraft = null;
|
||||
pendingExams = null;
|
||||
finding = false;
|
||||
_loading = false;
|
||||
connectionState = SchoolConnectionState.signedOut;
|
||||
message = '学校登录已退出';
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> _performLogout() async {
|
||||
_openSerial++;
|
||||
_pageGeneration++;
|
||||
|
||||
@@ -368,6 +368,8 @@ class UndergraduateSession extends ChangeNotifier {
|
||||
|
||||
void invalidateAuthentication() {
|
||||
_reset();
|
||||
_active = false;
|
||||
hasOpened = false;
|
||||
_connected = false;
|
||||
awaitingAuthentication = false;
|
||||
message = '学校登录已退出';
|
||||
|
||||
@@ -24,6 +24,10 @@ void showCourseDetails(BuildContext context, CourseOccurrence event) {
|
||||
const SizedBox(height: 20),
|
||||
_line(Icons.person_outline_rounded, event.course.teacher),
|
||||
_line(Icons.location_on_outlined, event.course.room),
|
||||
if (event.course.courseCode.isNotEmpty)
|
||||
_line(Icons.tag_rounded, '课程代码:${event.course.courseCode}'),
|
||||
if (event.course.notes.isNotEmpty)
|
||||
_line(Icons.info_outline_rounded, event.course.notes),
|
||||
_line(
|
||||
Icons.schedule_rounded,
|
||||
'${minuteLabel(event.start.hour * 60 + event.start.minute)}–${minuteLabel(event.end.hour * 60 + event.end.minute)} · 第 ${event.course.startPeriod}–${event.course.endPeriod} 节',
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||
import '../../app/app_controller.dart';
|
||||
import '../../app/app_theme.dart';
|
||||
import '../../domain/schedule_engine.dart';
|
||||
import '../../domain/school_identity.dart';
|
||||
import '../../widgets/directional_week_transition.dart';
|
||||
import '../profile/settings_page.dart';
|
||||
import 'week_grid.dart';
|
||||
@@ -84,13 +85,24 @@ class _TimetablePageState extends State<TimetablePage> {
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(14, 0, 14, 8),
|
||||
child: Text(
|
||||
c.snapshot.schoolTerm!.label,
|
||||
'${c.snapshot.schoolTerm!.school.label} · ${c.snapshot.schoolTerm!.label}',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: ink.withValues(alpha: 0.5),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!c.isDemo &&
|
||||
c.snapshot.schoolTerm != null &&
|
||||
c.snapshot.selectedSchool != null &&
|
||||
c.snapshot.selectedSchool != c.snapshot.schoolTerm!.school)
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(14, 0, 14, 8),
|
||||
child: Text(
|
||||
'当前仍为${c.snapshot.schoolTerm!.school.label}课表;新课表导入成功后才会替换。',
|
||||
style: const TextStyle(fontSize: 12, color: river),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
SurfaceCard(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 0),
|
||||
@@ -182,6 +194,12 @@ class _TimetablePageState extends State<TimetablePage> {
|
||||
monday: monday,
|
||||
today: today,
|
||||
settings: c.visibleSettings,
|
||||
periodCount:
|
||||
!c.isDemo &&
|
||||
c.snapshot.schoolTerm?.school ==
|
||||
SupportedSchool.uestcUndergraduate
|
||||
? 12
|
||||
: 11,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
@@ -14,7 +14,9 @@ class WeekGrid extends StatelessWidget {
|
||||
required this.monday,
|
||||
required this.today,
|
||||
required this.settings,
|
||||
});
|
||||
this.periodCount = 11,
|
||||
}) : assert(periodCount == 11 || periodCount == 12);
|
||||
final int periodCount;
|
||||
final List<CourseOccurrence> events;
|
||||
final DateTime monday, today;
|
||||
final AppSettings settings;
|
||||
@@ -111,7 +113,7 @@ class WeekGrid extends StatelessWidget {
|
||||
(period - 1) * rowHeight +
|
||||
(period > 4 ? gap : 0) +
|
||||
(period > 8 ? gap : 0);
|
||||
final height = 11 * rowHeight + 2 * gap;
|
||||
final height = periodCount * rowHeight + 2 * gap;
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -120,7 +122,7 @@ class WeekGrid extends StatelessWidget {
|
||||
height: header + height,
|
||||
child: Stack(
|
||||
children: [
|
||||
for (final slot in lessonSlots)
|
||||
for (final slot in lessonSlots.take(periodCount))
|
||||
Positioned(
|
||||
top: header + top(slot.period),
|
||||
left: 0,
|
||||
@@ -244,7 +246,7 @@ class WeekGrid extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
for (var p = 1; p <= 11; p++)
|
||||
for (var p = 1; p <= periodCount; p++)
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
|
||||
Reference in New Issue
Block a user