192 lines
6.1 KiB
Dart
192 lines
6.1 KiB
Dart
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('确认'),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|