21 changed files with 911 additions and 440 deletions
@ -1,44 +0,0 @@
|
||||
import 'package:flutter/material.dart'; |
||||
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
||||
class AppBarAdd extends StatelessWidget implements PreferredSizeWidget { |
||||
const AppBarAdd({super.key, required this.titleName, this.onAddPressed}); |
||||
final String titleName; |
||||
final VoidCallback? onAddPressed; |
||||
|
||||
@override |
||||
Widget build(BuildContext context) { |
||||
return AppBar( |
||||
title: Text( |
||||
titleName, |
||||
style: TextStyle( |
||||
fontWeight: FontWeight.bold, |
||||
fontFamily: 'MyFont', |
||||
fontSize: 18.sp, |
||||
color: Colors.white, |
||||
), |
||||
), |
||||
backgroundColor: Colors.transparent, |
||||
flexibleSpace: Container( |
||||
decoration: const BoxDecoration( |
||||
gradient: LinearGradient( |
||||
colors: [Color(0xFF418CFC), Color(0xFF3DBFFC)], |
||||
begin: Alignment.centerLeft, |
||||
end: Alignment.centerRight, |
||||
), |
||||
), |
||||
), |
||||
elevation: 0, |
||||
centerTitle: true, |
||||
actions: [ |
||||
IconButton( |
||||
icon: Icon(Icons.add, color: Colors.white), // 使用 .sp |
||||
onPressed: onAddPressed, |
||||
), |
||||
], |
||||
); |
||||
} |
||||
|
||||
@override |
||||
Size get preferredSize => const Size.fromHeight(kToolbarHeight); |
||||
} |
||||
@ -0,0 +1,66 @@
|
||||
import 'package:flutter/material.dart'; |
||||
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
import 'package:get/get.dart'; |
||||
|
||||
class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { |
||||
const CustomAppBar({ |
||||
super.key, |
||||
required this.titleName, |
||||
this.leadingVisible = false, |
||||
this.actionsVisible = false, |
||||
this.onAddPressed, |
||||
}); |
||||
final String titleName; |
||||
final bool leadingVisible; |
||||
final bool actionsVisible; |
||||
final VoidCallback? onAddPressed; |
||||
|
||||
@override |
||||
Widget build(BuildContext context) { |
||||
return AppBar( |
||||
title: Text( |
||||
titleName, |
||||
style: TextStyle( |
||||
fontWeight: FontWeight.bold, |
||||
fontFamily: 'MyFont', |
||||
fontSize: 17.5.sp, |
||||
color: Colors.white, |
||||
), |
||||
), |
||||
automaticallyImplyLeading: leadingVisible, |
||||
leading: leadingVisible |
||||
? IconButton( |
||||
icon: Icon( |
||||
Icons.arrow_back_ios_new_rounded, |
||||
size: 17.5.sp, |
||||
color: Colors.white, |
||||
), |
||||
onPressed: () => Get.back(), |
||||
) |
||||
: null, |
||||
backgroundColor: Colors.transparent, |
||||
flexibleSpace: Container( |
||||
decoration: const BoxDecoration( |
||||
gradient: LinearGradient( |
||||
colors: [Color(0xFF418CFC), Color(0xFF3DBFFC)], |
||||
begin: Alignment.centerLeft, |
||||
end: Alignment.centerRight, |
||||
), |
||||
), |
||||
), |
||||
elevation: 0, |
||||
centerTitle: true, |
||||
actions: actionsVisible |
||||
? [ |
||||
IconButton( |
||||
icon: Icon(Icons.add, color: Colors.white), // 使用 .sp |
||||
onPressed: onAddPressed, |
||||
), |
||||
] |
||||
: null, |
||||
); |
||||
} |
||||
|
||||
@override |
||||
Size get preferredSize => const Size.fromHeight(kToolbarHeight); |
||||
} |
||||
@ -0,0 +1,38 @@
|
||||
import 'package:get/get.dart'; |
||||
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/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/enterprise/presentation/controllers/base_enterprise_list_controller.dart'; |
||||
import 'package:problem_check_system/app/features/enterprise/presentation/controllers/enterprise_list_controller.dart'; |
||||
|
||||
class EnterpriseListBinding extends Bindings { |
||||
@override |
||||
void dependencies() { |
||||
Get.put<EnterpriseLocalDataSource>( |
||||
EnterpriseLocalDataSourceImpl( |
||||
databaseService: Get.find<DatabaseService>(), |
||||
), |
||||
); |
||||
Get.put<EnterpriseRemoteDataSource>(EnterpriseRemoteDataSourceImpl()); |
||||
Get.put<EnterpriseRepository>( |
||||
EnterpriseRepositoryImpl( |
||||
localDataSource: Get.find<EnterpriseLocalDataSource>(), |
||||
remoteDataSource: Get.find<EnterpriseRemoteDataSource>(), |
||||
), |
||||
); |
||||
Get.put<GetEnterpriseListUsecase>( |
||||
GetEnterpriseListUsecase(repository: Get.find<EnterpriseRepository>()), |
||||
); |
||||
Get.lazyPut<EnterpriseListController>( |
||||
() => EnterpriseListController( |
||||
getEnterpriseListUsecase: Get.find<GetEnterpriseListUsecase>(), |
||||
), |
||||
); |
||||
Get.lazyPut<BaseEnterpriseListController>( |
||||
() => Get.find<EnterpriseListController>(), |
||||
); |
||||
} |
||||
} |
||||
@ -1,8 +1,13 @@
|
||||
import 'package:get/get.dart'; |
||||
import 'package:problem_check_system/app/features/enterprise/presentation/controllers/base_enterprise_list_controller.dart'; |
||||
import 'package:problem_check_system/app/features/enterprise/presentation/controllers/enterprise_upload_controller.dart'; |
||||
|
||||
class EnterpriseUploadBinding extends Bindings { |
||||
@override |
||||
void dependencies() { |
||||
// TODO: implement dependencies |
||||
Get.lazyPut<EnterpriseUploadController>(() => EnterpriseUploadController()); |
||||
Get.lazyPut<BaseEnterpriseListController>( |
||||
() => Get.find<EnterpriseUploadController>(), |
||||
); |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,66 @@
|
||||
// lib/app/features/enterprise/presentation/controllers/base_enterprise_list_controller.dart |
||||
|
||||
import 'package:flutter/material.dart'; |
||||
import 'package:problem_check_system/app/features/enterprise/domain/entities/enterprise_list_item.dart'; |
||||
import 'package:get/get.dart'; |
||||
import 'package:problem_check_system/app/core/models/company_enum.dart'; |
||||
import 'package:problem_check_system/app/features/enterprise/domain/entities/enterprise.dart'; |
||||
|
||||
/// ----------------------------------------------------------------------------- |
||||
/// [抽象基类] 企业列表控制器接口 |
||||
/// ----------------------------------------------------------------------------- |
||||
/// |
||||
/// 定义了所有希望驱动 `EnterpriseListView` 的控制器必须实现的属性和方法。 |
||||
/// |
||||
/// **设计思想:** |
||||
/// - **依赖倒置原则**: `EnterpriseListView` (高层模块) 不直接依赖于 |
||||
/// `EnterpriseListController` 或 `EnterpriseUploadController` (低层模块), |
||||
/// 而是两者都依赖于这个抽象 (`BaseEnterpriseListController`)。 |
||||
/// - **接口隔离原则**: 这个基类只定义了 `EnterpriseListView` 真正需要交互的成员, |
||||
/// 不多也不少,确保了 View 和 Controller 之间的最小化耦合。 |
||||
/// |
||||
abstract class BaseEnterpriseListController extends GetxController { |
||||
// --- 状态属性 (View 需要监听的数据) --- |
||||
|
||||
/// 可观察的企业列表数据源。 |
||||
/// View 将监听此列表的变化来刷新UI。 |
||||
RxList<EnterpriseListItem> get enterpriseList; |
||||
|
||||
/// 是否正在加载数据。 |
||||
/// View 用它来显示或隐藏加载指示器 (如 `CircularProgressIndicator`)。 |
||||
RxBool get isLoading; |
||||
|
||||
/// [筛选功能] 企业名称的文本编辑器控制器。 |
||||
TextEditingController get nameController; |
||||
|
||||
/// [筛选功能] 已选择的企业类型。 |
||||
Rx<CompanyType?> get selectedType; |
||||
|
||||
/// [筛选功能] 已选择的开始日期。 |
||||
Rx<DateTime?> get startDate; |
||||
|
||||
/// [筛选功能] 已选择的结束日期。 |
||||
Rx<DateTime?> get endDate; |
||||
|
||||
/// [选择功能] 被选中的企业集合。 |
||||
/// 使用 `Set` 可以高效地进行增、删、查操作,并保证元素的唯一性。 |
||||
RxSet<Enterprise> get selectedEnterprises; |
||||
|
||||
// --- 操作方法 (View 需要调用的行为) --- |
||||
|
||||
/// 执行搜索/筛选操作。 |
||||
/// 由 View 中的“查询”按钮调用。 |
||||
void search(); |
||||
|
||||
/// 清空所有筛选条件并重新加载数据。 |
||||
/// 由 View 中的“重置”按钮调用。 |
||||
void clearFilters(); |
||||
|
||||
/// 处理整个卡片的点击事件。 |
||||
/// 在不同模式下(管理/选择),此方法的具体行为由子类实现。 |
||||
void onItemTap(EnterpriseListItem item); |
||||
|
||||
/// 处理卡片上复选框状态的变化。 |
||||
/// 当用户在选择模式下勾选或取消勾选时被调用。 |
||||
void onSelectionChanged(Enterprise enterprise); |
||||
} |
||||
@ -0,0 +1,116 @@
|
||||
// lib/app/features/enterprise/presentation/controllers/enterprise_upload_controller.dart |
||||
|
||||
import 'package:flutter/material.dart'; |
||||
import 'package:get/get.dart'; |
||||
import 'package:problem_check_system/app/core/models/company_enum.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 'base_enterprise_list_controller.dart'; |
||||
// 假设你有一个专门获取待上传列表的 Usecase |
||||
// import 'package:problem_check_system/app/features/enterprise/domain/usecases/get_pending_uploads_usecase.dart'; |
||||
|
||||
/// ----------------------------------------------------------------------------- |
||||
/// [具体实现] 企业上传选择控制器 |
||||
/// ----------------------------------------------------------------------------- |
||||
/// |
||||
/// 继承自 `BaseEnterpriseListController`,专门为“选择上传企业”页面服务。 |
||||
/// |
||||
/// **职责:** |
||||
/// - 从数据源加载**待上传**的企业列表。 |
||||
/// - 管理用户的多选状态 (`selectedEnterprises`)。 |
||||
/// - 处理卡片点击和复选框事件,更新选择集。 |
||||
/// - 提供确认上传的方法,并将结果返回给上一个页面。 |
||||
/// |
||||
class EnterpriseUploadController extends BaseEnterpriseListController { |
||||
// final GetPendingUploadsUsecase getPendingUploadsUsecase; |
||||
// EnterpriseUploadController({required this.getPendingUploadsUsecase}); |
||||
|
||||
// --- 实现基类中定义的属性 --- |
||||
@override |
||||
final enterpriseList = <EnterpriseListItem>[].obs; |
||||
@override |
||||
final isLoading = false.obs; |
||||
@override |
||||
final selectedEnterprises = <Enterprise>{}.obs; // 此控制器会重度使用此 Set |
||||
|
||||
// 在上传页,复杂的筛选功能通常是不需要的。 |
||||
// 我们仍然需要提供这些属性的实例以满足接口要求,但它们可能不会在UI中被使用。 |
||||
@override |
||||
final nameController = TextEditingController(); |
||||
@override |
||||
final selectedType = Rx<CompanyType?>(null); |
||||
@override |
||||
final startDate = Rx<DateTime?>(null); |
||||
@override |
||||
final endDate = Rx<DateTime?>(null); |
||||
|
||||
@override |
||||
void onInit() { |
||||
super.onInit(); |
||||
fetchPendingUploads(); |
||||
} |
||||
|
||||
// --- 实现基类中定义的方法 --- |
||||
@override |
||||
void search() { |
||||
// 上传页的“搜索”可能只是重新加载列表 |
||||
fetchPendingUploads(); |
||||
} |
||||
|
||||
@override |
||||
void clearFilters() { |
||||
// 上传页的“重置”可能只是清空一个简单的搜索框 |
||||
nameController.clear(); |
||||
fetchPendingUploads(); |
||||
} |
||||
|
||||
@override |
||||
void onItemTap(EnterpriseListItem item) { |
||||
// 在选择模式下,点击整个卡片的效果等同于操作复选框 |
||||
onSelectionChanged(item.enterprise); |
||||
} |
||||
|
||||
@override |
||||
void onSelectionChanged(Enterprise enterprise) { |
||||
// 核心逻辑:切换单个企业的选中状态 |
||||
if (selectedEnterprises.contains(enterprise)) { |
||||
selectedEnterprises.remove(enterprise); |
||||
} else { |
||||
selectedEnterprises.add(enterprise); |
||||
} |
||||
} |
||||
|
||||
// --- EnterpriseUploadController 特有的方法 --- |
||||
|
||||
/// 从数据源获取待上传的企业列表 |
||||
Future<void> fetchPendingUploads() async { |
||||
isLoading.value = true; |
||||
try { |
||||
// 在这里调用您的 Usecase 来获取待上传列表 |
||||
// final result = await getPendingUploadsUsecase.call(); |
||||
// enterpriseList.assignAll(result); |
||||
|
||||
// --- 使用模拟数据进行演示 --- |
||||
await Future.delayed(const Duration(seconds: 1)); |
||||
// final mockData = createMockEnterpriseListItems(); |
||||
// enterpriseList.assignAll(mockData); |
||||
} catch (e) { |
||||
Get.snackbar('错误', '加载待上传列表失败: $e'); |
||||
} finally { |
||||
isLoading.value = false; |
||||
} |
||||
} |
||||
|
||||
/// 确认上传,并返回结果 |
||||
void confirmUpload() { |
||||
if (selectedEnterprises.isEmpty) { |
||||
Get.snackbar('提示', '请至少选择一个企业进行上传'); |
||||
return; |
||||
} |
||||
// 在这里执行实际的上传业务逻辑... |
||||
print('正在上传 ${selectedEnterprises.length} 个企业...'); |
||||
|
||||
// 操作成功后,返回 true 通知上一个页面刷新 |
||||
Get.back(result: true); |
||||
} |
||||
} |
||||
@ -0,0 +1,280 @@
|
||||
import 'package:flutter/material.dart'; |
||||
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
import 'package:get/get.dart'; |
||||
import 'package:problem_check_system/app/core/extensions/datetime_extension.dart'; |
||||
import 'package:problem_check_system/app/core/models/company_enum.dart'; |
||||
import 'package:problem_check_system/app/features/enterprise/presentation/controllers/base_enterprise_list_controller.dart'; |
||||
import 'package:problem_check_system/app/features/enterprise/presentation/controllers/enterprise_list_controller.dart'; |
||||
import 'enterprise_card.dart'; |
||||
|
||||
/// 定义列表项的显示模式 |
||||
enum EnterpriseListPageMode { |
||||
/// 普通模式,显示操作按钮 |
||||
normal, |
||||
|
||||
/// 选择模式,显示复选框 |
||||
select, |
||||
} |
||||
|
||||
/// ----------------------------------------------------------------------------- |
||||
/// [共享UI组件] 企业列表视图 |
||||
/// ----------------------------------------------------------------------------- |
||||
/// |
||||
/// 一个可复用的、“哑”的(Dumb)UI组件,负责渲染企业列表和筛选器。 |
||||
/// |
||||
/// **设计思想:** |
||||
/// - **高内聚,低耦合**: 此 View 只负责 UI 的展示和用户事件的转发。它不包含任何业务逻辑。 |
||||
/// - **依赖于抽象**: 通过 `GetView<BaseEnterpriseListController>`,它依赖于我们定义的 |
||||
/// 抽象基类 (`BaseEnterpriseListController`),而不是任何具体的控制器实现。 |
||||
/// 这使得它可以被任何实现了该接口的控制器驱动。 |
||||
/// |
||||
class EnterpriseListView extends StatelessWidget { |
||||
const EnterpriseListView({ |
||||
super.key, |
||||
required this.controller, |
||||
this.filterSectionVisible = true, |
||||
this.itemMode = EnterpriseListPageMode.normal, |
||||
}); |
||||
final BaseEnterpriseListController controller; |
||||
|
||||
/// 是否显示顶部的筛选区域 |
||||
final bool filterSectionVisible; |
||||
|
||||
/// 列表项的模式(按钮模式或选择模式) |
||||
final EnterpriseListPageMode itemMode; |
||||
|
||||
@override |
||||
Widget build(BuildContext context) { |
||||
return Column( |
||||
children: [ |
||||
// 根据参数决定是否构建筛选区域 |
||||
if (filterSectionVisible) ...[ |
||||
_buildFilterSection(), |
||||
const Divider(height: 1, thickness: .1), |
||||
], |
||||
// 列表区域总是显示 |
||||
Expanded(child: _buildEnterpriseList()), |
||||
], |
||||
); |
||||
} |
||||
|
||||
/// 构建可展开的筛选查询区域。 |
||||
/// 此方法的所有交互都绑定到 `BaseEnterpriseListController` 的接口, |
||||
/// 因此它无需关心具体的控制器是哪个。 |
||||
Widget _buildFilterSection() { |
||||
return ExpansionTile( |
||||
title: const Text('筛选查询'), |
||||
leading: const Icon(Icons.filter_alt_outlined), |
||||
initiallyExpanded: false, // 默认收起 |
||||
children: [ |
||||
Padding( |
||||
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 4.h), |
||||
child: Column( |
||||
children: [ |
||||
// 1. 企业名称输入框 |
||||
TextFormField( |
||||
controller: controller.nameController, |
||||
decoration: InputDecoration( |
||||
labelText: '企业名称', |
||||
hintText: '请输入关键词', |
||||
prefixIcon: const Icon(Icons.business_center), |
||||
border: OutlineInputBorder( |
||||
borderRadius: BorderRadius.circular(8.r), |
||||
), |
||||
isDense: true, |
||||
), |
||||
), |
||||
SizedBox(height: 12.h), |
||||
|
||||
// 2. 企业类型下拉框 |
||||
Obx( |
||||
() => DropdownButtonFormField<CompanyType>( |
||||
initialValue: controller.selectedType.value, |
||||
decoration: InputDecoration( |
||||
labelText: '企业类型', |
||||
prefixIcon: const Icon(Icons.category), |
||||
border: OutlineInputBorder( |
||||
borderRadius: BorderRadius.circular(8.r), |
||||
), |
||||
isDense: true, |
||||
), |
||||
hint: const Text('请选择企业类型'), |
||||
isExpanded: true, |
||||
items: CompanyType.values.map((type) { |
||||
return DropdownMenuItem( |
||||
value: type, |
||||
child: Text(type.displayText), |
||||
); |
||||
}).toList(), |
||||
onChanged: (value) { |
||||
controller.selectedType.value = value; |
||||
}, |
||||
), |
||||
), |
||||
SizedBox(height: 12.h), |
||||
|
||||
// 3. 日期范围选择器 |
||||
Row( |
||||
children: [ |
||||
Expanded( |
||||
child: _buildDatePickerField('开始日期', controller.startDate), |
||||
), |
||||
SizedBox(width: 12.w), |
||||
Expanded( |
||||
child: _buildDatePickerField('结束日期', controller.endDate), |
||||
), |
||||
], |
||||
), |
||||
SizedBox(height: 16.h), |
||||
|
||||
// 4. 操作按钮 |
||||
Row( |
||||
children: [ |
||||
Expanded( |
||||
child: OutlinedButton.icon( |
||||
onPressed: controller.clearFilters, |
||||
icon: const Icon(Icons.refresh), |
||||
label: const Text('重置'), |
||||
style: OutlinedButton.styleFrom( |
||||
padding: EdgeInsets.symmetric(vertical: 12.h), |
||||
), |
||||
), |
||||
), |
||||
SizedBox(width: 16.w), |
||||
Expanded( |
||||
child: ElevatedButton.icon( |
||||
onPressed: controller.search, |
||||
icon: const Icon(Icons.search), |
||||
label: const Text('查询'), |
||||
style: ElevatedButton.styleFrom( |
||||
padding: EdgeInsets.symmetric(vertical: 12.h), |
||||
), |
||||
), |
||||
), |
||||
], |
||||
), |
||||
SizedBox(height: 8.h), // 增加底部间距 |
||||
], |
||||
), |
||||
), |
||||
], |
||||
); |
||||
} |
||||
|
||||
/// 构建日期选择器的辅助方法 |
||||
Widget _buildDatePickerField(String label, Rx<DateTime?> date) { |
||||
return InkWell( |
||||
onTap: () async { |
||||
final pickedDate = await showDatePicker( |
||||
context: Get.context!, |
||||
initialDate: date.value ?? DateTime.now(), |
||||
firstDate: DateTime(2020), // 调整一个合理的开始年份 |
||||
lastDate: DateTime(2125), |
||||
); |
||||
if (pickedDate != null) { |
||||
date.value = pickedDate; |
||||
} |
||||
}, |
||||
child: InputDecorator( |
||||
decoration: InputDecoration( |
||||
labelText: label, |
||||
prefixIcon: const Icon(Icons.calendar_today), |
||||
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8.r)), |
||||
isDense: true, |
||||
contentPadding: EdgeInsets.symmetric( |
||||
horizontal: 12.w, |
||||
vertical: 14.h, |
||||
), // 调整内边距 |
||||
), |
||||
child: Obx( |
||||
() => Text( |
||||
date.value == null ? '请选择日期' : date.value!.toDateString(), |
||||
style: TextStyle( |
||||
fontSize: 14.sp, |
||||
color: date.value == null ? Colors.grey[700] : Colors.black87, |
||||
), |
||||
), |
||||
), |
||||
), |
||||
); |
||||
} |
||||
|
||||
/// 构建企业列表 |
||||
Widget _buildEnterpriseList() { |
||||
// 使用 Obx 包裹以监听 controller 中所有 Rx 变量的变化 |
||||
return Obx(() { |
||||
// 在列表为空且仍在加载时显示加载指示器 |
||||
if (controller.isLoading.value && controller.enterpriseList.isEmpty) { |
||||
return const Center(child: CircularProgressIndicator()); |
||||
} |
||||
// 在加载完成但列表为空时显示提示信息 |
||||
if (controller.enterpriseList.isEmpty) { |
||||
return Center( |
||||
child: Column( |
||||
mainAxisAlignment: MainAxisAlignment.center, |
||||
children: [ |
||||
Icon( |
||||
Icons.folder_off_outlined, |
||||
size: 60.sp, |
||||
color: Colors.grey[400], |
||||
), |
||||
SizedBox(height: 16.h), |
||||
Text( |
||||
'没有找到相关企业', |
||||
style: TextStyle(fontSize: 16.sp, color: Colors.grey[600]), |
||||
), |
||||
], |
||||
), |
||||
); |
||||
} |
||||
|
||||
// 使用下拉刷新包裹列表 |
||||
return RefreshIndicator( |
||||
onRefresh: () async => controller.search(), |
||||
child: ListView.builder( |
||||
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h), |
||||
itemCount: controller.enterpriseList.length, |
||||
itemBuilder: (context, index) { |
||||
final item = controller.enterpriseList[index]; |
||||
final enterprise = item.enterprise; |
||||
// 核心: 从 base controller 获取选中状态 |
||||
final isSelected = controller.selectedEnterprises.contains( |
||||
enterprise, |
||||
); |
||||
|
||||
return Padding( |
||||
padding: EdgeInsets.only(bottom: 12.h), |
||||
child: EnterpriseCard( |
||||
enterpriseListItem: item, |
||||
isSelected: isSelected, |
||||
// 根据外部传入的 itemMode 决定卡片内部的 mode |
||||
mode: itemMode, |
||||
// --- [核心] 将卡片的所有交互事件转发给 controller 的抽象方法 --- |
||||
onTap: () => controller.onItemTap(item), |
||||
onSelectionChanged: (value) => |
||||
controller.onSelectionChanged(enterprise), |
||||
|
||||
// 对于只存在于特定 Controller 的方法,需要进行类型检查。 |
||||
// 这样可以确保即使在上传页面(其控制器没有这些方法),代码也不会崩溃。 |
||||
onEdit: () { |
||||
if (controller is EnterpriseListController) { |
||||
// 只有当控制器是 EnterpriseListController 类型时,才调用其特有方法 |
||||
(controller as EnterpriseListController).navigateToEditForm( |
||||
enterprise, |
||||
); |
||||
} |
||||
}, |
||||
onViewProblems: () { |
||||
if (controller is EnterpriseListController) { |
||||
(controller as EnterpriseListController) |
||||
.navigateToEnterpriseInfoPage(enterprise); |
||||
} |
||||
}, |
||||
), |
||||
); |
||||
}, |
||||
), |
||||
); |
||||
}); |
||||
} |
||||
} |
||||
@ -0,0 +1,13 @@
|
||||
import 'package:get/get.dart'; |
||||
import 'package:problem_check_system/app/core/repositories/auth_repository.dart'; |
||||
import 'package:problem_check_system/app/features/my/controllers/my_controller.dart'; |
||||
|
||||
class ProfileBinding implements Bindings { |
||||
@override |
||||
void dependencies() { |
||||
/// 注册我的控制器 |
||||
Get.lazyPut<MyController>( |
||||
() => MyController(authRepository: Get.find<AuthRepository>()), |
||||
); |
||||
} |
||||
} |
||||
@ -0,0 +1,20 @@
|
||||
import 'package:get/get.dart'; |
||||
import 'package:problem_check_system/app/core/models/problem_sync_status.dart'; |
||||
import 'package:problem_check_system/app/features/problem/data/repositories/problem_repository.dart'; |
||||
import 'package:problem_check_system/app/features/problem/presentation/controllers/problem_controller.dart'; |
||||
|
||||
class ProblemBinding extends Bindings { |
||||
@override |
||||
void dependencies() { |
||||
Get.put(ProblemStateManager(uuid: Get.find(), authRepository: Get.find())); |
||||
|
||||
/// 注册问题控制器 |
||||
Get.lazyPut<ProblemController>( |
||||
() => ProblemController( |
||||
problemRepository: Get.find<ProblemRepository>(), |
||||
problemStateManager: Get.find<ProblemStateManager>(), |
||||
), |
||||
fenix: true, |
||||
); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue