You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
348 lines
11 KiB
348 lines
11 KiB
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<Color>( |
|
Colors.white, |
|
), |
|
), |
|
) |
|
: Text( |
|
'确定', |
|
style: TextStyle(color: Colors.white, fontSize: 16.sp), |
|
), |
|
), |
|
), |
|
), |
|
], |
|
), |
|
); |
|
} |
|
}
|
|
|