feat:更新好友菜谱功能
This commit is contained in:
@@ -25,10 +25,10 @@ Future<bool> deleteRecipeApi(int id) {
|
|||||||
return httpUtil.delete<bool>("/food/recipe/$id");
|
return httpUtil.delete<bool>("/food/recipe/$id");
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Recipe>> queryRecipeByUserApi(int id) {
|
Future<List<RecipeSummary>> queryRecipeByUserApi(int id) {
|
||||||
return httpUtil.get<List<Recipe>>(
|
return httpUtil.get<List<RecipeSummary>>(
|
||||||
"/food/recipe/user/$id",
|
"/food/recipe/user/$id",
|
||||||
converter: (data) => convertList<Recipe>(data, Recipe.fromJson),
|
converter: (data) => convertList<RecipeSummary>(data, RecipeSummary.fromJson),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -176,7 +176,6 @@ class RecipeSummary {
|
|||||||
int commentCount;
|
int commentCount;
|
||||||
int userId;
|
int userId;
|
||||||
String username;
|
String username;
|
||||||
String avatar;
|
|
||||||
|
|
||||||
RecipeSummary({
|
RecipeSummary({
|
||||||
required this.id,
|
required this.id,
|
||||||
@@ -186,7 +185,6 @@ class RecipeSummary {
|
|||||||
required this.isShare,
|
required this.isShare,
|
||||||
required this.userId,
|
required this.userId,
|
||||||
required this.username,
|
required this.username,
|
||||||
required this.avatar,
|
|
||||||
required this.recordList,
|
required this.recordList,
|
||||||
required this.likeCount,
|
required this.likeCount,
|
||||||
required this.favouriteCount,
|
required this.favouriteCount,
|
||||||
|
|||||||
@@ -149,7 +149,6 @@ RecipeSummary _$RecipeSummaryFromJson(Map<String, dynamic> json) =>
|
|||||||
isShare: json['isShare'] as bool,
|
isShare: json['isShare'] as bool,
|
||||||
userId: (json['userId'] as num).toInt(),
|
userId: (json['userId'] as num).toInt(),
|
||||||
username: json['username'] as String,
|
username: json['username'] as String,
|
||||||
avatar: json['avatar'] as String,
|
|
||||||
recordList:
|
recordList:
|
||||||
(json['recordList'] as List<dynamic>)
|
(json['recordList'] as List<dynamic>)
|
||||||
.map((e) => FoodRecord.fromJson(e as Map<String, dynamic>))
|
.map((e) => FoodRecord.fromJson(e as Map<String, dynamic>))
|
||||||
@@ -172,7 +171,6 @@ Map<String, dynamic> _$RecipeSummaryToJson(RecipeSummary instance) =>
|
|||||||
'commentCount': instance.commentCount,
|
'commentCount': instance.commentCount,
|
||||||
'userId': instance.userId,
|
'userId': instance.userId,
|
||||||
'username': instance.username,
|
'username': instance.username,
|
||||||
'avatar': instance.avatar,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
RecipeDetail _$RecipeDetailFromJson(Map<String, dynamic> json) => RecipeDetail(
|
RecipeDetail _$RecipeDetailFromJson(Map<String, dynamic> json) => RecipeDetail(
|
||||||
|
|||||||
@@ -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 {
|
Future<void> refreshRecipeList() async {
|
||||||
if (isLoading) return;
|
if (isLoading) return;
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class LoginPage extends StatefulWidget {
|
|||||||
class _LoginPage extends State<LoginPage> {
|
class _LoginPage extends State<LoginPage> {
|
||||||
final GlobalKey _formKey = GlobalKey<FormState>();
|
final GlobalKey _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
String _username = "Cxx0822", _password = "19940822Cxx";
|
String _username = "", _password = "";
|
||||||
bool _isRemember = false;
|
bool _isRemember = false;
|
||||||
bool _isObscure = true;
|
bool _isObscure = true;
|
||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
|
|||||||
@@ -158,7 +158,10 @@ class ProfilePageState extends State<ProfilePage> {
|
|||||||
else if (provider.error.isNotEmpty)
|
else if (provider.error.isNotEmpty)
|
||||||
Text(provider.error)
|
Text(provider.error)
|
||||||
else
|
else
|
||||||
SingleChildScrollView(child: _buildContent(provider, context)),
|
SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.only(bottom: 90),
|
||||||
|
child: _buildContent(provider, context),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class ProfileUserPageState extends State<ProfileUserPage> {
|
|||||||
index: currentTab.index,
|
index: currentTab.index,
|
||||||
children: [
|
children: [
|
||||||
MomentList(momentList: provider.momentList, isUser: false),
|
MomentList(momentList: provider.momentList, isUser: false),
|
||||||
Text('个人菜谱'),
|
RecipeList(userId: provider.currentUser.id!),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -91,11 +91,11 @@ class ProfileUserPageState extends State<ProfileUserPage> {
|
|||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(
|
title: Text(
|
||||||
'${provider.currentUser.username}的个人信息',
|
'${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(
|
leading: IconButton(
|
||||||
icon: const Icon(Icons.arrow_back, color: Colors.white),
|
icon: Icon(Icons.arrow_back, color: colors.primary),
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () => Navigator.pop(context),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -82,8 +82,17 @@ class _RecipeDetailState extends State<RecipeDetailPage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final colors = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
return Scaffold(
|
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(
|
body: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class _RecordPageState extends State<RecordPage> {
|
|||||||
final ScrollController _scrollController = ScrollController();
|
final ScrollController _scrollController = ScrollController();
|
||||||
bool _showScrollToTop = false;
|
bool _showScrollToTop = false;
|
||||||
final List<Widget> _tabPages = [
|
final List<Widget> _tabPages = [
|
||||||
RecipeList(),
|
RecipeList(userId: 0),
|
||||||
RecipeCalendar(),
|
RecipeCalendar(),
|
||||||
RecipeTimeline(),
|
RecipeTimeline(),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ class _StatsPage extends State<StatsPage> {
|
|||||||
GlassCard(
|
GlassCard(
|
||||||
useOwnLayer: true,
|
useOwnLayer: true,
|
||||||
settings: LiquidGlassSettings(glassColor: colors.surface),
|
settings: LiquidGlassSettings(glassColor: colors.surface),
|
||||||
|
padding: EdgeInsetsGeometry.all(10),
|
||||||
child: StatsCard(
|
child: StatsCard(
|
||||||
icon: Icons.restaurant_menu,
|
icon: Icons.restaurant_menu,
|
||||||
title: '菜谱总数',
|
title: '菜谱总数',
|
||||||
@@ -50,6 +51,7 @@ class _StatsPage extends State<StatsPage> {
|
|||||||
GlassCard(
|
GlassCard(
|
||||||
useOwnLayer: true,
|
useOwnLayer: true,
|
||||||
settings: LiquidGlassSettings(glassColor: colors.surface),
|
settings: LiquidGlassSettings(glassColor: colors.surface),
|
||||||
|
padding: EdgeInsetsGeometry.all(10),
|
||||||
child: StatsCard(
|
child: StatsCard(
|
||||||
icon: Icons.grid_view_rounded,
|
icon: Icons.grid_view_rounded,
|
||||||
title: '菜谱类别',
|
title: '菜谱类别',
|
||||||
@@ -60,6 +62,7 @@ class _StatsPage extends State<StatsPage> {
|
|||||||
GlassCard(
|
GlassCard(
|
||||||
useOwnLayer: true,
|
useOwnLayer: true,
|
||||||
settings: LiquidGlassSettings(glassColor: colors.surface),
|
settings: LiquidGlassSettings(glassColor: colors.surface),
|
||||||
|
padding: EdgeInsetsGeometry.all(10),
|
||||||
child: StatsCard(
|
child: StatsCard(
|
||||||
icon: Icons.flag,
|
icon: Icons.flag,
|
||||||
title: '做菜次数',
|
title: '做菜次数',
|
||||||
@@ -70,6 +73,7 @@ class _StatsPage extends State<StatsPage> {
|
|||||||
GlassCard(
|
GlassCard(
|
||||||
useOwnLayer: true,
|
useOwnLayer: true,
|
||||||
settings: LiquidGlassSettings(glassColor: colors.surface),
|
settings: LiquidGlassSettings(glassColor: colors.surface),
|
||||||
|
padding: EdgeInsetsGeometry.all(10),
|
||||||
child: StatsCard(
|
child: StatsCard(
|
||||||
icon: Icons.show_chart,
|
icon: Icons.show_chart,
|
||||||
title: '平均次数',
|
title: '平均次数',
|
||||||
@@ -116,13 +120,10 @@ class _StatsPage extends State<StatsPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 8),
|
SizedBox(height: 8),
|
||||||
SizedBox(
|
GlassCard(
|
||||||
height: chartHeight,
|
useOwnLayer: true,
|
||||||
child: GlassCard(
|
settings: LiquidGlassSettings(glassColor: colors.surface),
|
||||||
useOwnLayer: true,
|
child: RankChart(title: '排行榜', data: provider.rankStats, unit: '次'),
|
||||||
settings: LiquidGlassSettings(glassColor: colors.surface),
|
|
||||||
child: RankChart(title: '排行榜', data: provider.rankStats, unit: '次'),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class ProfileInfo extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Icon(icon, size: 16, color: colors.primary),
|
Icon(icon, size: 16, color: colors.primary),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
Text(text, style: Theme.of(context).textTheme.bodyMedium),
|
Text(text, style: Theme.of(context).textTheme.bodySmall),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ class RecipeCard extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
CommonImage(imageUrls: imageUrls, index: 0),
|
CommonImage(imageUrls: imageUrls, index: 0),
|
||||||
SizedBox(height: 8),
|
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () => navigatorToRecipeDetail(context),
|
onTap: () => navigatorToRecipeDetail(context),
|
||||||
child: _buildRecipeContent(context),
|
child: _buildRecipeContent(context),
|
||||||
@@ -56,6 +55,11 @@ class RecipeCard extends StatelessWidget {
|
|||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
|
_buildIconText(
|
||||||
|
icon: Icons.star,
|
||||||
|
text: recipe.recommendRate.toString(),
|
||||||
|
color: colors.primary,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
@@ -70,7 +74,7 @@ class RecipeCard extends StatelessWidget {
|
|||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
_buildIconText(
|
_buildIconText(
|
||||||
icon: Icons.note_add,
|
icon: Icons.note_add,
|
||||||
text: recipe.recordList.length.toString(),
|
text: '${recipe.recordList.length.toString()}次',
|
||||||
color: colors.primary,
|
color: colors.primary,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ import 'package:food_hub_app/widgets/recipe/card.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class RecipeList extends StatefulWidget {
|
class RecipeList extends StatefulWidget {
|
||||||
const RecipeList({super.key});
|
final int userId;
|
||||||
|
|
||||||
|
const RecipeList({super.key, required this.userId});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<RecipeList> createState() => _RecipeListState();
|
State<RecipeList> createState() => _RecipeListState();
|
||||||
@@ -18,8 +20,11 @@ class _RecipeListState extends State<RecipeList> {
|
|||||||
|
|
||||||
// 初始化加载数据
|
// 初始化加载数据
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
context.read<FoodProvider>().refreshRecipeList();
|
if (widget.userId == 0) {
|
||||||
context.read<FoodProvider>().queryCategoryList();
|
context.read<FoodProvider>().refreshRecipeList();
|
||||||
|
} else {
|
||||||
|
context.read<FoodProvider>().queryRecipeByUserId(widget.userId);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +35,7 @@ class _RecipeListState extends State<RecipeList> {
|
|||||||
crossAxisCount: 2,
|
crossAxisCount: 2,
|
||||||
crossAxisSpacing: 8,
|
crossAxisSpacing: 8,
|
||||||
mainAxisSpacing: 8,
|
mainAxisSpacing: 8,
|
||||||
childAspectRatio: 0.9,
|
childAspectRatio: 0.85,
|
||||||
),
|
),
|
||||||
itemCount: provider.recipeSummaryList.length,
|
itemCount: provider.recipeSummaryList.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
|
|||||||
Reference in New Issue
Block a user