Browse Source

feat : 删除企业时删除企业问题

dev
徐振升 2 months ago
parent
commit
5969802919
  1. 9
      lib/app/core/routes/app_pages.dart
  2. 20
      lib/app/core/services/database_service.dart
  3. 14
      lib/app/features/enterprise/domain/entities/enterprise_list_item.dart
  4. 45
      lib/app/features/enterprise/domain/usecases/delete_enterprise_usecase.dart
  5. 54
      lib/app/features/enterprise/presentation/bindings/enterprise_list_binding.dart
  6. 26
      lib/app/features/enterprise/presentation/controllers/enterprise_list_controller.dart
  7. 4
      lib/app/features/enterprise/presentation/pages/enterprise_list_page.dart
  8. 5
      lib/app/features/my/bindings/profile_binding.dart
  9. 140
      lib/app/features/navigation/presentation/bindings/navigation_binding.dart
  10. 11
      lib/app/features/navigation/presentation/controllers/navigation_controller.dart
  11. 25
      lib/app/features/problem/data/datasources/problem_local_data_source.dart
  12. 182
      lib/app/features/problem/data/repositories/problem_repository_impl.dart
  13. 10
      lib/app/features/problem/domain/entities/problem_list_item_entity.dart
  14. 6
      lib/app/features/problem/domain/repositories/problem_repository.dart
  15. 29
      lib/app/features/problem/presentation/bindings/problem_binding.dart
  16. 72
      lib/app/features/problem/presentation/bindings/problem_list_binding.dart
  17. 38
      lib/app/features/problem/presentation/controllers/problem_list_controller.dart
  18. 2
      lib/app/features/problem/presentation/pages/problem_list_page.dart

9
lib/app/core/routes/app_pages.dart

