From 41fe9d6a2457c61c8eb653129054d26254b42f0a Mon Sep 17 00:00:00 2001 From: Cxx0822 <1556464090@qq.com> Date: Thu, 20 Nov 2025 22:54:44 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=9B=B4=E6=96=B0=E6=9C=8B=E5=8F=8B?= =?UTF-8?q?=E5=9C=88=E8=A1=A8=E5=8D=95=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/layout/nav_bar.dart | 2 +- lib/views/moment_form.dart | 184 ++++++++++++++++++++++++------------- 2 files changed, 121 insertions(+), 65 deletions(-) diff --git a/lib/layout/nav_bar.dart b/lib/layout/nav_bar.dart index 02a5511..a6e58ab 100644 --- a/lib/layout/nav_bar.dart +++ b/lib/layout/nav_bar.dart @@ -117,7 +117,7 @@ void _handleAddRecord(BuildContext context, FoodProvider provider) { } void _handleAddMoment(BuildContext context, FoodProvider provider) { - provider.resetRecordForm(); + provider.resetMomentForm(); provider.isEditing = false; Navigator.pop(context); Navigator.pushNamed(context, "/momentForm"); diff --git a/lib/views/moment_form.dart b/lib/views/moment_form.dart index 463fa91..619096b 100644 --- a/lib/views/moment_form.dart +++ b/lib/views/moment_form.dart @@ -6,7 +6,6 @@ import 'package:food_hub_app/utils/minio_utils.dart'; import 'package:food_hub_app/widgets/common/form.dart'; import 'package:food_hub_app/widgets/common/image.dart'; import 'package:food_hub_app/widgets/common/index.dart'; - import 'package:provider/provider.dart'; class MomentFormPage extends StatefulWidget { @@ -20,6 +19,78 @@ class _MomentFormPageState extends State { final _formKey = GlobalKey(); final _focusNode = FocusNode(); static const String _contentField = 'content'; + static const int maxContentLength = 200; + static const int maxImageCount = 9; // 最大图片数量 + + Widget _buildContentField() { + return FormBuilderTextField( + name: _contentField, + focusNode: _focusNode, + maxLines: 5, + minLines: 3, + maxLength: maxContentLength, + buildCounter: ( + context, { + required currentLength, + required isFocused, + maxLength, + }) { + return Text( + '$currentLength/$maxContentLength', + style: TextStyle( + color: + currentLength > maxLength! + ? Colors.red + : Theme.of(context).colorScheme.primary, + ), + ); + }, + onChanged: (value) { + setState(() { + // provider.momentFormItem.content = value!; + }); + }, + decoration: buildInputDecoration(context: context, hintText: '请输入朋友圈内容'), + validator: (value) { + if (value == null || value.isEmpty) { + return '请输入朋友圈内容'; + } + if (value.length > maxContentLength) { + // 修正为使用 maxContentLength + return '内容不能超过${maxContentLength}字'; + } + return null; + }, + ); + } + + Widget _buildImageGrid(FoodProvider provider) { + final imageUrls = provider.momentFormItem.imageList; + + return Wrap( + spacing: 8, + runSpacing: 8, + children: [ + ...imageUrls.asMap().entries.map((entry) { + final index = entry.key; + final imageUrl = entry.value; + return Stack( + children: [ + buildImagePreviewItem( + context: context, + imageUrls: imageUrls, + index: index, + onRemoveImage: () => _removeImage(provider, index), + ) + ], + ); + }), + // 上传按钮(如果还有剩余位置) + if (imageUrls.length < maxImageCount) + buildImageUploadButton(onPickImage: () => _pickImages(provider)), + ], + ); + } Widget _buildFormBuilder() { final provider = context.watch(); @@ -29,53 +100,16 @@ class _MomentFormPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - buildFormLabel('内容', required: true), + buildFormLabel('朋友圈内容', required: true), const SizedBox(height: 8), - FormBuilderTextField( - name: _contentField, - focusNode: _focusNode, - onChanged: (value) { - setState(() { - // provider.momentFormItem.content = value!; - }); - }, - decoration: buildInputDecoration( - context: context, - hintText: '请输入朋友圈内容', - prefixIcon: const Icon( - Icons.title, - size: 20, - color: Color(0xFF86909C), - ), - ), - validator: (value) { - if (value == null || value.isEmpty) { - return '请输入菜谱名称'; - } - return null; - }, - ), - - const SizedBox(height: 10), + _buildContentField(), + const SizedBox(height: 20), buildFormLabel('上传图片', required: true), const SizedBox(height: 10), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (provider.recordFormItem.imageUrl.isEmpty) - buildImageUploadButton(onPickImage: () => _pickImage(provider)) - else - buildImagePreviewItem( - context: context, - imageUrls: [provider.recordFormItem.imageUrl], - index: 0, - onRemoveImage: () => _removeImage(provider), - ), - ], - ), + _buildImageGrid(provider), - const SizedBox(height: 10), + const SizedBox(height: 20), buildFormButtonGroup( context: context, onConfirm: () => _submitForm(provider), @@ -85,41 +119,63 @@ class _MomentFormPageState extends State { ); } - /// 选择图片(限制单张) - Future _pickImage(FoodProvider provider) async { + /// 选择多张图片 + Future _pickImages(FoodProvider provider) async { + final currentCount = provider.momentFormItem.imageList.length; + final remainingCount = maxImageCount - currentCount; + + if (remainingCount <= 0) { + showErrorToast('最多只能上传$maxImageCount张图片'); + return; + } + FilePickerResult? result = await FilePicker.platform.pickFiles( type: FileType.custom, allowedExtensions: ['jpg', 'jpeg', 'png'], - allowMultiple: false, + allowMultiple: true, ); if (result != null) { - PlatformFile file = result.files.first; - final fileName = await MinIOHelper().uploadFile(file: file); - setState(() { - provider.recordFormItem.imageUrl = fileName; - }); + // 限制选择数量 + final filesToUpload = result.files.take(remainingCount).toList(); + + // 显示加载提示 + // showLoadingToast('正在上传图片...'); + + try { + final newImageUrls = []; + + // 逐个上传图片 + for (final file in filesToUpload) { + final fileName = await MinIOHelper().uploadFile(file: file); + newImageUrls.add(fileName); + } + + // 更新图片列表 + setState(() { + provider.momentFormItem.imageList.addAll(newImageUrls); + }); + + showSuccessToast('图片上传成功'); + } catch (e) { + showErrorToast('图片上传失败'); + } } } - /// 移除图片 - void _removeImage(FoodProvider provider) { + /// 移除单张图片 + void _removeImage(FoodProvider provider, int index) { setState(() { - provider.recordFormItem.imageUrl = ''; + provider.momentFormItem.imageList.removeAt(index); }); } /// 提交表单 void _submitForm(FoodProvider provider) { if (_formKey.currentState?.saveAndValidate() ?? false) { - if (provider.recordFormItem.imageUrl.isEmpty) { - showErrorToast('请上传图片'); - return; - } - - print(provider.recordFormItem.name); - print(provider.recordFormItem.date); - print(provider.recordFormItem.imageUrl); + // 这里处理表单提交逻辑 + // print('提交内容: ${_formKey.currentState?.value[_contentField]}'); + // print('图片列表: ${provider.recordFormItem.imageUrls}'); } } @@ -132,7 +188,7 @@ class _MomentFormPageState extends State { return Scaffold( appBar: AppBar( - title: Text(title, style: TextStyle(color: Colors.white)), + title: Text(title, style: const TextStyle(color: Colors.white)), backgroundColor: colors.primary, leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.white), @@ -142,7 +198,7 @@ class _MomentFormPageState extends State { backgroundColor: const Color(0xFFF5F5F5), body: SingleChildScrollView( child: Padding( - padding: EdgeInsets.all(5), + padding: const EdgeInsets.all(10), child: BuildCard(child: _buildFormBuilder()), ), ),