feat: 完成班级模块全量功能迭代
本次提交完成了班级模块的多项核心功能开发与优化: 1. 新增DELETE请求封装,支持业务删除接口且不自动重试 2. 完善UserPostCommonDto模型,新增头像字段适配详情接口 3. 重构路由架构,使用StatefulShellRoute实现Tab页面保活 4. 新增我的互动页面,包含我的动态/点赞/留言三个子页 5. 新增全部同学页面,展示班级全员信息与在线状态 6. 新增动态详情页面,支持查看完整评论与点赞头像 7. 抽离通用PostListBody组件,复用列表分页与交互逻辑 8. 优化班级列表页加载逻辑与图片预览交互 9. 新增评论删除、多图预览等细节交互功能
This commit is contained in:
@@ -74,6 +74,89 @@ class ClassApi {
|
||||
'content': content,
|
||||
});
|
||||
}
|
||||
|
||||
/// 我的点赞列表 —— GET /api/v1/UserLike/GetUserLike(游标分页)
|
||||
///
|
||||
/// 后端每项包一层 {userPost: {...}},这里统一解包成 UserPostDto,
|
||||
/// 页面拿到的是与班级动态一致的结构,直接复用 PostCard。
|
||||
Future<UserPostResponse> getMyLikePage({
|
||||
int pageIndex = 1,
|
||||
int pageSize = 10,
|
||||
int prevPageId = 0,
|
||||
}) async {
|
||||
final data = await DioClient.instance.get(
|
||||
'/api/v1/UserLike/GetUserLike',
|
||||
query: {
|
||||
'pageIndex': pageIndex,
|
||||
'pageSize': pageSize,
|
||||
'prevPageId': prevPageId,
|
||||
},
|
||||
);
|
||||
return _unwrapUserPostResponse(data);
|
||||
}
|
||||
|
||||
/// 我的留言列表 —— GET /api/v1/UserPost/GetUserCommon(游标分页)
|
||||
Future<UserPostResponse> getMyCommentPage({
|
||||
int pageIndex = 1,
|
||||
int pageSize = 10,
|
||||
int prevPageId = 0,
|
||||
}) async {
|
||||
final data = await DioClient.instance.get(
|
||||
'/api/v1/UserPost/GetUserCommon',
|
||||
query: {
|
||||
'pageIndex': pageIndex,
|
||||
'pageSize': pageSize,
|
||||
'prevPageId': prevPageId,
|
||||
},
|
||||
);
|
||||
return _unwrapUserPostResponse(data);
|
||||
}
|
||||
|
||||
/// 动态详情(含全量留言 / 点赞头像)—— GET /api/v1/UserPost/GetUserPostDetail/{id}
|
||||
Future<UserPostDto> getUserPostDetail(int id) async {
|
||||
final data = await DioClient.instance.get(
|
||||
'/api/v1/UserPost/GetUserPostDetail/$id',
|
||||
);
|
||||
return UserPostDto.fromJson(data as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
/// 删除评论 —— DELETE /api/v1/UserPost/DeleteUserCommon/{id}
|
||||
Future<void> deleteUserCommon(int commentId) async {
|
||||
await DioClient.instance.delete(
|
||||
'/api/v1/UserPost/DeleteUserCommon/$commentId',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 解包「我的点赞/留言」列表:每项若包了 userPost 则取内层,再统一转 UserPostDto
|
||||
UserPostResponse _unwrapUserPostResponse(dynamic data) {
|
||||
final raw = data is Map<String, dynamic> ? data : {'data': data};
|
||||
final payload = raw['data'] is Map<String, dynamic>
|
||||
? raw['data'] as Map<String, dynamic>
|
||||
: raw;
|
||||
final list = payload['data'];
|
||||
final posts = <UserPostDto>[];
|
||||
if (list is List) {
|
||||
for (final e in list) {
|
||||
if (e is! Map<String, dynamic>) continue;
|
||||
final inner = e['userPost'] is Map<String, dynamic>
|
||||
? e['userPost'] as Map<String, dynamic>
|
||||
: e;
|
||||
posts.add(UserPostDto.fromJson(inner));
|
||||
}
|
||||
}
|
||||
return UserPostResponse(
|
||||
data: posts,
|
||||
total: _toInt(payload['total']),
|
||||
pageIndex: _toInt(payload['pageIndex']),
|
||||
pageSize: _toInt(payload['pageSize']),
|
||||
);
|
||||
}
|
||||
|
||||
int _toInt(dynamic v) {
|
||||
if (v is num) return v.toInt();
|
||||
if (v is String) return int.tryParse(v) ?? 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// 积分排行榜接口
|
||||
|
||||
@@ -21,6 +21,7 @@ class UserPostCommonDto {
|
||||
this.content = '',
|
||||
this.createTime = '',
|
||||
this.id = 0,
|
||||
this.avatar = '',
|
||||
});
|
||||
|
||||
final int userId;
|
||||
@@ -28,6 +29,7 @@ class UserPostCommonDto {
|
||||
final String content;
|
||||
final String createTime;
|
||||
final int id;
|
||||
final String avatar;
|
||||
|
||||
factory UserPostCommonDto.fromJson(Map<String, dynamic> json) =>
|
||||
UserPostCommonDto(
|
||||
@@ -36,6 +38,8 @@ class UserPostCommonDto {
|
||||
content: json['content'] as String? ?? '',
|
||||
createTime: json['createTime'] as String? ?? '',
|
||||
id: _toInt(json['id']),
|
||||
// 详情接口的留言项带评论者头像
|
||||
avatar: json['avatar'] as String? ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -248,13 +252,16 @@ class UserRankPagedList {
|
||||
final ranksList = payload['userRanks'] is List
|
||||
? payload['userRanks'] as List<dynamic>
|
||||
: (payload['data'] is List
|
||||
? payload['data'] as List<dynamic>
|
||||
: const []);
|
||||
? payload['data'] as List<dynamic>
|
||||
: const []);
|
||||
return UserRankPagedList(
|
||||
myRank: payload['myRank'] is Map<String, dynamic>
|
||||
? UserRank.fromJson(payload['myRank'] as Map<String, dynamic>)
|
||||
: null,
|
||||
userRanks: ranksList.whereType<Map<String, dynamic>>().map(UserRank.fromJson).toList(),
|
||||
userRanks: ranksList
|
||||
.whereType<Map<String, dynamic>>()
|
||||
.map(UserRank.fromJson)
|
||||
.toList(),
|
||||
total: _toInt(payload['total']),
|
||||
pageIndex: _toInt(payload['pageIndex']),
|
||||
pageSize: _toInt(payload['pageSize']),
|
||||
@@ -304,4 +311,4 @@ int? _toIntOrNull(dynamic v) {
|
||||
if (v is num) return v.toInt();
|
||||
if (v is String) return int.tryParse(v);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user