@ -1,7 +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/bindings/enterprise_list_binding.dart';
import 'package:problem_check_system/app/features/enterprise/presentation/bindings/enterprise_upload_binding.dart';
import 'package:problem_check_system/app/features/enterprise/presentation/pages/enterprise_form_page.dart';
import 'package:problem_check_system/app/features/enterprise/presentation/pages/enterprise_upload_page.dart';
@ -14,7 +13,6 @@ import 'package:problem_check_system/app/features/auth/views/login_page.dart';
import 'package:problem_check_system/app/features/my/bindings/change_password_binding.dart';
import 'package:problem_check_system/app/features/my/views/change_password.dart';
import 'package:problem_check_system/app/features/problem/presentation/bindings/problem_form_binding.dart';
import 'package:problem_check_system/app/features/problem/presentation/bindings/problem_list_binding.dart';
import 'package:problem_check_system/app/features/problem/presentation/bindings/problem_upload_binding.dart';
import 'package:problem_check_system/app/features/problem/presentation/pages/problem_form_page.dart';
import 'package:problem_check_system/app/features/problem/presentation/pages/problem_upload_page.dart';
@ -34,12 +32,7 @@ abstract class AppPages {
GetPage(
name: AppRoutes.navigation,
page: () => const NavigationPage(),
binding: BindingsBuilder(() {
NavigationBinding().dependencies();
EnterpriseListBinding().dependencies();
ProblemListBinding().dependencies();
ProfileBinding().dependencies();
}),
binding: NavigationBinding(),
),
// GetPage(

20
lib/app/core/services/database_service.dart

@ -27,8 +27,11 @@ const String _createProblemsTable = '''
'pendingDelete'
)),
bindData TEXT
-- SQL
bindData TEXT,
--
FOREIGN KEY (enterpriseId)
REFERENCES enterprises (id)
ON DELETE CASCADE
)
''';
@ -79,6 +82,11 @@ class DatabaseService extends GetxService {
version: _dbVersion,
onCreate: _onCreate,
onUpgrade: _onUpgrade,
// App启动并打开数据库时
onOpen: (db) async {
await db.execute('PRAGMA foreign_keys = ON');
Get.log('外键约束已启用');
},
);
Get.log('数据库初始化成功');
@ -90,6 +98,10 @@ class DatabaseService extends GetxService {
///
Future<void> _onCreate(Database db, int version) async {
//
await db.execute(_createEnterprisesTable);
Get.log('`enterprises` 表创建成功');
//
await db.execute(_createProblemsTable);
Get.log('`problems` 表创建成功');
@ -101,10 +113,6 @@ class DatabaseService extends GetxService {
'CREATE INDEX idx_problems_syncStatus ON problems(syncStatus)',
);
Get.log('`problems` 表的索引创建成功');
//
await db.execute(_createEnterprisesTable);
Get.log('`enterprises` 表创建成功');
}
///

14
lib/app/features/enterprise/domain/entities/enterprise_list_item.dart

@ -21,4 +21,18 @@ class EnterpriseListItem extends Equatable {
uploadedProblems,
pendingProblems,
];
EnterpriseListItem copyWith({
Enterprise? enterprise,
int? totalProblems,
int? uploadedProblems,
int? pendingProblems,
}) {
return EnterpriseListItem(
enterprise: enterprise ?? this.enterprise,
totalProblems: totalProblems ?? this.totalProblems,
uploadedProblems: uploadedProblems ?? this.uploadedProblems,
pendingProblems: pendingProblems ?? this.pendingProblems,
);
}
}

45
lib/app/features/enterprise/domain/usecases/delete_enterprise_usecase.dart

@ -2,30 +2,47 @@ import 'package:problem_check_system/app/core/domain/entities/sync_status.dart';
import 'package:problem_check_system/app/core/repositories/auth_repository.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/problem/domain/repositories/problem_repository.dart';
///
///
/// UseCase
/// - (`pendingCreate`)
/// - `pendingDelete`便
class DeleteEnterpriseUsecase {
final EnterpriseRepository repository;
final EnterpriseRepository enterpriseRepository;
final ProblemRepository problemRepository;
final AuthRepository authRepository;
DeleteEnterpriseUsecase({
required this.repository,
required this.enterpriseRepository,
required this.problemRepository,
required this.authRepository,
});
Future<void> call(Enterprise enterprise) async {
//
if (enterprise.syncStatus == SyncStatus.pendingCreate) {
await enterpriseRepository.deleteEnterprise(enterprise.id);
return;
}
//
final nowUtc = DateTime.now().toUtc();
final userId = authRepository.getUserId();
//
if (enterprise.syncStatus == SyncStatus.pendingCreate) {
await repository.deleteEnterprise(enterprise.id);
} else {
//
final enterpriseToDelete = enterprise.copyWith(
lastModifiedTime: nowUtc,
lastModifierId: userId,
syncStatus: SyncStatus.pendingDelete,
);
await repository.updateEnterprise(enterpriseToDelete);
}
final enterpriseToDelete = enterprise.copyWith(
lastModifiedTime: nowUtc,
lastModifierId: userId,
syncStatus: SyncStatus.pendingDelete,
);
await enterpriseRepository.updateEnterprise(enterpriseToDelete);
await problemRepository.markProblemsAsPendingDeleteByEnterpriseId(
enterprise.id,
nowUtc,
userId,
);
}
}

54
lib/app/features/enterprise/presentation/bindings/enterprise_list_binding.dart

@ -1,58 +1,6 @@
import 'package:get/get.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/delete_enterprise_usecase.dart';
import 'package:problem_check_system/app/features/enterprise/domain/usecases/get_enterprise_list_usecase.dart';
import 'package:problem_check_system/app/features/enterprise/domain/usecases/resolve_conflict_usecase.dart';
import 'package:problem_check_system/app/features/enterprise/domain/usecases/sync_enterprises_usecase.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(http: Get.find<HttpProvider>()),
);
Get.put<EnterpriseRepository>(
EnterpriseRepositoryImpl(
localDataSource: Get.find<EnterpriseLocalDataSource>(),
remoteDataSource: Get.find<EnterpriseRemoteDataSource>(),
networkStatusService: Get.find(),
uuid: Get.find(),
),
);
Get.put<SyncEnterprisesUsecase>(
SyncEnterprisesUsecase(repository: Get.find<EnterpriseRepository>()),
);
Get.put<ResolveConflictUsecase>(
ResolveConflictUsecase(repository: Get.find<EnterpriseRepository>()),
);
Get.put<GetEnterpriseListUsecase>(
GetEnterpriseListUsecase(repository: Get.find<EnterpriseRepository>()),
);
Get.put<DeleteEnterpriseUsecase>(
DeleteEnterpriseUsecase(
repository: Get.find<EnterpriseRepository>(),
authRepository: Get.find(),
),
);
Get.lazyPut<EnterpriseListController>(
() => EnterpriseListController(
getEnterpriseListUsecase: Get.find<GetEnterpriseListUsecase>(),
syncEnterprisesUsecase: Get.find<SyncEnterprisesUsecase>(),
resolveConflictUsecase: Get.find<ResolveConflictUsecase>(),
deleteEnterpriseUsecase: Get.find<DeleteEnterpriseUsecase>(),
),
);
}
void dependencies() {}
}

