feat: 完成班级模块全量功能迭代

本次提交完成了班级模块的多项核心功能开发与优化:
1. 新增DELETE请求封装,支持业务删除接口且不自动重试
2. 完善UserPostCommonDto模型,新增头像字段适配详情接口
3. 重构路由架构,使用StatefulShellRoute实现Tab页面保活
4. 新增我的互动页面,包含我的动态/点赞/留言三个子页
5. 新增全部同学页面,展示班级全员信息与在线状态
6. 新增动态详情页面,支持查看完整评论与点赞头像
7. 抽离通用PostListBody组件,复用列表分页与交互逻辑
8. 优化班级列表页加载逻辑与图片预览交互
9. 新增评论删除、多图预览等细节交互功能
This commit is contained in:
崔宝新
2026-09-07 09:20:06 +08:00
parent 0c5aee59c0
commit 586c75f841
11 changed files with 1331 additions and 87 deletions
@@ -2,6 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:new_learn/core/api/class/model.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/utils/img_url.dart';
@@ -23,12 +24,16 @@ class PostCard extends StatelessWidget {
required this.post,
required this.onLike,
required this.onComment,
this.showCommentComposer = true,
});
final UserPostDto post;
final VoidCallback onLike;
final ValueChanged<String> onComment;
/// 是否显示卡片内嵌的评论预览 + 输入框(列表页 true;详情页由全量留言接管)
final bool showCommentComposer;
String get _avatar {
final url = ImgUrl.build(post.avatar);
return url.isEmpty
@@ -106,6 +111,7 @@ class PostCard extends StatelessWidget {
post: post,
onLike: onLike,
onComment: onComment,
showComposer: showCommentComposer,
),
],
),
@@ -295,11 +301,26 @@ class AlbumGrid extends StatelessWidget {
runSpacing: 9.h,
children: [
for (int i = 0; i < displayed.length; i++)
_gridItem(displayed[i], i, urls.length),
GestureDetector(
onTap: () => _preview(context, urls, i),
child: _gridItem(displayed[i], i, urls.length),
),
],
);
}
/// 点击相册图:进入整组大图预览,定位到点中的那张
void _preview(BuildContext context, List<String> allUrls, int index) {
ImagePreviewViewer.show(
context,
items: [
for (final u in allUrls)
PreviewImageItem(imageProvider: CachedNetworkImageProvider(u)),
],
initialIndex: index,
);
}
Widget _gridItem(String url, int index, int total) {
final more = total > 9 && index == 8 ? total - 9 : 0;
return ClipRRect(
@@ -344,12 +365,16 @@ class LikeCommentBar extends StatelessWidget {
required this.post,
required this.onLike,
required this.onComment,
this.showComposer = true,
});
final UserPostDto post;
final VoidCallback onLike;
final ValueChanged<String> onComment;
/// 是否显示评论预览 + 输入框(列表页 true;详情页 false,由全量留言列表接管)
final bool showComposer;
@override
Widget build(BuildContext context) {
return Column(
@@ -370,12 +395,14 @@ class LikeCommentBar extends StatelessWidget {
MetaButton(icon: Icons.chat_bubble_outline, count: post.replyCount),
],
),
if (post.commons.isNotEmpty) ...[
if (showComposer) ...[
if (post.commons.isNotEmpty) ...[
SizedBox(height: 12.h),
CommentPreview(post: post),
],
SizedBox(height: 12.h),
CommentPreview(post: post),
CommentInput(onSubmit: onComment),
],
SizedBox(height: 12.h),
CommentInput(onSubmit: onComment),
],
);
}
@@ -517,20 +544,25 @@ class _CommentInputState extends State<CommentInput> {
@override
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: Container(
height: 30.h,
padding: EdgeInsets.symmetric(horizontal: 12.w),
alignment: Alignment.centerLeft,
constraints: BoxConstraints(minHeight: 30.h),
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 5.h),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: const Color(0xFFE3ECFF)),
borderRadius: BorderRadius.circular(10.r),
),
// multiline:键盘右下角为「换行」,可换行写多条评论
child: TextField(
controller: _controller,
style: const TextStyle(fontSize: 12, color: Color(0xFF1D2B47)),
keyboardType: TextInputType.multiline,
textInputAction: TextInputAction.newline,
minLines: 1,
maxLines: 4,
decoration: const InputDecoration(
isDense: true,
border: InputBorder.none,