// ignore_for_file: invalid_use_of_protected_member, unnecessary_this part of '../../boxing_page.dart'; extension _BoxingScanPart on _BoxingPageState { void _onScan(ScanResult result) { if (_isAutoProcessing) { return; } if (_crossPaichaPending) { _feedbackService.trigger(FeedbackEvent.alreadyCompleted); return; } final parsed = CodeParser.parse(result.barcode); if (parsed.type != CodeType.zongpaiNo) { _feedbackService.trigger(FeedbackEvent.scanInvalid); this._showStatusOverride( '无效码,请重新扫描', StatusDotColor.red, const Duration(seconds: 2), ); return; } final zongpai = parsed.value; // 三种模式都允许后扫入的总排号覆盖当前扫码区;未确认数据不会入库。 this._queryBoxInfo(zongpai); } Future _queryBoxInfo(String zongpai) async { final action = await _apiActions.fetchBoxInfo(zongpai); if (!mounted) return false; if (!action.success) { _feedbackService.trigger(switch (action.errorKind) { BoxingActionErrorKind.network => FeedbackEvent.networkError, BoxingActionErrorKind.missingApiUrl => FeedbackEvent.submitFailure, _ => FeedbackEvent.scanInvalid, }); this._showStatusOverride( action.errorMessage ?? '查询失败', this._dotForActionError(action.errorKind), const Duration(seconds: 2), ); return false; } final result = action.data!; // 判断该总牌号是否已全部装箱完毕 final packedQuantity = result.currentZongpaiBoxes.fold( 0, (sum, item) => sum + item.quantity, ); final totalQuantity = result.quantity ?? 0; final alreadyCompleted = totalQuantity > 0 && packedQuantity >= totalQuantity; _feedbackService.trigger( alreadyCompleted ? FeedbackEvent.alreadyCompleted : FeedbackEvent.scanValid, ); setState(() { _zongpaiNo = zongpai; _paichanNo = result.paichanNo; _workOrderNo = result.workOrderNo; _erpQuantity = result.quantity; _currentZongpaiBoxes = result.currentZongpaiBoxes; _existingBoxes = result.existingBoxes; _maxBoxNo = result.maxBoxNo; _phase = BoxingPhase.scanned; _isDuplicateBoxNo = false; _editingBox = null; _editingAssignedItemId = null; _editingAssignedQuantity = ''; _deletingAssignedItemId = null; _completedJumpBoxNo = null; _statusOverrideText = null; if (_mode == BoxingMode.singleCode) { _paichanSwitchNotice = null; } // 根据模式自动填充 this._applyAutoFill(); }); return true; } Future _processAutoScanCodes(List codes) async { if (!mounted) return; setState(() { _isAutoProcessing = true; _autoWarnings.clear(); _statusOverrideText = '正在同步转运数据...'; _statusOverrideDot = StatusDotColor.orange; }); if (_mode == BoxingMode.singleCode) { final code = codes.first; final ok = await this._queryBoxInfo(code); if (!ok && mounted) { setState(() => _autoWarnings.add('总排号 $code 未找到排产号信息,已忽略')); } } else { for (final code in codes) { if (!mounted) return; final queried = await this._queryBoxInfo(code); if (!queried) { if (mounted) { setState(() => _autoWarnings.add('总排号 $code 未找到排产号信息,已忽略')); } continue; } if (!_canSubmit) { if (mounted) { setState(() => _autoWarnings.add('总排号 $code 暂不能装箱,已忽略')); } continue; } final saved = await this._submit(); if (!saved && mounted) { setState(() => _autoWarnings.add('总排号 $code 自动装箱失败,请手动处理')); } } } if (!mounted) return; setState(() { _isAutoProcessing = false; _statusOverrideText = null; _statusOverrideDot = null; }); _focusQuantityInput(); _requestFocus(); } void _applyAutoFill() { switch (_mode) { case BoxingMode.singleCode: final remaining = _remainingQuantity; if (remaining <= 0) { _boxNoController.clear(); _quantityController.clear(); _statusOverrideText = '该总排号已全部装箱完毕'; _statusOverrideDot = StatusDotColor.red; return; } _boxNoController.text = (_maxBoxNo + 1).toString(); _quantityController.text = remaining.toString(); _quantityController.selection = TextSelection( baseOffset: 0, extentOffset: _quantityController.text.length, ); WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted && _mode == BoxingMode.singleCode) { _quantityFocusNode.requestFocus(); } }); case BoxingMode.multiCode: final decision = decideMultiCodePaichanContext( lastPaichanNo: _lastScannedPaichanNo, currentPaichanNo: _paichanNo, currentBoxNoText: _boxNoController.text, maxBoxNo: _maxBoxNo, ); if (decision.isSwitched) { _crossPaichaPending = true; _feedbackService.trigger(FeedbackEvent.alreadyCompleted); this._showCrossPaichaDialog(); return; } else { _paichanSwitchNotice = null; } final boxNoToApply = decision.boxNoToApply; if (boxNoToApply != null) { _boxNoController.text = boxNoToApply.toString(); } _lastScannedPaichanNo = _paichanNo; final remaining = _remainingQuantity; if (remaining <= 0) { _quantityController.clear(); if (_manyToOnePackedItems.isEmpty && _currentZongpaiBoxes.isNotEmpty) { _completedJumpBoxNo = _currentZongpaiBoxes.first.boxNo; } _statusOverrideText = '该总排号已全部装箱完毕'; _statusOverrideDot = StatusDotColor.red; return; } _quantityController.text = remaining.toString(); _quantityController.selection = TextSelection( baseOffset: 0, extentOffset: _quantityController.text.length, ); WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted && _mode == BoxingMode.multiCode) { _quantityFocusNode.requestFocus(); } }); } _isDuplicateBoxNo = _boxNoIsDuplicate(); } Future _showCrossPaichaDialog() async { final currentPaicha = _lastScannedPaichanNo ?? '--'; final newPaicha = _paichanNo ?? '--'; final confirmed = await showCrossPaichanDialog( context: context, currentPaicha: currentPaicha, newPaicha: newPaicha, ); if (!mounted) return; confirmed ? this._confirmPaichanSwitch() : this._cancelPaichanSwitch(); } void _confirmPaichanSwitch() { setState(() { _crossPaichaPending = false; _manyToOnePackedItems.clear(); _editingPackedItemId = null; _editingPackedQuantity = ''; _deletingPackedItemId = null; _paichanSwitchNotice = '排产号已切换:${_paichanNo ?? "--"}'; _boxNoController.text = (_maxBoxNo + 1).toString(); _lastScannedPaichanNo = _paichanNo; }); _feedbackService.trigger(FeedbackEvent.paichanSwitch); // Continue with remaining quantity flow final remaining = _remainingQuantity; if (remaining <= 0) { _quantityController.clear(); if (_manyToOnePackedItems.isEmpty && _currentZongpaiBoxes.isNotEmpty) { _completedJumpBoxNo = _currentZongpaiBoxes.first.boxNo; } setState(() { _statusOverrideText = '该总排号已全部装箱完毕'; _statusOverrideDot = StatusDotColor.red; }); return; } setState(() { _quantityController.text = remaining.toString(); _quantityController.selection = TextSelection( baseOffset: 0, extentOffset: _quantityController.text.length, ); _isDuplicateBoxNo = _boxNoIsDuplicate(); }); WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted && _mode == BoxingMode.multiCode) { _quantityFocusNode.requestFocus(); } }); } void _cancelPaichanSwitch() { setState(() { _crossPaichaPending = false; _zongpaiNo = null; _paichanNo = _lastScannedPaichanNo; _phase = BoxingPhase.waiting; }); } }