class WritingTask { final String id; final String title; final String description; final WritingType type; final WritingDifficulty difficulty; final int timeLimit; // 分钟 final int wordLimit; final List keywords; final List requirements; final String? prompt; final String? imageUrl; final ExamType? examType; // 考试类型 final DateTime createdAt; final DateTime? updatedAt; const WritingTask({ required this.id, required this.title, required this.description, required this.type, required this.difficulty, required this.timeLimit, required this.wordLimit, required this.keywords, required this.requirements, this.prompt, this.imageUrl, this.examType, required this.createdAt, this.updatedAt, }); factory WritingTask.fromJson(Map json) { final idVal = json['id'] ?? json['prompt_id']; final typeVal = json['type']; final difficultyVal = json['difficulty']; final timeLimitVal = json['timeLimit'] ?? json['time_limit']; final wordLimitVal = json['wordLimit'] ?? json['word_limit']; final examTypeVal = json['examType'] ?? json['exam_type']; final createdAtVal = json['createdAt'] ?? json['created_at']; final updatedAtVal = json['updatedAt'] ?? json['updated_at']; return WritingTask( id: (idVal ?? '').toString(), title: (json['title'] ?? '').toString(), description: (json['description'] ?? '').toString(), type: typeVal is String ? WritingType.values.firstWhere( (e) => e.name == typeVal, orElse: () => WritingType.essay, ) : WritingType.essay, difficulty: difficultyVal is String ? WritingDifficulty.values.firstWhere( (e) => e.name == difficultyVal, orElse: () => WritingDifficulty.intermediate, ) : WritingDifficulty.intermediate, timeLimit: _asInt(timeLimitVal), wordLimit: _asInt(wordLimitVal), keywords: List.from(json['keywords'] ?? []), requirements: List.from(json['requirements'] ?? []), prompt: json['prompt'] as String?, imageUrl: json['imageUrl'] as String?, examType: examTypeVal is String ? ExamType.values.firstWhere( (e) => e.name == examTypeVal, orElse: () => ExamType.cet, ) : null, createdAt: _parseDate(createdAtVal), updatedAt: updatedAtVal != null ? _parseDate(updatedAtVal) : null, ); } Map toJson() { return { 'id': id, 'title': title, 'description': description, 'type': type.name, 'difficulty': difficulty.name, 'timeLimit': timeLimit, 'wordLimit': wordLimit, 'keywords': keywords, 'requirements': requirements, 'prompt': prompt, 'imageUrl': imageUrl, 'examType': examType?.name, 'createdAt': createdAt.toIso8601String(), 'updatedAt': updatedAt?.toIso8601String(), }; } WritingTask copyWith({ String? id, String? title, String? description, WritingType? type, WritingDifficulty? difficulty, int? timeLimit, int? wordLimit, List? keywords, List? requirements, String? prompt, String? imageUrl, ExamType? examType, DateTime? createdAt, DateTime? updatedAt, }) { return WritingTask( id: id ?? this.id, title: title ?? this.title, description: description ?? this.description, type: type ?? this.type, difficulty: difficulty ?? this.difficulty, timeLimit: timeLimit ?? this.timeLimit, wordLimit: wordLimit ?? this.wordLimit, keywords: keywords ?? this.keywords, requirements: requirements ?? this.requirements, prompt: prompt ?? this.prompt, imageUrl: imageUrl ?? this.imageUrl, examType: examType ?? this.examType, createdAt: createdAt ?? this.createdAt, updatedAt: updatedAt ?? this.updatedAt, ); } } enum WritingType { essay, letter, email, report, story, review, article, diary, description, argument, } enum WritingDifficulty { beginner, elementary, intermediate, upperIntermediate, advanced, } extension WritingTypeExtension on WritingType { String get displayName { switch (this) { case WritingType.essay: return '议论文'; case WritingType.letter: return '书信'; case WritingType.email: return '邮件'; case WritingType.report: return '报告'; case WritingType.story: return '故事'; case WritingType.review: return '评论'; case WritingType.article: return '文章'; case WritingType.diary: return '日记'; case WritingType.description: return '描述文'; case WritingType.argument: return '辩论文'; } } } extension WritingDifficultyExtension on WritingDifficulty { String get displayName { switch (this) { case WritingDifficulty.beginner: return '初级'; case WritingDifficulty.elementary: return '基础'; case WritingDifficulty.intermediate: return '中级'; case WritingDifficulty.upperIntermediate: return '中高级'; case WritingDifficulty.advanced: return '高级'; } } int get level { switch (this) { case WritingDifficulty.beginner: return 1; case WritingDifficulty.elementary: return 2; case WritingDifficulty.intermediate: return 3; case WritingDifficulty.upperIntermediate: return 4; case WritingDifficulty.advanced: return 5; } } } enum ExamType { cet, // 四六级 kaoyan, // 考研 toefl, // 托福 ielts, // 雅思 } extension ExamTypeExtension on ExamType { String get displayName { switch (this) { case ExamType.cet: return '四六级'; case ExamType.kaoyan: return '考研'; case ExamType.toefl: return '托福'; case ExamType.ielts: return '雅思'; } } String get description { switch (this) { case ExamType.cet: return '大学英语四六级考试写作'; case ExamType.kaoyan: return '研究生入学考试英语写作'; case ExamType.toefl: return 'TOEFL托福考试写作'; case ExamType.ielts: return 'IELTS雅思考试写作'; } } } int _asInt(dynamic v) { if (v == null) return 0; if (v is int) return v; if (v is num) return v.toInt(); if (v is String) { final parsed = double.tryParse(v); return parsed?.toInt() ?? int.tryParse(v) ?? 0; } return 0; } DateTime _parseDate(dynamic v) { if (v is String) { try { return DateTime.parse(v); } catch (_) {} } if (v is int) { return DateTime.fromMillisecondsSinceEpoch(v); } return DateTime.now(); }