software copyright

This commit is contained in:
jiahong
2026-03-22 15:24:40 +08:00
parent e303bb868a
commit 60f336e345
155 changed files with 127262 additions and 0 deletions
@@ -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();
}
}