26
lib/app/features/enterprise/presentation/controllers/enterprise_list_controller.dart

@ -2,6 +2,7 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:problem_check_system/app/core/domain/entities/sync_status.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/core/models/form_mode.dart';
@ -243,12 +244,28 @@ class EnterpriseListController extends GetxController {
// 4.
void deleteEnterprise(Enterprise enterprise) async {
try {
// UseCase
// 1. Usecase
await deleteEnterpriseUsecase(enterprise);
// UI列表中移除该项
enterpriseList.removeWhere((item) => item.enterprise.id == enterprise.id);
// 2. UI列表中找到对应的项并更新其状态
final int index = enterpriseList.indexWhere(
(item) => item.enterprise.id == enterprise.id,
);
if (index != -1) {
// EnterpriseListItem Enterprise
final updatedItem = enterpriseList[index].copyWith(
enterprise: enterprise.copyWith(syncStatus: SyncStatus.pendingDelete),
);
// UI的局部更新
enterpriseList[index] = updatedItem;
} else {
//
search();
}
// 3.
Get.snackbar(
'删除成功',
'"${enterprise.name}" 已被标记为删除。',
@ -262,6 +279,9 @@ class EnterpriseListController extends GetxController {
backgroundColor: Colors.red,
colorText: Colors.white,
);
Get.log('删除企业失败: $e');
// UI
search();
}
}

4
lib/app/features/enterprise/presentation/pages/enterprise_list_page.dart

@ -258,7 +258,9 @@ class EnterpriseListPage extends GetView<EnterpriseListController> {
// 2. 使 Dismissible
return Dismissible(
key: Key(enterprise.id), // 使ID作为唯一Key
key: Key(
'${enterprise.id}_${enterprise.syncStatus.name}',
), // 使ID作为唯一Key
// 3.
direction: isPendingDelete
? DismissDirection.none

5
lib/app/features/my/bindings/profile_binding.dart

@ -1,13 +1,8 @@
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>()),
);
}
}

140
lib/app/features/navigation/presentation/bindings/navigation_binding.dart

