Files
xianyan/lib/features/article/article_service.dart
Developer f91be94e9c refactor: 完成项目架构重构,统一模块导入路径
- 清理大量废弃的 barrel 导出文件,移除冗余的中间导出层
- 修复所有相对路径导入错误,统一调整为扁平化模块引用
- 更新多平台 pubspec 版本号与依赖库版本
- 补充后端功能问题管理后台与脚本工具
- 调整部分页面的快捷方式文案适配新功能
- 更新部分翻译覆盖率与API文档
2026-06-12 08:53:57 +08:00

198 lines
6.0 KiB
Dart

// ============================================================
// 闲言APP — 文章创作服务
// 创建时间: 2026-04-29
// 更新时间: 2026-04-29
// 作用: 封装文章创作/列表/详情/管理API调用
// 上次更新: 初始创建
// ============================================================
import 'package:dio/dio.dart';
import 'package:xianyan/core/network/api_client.dart';
import 'package:xianyan/core/network/api_exception.dart';
import 'package:xianyan/core/network/api_response.dart';
import 'article_models.dart';
class ArticleService {
ArticleService._();
static final ApiClient _api = ApiClient.instance;
static const String _basePath = '/api/article';
/// 获取文章列表
static Future<List<Article>> getArticleList({
int page = 1,
int limit = 20,
String? category,
String? keyword,
}) async {
try {
final response = await _api.get<Map<String, dynamic>>(
'$_basePath/list',
queryParameters: {
'page': page,
'limit': limit,
if (category != null) 'category': category,
if (keyword != null) 'keyword': keyword,
},
);
final apiResp = ApiResponse<Map<String, dynamic>>.fromJson(
response.data as Map<String, dynamic>,
);
if (!apiResp.isSuccess) {
throw ApiException(code: apiResp.code, message: apiResp.msg);
}
final list = apiResp.data?['list'] as List? ?? [];
return list
.map((e) => Article.fromJson(e as Map<String, dynamic>))
.toList();
} on DioException catch (e) {
throw _handleDioError(e);
}
}
/// 获取文章详情
static Future<Article> getArticleDetail({required int id}) async {
try {
final response = await _api.get<Map<String, dynamic>>(
'$_basePath/detail',
queryParameters: {'id': id},
);
final apiResp = ApiResponse<Map<String, dynamic>>.fromJson(
response.data as Map<String, dynamic>,
);
if (!apiResp.isSuccess) {
throw ApiException(code: apiResp.code, message: apiResp.msg);
}
return Article.fromJson(apiResp.data ?? {});
} on DioException catch (e) {
throw _handleDioError(e);
}
}
/// 提交/编辑文章
static Future<Map<String, dynamic>> submitArticle({
int? id,
required String title,
required String content,
String? summary,
String? category,
List<String>? tags,
}) async {
try {
final response = await _api.post<Map<String, dynamic>>(
'$_basePath/submit',
data: {
if (id != null) 'id': id,
'title': title,
'content': content,
if (summary != null) 'summary': summary,
if (category != null) 'category': category,
if (tags != null) 'tags': tags,
},
);
final respData = response.data as Map<String, dynamic>;
final code = respData['code'] as int? ?? 0;
if (code != 1) {
throw ApiException(
code: code,
message: respData['msg'] as String? ?? '提交失败',
);
}
return respData['data'] as Map<String, dynamic>? ?? {};
} on DioException catch (e) {
throw _handleDioError(e);
}
}
/// 获取我的文章
static Future<List<Article>> getMyArticles({
int page = 1,
int limit = 20,
}) async {
try {
final response = await _api.get<Map<String, dynamic>>(
'$_basePath/mine',
queryParameters: {'page': page, 'limit': limit},
);
final apiResp = ApiResponse<Map<String, dynamic>>.fromJson(
response.data as Map<String, dynamic>,
);
if (!apiResp.isSuccess) {
throw ApiException(code: apiResp.code, message: apiResp.msg);
}
final list = apiResp.data?['list'] as List? ?? [];
return list
.map((e) => Article.fromJson(e as Map<String, dynamic>))
.toList();
} on DioException catch (e) {
throw _handleDioError(e);
}
}
/// 删除文章
static Future<bool> deleteArticle({required int id}) async {
try {
final response = await _api.post<Map<String, dynamic>>(
'$_basePath/delete',
data: {'id': id},
);
final respData = response.data as Map<String, dynamic>;
final code = respData['code'] as int? ?? 0;
return code == 1;
} on DioException catch (e) {
throw _handleDioError(e);
}
}
/// 获取文章评论
static Future<List<ArticleComment>> getArticleComments({
required int articleId,
int page = 1,
int limit = 20,
}) async {
try {
final response = await _api.get<Map<String, dynamic>>(
'$_basePath/comments',
queryParameters: {
'article_id': articleId,
'page': page,
'limit': limit,
},
);
final apiResp = ApiResponse<Map<String, dynamic>>.fromJson(
response.data as Map<String, dynamic>,
);
if (!apiResp.isSuccess) {
throw ApiException(code: apiResp.code, message: apiResp.msg);
}
final list = apiResp.data?['list'] as List? ?? [];
return list
.map((e) => ArticleComment.fromJson(e as Map<String, dynamic>))
.toList();
} on DioException catch (e) {
throw _handleDioError(e);
}
}
static ApiException _handleDioError(DioException e) {
switch (e.type) {
case DioExceptionType.connectionTimeout:
case DioExceptionType.sendTimeout:
case DioExceptionType.receiveTimeout:
return const ApiException(code: -1, message: '连接超时,请检查网络');
case DioExceptionType.connectionError:
return const ApiException(code: -2, message: '网络连接失败');
default:
if (e.response?.data != null) {
try {
final data = e.response!.data as Map<String, dynamic>;
return ApiException(
code: data['code'] as int? ?? e.response?.statusCode ?? -5,
message: data['msg'] as String? ?? '请求失败',
);
} catch (_) {}
}
return const ApiException(code: -5, message: '未知网络错误');
}
}
}