Files
pad_scanner/lib/pages/registration/dialogs/registration_dialogs_part.dart

334 lines
10 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ignore_for_file: invalid_use_of_protected_member
part of '../../registration_page.dart';
extension _RegistrationDialogsPart on _RegistrationPageState {
void _showLocationSwitchDialog(
String newLocationCode,
CodeType newLocationType,
) {
final count = _zongpaiNos.length;
showDialog(
context: context,
barrierDismissible: false,
builder: (ctx) => AlertDialog(
backgroundColor: Colors.orange.shade50,
title: Row(
children: [
Icon(Icons.warning_amber, color: Colors.orange.shade800),
const SizedBox(width: 8),
Text('切换货架号', style: TextStyle(color: Colors.orange.shade900)),
],
),
content: Text(
'当前已有 $count 条待上架数据,切换货架号不会清除已扫描的总排号。',
style: const TextStyle(fontSize: 14),
),
actions: [
TextButton(
onPressed: () {
Navigator.pop(ctx);
},
child: const Text('取消'),
),
ElevatedButton(
onPressed: () {
Navigator.pop(ctx);
_feedbackService.trigger(FeedbackEvent.scanValid);
setState(() {
_locationCode = newLocationCode;
_locationType = newLocationType;
_clearStatusOverride();
});
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange.shade700,
foregroundColor: Colors.white,
),
child: const Text('确认切换'),
),
],
),
);
}
void _showDuplicateDialog(String zongpaiNo, Map<String, dynamic>? info) {
showDialog(
context: context,
barrierDismissible: false,
builder: (ctx) => AlertDialog(
backgroundColor: Colors.red.shade50,
title: const Row(
children: [
Icon(Icons.warning, color: Colors.red),
SizedBox(width: 8),
Text('重复上架', style: TextStyle(color: Colors.red)),
],
),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('总排号:$zongpaiNo'),
const SizedBox(height: 4),
Text('已登记货位:${info?["location_code"] ?? "未知"}'),
const SizedBox(height: 4),
Text('登记时间:${info?["registered_at"] ?? "未知"}'),
const SizedBox(height: 12),
const Text(
'请核查实物,确认是否操作错误。',
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
actions: [
TextButton(
onPressed: () {
_feedbackService.stopAlert();
Navigator.pop(ctx);
},
child: const Text('关闭'),
),
],
),
);
}
void _showLocationConflictDialog({
required List<PaichaOverviewItem> onShelfItems,
required List<PaichaOverviewItem> transferredItems,
}) {
final contentParts = <Widget>[];
if (onShelfItems.isNotEmpty) {
contentParts.add(
Text(
'重复上架',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.red.shade700,
),
),
);
for (final item in onShelfItems) {
contentParts.addAll([
Text('总排号:${item.zongpaiNo}'),
Text('已登记货位:${item.locationCode ?? "未知"}'),
const SizedBox(height: 6),
]);
}
}
if (transferredItems.isNotEmpty) {
if (onShelfItems.isNotEmpty) {
contentParts.add(const Divider());
contentParts.add(const SizedBox(height: 4));
}
contentParts.add(
Text(
'货物已转运',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.orange.shade700,
),
),
);
for (final item in transferredItems) {
contentParts.addAll([
Text('总排号:${item.zongpaiNo}'),
Text('转运货位:${item.locationCode ?? "未知"}'),
const SizedBox(height: 6),
]);
}
}
contentParts.add(const SizedBox(height: 4));
contentParts.add(
const Text(
'请核查实物,确认是否操作错误。',
style: TextStyle(fontWeight: FontWeight.bold),
),
);
showDialog(
context: context,
barrierDismissible: false,
builder: (ctx) => AlertDialog(
backgroundColor: Colors.red.shade50,
title: const Row(
children: [
Icon(Icons.warning, color: Colors.red),
SizedBox(width: 8),
Text('操作冲突', style: TextStyle(color: Colors.red)),
],
),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: contentParts,
),
actions: [
TextButton(
onPressed: () {
_feedbackService.stopAlert();
Navigator.pop(ctx);
},
child: const Text('关闭'),
),
],
),
);
}
Future<void> _showCrossPaichaDialog(String newZongpaiNo) async {
final currentPaicha = _overview?.paichaNo ?? '--';
final shouldSwitch = await _confirmCrossPaichaSwitch(
newZongpaiNo: newZongpaiNo,
currentPaicha: currentPaicha,
);
if (!mounted) return;
if (shouldSwitch) {
_switchToNewPaicha(newZongpaiNo);
return;
}
setState(() {
_crossPaichaPending = false;
});
}
Future<bool> _confirmCrossPaichaSwitch({
required String newZongpaiNo,
required String currentPaicha,
}) async {
final dialogFocus = FocusNode();
var dismissed = false;
var selectedIndex = 0; // 0 = "否" (default), 1 = "是"
void dismissAsNo() {
if (dismissed) return;
dismissed = true;
Navigator.of(context).pop(false);
}
void confirmSwitch() {
if (dismissed) return;
dismissed = true;
Navigator.of(context).pop(true);
}
final dialogFuture = showDialog<bool>(
context: context,
barrierDismissible: false,
builder: (ctx) => StatefulBuilder(
builder: (ctx, setDialogState) {
return KeyboardListener(
focusNode: dialogFocus,
onKeyEvent: (event) {
if (event is! KeyDownEvent) return;
if (event.logicalKey == LogicalKeyboardKey.arrowUp) {
setDialogState(() => selectedIndex = 0);
} else if (event.logicalKey == LogicalKeyboardKey.arrowDown) {
setDialogState(() => selectedIndex = 1);
} else if (event.logicalKey == LogicalKeyboardKey.enter) {
selectedIndex == 0 ? dismissAsNo() : confirmSwitch();
} else if (event.logicalKey == LogicalKeyboardKey.escape) {
dismissAsNo();
}
},
child: PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, _) {
if (!didPop) dismissAsNo();
},
child: AlertDialog(
backgroundColor: Colors.orange.shade50,
title: Row(
children: [
Icon(Icons.warning_amber, color: Colors.orange.shade800),
const SizedBox(width: 8),
Text(
'跨排产号扫描',
style: TextStyle(color: Colors.orange.shade900),
),
],
),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'总排号 $newZongpaiNo 不属于当前排产号($currentPaicha'
'是否切换到新的排产号?\n\n'
'选择「是」将放弃当前已扫描的所有数据。',
style: const TextStyle(fontSize: 14),
),
const SizedBox(height: 16),
_dialogOptionBtn(
label: '',
selected: selectedIndex == 0,
onTap: dismissAsNo,
),
const SizedBox(height: 8),
_dialogOptionBtn(
label: '是,切换排产号',
selected: selectedIndex == 1,
onTap: confirmSwitch,
),
],
),
),
),
);
},
),
);
WidgetsBinding.instance.addPostFrameCallback((_) {
dialogFocus.requestFocus();
});
final shouldSwitch = await dialogFuture;
return shouldSwitch ?? false;
}
Widget _dialogOptionBtn({
required String label,
required bool selected,
required VoidCallback onTap,
}) {
return SizedBox(
width: double.infinity,
height: 40,
child: ElevatedButton(
onPressed: onTap,
style: ElevatedButton.styleFrom(
backgroundColor: selected
? Colors.blue.shade700
: Colors.grey.shade200,
foregroundColor: selected ? Colors.white : Colors.black87,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
child: Text(
label,
style: TextStyle(
fontWeight: selected ? FontWeight.w800 : FontWeight.w600,
),
),
),
);
}
void _switchToNewPaicha(String newZongpaiNo) {
_feedbackService.trigger(FeedbackEvent.paichanSwitch);
setState(() {
_crossPaichaPending = false;
_zongpaiNos.clear();
_zongpaiNos.add(newZongpaiNo);
_overview = null;
_overviewNotFound = false;
_overviewError = null;
_clearStatusOverride();
});
_loadOverview(newZongpaiNo);
}
}