diff --git a/lib/app/features/problem/presentation/bindings/problem_form_binding.dart b/lib/app/features/problem/presentation/bindings/problem_form_binding.dart index 42ddb5e..525f1d4 100644 --- a/lib/app/features/problem/presentation/bindings/problem_form_binding.dart +++ b/lib/app/features/problem/presentation/bindings/problem_form_binding.dart @@ -1,5 +1,12 @@ import 'package:get/get.dart'; import 'package:problem_check_system/app/core/models/form_mode.dart'; +import 'package:problem_check_system/app/core/services/database_service.dart'; +import 'package:problem_check_system/app/core/services/http_provider.dart'; +import 'package:problem_check_system/app/features/enterprise/data/datasources/enterprise_local_data_source.dart'; +import 'package:problem_check_system/app/features/enterprise/data/datasources/enterprise_remote_data_source.dart'; +import 'package:problem_check_system/app/features/enterprise/data/repositories_impl/enterprise_repository_impl.dart'; +import 'package:problem_check_system/app/features/enterprise/domain/repositories/enterprise_repository.dart'; +import 'package:problem_check_system/app/features/enterprise/domain/usecases/get_enterprise_list_usecase.dart'; import 'package:problem_check_system/app/features/problem/domain/entities/problem_entity.dart'; import 'package:problem_check_system/app/features/problem/presentation/controllers/problem_form_controller.dart'; @@ -26,8 +33,34 @@ class ProblemFormBinding extends Bindings { } } + Get.put( + EnterpriseLocalDataSourceImpl( + databaseService: Get.find(), + ), + ); + Get.put( + EnterpriseRemoteDataSourceImpl(http: Get.find()), + ); + + Get.put( + EnterpriseRepositoryImpl( + localDataSource: Get.find(), + remoteDataSource: Get.find(), + networkStatusService: Get.find(), + uuid: Get.find(), + ), + ); + + Get.put( + GetEnterpriseListUsecase(repository: Get.find()), + ); + Get.lazyPut( - () => ProblemFormController(problem: problem, formMode: formMode), + () => ProblemFormController( + problem: problem, + formMode: formMode, + getEnterpriseListUsecase: Get.find(), + ), ); } } diff --git a/lib/app/features/problem/presentation/controllers/problem_form_controller.dart b/lib/app/features/problem/presentation/controllers/problem_form_controller.dart index 8fa2a1c..63a36b1 100644 --- a/lib/app/features/problem/presentation/controllers/problem_form_controller.dart +++ b/lib/app/features/problem/presentation/controllers/problem_form_controller.dart @@ -9,6 +9,8 @@ import 'package:path_provider/path_provider.dart'; import 'package:problem_check_system/app/core/models/form_mode.dart'; import 'package:problem_check_system/app/core/models/image_status.dart'; import 'package:problem_check_system/app/core/models/image_metadata_model.dart'; +import 'package:problem_check_system/app/features/enterprise/domain/entities/enterprise_list_item.dart'; +import 'package:problem_check_system/app/features/enterprise/domain/usecases/get_enterprise_list_usecase.dart'; import 'dart:io'; import 'package:problem_check_system/app/features/problem/domain/entities/problem_entity.dart'; import 'package:uuid/uuid.dart'; @@ -24,14 +26,23 @@ class ProblemFormController extends GetxController { return formMode == FormMode.view; } + bool get isShowBindData { + return problem?.bindData != null; + } + final titleName = "问题表单页".obs; final TextEditingController descriptionController = TextEditingController(); final TextEditingController locationController = TextEditingController(); final RxList selectedImages = [].obs; + final GetEnterpriseListUsecase getEnterpriseListUsecase; // 使用依赖注入,便于测试 - ProblemFormController({this.problem, this.formMode = FormMode.view}) { + ProblemFormController({ + this.problem, + this.formMode = FormMode.view, + required this.getEnterpriseListUsecase, + }) { if (problem != null) { if (problem!.bindData != null) { bindInfo = jsonDecode(problem!.bindData!); @@ -50,6 +61,7 @@ class ProblemFormController extends GetxController { @override void onInit() { super.onInit(); + updatePageTitle(); } @override @@ -73,6 +85,11 @@ class ProblemFormController extends GetxController { } } + // 获取企业列表数据 + Future> getAllEnterprises() async { + return await getEnterpriseListUsecase(); + } + // 改进的 pickImage 方法 Future pickImage(ImageSource source) async { try { diff --git a/lib/app/features/problem/presentation/pages/problem_form_page.dart b/lib/app/features/problem/presentation/pages/problem_form_page.dart index a683b7f..b55e9f2 100644 --- a/lib/app/features/problem/presentation/pages/problem_form_page.dart +++ b/lib/app/features/problem/presentation/pages/problem_form_page.dart @@ -24,7 +24,7 @@ class ProblemFormPage extends GetView { child: SingleChildScrollView( child: Column( children: [ - if (controller.problem?.bindData != null) + if (controller.isShowBindData) Container( color: Colors.white, padding: const EdgeInsets.symmetric( @@ -65,6 +65,7 @@ class ProblemFormPage extends GetView { ], ), ), + _buildDropDownCard(title: '企业名称'), _buildInputCard( title: '问题描述', textController: controller.descriptionController, @@ -150,7 +151,7 @@ class ProblemFormPage extends GetView { required String hintText, }) { return Card( - margin: EdgeInsets.all(17.w), + margin: EdgeInsets.all(16.w), child: Column( children: [ ListTile( @@ -179,7 +180,7 @@ class ProblemFormPage extends GetView { /// 构建图片展示卡片 Widget _buildImageCard(BuildContext context) { return Card( - margin: EdgeInsets.all(17.w), + margin: EdgeInsets.all(16.w), child: Column( children: [ const ListTile( @@ -414,4 +415,105 @@ class ProblemFormPage extends GetView { ), ); } + + Widget _buildDropDownCard({required String title}) { + return Card( + // margin 让卡片与屏幕边缘有间距 + margin: const EdgeInsets.all(16.0), + // elevation 控制阴影大小 + elevation: 2, + clipBehavior: Clip.antiAlias, + child: Column( + // mainAxisSize.min 让 Column 的高度自适应内容 + mainAxisSize: MainAxisSize.min, + // crossAxisAlignment.start 让子组件默认左对齐 + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // --- 1. 顶部区域:标签和按钮 --- + _buildTopSection(), + + // 在顶部和底部之间增加一些垂直间距 + const SizedBox(height: 20.0), + + // --- 2. 底部区域:下拉选择器显示 --- + _buildDropdownSelector(), + ], + ), + ); + } + + /// 构建顶部区域的私有方法,包含“企业名称”和“新增企业”按钮 + Widget _buildTopSection() { + return Row( + // [核心] 使用 MainAxisAlignment.spaceBetween 将子组件推向两端 + mainAxisAlignment: MainAxisAlignment.spaceBetween, + // crossAxisAlignment.start 确保按钮和文本在垂直方向上顶部对齐 + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 左侧的标题 + Padding( + padding: EdgeInsetsGeometry.only(left: 16.w, top: 10.5.h), + child: const Text( + '企业名称', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + ), + // 右侧的按钮 + ElevatedButton( + onPressed: () {}, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF42A5F5), + foregroundColor: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 12.h), + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + // [!!!] 移除按钮自身的阴影,因为它现在在卡片内部 + // elevation: 0, + // [!!!] 自定义形状,只保留左下角圆角,以完美贴合卡片边缘 + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(12.r), + ), + ), + ), + child: Text( + "新增企业", + style: TextStyle(fontSize: 13.sp, fontWeight: FontWeight.bold), + ), + ), + ], + ); + } + + /// 构建底部类似下拉菜单的显示区域 + Widget _buildDropdownSelector() { + // 使用 InkWell 包裹,使整个区域都可以响应点击事件 + return InkWell( + onTap: () { + // 在这里处理点击事件,例如弹出一个选择企业的对话框或页面 + print('下拉选择区域被点击'); + }, + // 自定义圆角,使其与外部容器的点击效果一致 + borderRadius: BorderRadius.circular(8.0), + child: Padding( + padding: EdgeInsets.only(left: 16.w, top: 0, right: 16.w, bottom: 16.h), + child: Row( + // 同样使用 spaceBetween 将文本和图标推向两端 + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + // 左侧的企业名称文本 + const Text( + '山东汇丰石化集团有限公司', + style: TextStyle(fontSize: 16, color: Colors.black54), + ), + // 右侧的下拉箭头图标 + Icon(Icons.arrow_drop_down, color: Colors.grey[700]), + ], + ), + ), + ); + } }