Add pending accessories section to both single-code and multi-code boxing modes. Accessories display with orange styling and a "加入本箱" button that calls saveBoxRecord with item_type=accessory. Extend API service with PendingAccessory model, itemType fields on data classes, and optional accessory_id parameter on saveBoxRecord. Show accessories with visual indicator (wrench icon + orange background) in boxing detail page. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
205 lines
6.0 KiB
Dart
205 lines
6.0 KiB
Dart
// ignore_for_file: invalid_use_of_protected_member, unnecessary_this
|
|
|
|
part of '../../boxing_page.dart';
|
|
|
|
extension _BoxingSubmitPart on _BoxingPageState {
|
|
Future<bool> _submit() async {
|
|
if (!_canSubmit) return false;
|
|
|
|
final boxNo = int.parse(_boxNoController.text);
|
|
final quantity = int.parse(_quantityController.text);
|
|
|
|
setState(() => _isSubmitting = true);
|
|
|
|
final editing = _editingBox;
|
|
final action = editing == null
|
|
? await _apiActions.saveBoxRecord(
|
|
zongpaiNo: _zongpaiNo!,
|
|
boxNo: boxNo,
|
|
quantity: quantity,
|
|
)
|
|
: await _apiActions.updateBoxRecord(
|
|
boxItemId: editing.boxItemId,
|
|
boxNo: boxNo,
|
|
quantity: quantity,
|
|
);
|
|
|
|
if (!mounted) return false;
|
|
|
|
setState(() => _isSubmitting = false);
|
|
|
|
if (action.success) {
|
|
if (editing == null) {
|
|
this._onSubmitSuccess(boxNo, quantity, action.data!.boxItemId);
|
|
} else {
|
|
this._onUpdateSuccess(editing, boxNo, quantity);
|
|
}
|
|
return true;
|
|
} else if (action.errorKind == BoxingActionErrorKind.duplicate) {
|
|
_feedbackService.trigger(FeedbackEvent.duplicateBoxNo);
|
|
this._showStatusOverride(
|
|
'该总排号在箱号 ${action.boxNo ?? ""} 已存在,请重新输入',
|
|
StatusDotColor.amber,
|
|
const Duration(seconds: 2),
|
|
);
|
|
return false;
|
|
} else {
|
|
this._showActionError(action, fallback: '提交失败');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void _onSubmitSuccess(int boxNo, int quantity, int? boxItemId) {
|
|
_feedbackService.trigger(FeedbackEvent.submitSuccess);
|
|
|
|
setState(() {
|
|
if (_mode == BoxingMode.singleCode && boxItemId != null) {
|
|
_currentZongpaiBoxes = List.from(_currentZongpaiBoxes)
|
|
..add(
|
|
CurrentZongpaiBoxData(
|
|
boxItemId: boxItemId,
|
|
boxNo: boxNo,
|
|
quantity: quantity,
|
|
),
|
|
);
|
|
}
|
|
this._addExistingBoxItem(boxNo, quantity, boxItemId);
|
|
_maxBoxNo = _maxBoxNo > boxNo ? _maxBoxNo : boxNo;
|
|
});
|
|
|
|
switch (_mode) {
|
|
case BoxingMode.singleCode:
|
|
final remaining = _remainingQuantity;
|
|
if (remaining <= 0) {
|
|
this._showStatusOverride(
|
|
'装箱成功',
|
|
StatusDotColor.green,
|
|
const Duration(milliseconds: 1500),
|
|
);
|
|
} else {
|
|
setState(() {
|
|
_phase = BoxingPhase.scanned;
|
|
_boxNoController.text = (_maxBoxNo + 1).toString();
|
|
_quantityController.text = remaining.toString();
|
|
_quantityController.selection = TextSelection(
|
|
baseOffset: 0,
|
|
extentOffset: _quantityController.text.length,
|
|
);
|
|
_isDuplicateBoxNo = false;
|
|
});
|
|
_focusQuantityInput();
|
|
this._showStatusOverride(
|
|
'请继续完成剩余数量装箱',
|
|
StatusDotColor.green,
|
|
const Duration(milliseconds: 1500),
|
|
);
|
|
}
|
|
|
|
case BoxingMode.multiCode:
|
|
_lastScannedPaichanNo = _paichanNo;
|
|
setState(() {
|
|
if (boxItemId != null) {
|
|
_manyToOnePackedItems.add(
|
|
ManyToOnePackedItem(
|
|
boxItemId: boxItemId,
|
|
zongpaiNo: _zongpaiNo!,
|
|
paichanNo: _paichanNo,
|
|
workOrderNo: _workOrderNo,
|
|
boxNo: boxNo,
|
|
quantity: quantity,
|
|
totalQuantity: _erpQuantity,
|
|
),
|
|
);
|
|
}
|
|
_phase = BoxingPhase.waiting;
|
|
_zongpaiNo = null;
|
|
_editingPackedItemId = null;
|
|
_editingPackedQuantity = '';
|
|
_deletingPackedItemId = null;
|
|
});
|
|
this._showStatusOverride(
|
|
'装箱成功,请继续扫码',
|
|
StatusDotColor.green,
|
|
const Duration(milliseconds: 1500),
|
|
);
|
|
}
|
|
}
|
|
|
|
void _onUpdateSuccess(
|
|
CurrentZongpaiBoxData editing,
|
|
int boxNo,
|
|
int quantity,
|
|
) {
|
|
_feedbackService.trigger(FeedbackEvent.submitSuccess);
|
|
|
|
setState(() {
|
|
_currentZongpaiBoxes = _currentZongpaiBoxes.map((item) {
|
|
if (item.boxItemId != editing.boxItemId) return item;
|
|
return CurrentZongpaiBoxData(
|
|
boxItemId: item.boxItemId,
|
|
boxNo: boxNo,
|
|
quantity: quantity,
|
|
);
|
|
}).toList();
|
|
this._replaceExistingBoxItem(editing, boxNo, quantity);
|
|
_editingBox = null;
|
|
_boxNoController.text = (_maxBoxNo + 1).toString();
|
|
final remaining = _remainingQuantity;
|
|
if (remaining > 0) {
|
|
_quantityController.text = remaining.toString();
|
|
} else {
|
|
_quantityController.clear();
|
|
}
|
|
_isDuplicateBoxNo = false;
|
|
});
|
|
this._showStatusOverride(
|
|
'修改成功',
|
|
StatusDotColor.green,
|
|
const Duration(milliseconds: 1500),
|
|
);
|
|
}
|
|
|
|
Future<void> _submitAccessory(PendingAccessory accessory) async {
|
|
if (_zongpaiNo == null || _isSubmitting) return;
|
|
|
|
final boxNo = int.tryParse(_boxNoController.text);
|
|
if (boxNo == null || boxNo <= 0) {
|
|
this._showStatusOverride(
|
|
'请先输入有效箱号',
|
|
StatusDotColor.red,
|
|
const Duration(seconds: 2),
|
|
);
|
|
return;
|
|
}
|
|
|
|
setState(() => _isSubmitting = true);
|
|
|
|
final action = await _apiActions.saveBoxRecord(
|
|
zongpaiNo: _zongpaiNo!,
|
|
boxNo: boxNo,
|
|
quantity: accessory.quantity,
|
|
itemType: 'accessory',
|
|
accessoryId: accessory.accessoryId,
|
|
);
|
|
|
|
if (!mounted) return;
|
|
|
|
setState(() => _isSubmitting = false);
|
|
|
|
if (action.success) {
|
|
_feedbackService.trigger(FeedbackEvent.submitSuccess);
|
|
// Refresh box info to update pending accessories
|
|
await this._queryBoxInfo(_zongpaiNo!);
|
|
if (mounted) {
|
|
this._showStatusOverride(
|
|
'${accessory.accessoryType} 已加入箱号 $boxNo',
|
|
StatusDotColor.green,
|
|
const Duration(milliseconds: 1500),
|
|
);
|
|
}
|
|
} else {
|
|
this._showActionError(action, fallback: '附件装箱失败');
|
|
}
|
|
}
|
|
}
|