import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:image_picker/image_picker.dart'; import 'package:problem_check_system/controllers/add_problem_controller.dart'; class AddProblemPage extends StatelessWidget { AddProblemPage({super.key}); final AddProblemController controller = Get.put(AddProblemController()); // 显示底部选择器的方法 void _showImageSourceBottomSheet(BuildContext context) { showModalBottomSheet( context: context, shape: RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16.r)), ), builder: (BuildContext context) { return SafeArea( child: Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox(height: 16.h), Text( '选择图片来源', style: TextStyle(fontSize: 18.sp, fontWeight: FontWeight.bold), ), SizedBox(height: 16.h), Divider(height: 1.h), ListTile( leading: Icon(Icons.camera_alt, color: Colors.blue), title: Text('拍照'), onTap: () { Navigator.pop(context); controller.pickImage(ImageSource.camera); }, ), Divider(height: 1.h), ListTile( leading: Icon(Icons.photo_library, color: Colors.blue), title: Text('从相册选择'), onTap: () { Navigator.pop(context); controller.pickImage(ImageSource.gallery); }, ), Divider(height: 1.h), ListTile( leading: Icon(Icons.cancel, color: Colors.grey), title: Text('取消', style: TextStyle(color: Colors.grey)), onTap: () => Navigator.pop(context), ), SizedBox(height: 8.h), ], ), ); }, ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( flexibleSpace: Container( decoration: const BoxDecoration( gradient: LinearGradient( colors: [Color(0xFF418CFC), Color(0xFF3DBFFC)], begin: Alignment.centerLeft, end: Alignment.centerRight, ), ), ), leading: IconButton( icon: const Icon(Icons.arrow_back_ios_new_rounded), color: Colors.white, onPressed: () { Navigator.pop(context); }, ), title: const Text('新增问题', style: TextStyle(color: Colors.white)), centerTitle: true, backgroundColor: Colors.transparent, ), body: Column( children: [ Expanded( child: SingleChildScrollView( child: Column( children: [ Card( margin: EdgeInsets.all(17.w), child: Column( children: [ ListTile( title: const Text( '问题描述', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), subtitle: TextField( maxLines: null, controller: controller.descriptionController, decoration: const InputDecoration( hintText: '请输入问题描述', border: InputBorder.none, ), ), ), ], ), ), Card( margin: EdgeInsets.all(17.w), child: Column( children: [ ListTile( title: const Text( '所在位置', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), subtitle: TextField( maxLines: null, controller: controller.locationController, decoration: const InputDecoration( hintText: '请输入问题所在位置', border: InputBorder.none, ), ), ), ], ), ), Card( margin: EdgeInsets.all(17.w), child: Column( children: [ ListTile( title: const Text( '问题图片', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 8.h), _buildImageGridWithAddButton(context), ], ), ), ], ), ), ], ), ), ), _bottomButton(), ], ), ); } Widget _buildImageGridWithAddButton(BuildContext context) { return Obx(() { // 计算总项目数(图片数 + 添加按钮) int totalItems = controller.selectedImages.length + 1; return GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, crossAxisSpacing: 8.w, mainAxisSpacing: 8.h, childAspectRatio: 1, ), itemCount: totalItems, itemBuilder: (context, index) { // 如果是最后一个项目,显示添加按钮 if (index == controller.selectedImages.length) { return _buildAddImageButton(context); } // 否则显示图片 return _buildImageItem(index); }, ); }); } Widget _buildAddImageButton(BuildContext context) { return InkWell( onTap: () => _showImageSourceBottomSheet(context), child: Container( decoration: BoxDecoration( color: Colors.grey.shade100, borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.grey.shade300, width: 1), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.add_photo_alternate, size: 24.sp, color: Colors.grey.shade600, ), SizedBox(height: 4.h), Text( '添加图片', style: TextStyle(color: Colors.grey.shade600, fontSize: 12.sp), ), ], ), ), ); } Widget _buildImageItem(int index) { return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.grey.shade300), ), child: Stack( children: [ ClipRRect( borderRadius: BorderRadius.circular(8), child: Image.file( File(controller.selectedImages[index].path), width: double.infinity, height: double.infinity, fit: BoxFit.cover, ), ), Positioned( top: 0, right: 0, child: GestureDetector( onTap: () => controller.removeImage(index), child: Container( decoration: const BoxDecoration( color: Colors.black54, shape: BoxShape.circle, ), padding: EdgeInsets.all(4.w), child: Icon(Icons.close, color: Colors.white, size: 16.sp), ), ), ), ], ), ); } Widget _bottomButton() { return Container( width: 375.w, padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.h), decoration: BoxDecoration( color: Colors.grey[200], borderRadius: BorderRadius.only( topLeft: Radius.circular(12.r), topRight: Radius.circular(12.r), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.r), ), padding: EdgeInsets.symmetric(vertical: 12.h), ), onPressed: () { Get.back(); }, child: Text( '取消', style: TextStyle(color: Colors.grey, fontSize: 16.sp), ), ), ), SizedBox(width: 10.w), Expanded( child: Obx( () => ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF418CFC), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.r), ), padding: EdgeInsets.symmetric(vertical: 12.h), ), onPressed: controller.isLoading.value ? null : () { if (controller.descriptionController.text.isEmpty) { Get.snackbar( '提示', '问题描述不能为空', snackPosition: SnackPosition.TOP, backgroundColor: Colors.black87, colorText: Colors.white, ); return; } controller.saveProblem(); }, child: controller.isLoading.value ? SizedBox( width: 20.w, height: 20.h, child: CircularProgressIndicator( strokeWidth: 2, valueColor: const AlwaysStoppedAnimation( Colors.white, ), ), ) : Text( '确定', style: TextStyle(color: Colors.white, fontSize: 16.sp), ), ), ), ), ], ), ); } }