Browse Source

fix : 同步企业上传修改时间到本地数据库

dev
徐振升 1 week ago
parent
commit
d459d905ff
  1. 19
      lib/app/features/enterprise/data/datasources/enterprise_remote_data_source.dart
  2. 15
      lib/app/features/enterprise/data/repositories_impl/enterprise_repository_impl.dart
  3. 2
      lib/app/features/enterprise/domain/repositories/enterprise_repository.dart
  4. 11
      lib/app/features/enterprise/domain/usecases/upload_enterprises_usecase.dart
  5. 116
      lib/app/features/enterprise/presentation/controllers/enterprise_list_controller.dart
  6. 2
      lib/app/features/enterprise/presentation/pages/enterprise_form_page.dart

19
lib/app/features/enterprise/data/datasources/enterprise_remote_data_source.dart

@ -7,10 +7,10 @@ import 'package:problem_check_system/app/features/enterprise/data/model/enterpri
/// API /// API
abstract class EnterpriseRemoteDataSource { abstract class EnterpriseRemoteDataSource {
/// ///
Future<void> createEnterprise(EnterpriseModel enterprise); Future<EnterpriseDto> createEnterprise(EnterpriseModel enterprise);
/// ///
Future<void> updateEnterprise(EnterpriseModel enterprise); Future<EnterpriseDto> updateEnterprise(EnterpriseModel enterprise);
/// ///
Future<void> deleteEnterprise(String enterpriseId); Future<void> deleteEnterprise(String enterpriseId);
@ -25,14 +25,15 @@ class EnterpriseRemoteDataSourceImpl implements EnterpriseRemoteDataSource {
static const String enterprisesEndpoint = '/api/Companies'; static const String enterprisesEndpoint = '/api/Companies';
@override @override
Future<void> createEnterprise(EnterpriseModel enterprise) async { Future<EnterpriseDto> createEnterprise(EnterpriseModel enterprise) async {
try { try {
final enterpriseDto = EnterpriseDto.fromModel(enterprise); final enterpriseDto = EnterpriseDto.fromModel(enterprise);
final data = enterpriseDto.toJson(); final data = enterpriseDto.toJson();
await http.post( final response = await http.post(
'$enterprisesEndpoint/CreateWithId?Id=${enterprise.id}', '$enterprisesEndpoint/CreateWithId?Id=${enterprise.id}',
data: data, data: data,
); );
return EnterpriseDto.fromJson(response.data);
} catch (e) { } catch (e) {
rethrow; rethrow;
} }
@ -48,12 +49,16 @@ class EnterpriseRemoteDataSourceImpl implements EnterpriseRemoteDataSource {
} }
@override @override
Future<void> updateEnterprise(EnterpriseModel enterprise) async { Future<EnterpriseDto> updateEnterprise(EnterpriseModel enterprise) async {
try { try {
final enterpriseDto = EnterpriseDto.fromModel(enterprise); final enterpriseDto = EnterpriseDto.fromModel(enterprise);
final data = enterpriseDto.toJson(); final data = enterpriseDto.toJson();
// ID // ID
await http.patch('$enterprisesEndpoint/${enterprise.id}', data: data); final response = await http.patch(
'$enterprisesEndpoint/${enterprise.id}',
data: data,
);
return EnterpriseDto.fromJson(response.data);
} catch (e) { } catch (e) {
rethrow; rethrow;
} }
@ -62,7 +67,7 @@ class EnterpriseRemoteDataSourceImpl implements EnterpriseRemoteDataSource {
@override @override
Future<List<EnterpriseDto>> getEnterprises() async { Future<List<EnterpriseDto>> getEnterprises() async {
try { try {
final response = await http.get(enterprisesEndpoint); final response = await http.get("$enterprisesEndpoint?PageSize=999");
final Map<String, dynamic> data = response.data; final Map<String, dynamic> data = response.data;
final List<dynamic> enterprises = data['items']; final List<dynamic> enterprises = data['items'];
return enterprises.map((json) => EnterpriseDto.fromJson(json)).toList(); return enterprises.map((json) => EnterpriseDto.fromJson(json)).toList();

15
lib/app/features/enterprise/data/repositories_impl/enterprise_repository_impl.dart

@ -2,6 +2,7 @@ import 'package:problem_check_system/app/core/models/sync_status.dart';
import 'package:problem_check_system/app/core/services/network_status_service.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_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/datasources/enterprise_remote_data_source.dart';
import 'package:problem_check_system/app/features/enterprise/data/model/enterprise_dto.dart';
import 'package:problem_check_system/app/features/enterprise/data/model/enterprise_model.dart'; import 'package:problem_check_system/app/features/enterprise/data/model/enterprise_model.dart';
import 'package:problem_check_system/app/features/enterprise/domain/entities/enterprise.dart'; import 'package:problem_check_system/app/features/enterprise/domain/entities/enterprise.dart';
import 'package:problem_check_system/app/features/enterprise/domain/entities/enterprise_conflict.dart'; import 'package:problem_check_system/app/features/enterprise/domain/entities/enterprise_conflict.dart';
@ -83,29 +84,31 @@ class EnterpriseRepositoryImpl implements EnterpriseRepository {
} }
@override @override
Future<void> syncEnterpriseToServer(Enterprise enterprise) async { Future<Enterprise> syncEnterpriseToServer(Enterprise enterprise) async {
// Domain Data Model // Domain Data Model
final enterpriseModel = EnterpriseModel.fromEntity(enterprise); final enterpriseModel = EnterpriseModel.fromEntity(enterprise);
EnterpriseDto syncedDto;
// **** // ****
// Repository DataSource // Repository DataSource
switch (enterprise.syncStatus) { switch (enterprise.syncStatus) {
case SyncStatus.pendingCreate: case SyncStatus.pendingCreate:
await remoteDataSource.createEnterprise(enterpriseModel); syncedDto = await remoteDataSource.createEnterprise(enterpriseModel);
break; break;
case SyncStatus.pendingUpdate: case SyncStatus.pendingUpdate:
await remoteDataSource.updateEnterprise(enterpriseModel); syncedDto = await remoteDataSource.updateEnterprise(enterpriseModel);
break; break;
case SyncStatus.pendingDelete: case SyncStatus.pendingDelete:
await remoteDataSource.deleteEnterprise(enterprise.id); await remoteDataSource.deleteEnterprise(enterprise.id);
break; return enterprise;
// //
case SyncStatus.synced: case SyncStatus.synced:
case SyncStatus.untracked: case SyncStatus.untracked:
break; return enterprise;
} }
return syncedDto.toModel().toEntity();
} }
// todo **************************************************************************
@override @override
Future<void> updateEnterpriseSyncStatus( Future<void> updateEnterpriseSyncStatus(
String enterpriseId, String enterpriseId,

2
lib/app/features/enterprise/domain/repositories/enterprise_repository.dart

@ -21,7 +21,7 @@ abstract class EnterpriseRepository implements SyncableRepository<Enterprise> {
bool? isUploaded, bool? isUploaded,
}); });
Future<void> syncEnterpriseToServer(Enterprise enterprise) async {} Future<Enterprise> syncEnterpriseToServer(Enterprise enterprise);
Future<void> updateEnterpriseSyncStatus(String id, SyncStatus synced) async {} Future<void> updateEnterpriseSyncStatus(String id, SyncStatus synced) async {}

11
lib/app/features/enterprise/domain/usecases/upload_enterprises_usecase.dart

@ -58,15 +58,14 @@ class UploadEnterprisesUseCase {
final enterprise = enterprisesToUpload[i].enterprise; final enterprise = enterprisesToUpload[i].enterprise;
try { try {
// 1. // 1.
await repository.syncEnterpriseToServer(enterprise); final syncedEnterprise = await repository.syncEnterpriseToServer(
enterprise,
);
// 2. // 2.
if (enterprise.syncStatus == SyncStatus.pendingDelete) { if (enterprise.syncStatus == SyncStatus.pendingDelete) {
// repository.deleteLocalEnterprise(enterprise.id); // // repository.deleteLocalEnterprise(enterprise.id);
} else { } else {
await repository.updateEnterpriseSyncStatus( await repository.updateEnterprise(syncedEnterprise);
enterprise.id,
SyncStatus.synced,
);
} }
successCount++; successCount++;
} catch (e) { } catch (e) {

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

@ -51,7 +51,8 @@ class EnterpriseListController extends GetxController {
@override @override
void onInit() { void onInit() {
// - // -
loadAndSyncEnterprises(); // loadAndSyncEnterprises();
search();
super.onInit(); super.onInit();
} }
@ -96,51 +97,119 @@ class EnterpriseListController extends GetxController {
} }
} }
// // []
Future<Enterprise?> _showConflictDialog(EnterpriseConflict conflict) { Future<Enterprise?> _showConflictDialog(EnterpriseConflict conflict) {
return Get.dialog<Enterprise>( return Get.dialog<Enterprise>(
AlertDialog( AlertDialog(
title: Text('数据冲突: ${conflict.localVersion.name}'), title: Text('数据冲突'),
// [ 1] content
content: Column( content: Column(
// mainAxisSize.min Column
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
// crossAxisAlignment.stretch
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
const Text('服务器上的数据与本地数据不一致,请选择要保留的版本。'), Text('${conflict.localVersion.name} 服务器上的数据与本地数据不一致,请选择要保留的版本。'),
const SizedBox(height: 24), // const SizedBox(height: 24),
//
ElevatedButton( // --- ---
Row(
children: [
// 使 Expanded
Expanded(
child: ElevatedButton(
child: Text( child: Text(
'使用客户端版本\n(修改于: ${conflict.localVersion.lastModifiedTime.toUtc().toDateTimeString2()})', '使用客户端版本\n(修改于: ${conflict.localVersion.lastModifiedTime.toLocal().toDateTimeString2()})',
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
onPressed: () => Get.back(result: conflict.localVersion), onPressed: () => Get.back(result: conflict.localVersion),
), ),
),
const SizedBox(width: 8), //
//
IconButton(
icon: const Icon(Icons.info_outline),
tooltip: '查看客户端版本详情',
onPressed: () => navigateToDetailsView(conflict.localVersion),
),
],
),
const SizedBox(height: 8), const SizedBox(height: 8),
// // --- ---
ElevatedButton( Row(
children: [
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Get.theme.colorScheme.primary, backgroundColor: Get.theme.colorScheme.primary,
foregroundColor: Get.theme.colorScheme.onPrimary, foregroundColor: Get.theme.colorScheme.onPrimary,
), ),
child: Text( child: Text(
'使用服务器版本\n(修改于: ${conflict.serverVersion.lastModifiedTime.toUtc().toDateTimeString2()})', '使用服务器版本\n(修改于: ${conflict.serverVersion.lastModifiedTime.toLocal().toDateTimeString2()})',
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
onPressed: () => Get.back(result: conflict.serverVersion), onPressed: () => Get.back(result: conflict.serverVersion),
), ),
),
const SizedBox(width: 8),
IconButton(
icon: const Icon(Icons.info_outline),
tooltip: '查看服务器版本详情',
onPressed: () =>
navigateToDetailsView(conflict.serverVersion),
),
],
),
], ],
), ),
// [ 2] actions
// actions: [ ... ],
), ),
// false
barrierDismissible: false,
); );
} }
// //
// Future<Enterprise?> _showConflictDialog(EnterpriseConflict conflict) {
// return Get.dialog<Enterprise>(
// AlertDialog(
// title: Text('数据冲突: ${conflict.localVersion.name}'),
// // [ 1] content
// content: Column(
// // mainAxisSize.min Column
// mainAxisSize: MainAxisSize.min,
// // crossAxisAlignment.stretch
// crossAxisAlignment: CrossAxisAlignment.stretch,
// children: [
// const Text('服务器上的数据与本地数据不一致,请选择要保留的版本。'),
// const SizedBox(height: 24), //
// //
// ElevatedButton(
// child: Text(
// '使用客户端版本\n(修改于: ${conflict.localVersion.lastModifiedTime.toUtc().toDateTimeString2()})',
// textAlign: TextAlign.center,
// ),
// onPressed: () => Get.back(result: conflict.localVersion),
// ),
// const SizedBox(height: 8),
// //
// ElevatedButton(
// style: ElevatedButton.styleFrom(
// backgroundColor: Get.theme.colorScheme.primary,
// foregroundColor: Get.theme.colorScheme.onPrimary,
// ),
// child: Text(
// '使用服务器版本\n(修改于: ${conflict.serverVersion.lastModifiedTime.toUtc().toDateTimeString2()})',
// textAlign: TextAlign.center,
// ),
// onPressed: () => Get.back(result: conflict.serverVersion),
// ),
// ],
// ),
// // [ 2] actions
// // actions: [ ... ],
// ),
// );
// }
void search() { void search() {
loadEnterprises(); loadEnterprises();
@ -191,6 +260,17 @@ class EnterpriseListController extends GetxController {
} }
} }
// []
void navigateToDetailsView(Enterprise enterprise) {
Get.toNamed(
AppRoutes.enterpriseForm,
arguments: {
'data': enterprise,
'mode': FormMode.view, //
},
);
}
/// ///
Future<void> navigateToAddForm() async { Future<void> navigateToAddForm() async {
final result = await Get.toNamed( final result = await Get.toNamed(

2
lib/app/features/enterprise/presentation/pages/enterprise_form_page.dart

@ -22,7 +22,7 @@ class EnterpriseFormPage extends GetView<EnterpriseFormController> {
child: Column( child: Column(
children: [ children: [
Expanded(child: EnterpriseFormView()), Expanded(child: EnterpriseFormView()),
_buildBottomButtons(), if (!controller.isReadOnly) _buildBottomButtons(),
], ],
), ),
), ),

Loading…
Cancel
Save