software copyright
This commit is contained in:
@@ -0,0 +1,521 @@
|
||||
// 自然写互动课堂平板端应用软件 V1.0
|
||||
// bloc/homework_bloc.dart - 作业状态管理(Bloc模式)
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
/// 作业状态枚举
|
||||
enum HomeworkStatus {
|
||||
/// 待完成
|
||||
pending,
|
||||
|
||||
/// 进行中(已开始作答)
|
||||
inProgress,
|
||||
|
||||
/// 已提交
|
||||
submitted,
|
||||
|
||||
/// 已批改
|
||||
graded,
|
||||
|
||||
/// 已过期
|
||||
expired,
|
||||
}
|
||||
|
||||
/// 作业数据模型
|
||||
class HomeworkItem {
|
||||
final String id;
|
||||
final String title;
|
||||
final String subject;
|
||||
final String teacherName;
|
||||
final HomeworkStatus status;
|
||||
final DateTime? assignedAt;
|
||||
final DateTime? deadline;
|
||||
final DateTime? submittedAt;
|
||||
final int? score;
|
||||
final int totalQuestions;
|
||||
final int answeredQuestions;
|
||||
final String? coverImageUrl;
|
||||
|
||||
HomeworkItem({
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.subject,
|
||||
required this.teacherName,
|
||||
this.status = HomeworkStatus.pending,
|
||||
this.assignedAt,
|
||||
this.deadline,
|
||||
this.submittedAt,
|
||||
this.score,
|
||||
this.totalQuestions = 0,
|
||||
this.answeredQuestions = 0,
|
||||
this.coverImageUrl,
|
||||
});
|
||||
|
||||
/// 是否已过截止时间
|
||||
bool get isOverdue =>
|
||||
deadline != null && DateTime.now().isAfter(deadline!);
|
||||
|
||||
/// 作答进度百分比
|
||||
double get progress => totalQuestions > 0
|
||||
? answeredQuestions / totalQuestions
|
||||
: 0.0;
|
||||
|
||||
/// 从JSON解析
|
||||
factory HomeworkItem.fromJson(Map<String, dynamic> json) {
|
||||
return HomeworkItem(
|
||||
id: json['id'] ?? '',
|
||||
title: json['title'] ?? '',
|
||||
subject: json['subject'] ?? '',
|
||||
teacherName: json['teacher_name'] ?? '',
|
||||
status: _parseStatus(json['status']),
|
||||
assignedAt: json['assigned_at'] != null
|
||||
? DateTime.tryParse(json['assigned_at'])
|
||||
: null,
|
||||
deadline: json['deadline'] != null
|
||||
? DateTime.tryParse(json['deadline'])
|
||||
: null,
|
||||
submittedAt: json['submitted_at'] != null
|
||||
? DateTime.tryParse(json['submitted_at'])
|
||||
: null,
|
||||
score: json['score'],
|
||||
totalQuestions: json['total_questions'] ?? 0,
|
||||
answeredQuestions: json['answered_questions'] ?? 0,
|
||||
coverImageUrl: json['cover_image_url'],
|
||||
);
|
||||
}
|
||||
|
||||
/// 解析状态字符串
|
||||
static HomeworkStatus _parseStatus(String? status) {
|
||||
switch (status) {
|
||||
case 'pending':
|
||||
return HomeworkStatus.pending;
|
||||
case 'in_progress':
|
||||
return HomeworkStatus.inProgress;
|
||||
case 'submitted':
|
||||
return HomeworkStatus.submitted;
|
||||
case 'graded':
|
||||
return HomeworkStatus.graded;
|
||||
case 'expired':
|
||||
return HomeworkStatus.expired;
|
||||
default:
|
||||
return HomeworkStatus.pending;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 作业详情中的题目数据
|
||||
class HomeworkQuestion {
|
||||
final String id;
|
||||
final int index;
|
||||
final String type;
|
||||
final String content;
|
||||
final String? imageUrl;
|
||||
final List<String>? options;
|
||||
final String? correctAnswer;
|
||||
final String? studentAnswer;
|
||||
final List<Map<String, dynamic>>? studentStrokes;
|
||||
final int? questionScore;
|
||||
final int? earnedScore;
|
||||
final String? teacherComment;
|
||||
|
||||
HomeworkQuestion({
|
||||
required this.id,
|
||||
required this.index,
|
||||
required this.type,
|
||||
required this.content,
|
||||
this.imageUrl,
|
||||
this.options,
|
||||
this.correctAnswer,
|
||||
this.studentAnswer,
|
||||
this.studentStrokes,
|
||||
this.questionScore,
|
||||
this.earnedScore,
|
||||
this.teacherComment,
|
||||
});
|
||||
|
||||
/// 从JSON解析
|
||||
factory HomeworkQuestion.fromJson(Map<String, dynamic> json) {
|
||||
return HomeworkQuestion(
|
||||
id: json['id'] ?? '',
|
||||
index: json['index'] ?? 0,
|
||||
type: json['type'] ?? 'write',
|
||||
content: json['content'] ?? '',
|
||||
imageUrl: json['image_url'],
|
||||
options: json['options'] != null
|
||||
? List<String>.from(json['options'])
|
||||
: null,
|
||||
correctAnswer: json['correct_answer'],
|
||||
studentAnswer: json['student_answer'],
|
||||
studentStrokes: json['student_strokes'] != null
|
||||
? List<Map<String, dynamic>>.from(json['student_strokes'])
|
||||
: null,
|
||||
questionScore: json['question_score'],
|
||||
earnedScore: json['earned_score'],
|
||||
teacherComment: json['teacher_comment'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Bloc Events(作业相关事件定义)
|
||||
// ============================================================
|
||||
|
||||
/// 作业事件基类
|
||||
abstract class HomeworkEvent {}
|
||||
|
||||
/// 加载作业列表事件
|
||||
class LoadHomeworkListEvent extends HomeworkEvent {
|
||||
final HomeworkStatus? filterStatus;
|
||||
final int page;
|
||||
final bool refresh;
|
||||
|
||||
LoadHomeworkListEvent({
|
||||
this.filterStatus,
|
||||
this.page = 1,
|
||||
this.refresh = false,
|
||||
});
|
||||
}
|
||||
|
||||
/// 下载作业详情事件(用于离线作答)
|
||||
class DownloadHomeworkEvent extends HomeworkEvent {
|
||||
final String homeworkId;
|
||||
DownloadHomeworkEvent(this.homeworkId);
|
||||
}
|
||||
|
||||
/// 保存作答进度事件(本地暂存)
|
||||
class SaveAnswerProgressEvent extends HomeworkEvent {
|
||||
final String homeworkId;
|
||||
final String questionId;
|
||||
final String? textAnswer;
|
||||
final List<Map<String, dynamic>>? strokeData;
|
||||
|
||||
SaveAnswerProgressEvent({
|
||||
required this.homeworkId,
|
||||
required this.questionId,
|
||||
this.textAnswer,
|
||||
this.strokeData,
|
||||
});
|
||||
}
|
||||
|
||||
/// 提交作业事件
|
||||
class SubmitHomeworkEvent extends HomeworkEvent {
|
||||
final String homeworkId;
|
||||
SubmitHomeworkEvent(this.homeworkId);
|
||||
}
|
||||
|
||||
/// 查看批改结果事件
|
||||
class ViewGradeResultEvent extends HomeworkEvent {
|
||||
final String homeworkId;
|
||||
ViewGradeResultEvent(this.homeworkId);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Bloc States(作业相关状态定义)
|
||||
// ============================================================
|
||||
|
||||
/// 作业状态基类
|
||||
abstract class HomeworkState {}
|
||||
|
||||
/// 初始状态
|
||||
class HomeworkInitialState extends HomeworkState {}
|
||||
|
||||
/// 加载中状态
|
||||
class HomeworkLoadingState extends HomeworkState {
|
||||
final String? message;
|
||||
HomeworkLoadingState({this.message});
|
||||
}
|
||||
|
||||
/// 作业列表加载成功状态
|
||||
class HomeworkListLoadedState extends HomeworkState {
|
||||
final List<HomeworkItem> homeworks;
|
||||
final bool hasMore;
|
||||
final int currentPage;
|
||||
final HomeworkStatus? currentFilter;
|
||||
|
||||
/// 各状态的作业计数统计
|
||||
final Map<HomeworkStatus, int> statusCounts;
|
||||
|
||||
HomeworkListLoadedState({
|
||||
required this.homeworks,
|
||||
this.hasMore = false,
|
||||
this.currentPage = 1,
|
||||
this.currentFilter,
|
||||
this.statusCounts = const {},
|
||||
});
|
||||
}
|
||||
|
||||
/// 作业详情加载成功状态
|
||||
class HomeworkDetailLoadedState extends HomeworkState {
|
||||
final HomeworkItem homework;
|
||||
final List<HomeworkQuestion> questions;
|
||||
final bool isOfflineAvailable;
|
||||
|
||||
HomeworkDetailLoadedState({
|
||||
required this.homework,
|
||||
required this.questions,
|
||||
this.isOfflineAvailable = false,
|
||||
});
|
||||
}
|
||||
|
||||
/// 作答进度保存成功状态
|
||||
class AnswerSavedState extends HomeworkState {
|
||||
final String homeworkId;
|
||||
final String questionId;
|
||||
final int answeredCount;
|
||||
final int totalCount;
|
||||
|
||||
AnswerSavedState({
|
||||
required this.homeworkId,
|
||||
required this.questionId,
|
||||
required this.answeredCount,
|
||||
required this.totalCount,
|
||||
});
|
||||
}
|
||||
|
||||
/// 作业提交成功状态
|
||||
class HomeworkSubmittedState extends HomeworkState {
|
||||
final String homeworkId;
|
||||
final DateTime submittedAt;
|
||||
|
||||
HomeworkSubmittedState({
|
||||
required this.homeworkId,
|
||||
required this.submittedAt,
|
||||
});
|
||||
}
|
||||
|
||||
/// 批改结果状态
|
||||
class GradeResultState extends HomeworkState {
|
||||
final HomeworkItem homework;
|
||||
final List<HomeworkQuestion> questions;
|
||||
final int totalScore;
|
||||
final int earnedScore;
|
||||
final String? overallComment;
|
||||
|
||||
GradeResultState({
|
||||
required this.homework,
|
||||
required this.questions,
|
||||
required this.totalScore,
|
||||
required this.earnedScore,
|
||||
this.overallComment,
|
||||
});
|
||||
}
|
||||
|
||||
/// 错误状态
|
||||
class HomeworkErrorState extends HomeworkState {
|
||||
final String message;
|
||||
final String? actionType;
|
||||
|
||||
HomeworkErrorState({
|
||||
required this.message,
|
||||
this.actionType,
|
||||
});
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// HomeworkBloc 实现
|
||||
// ============================================================
|
||||
|
||||
/// 作业状态管理Bloc
|
||||
/// 管理作业列表加载、下载、作答、提交、查看批改结果等完整流程
|
||||
class HomeworkBloc {
|
||||
/// 当前状态
|
||||
HomeworkState _state = HomeworkInitialState();
|
||||
|
||||
/// 状态流控制器
|
||||
final StreamController<HomeworkState> _stateController =
|
||||
StreamController<HomeworkState>.broadcast();
|
||||
|
||||
/// 本地缓存的作业列表
|
||||
List<HomeworkItem> _cachedHomeworks = [];
|
||||
|
||||
/// 本地缓存的作答进度 {homeworkId: {questionId: answerData}}
|
||||
final Map<String, Map<String, dynamic>> _answerCache = {};
|
||||
|
||||
/// 获取当前状态
|
||||
HomeworkState get state => _state;
|
||||
|
||||
/// 状态流
|
||||
Stream<HomeworkState> get stateStream => _stateController.stream;
|
||||
|
||||
/// 发射新状态
|
||||
void _emit(HomeworkState newState) {
|
||||
_state = newState;
|
||||
_stateController.add(newState);
|
||||
}
|
||||
|
||||
/// 处理事件分发
|
||||
void add(HomeworkEvent event) {
|
||||
if (event is LoadHomeworkListEvent) {
|
||||
_handleLoadList(event);
|
||||
} else if (event is DownloadHomeworkEvent) {
|
||||
_handleDownload(event);
|
||||
} else if (event is SaveAnswerProgressEvent) {
|
||||
_handleSaveAnswer(event);
|
||||
} else if (event is SubmitHomeworkEvent) {
|
||||
_handleSubmit(event);
|
||||
} else if (event is ViewGradeResultEvent) {
|
||||
_handleViewGrade(event);
|
||||
}
|
||||
}
|
||||
|
||||
/// 处理加载作业列表
|
||||
Future<void> _handleLoadList(LoadHomeworkListEvent event) async {
|
||||
try {
|
||||
_emit(HomeworkLoadingState(message: '正在加载作业列表...'));
|
||||
|
||||
// 调用API获取作业列表
|
||||
// final response = await PadApiService.instance.getHomeworkList(
|
||||
// page: event.page,
|
||||
// status: event.filterStatus?.name,
|
||||
// );
|
||||
|
||||
// 模拟数据处理逻辑
|
||||
if (event.refresh) {
|
||||
_cachedHomeworks.clear();
|
||||
}
|
||||
|
||||
// 统计各状态作业数量
|
||||
final statusCounts = <HomeworkStatus, int>{};
|
||||
for (final hw in _cachedHomeworks) {
|
||||
statusCounts[hw.status] = (statusCounts[hw.status] ?? 0) + 1;
|
||||
}
|
||||
|
||||
// 根据筛选条件过滤
|
||||
List<HomeworkItem> filtered = _cachedHomeworks;
|
||||
if (event.filterStatus != null) {
|
||||
filtered = _cachedHomeworks
|
||||
.where((hw) => hw.status == event.filterStatus)
|
||||
.toList();
|
||||
}
|
||||
|
||||
_emit(HomeworkListLoadedState(
|
||||
homeworks: filtered,
|
||||
hasMore: false,
|
||||
currentPage: event.page,
|
||||
currentFilter: event.filterStatus,
|
||||
statusCounts: statusCounts,
|
||||
));
|
||||
} catch (e) {
|
||||
_emit(HomeworkErrorState(
|
||||
message: '加载作业列表失败: $e',
|
||||
actionType: 'load_list',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 处理下载作业详情(支持离线作答)
|
||||
Future<void> _handleDownload(DownloadHomeworkEvent event) async {
|
||||
try {
|
||||
_emit(HomeworkLoadingState(message: '正在下载作业内容...'));
|
||||
|
||||
// 调用API下载作业详情
|
||||
// final response = await PadApiService.instance.downloadHomework(
|
||||
// event.homeworkId,
|
||||
// );
|
||||
|
||||
// 将作业内容缓存到本地SQLite(支持离线作答)
|
||||
// await LocalRepository.instance.cacheHomework(...)
|
||||
|
||||
// _emit(HomeworkDetailLoadedState(...));
|
||||
} catch (e) {
|
||||
_emit(HomeworkErrorState(
|
||||
message: '下载作业失败: $e',
|
||||
actionType: 'download',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 处理保存作答进度(本地暂存,支持断点续答)
|
||||
Future<void> _handleSaveAnswer(SaveAnswerProgressEvent event) async {
|
||||
try {
|
||||
// 更新内存缓存
|
||||
_answerCache.putIfAbsent(event.homeworkId, () => {});
|
||||
_answerCache[event.homeworkId]![event.questionId] = {
|
||||
'text_answer': event.textAnswer,
|
||||
'stroke_data': event.strokeData,
|
||||
'saved_at': DateTime.now().toIso8601String(),
|
||||
};
|
||||
|
||||
// 持久化到本地数据库
|
||||
// await LocalRepository.instance.saveAnswerProgress(...)
|
||||
|
||||
// 计算已作答题目数
|
||||
final answeredCount = _answerCache[event.homeworkId]?.length ?? 0;
|
||||
|
||||
_emit(AnswerSavedState(
|
||||
homeworkId: event.homeworkId,
|
||||
questionId: event.questionId,
|
||||
answeredCount: answeredCount,
|
||||
totalCount: 0, // 从缓存的作业详情中获取
|
||||
));
|
||||
} catch (e) {
|
||||
_emit(HomeworkErrorState(
|
||||
message: '保存作答进度失败: $e',
|
||||
actionType: 'save_answer',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 处理提交作业
|
||||
Future<void> _handleSubmit(SubmitHomeworkEvent event) async {
|
||||
try {
|
||||
_emit(HomeworkLoadingState(message: '正在提交作业...'));
|
||||
|
||||
// 收集所有作答数据
|
||||
final answers = _answerCache[event.homeworkId] ?? {};
|
||||
|
||||
// 构建提交数据(含笔迹页面数据)
|
||||
final strokePages = answers.entries.map((entry) {
|
||||
return {
|
||||
'question_id': entry.key,
|
||||
'answer': entry.value,
|
||||
};
|
||||
}).toList();
|
||||
|
||||
// 调用API提交
|
||||
// final response = await PadApiService.instance.submitHomework(
|
||||
// homeworkId: event.homeworkId,
|
||||
// strokePages: strokePages,
|
||||
// );
|
||||
|
||||
// 提交成功后清除本地缓存
|
||||
_answerCache.remove(event.homeworkId);
|
||||
|
||||
_emit(HomeworkSubmittedState(
|
||||
homeworkId: event.homeworkId,
|
||||
submittedAt: DateTime.now(),
|
||||
));
|
||||
} catch (e) {
|
||||
_emit(HomeworkErrorState(
|
||||
message: '提交作业失败: $e',
|
||||
actionType: 'submit',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 处理查看批改结果
|
||||
Future<void> _handleViewGrade(ViewGradeResultEvent event) async {
|
||||
try {
|
||||
_emit(HomeworkLoadingState(message: '正在加载批改结果...'));
|
||||
|
||||
// 调用API获取批改结果
|
||||
// final response = await PadApiService.instance.getHomeworkResult(
|
||||
// event.homeworkId,
|
||||
// );
|
||||
|
||||
// _emit(GradeResultState(...));
|
||||
} catch (e) {
|
||||
_emit(HomeworkErrorState(
|
||||
message: '加载批改结果失败: $e',
|
||||
actionType: 'view_grade',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// 释放资源
|
||||
void dispose() {
|
||||
_stateController.close();
|
||||
_cachedHomeworks.clear();
|
||||
_answerCache.clear();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user