refactor(class): 抽离攻克任务组件并优化样式与资源

1.  将ResolveProblemBox从class_update_widgets.dart抽离到公共组件目录
2.  替换静态渐变背景为CDN资源背景图,适配平板和手机端
3.  将点赞评论按钮的图标从内置Icons替换为本地png资源
4.  更新pubspec.yaml添加新的图片资源路径
5.  删除冗余的空行配置
This commit is contained in:
崔宝新
2026-09-07 17:01:48 +08:00
parent d5f73cfbb5
commit ebde2ae977
6 changed files with 139 additions and 68 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 901 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 B

@@ -0,0 +1,117 @@
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/utils/img_url.dart';
import 'package:new_learn/core/utils/screen_adapt_template.dart';
/// ============================================================
/// 【ResolveProblemBox】攻克任务卡(对标 Vue ResolveProblem.vue)
///
/// 用于展示"刚刚攻克了 「xxx」 的所有高难考点"类提示。
/// 由 class_update_widgets.dart 抽离,详情页也可复用。
/// 背景图 + 云朵装饰走 CDN,与 Vue 版 $img('/StaticResource/...') 同源。
/// ============================================================
class ResolveProblemBox extends StatelessWidget {
const ResolveProblemBox({
super.key,
this.title = '刚刚攻克了',
required this.desc,
});
/// 标题(默认 "刚刚攻克了")
final String title;
/// 攻克的知识点描述(如 "二次函数最值问题")
final String desc;
@override
Widget build(BuildContext context) {
final isPad = MediaQuery.sizeOf(context).width >= AppAdapt.tabletBreakpoint;
final bgUrl = ImgUrl.build(
isPad
? '/StaticResource/2026-06-02/resolve-bg2-pad1780388446390.png'
: '/StaticResource/2026-05-07/resolve-bg2.png',
);
final cloudUrl = ImgUrl.build(
isPad
? '/StaticResource/2026-06-02/cloud-pad1780388443051.png'
: '/StaticResource/2026-05-07/cloud.png',
);
final cloudHeight = isPad ? 107.h : 74.h;
return Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.r),
image: DecorationImage(
image: CachedNetworkImageProvider(bgUrl),
fit: BoxFit.fill,
alignment: Alignment.topCenter,
),
),
// 裁剪所有子元素到圆角内(对标 Vue overflow:hidden)
clipBehavior: Clip.antiAlias,
child: Stack(
// Stack 默认不裁剪 Positioned 子元素,必须显式设置
clipBehavior: Clip.hardEdge,
children: [
// 底部云朵装饰(贴底部,z-index 1)
Positioned(
left: 0,
right: 0,
bottom: 0,
child: CachedNetworkImage(
imageUrl: cloudUrl,
height: cloudHeight,
width: double.infinity,
fit: BoxFit.fitWidth,
),
),
// 文本层(padding 在云朵之上,z-index 2)
Padding(
padding: EdgeInsets.fromLTRB(19.w, 25.h, 19.w, 11.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
title,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w900,
color: Color(0xFF1D2B47),
),
),
SizedBox(height: 3.h),
Text.rich(
TextSpan(
children: [
TextSpan(
text: '「$desc」',
style: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: Color(0xFF1D2B47),
),
),
const TextSpan(
text: ' 的所有高难考点!',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: Color(0xFF45597E),
),
),
],
),
),
],
),
),
],
),
);
}
}
@@ -5,6 +5,7 @@ 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/resolve_problem_box.dart';
import 'package:new_learn/core/components/user_circle_avatar.dart';
import 'package:new_learn/core/utils/img_url.dart';
@@ -12,7 +13,8 @@ import 'package:new_learn/core/utils/img_url.dart';
/// 【班级动态组件】由 class_update_view.dart 抽离的展示组件
///
/// PostCard(动态卡片,按 type 分发内容 + 相册 + 点赞评论栏)
/// CardHeader / SubjectTag / ResolveProblemBox / AlbumDesc / AlbumGrid
/// CardHeader / SubjectTag / AlbumDesc / AlbumGrid / LikeCommentBar / ...
/// ResolveProblemBox 已抽离到 core/components/resolve_problem_box.dart
/// LikeCommentBar / MetaButton / CommentPreview / CommentInput
///
/// 原为 class_update_view.dart 内的私有组件,重命名去下划线后放到本文件。
@@ -263,65 +265,6 @@ class SubjectTag extends StatelessWidget {
}
}
/// 攻克任务卡(对标 ResolveProblem)
class ResolveProblemBox extends StatelessWidget {
const ResolveProblemBox({super.key, required this.desc});
final String desc;
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: EdgeInsets.fromLTRB(19.w, 25.h, 19.w, 11.h),
decoration: BoxDecoration(
gradient: const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Color(0xFFEAF4FF), Color(0xFFFFFFFF)],
),
borderRadius: BorderRadius.circular(10.r),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'刚刚攻克了',
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w900,
color: Color(0xFF1D2B47),
),
),
SizedBox(height: 3.h),
Text.rich(
TextSpan(
children: [
TextSpan(
text: '「$desc」',
style: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: Color(0xFF1D2B47),
),
),
const TextSpan(
text: ' 的所有高难考点!',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: Color(0xFF45597E),
),
),
],
),
),
],
),
);
}
}
/// 纯文字笔记(album-desc,最多 2 行)
class AlbumDesc extends StatelessWidget {
const AlbumDesc({super.key, required this.text});
@@ -441,15 +384,26 @@ class LikeCommentBar extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.end,
children: [
MetaButton(
icon: post.userLikeStatus
? Icons.favorite
: Icons.favorite_border,
icon: Image.asset(
post.userLikeStatus
? 'assets/img/class/like-check-icon.png'
: 'assets/img/class/like-icon.png',
width: 13.w,
height: 13.w,
),
count: post.likeCount,
active: post.userLikeStatus,
onTap: onLike,
),
SizedBox(width: 8.w),
MetaButton(icon: Icons.chat_bubble_outline, count: post.replyCount),
MetaButton(
icon: Image.asset(
'assets/img/class/comment-icon.png',
width: 13.w,
height: 13.w,
),
count: post.replyCount,
),
],
),
if (showComposer) ...[
@@ -474,7 +428,7 @@ class MetaButton extends StatelessWidget {
this.onTap,
});
final IconData icon;
final Widget icon;
final int count;
final bool active;
final VoidCallback? onTap;
@@ -496,7 +450,7 @@ class MetaButton extends StatelessWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(icon, size: 13.w, color: color),
icon,
SizedBox(width: 4.w),
Text('$count', style: TextStyle(fontSize: 13, color: color)),
],
+2 -2
View File
@@ -2,7 +2,7 @@ name: new_learn
description: "A new Flutter project."
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
publish_to: "none" # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
@@ -222,7 +222,6 @@ dev_dependencies:
# The following section is specific to Flutter packages.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
@@ -236,6 +235,7 @@ flutter:
- assets/img/tabbar/
- assets/img/tabbar/default/
- assets/audio/
- assets/img/class/
# To add assets to your application, add an assets section, like this:
# assets: