import 'package:json_annotation/json_annotation.dart'; import 'word_model.dart'; import 'vocabulary_book_category.dart'; part 'vocabulary_book_model.g.dart'; /// 词汇书类型 enum VocabularyBookType { @JsonValue('system') system, // 系统词汇书 @JsonValue('custom') custom, // 用户自定义词汇书 @JsonValue('shared') shared, // 共享词汇书 } /// 词汇书难度 enum VocabularyBookDifficulty { @JsonValue('beginner') beginner, @JsonValue('elementary') elementary, @JsonValue('intermediate') intermediate, @JsonValue('advanced') advanced, @JsonValue('expert') expert, } /// 词汇书模型 @JsonSerializable() class VocabularyBook { /// 词汇书ID final String id; /// 词汇书名称 final String name; /// 词汇书描述 final String? description; /// 词汇书类型 @JsonKey(defaultValue: VocabularyBookType.system) final VocabularyBookType type; /// 难度等级 @JsonKey(name: 'level') final VocabularyBookDifficulty difficulty; /// 封面图片URL @JsonKey(name: 'cover_image') final String? coverImageUrl; /// 单词总数 @JsonKey(name: 'total_words') final int totalWords; /// 创建者ID @JsonKey(name: 'creator_id') final String? creatorId; /// 创建者名称 @JsonKey(name: 'creator_name') final String? creatorName; /// 是否公开 @JsonKey(name: 'is_public', defaultValue: false) final bool isPublic; /// 标签列表 @JsonKey(defaultValue: []) final List tags; /// 分类 final String? category; /// 主分类 @JsonKey(name: 'main_category') final VocabularyBookMainCategory? mainCategory; /// 子分类(JSON字符串,根据主分类解析为对应的子分类枚举) @JsonKey(name: 'sub_category') final String? subCategory; /// 适用等级 @JsonKey(name: 'target_levels', defaultValue: []) final List targetLevels; /// 预计学习天数 @JsonKey(name: 'estimated_days', defaultValue: 30) final int estimatedDays; /// 每日学习单词数 @JsonKey(name: 'daily_word_count', defaultValue: 20) final int dailyWordCount; /// 下载次数 @JsonKey(name: 'download_count', defaultValue: 0) final int downloadCount; /// 评分 (1-5) @JsonKey(defaultValue: 0.0) final double rating; /// 评价数量 @JsonKey(name: 'review_count', defaultValue: 0) final int reviewCount; /// 创建时间 @JsonKey(name: 'created_at') final DateTime createdAt; /// 更新时间 @JsonKey(name: 'updated_at') final DateTime updatedAt; const VocabularyBook({ required this.id, required this.name, this.description, required this.type, required this.difficulty, this.coverImageUrl, required this.totalWords, this.creatorId, this.creatorName, this.isPublic = false, this.tags = const [], this.category, this.mainCategory, this.subCategory, this.targetLevels = const [], this.estimatedDays = 30, this.dailyWordCount = 20, this.downloadCount = 0, this.rating = 0.0, this.reviewCount = 0, required this.createdAt, required this.updatedAt, }); factory VocabularyBook.fromJson(Map json) { final book = _$VocabularyBookFromJson(json); // 如果有category字符串但没有mainCategory,则从category映射 if (book.category != null && book.mainCategory == null) { return book.copyWith( mainCategory: VocabularyBookCategoryHelper.getMainCategoryFromName(book.category), ); } return book; } Map toJson() => _$VocabularyBookToJson(this); VocabularyBook copyWith({ String? id, String? name, String? description, VocabularyBookType? type, VocabularyBookDifficulty? difficulty, String? coverImageUrl, int? totalWords, String? creatorId, String? creatorName, bool? isPublic, List? tags, String? category, VocabularyBookMainCategory? mainCategory, String? subCategory, List? targetLevels, int? estimatedDays, int? dailyWordCount, int? downloadCount, double? rating, int? reviewCount, DateTime? createdAt, DateTime? updatedAt, }) { return VocabularyBook( id: id ?? this.id, name: name ?? this.name, description: description ?? this.description, type: type ?? this.type, difficulty: difficulty ?? this.difficulty, coverImageUrl: coverImageUrl ?? this.coverImageUrl, totalWords: totalWords ?? this.totalWords, creatorId: creatorId ?? this.creatorId, creatorName: creatorName ?? this.creatorName, isPublic: isPublic ?? this.isPublic, tags: tags ?? this.tags, category: category ?? this.category, mainCategory: mainCategory ?? this.mainCategory, subCategory: subCategory ?? this.subCategory, targetLevels: targetLevels ?? this.targetLevels, estimatedDays: estimatedDays ?? this.estimatedDays, dailyWordCount: dailyWordCount ?? this.dailyWordCount, downloadCount: downloadCount ?? this.downloadCount, rating: rating ?? this.rating, reviewCount: reviewCount ?? this.reviewCount, createdAt: createdAt ?? this.createdAt, updatedAt: updatedAt ?? this.updatedAt, ); } } /// 用户词汇书学习进度 @JsonSerializable() class UserVocabularyBookProgress { /// 进度ID @JsonKey(fromJson: _idFromJson) final String id; /// 用户ID @JsonKey(name: 'user_id', fromJson: _userIdFromJson) final String userId; /// 词汇书ID @JsonKey(name: 'book_id') final String vocabularyBookId; /// 已学习单词数 @JsonKey(name: 'learned_words') final int learnedWords; /// 已掌握单词数 @JsonKey(name: 'mastered_words') final int masteredWords; /// 学习进度百分比 (0-100) @JsonKey(name: 'progress_percentage') final double progressPercentage; /// 连续学习天数 @JsonKey(name: 'streak_days') final int streakDays; /// 总学习天数 @JsonKey(name: 'total_study_days') final int totalStudyDays; /// 平均每日学习单词数 @JsonKey(name: 'average_daily_words') final double averageDailyWords; /// 预计完成时间 @JsonKey(name: 'estimated_completion_date') final DateTime? estimatedCompletionDate; /// 是否已完成 @JsonKey(name: 'is_completed') final bool isCompleted; /// 完成时间 @JsonKey(name: 'completed_at') final DateTime? completedAt; /// 开始学习时间 @JsonKey(name: 'started_at') final DateTime startedAt; /// 最后学习时间 @JsonKey(name: 'last_studied_at') final DateTime? lastStudiedAt; const UserVocabularyBookProgress({ required this.id, required this.userId, required this.vocabularyBookId, this.learnedWords = 0, this.masteredWords = 0, this.progressPercentage = 0.0, this.streakDays = 0, this.totalStudyDays = 0, this.averageDailyWords = 0.0, this.estimatedCompletionDate, this.isCompleted = false, this.completedAt, required this.startedAt, this.lastStudiedAt, }); factory UserVocabularyBookProgress.fromJson(Map json) => _$UserVocabularyBookProgressFromJson(json); Map toJson() => _$UserVocabularyBookProgressToJson(this); /// 类型转换方法 static String _idFromJson(dynamic value) => value?.toString() ?? '0'; static String _userIdFromJson(dynamic value) => value?.toString() ?? '0'; UserVocabularyBookProgress copyWith({ String? id, String? userId, String? vocabularyBookId, int? learnedWords, int? masteredWords, double? progressPercentage, int? streakDays, int? totalStudyDays, double? averageDailyWords, DateTime? estimatedCompletionDate, bool? isCompleted, DateTime? completedAt, DateTime? startedAt, DateTime? lastStudiedAt, }) { return UserVocabularyBookProgress( id: id ?? this.id, userId: userId ?? this.userId, vocabularyBookId: vocabularyBookId ?? this.vocabularyBookId, learnedWords: learnedWords ?? this.learnedWords, masteredWords: masteredWords ?? this.masteredWords, progressPercentage: progressPercentage ?? this.progressPercentage, streakDays: streakDays ?? this.streakDays, totalStudyDays: totalStudyDays ?? this.totalStudyDays, averageDailyWords: averageDailyWords ?? this.averageDailyWords, estimatedCompletionDate: estimatedCompletionDate ?? this.estimatedCompletionDate, isCompleted: isCompleted ?? this.isCompleted, completedAt: completedAt ?? this.completedAt, startedAt: startedAt ?? this.startedAt, lastStudiedAt: lastStudiedAt ?? this.lastStudiedAt, ); } } /// 词汇书单词关联 @JsonSerializable() class VocabularyBookWord { /// 关联ID @JsonKey(name: 'id', fromJson: _idFromJson) final String id; /// 词汇书ID @JsonKey(name: 'book_id') final String vocabularyBookId; /// 单词ID @JsonKey(name: 'vocabulary_id') final String wordId; /// 在词汇书中的顺序 @JsonKey(name: 'sort_order', defaultValue: 0) final int order; /// 单词信息 final Word? word; /// 添加时间 @JsonKey(name: 'created_at') final DateTime addedAt; const VocabularyBookWord({ required this.id, required this.vocabularyBookId, required this.wordId, required this.order, this.word, required this.addedAt, }); /// 处理id字段的类型转换(后端可能返回int或string) static String _idFromJson(dynamic value) { if (value is int) { return value.toString(); } return value.toString(); } factory VocabularyBookWord.fromJson(Map json) => _$VocabularyBookWordFromJson(json); Map toJson() => _$VocabularyBookWordToJson(this); VocabularyBookWord copyWith({ String? id, String? vocabularyBookId, String? wordId, int? order, Word? word, DateTime? addedAt, }) { return VocabularyBookWord( id: id ?? this.id, vocabularyBookId: vocabularyBookId ?? this.vocabularyBookId, wordId: wordId ?? this.wordId, order: order ?? this.order, word: word ?? this.word, addedAt: addedAt ?? this.addedAt, ); } }