Files
flutterApp/lib/features/regions/data/datasources/region_remote_datasource.dart
2026-11-06 08:44:05 +08:00

118 lines
4.4 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:convert';
import 'package:dio/dio.dart';
import '../../../../core/consts/http_api_consts.dart';
import '../../../../core/logging/i_logger_service.dart';
import '../../domain/entities/region_draft.dart';
import '../models/region_model.dart';
class RegionRemoteDatasource {
RegionRemoteDatasource(this.dio, this.logger);
final Dio dio;
final ILoggerService logger;
Future<List<RegionDraft>> loadRegions(int siteId) async {
logger.logWithLevel(
'[分区列表] 请求: GET ${HttpApiConsts.regionsBySite}?siteId=$siteId',
shouldLog: true,
);
final response = await dio.get(
HttpApiConsts.regionsBySite,
queryParameters: {'siteId': siteId},
);
final data = response.data;
logger.logWithLevel(
'[分区列表] 响应: HTTP ${response.statusCode}, ${jsonEncode(data)}',
shouldLog: true,
);
if (response.statusCode != 200 ||
data is! Map ||
'${data['code']}' != '200') {
throw Exception(data is Map ? data['msg'] ?? '分区加载失败' : '分区列表响应格式错误');
}
final rows = data['data'] ?? const [];
if (rows is! List) throw const FormatException('分区列表 data 必须为数组');
final result = <int, RegionDraft>{};
for (final row in rows) {
if (row is! Map) continue;
if (row['delFlag'] == true ||
row['type'] != null && row['type'] != 'region') {
continue;
}
final region = RegionModel.fromJson(Map<String, dynamic>.from(row));
if (region.siteId == siteId) result[region.id!] = region;
}
return result.values.toList();
}
Future<bool> deleteRegions(List<int> ids) async {
logger.logWithLevel(
'[分区删除] 请求: POST ${HttpApiConsts.deleteRegions}, 参数: ${jsonEncode(ids)}',
shouldLog: true,
);
final response = await dio.post(HttpApiConsts.deleteRegions, data: ids);
final data = response.data;
logger.logWithLevel(
'[分区删除] 响应: HTTP ${response.statusCode}, ${jsonEncode(data)}',
shouldLog: true,
);
if (response.statusCode != 200 ||
data is! Map ||
'${data['code']}' != '200') {
throw Exception(data is Map ? data['msg'] ?? '分区删除失败' : '分区删除响应格式错误');
}
final result = data['data'];
if (result == false || result is num && result <= 0) {
throw Exception('分区未删除,请重试');
}
return true;
}
Future<RegionSaveResult> save(RegionDraft draft) async {
final body = <String, dynamic>{
if (draft.id != null) 'id': draft.id,
'regionName': draft.name.trim(),
'regionCode': draft.code.trim(),
'siteId': draft.siteId,
'type': 'region',
'remark': draft.remark,
'scope': [
for (final point in draft.scope) {'lat': point.lat, 'lng': point.lng},
],
'status': draft.enabled ? 1 : 0,
'defaultRoute': draft.defaultRouteId,
'bindRoutes': draft.boundRouteIds.toSet().toList()..sort(),
};
final url = HttpApiConsts.saveRegion;
logger.logWithLevel('[分区保存] 请求: POST $url', shouldLog: true);
logger.logWithLevel('[分区保存] 参数: ${jsonEncode(body)}', shouldLog: true);
try {
final response = await dio.post(url, data: body);
logger.logWithLevel(
'[分区保存] 响应: HTTP ${response.statusCode}, ${jsonEncode(response.data)}',
shouldLog: true,
);
final data = response.data;
if (response.statusCode != 200 ||
data is! Map ||
'${data['code']}' != '200') {
throw Exception(data is Map ? data['msg'] ?? '分区保存失败' : '分区保存响应格式错误');
}
final result = data['data'];
if (result == false || result is num && result <= 0) {
throw Exception('分区未保存,请重试');
}
// 数字 data 视为保存数量;只有对象内明确的 id 才能用作后续更新主键。
final returnedId = result is Map ? int.tryParse('${result['id']}') : null;
final id = returnedId != null && returnedId > 0 ? returnedId : draft.id;
logger.logWithLevel(
'[分区保存] 成功,${draft.id == null ? '新建' : '修改'}分区,id=$id',
shouldLog: true,
);
return RegionSaveResult(id: id);
} catch (error) {
logger.logWithLevel('[分区保存] 异常: $error', shouldLog: true);
rethrow;
}
}
}