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
+180
View File
@@ -0,0 +1,180 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:go_router/go_router.dart';
import 'package:new_learn/core/api/class/api.dart';
import 'package:new_learn/core/api/class/model.dart';
import 'package:new_learn/features/class/widgets/post_list_body.dart';
/// ============================================================
/// 【MyInteractPage】「我的互动」页 —— 对标 Vue pages/classPackage/myInteract/myInteract.vue
///
/// 一、入口:从「我的」页等进入。
/// 二、结构:NavBar("我的互动") + 3 颗胶囊 tab + 内容区
/// 「我的动态 / 我的点赞 / 我的留言」
/// 三、子列表用通用 PostListBody:
/// 动态 getUserClassPost(queryType=0);点赞 getMyLikePage;留言 getMyCommentPage。
/// 点赞页取消点赞时从列表移除该项(removeOnUnlike);其余保留。
/// 四、懒加载:默认建第一个 tab,切到再建(对标 renderedTabs)。
/// ============================================================
class MyInteractPage extends StatefulWidget {
const MyInteractPage({super.key});
@override
State<MyInteractPage> createState() => _MyInteractPageState();
}
class _MyInteractPageState extends State<MyInteractPage> {
static const List<String> _tabs = ['我的动态', '我的点赞', '我的留言'];
int _currentTab = 0;
final List<bool> _loadedTabs = [true, false, false];
void _switchTab(int index) {
if (_currentTab == index) return;
setState(() {
_loadedTabs[index] = true;
_currentTab = index;
});
}
void _openDetail(UserPostDto post) {
context.push('/class/my-update-detail', extra: post);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF5F8FA),
appBar: AppBar(
backgroundColor: const Color(0xFFF5F8FA),
elevation: 0,
title: const Text(
'我的互动',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w400,
color: Color(0xFF1D2B47),
),
),
centerTitle: true,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Color(0xFF1D2B47)),
onPressed: () =>
context.canPop() ? context.pop() : context.go('/class'),
),
),
body: Column(
children: [
_buildTabs(),
Expanded(
child: IndexedStack(
index: _currentTab,
children: [
if (_loadedTabs[0]) _UpdateTab(onTapPost: _openDetail),
if (_loadedTabs[1]) _LikeTab(onTapPost: _openDetail),
if (_loadedTabs[2]) _CommentTab(onTapPost: _openDetail),
],
),
),
],
),
);
}
Widget _buildTabs() {
return Container(
width: double.infinity,
padding: EdgeInsets.fromLTRB(14.w, 12.h, 14.w, 22.h),
child: Row(
children: [
for (int i = 0; i < _tabs.length; i++) ...[
if (i > 0) SizedBox(width: 12.w),
_buildTabItem(i),
],
],
),
);
}
Widget _buildTabItem(int index) {
final active = _currentTab == index;
return GestureDetector(
onTap: () => _switchTab(index),
child: Container(
width: 84.w,
height: 37.h,
alignment: Alignment.center,
decoration: BoxDecoration(
color: active ? const Color(0xFF3D7DF5) : Colors.white,
borderRadius: BorderRadius.circular(20.r),
),
child: Text(
_tabs[index],
style: TextStyle(
fontSize: 15,
color: active ? Colors.white : const Color(0xFF687FAD),
),
),
),
);
}
}
class _UpdateTab extends StatelessWidget {
const _UpdateTab({required this.onTapPost});
final ValueChanged<UserPostDto> onTapPost;
@override
Widget build(BuildContext context) {
return PostListBody(
fetchPage: ({required pageIndex, required pageSize, required prevPageId}) =>
ClassApi.instance.getUserClassPost(
queryType: 0,
pageIndex: pageIndex,
pageSize: pageSize,
prevPageId: prevPageId,
),
emptyText: '暂无动态',
onTapPost: onTapPost,
);
}
}
class _LikeTab extends StatelessWidget {
const _LikeTab({required this.onTapPost});
final ValueChanged<UserPostDto> onTapPost;
@override
Widget build(BuildContext context) {
return PostListBody(
fetchPage: ({required pageIndex, required pageSize, required prevPageId}) =>
ClassApi.instance.getMyLikePage(
pageIndex: pageIndex,
pageSize: pageSize,
prevPageId: prevPageId,
),
emptyText: '暂无点赞',
removeOnUnlike: true,
onTapPost: onTapPost,
);
}
}
class _CommentTab extends StatelessWidget {
const _CommentTab({required this.onTapPost});
final ValueChanged<UserPostDto> onTapPost;
@override
Widget build(BuildContext context) {
return PostListBody(
fetchPage: ({required pageIndex, required pageSize, required prevPageId}) =>
ClassApi.instance.getMyCommentPage(
pageIndex: pageIndex,
pageSize: pageSize,
prevPageId: prevPageId,
),
emptyText: '暂无留言',
onTapPost: onTapPost,
);
}
}