improve single-code boxing UX: preserve state, fix work order display, add double-vibrate alert
- Keep UI state after boxing completion for operator review instead of auto-reset - Show real work order number instead of hardcoded "本次扫码" in assigned list - Add double-vibration feedback when re-scanning already completed zongpai - Change completed status banner and dot from green to red for clearer warning Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -344,7 +344,19 @@ class _BoxingPageState extends State<BoxingPage> with WidgetsBindingObserver {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_feedbackService.trigger(FeedbackEvent.scanValid);
|
// 判断该总牌号是否已全部装箱完毕
|
||||||
|
final packedQuantity = result.currentZongpaiBoxes.fold<int>(
|
||||||
|
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(() {
|
setState(() {
|
||||||
_zongpaiNo = zongpai;
|
_zongpaiNo = zongpai;
|
||||||
@@ -686,9 +698,6 @@ class _BoxingPageState extends State<BoxingPage> with WidgetsBindingObserver {
|
|||||||
StatusDotColor.green,
|
StatusDotColor.green,
|
||||||
const Duration(milliseconds: 1500),
|
const Duration(milliseconds: 1500),
|
||||||
);
|
);
|
||||||
Future.delayed(const Duration(milliseconds: 1500), () {
|
|
||||||
if (mounted) setState(() => _resetState());
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
setState(() {
|
setState(() {
|
||||||
_phase = _Phase.scanned;
|
_phase = _Phase.scanned;
|
||||||
@@ -1285,7 +1294,7 @@ class _BoxingPageState extends State<BoxingPage> with WidgetsBindingObserver {
|
|||||||
case _Phase.scanned:
|
case _Phase.scanned:
|
||||||
_statusDot = StatusDotColor.blue;
|
_statusDot = StatusDotColor.blue;
|
||||||
if (_remainingQuantity <= 0) {
|
if (_remainingQuantity <= 0) {
|
||||||
_statusDot = StatusDotColor.green;
|
_statusDot = StatusDotColor.red;
|
||||||
_statusText = '该总排号已全部装箱完毕';
|
_statusText = '该总排号已全部装箱完毕';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1423,11 +1432,11 @@ class _BoxingPageState extends State<BoxingPage> with WidgetsBindingObserver {
|
|||||||
_remainingQuantity <= 0) {
|
_remainingQuantity <= 0) {
|
||||||
banners.add(
|
banners.add(
|
||||||
_noticeBanner(
|
_noticeBanner(
|
||||||
icon: Icon(Icons.check, size: 14, color: Colors.green.shade800),
|
icon: Icon(Icons.warning, size: 14, color: Colors.red.shade800),
|
||||||
text: '${_zongpaiNo!} 已全部装箱完毕,无需操作',
|
text: '${_zongpaiNo!} 已全部装箱完毕,无需操作',
|
||||||
background: Colors.green.shade50,
|
background: Colors.red.shade50,
|
||||||
foreground: Colors.green.shade800,
|
foreground: Colors.red.shade800,
|
||||||
border: Colors.green.shade100,
|
border: Colors.red.shade100,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1762,7 +1771,7 @@ class _BoxingPageState extends State<BoxingPage> with WidgetsBindingObserver {
|
|||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'本次扫码',
|
_workOrderNo ?? '--',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
color: Colors.grey.shade500,
|
color: Colors.grey.shade500,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ enum FeedbackEvent {
|
|||||||
duplicateError, // Duplicate (shelf) → alert loop + continuous vibrate
|
duplicateError, // Duplicate (shelf) → alert loop + continuous vibrate
|
||||||
networkError, // Network error → failure sound + short vibrate
|
networkError, // Network error → failure sound + short vibrate
|
||||||
duplicateBoxNo, // Duplicate box no → failure sound + short vibrate
|
duplicateBoxNo, // Duplicate box no → failure sound + short vibrate
|
||||||
|
alreadyCompleted, // Zongpai already boxed → beep + double vibrate
|
||||||
modeSwitch, // Mode toggle → beep only
|
modeSwitch, // Mode toggle → beep only
|
||||||
paichanSwitch, // Paichan changed → beep + short vibrate
|
paichanSwitch, // Paichan changed → beep + short vibrate
|
||||||
}
|
}
|
||||||
@@ -55,6 +56,10 @@ class FeedbackService {
|
|||||||
_soundService.playFailure();
|
_soundService.playFailure();
|
||||||
_vibrateShort();
|
_vibrateShort();
|
||||||
|
|
||||||
|
case FeedbackEvent.alreadyCompleted:
|
||||||
|
_soundService.playBeep();
|
||||||
|
_vibrateDouble();
|
||||||
|
|
||||||
case FeedbackEvent.modeSwitch:
|
case FeedbackEvent.modeSwitch:
|
||||||
_soundService.playBeep();
|
_soundService.playBeep();
|
||||||
|
|
||||||
@@ -82,6 +87,11 @@ class FeedbackService {
|
|||||||
Vibration.vibrate(pattern: [0, 300, 100, 300, 100, 300]);
|
Vibration.vibrate(pattern: [0, 300, 100, 300, 100, 300]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Two short bursts to signal an already-completed item.
|
||||||
|
void _vibrateDouble() {
|
||||||
|
Vibration.vibrate(pattern: [0, 200, 100, 200]);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> dispose() async {
|
Future<void> dispose() async {
|
||||||
await _soundService.dispose();
|
await _soundService.dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user