init
This commit is contained in:
280
client/lib/features/reading/services/reading_service.dart
Normal file
280
client/lib/features/reading/services/reading_service.dart
Normal file
@@ -0,0 +1,280 @@
|
||||
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');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user