feat:新增菜谱详细信息模块
This commit is contained in:
@@ -2,10 +2,10 @@ import 'package:food_hub_app/models/recipe.dart';
|
|||||||
import 'package:food_hub_app/utils/http_util.dart';
|
import 'package:food_hub_app/utils/http_util.dart';
|
||||||
import 'package:food_hub_app/utils/index.dart';
|
import 'package:food_hub_app/utils/index.dart';
|
||||||
|
|
||||||
Future<Recipe> queryRecipeByIdApi(int id) {
|
Future<RecipeDetail> queryRecipeByIdApi(int id) {
|
||||||
return HttpUtil().get<Recipe>(
|
return HttpUtil().get<RecipeDetail>(
|
||||||
"/food/recipe/$id",
|
"/food/recipe/$id",
|
||||||
converter: (data) => Recipe.fromJson(data),
|
converter: (data) => RecipeDetail.fromJson(data),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,11 +35,11 @@ Future<List<Recipe>> queryRecipeUserFavouriteApi() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Recipe>> queryRecipeApi(RecipeQuery recipeQuery) {
|
Future<List<RecipeSummary>> queryRecipeApi(RecipeQuery recipeQuery) {
|
||||||
return HttpUtil().get<List<Recipe>>(
|
return HttpUtil().get<List<RecipeSummary>>(
|
||||||
"/food/recipe",
|
"/food/recipe",
|
||||||
queryParameters: recipeQuery.toJson(),
|
queryParameters: recipeQuery.toJson(),
|
||||||
converter: (data) => convertListResponse<Recipe>(data, Recipe.fromJson),
|
converter: (data) => convertListResponse<RecipeSummary>(data, RecipeSummary.fromJson),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import 'package:flutter_localizations/flutter_localizations.dart';
|
|||||||
import 'package:food_hub_app/utils/sp_util.dart';
|
import 'package:food_hub_app/utils/sp_util.dart';
|
||||||
import 'package:food_hub_app/views/home.dart';
|
import 'package:food_hub_app/views/home.dart';
|
||||||
import 'package:food_hub_app/views/login.dart';
|
import 'package:food_hub_app/views/login.dart';
|
||||||
import 'package:food_hub_app/views/recordForm.dart';
|
import 'package:food_hub_app/views/record_form.dart';
|
||||||
import 'package:food_hub_app/widgets/recipe/detail.dart';
|
import 'package:food_hub_app/views/recipe_detail.dart';
|
||||||
import 'package:form_builder_validators/form_builder_validators.dart';
|
import 'package:form_builder_validators/form_builder_validators.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ class MyApp extends StatelessWidget {
|
|||||||
routes: {
|
routes: {
|
||||||
'/home': (context) => HomePage(),
|
'/home': (context) => HomePage(),
|
||||||
'/recordForm': (context) => RecordFormPage(),
|
'/recordForm': (context) => RecordFormPage(),
|
||||||
'/recipeDetail': (context) => RecipeDetail(),
|
'/recipeDetail': (context) => RecipeDetailPage(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,43 +4,43 @@ part 'recipe.g.dart';
|
|||||||
|
|
||||||
/// 食材信息
|
/// 食材信息
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class Material {
|
class RecipeMaterial {
|
||||||
String type;
|
String type;
|
||||||
String name;
|
String name;
|
||||||
String amount;
|
String amount;
|
||||||
|
|
||||||
Material({required this.type, required this.name, required this.amount});
|
RecipeMaterial({required this.type, required this.name, required this.amount});
|
||||||
|
|
||||||
factory Material.fromJson(Map<String, dynamic> json) =>
|
factory RecipeMaterial.fromJson(Map<String, dynamic> json) =>
|
||||||
_$MaterialFromJson(json);
|
_$RecipeMaterialFromJson(json);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$MaterialToJson(this);
|
Map<String, dynamic> toJson() => _$RecipeMaterialToJson(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 步骤信息
|
/// 步骤信息
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class Step {
|
class RecipeStep {
|
||||||
int sort;
|
int sort;
|
||||||
String content;
|
String content;
|
||||||
String imageUrl;
|
String imageUrl;
|
||||||
|
|
||||||
Step({required this.sort, required this.content, required this.imageUrl});
|
RecipeStep({required this.sort, required this.content, required this.imageUrl});
|
||||||
|
|
||||||
factory Step.fromJson(Map<String, dynamic> json) => _$StepFromJson(json);
|
factory RecipeStep.fromJson(Map<String, dynamic> json) => _$RecipeStepFromJson(json);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$StepToJson(this);
|
Map<String, dynamic> toJson() => _$RecipeStepToJson(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 评论信息
|
/// 评论信息
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class Comment {
|
class RecipeComment {
|
||||||
int id;
|
int id;
|
||||||
String username;
|
String username;
|
||||||
String avatar;
|
String avatar;
|
||||||
String content;
|
String content;
|
||||||
String date;
|
String date;
|
||||||
|
|
||||||
Comment({
|
RecipeComment({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.username,
|
required this.username,
|
||||||
required this.avatar,
|
required this.avatar,
|
||||||
@@ -48,10 +48,10 @@ class Comment {
|
|||||||
required this.date,
|
required this.date,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory Comment.fromJson(Map<String, dynamic> json) =>
|
factory RecipeComment.fromJson(Map<String, dynamic> json) =>
|
||||||
_$CommentFromJson(json);
|
_$RecipeCommentFromJson(json);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$CommentToJson(this);
|
Map<String, dynamic> toJson() => _$RecipeCommentToJson(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 成果信息
|
/// 成果信息
|
||||||
@@ -94,44 +94,44 @@ class RecipeQuery {
|
|||||||
/// 菜谱信息
|
/// 菜谱信息
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class Recipe {
|
class Recipe {
|
||||||
int? id;
|
int id;
|
||||||
String name;
|
String name;
|
||||||
String category;
|
String category;
|
||||||
double recommendRate;
|
double recommendRate;
|
||||||
String? remark;
|
String remark;
|
||||||
bool isShare;
|
bool isShare;
|
||||||
int? userId;
|
int userId;
|
||||||
String? username;
|
String username;
|
||||||
String? avatar;
|
String avatar;
|
||||||
List<Material>? materialList;
|
List<RecipeMaterial> materialList;
|
||||||
List<Step>? stepList;
|
List<RecipeStep> stepList;
|
||||||
List<Record> recordList;
|
List<Record> recordList;
|
||||||
List<int>? likeList;
|
List<int> likeList;
|
||||||
int? likeCount;
|
int likeCount;
|
||||||
List<int>? favouriteList;
|
List<int> favouriteList;
|
||||||
int? favouriteCount;
|
int favouriteCount;
|
||||||
List<Comment>? commentList;
|
List<RecipeComment> commentList;
|
||||||
int? commentCount;
|
int commentCount;
|
||||||
|
|
||||||
Recipe({
|
Recipe({
|
||||||
this.id,
|
required this.id,
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.category,
|
required this.category,
|
||||||
required this.recommendRate,
|
required this.recommendRate,
|
||||||
this.remark,
|
required this.remark,
|
||||||
required this.isShare,
|
required this.isShare,
|
||||||
this.userId,
|
required this.userId,
|
||||||
this.username,
|
required this.username,
|
||||||
this.avatar,
|
required this.avatar,
|
||||||
this.materialList,
|
required this.materialList,
|
||||||
this.stepList,
|
required this.stepList,
|
||||||
required this.recordList,
|
required this.recordList,
|
||||||
this.likeList,
|
required this.likeList,
|
||||||
this.likeCount,
|
required this.likeCount,
|
||||||
this.favouriteList,
|
required this.favouriteList,
|
||||||
this.favouriteCount,
|
required this.favouriteCount,
|
||||||
this.commentList,
|
required this.commentList,
|
||||||
this.commentCount,
|
required this.commentCount,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory Recipe.fromJson(Map<String, dynamic> json) => _$RecipeFromJson(json);
|
factory Recipe.fromJson(Map<String, dynamic> json) => _$RecipeFromJson(json);
|
||||||
@@ -139,4 +139,80 @@ class Recipe {
|
|||||||
Map<String, dynamic> toJson() => _$RecipeToJson(this);
|
Map<String, dynamic> toJson() => _$RecipeToJson(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class RecipeSummary {
|
||||||
|
int id;
|
||||||
|
String name;
|
||||||
|
String category;
|
||||||
|
double recommendRate;
|
||||||
|
bool isShare;
|
||||||
|
List<Record> recordList;
|
||||||
|
int likeCount;
|
||||||
|
int favouriteCount;
|
||||||
|
int commentCount;
|
||||||
|
int userId;
|
||||||
|
String username;
|
||||||
|
String avatar;
|
||||||
|
|
||||||
|
RecipeSummary({
|
||||||
|
required this.id,
|
||||||
|
required this.name,
|
||||||
|
required this.category,
|
||||||
|
required this.recommendRate,
|
||||||
|
required this.isShare,
|
||||||
|
required this.userId,
|
||||||
|
required this.username,
|
||||||
|
required this.avatar,
|
||||||
|
required this.recordList,
|
||||||
|
required this.likeCount,
|
||||||
|
required this.favouriteCount,
|
||||||
|
required this.commentCount,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory RecipeSummary.fromJson(Map<String, dynamic> json) => _$RecipeSummaryFromJson(json);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => _$RecipeSummaryToJson(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class RecipeDetail {
|
||||||
|
int id;
|
||||||
|
String name;
|
||||||
|
String category;
|
||||||
|
double recommendRate;
|
||||||
|
String remark;
|
||||||
|
bool isShare;
|
||||||
|
int userId;
|
||||||
|
String username;
|
||||||
|
String avatar;
|
||||||
|
List<RecipeMaterial> materialList;
|
||||||
|
List<RecipeStep> stepList;
|
||||||
|
List<Record> recordList;
|
||||||
|
List<int> likeList;
|
||||||
|
List<int> favouriteList;
|
||||||
|
List<RecipeComment> commentList;
|
||||||
|
|
||||||
|
RecipeDetail({
|
||||||
|
required this.id,
|
||||||
|
required this.name,
|
||||||
|
required this.category,
|
||||||
|
required this.recommendRate,
|
||||||
|
required this.remark,
|
||||||
|
required this.isShare,
|
||||||
|
required this.userId,
|
||||||
|
required this.username,
|
||||||
|
required this.avatar,
|
||||||
|
required this.materialList,
|
||||||
|
required this.stepList,
|
||||||
|
required this.recordList,
|
||||||
|
required this.likeList,
|
||||||
|
required this.favouriteList,
|
||||||
|
required this.commentList,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory RecipeDetail.fromJson(Map<String, dynamic> json) => _$RecipeDetailFromJson(json);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => _$RecipeDetailToJson(this);
|
||||||
|
}
|
||||||
|
|
||||||
enum ViewType { recipe, calendar, timeline }
|
enum ViewType { recipe, calendar, timeline }
|
||||||
|
|||||||
@@ -6,31 +6,35 @@ part of 'recipe.dart';
|
|||||||
// JsonSerializableGenerator
|
// JsonSerializableGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
Material _$MaterialFromJson(Map<String, dynamic> json) => Material(
|
RecipeMaterial _$RecipeMaterialFromJson(Map<String, dynamic> json) =>
|
||||||
|
RecipeMaterial(
|
||||||
type: json['type'] as String,
|
type: json['type'] as String,
|
||||||
name: json['name'] as String,
|
name: json['name'] as String,
|
||||||
amount: json['amount'] as String,
|
amount: json['amount'] as String,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$MaterialToJson(Material instance) => <String, dynamic>{
|
Map<String, dynamic> _$RecipeMaterialToJson(RecipeMaterial instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
'type': instance.type,
|
'type': instance.type,
|
||||||
'name': instance.name,
|
'name': instance.name,
|
||||||
'amount': instance.amount,
|
'amount': instance.amount,
|
||||||
};
|
};
|
||||||
|
|
||||||
Step _$StepFromJson(Map<String, dynamic> json) => Step(
|
RecipeStep _$RecipeStepFromJson(Map<String, dynamic> json) => RecipeStep(
|
||||||
sort: (json['sort'] as num).toInt(),
|
sort: (json['sort'] as num).toInt(),
|
||||||
content: json['content'] as String,
|
content: json['content'] as String,
|
||||||
imageUrl: json['imageUrl'] as String,
|
imageUrl: json['imageUrl'] as String,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$StepToJson(Step instance) => <String, dynamic>{
|
Map<String, dynamic> _$RecipeStepToJson(RecipeStep instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
'sort': instance.sort,
|
'sort': instance.sort,
|
||||||
'content': instance.content,
|
'content': instance.content,
|
||||||
'imageUrl': instance.imageUrl,
|
'imageUrl': instance.imageUrl,
|
||||||
};
|
};
|
||||||
|
|
||||||
Comment _$CommentFromJson(Map<String, dynamic> json) => Comment(
|
RecipeComment _$RecipeCommentFromJson(Map<String, dynamic> json) =>
|
||||||
|
RecipeComment(
|
||||||
id: (json['id'] as num).toInt(),
|
id: (json['id'] as num).toInt(),
|
||||||
username: json['username'] as String,
|
username: json['username'] as String,
|
||||||
avatar: json['avatar'] as String,
|
avatar: json['avatar'] as String,
|
||||||
@@ -38,7 +42,8 @@ Comment _$CommentFromJson(Map<String, dynamic> json) => Comment(
|
|||||||
date: json['date'] as String,
|
date: json['date'] as String,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$CommentToJson(Comment instance) => <String, dynamic>{
|
Map<String, dynamic> _$RecipeCommentToJson(RecipeComment instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
'id': instance.id,
|
'id': instance.id,
|
||||||
'username': instance.username,
|
'username': instance.username,
|
||||||
'avatar': instance.avatar,
|
'avatar': instance.avatar,
|
||||||
@@ -71,42 +76,42 @@ Map<String, dynamic> _$RecipeQueryToJson(RecipeQuery instance) =>
|
|||||||
<String, dynamic>{'category': instance.category};
|
<String, dynamic>{'category': instance.category};
|
||||||
|
|
||||||
Recipe _$RecipeFromJson(Map<String, dynamic> json) => Recipe(
|
Recipe _$RecipeFromJson(Map<String, dynamic> json) => Recipe(
|
||||||
id: (json['id'] as num?)?.toInt(),
|
id: (json['id'] as num).toInt(),
|
||||||
name: json['name'] as String,
|
name: json['name'] as String,
|
||||||
category: json['category'] as String,
|
category: json['category'] as String,
|
||||||
recommendRate: (json['recommendRate'] as num).toDouble(),
|
recommendRate: (json['recommendRate'] as num).toDouble(),
|
||||||
remark: json['remark'] as String?,
|
remark: json['remark'] as String,
|
||||||
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?,
|
avatar: json['avatar'] as String,
|
||||||
materialList:
|
materialList:
|
||||||
(json['materialList'] as List<dynamic>?)
|
(json['materialList'] as List<dynamic>)
|
||||||
?.map((e) => Material.fromJson(e as Map<String, dynamic>))
|
.map((e) => RecipeMaterial.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
stepList:
|
stepList:
|
||||||
(json['stepList'] as List<dynamic>?)
|
(json['stepList'] as List<dynamic>)
|
||||||
?.map((e) => Step.fromJson(e as Map<String, dynamic>))
|
.map((e) => RecipeStep.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
recordList:
|
recordList:
|
||||||
(json['recordList'] as List<dynamic>)
|
(json['recordList'] as List<dynamic>)
|
||||||
.map((e) => Record.fromJson(e as Map<String, dynamic>))
|
.map((e) => Record.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
likeList:
|
likeList:
|
||||||
(json['likeList'] as List<dynamic>?)
|
(json['likeList'] as List<dynamic>)
|
||||||
?.map((e) => (e as num).toInt())
|
.map((e) => (e as num).toInt())
|
||||||
.toList(),
|
.toList(),
|
||||||
likeCount: (json['likeCount'] as num?)?.toInt(),
|
likeCount: (json['likeCount'] as num).toInt(),
|
||||||
favouriteList:
|
favouriteList:
|
||||||
(json['favouriteList'] as List<dynamic>?)
|
(json['favouriteList'] as List<dynamic>)
|
||||||
?.map((e) => (e as num).toInt())
|
.map((e) => (e as num).toInt())
|
||||||
.toList(),
|
.toList(),
|
||||||
favouriteCount: (json['favouriteCount'] as num?)?.toInt(),
|
favouriteCount: (json['favouriteCount'] as num).toInt(),
|
||||||
commentList:
|
commentList:
|
||||||
(json['commentList'] as List<dynamic>?)
|
(json['commentList'] as List<dynamic>)
|
||||||
?.map((e) => Comment.fromJson(e as Map<String, dynamic>))
|
.map((e) => RecipeComment.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
commentCount: (json['commentCount'] as num?)?.toInt(),
|
commentCount: (json['commentCount'] as num).toInt(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$RecipeToJson(Recipe instance) => <String, dynamic>{
|
Map<String, dynamic> _$RecipeToJson(Recipe instance) => <String, dynamic>{
|
||||||
@@ -129,3 +134,93 @@ Map<String, dynamic> _$RecipeToJson(Recipe instance) => <String, dynamic>{
|
|||||||
'commentList': instance.commentList,
|
'commentList': instance.commentList,
|
||||||
'commentCount': instance.commentCount,
|
'commentCount': instance.commentCount,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
RecipeSummary _$RecipeSummaryFromJson(Map<String, dynamic> json) =>
|
||||||
|
RecipeSummary(
|
||||||
|
id: (json['id'] as num).toInt(),
|
||||||
|
name: json['name'] as String,
|
||||||
|
category: json['category'] as String,
|
||||||
|
recommendRate: (json['recommendRate'] as num).toDouble(),
|
||||||
|
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) => Record.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
likeCount: (json['likeCount'] as num).toInt(),
|
||||||
|
favouriteCount: (json['favouriteCount'] as num).toInt(),
|
||||||
|
commentCount: (json['commentCount'] as num).toInt(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$RecipeSummaryToJson(RecipeSummary instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'id': instance.id,
|
||||||
|
'name': instance.name,
|
||||||
|
'category': instance.category,
|
||||||
|
'recommendRate': instance.recommendRate,
|
||||||
|
'isShare': instance.isShare,
|
||||||
|
'recordList': instance.recordList,
|
||||||
|
'likeCount': instance.likeCount,
|
||||||
|
'favouriteCount': instance.favouriteCount,
|
||||||
|
'commentCount': instance.commentCount,
|
||||||
|
'userId': instance.userId,
|
||||||
|
'username': instance.username,
|
||||||
|
'avatar': instance.avatar,
|
||||||
|
};
|
||||||
|
|
||||||
|
RecipeDetail _$RecipeDetailFromJson(Map<String, dynamic> json) => RecipeDetail(
|
||||||
|
id: (json['id'] as num).toInt(),
|
||||||
|
name: json['name'] as String,
|
||||||
|
category: json['category'] as String,
|
||||||
|
recommendRate: (json['recommendRate'] as num).toDouble(),
|
||||||
|
remark: json['remark'] as String,
|
||||||
|
isShare: json['isShare'] as bool,
|
||||||
|
userId: (json['userId'] as num).toInt(),
|
||||||
|
username: json['username'] as String,
|
||||||
|
avatar: json['avatar'] as String,
|
||||||
|
materialList:
|
||||||
|
(json['materialList'] as List<dynamic>)
|
||||||
|
.map((e) => RecipeMaterial.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
stepList:
|
||||||
|
(json['stepList'] as List<dynamic>)
|
||||||
|
.map((e) => RecipeStep.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
recordList:
|
||||||
|
(json['recordList'] as List<dynamic>)
|
||||||
|
.map((e) => Record.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
likeList:
|
||||||
|
(json['likeList'] as List<dynamic>)
|
||||||
|
.map((e) => (e as num).toInt())
|
||||||
|
.toList(),
|
||||||
|
favouriteList:
|
||||||
|
(json['favouriteList'] as List<dynamic>)
|
||||||
|
.map((e) => (e as num).toInt())
|
||||||
|
.toList(),
|
||||||
|
commentList:
|
||||||
|
(json['commentList'] as List<dynamic>)
|
||||||
|
.map((e) => RecipeComment.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$RecipeDetailToJson(RecipeDetail instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'id': instance.id,
|
||||||
|
'name': instance.name,
|
||||||
|
'category': instance.category,
|
||||||
|
'recommendRate': instance.recommendRate,
|
||||||
|
'remark': instance.remark,
|
||||||
|
'isShare': instance.isShare,
|
||||||
|
'userId': instance.userId,
|
||||||
|
'username': instance.username,
|
||||||
|
'avatar': instance.avatar,
|
||||||
|
'materialList': instance.materialList,
|
||||||
|
'stepList': instance.stepList,
|
||||||
|
'recordList': instance.recordList,
|
||||||
|
'likeList': instance.likeList,
|
||||||
|
'favouriteList': instance.favouriteList,
|
||||||
|
'commentList': instance.commentList,
|
||||||
|
};
|
||||||
|
|||||||
@@ -14,11 +14,10 @@ class MomentPage extends StatefulWidget {
|
|||||||
|
|
||||||
class _MomentPageState extends State<MomentPage> {
|
class _MomentPageState extends State<MomentPage> {
|
||||||
List<Moment> momentList = [];
|
List<Moment> momentList = [];
|
||||||
|
int _currentPage = 1;
|
||||||
// 分页相关变量
|
|
||||||
int _page = 1;
|
|
||||||
final int _pageSize = 3;
|
final int _pageSize = 3;
|
||||||
bool _hasMore = true;
|
bool _hasMore = true;
|
||||||
|
|
||||||
// 初始化EasyRefresh控制器
|
// 初始化EasyRefresh控制器
|
||||||
final EasyRefreshController _freshController = EasyRefreshController(
|
final EasyRefreshController _freshController = EasyRefreshController(
|
||||||
controlFinishRefresh: true,
|
controlFinishRefresh: true,
|
||||||
@@ -49,11 +48,10 @@ class _MomentPageState extends State<MomentPage> {
|
|||||||
try {
|
try {
|
||||||
// 如果是刷新,重置页码
|
// 如果是刷新,重置页码
|
||||||
if (isRefresh) {
|
if (isRefresh) {
|
||||||
_page = 1;
|
_currentPage = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调用API获取数据,传入页码和页大小
|
final result = await queryMomentByPageApi(_currentPage, _pageSize);
|
||||||
final result = await queryMomentByPageApi(_page, _pageSize);
|
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
if (isRefresh) {
|
if (isRefresh) {
|
||||||
@@ -68,7 +66,7 @@ class _MomentPageState extends State<MomentPage> {
|
|||||||
_hasMore = result.current < result.pages;
|
_hasMore = result.current < result.pages;
|
||||||
// 如果有更多数据,准备加载下一页
|
// 如果有更多数据,准备加载下一页
|
||||||
if (_hasMore) {
|
if (_hasMore) {
|
||||||
_page++;
|
_currentPage++;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
247
lib/views/recipe_detail.dart
Normal file
247
lib/views/recipe_detail.dart
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:food_hub_app/api/recipe.dart';
|
||||||
|
import 'package:food_hub_app/models/recipe.dart';
|
||||||
|
import 'package:food_hub_app/widgets/common/index.dart';
|
||||||
|
|
||||||
|
class RecipeDetailPage extends StatefulWidget {
|
||||||
|
const RecipeDetailPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<RecipeDetailPage> createState() => _RecipeDetailState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _RecipeDetailState extends State<RecipeDetailPage> {
|
||||||
|
RecipeDetail recipe = RecipeDetail(
|
||||||
|
id: 0,
|
||||||
|
name: '',
|
||||||
|
category: '',
|
||||||
|
recommendRate: 0,
|
||||||
|
remark: '',
|
||||||
|
isShare: false,
|
||||||
|
userId: 0,
|
||||||
|
username: '',
|
||||||
|
avatar: '',
|
||||||
|
materialList: [],
|
||||||
|
stepList: [],
|
||||||
|
recordList: [],
|
||||||
|
likeList: [],
|
||||||
|
favouriteList: [],
|
||||||
|
commentList: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
// 定义三个分类列表
|
||||||
|
List<RecipeMaterial> mainMaterialList = []; // 主料
|
||||||
|
List<RecipeMaterial> auxiliaryMaterialList = []; // 配料
|
||||||
|
List<RecipeMaterial> accessoryMaterialList = []; // 辅料
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
super.didChangeDependencies();
|
||||||
|
refreshRecipeDetail();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> refreshRecipeDetail() async {
|
||||||
|
// 获取参数
|
||||||
|
final args = ModalRoute.of(context)?.settings.arguments as Map;
|
||||||
|
final recipeId = args['id'];
|
||||||
|
final result = await queryRecipeByIdApi(recipeId);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
recipe = result;
|
||||||
|
getRecipeMaterial();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void getRecipeMaterial() {
|
||||||
|
for (var material in recipe.materialList) {
|
||||||
|
switch (material.type) {
|
||||||
|
case '主料':
|
||||||
|
mainMaterialList.add(material);
|
||||||
|
break;
|
||||||
|
case '配料':
|
||||||
|
auxiliaryMaterialList.add(material);
|
||||||
|
break;
|
||||||
|
case '辅料':
|
||||||
|
accessoryMaterialList.add(material);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text('菜谱信息', style: TextStyle(color: Colors.white)),
|
||||||
|
backgroundColor: Theme.of(context).primaryColor,
|
||||||
|
leading: IconButton(
|
||||||
|
icon: Icon(Icons.arrow_back, color: Colors.white),
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
backgroundColor: Color(0xFFF5F5F5),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
child: Padding(padding: EdgeInsets.all(5), child: _buildRecipeDetail()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildRecipeDetail() {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
_buildTitleSection(),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
_buildInfoCard(
|
||||||
|
context,
|
||||||
|
icon: Icons.info,
|
||||||
|
title: "基础信息",
|
||||||
|
content: _buildTag(context, title: recipe.category),
|
||||||
|
),
|
||||||
|
_buildInfoCard(
|
||||||
|
context,
|
||||||
|
icon: Icons.shopping_cart,
|
||||||
|
title: "食材信息",
|
||||||
|
content: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildMaterialSection(context, '主料', mainMaterialList),
|
||||||
|
_buildMaterialSection(context, '辅料', auxiliaryMaterialList),
|
||||||
|
_buildMaterialSection(context, '调料', accessoryMaterialList),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_buildInfoCard(
|
||||||
|
context,
|
||||||
|
icon: Icons.list,
|
||||||
|
title: "步骤信息",
|
||||||
|
content: Column(
|
||||||
|
children:
|
||||||
|
recipe.stepList.map((step) => _buildStepSection(step)).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_buildInfoCard(
|
||||||
|
context,
|
||||||
|
icon: Icons.note,
|
||||||
|
title: "其他信息",
|
||||||
|
content: Text(
|
||||||
|
'备注:${recipe.remark.isEmpty ? '无' : recipe.remark}',
|
||||||
|
style: const TextStyle(height: 1.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildTag(BuildContext context, {required String title}) {
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Color.lerp(Theme.of(context).primaryColor, Colors.white, 0.8),
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(color: Theme.of(context).primaryColor),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildTitleSection() {
|
||||||
|
return Text(
|
||||||
|
recipe.name,
|
||||||
|
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildMaterialSection(
|
||||||
|
BuildContext context,
|
||||||
|
String title,
|
||||||
|
List<RecipeMaterial> materials,
|
||||||
|
) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 8, top: 12),
|
||||||
|
child: Text(title, style: TextStyle(fontWeight: FontWeight.bold)),
|
||||||
|
),
|
||||||
|
if (materials.isEmpty)
|
||||||
|
_buildTag(context, title: '无')
|
||||||
|
else
|
||||||
|
Wrap(
|
||||||
|
spacing: 8.0,
|
||||||
|
runSpacing: 8.0,
|
||||||
|
children:
|
||||||
|
materials
|
||||||
|
.map(
|
||||||
|
(m) => _buildTag(context, title: '${m.name} ${m.amount}'),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildStepSection(RecipeStep step) {
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text("第${step.sort + 1}步"),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
step.content,
|
||||||
|
style: const TextStyle(
|
||||||
|
height: 1.4,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
if (step.imageUrl.isNotEmpty)
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: Image.network(
|
||||||
|
step.imageUrl,
|
||||||
|
width: double.infinity,
|
||||||
|
height: 180,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildInfoCard(
|
||||||
|
BuildContext context, {
|
||||||
|
required IconData icon,
|
||||||
|
required String title,
|
||||||
|
required Widget content,
|
||||||
|
}) {
|
||||||
|
return cardContainer(
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(icon, color: Theme.of(context).primaryColor),
|
||||||
|
const SizedBox(width: 5),
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(height: 5),
|
||||||
|
content,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,19 @@ InputDecoration formInputDecoration({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget cardContainer(Widget content) {
|
||||||
|
return Card(
|
||||||
|
elevation: 0,
|
||||||
|
color: Colors.white,
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(10),
|
||||||
|
child: content,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 圆形图标按钮
|
||||||
Widget circleIconButton({
|
Widget circleIconButton({
|
||||||
required IconData icon,
|
required IconData icon,
|
||||||
required VoidCallback onPressed,
|
required VoidCallback onPressed,
|
||||||
@@ -70,6 +83,7 @@ Text buttonText({required String text}) {
|
|||||||
return Text(text, style: TextStyle(color: Colors.white));
|
return Text(text, style: TextStyle(color: Colors.white));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 图片错误显示
|
||||||
Widget errorImageContainer(double height) {
|
Widget errorImageContainer(double height) {
|
||||||
return Container(
|
return Container(
|
||||||
height: 200,
|
height: 200,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import 'package:food_hub_app/widgets/common/image.dart';
|
|||||||
import 'package:food_hub_app/widgets/common/index.dart';
|
import 'package:food_hub_app/widgets/common/index.dart';
|
||||||
|
|
||||||
class RecipeCard extends StatelessWidget {
|
class RecipeCard extends StatelessWidget {
|
||||||
final Recipe recipe;
|
final RecipeSummary recipe;
|
||||||
|
|
||||||
const RecipeCard({super.key, required this.recipe});
|
const RecipeCard({super.key, required this.recipe});
|
||||||
|
|
||||||
@@ -104,7 +104,12 @@ class RecipeCard extends StatelessWidget {
|
|||||||
circleIconButton(
|
circleIconButton(
|
||||||
context: context,
|
context: context,
|
||||||
icon: Icons.book,
|
icon: Icons.book,
|
||||||
onPressed: () => Navigator.pushNamed(context, '/recipeDetail'),
|
onPressed:
|
||||||
|
() => Navigator.pushNamed(
|
||||||
|
context,
|
||||||
|
'/recipeDetail',
|
||||||
|
arguments: {'id': recipe.id},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,227 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:food_hub_app/models/recipe.dart' as recipeModel;
|
|
||||||
|
|
||||||
class RecipeDetail extends StatefulWidget {
|
|
||||||
const RecipeDetail({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<RecipeDetail> createState() => _RecipeDetailState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _RecipeDetailState extends State<RecipeDetail> {
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
recipeModel.Recipe recipe = recipeModel.Recipe(
|
|
||||||
name: '雪糕',
|
|
||||||
category: '冷饮',
|
|
||||||
recommendRate: 4,
|
|
||||||
isShare: true,
|
|
||||||
recordList: [],
|
|
||||||
stepList: [
|
|
||||||
recipeModel.Step(
|
|
||||||
sort: 1,
|
|
||||||
content: '将牛奶倒入锅中,小火加热至微沸',
|
|
||||||
imageUrl: 'https://picsum.photos/400/300?step=1', // 步骤图片URL
|
|
||||||
),
|
|
||||||
recipeModel.Step(sort: 2, content: '你好', imageUrl: ''),
|
|
||||||
],
|
|
||||||
materialList: [],
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text('菜谱信息', style: TextStyle(color: Colors.white)),
|
|
||||||
backgroundColor: Theme.of(context).primaryColor,
|
|
||||||
leading: IconButton(
|
|
||||||
icon: Icon(Icons.arrow_back, color: Colors.white),
|
|
||||||
onPressed: () => Navigator.pop(context),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
backgroundColor: Color(0xFFF5F5F5),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.all(5),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
recipe.name,
|
|
||||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
// 基础信息卡片
|
|
||||||
_buildInfoCard(
|
|
||||||
context,
|
|
||||||
icon: Icons.info,
|
|
||||||
title: "基础信息",
|
|
||||||
content: Column(
|
|
||||||
children: [_buildInfoRow("类别", recipe.category)],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
// 食材信息卡片
|
|
||||||
_buildInfoCard(
|
|
||||||
context,
|
|
||||||
icon: Icons.shopping_cart,
|
|
||||||
title: "食材信息",
|
|
||||||
content: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
_buildMaterialSection("主料", 1),
|
|
||||||
_buildMaterialSection("配料", 2),
|
|
||||||
_buildMaterialSection("辅料", 3),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
// 步骤信息卡片
|
|
||||||
_buildInfoCard(
|
|
||||||
context,
|
|
||||||
icon: Icons.list,
|
|
||||||
title: "步骤信息",
|
|
||||||
content: Column(
|
|
||||||
children:
|
|
||||||
recipe.stepList?.map((step) {
|
|
||||||
return _buildStepSection(step);
|
|
||||||
}).toList() ??
|
|
||||||
[],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
// 其他信息卡片
|
|
||||||
if (recipe.remark != null && recipe.remark!.isNotEmpty)
|
|
||||||
_buildInfoCard(
|
|
||||||
context,
|
|
||||||
icon: Icons.note,
|
|
||||||
title: "其他信息",
|
|
||||||
content: Text(
|
|
||||||
recipe.remark!,
|
|
||||||
style: const TextStyle(height: 1.5),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建食材分类部分
|
|
||||||
Widget _buildMaterialSection(String title, int type) {
|
|
||||||
final materials =
|
|
||||||
recipe.materialList
|
|
||||||
?.where((material) => material.type == type)
|
|
||||||
?.toList() ??
|
|
||||||
[];
|
|
||||||
|
|
||||||
if (materials.isEmpty) return const SizedBox.shrink();
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
|
||||||
child: Text(
|
|
||||||
title,
|
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
...materials.map((material) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 4.0),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
const Icon(Icons.circle, size: 6, color: Colors.grey),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Text("${material.name} ${material.amount ?? ''}"),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildStepSection(recipeModel.Step step) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 16.0),
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text("第${step.sort}步"),
|
|
||||||
SizedBox(width: 10),
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(step.content, style: const TextStyle(height: 1.4, fontWeight: FontWeight.bold)),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
if (step.imageUrl.isNotEmpty)
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
child: Image.network(
|
|
||||||
step.imageUrl,
|
|
||||||
width: double.infinity,
|
|
||||||
height: 180,
|
|
||||||
fit: BoxFit.contain,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建信息行
|
|
||||||
Widget _buildInfoRow(String label, String value) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [Text(label), Text(value)],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 通用卡片组件
|
|
||||||
Widget _buildInfoCard(
|
|
||||||
BuildContext context, {
|
|
||||||
required IconData icon,
|
|
||||||
required String title,
|
|
||||||
required Widget content,
|
|
||||||
}) {
|
|
||||||
return Card(
|
|
||||||
elevation: 0,
|
|
||||||
color: Colors.white,
|
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(10),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Icon(icon, color: Theme.of(context).primaryColor),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Text(
|
|
||||||
title,
|
|
||||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
SizedBox(height: 5),
|
|
||||||
content,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,7 +12,7 @@ class RecipeList extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _RecipeListState extends State<RecipeList> {
|
class _RecipeListState extends State<RecipeList> {
|
||||||
List<Recipe> recipeList = [];
|
List<RecipeSummary> recipeSummaryList = [];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -24,19 +24,19 @@ class _RecipeListState extends State<RecipeList> {
|
|||||||
final result = await queryRecipeApi(RecipeQuery(category: ""));
|
final result = await queryRecipeApi(RecipeQuery(category: ""));
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
recipeList = result;
|
recipeSummaryList = result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (recipeList.isEmpty) {
|
if (recipeSummaryList.isEmpty) {
|
||||||
return const TDEmpty(type: TDEmptyType.plain, emptyText: '暂无数据');
|
return const TDEmpty(type: TDEmptyType.plain, emptyText: '暂无数据');
|
||||||
} else {
|
} else {
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
itemCount: recipeList.length,
|
itemCount: recipeSummaryList.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return RecipeCard(recipe: recipeList[index]);
|
return RecipeCard(recipe: recipeSummaryList[index]);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,9 +33,7 @@ class _RecipeTimeline extends State<RecipeTimeline> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return Column(
|
||||||
padding: EdgeInsets.all(10),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
children: [
|
||||||
YearSelector(
|
YearSelector(
|
||||||
initialYear: DateTime.now().year,
|
initialYear: DateTime.now().year,
|
||||||
@@ -43,10 +41,8 @@ class _RecipeTimeline extends State<RecipeTimeline> {
|
|||||||
maxYear: 2100,
|
maxYear: 2100,
|
||||||
onYearChanged: (year) => refreshRecord(year),
|
onYearChanged: (year) => refreshRecord(year),
|
||||||
),
|
),
|
||||||
SizedBox(height: 10),
|
|
||||||
Expanded(child: timelineContainer(recordList)),
|
Expanded(child: timelineContainer(recordList)),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user