267 lines
6.9 KiB
Dart
267 lines
6.9 KiB
Dart
|
|
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();
|
||
|
|
}
|