feat: extend boxing page for accessory boxing support
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>
This commit is contained in:
@@ -118,6 +118,30 @@ class PaichaOverviewResult {
|
||||
|
||||
// === 装箱模块数据类 ===
|
||||
|
||||
/// 待装箱附件
|
||||
class PendingAccessory {
|
||||
final int accessoryId;
|
||||
final String accessoryType;
|
||||
final int quantity;
|
||||
final String? locationCode;
|
||||
|
||||
PendingAccessory({
|
||||
required this.accessoryId,
|
||||
required this.accessoryType,
|
||||
required this.quantity,
|
||||
this.locationCode,
|
||||
});
|
||||
|
||||
factory PendingAccessory.fromJson(Map<String, dynamic> json) {
|
||||
return PendingAccessory(
|
||||
accessoryId: json['accessory_id'] as int,
|
||||
accessoryType: json['accessory_type'] as String,
|
||||
quantity: json['quantity'] as int,
|
||||
locationCode: json['location_code']?.toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 箱号内单个总排号明细
|
||||
class BoxItemData {
|
||||
final int? boxItemId;
|
||||
@@ -125,6 +149,7 @@ class BoxItemData {
|
||||
final String? workOrderNo;
|
||||
final int quantity;
|
||||
final int? totalQuantity;
|
||||
final String itemType;
|
||||
|
||||
BoxItemData({
|
||||
this.boxItemId,
|
||||
@@ -132,6 +157,7 @@ class BoxItemData {
|
||||
this.workOrderNo,
|
||||
required this.quantity,
|
||||
this.totalQuantity,
|
||||
this.itemType = 'product',
|
||||
});
|
||||
|
||||
factory BoxItemData.fromJson(Map<String, dynamic> json) {
|
||||
@@ -141,6 +167,7 @@ class BoxItemData {
|
||||
workOrderNo: json['work_order_no']?.toString(),
|
||||
quantity: json['quantity'] as int,
|
||||
totalQuantity: json['total_quantity'] as int?,
|
||||
itemType: json['item_type'] as String? ?? 'product',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -167,11 +194,13 @@ class CurrentZongpaiBoxData {
|
||||
final int boxItemId;
|
||||
final int boxNo;
|
||||
final int quantity;
|
||||
final String itemType;
|
||||
|
||||
CurrentZongpaiBoxData({
|
||||
required this.boxItemId,
|
||||
required this.boxNo,
|
||||
required this.quantity,
|
||||
this.itemType = 'product',
|
||||
});
|
||||
|
||||
factory CurrentZongpaiBoxData.fromJson(Map<String, dynamic> json) {
|
||||
@@ -179,6 +208,7 @@ class CurrentZongpaiBoxData {
|
||||
boxItemId: json['box_item_id'] as int,
|
||||
boxNo: json['box_no'] as int,
|
||||
quantity: json['quantity'] as int,
|
||||
itemType: json['item_type'] as String? ?? 'product',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -195,7 +225,7 @@ class BoxInfoResult {
|
||||
final List<BoxDetailData> existingBoxes;
|
||||
final int maxBoxNo;
|
||||
final int suggestedBoxNo;
|
||||
final int pendingAccessories;
|
||||
final List<PendingAccessory> pendingAccessories;
|
||||
|
||||
BoxInfoResult({
|
||||
required this.success,
|
||||
@@ -208,7 +238,7 @@ class BoxInfoResult {
|
||||
this.existingBoxes = const [],
|
||||
this.maxBoxNo = 0,
|
||||
this.suggestedBoxNo = 1,
|
||||
this.pendingAccessories = 0,
|
||||
this.pendingAccessories = const [],
|
||||
});
|
||||
|
||||
factory BoxInfoResult.ok(Map<String, dynamic> json) {
|
||||
@@ -224,6 +254,11 @@ class BoxInfoResult {
|
||||
)
|
||||
.toList() ??
|
||||
[];
|
||||
final pendingAccessories =
|
||||
(json['pending_accessories'] as List<dynamic>?)
|
||||
?.map((a) => PendingAccessory.fromJson(a as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[];
|
||||
return BoxInfoResult(
|
||||
success: true,
|
||||
zongpaiNo: json['zongpai_no'] as String?,
|
||||
@@ -234,7 +269,7 @@ class BoxInfoResult {
|
||||
existingBoxes: boxes,
|
||||
maxBoxNo: json['max_box_no'] as int? ?? 0,
|
||||
suggestedBoxNo: json['suggested_box_no'] as int? ?? 1,
|
||||
pendingAccessories: json['pending_accessories'] as int? ?? 0,
|
||||
pendingAccessories: pendingAccessories,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -583,18 +618,25 @@ class ApiService {
|
||||
required String zongpaiNo,
|
||||
required int boxNo,
|
||||
required int quantity,
|
||||
String itemType = 'product',
|
||||
int? accessoryId,
|
||||
}) async {
|
||||
final uri = Uri.parse('$baseUrl/CargoTrace/box');
|
||||
try {
|
||||
final bodyMap = <String, dynamic>{
|
||||
'zongpai_no': zongpaiNo,
|
||||
'box_no': boxNo,
|
||||
'quantity': quantity,
|
||||
'item_type': itemType,
|
||||
};
|
||||
if (accessoryId != null) {
|
||||
bodyMap['accessory_id'] = accessoryId;
|
||||
}
|
||||
final response = await _client
|
||||
.post(
|
||||
uri,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonEncode({
|
||||
'zongpai_no': zongpaiNo,
|
||||
'box_no': boxNo,
|
||||
'quantity': quantity,
|
||||
}),
|
||||
body: jsonEncode(bodyMap),
|
||||
)
|
||||
.timeout(timeout);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user