This commit is contained in:
sjk
2025-11-17 13:39:05 +08:00
commit d4cfe2b9de
479 changed files with 109324 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
/// 写作完成记录模型
class WritingRecord {
final String id;
final String taskId;
final String taskTitle;
final String taskDescription;
final String content;
final int wordCount;
final int timeUsed; // 使用的时间(秒)
final int score;
final DateTime completedAt;
final Map<String, dynamic>? feedback;
const WritingRecord({
required this.id,
required this.taskId,
required this.taskTitle,
required this.taskDescription,
required this.content,
required this.wordCount,
required this.timeUsed,
required this.score,
required this.completedAt,
this.feedback,
});
Map<String, dynamic> toJson() {
return {
'id': id,
'taskId': taskId,
'taskTitle': taskTitle,
'taskDescription': taskDescription,
'content': content,
'wordCount': wordCount,
'timeUsed': timeUsed,
'score': score,
'completedAt': completedAt.toIso8601String(),
'feedback': feedback,
};
}
factory WritingRecord.fromJson(Map<String, dynamic> json) {
return WritingRecord(
id: json['id'],
taskId: json['taskId'],
taskTitle: json['taskTitle'],
taskDescription: json['taskDescription'],
content: json['content'],
wordCount: json['wordCount'],
timeUsed: json['timeUsed'],
score: json['score'],
completedAt: DateTime.parse(json['completedAt']),
feedback: json['feedback'],
);
}
WritingRecord copyWith({
String? id,
String? taskId,
String? taskTitle,
String? taskDescription,
String? content,
int? wordCount,
int? timeUsed,
int? score,
DateTime? completedAt,
Map<String, dynamic>? feedback,
}) {
return WritingRecord(
id: id ?? this.id,
taskId: taskId ?? this.taskId,
taskTitle: taskTitle ?? this.taskTitle,
taskDescription: taskDescription ?? this.taskDescription,
content: content ?? this.content,
wordCount: wordCount ?? this.wordCount,
timeUsed: timeUsed ?? this.timeUsed,
score: score ?? this.score,
completedAt: completedAt ?? this.completedAt,
feedback: feedback ?? this.feedback,
);
}
String get formattedDate {
return '${completedAt.year}-${completedAt.month.toString().padLeft(2, '0')}-${completedAt.day.toString().padLeft(2, '0')}';
}
String get formattedTime {
final minutes = timeUsed ~/ 60;
final seconds = timeUsed % 60;
return '${minutes}${seconds}';
}
String get scoreText {
return '${score}';
}
}

View File

