Files
ai_english/client/lib/features/reading/services/reading_service.dart

280 lines
7.9 KiB
Dart
Raw Normal View History

2025-11-17 13:39:05 +08:00
import 'package:dio/dio.dart';
import '../../../core/network/api_client.dart';
import '../../../core/network/api_endpoints.dart';
import '../../../core/services/enhanced_api_service.dart';
import '../../../core/models/api_response.dart';
import '../models/reading_article.dart';
import '../models/reading_question.dart';
import '../models/reading_stats.dart';
/// 阅读服务类
class ReadingService {
final ApiClient _apiClient = ApiClient.instance;
final EnhancedApiService _enhancedApiService = EnhancedApiService();
// 缓存时长配置
static const Duration _shortCacheDuration = Duration(minutes: 5);
static const Duration _longCacheDuration = Duration(hours: 1);
/// 获取文章列表
Future<List<ReadingArticle>> getArticles({
String? category,
String? difficulty,
int page = 1,
int limit = 20,
}) async {
try {
final response = await _enhancedApiService.get<List<ReadingArticle>>(
ApiEndpoints.readingMaterials,
queryParameters: {
if (category != null) 'category': category,
if (difficulty != null) 'level': difficulty,
'page': page,
'limit': limit,
},
cacheDuration: _shortCacheDuration,
fromJson: (data) {
final List<dynamic> list = data['data'] ?? [];
return list.map((json) => ReadingArticle.fromJson(json)).toList();
},
);
if (response.success && response.data != null) {
return response.data!;
} else {
throw Exception(response.message);
}
} catch (e) {
throw Exception('获取文章列表失败: $e');
}
}
/// 获取单篇文章详情
Future<ReadingArticle> getArticle(String articleId) async {
try {
final response = await _enhancedApiService.get<ReadingArticle>(
'${ApiEndpoints.readingMaterials}/$articleId',
cacheDuration: _longCacheDuration,
fromJson: (data) => ReadingArticle.fromJson(data['data']),
);
if (response.success && response.data != null) {
return response.data!;
} else {
throw Exception(response.message);
}
} catch (e) {
throw Exception('获取文章详情失败: $e');
}
}
/// 获取文章练习题
Future<ReadingExercise> getArticleExercise(String articleId) async {
try {
final response = await _enhancedApiService.get<ReadingExercise>(
'${ApiEndpoints.reading}/exercises/$articleId',
cacheDuration: _longCacheDuration,
fromJson: (data) => ReadingExercise.fromJson(data['data']),
);
if (response.success && response.data != null) {
return response.data!;
} else {
throw Exception(response.message);
}
} catch (e) {
throw Exception('获取练习题失败: $e');
}
}
/// 提交练习答案
Future<ReadingExercise> submitExercise(ReadingExercise exercise) async {
try {
final response = await _apiClient.post(
'${ApiEndpoints.reading}/exercises/${exercise.id}/submit',
data: exercise.toJson(),
);
if (response.statusCode == 200) {
return ReadingExercise.fromJson(response.data['data']);
} else {
throw Exception('Failed to submit exercise');
}
} catch (e) {
throw Exception('Error submitting exercise: $e');
}
}
/// 记录阅读进度
Future<void> recordReadingProgress({
required String articleId,
required int readingTime,
required bool completed,
double? comprehensionScore,
}) async {
try {
final response = await _apiClient.post(
'${ApiEndpoints.readingRecords}',
data: {
'article_id': articleId,
'reading_time': readingTime,
'completed': completed,
if (comprehensionScore != null) 'comprehension_score': comprehensionScore,
},
);
if (response.statusCode != 200) {
throw Exception('Failed to record progress');
}
} catch (e) {
throw Exception('Error recording progress: $e');
}
}
/// 获取阅读统计
Future<ReadingStats> getReadingStats() async {
try {
final response = await _apiClient.get(
ApiEndpoints.readingStats,
);
if (response.statusCode == 200) {
return ReadingStats.fromJson(response.data['data']);
} else {
throw Exception('Failed to load reading stats');
}
} catch (e) {
throw Exception('Error fetching reading stats: $e');
}
}
/// 获取推荐文章
Future<List<ReadingArticle>> getRecommendedArticles({int limit = 10}) async {
try {
final response = await _apiClient.get(
'${ApiEndpoints.reading}/recommendations',
queryParameters: {'limit': limit},
);
if (response.statusCode == 200) {
final List<dynamic> data = response.data['data'];
return data.map((json) => ReadingArticle.fromJson(json)).toList();
} else {
throw Exception('Failed to load recommended articles');
}
} catch (e) {
throw Exception('Error fetching recommended articles: $e');
}
}
/// 搜索文章
Future<List<ReadingArticle>> searchArticles({
required String query,
String? category,
String? difficulty,
int page = 1,
int limit = 20,
}) async {
try {
final response = await _apiClient.get(
'${ApiEndpoints.readingMaterials}/search',
queryParameters: {
'q': query,
if (category != null) 'category': category,
if (difficulty != null) 'difficulty': difficulty,
'page': page,
'limit': limit,
},
);
if (response.statusCode == 200) {
final List<dynamic> data = response.data['data'];
return data.map((json) => ReadingArticle.fromJson(json)).toList();
} else {
throw Exception('Failed to search articles');
}
} catch (e) {
throw Exception('Error searching articles: $e');
}
}
/// 收藏文章
Future<void> favoriteArticle(String articleId) async {
try {
final response = await _apiClient.post(
'${ApiEndpoints.readingMaterials}/$articleId/favorite',
);
if (response.statusCode != 200) {
throw Exception('Failed to favorite article');
}
} catch (e) {
throw Exception('Error favoriting article: $e');
}
}
/// 取消收藏文章
Future<void> unfavoriteArticle(String articleId) async {
try {
final response = await _apiClient.delete(
'${ApiEndpoints.readingMaterials}/$articleId/favorite',
);
if (response.statusCode != 200) {
throw Exception('Failed to unfavorite article');
}
} catch (e) {
throw Exception('Error unfavoriting article: $e');
}
}
/// 获取收藏文章
Future<List<ReadingArticle>> getFavoriteArticles({
int page = 1,
int limit = 20,
}) async {
try {
final response = await _apiClient.get(
'${ApiEndpoints.readingMaterials}/favorites',
queryParameters: {
'page': page,
'limit': limit,
},
);
if (response.statusCode == 200) {
final List<dynamic> data = response.data['data'];
return data.map((json) => ReadingArticle.fromJson(json)).toList();
} else {
throw Exception('Failed to load favorite articles');
}
} catch (e) {
throw Exception('Error fetching favorite articles: $e');
}
}
/// 获取阅读历史
Future<List<ReadingArticle>> getReadingHistory({
int page = 1,
int limit = 20,
}) async {
try {
final response = await _apiClient.get(
'${ApiEndpoints.readingRecords}',
queryParameters: {
'page': page,
'limit': limit,
},
);
if (response.statusCode == 200) {
final List<dynamic> data = response.data['data'];
return data.map((json) => ReadingArticle.fromJson(json)).toList();
} else {
throw Exception('Failed to load reading history');
}
} catch (e) {
throw Exception('Error fetching reading history: $e');
}
}
}