Files
video/app/lib/services/user_service.dart
2026-10-15 20:36:59 +08:00

120 lines
3.5 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:dio/dio.dart';
import '../core/network/api_client.dart';
import '../core/network/endpoints.dart';
import '../models/user_model.dart';
import '../models/user_profile.dart';
import '../models/video_item.dart';
/// 用户服务(《03-接口文档》第 4 章 + 6.6/6.7)
class UserService {
UserService._();
/// 4.1 获取个人信息
static Future<UserModel> fetchMe() async {
final data = await ApiClient.get<Map<String, dynamic>>(Endpoints.me);
return UserModel.fromJson(data);
}
/// 4.2 修改资料(返回更新后的完整用户对象)
static Future<UserModel> updateMe({
String? nickname,
String? bio,
int? gender,
}) async {
final data = await ApiClient.put<Map<String, dynamic>>(
Endpoints.me,
data: {
if (nickname != null) 'nickname': nickname,
if (bio != null) 'bio': bio,
if (gender != null) 'gender': gender,
},
);
return UserModel.fromJson(data);
}
/// 4.3 上传头像(multipart,字段名 file;仅支持 jpg/png,≤5MB)
static Future<String> uploadAvatar({
required String filePath,
required String fileName,
}) async {
final data = await ApiClient.post<Map<String, dynamic>>(
Endpoints.meAvatar,
data: FormData.fromMap({
'file': await MultipartFile.fromFile(filePath, filename: fileName),
}),
);
return (data['avatar_url'] as String?) ?? '';
}
/// 4.7 用户公开主页(游客可)
static Future<UserPublicProfile> fetchPublicProfile(int userId) async {
final data =
await ApiClient.get<Map<String, dynamic>>(Endpoints.userDetail(userId));
return UserPublicProfile.fromJson(data);
}
/// 4.8 他人作品列表(仅已发布)
static Future<PagedVideos> fetchUserVideos(
int userId, {
int page = 1,
int pageSize = 50,
}) =>
_fetchVideos(Endpoints.userVideos(userId), page: page, pageSize: pageSize);
/// 我的作品(需登录,含各状态)
static Future<PagedVideos> fetchMyVideos({
int page = 1,
int pageSize = 50,
}) =>
_fetchVideos(Endpoints.meVideos, page: page, pageSize: pageSize);
/// 6.6 我的收藏(需登录)
static Future<PagedVideos> fetchMyFavorites({
int page = 1,
int pageSize = 50,
}) =>
_fetchVideos(Endpoints.meFavorites, page: page, pageSize: pageSize);
/// 6.7 观看历史(需登录):video + watched_at + cost_type
static Future<List<HistoryItem>> fetchMyHistory({
int page = 1,
int pageSize = 50,
}) async {
final data = await ApiClient.get<Map<String, dynamic>>(
Endpoints.meHistory,
queryParameters: {'page': page, 'page_size': pageSize},
);
return ((data['list'] as List?) ?? const [])
.whereType<Map<String, dynamic>>()
.map(HistoryItem.fromJson)
.toList();
}
static Future<PagedVideos> _fetchVideos(
String path, {
required int page,
required int pageSize,
}) async {
final data = await ApiClient.get<Map<String, dynamic>>(
path,
queryParameters: {'page': page, 'page_size': pageSize},
);
return PagedVideos(
total: (data['total'] as num?)?.toInt() ?? 0,
items: ((data['list'] as List?) ?? const [])
.whereType<Map<String, dynamic>>()
.map(VideoItem.fromJson)
.toList(),
);
}
}
/// 视频分页结果(普通 page/page_size 分页)
class PagedVideos {
PagedVideos({required this.total, required this.items});
final int total;
final List<VideoItem> items;
}