@@ -0,0 +1,238 @@
class WritingStats {
final String userId;
final int totalTasks;
final int completedTasks;
final int totalWords;
final int totalTimeSpent; // 秒
final double averageScore;
final Map<String, int> taskTypeStats;
final Map<String, int> difficultyStats;
final List<WritingProgressData> progressData;
final WritingSkillAnalysis skillAnalysis;
final DateTime lastUpdated;
const WritingStats({
required this.userId,
required this.totalTasks,
required this.completedTasks,
required this.totalWords,
required this.totalTimeSpent,
required this.averageScore,
required this.taskTypeStats,
required this.difficultyStats,
required this.progressData,
required this.skillAnalysis,
required this.lastUpdated,
});
double get completionRate => totalTasks > 0 ? (completedTasks / totalTasks) * 100 : 0;
double get averageWordsPerTask => completedTasks > 0 ? totalWords / completedTasks : 0;
double get averageTimePerTask => completedTasks > 0 ? totalTimeSpent / completedTasks : 0;
factory WritingStats.fromJson(Map<String, dynamic> json) {
final userIdVal = json['userId'];
final totalTasksVal = json['totalTasks'] ?? json['total_submissions'];
final completedTasksVal = json['completedTasks'] ?? json['completed_submissions'];
final totalWordsVal = json['totalWords'] ?? json['total_word_count'];
final totalTimeSpentVal = json['totalTimeSpent'] ?? json['total_time_spent'];
final averageScoreVal = json['averageScore'] ?? json['average_score'];
final difficultyStatsVal = json['difficultyStats'] ?? json['difficulty_stats'] ?? {};
final progressDataVal = json['progressData'] ?? [];
final skillAnalysisVal = json['skillAnalysis'];
final lastUpdatedVal = json['lastUpdated'];
final stats = WritingStats(
userId: userIdVal?.toString() ?? '',
totalTasks: _asInt(totalTasksVal),
completedTasks: _asInt(completedTasksVal),
totalWords: _asInt(totalWordsVal),
totalTimeSpent: _asInt(totalTimeSpentVal),
averageScore: _asDouble(averageScoreVal),
taskTypeStats: Map<String, int>.from(json['taskTypeStats'] ?? {}),
difficultyStats: Map<String, int>.from(difficultyStatsVal),
progressData: (progressDataVal is List)
? progressDataVal
.map((e) => WritingProgressData.fromJson(Map<String, dynamic>.from(e)))
.toList()
: <WritingProgressData>[],
skillAnalysis: skillAnalysisVal is Map<String, dynamic>
? WritingSkillAnalysis.fromJson(skillAnalysisVal)
: WritingSkillAnalysis(
criteriaScores: {
'grammar': _normalize01(_asDouble(json['average_grammar_score'])),
'coherence': _normalize01(_asDouble(json['average_coherence_score'])),
'vocab': _normalize01(_asDouble(json['average_vocab_score'])),
},
errorCounts: {},
strengths: const [],
weaknesses: const [],
recommendations: const [],
improvementRate: 0.0,
lastAnalyzed: DateTime.now(),
),
lastUpdated: lastUpdatedVal is String
? DateTime.parse(lastUpdatedVal)
: DateTime.now(),
);
return stats;
}
Map<String, dynamic> toJson() {
return {
'userId': userId,
'totalTasks': totalTasks,
'completedTasks': completedTasks,
'totalWords': totalWords,
'totalTimeSpent': totalTimeSpent,
'averageScore': averageScore,
'taskTypeStats': taskTypeStats,
'difficultyStats': difficultyStats,
'progressData': progressData.map((e) => e.toJson()).toList(),
'skillAnalysis': skillAnalysis.toJson(),
'lastUpdated': lastUpdated.toIso8601String(),
};
}
WritingStats copyWith({
String? userId,
int? totalTasks,
int? completedTasks,
int? totalWords,
int? totalTimeSpent,
double? averageScore,
Map<String, int>? taskTypeStats,
Map<String, int>? difficultyStats,
List<WritingProgressData>? progressData,
WritingSkillAnalysis? skillAnalysis,
DateTime? lastUpdated,
}) {
return WritingStats(
userId: userId ?? this.userId,
totalTasks: totalTasks ?? this.totalTasks,
completedTasks: completedTasks ?? this.completedTasks,
totalWords: totalWords ?? this.totalWords,
totalTimeSpent: totalTimeSpent ?? this.totalTimeSpent,
averageScore: averageScore ?? this.averageScore,
taskTypeStats: taskTypeStats ?? this.taskTypeStats,
difficultyStats: difficultyStats ?? this.difficultyStats,
progressData: progressData ?? this.progressData,
skillAnalysis: skillAnalysis ?? this.skillAnalysis,
lastUpdated: lastUpdated ?? this.lastUpdated,
);
}
}
class WritingProgressData {
final DateTime date;
final double score;
final int wordCount;
final int timeSpent;
final String taskType;
final String difficulty;
const WritingProgressData({
required this.date,
required this.score,
required this.wordCount,
required this.timeSpent,
required this.taskType,
required this.difficulty,
});
factory WritingProgressData.fromJson(Map<String, dynamic> json) {
return WritingProgressData(
date: DateTime.parse(json['date'] as String),
score: (json['score'] as num).toDouble(),
wordCount: json['wordCount'] as int,
timeSpent: json['timeSpent'] as int,
taskType: json['taskType'] as String,
difficulty: json['difficulty'] as String,
);
}
Map<String, dynamic> toJson() {
return {
'date': date.toIso8601String(),
'score': score,
'wordCount': wordCount,
'timeSpent': timeSpent,
'taskType': taskType,
'difficulty': difficulty,
};
}
}
class WritingSkillAnalysis {
final Map<String, double> criteriaScores;
final Map<String, int> errorCounts;
final List<String> strengths;
final List<String> weaknesses;
final List<String> recommendations;
final double improvementRate;
final DateTime lastAnalyzed;
const WritingSkillAnalysis({
required this.criteriaScores,
required this.errorCounts,
required this.strengths,
required this.weaknesses,
required this.recommendations,
required this.improvementRate,
required this.lastAnalyzed,
});
factory WritingSkillAnalysis.fromJson(Map<String, dynamic> json) {
return WritingSkillAnalysis(
criteriaScores: Map<String, double>.from(
(json['criteriaScores'] as Map<String, dynamic>).map(
(k, v) => MapEntry(k, (v as num).toDouble()),
),
),
errorCounts: Map<String, int>.from(json['errorCounts'] ?? {}),
strengths: List<String>.from(json['strengths'] ?? []),
weaknesses: List<String>.from(json['weaknesses'] ?? []),
recommendations: List<String>.from(json['recommendations'] ?? []),
improvementRate: (json['improvementRate'] as num).toDouble(),
lastAnalyzed: DateTime.parse(json['lastAnalyzed'] as String),
);
}
Map<String, dynamic> toJson() {
return {
'criteriaScores': criteriaScores,
'errorCounts': errorCounts,
'strengths': strengths,
'weaknesses': weaknesses,
'recommendations': recommendations,
'improvementRate': improvementRate,
'lastAnalyzed': lastAnalyzed.toIso8601String(),
};
}
}
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;
}
double _asDouble(dynamic v) {
if (v == null) return 0.0;
if (v is double) return v;
if (v is num) return v.toDouble();
if (v is String) return double.tryParse(v) ?? 0.0;
return 0.0;
}
double _normalize01(double v) {
if (v <= 1.0) return v;
return v / 100.0;
}

