From 9d3a3f2e80692032418e1414e9ce2d8fc6d06ea4 Mon Sep 17 00:00:00 2001 From: Cxx0822 <1556464090@qq.com> Date: Tue, 30 Jun 2026 23:26:49 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=9B=B4=E6=96=B0=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E8=8F=9C=E8=B0=B1=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/apis/recipe.dart | 6 +- lib/main.dart | 2 +- lib/models/recipe.dart | 11 +- lib/models/recipe.g.dart | 6 - lib/provider/food_provider.dart | 104 +++++++++ lib/views/profile_user.dart | 16 +- lib/views/recipe_detail.dart | 133 ++++++----- lib/views/recipe_form.dart | 334 ++++++++-------------------- lib/widgets/profile/basic_info.dart | 1 - 9 files changed, 282 insertions(+), 331 deletions(-) diff --git a/lib/apis/recipe.dart b/lib/apis/recipe.dart index da62fe9..960473d 100644 --- a/lib/apis/recipe.dart +++ b/lib/apis/recipe.dart @@ -6,10 +6,10 @@ import 'package:food_hub_app/utils/index.dart'; final httpUtil = HttpUtil(baseUrl: AppConfig.baseApiUrl); -Future queryRecipeByIdApi(int id) { - return httpUtil.get( +Future queryRecipeByIdApi(int id) { + return httpUtil.get( "/food/recipe/$id", - converter: (data) => RecipeDetail.fromJson(data), + converter: (data) => Recipe.fromJson(data), ); } diff --git a/lib/main.dart b/lib/main.dart index 0cecc69..b10ecc9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -24,7 +24,7 @@ void main() async { FormBuilderLocalizations.delegate.load(const Locale('zh', 'CN')); await SPUtil.init(); - // await initLogger(); + await initLogger(); // 预编译 shader,防止首帧白闪 await LiquidGlassWidgets.initialize(); diff --git a/lib/models/recipe.dart b/lib/models/recipe.dart index 3e0957f..6663d2b 100644 --- a/lib/models/recipe.dart +++ b/lib/models/recipe.dart @@ -131,11 +131,8 @@ class Recipe { List stepList; List recordList; List likeList; - int likeCount; List favouriteList; - int favouriteCount; List commentList; - int commentCount; Recipe({ required this.id, @@ -151,11 +148,8 @@ class Recipe { required this.stepList, required this.recordList, required this.likeList, - required this.likeCount, required this.favouriteList, - required this.favouriteCount, required this.commentList, - required this.commentCount, }); factory Recipe.fromJson(Map json) => _$RecipeFromJson(json); @@ -177,11 +171,8 @@ class Recipe { stepList: [], recordList: [], likeList: [], - likeCount: 0, favouriteList: [], - favouriteCount: 0, - commentList: [], - commentCount: 0, + commentList: [] ); } } diff --git a/lib/models/recipe.g.dart b/lib/models/recipe.g.dart index 0cc2b44..708c04a 100644 --- a/lib/models/recipe.g.dart +++ b/lib/models/recipe.g.dart @@ -106,17 +106,14 @@ Recipe _$RecipeFromJson(Map json) => Recipe( (json['likeList'] as List) .map((e) => (e as num).toInt()) .toList(), - likeCount: (json['likeCount'] as num).toInt(), favouriteList: (json['favouriteList'] as List) .map((e) => (e as num).toInt()) .toList(), - favouriteCount: (json['favouriteCount'] as num).toInt(), commentList: (json['commentList'] as List) .map((e) => RecipeComment.fromJson(e as Map)) .toList(), - commentCount: (json['commentCount'] as num).toInt(), ); Map _$RecipeToJson(Recipe instance) => { @@ -133,11 +130,8 @@ Map _$RecipeToJson(Recipe instance) => { 'stepList': instance.stepList, 'recordList': instance.recordList, 'likeList': instance.likeList, - 'likeCount': instance.likeCount, 'favouriteList': instance.favouriteList, - 'favouriteCount': instance.favouriteCount, 'commentList': instance.commentList, - 'commentCount': instance.commentCount, }; RecipeSummary _$RecipeSummaryFromJson(Map json) => diff --git a/lib/provider/food_provider.dart b/lib/provider/food_provider.dart index 4e2452b..894a6aa 100644 --- a/lib/provider/food_provider.dart +++ b/lib/provider/food_provider.dart @@ -66,6 +66,86 @@ class FoodProvider with ChangeNotifier { notifyListeners(); } + void updateRecipeFormItem({ + String? name, + String? category, + double? recommendRate, + String? remark, + bool? isShare, + }) { + if (name != null) recipeFormItem.name = name; + if (category != null) recipeFormItem.category = category; + if (recommendRate != null) recipeFormItem.recommendRate = recommendRate; + if (remark != null) recipeFormItem.remark = remark; + if (isShare != null) recipeFormItem.isShare = isShare; + notifyListeners(); + } + + void addRecipeMaterial() { + recipeFormItem.materialList.add( + RecipeMaterial( + id: DateTime.now().microsecondsSinceEpoch, + type: '主料', + name: '', + amount: '', + ), + ); + notifyListeners(); + } + + void updateRecipeMaterial( + int index, { + String? type, + String? name, + String? amount, + }) { + final material = recipeFormItem.materialList[index]; + recipeFormItem.materialList[index] = RecipeMaterial( + id: material.id, + type: type ?? material.type, + name: name ?? material.name, + amount: amount ?? material.amount, + ); + notifyListeners(); + } + + void removeRecipeMaterial(int index) { + recipeFormItem.materialList.removeAt(index); + notifyListeners(); + } + + void addRecipeStep() { + recipeFormItem.stepList.add( + RecipeStep( + id: DateTime.now().microsecondsSinceEpoch, + sort: recipeFormItem.stepList.length, + content: '', + imageUrl: '', + ), + ); + notifyListeners(); + } + + void updateRecipeStep(int index, {String? content, String? imageUrl}) { + final step = recipeFormItem.stepList[index]; + recipeFormItem.stepList[index] = RecipeStep( + id: step.id, + sort: step.sort, + content: content ?? step.content, + imageUrl: imageUrl ?? step.imageUrl, + ); + } + + void removeRecipeStep(int index) { + recipeFormItem.stepList.removeAt(index); + + for (int i = 0; i < recipeFormItem.stepList.length; i++) { + recipeFormItem.stepList[i].sort = i; + } + + notifyListeners(); + } + void updateRecordFormItem({String? name, String? date, String? imageUrl}) { if (name != null) recordFormItem.name = name; if (date != null) recordFormItem.date = date; @@ -167,6 +247,30 @@ class FoodProvider with ChangeNotifier { } } + Future handleRecipe() async { + if (isLoading) return true; + + try { + isLoading = true; + error = null; + notifyListeners(); + + if (isEditing) { + await updateRecipeApi(recipeFormItem.id!, recipeFormItem); + } else { + await addRecipeApi(recipeFormItem); + } + return true; + } catch (e) { + error = '处理数据失败: $e'; + debugPrint('处理数据失败: $e'); + return false; + } finally { + isLoading = false; + notifyListeners(); + } + } + Future refreshRecordList() async { if (isLoading) return; diff --git a/lib/views/profile_user.dart b/lib/views/profile_user.dart index f71b522..d81e5dd 100644 --- a/lib/views/profile_user.dart +++ b/lib/views/profile_user.dart @@ -1,19 +1,14 @@ import 'package:flutter/material.dart'; -import 'package:flutter_common/utils/sp_utils.dart'; import 'package:flutter_common/widget/common_widget.dart'; -import 'package:flutter_common/widget/dialog_widget.dart'; -import 'package:food_hub_app/models/session.dart'; -import 'package:food_hub_app/provider/app_provider.dart'; import 'package:food_hub_app/provider/user_provider.dart'; import 'package:food_hub_app/widgets/common/index.dart'; import 'package:food_hub_app/widgets/moment/list.dart'; import 'package:food_hub_app/widgets/profile/basic_info.dart'; -import 'package:food_hub_app/widgets/recipe/calendar.dart'; import 'package:food_hub_app/widgets/recipe/list.dart'; -import 'package:food_hub_app/widgets/recipe/timeline.dart'; import 'package:provider/provider.dart'; enum ProfileTab { + profile('基础信息'), moment('朋友圈'), recipe('菜谱'); @@ -30,7 +25,7 @@ class ProfileUserPage extends StatefulWidget { } class ProfileUserPageState extends State { - late ProfileTab currentTab = ProfileTab.moment; + late ProfileTab currentTab = ProfileTab.profile; void _onTabChange(ProfileTab tab) { setState(() { @@ -60,10 +55,6 @@ class ProfileUserPageState extends State { Widget _buildContent(UserProvider provider) { return Column( children: [ - SizedBox( - width: double.infinity, - child: ProfileInfo(user: provider.currentUser), - ), _buildTabs( context: context, currentTab: currentTab, @@ -73,6 +64,9 @@ class ProfileUserPageState extends State { child: IndexedStack( index: currentTab.index, children: [ + SizedBox( + width: double.infinity, child: ProfileInfo(user: provider.currentUser) + ), MomentList(momentList: provider.momentList, isUser: false), RecipeList(userId: provider.currentUser.id!), ], diff --git a/lib/views/recipe_detail.dart b/lib/views/recipe_detail.dart index 0d66111..83bdddd 100644 --- a/lib/views/recipe_detail.dart +++ b/lib/views/recipe_detail.dart @@ -2,8 +2,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_common/widget/common_widget.dart'; import 'package:food_hub_app/apis/recipe.dart'; import 'package:food_hub_app/models/recipe.dart'; +import 'package:food_hub_app/provider/food_provider.dart'; import 'package:food_hub_app/utils/screenshot_util.dart'; +import 'package:food_hub_app/views/recipe_form.dart'; import 'package:food_hub_app/widgets/common/index.dart'; +import 'package:provider/provider.dart'; class RecipeDetailPage extends StatefulWidget { const RecipeDetailPage({super.key}); @@ -13,14 +16,11 @@ class RecipeDetailPage extends StatefulWidget { } class _RecipeDetailState extends State { - RecipeDetail recipe = RecipeDetail.getEmpty(); + Recipe recipe = Recipe.getEmpty(); final GlobalKey _recipeDetailKey = GlobalKey(); bool _isSharing = false; - // 定义三个分类列表 - List mainMaterialList = []; // 主料 - List auxiliaryMaterialList = []; // 配料 - List accessoryMaterialList = []; // 辅料 + List materialList = []; @override void didChangeDependencies() { @@ -40,25 +40,29 @@ class _RecipeDetailState extends State { } void getRecipeMaterial() { - mainMaterialList.clear(); - auxiliaryMaterialList.clear(); - accessoryMaterialList.clear(); + materialList.clear(); for (var material in recipe.materialList) { - switch (material.type) { - case '主料': - mainMaterialList.add(material); - break; - case '配料': - auxiliaryMaterialList.add(material); - break; - case '辅料': - accessoryMaterialList.add(material); - break; - } + materialList.add(material); } } + void _handleEditRecipe(FoodProvider provider) { + provider.initRecipeForm(recipe); + provider.isEditing = true; + + showModalBottomSheet( + context: context, + constraints: BoxConstraints(minHeight: 600), + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + isScrollControlled: true, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(16)), + ), + builder: (context) => RecipeForm(), + ); + } + // 分享图片 Future _shareRecipeAsImage() async { if (_isSharing) return; @@ -83,6 +87,7 @@ class _RecipeDetailState extends State { @override Widget build(BuildContext context) { final colors = Theme.of(context).colorScheme; + final provider = context.watch(); return Scaffold( appBar: AppBar( @@ -104,7 +109,7 @@ class _RecipeDetailState extends State { child: _buildRecipeDetail(), ), ), - _buildButtons(), + _buildButtons(provider), ], ), ), @@ -121,7 +126,23 @@ class _RecipeDetailState extends State { context, icon: Icons.info, title: "基础信息", - content: buildTag(context, recipe.category), + content: Text(recipe.category), + ), + SizedBox(height: 8), + _buildInfoCard( + context, + icon: Icons.star, + title: "推荐指数", + content: Row( + mainAxisSize: MainAxisSize.min, + children: List.generate(5, (index) { + return Icon( + index < recipe.recommendRate ? Icons.star : Icons.star_border, + color: Theme.of(context).primaryColor, + size: 20, + ); + }), + ), ), SizedBox(height: 8), _buildInfoCard( @@ -130,11 +151,7 @@ class _RecipeDetailState extends State { title: "食材信息", content: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildMaterialSection(context, '主料', mainMaterialList), - _buildMaterialSection(context, '辅料', auxiliaryMaterialList), - _buildMaterialSection(context, '调料', accessoryMaterialList), - ], + children: [_buildMaterialSection(materialList)], ), ), SizedBox(height: 8), @@ -142,10 +159,7 @@ class _RecipeDetailState extends State { context, icon: Icons.list, title: "步骤信息", - content: Column( - children: - recipe.stepList.map((step) => _buildStepSection(step)).toList(), - ), + content: Column(children: [_buildStepSection(recipe.stepList)]), ), SizedBox(height: 8), _buildInfoCard( @@ -168,34 +182,43 @@ class _RecipeDetailState extends State { ); } - Widget _buildMaterialSection( - BuildContext context, - String title, - List materials, - ) { + Widget _buildMaterialSection(List 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, '无') else - Wrap( + Column( + crossAxisAlignment: CrossAxisAlignment.start, spacing: 8.0, - runSpacing: 8.0, - children: - materials - .map((m) => buildTag(context, '${m.name} ${m.amount}')) - .toList(), + children: materials.map((m) => _buildMaterialItem(m)).toList(), ), ], ); } - Widget _buildStepSection(RecipeStep step) { + Widget _buildMaterialItem(RecipeMaterial material) { + return Text('${material.name} ${material.amount}'); + } + + Widget _buildStepSection(List steps) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (steps.isEmpty) + buildTag(context, '无') + else + Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 8.0, + children: steps.map((m) => _buildStepItem(m)).toList(), + ), + ], + ); + } + + Widget _buildStepItem(RecipeStep step) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -213,16 +236,6 @@ class _RecipeDetailState extends State { ), ), 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, - ), - ), ], ), ), @@ -257,10 +270,16 @@ class _RecipeDetailState extends State { ); } - Widget _buildButtons() { + Widget _buildButtons(FoodProvider provider) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ + circleIconButton( + context: context, + icon: Icons.edit, + onPressed: () => _handleEditRecipe(provider), + ), + SizedBox(width: 8), circleIconButton( context: context, icon: _isSharing ? Icons.hourglass_top : Icons.share, diff --git a/lib/views/recipe_form.dart b/lib/views/recipe_form.dart index 4dc14db..dd1d971 100644 --- a/lib/views/recipe_form.dart +++ b/lib/views/recipe_form.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_common/widget/dialog_widget.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:food_hub_app/models/recipe.dart'; import 'package:food_hub_app/provider/food_provider.dart'; @@ -21,10 +22,6 @@ class RecipeForm extends StatefulWidget { class _RecipeFormState extends State { final _formKey = GlobalKey(); int _currentStep = 0; - List _materials = []; - List _materialZhuliaos = []; - List _materialFuliaos = []; - List _steps = []; // 表单字段名称常量 static const String _nameField = 'name'; @@ -54,18 +51,18 @@ class _RecipeFormState extends State { Widget _buildStepContent(FoodProvider provider) { switch (_currentStep) { case 0: - return _buildBasicInfoStep(provider); + return _buildInfo(provider); case 1: - return _buildMaterialsStep(); + return _buildMaterials(provider); case 2: - return _buildStepsStep(); + return _buildSteps(provider); default: - return _buildBasicInfoStep(provider); + return _buildInfo(provider); } } // 第一步:基本信息 - Widget _buildBasicInfoStep(FoodProvider provider) { + Widget _buildInfo(FoodProvider provider) { return SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -80,6 +77,9 @@ class _RecipeFormState extends State { hintText: '请输入菜谱名称', prefixIcon: Icons.restaurant_menu, ), + onChanged: (value) { + provider.updateRecipeFormItem(name: value ?? ''); + }, validator: FormBuilderValidators.compose([ FormBuilderValidators.required(errorText: '菜谱名称不能为空'), FormBuilderValidators.maxLength(50, errorText: '名称不能超过50个字符'), @@ -106,6 +106,9 @@ class _RecipeFormState extends State { ), ) .toList(), + onChanged: (value) { + provider.updateRecipeFormItem(category: value ?? ''); + }, validator: FormBuilderValidators.required(errorText: '请选择分类'), ), const SizedBox(height: 16), @@ -120,6 +123,9 @@ class _RecipeFormState extends State { divisions: 4, activeColor: Theme.of(context).colorScheme.primary, decoration: const InputDecoration(border: InputBorder.none), + onChanged: (value) { + provider.updateRecipeFormItem(recommendRate: value ?? 0); + }, ), const SizedBox(height: 16), @@ -133,6 +139,9 @@ class _RecipeFormState extends State { context: context, hintText: '请输入菜谱的特别说明或小贴士', ), + onChanged: (value) { + provider.updateRecipeFormItem(remark: value ?? ''); + }, ), const SizedBox(height: 16), @@ -140,6 +149,9 @@ class _RecipeFormState extends State { name: _isShareField, initialValue: provider.recipeFormItem.isShare, title: const Text('公开分享此菜谱'), + onChanged: (value) { + provider.updateRecipeFormItem(isShare: value ?? false); + }, ), ], ), @@ -147,7 +159,9 @@ class _RecipeFormState extends State { } // 第二步:食材清单 - Widget _buildMaterialsStep() { + Widget _buildMaterials(FoodProvider provider) { + final materials = provider.recipeFormItem.materialList; + return SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -161,12 +175,12 @@ class _RecipeFormState extends State { Icons.add, color: Theme.of(context).colorScheme.primary, ), - onPressed: _addMaterial, + onPressed: () => provider.addRecipeMaterial(), tooltip: '添加食材', ), ], ), - if (_materials.isEmpty) + if (materials.isEmpty) Container( color: Theme.of(context).colorScheme.surface, margin: EdgeInsets.only(bottom: 10), @@ -185,24 +199,28 @@ class _RecipeFormState extends State { else Column( children: - _materials.asMap().entries.map((entry) { - final index = entry.key; - final material = entry.value; + materials.asMap().entries.map((entry) { + final index = entry.key; + final material = entry.value; - return Column( - children: [ - _buildMaterialItem(index, material), - const SizedBox(height: 8) - ], - ); - }).toList(), + return Column( + children: [ + _buildMaterialItem(index, material, provider), + const SizedBox(height: 8), + ], + ); + }).toList(), ), ], ), ); } - Widget _buildMaterialItem(int index, RecipeMaterial material) { + Widget _buildMaterialItem( + int index, + RecipeMaterial material, + FoodProvider provider, + ) { return Column( key: ValueKey(material.id), children: [ @@ -217,7 +235,7 @@ class _RecipeFormState extends State { prefixIcon: Icons.content_paste, ), onChanged: (value) { - _updateMaterial(index, name: value); + provider.updateRecipeMaterial(index, name: value); }, ), ), @@ -231,13 +249,13 @@ class _RecipeFormState extends State { prefixIcon: Icons.scale, ), onChanged: (value) { - _updateMaterial(index, amount: value); + provider.updateRecipeMaterial(index, amount: value); }, ), ), IconButton( icon: const Icon(Icons.delete, color: Colors.red, size: 20), - onPressed: () => _removeMaterial(index), + onPressed: () => provider.removeRecipeMaterial(index), ), ], ), @@ -245,44 +263,10 @@ class _RecipeFormState extends State { ); } - void _addMaterial() { - setState(() { - _materials.add( - RecipeMaterial( - id: DateTime.now().microsecondsSinceEpoch, - type: '主料', - name: '', - amount: '', - ), - ); - }); - } - - void _removeMaterial(int index) { - setState(() { - _materials.removeAt(index); - }); - } - - void _updateMaterial( - int index, { - String? type, - String? name, - String? amount, - }) { - setState(() { - final material = _materials[index]; - _materials[index] = RecipeMaterial( - id: material.id, - type: type ?? material.type, - name: name ?? material.name, - amount: amount ?? material.amount, - ); - }); - } - // 第三步:制作步骤 - Widget _buildStepsStep() { + Widget _buildSteps(FoodProvider provider) { + final steps = provider.recipeFormItem.stepList; + return SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -296,12 +280,12 @@ class _RecipeFormState extends State { Icons.add, color: Theme.of(context).colorScheme.primary, ), - onPressed: _addStep, + onPressed: () => provider.addRecipeStep(), tooltip: '添加步骤', ), ], ), - if (_steps.isEmpty) + if (steps.isEmpty) Container( color: Theme.of(context).colorScheme.surface, margin: EdgeInsets.only(bottom: 10), @@ -320,24 +304,24 @@ class _RecipeFormState extends State { else Column( children: - _steps.asMap().entries.map((entry) { - final index = entry.key; - final step = entry.value; + steps.asMap().entries.map((entry) { + final index = entry.key; + final step = entry.value; - return Column( - children: [ - _buildStepItem(index, step), - const SizedBox(height: 8) - ], - ); - }).toList(), + return Column( + children: [ + _buildStepItem(index, step, provider), + const SizedBox(height: 8), + ], + ); + }).toList(), ), ], ), ); } - Widget _buildStepItem(int index, RecipeStep step) { + Widget _buildStepItem(int index, RecipeStep step, FoodProvider provider) { return Row( key: ValueKey(step.id), crossAxisAlignment: CrossAxisAlignment.center, @@ -369,81 +353,22 @@ class _RecipeFormState extends State { decoration: buildInputDecoration( context: context, hintText: '请输入内容', - prefixIcon: Icons.content_paste + prefixIcon: Icons.content_paste, ), onChanged: (value) { - _updateStep(index, content: value); + provider.updateRecipeStep(index, content: value); }, ), ), // 删除按钮 IconButton( icon: const Icon(Icons.delete, color: Colors.red), - onPressed: () => _removeStep(index), + onPressed: () => provider.removeRecipeStep(index), ), ], ); } - void _addStep() { - setState(() { - _steps.add( - RecipeStep( - id: DateTime.now().microsecondsSinceEpoch, - sort: _steps.length, - content: '', - imageUrl: '', - ), - ); - }); - } - - void _removeStep(int index) { - setState(() { - _steps.removeAt(index); - // // 重新排序 - // for (int i = 0; i < _steps.length; i++) { - // _steps[i] = RecipeStep( - // id: DateTime.now().microsecond, - // sort: i, - // content: _steps[i].content, - // imageUrl: _steps[i].imageUrl, - // ); - // } - }); - } - - void _reorderStep(int oldIndex, int newIndex) { - setState(() { - if (oldIndex < newIndex) { - newIndex -= 1; - } - final RecipeStep item = _steps.removeAt(oldIndex); - _steps.insert(newIndex, item); - // 更新排序序号 - for (int i = 0; i < _steps.length; i++) { - _steps[i] = RecipeStep( - id: DateTime.now().microsecond, - sort: i, - content: _steps[i].content, - imageUrl: _steps[i].imageUrl, - ); - } - }); - } - - void _updateStep(int index, {String? content, String? imageUrl}) { - setState(() { - final step = _steps[index]; - _steps[index] = RecipeStep( - id: step.id, - sort: step.sort, - content: content ?? step.content, - imageUrl: imageUrl ?? step.imageUrl, - ); - }); - } - // 步骤指示器 Widget _buildStepIndicator() { return Container( @@ -545,7 +470,7 @@ class _RecipeFormState extends State { } // 导航按钮 - Widget _buildNavigationButtons() { + Widget _buildNavigationButtons(FoodProvider provider) { final isLastStep = _currentStep == 2; final isFirstStep = _currentStep == 0; @@ -563,15 +488,15 @@ class _RecipeFormState extends State { Expanded( child: buildPrimaryButton( context: context, - text: isLastStep ? '完成创建' : '下一步', - onPressed: _nextStep, + text: isLastStep ? '提交' : '下一步', + onPressed: () => _nextStep(provider), ), ), ], ); } - void _nextStep() { + void _nextStep(FoodProvider provider) { if (_currentStep < 2) { if (_formKey.currentState?.saveAndValidate() ?? false) { setState(() { @@ -579,7 +504,7 @@ class _RecipeFormState extends State { }); } } else { - _submitForm(); + _submitForm(provider); } } @@ -591,112 +516,37 @@ class _RecipeFormState extends State { } } - bool _validateCurrentStep() { - return true; - switch (_currentStep) { - case 0: - // 验证基本信息 - final name = - _formKey.currentState?.fields[_nameField]?.value?.toString() ?? ''; - final category = - _formKey.currentState?.fields[_categoryField]?.value?.toString() ?? - ''; - - if (name.isEmpty) { - ToastUtil.error('请输入菜谱名称'); - return false; - } - if (category.isEmpty) { - ToastUtil.error('请选择分类'); - return false; - } - return true; - - case 1: - // 验证食材清单 - if (_materials.isEmpty) { - ToastUtil.error('请至少添加一个食材'); - return false; - } - - for (var material in _materials) { - if (material.name.isEmpty || material.amount.isEmpty) { - ToastUtil.error('请完善食材信息'); - return false; - } - } - return true; - - case 2: - // 验证制作步骤 - if (_steps.isEmpty) { - ToastUtil.error('请至少添加一个制作步骤'); - return false; - } - - for (var step in _steps) { - if (step.content.isEmpty) { - ToastUtil.error('请完善步骤说明'); - return false; - } - } - return true; - - default: - return true; - } - } - - void _submitForm() { + void _submitForm(FoodProvider provider) async { if (_formKey.currentState?.saveAndValidate() ?? false) { - if (_validateCurrentStep()) { - final formData = _formKey.currentState!.value; + LoadingDialog.show(context, message: '提交中'); + final result = await provider.handleRecipe(); + if (result == true) { + LoadingDialog.hide(context); - // 构建完整的RecipeDetail对象 - // final recipe = RecipeDetail( - // id: widget.initialData?.id ?? 0, - // name: formData[_nameField], - // category: formData[_categoryField], - // recommendRate: formData[_recommendRateField] ?? 3.0, - // remark: formData[_remarkField] ?? '', - // isShare: formData[_isShareField] ?? false, - // userId: widget.initialData?.userId ?? 0, - // username: widget.initialData?.username ?? '', - // avatar: widget.initialData?.avatar ?? '', - // materialList: _materials, - // stepList: _steps, - // recordList: widget.initialData?.recordList ?? [], - // likeList: widget.initialData?.likeList ?? [], - // favouriteList: widget.initialData?.favouriteList ?? [], - // commentList: widget.initialData?.commentList ?? [], - // ); - // - // _saveRecipe(recipe); + if (provider.isEditing) { + showSuccessTip(context, '更新菜谱成功'); + } else { + showSuccessTip(context, '新增菜谱成功'); + } + + Future.delayed(Duration(milliseconds: 1500), () { + if (mounted) { + Navigator.pop(context); + } + }); + } else { + LoadingDialog.hide(context); + if (provider.isEditing) { + showErrorTip(context, '更新菜谱失败'); + } else { + showErrorTip(context, '新增菜谱失败'); + } } } else { ToastUtil.error('请检查表单填写是否正确'); } } - void _saveRecipe(RecipeDetail recipe) { - LoadingDialog.show(context, message: '提交中'); - - // 模拟保存操作 - // Future.delayed(const Duration(seconds: 2), () { - // LoadingDialog.hide(context); - // - // if (mounted) { - // ToastUtil.success(widget.initialData == null ? '菜谱创建成功!' : '菜谱更新成功!'); - // - // Future.delayed(const Duration(milliseconds: 1500), () { - // if (mounted) { - // Navigator.pop(context); - // } - // }); - // } - // }); - } - @override Widget build(BuildContext context) { final provider = context.watch(); @@ -713,7 +563,7 @@ class _RecipeFormState extends State { children: [ _buildStepIndicator(), FormBuilder(key: _formKey, child: _buildStepContent(provider)), - _buildNavigationButtons(), + _buildNavigationButtons(provider), ], ), ), diff --git a/lib/widgets/profile/basic_info.dart b/lib/widgets/profile/basic_info.dart index e16317d..771c19f 100644 --- a/lib/widgets/profile/basic_info.dart +++ b/lib/widgets/profile/basic_info.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_common/utils/date_utils.dart'; -import 'package:flutter_common/widget/common_widget.dart'; import 'package:food_hub_app/config/app_config.dart'; import 'package:food_hub_app/models/session.dart'; import 'package:food_hub_app/widgets/common/index.dart';