diff --git a/android/gradle.properties b/android/gradle.properties index a4070d9..e4cd1cd 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,4 +1,5 @@ org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError +kotlin.incremental=false android.useAndroidX=true android.enableJetifier=true systemProp.http.proxyHost=127.0.0.1 diff --git a/lib/pages/boxing_page.dart b/lib/pages/boxing_page.dart index 7d3ad07..86e016d 100644 --- a/lib/pages/boxing_page.dart +++ b/lib/pages/boxing_page.dart @@ -155,8 +155,10 @@ class _BoxingPageState extends State { return; } - // 其他模式:等待扫码阶段才处理 - if (_phase != _Phase.waiting) return; + // 一码一箱:允许覆盖,直接查询新二维码(不提前清空状态,避免闪烁) + if (_mode != BoxingMode.one2one && _phase != _Phase.waiting) { + return; + } _queryBoxInfo(zongpai); } @@ -276,11 +278,17 @@ class _BoxingPageState extends State { setState(() => _isSubmitting = true); + final modeStr = switch (_mode) { + BoxingMode.one2one => 'one-to-one', + BoxingMode.one2many => 'one-to-many', + BoxingMode.many2one => 'many-to-one', + }; final result = await _apiService.saveBoxRecord( baseUrl: baseUrl, zongpaiNo: _zongpaiNo!, boxNo: boxNo, quantity: quantity, + boxMode: modeStr, ); if (!mounted) return; @@ -290,10 +298,14 @@ class _BoxingPageState extends State { if (result.success) { _onSubmitSuccess(boxNo, quantity); } else if (result.isDuplicate) { - _showFeedback( - '排产号 ${result.paichanNo ?? ""} 下箱号 ${result.boxNo ?? ""} 已存在', - isError: true, - ); + if (_mode == BoxingMode.one2one) { + _showFeedback('该总排号已绑定箱号 ${result.boxNo ?? "?"},请勿重复装箱', isError: true); + } else { + _showFeedback( + '排产号 ${result.paichanNo ?? ""} 下箱号 ${result.boxNo ?? ""} 已存在', + isError: true, + ); + } } else { _showFeedback(result.errorMessage ?? '提交失败', isError: true); } @@ -305,10 +317,12 @@ class _BoxingPageState extends State { _lastQuantity = quantity; // 刷新已有箱号列表(将新记录加入本地列表) _existingBoxes = List.from(_existingBoxes) - ..add(BoxDetailData( - boxNo: boxNo, - items: [BoxItemData(zongpaiNo: _zongpaiNo!, quantity: quantity)], - )); + ..add( + BoxDetailData( + boxNo: boxNo, + items: [BoxItemData(zongpaiNo: _zongpaiNo!, quantity: quantity)], + ), + ); _maxBoxNo = _maxBoxNo > boxNo ? _maxBoxNo : boxNo; }); @@ -440,10 +454,7 @@ class _BoxingPageState extends State { child: TextButton.icon( onPressed: _cycleMode, icon: const Icon(Icons.swap_horiz, size: 18), - label: Text( - _modeLabel, - style: const TextStyle(fontSize: 13), - ), + label: Text(_modeLabel, style: const TextStyle(fontSize: 13)), style: TextButton.styleFrom( foregroundColor: _mode == BoxingMode.many2one ? Colors.orange @@ -704,7 +715,9 @@ class _BoxingPageState extends State { style: TextStyle( fontSize: 13, fontWeight: FontWeight.w600, - color: _maxBoxNo > 0 ? Colors.amber.shade800 : Colors.grey, + color: _maxBoxNo > 0 + ? Colors.amber.shade800 + : Colors.grey, ), ), ], @@ -824,8 +837,9 @@ class _BoxingPageState extends State { child: ElevatedButton( onPressed: _canSubmit ? _submit : null, style: ElevatedButton.styleFrom( - backgroundColor: - _canSubmit ? Theme.of(context).colorScheme.primary : Colors.grey.shade300, + backgroundColor: _canSubmit + ? Theme.of(context).colorScheme.primary + : Colors.grey.shade300, foregroundColor: _canSubmit ? Colors.white : Colors.grey.shade600, ), child: _isSubmitting diff --git a/lib/services/api_service.dart b/lib/services/api_service.dart index 7e988ba..47cc423 100644 --- a/lib/services/api_service.dart +++ b/lib/services/api_service.dart @@ -15,11 +15,14 @@ class RegistrationResult { this.duplicateInfo, }); - factory RegistrationResult.ok() => - RegistrationResult(success: true); + factory RegistrationResult.ok() => RegistrationResult(success: true); factory RegistrationResult.duplicate(Map info) => - RegistrationResult(success: false, isDuplicate: true, duplicateInfo: info); + RegistrationResult( + success: false, + isDuplicate: true, + duplicateInfo: info, + ); factory RegistrationResult.error(String message) => RegistrationResult(success: false, errorMessage: message); @@ -50,7 +53,8 @@ class BoxDetailData { BoxDetailData({required this.boxNo, required this.items}); factory BoxDetailData.fromJson(Map json) { - final items = (json['items'] as List?) + final items = + (json['items'] as List?) ?.map((i) => BoxItemData.fromJson(i as Map)) .toList() ?? []; @@ -81,7 +85,8 @@ class BoxInfoResult { }); factory BoxInfoResult.ok(Map json) { - final boxes = (json['existing_boxes'] as List?) + final boxes = + (json['existing_boxes'] as List?) ?.map((b) => BoxDetailData.fromJson(b as Map)) .toList() ?? []; @@ -144,7 +149,7 @@ class ApiService { final Duration timeout; ApiService({http.Client? client, this.timeout = const Duration(seconds: 5)}) - : _client = client ?? http.Client(); + : _client = client ?? http.Client(); /// Submit a shelf registration (上架登记). Future registerLocation({ @@ -177,7 +182,10 @@ class ApiService { return RegistrationResult.duplicate(body); default: final body = jsonDecode(response.body) as Map; - final msg = body['message'] ?? body['error'] ?? 'Unknown error (${response.statusCode})'; + final msg = + body['message'] ?? + body['error'] ?? + 'Unknown error (${response.statusCode})'; return RegistrationResult.error(msg.toString()); } } catch (e) { @@ -190,9 +198,9 @@ class ApiService { required String baseUrl, required String zongpaiNo, }) async { - final uri = Uri.parse('$baseUrl/CargoTrace/box/info').replace( - queryParameters: {'zongpai_no': zongpaiNo}, - ); + final uri = Uri.parse( + '$baseUrl/CargoTrace/box/info', + ).replace(queryParameters: {'zongpai_no': zongpaiNo}); try { final response = await _client .get(uri, headers: {'Content-Type': 'application/json'}) @@ -220,6 +228,7 @@ class ApiService { required String zongpaiNo, required int boxNo, required int quantity, + required String boxMode, }) async { final uri = Uri.parse('$baseUrl/CargoTrace/box'); try { @@ -231,6 +240,7 @@ class ApiService { 'zongpai_no': zongpaiNo, 'box_no': boxNo, 'quantity': quantity, + 'box_mode': boxMode, }), ) .timeout(timeout);