View File

@@ -0,0 +1,408 @@
import 'writing_task.dart';
class WritingSubmission {
final String id;
final String taskId;
final String userId;
final String content;
final int wordCount;
final int timeSpent; // 秒
final WritingStatus status;
final DateTime submittedAt;
final WritingFeedback? feedback;
final WritingScore? score;
const WritingSubmission({
required this.id,
required this.taskId,
required this.userId,
required this.content,
required this.wordCount,
required this.timeSpent,
required this.status,
required this.submittedAt,
this.feedback,
this.score,
});
factory WritingSubmission.fromJson(Map<String, dynamic> json) {
return WritingSubmission(
id: json['id'] as String,
taskId: json['taskId'] as String,
userId: json['userId'] as String,
content: json['content'] as String,
wordCount: json['wordCount'] as int,
timeSpent: json['timeSpent'] as int,
status: WritingStatus.values.firstWhere(
(e) => e.name == json['status'],
orElse: () => WritingStatus.draft,
),
submittedAt: DateTime.parse(json['submittedAt'] as String),
feedback: json['feedback'] != null
? WritingFeedback.fromJson(json['feedback'] as Map<String, dynamic>)
: null,
score: json['score'] != null
? WritingScore.fromJson(json['score'] as Map<String, dynamic>)
: null,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'taskId': taskId,
'userId': userId,
'content': content,
'wordCount': wordCount,
'timeSpent': timeSpent,
'status': status.name,
'submittedAt': submittedAt.toIso8601String(),
'feedback': feedback?.toJson(),
'score': score?.toJson(),
};
}
WritingSubmission copyWith({
String? id,
String? taskId,
String? userId,
String? content,
int? wordCount,
int? timeSpent,
WritingStatus? status,
DateTime? submittedAt,
WritingFeedback? feedback,
WritingScore? score,
}) {
return WritingSubmission(
id: id ?? this.id,
taskId: taskId ?? this.taskId,
userId: userId ?? this.userId,
content: content ?? this.content,
wordCount: wordCount ?? this.wordCount,
timeSpent: timeSpent ?? this.timeSpent,
status: status ?? this.status,
submittedAt: submittedAt ?? this.submittedAt,
feedback: feedback ?? this.feedback,
score: score ?? this.score,
);
}
}
class WritingFeedback {
final String id;
final String submissionId;
final String overallComment;
final List<WritingCriteriaFeedback> criteriaFeedbacks;
final List<WritingError> errors;
final List<WritingSuggestion> suggestions;
final DateTime createdAt;
const WritingFeedback({
required this.id,
required this.submissionId,
required this.overallComment,
required this.criteriaFeedbacks,
required this.errors,
required this.suggestions,
required this.createdAt,
});
factory WritingFeedback.fromJson(Map<String, dynamic> json) {
return WritingFeedback(
id: json['id'] as String,
submissionId: json['submissionId'] as String,
overallComment: json['overallComment'] as String,
criteriaFeedbacks: (json['criteriaFeedbacks'] as List<dynamic>)
.map((e) => WritingCriteriaFeedback.fromJson(e as Map<String, dynamic>))
.toList(),
errors: (json['errors'] as List<dynamic>)
.map((e) => WritingError.fromJson(e as Map<String, dynamic>))
.toList(),
suggestions: (json['suggestions'] as List<dynamic>)
.map((e) => WritingSuggestion.fromJson(e as Map<String, dynamic>))
.toList(),
createdAt: DateTime.parse(json['createdAt'] as String),
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'submissionId': submissionId,
'overallComment': overallComment,
'criteriaFeedbacks': criteriaFeedbacks.map((e) => e.toJson()).toList(),
'errors': errors.map((e) => e.toJson()).toList(),
'suggestions': suggestions.map((e) => e.toJson()).toList(),
'createdAt': createdAt.toIso8601String(),
};
}
}
class WritingScore {
final String id;
final String submissionId;
final double totalScore;
final double maxScore;
final Map<WritingCriteria, double> criteriaScores;
final String grade;
final DateTime createdAt;
const WritingScore({
required this.id,
required this.submissionId,
required this.totalScore,
required this.maxScore,
required this.criteriaScores,
required this.grade,
required this.createdAt,
});
double get percentage => (totalScore / maxScore) * 100;
factory WritingScore.fromJson(Map<String, dynamic> json) {
return WritingScore(
id: json['id'] as String,
submissionId: json['submissionId'] as String,
totalScore: (json['totalScore'] as num).toDouble(),
maxScore: (json['maxScore'] as num).toDouble(),
criteriaScores: Map<WritingCriteria, double>.fromEntries(
(json['criteriaScores'] as Map<String, dynamic>).entries.map(
(e) => MapEntry(
WritingCriteria.values.firstWhere((c) => c.name == e.key),
(e.value as num).toDouble(),
),
),
),
grade: json['grade'] as String,
createdAt: DateTime.parse(json['createdAt'] as String),
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'submissionId': submissionId,
'totalScore': totalScore,
'maxScore': maxScore,
'criteriaScores': Map<String, dynamic>.fromEntries(
criteriaScores.entries.map(
(e) => MapEntry(e.key.name, e.value),
),
),
'grade': grade,
'createdAt': createdAt.toIso8601String(),
};
}
}
class WritingCriteriaFeedback {
final WritingCriteria criteria;
final double score;
final double maxScore;
final String comment;
final List<String> strengths;
final List<String> improvements;
const WritingCriteriaFeedback({
required this.criteria,
required this.score,
required this.maxScore,
required this.comment,
required this.strengths,
required this.improvements,
});
factory WritingCriteriaFeedback.fromJson(Map<String, dynamic> json) {
return WritingCriteriaFeedback(
criteria: WritingCriteria.values.firstWhere(
(e) => e.name == json['criteria'],
),
score: (json['score'] as num).toDouble(),
maxScore: (json['maxScore'] as num).toDouble(),
comment: json['comment'] as String,
strengths: List<String>.from(json['strengths'] ?? []),
improvements: List<String>.from(json['improvements'] ?? []),
);
}
Map<String, dynamic> toJson() {
return {
'criteria': criteria.name,
'score': score,
'maxScore': maxScore,
'comment': comment,
'strengths': strengths,
'improvements': improvements,
};
}
}
class WritingError {
final WritingErrorType type;
final String description;
final String originalText;
final String? suggestedText;
final int startPosition;
final int endPosition;
final String explanation;
const WritingError({
required this.type,
required this.description,
required this.originalText,
this.suggestedText,
required this.startPosition,
required this.endPosition,
required this.explanation,
});
factory WritingError.fromJson(Map<String, dynamic> json) {
return WritingError(
type: WritingErrorType.values.firstWhere(
(e) => e.name == json['type'],
),
description: json['description'] as String,
originalText: json['originalText'] as String,
suggestedText: json['suggestedText'] as String?,
startPosition: json['startPosition'] as int,
endPosition: json['endPosition'] as int,
explanation: json['explanation'] as String,
);
}
Map<String, dynamic> toJson() {
return {
'type': type.name,
'description': description,
'originalText': originalText,
'suggestedText': suggestedText,
'startPosition': startPosition,
'endPosition': endPosition,
'explanation': explanation,
};
}
}
class WritingSuggestion {
final WritingSuggestionType type;
final String title;
final String description;
final String? example;
final int? position;
const WritingSuggestion({
required this.type,
required this.title,
required this.description,
this.example,
this.position,
});
factory WritingSuggestion.fromJson(Map<String, dynamic> json) {
return WritingSuggestion(
type: WritingSuggestionType.values.firstWhere(
(e) => e.name == json['type'],
),
title: json['title'] as String,
description: json['description'] as String,
example: json['example'] as String?,
position: json['position'] as int?,
);
}
Map<String, dynamic> toJson() {
return {
'type': type.name,
'title': title,
'description': description,
'example': example,
'position': position,
};
}
}
enum WritingStatus {
draft,
submitted,
grading,
graded,
revised,
}
enum WritingCriteria {
content,
organization,
vocabulary,
grammar,
mechanics,
}
enum WritingErrorType {
grammar,
spelling,
punctuation,
vocabulary,
structure,
style,
}
enum WritingSuggestionType {
improvement,
enhancement,
alternative,
clarification,
}
extension WritingStatusExtension on WritingStatus {
String get displayName {
switch (this) {
case WritingStatus.draft:
return '草稿';
case WritingStatus.submitted:
return '已提交';
case WritingStatus.grading:
return '评分中';
case WritingStatus.graded:
return '已评分';
case WritingStatus.revised:
return '已修改';
}
}
}
extension WritingCriteriaExtension on WritingCriteria {
String get displayName {
switch (this) {
case WritingCriteria.content:
return '内容';
case WritingCriteria.organization:
return '结构';
case WritingCriteria.vocabulary:
return '词汇';
case WritingCriteria.grammar:
return '语法';
case WritingCriteria.mechanics:
return '拼写标点';
}
}
}
extension WritingErrorTypeExtension on WritingErrorType {
String get displayName {
switch (this) {
case WritingErrorType.grammar:
return '语法错误';
case WritingErrorType.spelling:
return '拼写错误';
case WritingErrorType.punctuation:
return '标点错误';
case WritingErrorType.vocabulary:
return '词汇错误';
case WritingErrorType.structure:
return '结构错误';
case WritingErrorType.style:
return '风格问题';
}
}
}

View File

@@ -0,0 +1,267 @@
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();
}