feat(android): add attachment pending banner on boxing page

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Misaka_Company
2026-08-12 15:06:15 +08:00
parent 15c29bceb8
commit cf974cee92
4 changed files with 39 additions and 0 deletions

View File

@@ -71,6 +71,13 @@ extension _BoxingScanPart on _BoxingPageState {
: FeedbackEvent.scanValid,
);
final attSummary = result.attachmentSummary;
final pending =
attSummary != null &&
attSummary['determination'] == 'has' &&
attSummary['all_complete'] != true;
final pendingCount = attSummary?['pending_count'] as int? ?? 0;
setState(() {
_zongpaiNo = zongpai;
_paichanNo = result.paichanNo;
@@ -87,6 +94,8 @@ extension _BoxingScanPart on _BoxingPageState {
_deletingAssignedItemId = null;
_completedJumpBoxNo = null;
_statusOverrideText = null;
_attachmentPending = pending;
_attachmentPendingCount = pendingCount;
if (_mode == BoxingMode.singleCode) {
_paichanSwitchNotice = null;
}

View File

@@ -12,6 +12,8 @@ class BoxingNoticeBanners extends StatelessWidget {
final int remainingQuantity;
final String? zongpaiNo;
final int? completedJumpBoxNo;
final bool attachmentPending;
final int attachmentPendingCount;
final VoidCallback onJumpToCompletedBox;
const BoxingNoticeBanners({
@@ -26,6 +28,8 @@ class BoxingNoticeBanners extends StatelessWidget {
required this.remainingQuantity,
required this.zongpaiNo,
required this.completedJumpBoxNo,
this.attachmentPending = false,
this.attachmentPendingCount = 0,
required this.onJumpToCompletedBox,
});
@@ -76,6 +80,21 @@ class BoxingNoticeBanners extends StatelessWidget {
),
);
}
if (attachmentPending) {
banners.add(
_NoticeBanner(
icon: Icon(
Icons.warning_amber,
size: 14,
color: Colors.amber.shade900,
),
text: '本单有附件,尚未到齐(剩 $attachmentPendingCount 种)',
background: Colors.amber.shade50,
foreground: Colors.amber.shade900,
border: Colors.amber.shade200,
),
);
}
if (isDuplicateBoxNo && phase == BoxingPhase.scanned) {
banners.add(
_NoticeBanner(

View File

@@ -118,6 +118,10 @@ class _BoxingPageState extends State<BoxingPage> with WidgetsBindingObserver {
// ignore: unused_field -- already boxed qty for this category (later task)
int? _attachmentBoxedQty;
/// Whether to show the attachment-pending banner.
bool _attachmentPending = false;
int _attachmentPendingCount = 0;
@override
void initState() {
super.initState();
@@ -265,6 +269,8 @@ class _BoxingPageState extends State<BoxingPage> with WidgetsBindingObserver {
_attachmentCategoryName = null;
_attachmentExpectedQty = null;
_attachmentBoxedQty = null;
_attachmentPending = false;
_attachmentPendingCount = 0;
}
// === 重复箱号检测 ===
@@ -388,6 +394,8 @@ class _BoxingPageState extends State<BoxingPage> with WidgetsBindingObserver {
remainingQuantity: _remainingQuantity,
zongpaiNo: _zongpaiNo,
completedJumpBoxNo: _completedJumpBoxNo,
attachmentPending: _attachmentPending,
attachmentPendingCount: _attachmentPendingCount,
onJumpToCompletedBox: () => this._jumpToCompletedBox(),
),

View File

@@ -195,6 +195,7 @@ class BoxInfoResult {
final List<BoxDetailData> existingBoxes;
final int maxBoxNo;
final int suggestedBoxNo;
final Map<String, dynamic>? attachmentSummary;
BoxInfoResult({
required this.success,
@@ -207,6 +208,7 @@ class BoxInfoResult {
this.existingBoxes = const [],
this.maxBoxNo = 0,
this.suggestedBoxNo = 1,
this.attachmentSummary,
});
factory BoxInfoResult.ok(Map<String, dynamic> json) {
@@ -232,6 +234,7 @@ class BoxInfoResult {
existingBoxes: boxes,
maxBoxNo: json['max_box_no'] as int? ?? 0,
suggestedBoxNo: json['suggested_box_no'] as int? ?? 1,
attachmentSummary: json['attachment_summary'] as Map<String, dynamic>?,
);
}