@ -1,12 +1,124 @@
import 'package:get/get.dart';
import 'package:problem_check_system/app/core/bindings/base_bindings.dart';
import 'package:problem_check_system/app/core/repositories/auth_repository.dart';
import 'package:problem_check_system/app/core/repositories/image_repository.dart';
import 'package:problem_check_system/app/core/repositories/image_repository_impl.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/core/services/network_status_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/delete_enterprise_usecase.dart';
import 'package:problem_check_system/app/features/enterprise/domain/usecases/get_enterprise_list_usecase.dart';
import 'package:problem_check_system/app/features/enterprise/domain/usecases/get_enterprises_usecase.dart';
import 'package:problem_check_system/app/features/enterprise/domain/usecases/resolve_conflict_usecase.dart';
import 'package:problem_check_system/app/features/enterprise/domain/usecases/sync_enterprises_usecase.dart';
import 'package:problem_check_system/app/features/enterprise/presentation/controllers/enterprise_list_controller.dart';
import 'package:problem_check_system/app/features/my/controllers/my_controller.dart';
import 'package:problem_check_system/app/features/navigation/presentation/controllers/navigation_controller.dart';
import 'package:problem_check_system/app/features/problem/data/datasources/problem_local_data_source.dart';
import 'package:problem_check_system/app/features/problem/data/datasources/problem_remote_data_source.dart';
import 'package:problem_check_system/app/features/problem/data/repositories/problem_repository_impl.dart';
import 'package:problem_check_system/app/features/problem/domain/repositories/problem_repository.dart';
import 'package:problem_check_system/app/features/problem/domain/usecases/delete_problem_usecase.dart';
import 'package:problem_check_system/app/features/problem/domain/usecases/get_all_problems_usecase.dart';
import 'package:problem_check_system/app/features/problem/domain/usecases/resolve_conflict_usecase.dart';
import 'package:problem_check_system/app/features/problem/domain/usecases/sync_problems_usecase.dart';
import 'package:problem_check_system/app/features/problem/presentation/controllers/problem_list_controller.dart';
class NavigationBinding extends Bindings {
class NavigationBinding extends BaseBindings {
@override
void dependencies() {
///
void register1Services() {
// TODO: implement register1Services
}
@override
void register2DataSource() {
Get.put<EnterpriseLocalDataSource>(
EnterpriseLocalDataSourceImpl(
databaseService: Get.find<DatabaseService>(),
),
);
Get.put<EnterpriseRemoteDataSource>(
EnterpriseRemoteDataSourceImpl(http: Get.find<HttpProvider>()),
);
Get.lazyPut<ProblemLocalDataSource>(
() => ProblemLocalDataSourceImpl(
databaseService: Get.find<DatabaseService>(),
),
);
Get.lazyPut<ProblemRemoteDataSource>(
() => ProblemRemoteDataSourceImpl(http: Get.find()),
);
}
@override
void register3Repositories() {
Get.put<EnterpriseRepository>(
EnterpriseRepositoryImpl(
localDataSource: Get.find<EnterpriseLocalDataSource>(),
remoteDataSource: Get.find<EnterpriseRemoteDataSource>(),
networkStatusService: Get.find(),
uuid: Get.find(),
),
);
Get.lazyPut<ImageRepository>(
() => ImageRepositoryImpl(httpProvider: Get.find()),
);
Get.lazyPut<ProblemRepository>(
() => ProblemRepositoryImpl(
localDataSource: Get.find(),
remoteDataSource: Get.find(),
networkStatusService: Get.find(),
imageRepository: Get.find(),
),
);
}
@override
void register4Usecases() {
Get.put<SyncEnterprisesUsecase>(
SyncEnterprisesUsecase(repository: Get.find<EnterpriseRepository>()),
);
Get.put<ResolveConflictUsecase>(
ResolveConflictUsecase(repository: Get.find<EnterpriseRepository>()),
);
Get.put<GetEnterpriseListUsecase>(
GetEnterpriseListUsecase(repository: Get.find<EnterpriseRepository>()),
);
Get.put<DeleteEnterpriseUsecase>(
DeleteEnterpriseUsecase(
enterpriseRepository: Get.find<EnterpriseRepository>(),
problemRepository: Get.find(),
authRepository: Get.find(),
),
);
Get.lazyPut<GetEnterprisesUsecase>(
() => GetEnterprisesUsecase(repository: Get.find()),
);
Get.lazyPut<GetAllProblemsUsecase>(
() => GetAllProblemsUsecase(problemRepository: Get.find()),
);
Get.lazyPut<SyncProblemsUsecase>(
() => SyncProblemsUsecase(repository: Get.find()),
);
Get.lazyPut<ProblemResolveConflictUsecase>(
() => ProblemResolveConflictUsecase(repository: Get.find()),
);
Get.lazyPut<DeleteProblemUsecase>(
() => DeleteProblemUsecase(
problemRepository: Get.find(),
authRepository: Get.find(),
),
);
}
@override
void register5Controllers() {
Get.lazyPut<NavigationController>(
() => NavigationController(
networkStatusService: Get.find<NetworkStatusService>(),
@ -14,5 +126,27 @@ class NavigationBinding extends Bindings {
problemListController: Get.find(),
),
);
Get.lazyPut<EnterpriseListController>(
() => EnterpriseListController(
getEnterpriseListUsecase: Get.find<GetEnterpriseListUsecase>(),
syncEnterprisesUsecase: Get.find<SyncEnterprisesUsecase>(),
resolveConflictUsecase: Get.find<ResolveConflictUsecase>(),
deleteEnterpriseUsecase: Get.find<DeleteEnterpriseUsecase>(),
),
);
Get.lazyPut<ProblemListController>(
() => ProblemListController(
getAllProblemsUsecase: Get.find(),
syncProblemsUsecase: Get.find(),
problemResolveConflictUsecase: Get.find(),
getEnterprisesUsecase: Get.find(),
deleteProblemUsecase: Get.find(),
),
);
Get.lazyPut<MyController>(
() => MyController(authRepository: Get.find<AuthRepository>()),
);
}
}

11
lib/app/features/navigation/presentation/controllers/navigation_controller.dart

@ -55,6 +55,17 @@ class NavigationController extends GetxController {
void changePageIndex(int index) {
if (selectedIndex.value == index) return;
selectedIndex.value = index;
// 使 switch
switch (selectedIndex.value) {
case 1: //
enterpriseListController.search();
break;
case 2: //
problemListController.search();
break;
default:
break;
}
}
/// floatingButton更新位置

25
lib/app/features/problem/data/datasources/problem_local_data_source.dart

@ -37,6 +37,12 @@ abstract class ProblemLocalDataSource {
Future<void> deleteProblem(String id);
Future<void> cacheProblems(List<Map<String, dynamic>> newProblems);
Future<void> markProblemsAsPendingDeleteByEnterpriseId(
String id,
DateTime nowUtc,
String userId,
) async {}
}
// IProblemLocalDataSource
@ -184,4 +190,23 @@ class ProblemLocalDataSourceImpl implements ProblemLocalDataSource {
// 3. batch
await batch.commit(noResult: true);
}
@override
Future<void> markProblemsAsPendingDeleteByEnterpriseId(
String id,
DateTime nowUtc,
String userId,
) async {
final db = await _databaseService.database;
await db.update(
_tableName, // 1.
{
'syncStatus': SyncStatus.pendingDelete.name, // 2.
'lastModifiedTime': nowUtc.toIso8601String(),
'lastModifierId': userId,
},
where: 'enterpriseId = ?', // 3.
whereArgs: [id], // 4. SQL注入
);
}
}

182
lib/app/features/problem/data/repositories/problem_repository_impl.dart

@ -315,43 +315,51 @@ class ProblemRepositoryImpl implements ProblemRepository {
// 4.
if (newProblems.isNotEmpty) {
final List<ProblemEntity> problemsWithLocalImages = [];
for (final problem in newProblems) {
//
final List<String> localImagePaths = [];
// URL
for (final remoteUrl in problem.imageUrls) {
try {
Get.log('准备下载图片: $remoteUrl for problem ${problem.id}');
// ImageRepository
final localPath = await imageRepository.downloadImage(
remoteUrl,
problem.id,
);
//
localImagePaths.add(localPath);
Get.log('图片下载并替换成功: $remoteUrl -> $localPath');
} catch (e) {
//
//
Get.log('图片下载失败: $remoteUrl, 错误: $e');
// localImagePaths
// remoteUrl
//
}
}
// 使 copyWith
// URL
final updatedProblem = problem.copyWith(imageUrls: localImagePaths);
// 使 Future.wait
final downloadFutures = newProblems
.map((p) => _downloadImagesForProblem(p))
.toList();
final List<ProblemEntity> problemsWithLocalImages = await Future.wait(
downloadFutures,
);
// final List<ProblemEntity> problemsWithLocalImages = [];
// for (final problem in newProblems) {
// //
// final List<String> localImagePaths = [];
// // URL
// for (final remoteUrl in problem.imageUrls) {
// try {
// Get.log('准备下载图片: $remoteUrl for problem ${problem.id}');
// // ImageRepository
// final localPath = await imageRepository.downloadImage(
// remoteUrl,
// problem.id,
// );
// //
// localImagePaths.add(localPath);
// Get.log('图片下载并替换成功: $remoteUrl -> $localPath');
// } catch (e) {
// //
// //
// Get.log('图片下载失败: $remoteUrl, 错误: $e');
// // localImagePaths
// // remoteUrl
// //
// }
// }
// // 使 copyWith
// // URL
// final updatedProblem = problem.copyWith(imageUrls: localImagePaths);
// //
// problemsWithLocalImages.add(updatedProblem);
// }
//
problemsWithLocalImages.add(updatedProblem);
}
List<Map<String, dynamic>> problemMaps = problemsWithLocalImages
.map((entity) => ProblemModel.fromEntity(entity).toMap())
.toList();
@ -366,9 +374,103 @@ class ProblemRepositoryImpl implements ProblemRepository {
}
@override
Future<void> resolveConflictAndUpdate(ProblemEntity chosenProblem) {
//
final problemMap = ProblemModel.fromEntity(chosenProblem).toMap();
return localDataSource.updateProblem(problemMap);
Future<void> resolveConflictAndUpdate(ProblemEntity chosenProblem) async {
// ////
// // URL
// final List<String> localImagePaths = [];
// for (final remoteUrl in chosenProblem.imageUrls) {
// try {
// Get.log('准备下载图片: $remoteUrl for problem ${chosenProblem.id}');
// // ImageRepository
// final localPath = await imageRepository.downloadImage(
// remoteUrl,
// chosenProblem.id,
// );
// //
// localImagePaths.add(localPath);
// Get.log('图片下载并替换成功: $remoteUrl -> $localPath');
// } catch (e) {
// //
// //
// Get.log('图片下载失败: $remoteUrl, 错误: $e');
// // localImagePaths
// // remoteUrl
// //
// }
// }
// // 使 copyWith
// // URL
// final updatedProblem = chosenProblem.copyWith(imageUrls: localImagePaths);
// ////
// //
// final problemMap = ProblemModel.fromEntity(updatedProblem).toMap();
// return localDataSource.updateProblem(problemMap);
// 1.
final problemWithLocalImages = await _downloadImagesForProblem(
chosenProblem,
);
// 2. Map
final problemMap = ProblemModel.fromEntity(problemWithLocalImages).toMap();
// 3. update
// ( localDataSource Model Model)
await localDataSource.updateProblem(problemMap);
}
// ProblemRepositoryImpl.dart
///
Future<ProblemEntity> _downloadImagesForProblem(ProblemEntity problem) async {
// URL
if (problem.imageUrls.isEmpty) {
return problem;
}
// Future
final downloadFutures = problem.imageUrls.map((url) async {
try {
// URL
if (url.startsWith('http')) {
Get.log('准备下载图片: $url for problem ${problem.id}');
final localPath = await imageRepository.downloadImage(
url,
problem.id,
);
Get.log('图片下载并替换成功: $url -> $localPath');
return localPath;
}
//
return url;
} catch (e) {
Get.log('图片下载失败: $url, 错误: $e');
return null; // null便
}
}).toList();
// 使 Future.wait
final List<String?> results = await Future.wait(downloadFutures);
// null
final List<String> localImagePaths = results.whereType<String>().toList();
//
return problem.copyWith(imageUrls: localImagePaths);
}
@override
Future<void> markProblemsAsPendingDeleteByEnterpriseId(
String id,
DateTime nowUtc,
String userId,
) async {
await localDataSource.markProblemsAsPendingDeleteByEnterpriseId(
id,
nowUtc,
userId,
);
}
}

10
lib/app/features/problem/domain/entities/problem_list_item_entity.dart

@ -17,4 +17,14 @@ class ProblemListItemEntity {
return ProblemBindStatus.bound;
}
}
ProblemListItemEntity copyWith({
ProblemEntity? problemEntity,
String? enterpriseName,
}) {
return ProblemListItemEntity(
problemEntity: problemEntity ?? this.problemEntity,
enterpriseName: enterpriseName ?? this.enterpriseName,
);
}
}

6
lib/app/features/problem/domain/repositories/problem_repository.dart

@ -23,4 +23,10 @@ abstract class ProblemRepository {
Future<ProblemSyncResult> syncWithServer();
//
Future<void> resolveConflictAndUpdate(ProblemEntity chosenProblem) async {}
Future<void> markProblemsAsPendingDeleteByEnterpriseId(
String id,
DateTime nowUtc,
String userId,
);
}

29
lib/app/features/problem/presentation/bindings/problem_binding.dart

@ -1,29 +0,0 @@
// import 'package:get/get.dart';
// import 'package:problem_check_system/app/core/models/problem_sync_status.dart';
// import 'package:problem_check_system/app/core/services/database_service.dart';
// import 'package:problem_check_system/app/features/problem/data/datasources/problem_local_data_source.dart';
// import 'package:problem_check_system/app/features/problem/data/repositories/problem_repository_impl.dart';
// import 'package:problem_check_system/app/features/problem/domain/repositories/problem_repository.dart';
// class ProblemBinding extends Bindings {
// @override
// void dependencies() {
// Get.lazyPut<IProblemLocalDataSource>(
// () =>
// ProblemLocalDataSource(databaseService: Get.find<DatabaseService>()),
// );
// Get.lazyPut<IProblemRepository>(
// () => ProblemRepository(Get.find<ProblemLocalDataSource>()),
// );
// Get.put(ProblemStateManager(uuid: Get.find(), authRepository: Get.find()));
// ///
// Get.lazyPut<ProblemController>(
// () => ProblemController(
// problemRepository: Get.find<ProblemRepository>(),
// problemStateManager: Get.find<ProblemStateManager>(),
// ),
// fenix: true,
// );
// }
// }

72
lib/app/features/problem/presentation/bindings/problem_list_binding.dart

@ -1,82 +1,18 @@
import 'package:get/get.dart';
import 'package:problem_check_system/app/core/bindings/base_bindings.dart';
import 'package:problem_check_system/app/core/repositories/image_repository.dart';
import 'package:problem_check_system/app/core/repositories/image_repository_impl.dart';
import 'package:problem_check_system/app/core/services/database_service.dart';
import 'package:problem_check_system/app/features/enterprise/domain/usecases/get_enterprises_usecase.dart';
import 'package:problem_check_system/app/features/problem/data/datasources/problem_local_data_source.dart';
import 'package:problem_check_system/app/features/problem/data/datasources/problem_remote_data_source.dart';
import 'package:problem_check_system/app/features/problem/data/repositories/problem_repository_impl.dart';
import 'package:problem_check_system/app/features/problem/domain/repositories/problem_repository.dart';
import 'package:problem_check_system/app/features/problem/domain/usecases/delete_problem_usecase.dart';
import 'package:problem_check_system/app/features/problem/domain/usecases/get_all_problems_usecase.dart';
import 'package:problem_check_system/app/features/problem/domain/usecases/resolve_conflict_usecase.dart';
import 'package:problem_check_system/app/features/problem/domain/usecases/sync_problems_usecase.dart';
import 'package:problem_check_system/app/features/problem/presentation/controllers/problem_list_controller.dart';
class ProblemListBinding extends BaseBindings {
@override
void register1Services() {}
@override
void register2DataSource() {
Get.lazyPut<ProblemLocalDataSource>(
() => ProblemLocalDataSourceImpl(
databaseService: Get.find<DatabaseService>(),
),
);
Get.lazyPut<ProblemRemoteDataSource>(
() => ProblemRemoteDataSourceImpl(http: Get.find()),
);
}
void register2DataSource() {}
@override
void register3Repositories() {
Get.lazyPut<ImageRepository>(
() => ImageRepositoryImpl(httpProvider: Get.find()),
);
Get.lazyPut<ProblemRepository>(
() => ProblemRepositoryImpl(
localDataSource: Get.find(),
remoteDataSource: Get.find(),
networkStatusService: Get.find(),
imageRepository: Get.find(),
),
);
}
void register3Repositories() {}
@override
void register4Usecases() {
Get.lazyPut<GetEnterprisesUsecase>(
() => GetEnterprisesUsecase(repository: Get.find()),
);
Get.lazyPut<GetAllProblemsUsecase>(
() => GetAllProblemsUsecase(problemRepository: Get.find()),
);
Get.lazyPut<SyncProblemsUsecase>(
() => SyncProblemsUsecase(repository: Get.find()),
);
Get.lazyPut<ProblemResolveConflictUsecase>(
() => ProblemResolveConflictUsecase(repository: Get.find()),
);
Get.lazyPut<DeleteProblemUsecase>(
() => DeleteProblemUsecase(
problemRepository: Get.find(),
authRepository: Get.find(),
),
);
}
void register4Usecases() {}
@override
void register5Controllers() {
Get.lazyPut<ProblemListController>(
() => ProblemListController(
getAllProblemsUsecase: Get.find(),
syncProblemsUsecase: Get.find(),
problemResolveConflictUsecase: Get.find(),
getEnterprisesUsecase: Get.find(),
deleteProblemUsecase: Get.find(),
),
);
}
void register5Controllers() {}
}

38
lib/app/features/problem/presentation/controllers/problem_list_controller.dart

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:problem_check_system/app/core/domain/entities/sync_status.dart';
import 'package:problem_check_system/app/core/extensions/datetime_extension.dart';
import 'package:problem_check_system/app/core/models/form_mode.dart';
import 'package:problem_check_system/app/core/routes/app_routes.dart';
@ -253,25 +254,38 @@ class ProblemListController extends GetxController {
///
Future<void> deleteProblem(ProblemEntity problem) async {
// 使 try-catch
try {
// deleteProblemUsecase
// 1. Usecase
await deleteProblemUsecase(problem);
// [!!!] UI列表中移除该项
// problemList .obsUI会自动更新
problemList.removeWhere((item) => item.problemEntity.id == problem.id);
// 2.
//
final int index = problemList.indexWhere(
(item) => item.problemEntity.id == problem.id,
);
//
if (index != -1) {
// ProblemListItemEntity ProblemEntity
final updatedItem = problemList[index].copyWith(
problemEntity: problem.copyWith(syncStatus: SyncStatus.pendingDelete),
);
// 使
// problemList .obsUI的局部更新
problemList[index] = updatedItem;
} else {
//
search();
}
//
// 3.
Get.snackbar(
'删除成功',
'"${problem.description}" 已被删除。',
'"${problem.description}" 已被标记为删除。',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.green,
colorText: Colors.white,
);
} catch (e) {
//
Get.snackbar(
'删除失败',
'无法删除该问题: $e',
@ -279,8 +293,8 @@ class ProblemListController extends GetxController {
backgroundColor: Colors.red,
colorText: Colors.white,
);
// UI状
// loadAndSyncProblems();
//
search();
}
}

2
lib/app/features/problem/presentation/pages/problem_list_page.dart

@ -353,7 +353,7 @@ class ProblemListPage extends GetView<ProblemListController> {
// 2. Dismissible Key
// Flutter
// 使ID
key: Key(problemEntity.id),
key: Key('${problemEntity.id}_${problemEntity.syncStatus.name}'),
// 3.
// isPendingDelete true none

Loading…
Cancel
Save