Centralize all API call logic (fetchBoxInfo, saveBoxRecord, updateBoxRecord, deleteBoxRecord) into BoxingApiActions class with unified error categorization (network, duplicate, missingApiUrl). Add helper methods to reduce repetitive error handling in boxing_page. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
151 lines
4.3 KiB
Dart
151 lines
4.3 KiB
Dart
import 'package:pad_scanner/services/api_service.dart';
|
|
import 'package:pad_scanner/services/app_config_service.dart';
|
|
|
|
enum BoxingActionErrorKind { missingApiUrl, network, duplicate, backend }
|
|
|
|
class BoxingActionResult<T> {
|
|
final bool success;
|
|
final T? data;
|
|
final BoxingActionErrorKind? errorKind;
|
|
final String? errorMessage;
|
|
final int? boxNo;
|
|
|
|
const BoxingActionResult._({
|
|
required this.success,
|
|
this.data,
|
|
this.errorKind,
|
|
this.errorMessage,
|
|
this.boxNo,
|
|
});
|
|
|
|
const BoxingActionResult.ok(T data) : this._(success: true, data: data);
|
|
|
|
const BoxingActionResult.error({
|
|
required BoxingActionErrorKind kind,
|
|
required String message,
|
|
int? boxNo,
|
|
}) : this._(
|
|
success: false,
|
|
errorKind: kind,
|
|
errorMessage: message,
|
|
boxNo: boxNo,
|
|
);
|
|
}
|
|
|
|
typedef ApiUrlLoader = Future<String?> Function();
|
|
|
|
class BoxingApiActions {
|
|
static const networkErrorMessage = '网络异常,请检查网络连接';
|
|
static const missingApiUrlMessage = '未配置 API 地址,请前往设置';
|
|
|
|
final ApiService _apiService;
|
|
final ApiUrlLoader _loadApiUrl;
|
|
|
|
BoxingApiActions({required ApiService apiService, ApiUrlLoader? loadApiUrl})
|
|
: _apiService = apiService,
|
|
_loadApiUrl =
|
|
loadApiUrl ?? (() => AppConfigService().getString('api_url'));
|
|
|
|
Future<BoxingActionResult<BoxInfoResult>> fetchBoxInfo(String zongpai) async {
|
|
final baseUrl = await _requireBaseUrl();
|
|
if (baseUrl == null) return _missingApiUrl();
|
|
|
|
final result = await _apiService.fetchBoxInfo(
|
|
baseUrl: baseUrl,
|
|
zongpaiNo: zongpai,
|
|
);
|
|
if (result.success) return BoxingActionResult.ok(result);
|
|
return BoxingActionResult.error(
|
|
kind: _kindForMessage(result.errorMessage),
|
|
message: result.errorMessage ?? '查询失败',
|
|
);
|
|
}
|
|
|
|
Future<BoxingActionResult<BoxSaveResult>> saveBoxRecord({
|
|
required String zongpaiNo,
|
|
required int boxNo,
|
|
required int quantity,
|
|
}) async {
|
|
final baseUrl = await _requireBaseUrl();
|
|
if (baseUrl == null) return _missingApiUrl();
|
|
|
|
final result = await _apiService.saveBoxRecord(
|
|
baseUrl: baseUrl,
|
|
zongpaiNo: zongpaiNo,
|
|
boxNo: boxNo,
|
|
quantity: quantity,
|
|
);
|
|
return _saveResult(result, fallbackMessage: '提交失败');
|
|
}
|
|
|
|
Future<BoxingActionResult<BoxSaveResult>> updateBoxRecord({
|
|
required int boxItemId,
|
|
required int boxNo,
|
|
required int quantity,
|
|
}) async {
|
|
final baseUrl = await _requireBaseUrl();
|
|
if (baseUrl == null) return _missingApiUrl();
|
|
|
|
final result = await _apiService.updateBoxRecord(
|
|
baseUrl: baseUrl,
|
|
boxItemId: boxItemId,
|
|
boxNo: boxNo,
|
|
quantity: quantity,
|
|
);
|
|
return _saveResult(result, fallbackMessage: '修改失败');
|
|
}
|
|
|
|
Future<BoxingActionResult<BoxDeleteResult>> deleteBoxRecord({
|
|
required int boxItemId,
|
|
}) async {
|
|
final baseUrl = await _requireBaseUrl();
|
|
if (baseUrl == null) return _missingApiUrl();
|
|
|
|
final result = await _apiService.deleteBoxRecord(
|
|
baseUrl: baseUrl,
|
|
boxItemId: boxItemId,
|
|
);
|
|
if (result.success) return BoxingActionResult.ok(result);
|
|
return BoxingActionResult.error(
|
|
kind: _kindForMessage(result.errorMessage),
|
|
message: result.errorMessage ?? '删除失败',
|
|
);
|
|
}
|
|
|
|
Future<String?> _requireBaseUrl() async {
|
|
final baseUrl = await _loadApiUrl() ?? '';
|
|
if (baseUrl.isEmpty) return null;
|
|
return baseUrl;
|
|
}
|
|
|
|
BoxingActionResult<T> _missingApiUrl<T>() {
|
|
return const BoxingActionResult.error(
|
|
kind: BoxingActionErrorKind.missingApiUrl,
|
|
message: missingApiUrlMessage,
|
|
);
|
|
}
|
|
|
|
BoxingActionResult<BoxSaveResult> _saveResult(
|
|
BoxSaveResult result, {
|
|
required String fallbackMessage,
|
|
}) {
|
|
if (result.success) return BoxingActionResult.ok(result);
|
|
if (result.isDuplicate) {
|
|
return BoxingActionResult.error(
|
|
kind: BoxingActionErrorKind.duplicate,
|
|
message: result.errorMessage ?? fallbackMessage,
|
|
boxNo: result.boxNo,
|
|
);
|
|
}
|
|
return BoxingActionResult.error(
|
|
kind: _kindForMessage(result.errorMessage),
|
|
message: result.errorMessage ?? fallbackMessage,
|
|
);
|
|
}
|
|
|
|
BoxingActionErrorKind _kindForMessage(String? message) {
|
|
if (message == networkErrorMessage) return BoxingActionErrorKind.network;
|
|
return BoxingActionErrorKind.backend;
|
|
}
|
|
}
|