feat(android): add attachment config dialog and FJ- scan in registration
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
191
lib/pages/registration/dialogs/attachment_config_dialog.dart
Normal file
191
lib/pages/registration/dialogs/attachment_config_dialog.dart
Normal file
@@ -0,0 +1,191 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:pad_scanner/services/api_service.dart';
|
||||
|
||||
class AttachmentConfigDialogResult {
|
||||
final String determination; // 'has' or 'none'
|
||||
final List<AttachmentConfigItemData> items; // empty if 'none'
|
||||
|
||||
const AttachmentConfigDialogResult({
|
||||
required this.determination,
|
||||
required this.items,
|
||||
});
|
||||
}
|
||||
|
||||
/// Show the attachment configuration dialog for an order.
|
||||
///
|
||||
/// [categories] — the full active category list from GET /attachment/categories.
|
||||
/// [prefillItems] — existing attachment status items (for pre-fill when
|
||||
/// determination is already 'has' due to earlier attachment arrival).
|
||||
/// [erpQuantity] — default expected_qty per selected type.
|
||||
Future<AttachmentConfigDialogResult?> showAttachmentConfigDialog({
|
||||
required BuildContext context,
|
||||
required String zongpaiNo,
|
||||
required List<AttachmentCategoryData> categories,
|
||||
required List<AttachmentStatusItemData> prefillItems,
|
||||
required int erpQuantity,
|
||||
}) {
|
||||
return showDialog<AttachmentConfigDialogResult>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (ctx) => _AttachmentConfigDialog(
|
||||
zongpaiNo: zongpaiNo,
|
||||
categories: categories,
|
||||
prefillItems: prefillItems,
|
||||
erpQuantity: erpQuantity,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class _AttachmentConfigDialog extends StatefulWidget {
|
||||
final String zongpaiNo;
|
||||
final List<AttachmentCategoryData> categories;
|
||||
final List<AttachmentStatusItemData> prefillItems;
|
||||
final int erpQuantity;
|
||||
|
||||
const _AttachmentConfigDialog({
|
||||
required this.zongpaiNo,
|
||||
required this.categories,
|
||||
required this.prefillItems,
|
||||
required this.erpQuantity,
|
||||
});
|
||||
|
||||
@override
|
||||
State<_AttachmentConfigDialog> createState() =>
|
||||
_AttachmentConfigDialogState();
|
||||
}
|
||||
|
||||
class _AttachmentConfigDialogState extends State<_AttachmentConfigDialog> {
|
||||
late Map<int, bool> _selected; // category_id → checked
|
||||
late Map<int, TextEditingController> _controllers; // category_id → qty
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_selected = {};
|
||||
_controllers = {};
|
||||
final prefillSet = <int>{};
|
||||
for (final item in widget.prefillItems) {
|
||||
_selected[item.categoryId] = true;
|
||||
prefillSet.add(item.categoryId);
|
||||
}
|
||||
for (final cat in widget.categories) {
|
||||
if (!_selected.containsKey(cat.id)) {
|
||||
_selected[cat.id] = prefillSet.contains(cat.id);
|
||||
}
|
||||
final ctrl = TextEditingController(
|
||||
text: prefillSet.contains(cat.id)
|
||||
? widget.prefillItems
|
||||
.firstWhere((i) => i.categoryId == cat.id)
|
||||
.expectedQty
|
||||
.toString()
|
||||
: widget.erpQuantity.toString(),
|
||||
);
|
||||
_controllers[cat.id] = ctrl;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
for (final ctrl in _controllers.values) {
|
||||
ctrl.dispose();
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final hasAnyChecked = _selected.values.any((v) => v);
|
||||
|
||||
return AlertDialog(
|
||||
title: Text('${widget.zongpaiNo} — 附件配置'),
|
||||
content: SizedBox(
|
||||
width: 500,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text(
|
||||
'请勾选本订单携带的附件类型,并确认每种数量:',
|
||||
style: TextStyle(fontSize: 13),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
...widget.categories.map(
|
||||
(cat) => CheckboxListTile(
|
||||
dense: true,
|
||||
title: Text(cat.name, style: const TextStyle(fontSize: 14)),
|
||||
subtitle: Row(
|
||||
children: [
|
||||
const Text('应到: ', style: TextStyle(fontSize: 12)),
|
||||
SizedBox(
|
||||
width: 80,
|
||||
child: TextField(
|
||||
controller: _controllers[cat.id],
|
||||
keyboardType: TextInputType.number,
|
||||
enabled: _selected[cat.id] == true,
|
||||
style: const TextStyle(fontSize: 14),
|
||||
decoration: const InputDecoration(
|
||||
isDense: true,
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
vertical: 4,
|
||||
horizontal: 8,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
value: _selected[cat.id] ?? false,
|
||||
onChanged: (v) =>
|
||||
setState(() => _selected[cat.id] = v ?? false),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text('取消'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(
|
||||
context,
|
||||
AttachmentConfigDialogResult(determination: 'none', items: []),
|
||||
);
|
||||
},
|
||||
child: const Text('无附件'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: hasAnyChecked
|
||||
? () {
|
||||
final items = <AttachmentConfigItemData>[];
|
||||
for (final cat in widget.categories) {
|
||||
if (_selected[cat.id] == true) {
|
||||
final qty =
|
||||
int.tryParse(_controllers[cat.id]!.text.trim()) ??
|
||||
widget.erpQuantity;
|
||||
items.add(
|
||||
AttachmentConfigItemData(
|
||||
categoryId: cat.id,
|
||||
expectedQty: qty,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Navigator.pop(
|
||||
context,
|
||||
AttachmentConfigDialogResult(
|
||||
determination: 'has',
|
||||
items: items,
|
||||
),
|
||||
);
|
||||
}
|
||||
: null,
|
||||
child: const Text('确认'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user