import 'package:json_annotation/json_annotation.dart'; part 'word_model.g.dart'; /// 单词难度等级 enum WordDifficulty { @JsonValue('beginner') beginner, @JsonValue('elementary') elementary, @JsonValue('intermediate') intermediate, @JsonValue('advanced') advanced, @JsonValue('expert') expert, } /// 单词类型 enum WordType { @JsonValue('noun') noun, @JsonValue('verb') verb, @JsonValue('adjective') adjective, @JsonValue('adverb') adverb, @JsonValue('preposition') preposition, @JsonValue('conjunction') conjunction, @JsonValue('interjection') interjection, @JsonValue('pronoun') pronoun, @JsonValue('article') article, @JsonValue('phrase') phrase, } /// 学习状态 enum LearningStatus { @JsonValue('new') newWord, @JsonValue('learning') learning, @JsonValue('reviewing') reviewing, @JsonValue('mastered') mastered, @JsonValue('forgotten') forgotten, } /// 单词模型 @JsonSerializable() class Word { /// 单词ID @JsonKey(name: 'id', fromJson: _idFromJson) final String id; /// 处理id字段的类型转换(后端返回int64) static String _idFromJson(dynamic value) { if (value is int) { return value.toString(); } return value.toString(); } /// 单词 final String word; /// 音标 final String? phonetic; /// 音频URL @JsonKey(name: 'audio_url') final String? audioUrl; /// 词性和释义列表 @JsonKey(defaultValue: []) final List definitions; /// 例句列表 @JsonKey(defaultValue: []) final List examples; /// 同义词 @JsonKey(defaultValue: []) final List synonyms; /// 反义词 @JsonKey(defaultValue: []) final List antonyms; /// 词根词缀 final WordEtymology? etymology; /// 难度等级 @JsonKey(name: 'difficulty', fromJson: _difficultyFromJson) final WordDifficulty difficulty; /// 频率等级 (1-5) @JsonKey(defaultValue: 0) final int frequency; /// 图片URL @JsonKey(name: 'image_url') final String? imageUrl; /// 记忆技巧 @JsonKey(name: 'memory_tip') final String? memoryTip; /// 创建时间 @JsonKey(name: 'created_at') final DateTime createdAt; /// 更新时间 @JsonKey(name: 'updated_at') final DateTime updatedAt; const Word({ required this.id, required this.word, this.phonetic, this.audioUrl, required this.definitions, this.examples = const [], this.synonyms = const [], this.antonyms = const [], this.etymology, required this.difficulty, required this.frequency, this.imageUrl, this.memoryTip, required this.createdAt, required this.updatedAt, }); factory Word.fromJson(Map json) => _$WordFromJson(json); Map toJson() => _$WordToJson(this); /// 处理difficulty字段(后端可能为null、空字符串或其他值) static WordDifficulty _difficultyFromJson(dynamic value) { if (value == null || value == '') return WordDifficulty.beginner; final stringValue = value.toString().toLowerCase(); switch (stringValue) { case 'beginner': case '1': return WordDifficulty.beginner; case 'elementary': case '2': return WordDifficulty.elementary; case 'intermediate': case '3': return WordDifficulty.intermediate; case 'advanced': case '4': return WordDifficulty.advanced; case 'expert': case '5': return WordDifficulty.expert; default: return WordDifficulty.beginner; // 默认为初级 } } Word copyWith({ String? id, String? word, String? phonetic, String? audioUrl, List? definitions, List? examples, List? synonyms, List? antonyms, WordEtymology? etymology, WordDifficulty? difficulty, int? frequency, String? imageUrl, String? memoryTip, DateTime? createdAt, DateTime? updatedAt, }) { return Word( id: id ?? this.id, word: word ?? this.word, phonetic: phonetic ?? this.phonetic, audioUrl: audioUrl ?? this.audioUrl, definitions: definitions ?? this.definitions, examples: examples ?? this.examples, synonyms: synonyms ?? this.synonyms, antonyms: antonyms ?? this.antonyms, etymology: etymology ?? this.etymology, difficulty: difficulty ?? this.difficulty, frequency: frequency ?? this.frequency, imageUrl: imageUrl ?? this.imageUrl, memoryTip: memoryTip ?? this.memoryTip, createdAt: createdAt ?? this.createdAt, updatedAt: updatedAt ?? this.updatedAt, ); } } /// 单词释义 @JsonSerializable() class WordDefinition { /// 词性 @JsonKey(name: 'type', fromJson: _typeFromJson) final WordType type; /// 释义 final String definition; /// 中文翻译 @JsonKey(name: 'translation', fromJson: _translationFromJson) final String translation; /// 使用频率 (1-5) @JsonKey(defaultValue: 3) final int frequency; const WordDefinition({ required this.type, required this.definition, required this.translation, this.frequency = 3, }); /// 处理type字段(后端可能为null或空字符串) static WordType _typeFromJson(dynamic value) { if (value == null || value == '') return WordType.noun; final stringValue = value.toString().toLowerCase(); switch (stringValue) { case 'noun': case 'n': return WordType.noun; case 'verb': case 'v': return WordType.verb; case 'adjective': case 'adj': return WordType.adjective; case 'adverb': case 'adv': return WordType.adverb; case 'preposition': case 'prep': return WordType.preposition; case 'conjunction': case 'conj': return WordType.conjunction; case 'interjection': case 'interj': return WordType.interjection; case 'pronoun': case 'pron': return WordType.pronoun; case 'article': case 'art': return WordType.article; case 'phrase': return WordType.phrase; default: return WordType.noun; // 默认为名词 } } /// 处理translation字段(后端可能为null) static String _translationFromJson(dynamic value) { if (value == null) return ''; return value.toString(); } factory WordDefinition.fromJson(Map json) => _$WordDefinitionFromJson(json); Map toJson() => _$WordDefinitionToJson(this); WordDefinition copyWith({ WordType? type, String? definition, String? translation, int? frequency, }) { return WordDefinition( type: type ?? this.type, definition: definition ?? this.definition, translation: translation ?? this.translation, frequency: frequency ?? this.frequency, ); } } /// 单词例句 @JsonSerializable() class WordExample { /// 例句 @JsonKey(name: 'example', fromJson: _sentenceFromJson) final String sentence; /// 中文翻译 @JsonKey(name: 'translation', fromJson: _exampleTranslationFromJson) final String translation; /// 音频URL @JsonKey(name: 'audio_url') final String? audioUrl; /// 来源 final String? source; const WordExample({ required this.sentence, required this.translation, this.audioUrl, this.source, }); /// 处理example字段(映射到sentence) static String _sentenceFromJson(dynamic value) { if (value == null) return ''; return value.toString(); } /// 处理translation字段(后端可能为null) static String _exampleTranslationFromJson(dynamic value) { if (value == null) return ''; return value.toString(); } factory WordExample.fromJson(Map json) => _$WordExampleFromJson(json); Map toJson() => _$WordExampleToJson(this); WordExample copyWith({ String? sentence, String? translation, String? audioUrl, String? source, }) { return WordExample( sentence: sentence ?? this.sentence, translation: translation ?? this.translation, audioUrl: audioUrl ?? this.audioUrl, source: source ?? this.source, ); } } /// 词根词缀 @JsonSerializable() class WordEtymology { /// 词根 final List roots; /// 前缀 final List prefixes; /// 后缀 final List suffixes; /// 词源说明 final String? origin; const WordEtymology({ this.roots = const [], this.prefixes = const [], this.suffixes = const [], this.origin, }); factory WordEtymology.fromJson(Map json) => _$WordEtymologyFromJson(json); Map toJson() => _$WordEtymologyToJson(this); WordEtymology copyWith({ List? roots, List? prefixes, List? suffixes, String? origin, }) { return WordEtymology( roots: roots ?? this.roots, prefixes: prefixes ?? this.prefixes, suffixes: suffixes ?? this.suffixes, origin: origin ?? this.origin, ); } } /// 用户单词学习记录 @JsonSerializable() class UserWordProgress { /// 记录ID @JsonKey(fromJson: _idFromJson) final String id; /// 用户ID @JsonKey(name: 'user_id', fromJson: _userIdFromJson) final String userId; /// 单词ID @JsonKey(name: 'vocabulary_id', fromJson: _wordIdFromJson) final String wordId; /// 学习状态 final LearningStatus status; /// 学习次数 @JsonKey(name: 'study_count') final int studyCount; /// 正确次数 @JsonKey(name: 'correct_count') final int correctCount; /// 错误次数 @JsonKey(name: 'wrong_count') final int wrongCount; /// 熟练度 (0-100) final int proficiency; /// 下次复习时间 @JsonKey(name: 'next_review_at') final DateTime? nextReviewAt; /// 复习间隔 (天) @JsonKey(name: 'review_interval') final int reviewInterval; /// 首次学习时间 @JsonKey(name: 'first_studied_at') final DateTime firstStudiedAt; /// 最后学习时间 @JsonKey(name: 'last_studied_at') final DateTime lastStudiedAt; /// 掌握时间 @JsonKey(name: 'mastered_at') final DateTime? masteredAt; const UserWordProgress({ required this.id, required this.userId, required this.wordId, required this.status, this.studyCount = 0, this.correctCount = 0, this.wrongCount = 0, this.proficiency = 0, this.nextReviewAt, this.reviewInterval = 1, required this.firstStudiedAt, required this.lastStudiedAt, this.masteredAt, }); factory UserWordProgress.fromJson(Map json) => _$UserWordProgressFromJson(json); Map toJson() => _$UserWordProgressToJson(this); UserWordProgress copyWith({ String? id, String? userId, String? wordId, LearningStatus? status, int? studyCount, int? correctCount, int? wrongCount, int? proficiency, DateTime? nextReviewAt, int? reviewInterval, DateTime? firstStudiedAt, DateTime? lastStudiedAt, DateTime? masteredAt, }) { return UserWordProgress( id: id ?? this.id, userId: userId ?? this.userId, wordId: wordId ?? this.wordId, status: status ?? this.status, studyCount: studyCount ?? this.studyCount, correctCount: correctCount ?? this.correctCount, wrongCount: wrongCount ?? this.wrongCount, proficiency: proficiency ?? this.proficiency, nextReviewAt: nextReviewAt ?? this.nextReviewAt, reviewInterval: reviewInterval ?? this.reviewInterval, firstStudiedAt: firstStudiedAt ?? this.firstStudiedAt, lastStudiedAt: lastStudiedAt ?? this.lastStudiedAt, masteredAt: masteredAt ?? this.masteredAt, ); } /// 计算学习准确率 double get accuracy { if (studyCount == 0) return 0.0; return correctCount / studyCount; } /// 是否需要复习 bool get needsReview { if (nextReviewAt == null) return false; return DateTime.now().isAfter(nextReviewAt!); } /// 是否为新单词 bool get isNew => status == LearningStatus.newWord; /// 是否已掌握 bool get isMastered => status == LearningStatus.mastered; /// 类型转换方法 static String _idFromJson(dynamic value) => value.toString(); static String _userIdFromJson(dynamic value) => value.toString(); static String _wordIdFromJson(dynamic value) => value.toString(); }