enum QuestionType { multipleChoice, trueFalse, fillInBlank, shortAnswer, } class ReadingQuestion { final String id; final String articleId; final QuestionType type; final String question; final List options; // For multiple choice questions final String correctAnswer; final String explanation; final int order; final String? userAnswer; final bool? isCorrect; const ReadingQuestion({ required this.id, required this.articleId, required this.type, required this.question, required this.options, required this.correctAnswer, required this.explanation, required this.order, this.userAnswer, this.isCorrect, }); factory ReadingQuestion.fromJson(Map json) { return ReadingQuestion( id: json['id'] as String, articleId: json['articleId'] as String, type: QuestionType.values.firstWhere( (e) => e.toString().split('.').last == json['type'], orElse: () => QuestionType.multipleChoice, ), question: json['question'] as String, options: List.from(json['options'] as List? ?? []), correctAnswer: json['correctAnswer'] as String, explanation: json['explanation'] as String, order: json['order'] as int, userAnswer: json['userAnswer'] as String?, isCorrect: json['isCorrect'] as bool?, ); } Map toJson() { return { 'id': id, 'articleId': articleId, 'type': type.toString().split('.').last, 'question': question, 'options': options, 'correctAnswer': correctAnswer, 'explanation': explanation, 'order': order, 'userAnswer': userAnswer, 'isCorrect': isCorrect, }; } ReadingQuestion copyWith({ String? id, String? articleId, QuestionType? type, String? question, List? options, String? correctAnswer, String? explanation, int? order, String? userAnswer, bool? isCorrect, }) { return ReadingQuestion( id: id ?? this.id, articleId: articleId ?? this.articleId, type: type ?? this.type, question: question ?? this.question, options: options ?? this.options, correctAnswer: correctAnswer ?? this.correctAnswer, explanation: explanation ?? this.explanation, order: order ?? this.order, userAnswer: userAnswer ?? this.userAnswer, isCorrect: isCorrect ?? this.isCorrect, ); } String get typeLabel { switch (type) { case QuestionType.multipleChoice: return '选择题'; case QuestionType.trueFalse: return '判断题'; case QuestionType.fillInBlank: return '填空题'; case QuestionType.shortAnswer: return '简答题'; } } } class ReadingExercise { final String id; final String articleId; final List questions; final DateTime? startTime; final DateTime? endTime; final double? score; final bool isCompleted; const ReadingExercise({ required this.id, required this.articleId, required this.questions, this.startTime, this.endTime, this.score, this.isCompleted = false, }); factory ReadingExercise.fromJson(Map json) { return ReadingExercise( id: json['id'] as String, articleId: json['articleId'] as String, questions: (json['questions'] as List) .map((q) => ReadingQuestion.fromJson(q as Map)) .toList(), startTime: json['startTime'] != null ? DateTime.parse(json['startTime'] as String) : null, endTime: json['endTime'] != null ? DateTime.parse(json['endTime'] as String) : null, score: json['score'] as double?, isCompleted: json['isCompleted'] as bool? ?? false, ); } Map toJson() { return { 'id': id, 'articleId': articleId, 'questions': questions.map((q) => q.toJson()).toList(), 'startTime': startTime?.toIso8601String(), 'endTime': endTime?.toIso8601String(), 'score': score, 'isCompleted': isCompleted, }; } ReadingExercise copyWith({ String? id, String? articleId, List? questions, DateTime? startTime, DateTime? endTime, double? score, bool? isCompleted, }) { return ReadingExercise( id: id ?? this.id, articleId: articleId ?? this.articleId, questions: questions ?? this.questions, startTime: startTime ?? this.startTime, endTime: endTime ?? this.endTime, score: score ?? this.score, isCompleted: isCompleted ?? this.isCompleted, ); } int get totalQuestions => questions.length; int get answeredQuestions { return questions.where((q) => q.userAnswer != null).length; } int get correctAnswers { return questions.where((q) => q.isCorrect == true).length; } double get progressPercentage { if (totalQuestions == 0) return 0.0; return (answeredQuestions / totalQuestions) * 100; } Duration? get duration { if (startTime != null && endTime != null) { return endTime!.difference(startTime!); } return null; } } /// 阅读练习结果 class ReadingExerciseResult { final double score; final int correctCount; final int totalCount; final Duration timeSpent; // 用时 final double accuracy; const ReadingExerciseResult({ required this.score, required this.correctCount, required this.totalCount, required this.timeSpent, required this.accuracy, }); /// 错误题数 int get wrongCount => totalCount - correctCount; /// 总题数(别名) int get totalQuestions => totalCount; factory ReadingExerciseResult.fromJson(Map json) { return ReadingExerciseResult( score: (json['score'] as num).toDouble(), correctCount: json['correctCount'] as int, totalCount: json['totalCount'] as int, timeSpent: Duration(seconds: json['timeSpent'] as int), accuracy: (json['accuracy'] as num).toDouble(), ); } Map toJson() { return { 'score': score, 'correctCount': correctCount, 'totalCount': totalCount, 'timeSpent': timeSpent.inSeconds, 'accuracy': accuracy, }; } bool get isPassed => score >= 60.0; }