feat: 完成班级模块全量功能迭代
本次提交完成了班级模块的多项核心功能开发与优化: 1. 新增DELETE请求封装,支持业务删除接口且不自动重试 2. 完善UserPostCommonDto模型,新增头像字段适配详情接口 3. 重构路由架构,使用StatefulShellRoute实现Tab页面保活 4. 新增我的互动页面,包含我的动态/点赞/留言三个子页 5. 新增全部同学页面,展示班级全员信息与在线状态 6. 新增动态详情页面,支持查看完整评论与点赞头像 7. 抽离通用PostListBody组件,复用列表分页与交互逻辑 8. 优化班级列表页加载逻辑与图片预览交互 9. 新增评论删除、多图预览等细节交互功能
This commit is contained in:
@@ -2,6 +2,8 @@ import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:new_learn/core/components/image_preview_viewer.dart';
|
||||
import 'package:new_learn/core/components/user_circle_avatar.dart';
|
||||
import 'package:new_learn/core/models/user_model.dart';
|
||||
import 'package:new_learn/core/providers/user_provider.dart';
|
||||
@@ -121,7 +123,10 @@ class _ClassUpdateViewState extends ConsumerState<ClassUpdateView> {
|
||||
..addAll(res.data);
|
||||
_pageIndex = 1;
|
||||
_prevPageId = res.data.isNotEmpty ? res.data.last.id : 0;
|
||||
_hasMore = res.data.length >= _pageSize;
|
||||
// 优先用总条数判断是否还有更多;total 不可用时退回"本页满页才继续"
|
||||
_hasMore = res.total > 0
|
||||
? res.data.length < res.total
|
||||
: res.data.length >= _pageSize;
|
||||
_loading = false;
|
||||
});
|
||||
} catch (_) {
|
||||
@@ -147,7 +152,10 @@ class _ClassUpdateViewState extends ConsumerState<ClassUpdateView> {
|
||||
_posts.addAll(res.data);
|
||||
_pageIndex += 1;
|
||||
if (res.data.isNotEmpty) _prevPageId = res.data.last.id;
|
||||
_hasMore = res.data.length >= _pageSize;
|
||||
// 累计长度 vs 总条数,即使每页都返回满页也能在到底后正确收尾
|
||||
_hasMore = res.total > 0
|
||||
? _posts.length < res.total
|
||||
: res.data.length >= _pageSize;
|
||||
_loadingMore = false;
|
||||
});
|
||||
} catch (_) {
|
||||
@@ -258,24 +266,43 @@ class _ClassUpdateViewState extends ConsumerState<ClassUpdateView> {
|
||||
controller: _scrollController,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding: EdgeInsets.symmetric(horizontal: 14.w),
|
||||
itemCount: _posts.length + (_hasMore ? 1 : 0),
|
||||
itemCount: _posts.length + 1,
|
||||
itemBuilder: (context, index) {
|
||||
if (index >= _posts.length) {
|
||||
// 底部占位:加载中显示菊花,没有更多则显示提示文案
|
||||
if (_hasMore) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 16.h),
|
||||
child: const Center(
|
||||
child: SizedBox(
|
||||
width: 22,
|
||||
height: 22,
|
||||
child: CircularProgressIndicator(strokeWidth: 2.5),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 16.h),
|
||||
child: const Center(
|
||||
child: SizedBox(
|
||||
width: 22,
|
||||
height: 22,
|
||||
child: CircularProgressIndicator(strokeWidth: 2.5),
|
||||
padding: EdgeInsets.symmetric(vertical: 20.h),
|
||||
child: Center(
|
||||
child: Text(
|
||||
'没有更多了',
|
||||
style: TextStyle(
|
||||
fontSize: 12.sp,
|
||||
color: const Color(0xFFB4C2E0),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return PostCard(
|
||||
post: _posts[index],
|
||||
onLike: () => _toggleLike(index),
|
||||
onComment: (content) => _submitComment(index, content),
|
||||
final post = _posts[index];
|
||||
return GestureDetector(
|
||||
onTap: () => context.push('/class/my-update-detail', extra: post),
|
||||
child: PostCard(
|
||||
post: post,
|
||||
onLike: () => _toggleLike(index),
|
||||
onComment: (content) => _submitComment(index, content),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -357,39 +384,49 @@ class _ClassUpdateViewState extends ConsumerState<ClassUpdateView> {
|
||||
for (int i = 0; i < urls.length; i++)
|
||||
Positioned(
|
||||
left: i * overlap,
|
||||
child: UserCircleAvatar(url: urls[i], radius: size / 2),
|
||||
child: GestureDetector(
|
||||
// 点头像 → 大图预览单张
|
||||
onTap: () => ImagePreviewViewer.showSingle(
|
||||
context,
|
||||
imageProvider: CachedNetworkImageProvider(urls[i]),
|
||||
),
|
||||
child: UserCircleAvatar(url: urls[i], radius: size / 2),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 右侧「全部」按钮
|
||||
/// 右侧「全部」按钮 → 全部同学页
|
||||
Widget _buildAllButton() {
|
||||
return Container(
|
||||
width: 62.w,
|
||||
height: 34.h,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [Color(0xFF3D7DF5), Color(0xFF3C84FF), Color(0xFF8AD1FD)],
|
||||
return GestureDetector(
|
||||
onTap: () => context.push('/class/all-student'),
|
||||
child: Container(
|
||||
width: 62.w,
|
||||
height: 34.h,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [Color(0xFF3D7DF5), Color(0xFF3C84FF), Color(0xFF8AD1FD)],
|
||||
),
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(15.r),
|
||||
bottomLeft: Radius.circular(15.r),
|
||||
bottomRight: Radius.circular(20.r),
|
||||
),
|
||||
),
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(15.r),
|
||||
bottomLeft: Radius.circular(15.r),
|
||||
bottomRight: Radius.circular(20.r),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('全部', style: TextStyle(fontSize: 14, color: Colors.white)),
|
||||
SizedBox(width: 2.w),
|
||||
Icon(Icons.chevron_right, size: 14, color: Colors.white),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('全部', style: TextStyle(fontSize: 14, color: Colors.white)),
|
||||
SizedBox(width: 2.w),
|
||||
Icon(Icons.chevron_right, size: 14, color: Colors.white),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user