From 6260db845c10f90ca0a62b409888fc72e083df8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=8C=AF=E5=8D=87?= <359059686@qq.com> Date: Wed, 22 Oct 2025 17:33:30 +0800 Subject: [PATCH] =?UTF-8?q?refactor=20:=20=E4=BC=81=E4=B8=9A=E8=A1=A8?= =?UTF-8?q?=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/app/core/routes/app_pages.dart | 2 + .../bindings/enterprise_form_binding.dart | 8 - .../bindings/enterprise_info_binding.dart | 10 + .../enterprise_form_controller.dart | 121 ++++++--- .../enterprise_info_controller.dart | 8 + .../enterprise_list_controller.dart | 15 +- .../pages/enterprise_form_page.dart | 246 +---------------- .../pages/enterprise_info_page.dart | 5 +- .../pages/enterprise_list_page.dart | 2 +- .../presentation/widgets/enterprise_card.dart | 1 - .../widgets/enterprise_form_view.dart | 257 ++++++++++++++++++ 11 files changed, 382 insertions(+), 293 deletions(-) create mode 100644 lib/app/features/enterprise/presentation/bindings/enterprise_info_binding.dart create mode 100644 lib/app/features/enterprise/presentation/controllers/enterprise_info_controller.dart create mode 100644 lib/app/features/enterprise/presentation/widgets/enterprise_form_view.dart diff --git a/lib/app/core/routes/app_pages.dart b/lib/app/core/routes/app_pages.dart index e2d22e2..4289809 100644 --- a/lib/app/core/routes/app_pages.dart +++ b/lib/app/core/routes/app_pages.dart @@ -1,5 +1,6 @@ import 'package:get/get.dart'; import 'package:problem_check_system/app/features/enterprise/presentation/bindings/enterprise_form_binding.dart'; +import 'package:problem_check_system/app/features/enterprise/presentation/bindings/enterprise_info_binding.dart'; import 'package:problem_check_system/app/features/enterprise/presentation/pages/enterprise_form_page.dart'; import 'package:problem_check_system/app/features/navigation/presentation/bindings/navigation_binding.dart'; import 'package:problem_check_system/app/features/navigation/presentation/pages/navigation_page.dart'; @@ -52,6 +53,7 @@ abstract class AppPages { GetPage( name: AppRoutes.enterpriseInfo, page: () => const EnterpriseInfoPage(), + binding: EnterpriseInfoBinding(), ), GetPage( name: AppRoutes.enterpriseForm, diff --git a/lib/app/features/enterprise/presentation/bindings/enterprise_form_binding.dart b/lib/app/features/enterprise/presentation/bindings/enterprise_form_binding.dart index 9492ffb..2d532cf 100644 --- a/lib/app/features/enterprise/presentation/bindings/enterprise_form_binding.dart +++ b/lib/app/features/enterprise/presentation/bindings/enterprise_form_binding.dart @@ -5,7 +5,6 @@ import 'package:problem_check_system/app/core/services/database_service.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/entities/enterprise.dart'; import 'package:problem_check_system/app/features/enterprise/domain/repositories/enterprise_repository.dart'; import 'package:problem_check_system/app/features/enterprise/domain/usecases/add_enterprise_usecase.dart'; import 'package:problem_check_system/app/features/enterprise/domain/usecases/editor_enterprise_usecase.dart'; @@ -15,12 +14,6 @@ import 'package:uuid/uuid.dart'; // 确保导入您的模型 class EnterpriseFormBinding extends Bindings { @override void dependencies() { - // 1. 尝试从路由参数中获取 Enterprise 对象。 - // - 如果是修改模式,Get.arguments 会是您传入的 Enterprise 对象。 - // - 如果是新增模式,Get.arguments 会是 null。 - // - 使用 as Enterprise? 进行安全的类型转换。 - final Enterprise? enterpriseToEdit = Get.arguments as Enterprise?; - Get.lazyPut( () => EnterpriseLocalDataSourceImpl( databaseService: Get.find(), @@ -48,7 +41,6 @@ class EnterpriseFormBinding extends Bindings { // 2. 将获取到的参数(可能为 null)传递给 Controller 的构造函数。 Get.lazyPut( () => EnterpriseFormController( - initialData: enterpriseToEdit, addEnterpriseUsecase: Get.find(), editEnterpriseUsecase: Get.find(), ), diff --git a/lib/app/features/enterprise/presentation/bindings/enterprise_info_binding.dart b/lib/app/features/enterprise/presentation/bindings/enterprise_info_binding.dart new file mode 100644 index 0000000..a4921c0 --- /dev/null +++ b/lib/app/features/enterprise/presentation/bindings/enterprise_info_binding.dart @@ -0,0 +1,10 @@ +import 'package:get/get.dart'; +import 'package:problem_check_system/app/features/enterprise/presentation/controllers/enterprise_form_controller.dart'; + +class EnterpriseInfoBinding extends Bindings { + @override + void dependencies() { + // 2. 将获取到的参数(可能为 null)传递给 Controller 的构造函数。 + Get.lazyPut(() => EnterpriseFormController()); + } +} diff --git a/lib/app/features/enterprise/presentation/controllers/enterprise_form_controller.dart b/lib/app/features/enterprise/presentation/controllers/enterprise_form_controller.dart index 261dd4b..b3afe1c 100644 --- a/lib/app/features/enterprise/presentation/controllers/enterprise_form_controller.dart +++ b/lib/app/features/enterprise/presentation/controllers/enterprise_form_controller.dart @@ -5,22 +5,38 @@ import 'package:problem_check_system/app/features/enterprise/domain/entities/ent import 'package:problem_check_system/app/features/enterprise/domain/usecases/add_enterprise_usecase.dart'; import 'package:problem_check_system/app/features/enterprise/domain/usecases/editor_enterprise_usecase.dart'; +enum FormMode { + /// 新增 + add, + + /// 编辑 + edit, + + /// 查看 + view, +} + class EnterpriseFormController extends GetxController { - // 通过构造函数接收可能存在的初始数据 - final Enterprise? initialData; - final AddEnterpriseUsecase addEnterpriseUsecase; - final EditEnterpriseUsecase editEnterpriseUsecase; + final AddEnterpriseUsecase? addEnterpriseUsecase; + final EditEnterpriseUsecase? editEnterpriseUsecase; + final formKey = GlobalKey(); + Enterprise? enterprise; + + /// 表单模式 + final Rx formMode = FormMode.add.obs; + + bool get isReadOnly { + return formMode.value == FormMode.view; + } EnterpriseFormController({ - this.initialData, - required this.addEnterpriseUsecase, - required this.editEnterpriseUsecase, + this.addEnterpriseUsecase, + this.editEnterpriseUsecase, }); // --- 状态管理 --- var isSubmitting = false.obs; - var isEditMode = false.obs; var pageTitle = '新增企业'.obs; final Rx selectedType = Rx(null); final Rx selectedScope = Rx(null); @@ -39,44 +55,75 @@ class EnterpriseFormController extends GetxController { @override void onInit() { super.onInit(); - // 判断是新增还是修改模式 - if (initialData != null) { - isEditMode.value = true; - pageTitle.value = '修改信息'; - // 用初始数据填充表单 - enterpriseNameController.text = initialData!.name; - enterpriseAddressController.text = initialData!.address ?? ''; - contactPersonController.text = initialData!.contactPerson ?? ''; - contactPhoneController.text = initialData!.contactPhone ?? ''; - hazardSourceController.text = initialData!.majorHazardsDescription ?? ''; - selectedType.value = CompanyType.values.firstWhereOrNull( - (e) => e.displayText == initialData!.type, - ); - selectedScope.value = CompanyScope.values.firstWhereOrNull( - (e) => e.displayText == initialData!.scale, - ); - } else { - isEditMode.value = false; - pageTitle.value = '新增企业'; - // 新增模式,表单为空 (或有默认值) + if (Get.arguments is Map) { + final arguments = Get.arguments as Map; + + // 设置模式 + if (arguments.containsKey('mode')) { + formMode.value = arguments['mode']; + } + + // 如果是编辑或查看模式,需要填充数据 + if (arguments.containsKey('data')) { + enterprise = arguments['data'] as Enterprise; + populateForm(); + } + updatePageTitle(); } } + void updatePageTitle() { + switch (formMode.value) { + case FormMode.add: + pageTitle.value = '新增企业'; + break; + case FormMode.edit: + pageTitle.value = '修改企业信息'; + break; + case FormMode.view: + pageTitle.value = '查看企业信息'; + break; + } + } + + // 一个用于填充表单数据的方法 + void populateForm() { + pageTitle.value = '修改信息'; + // 用初始数据填充表单 + enterpriseNameController.text = enterprise!.name; + enterpriseAddressController.text = enterprise!.address ?? ''; + contactPersonController.text = enterprise!.contactPerson ?? ''; + contactPhoneController.text = enterprise!.contactPhone ?? ''; + hazardSourceController.text = enterprise!.majorHazardsDescription ?? ''; + selectedType.value = CompanyType.values.firstWhereOrNull( + (e) => e.displayText == enterprise!.type, + ); + selectedScope.value = CompanyScope.values.firstWhereOrNull( + (e) => e.displayText == enterprise!.scale, + ); + } + // 提交表单的逻辑 void submitForm() { if (formKey.currentState?.validate() ?? false) { - if (isEditMode.value) { - _updateEnterprise(); - } else { - _createEnterprise(); + switch (formMode.value) { + case FormMode.add: + _createEnterprise(); + break; + case FormMode.edit: + _updateEnterprise(); + break; + case FormMode.view: + return; } } } void _createEnterprise() async { try { + if (addEnterpriseUsecase == null) return; isSubmitting.value = true; // 开始提交,显示加载 - await addEnterpriseUsecase( + await addEnterpriseUsecase!( name: enterpriseNameController.text, type: selectedType.value!.displayText, address: enterpriseAddressController.text, @@ -99,8 +146,8 @@ class EnterpriseFormController extends GetxController { } void _updateEnterprise() async { - // 确保 initialData 不为 null,这是编辑模式的前提 - if (initialData == null) return; + // 确保 enterprise 不为 null,这是编辑模式的前提 + if (enterprise == null || editEnterpriseUsecase == null) return; try { // 1. 开始提交,更新 UI 状态 (例如显示加载动画) @@ -109,7 +156,7 @@ class EnterpriseFormController extends GetxController { // 2. 从 UI 收集更新后的数据,并与原始数据合并 // 使用我们在 Usecase 步骤中创建的 copyWith 方法,这非常方便! // 它能保留 id, creationTime 等不变的字段。 - final updatedEnterprise = initialData!.copyWith( + final updatedEnterprise = enterprise!.copyWith( name: enterpriseNameController.text, type: selectedType.value!.displayText, address: enterpriseAddressController.text, @@ -120,7 +167,7 @@ class EnterpriseFormController extends GetxController { ); // 3. 调用 EditEnterpriseUsecase - await editEnterpriseUsecase(updatedEnterprise); + await editEnterpriseUsecase!(updatedEnterprise); // 4. 操作成功,返回上一页并通知列表刷新 Get.back(result: true); diff --git a/lib/app/features/enterprise/presentation/controllers/enterprise_info_controller.dart b/lib/app/features/enterprise/presentation/controllers/enterprise_info_controller.dart new file mode 100644 index 0000000..4906def --- /dev/null +++ b/lib/app/features/enterprise/presentation/controllers/enterprise_info_controller.dart @@ -0,0 +1,8 @@ +import 'package:get/get.dart'; +import 'package:problem_check_system/app/features/enterprise/presentation/controllers/enterprise_form_controller.dart'; + +class EnterpriseInfoController extends GetxController { + EnterpriseInfoController({required this.enterpriseFormController}); + + final EnterpriseFormController enterpriseFormController; +} diff --git a/lib/app/features/enterprise/presentation/controllers/enterprise_list_controller.dart b/lib/app/features/enterprise/presentation/controllers/enterprise_list_controller.dart index d6cccae..d57d598 100644 --- a/lib/app/features/enterprise/presentation/controllers/enterprise_list_controller.dart +++ b/lib/app/features/enterprise/presentation/controllers/enterprise_list_controller.dart @@ -7,6 +7,7 @@ import 'package:problem_check_system/app/core/routes/app_routes.dart'; import 'package:problem_check_system/app/features/enterprise/domain/entities/enterprise.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 'package:problem_check_system/app/features/enterprise/presentation/controllers/enterprise_form_controller.dart'; class EnterpriseListController extends GetxController { // --- 状态管理 --- @@ -75,7 +76,7 @@ class EnterpriseListController extends GetxController { Future navigateToEditForm(Enterprise enterprise) async { final result = await Get.toNamed( AppRoutes.enterpriseForm, - arguments: enterprise, // 将要编辑的数据作为参数传递 + arguments: {'data': enterprise, 'mode': FormMode.edit}, // 将要编辑的数据作为参数传递 ); if (result == true) { refreshList(); // 调用控制器的方法刷新 @@ -84,7 +85,10 @@ class EnterpriseListController extends GetxController { /// 导航到新增表单页面 Future navigateToAddForm() async { - final result = await Get.toNamed(AppRoutes.enterpriseForm); + final result = await Get.toNamed( + AppRoutes.enterpriseForm, + arguments: {'mode': FormMode.add}, + ); if (result == true) { refreshList(); // 调用控制器的方法刷新 } @@ -99,8 +103,11 @@ class EnterpriseListController extends GetxController { } /// 导航到企业问题列表 - Future navigateToEnterpriseInfoPage() async { - final result = await Get.toNamed(AppRoutes.enterpriseInfo); + Future navigateToEnterpriseInfoPage(Enterprise enterprise) async { + final result = await Get.toNamed( + AppRoutes.enterpriseInfo, + arguments: {'data': enterprise, 'mode': FormMode.view}, + ); if (result == true) { refreshList(); // 调用控制器的方法刷新 } diff --git a/lib/app/features/enterprise/presentation/pages/enterprise_form_page.dart b/lib/app/features/enterprise/presentation/pages/enterprise_form_page.dart index 935e091..36ebe70 100644 --- a/lib/app/features/enterprise/presentation/pages/enterprise_form_page.dart +++ b/lib/app/features/enterprise/presentation/pages/enterprise_form_page.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:problem_check_system/app/core/models/company_enum.dart'; import 'package:problem_check_system/app/features/enterprise/presentation/controllers/enterprise_form_controller.dart'; +import 'package:problem_check_system/app/features/enterprise/presentation/widgets/enterprise_form_view.dart'; // ------------------- 页面视图 (View) ------------------- // 使用 GetView 可以方便地访问控制器 @@ -15,74 +15,11 @@ class EnterpriseFormPage extends GetView { backgroundColor: const Color(0xFFF5F5F5), appBar: _buildAppBar(), body: SafeArea( - child: Form( - key: controller.formKey, - child: Column( - children: [ - Expanded( - child: SingleChildScrollView( - padding: EdgeInsets.symmetric( - horizontal: 16.w, - vertical: 12.h, - ), - child: Column( - children: [ - buildTitleSection(title: '必填信息'), - SizedBox(height: 12.h), - _buildInfoSection( - children: [ - _buildTextField( - label: '企业名称', - hint: '达拉特旗', - textController: controller.enterpriseNameController, - validator: (value) { - if (value == null || value.isEmpty) { - return '企业名称不能为空'; - } - return null; - }, - isRequired: true, - ), - _buildCompanyTypeDropdown(), - ], - ), - SizedBox(height: 12.h), - buildTitleSection(title: '选填信息'), - SizedBox(height: 12.h), - _buildInfoSection( - children: [ - _buildTextField( - label: '企业地址', - hint: '请输入企业地址', - textController: - controller.enterpriseAddressController, - ), - _buildCompanyScopeDropdown(), - _buildTextField( - label: '联系人', - hint: '请输入联系人姓名', - textController: controller.contactPersonController, - ), - _buildTextField( - label: '联系电话', - hint: '请输入联系电话', - textController: controller.contactPhoneController, - ), - _buildTextField( - label: '有无重大危险源;重大危险源情况', - hint: '请输入有无重大危险源;重大危险源情况', - textController: controller.hazardSourceController, - hasDivider: false, - ), - ], - ), - ], - ), - ), - ), - _buildBottomButtons(), - ], - ), + child: Column( + children: [ + Expanded(child: EnterpriseFormView()), + _buildBottomButtons(), + ], ), ), ); @@ -126,177 +63,6 @@ class EnterpriseFormPage extends GetView { ); } - Widget buildTitleSection({required String title}) { - return Row( - children: [ - Container(width: 4.w, height: 16.h, color: Colors.blue), - SizedBox(width: 8.w), - Text( - title, - style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.bold), - ), - ], - ); - } - - // 构建信息区块 (例如 "必填信息") - Widget _buildInfoSection({required List children}) { - return Container( - padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8.r), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [...children], - ), - ); - } - - // 构建带标签的文本输入框 - Widget _buildTextField({ - required String label, - required String hint, - required TextEditingController textController, - bool isRequired = false, - bool hasDivider = true, - String? Function(String?)? validator, - }) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.symmetric(vertical: 10.h), - child: _buildLabel(label, isRequired), - ), - TextFormField( - controller: textController, - validator: validator, - decoration: InputDecoration( - hintText: hint, - hintStyle: TextStyle(color: Colors.grey[400], fontSize: 14.sp), - border: InputBorder.none, - isDense: true, - contentPadding: EdgeInsets.zero, - ), - style: TextStyle(fontSize: 14.sp, color: Colors.black87), - ), - if (hasDivider) const Divider(height: 1, color: Color(0xFFF0F0F0)), - ], - ); - } - - // 构建下拉选择框样式 - // [新] 构建企业类型下拉框 - Widget _buildCompanyTypeDropdown() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.symmetric(vertical: 10.h), - child: _buildLabel('企业类型', true), // isRequired = true - ), - // 使用 Obx 监听 controller 中 selectedType 的变化 - Obx( - () => DropdownButtonFormField( - initialValue: controller.selectedType.value, - validator: (value) { - if (value == null) { - return '请选择企业类型'; - } - return null; - }, - hint: Text( - '请选择企业类型', - style: TextStyle(color: Colors.grey[400], fontSize: 14.sp), - ), - isExpanded: true, // 让下拉菜单撑满宽度 - decoration: const InputDecoration( - border: InputBorder.none, - isDense: true, - contentPadding: EdgeInsets.zero, - ), - items: CompanyType.values.map((CompanyType type) { - return DropdownMenuItem( - value: type, - child: Text( - type.displayText, - style: TextStyle(fontSize: 14.sp), - ), - ); - }).toList(), - onChanged: (CompanyType? newValue) { - controller.selectedType.value = newValue; - }, - // 自定义下拉箭头图标 - icon: const Icon(Icons.arrow_drop_down, color: Colors.grey), - ), - ), - const Divider(height: 1, color: Color(0xFFF0F0F0)), - ], - ); - } - - // [新] 构建企业规模下拉框 - Widget _buildCompanyScopeDropdown() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.symmetric(vertical: 10.h), - child: _buildLabel('企业规模', false), // isRequired = false - ), - Obx( - () => DropdownButtonFormField( - initialValue: controller.selectedScope.value, - hint: Text( - '请选择企业规模', - style: TextStyle(color: Colors.grey[400], fontSize: 14.sp), - ), - isExpanded: true, - decoration: const InputDecoration( - border: InputBorder.none, - isDense: true, - contentPadding: EdgeInsets.zero, - ), - items: CompanyScope.values.map((CompanyScope scope) { - return DropdownMenuItem( - value: scope, - child: Text( - scope.displayText, - style: TextStyle(fontSize: 14.sp), - ), - ); - }).toList(), - onChanged: (CompanyScope? newValue) { - controller.selectedScope.value = newValue; - }, - icon: const Icon(Icons.arrow_drop_down, color: Colors.grey), - ), - ), - const Divider(height: 1, color: Color(0xFFF0F0F0)), - ], - ); - } - - // 构建字段标签 (带红色星号) - Widget _buildLabel(String label, bool isRequired) { - return RichText( - text: TextSpan( - style: TextStyle(fontSize: 14.sp, color: Colors.black87), - children: [ - if (isRequired) - const TextSpan( - text: '* ', - style: TextStyle(color: Colors.red), - ), - TextSpan(text: label), - ], - ), - ); - } - // 构建底部的取消和确定按钮 Widget _buildBottomButtons() { return Container( diff --git a/lib/app/features/enterprise/presentation/pages/enterprise_info_page.dart b/lib/app/features/enterprise/presentation/pages/enterprise_info_page.dart index fa21632..1014e41 100644 --- a/lib/app/features/enterprise/presentation/pages/enterprise_info_page.dart +++ b/lib/app/features/enterprise/presentation/pages/enterprise_info_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; +import 'package:problem_check_system/app/features/enterprise/presentation/widgets/enterprise_form_view.dart'; // 支付宝消息页面 class EnterpriseInfoPage extends StatelessWidget { @@ -21,7 +22,7 @@ class EnterpriseInfoPage extends StatelessWidget { body: const TabBarView( children: [ Center(child: Text('企业问题列表')), - Center(child: Text('企业基本信息')), + EnterpriseFormView(), ], ), ), @@ -56,7 +57,7 @@ class EnterpriseInfoPage extends StatelessWidget { title: TabBar( isScrollable: false, // true: Tab的宽度由内容决定; false: 均分宽度 labelColor: Colors.white, // 选中 Tab 的文字颜色 - unselectedLabelColor: Colors.grey, // 未选中 Tab 的文字颜色 + unselectedLabelColor: Colors.grey[300], // 未选中 Tab 的文字颜色 // labelStyle: const TextStyle(fontSize: 17, fontWeight: FontWeight.bold), // unselectedLabelStyle: const TextStyle(fontSize: 17), overlayColor: WidgetStateProperty.all(Colors.transparent), diff --git a/lib/app/features/enterprise/presentation/pages/enterprise_list_page.dart b/lib/app/features/enterprise/presentation/pages/enterprise_list_page.dart index cf948d8..a12bc9a 100644 --- a/lib/app/features/enterprise/presentation/pages/enterprise_list_page.dart +++ b/lib/app/features/enterprise/presentation/pages/enterprise_list_page.dart @@ -218,7 +218,7 @@ class EnterpriseListPage extends GetView { controller.navigateToEditForm(item.enterprise); }, onViewProblems: () { - controller.navigateToEnterpriseInfoPage(); + controller.navigateToEnterpriseInfoPage(item.enterprise); }, ), ); diff --git a/lib/app/features/enterprise/presentation/widgets/enterprise_card.dart b/lib/app/features/enterprise/presentation/widgets/enterprise_card.dart index f858f80..b35e8a8 100644 --- a/lib/app/features/enterprise/presentation/widgets/enterprise_card.dart +++ b/lib/app/features/enterprise/presentation/widgets/enterprise_card.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:intl/intl.dart'; import 'package:problem_check_system/app/core/extensions/datetime_extension.dart'; import 'package:problem_check_system/app/core/models/sync_status.dart'; import 'package:problem_check_system/app/features/enterprise/domain/entities/enterprise_list_item.dart'; diff --git a/lib/app/features/enterprise/presentation/widgets/enterprise_form_view.dart b/lib/app/features/enterprise/presentation/widgets/enterprise_form_view.dart new file mode 100644 index 0000000..95aa8bc --- /dev/null +++ b/lib/app/features/enterprise/presentation/widgets/enterprise_form_view.dart @@ -0,0 +1,257 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:problem_check_system/app/core/models/company_enum.dart'; +import 'package:problem_check_system/app/features/enterprise/presentation/controllers/enterprise_form_controller.dart'; + +// 这是一个可复用的 "视图" 组件,不包含 Scaffold +class EnterpriseFormView extends GetView { + const EnterpriseFormView({super.key}); + + @override + Widget build(BuildContext context) { + // 根 Widget 是 Form,包裹着可滚动的内容 + return Form( + key: controller.formKey, + child: SingleChildScrollView( + padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h), + child: Column( + children: [ + // --- 这里是所有表单内容 --- + buildTitleSection(title: '必填信息'), + SizedBox(height: 12.h), + _buildInfoSection( + children: [ + _buildTextField( + label: '企业名称', + hint: '达拉特旗', + textController: controller.enterpriseNameController, + validator: (value) { + if (value == null || value.isEmpty) { + return '企业名称不能为空'; + } + return null; + }, + isRequired: true, + ), + _buildCompanyTypeDropdown(), + ], + ), + SizedBox(height: 12.h), + buildTitleSection(title: '选填信息'), + SizedBox(height: 12.h), + _buildInfoSection( + children: [ + _buildTextField( + label: '企业地址', + hint: '请输入企业地址', + textController: controller.enterpriseAddressController, + ), + _buildCompanyScopeDropdown(), + _buildTextField( + label: '联系人', + hint: '请输入联系人姓名', + textController: controller.contactPersonController, + ), + _buildTextField( + label: '联系电话', + hint: '请输入联系电话', + textController: controller.contactPhoneController, + ), + _buildTextField( + label: '有无重大危险源;重大危险源情况', + hint: '请输入有无重大危险源;重大危险源情况', + textController: controller.hazardSourceController, + hasDivider: false, + ), + ], + ), + ], + ), + ), + ); + } + + // --- 所有构建UI的辅助方法都移到这里 --- + Widget buildTitleSection({required String title}) { + return Row( + children: [ + Container(width: 4.w, height: 16.h, color: Colors.blue), + SizedBox(width: 8.w), + Text( + title, + style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.bold), + ), + ], + ); + } + + // 构建信息区块 (例如 "必填信息") + Widget _buildInfoSection({required List children}) { + return Container( + padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.r), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [...children], + ), + ); + } + + // 构建带标签的文本输入框 + Widget _buildTextField({ + required String label, + required String hint, + required TextEditingController textController, + bool isRequired = false, + bool hasDivider = true, + String? Function(String?)? validator, + }) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.symmetric(vertical: 10.h), + child: _buildLabel(label, isRequired), + ), + TextFormField( + controller: textController, + readOnly: controller.isReadOnly, + validator: validator, + decoration: InputDecoration( + hintText: hint, + hintStyle: TextStyle(color: Colors.grey[400], fontSize: 14.sp), + border: InputBorder.none, + isDense: true, + contentPadding: EdgeInsets.zero, + enabledBorder: controller.isReadOnly ? InputBorder.none : null, + focusedBorder: controller.isReadOnly ? InputBorder.none : null, + ), + style: TextStyle(fontSize: 14.sp, color: Colors.black87), + ), + if (hasDivider) const Divider(height: 1, color: Color(0xFFF0F0F0)), + ], + ); + } + + // 构建下拉选择框样式 + // [新] 构建企业类型下拉框 + Widget _buildCompanyTypeDropdown() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.symmetric(vertical: 10.h), + child: _buildLabel('企业类型', true), // isRequired = true + ), + // 使用 Obx 监听 controller 中 selectedType 的变化 + Obx( + () => DropdownButtonFormField( + initialValue: controller.selectedType.value, + validator: (value) { + if (value == null) { + return '请选择企业类型'; + } + return null; + }, + hint: Text( + '请选择企业类型', + style: TextStyle(color: Colors.grey[400], fontSize: 14.sp), + ), + isExpanded: true, // 让下拉菜单撑满宽度 + decoration: const InputDecoration( + border: InputBorder.none, + isDense: true, + contentPadding: EdgeInsets.zero, + ), + items: CompanyType.values.map((CompanyType type) { + return DropdownMenuItem( + value: type, + child: Text( + type.displayText, + style: TextStyle(fontSize: 14.sp), + ), + ); + }).toList(), + onChanged: controller.isReadOnly + ? null // 设置为 null 即可禁用 + : (CompanyType? newValue) { + controller.selectedType.value = newValue; + }, + // 自定义下拉箭头图标 + icon: controller.isReadOnly + ? const SizedBox.shrink() + : const Icon(Icons.arrow_drop_down, color: Colors.grey), + ), + ), + const Divider(height: 1, color: Color(0xFFF0F0F0)), + ], + ); + } + + // [新] 构建企业规模下拉框 + Widget _buildCompanyScopeDropdown() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.symmetric(vertical: 10.h), + child: _buildLabel('企业规模', false), // isRequired = false + ), + Obx( + () => DropdownButtonFormField( + initialValue: controller.selectedScope.value, + hint: Text( + '请选择企业规模', + style: TextStyle(color: Colors.grey[400], fontSize: 14.sp), + ), + isExpanded: true, + decoration: const InputDecoration( + border: InputBorder.none, + isDense: true, + contentPadding: EdgeInsets.zero, + ), + items: CompanyScope.values.map((CompanyScope scope) { + return DropdownMenuItem( + value: scope, + child: Text( + scope.displayText, + style: TextStyle(fontSize: 14.sp), + ), + ); + }).toList(), + onChanged: controller.isReadOnly + ? null // 设置为 null 即可禁用 + : (CompanyScope? newValue) { + controller.selectedScope.value = newValue; + }, + icon: controller.isReadOnly + ? const SizedBox.shrink() + : const Icon(Icons.arrow_drop_down, color: Colors.grey), + ), + ), + const Divider(height: 1, color: Color(0xFFF0F0F0)), + ], + ); + } + + // 构建字段标签 (带红色星号) + Widget _buildLabel(String label, bool isRequired) { + return RichText( + text: TextSpan( + style: TextStyle(fontSize: 14.sp, color: Colors.black87), + children: [ + if (isRequired) + const TextSpan( + text: '* ', + style: TextStyle(color: Colors.red), + ), + TextSpan(text: label), + ], + ), + ); + } +}