Files
ai_english/client/lib/features/writing/models/writing_task.dart

267 lines
6.9 KiB
Dart
Raw Permalink Normal View History

2025-11-17 14:09:17 +08:00
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<String> keywords;
final List<String> 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<String, dynamic> 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<String>.from(json['keywords'] ?? []),
requirements: List<String>.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<String, dynamic> 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<String>? keywords,
List<String>? 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();
}