feat:更新好友菜谱功能

This commit is contained in:
2026-06-28 19:54:32 +08:00
parent a340ba424e
commit c10e8e5ffb
13 changed files with 67 additions and 29 deletions

View File

@@ -25,10 +25,10 @@ Future<bool> deleteRecipeApi(int id) {
return httpUtil.delete<bool>("/food/recipe/$id");
}
Future<List<Recipe>> queryRecipeByUserApi(int id) {
return httpUtil.get<List<Recipe>>(
Future<List<RecipeSummary>> queryRecipeByUserApi(int id) {
return httpUtil.get<List<RecipeSummary>>(
"/food/recipe/user/$id",
converter: (data) => convertList<Recipe>(data, Recipe.fromJson),
converter: (data) => convertList<RecipeSummary>(data, RecipeSummary.fromJson),
);
}

View File

@@ -176,7 +176,6 @@ class RecipeSummary {
int commentCount;
int userId;
String username;
String avatar;
RecipeSummary({
required this.id,
@@ -186,7 +185,6 @@ class RecipeSummary {
required this.isShare,
required this.userId,
required this.username,
required this.avatar,
required this.recordList,
required this.likeCount,
required this.favouriteCount,

View File

@@ -149,7 +149,6 @@ RecipeSummary _$RecipeSummaryFromJson(Map<String, dynamic> json) =>
isShare: json['isShare'] as bool,
userId: (json['userId'] as num).toInt(),
username: json['username'] as String,
avatar: json['avatar'] as String,
recordList:
(json['recordList'] as List<dynamic>)
.map((e) => FoodRecord.fromJson(e as Map<String, dynamic>))
@@ -172,7 +171,6 @@ Map<String, dynamic> _$RecipeSummaryToJson(RecipeSummary instance) =>
'commentCount': instance.commentCount,
'userId': instance.userId,
'username': instance.username,
'avatar': instance.avatar,
};
RecipeDetail _$RecipeDetailFromJson(Map<String, dynamic> json) => RecipeDetail(

View File

@@ -116,6 +116,26 @@ class FoodProvider with ChangeNotifier {
}
}
Future<void> queryRecipeByUserId(int userId) async {
if (isLoading) return;
try {
isLoading = true;
error = null;
notifyListeners();
final result = await queryRecipeByUserApi(userId);
recipeSummaryList = result;
notifyListeners();
} catch (e) {
error = '加载数据失败: $e';
debugPrint('加载数据失败: $e');
} finally {
isLoading = false;
notifyListeners();
}
}
Future<void> refreshRecipeList() async {
if (isLoading) return;

View File

@@ -19,7 +19,7 @@ class LoginPage extends StatefulWidget {
class _LoginPage extends State<LoginPage> {
final GlobalKey _formKey = GlobalKey<FormState>();
String _username = "Cxx0822", _password = "19940822Cxx";
String _username = "", _password = "";
bool _isRemember = false;
bool _isObscure = true;
bool _isLoading = false;

View File

@@ -158,7 +158,10 @@ class ProfilePageState extends State<ProfilePage> {
else if (provider.error.isNotEmpty)
Text(provider.error)
else
SingleChildScrollView(child: _buildContent(provider, context)),
SingleChildScrollView(
padding: const EdgeInsets.only(bottom: 90),
child: _buildContent(provider, context),
),
],
),
),

View File

@@ -74,7 +74,7 @@ class ProfileUserPageState extends State<ProfileUserPage> {
index: currentTab.index,
children: [
MomentList(momentList: provider.momentList, isUser: false),
Text('个人菜谱'),
RecipeList(userId: provider.currentUser.id!),
],
),
),
@@ -91,11 +91,11 @@ class ProfileUserPageState extends State<ProfileUserPage> {
appBar: AppBar(
title: Text(
'${provider.currentUser.username}的个人信息',
style: const TextStyle(color: Colors.white),
style: Theme.of(context).textTheme.titleLarge,
),
backgroundColor: colors.primary,
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.white),
icon: Icon(Icons.arrow_back, color: colors.primary),
onPressed: () => Navigator.pop(context),
),
),

View File

@@ -82,8 +82,17 @@ class _RecipeDetailState extends State<RecipeDetailPage> {
@override
Widget build(BuildContext context) {
final colors = Theme.of(context).colorScheme;
return Scaffold(
appBar: AppBar(title: Text('菜谱信息')),
appBar: AppBar(
title: Text('菜谱信息', style: Theme.of(context).textTheme.titleLarge),
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
leading: IconButton(
icon: Icon(Icons.arrow_back, color: colors.primary),
onPressed: () => Navigator.pop(context),
),
),
body: SingleChildScrollView(
child: Column(
children: [

View File

@@ -36,7 +36,7 @@ class _RecordPageState extends State<RecordPage> {
final ScrollController _scrollController = ScrollController();
bool _showScrollToTop = false;
final List<Widget> _tabPages = [
RecipeList(),
RecipeList(userId: 0),
RecipeCalendar(),
RecipeTimeline(),
];

View File

@@ -40,6 +40,7 @@ class _StatsPage extends State<StatsPage> {
GlassCard(
useOwnLayer: true,
settings: LiquidGlassSettings(glassColor: colors.surface),
padding: EdgeInsetsGeometry.all(10),
child: StatsCard(
icon: Icons.restaurant_menu,
title: '菜谱总数',
@@ -50,6 +51,7 @@ class _StatsPage extends State<StatsPage> {
GlassCard(
useOwnLayer: true,
settings: LiquidGlassSettings(glassColor: colors.surface),
padding: EdgeInsetsGeometry.all(10),
child: StatsCard(
icon: Icons.grid_view_rounded,
title: '菜谱类别',
@@ -60,6 +62,7 @@ class _StatsPage extends State<StatsPage> {
GlassCard(
useOwnLayer: true,
settings: LiquidGlassSettings(glassColor: colors.surface),
padding: EdgeInsetsGeometry.all(10),
child: StatsCard(
icon: Icons.flag,
title: '做菜次数',
@@ -70,6 +73,7 @@ class _StatsPage extends State<StatsPage> {
GlassCard(
useOwnLayer: true,
settings: LiquidGlassSettings(glassColor: colors.surface),
padding: EdgeInsetsGeometry.all(10),
child: StatsCard(
icon: Icons.show_chart,
title: '平均次数',
@@ -116,14 +120,11 @@ class _StatsPage extends State<StatsPage> {
),
),
SizedBox(height: 8),
SizedBox(
height: chartHeight,
child: GlassCard(
GlassCard(
useOwnLayer: true,
settings: LiquidGlassSettings(glassColor: colors.surface),
child: RankChart(title: '排行榜', data: provider.rankStats, unit: ''),
),
),
],
);
}

View File

@@ -44,7 +44,7 @@ class ProfileInfo extends StatelessWidget {
children: [
Icon(icon, size: 16, color: colors.primary),
const SizedBox(width: 6),
Text(text, style: Theme.of(context).textTheme.bodyMedium),
Text(text, style: Theme.of(context).textTheme.bodySmall),
],
);
}

View File

@@ -29,7 +29,6 @@ class RecipeCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CommonImage(imageUrls: imageUrls, index: 0),
SizedBox(height: 8),
InkWell(
onTap: () => navigatorToRecipeDetail(context),
child: _buildRecipeContent(context),
@@ -56,6 +55,11 @@ class RecipeCard extends StatelessWidget {
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
_buildIconText(
icon: Icons.star,
text: recipe.recommendRate.toString(),
color: colors.primary,
),
],
),
SizedBox(height: 5),
@@ -70,7 +74,7 @@ class RecipeCard extends StatelessWidget {
const SizedBox(width: 12),
_buildIconText(
icon: Icons.note_add,
text: recipe.recordList.length.toString(),
text: '${recipe.recordList.length.toString()}',
color: colors.primary,
),
],

View File

@@ -5,7 +5,9 @@ import 'package:food_hub_app/widgets/recipe/card.dart';
import 'package:provider/provider.dart';
class RecipeList extends StatefulWidget {
const RecipeList({super.key});
final int userId;
const RecipeList({super.key, required this.userId});
@override
State<RecipeList> createState() => _RecipeListState();
@@ -18,8 +20,11 @@ class _RecipeListState extends State<RecipeList> {
// 初始化加载数据
WidgetsBinding.instance.addPostFrameCallback((_) {
if (widget.userId == 0) {
context.read<FoodProvider>().refreshRecipeList();
context.read<FoodProvider>().queryCategoryList();
} else {
context.read<FoodProvider>().queryRecipeByUserId(widget.userId);
}
});
}
@@ -30,7 +35,7 @@ class _RecipeListState extends State<RecipeList> {
crossAxisCount: 2,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
childAspectRatio: 0.9,
childAspectRatio: 0.85,
),
itemCount: provider.recipeSummaryList.length,
itemBuilder: (context, index) {