Files
ai_english/client/lib/features/writing/models/writing_stats.dart
2025-11-17 13:39:05 +08:00

238 lines
7.7 KiB
Dart

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;
}