Files
ai_english/client/lib/features/vocabulary/models/vocabulary_book_model.dart

388 lines
10 KiB
Dart
Raw Normal View History

2025-11-17 14:09:17 +08:00
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<String> 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<String> 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<String, dynamic> 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<String, dynamic> 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<String>? tags,
String? category,
VocabularyBookMainCategory? mainCategory,
String? subCategory,
List<String>? 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<String, dynamic> json) => _$UserVocabularyBookProgressFromJson(json);
Map<String, dynamic> 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<String, dynamic> json) => _$VocabularyBookWordFromJson(json);
Map<String, dynamic> 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,
);
}
}