feat(android): add attachment config dialog and FJ- scan in registration
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,83 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pad_scanner/services/api_service.dart';
|
||||||
|
|
||||||
|
/// Show a single-category picker. Returns the selected category, or null.
|
||||||
|
Future<AttachmentCategoryData?> showAttachmentCategoryPicker({
|
||||||
|
required BuildContext context,
|
||||||
|
required List<AttachmentCategoryData> categories,
|
||||||
|
}) {
|
||||||
|
return showDialog<AttachmentCategoryData>(
|
||||||
|
context: context,
|
||||||
|
builder: (ctx) => _CategoryPickerDialog(categories: categories),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CategoryPickerDialog extends StatefulWidget {
|
||||||
|
final List<AttachmentCategoryData> categories;
|
||||||
|
const _CategoryPickerDialog({required this.categories});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_CategoryPickerDialog> createState() => _CategoryPickerDialogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CategoryPickerDialogState extends State<_CategoryPickerDialog> {
|
||||||
|
int? _selectedId;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text('选择附件类型'),
|
||||||
|
content: SizedBox(
|
||||||
|
width: 400,
|
||||||
|
child: RadioGroup<int>(
|
||||||
|
groupValue: _selectedId,
|
||||||
|
onChanged: (v) => setState(() => _selectedId = v),
|
||||||
|
child: widget.categories.length <= 6
|
||||||
|
? Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: widget.categories
|
||||||
|
.map(
|
||||||
|
(cat) => RadioListTile<int>(
|
||||||
|
dense: true,
|
||||||
|
title: Text(cat.name),
|
||||||
|
value: cat.id,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
)
|
||||||
|
: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: widget.categories
|
||||||
|
.map(
|
||||||
|
(cat) => RadioListTile<int>(
|
||||||
|
dense: true,
|
||||||
|
title: Text(cat.name),
|
||||||
|
value: cat.id,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
child: const Text('取消'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: _selectedId != null
|
||||||
|
? () {
|
||||||
|
final cat = widget.categories.firstWhere(
|
||||||
|
(c) => c.id == _selectedId,
|
||||||
|
);
|
||||||
|
Navigator.pop(context, cat);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
child: const Text('确认'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
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('确认'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
185
lib/pages/registration/parts/registration_attachment_part.dart
Normal file
185
lib/pages/registration/parts/registration_attachment_part.dart
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
// ignore_for_file: invalid_use_of_protected_member
|
||||||
|
|
||||||
|
part of '../../registration_page.dart';
|
||||||
|
|
||||||
|
extension _RegistrationAttachmentPart on _RegistrationPageState {
|
||||||
|
/// Handle FJ- attachment scan: pick category, then register location.
|
||||||
|
Future<void> _handleAttachmentScan(String zongpaiNo) async {
|
||||||
|
if (_crossPaichaPending) {
|
||||||
|
_triggerDoubleVibration();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final baseUrl = await _baseUrl();
|
||||||
|
if (baseUrl == null || !mounted) return;
|
||||||
|
|
||||||
|
// 1. Fetch categories (cache in the page state)
|
||||||
|
final catResult = await _apiService.fetchAttachmentCategories(
|
||||||
|
baseUrl: baseUrl,
|
||||||
|
);
|
||||||
|
if (!catResult.success || !mounted) {
|
||||||
|
_feedbackService.trigger(FeedbackEvent.scanInvalid);
|
||||||
|
_showStatusOverride(
|
||||||
|
catResult.errorMessage ?? '加载附件类型失败',
|
||||||
|
StatusDotColor.red,
|
||||||
|
const Duration(seconds: 2),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final categories = catResult.categories;
|
||||||
|
|
||||||
|
// 2. Pick category (single choice)
|
||||||
|
final picked = await showAttachmentCategoryPicker(
|
||||||
|
context: context,
|
||||||
|
categories: categories,
|
||||||
|
);
|
||||||
|
if (picked == null || !mounted) return;
|
||||||
|
|
||||||
|
// 3. Now treat this zongpai as "scanned" with the picked category
|
||||||
|
// For the registration flow: append scanned zongpai (for location binding)
|
||||||
|
// and store category context for the submit path
|
||||||
|
_feedbackService.trigger(FeedbackEvent.scanValid);
|
||||||
|
setState(() {
|
||||||
|
if (_mode == RegistrationMode.multiCode) {
|
||||||
|
if (!_zongpaiNos.contains(zongpaiNo)) {
|
||||||
|
_zongpaiNos.add(zongpaiNo);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_zongpaiNos.isEmpty) {
|
||||||
|
_zongpaiNos.add(zongpaiNo);
|
||||||
|
} else {
|
||||||
|
_zongpaiNos[0] = zongpaiNo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Store the last-scanned attachment category for submit
|
||||||
|
_pendingAttachmentCategory = picked.id;
|
||||||
|
_clearStatusOverride();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 4. Refresh the overview (the zongpai is now a product scan for display,
|
||||||
|
// attachment status will be shown via a separate banner/tag)
|
||||||
|
final shouldRefresh = _overviewZongpaiNo != zongpaiNo;
|
||||||
|
if (shouldRefresh) {
|
||||||
|
_loadOverview(zongpaiNo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle a product scan with attachment-config integration.
|
||||||
|
/// Called from the existing _handleZongpaiScan when a product code is scanned.
|
||||||
|
Future<void> _checkAndConfigureAttachment(String zongpaiNo) async {
|
||||||
|
final baseUrl = await _baseUrl();
|
||||||
|
if (baseUrl == null || !mounted) return;
|
||||||
|
|
||||||
|
// Fetch attachment status for this zongpai
|
||||||
|
final status = await _apiService.fetchAttachmentStatus(
|
||||||
|
baseUrl: baseUrl,
|
||||||
|
zongpaiNo: zongpaiNo,
|
||||||
|
);
|
||||||
|
if (!mounted) return;
|
||||||
|
|
||||||
|
if (!status.success) {
|
||||||
|
// Network error or other — defer to product scan flow without blocking
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status.determination == 'none') {
|
||||||
|
// Already determined none — nothing to configure
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status.determination == 'undetermined' ||
|
||||||
|
status.determination == 'has') {
|
||||||
|
// Fetch categories for the dialog
|
||||||
|
final catResult = await _apiService.fetchAttachmentCategories(
|
||||||
|
baseUrl: baseUrl,
|
||||||
|
);
|
||||||
|
if (!catResult.success || !mounted) return;
|
||||||
|
|
||||||
|
// Fetch ERP quantity for default expected_qty
|
||||||
|
final overview = _overview;
|
||||||
|
final erpQty = overview?.success == true
|
||||||
|
? overview!.items
|
||||||
|
.where((i) => i.zongpaiNo == zongpaiNo)
|
||||||
|
.fold<int>(0, (sum, i) => sum + i.quantity)
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
final result = await showAttachmentConfigDialog(
|
||||||
|
context: context,
|
||||||
|
zongpaiNo: zongpaiNo,
|
||||||
|
categories: catResult.categories,
|
||||||
|
prefillItems: status.items,
|
||||||
|
erpQuantity: erpQty > 0 ? erpQty : 1,
|
||||||
|
);
|
||||||
|
if (result == null || !mounted) return;
|
||||||
|
|
||||||
|
// Submit config
|
||||||
|
final configResult = await _apiService.putAttachmentConfig(
|
||||||
|
baseUrl: baseUrl,
|
||||||
|
zongpaiNo: zongpaiNo,
|
||||||
|
determination: result.determination,
|
||||||
|
items: result.items,
|
||||||
|
);
|
||||||
|
if (!mounted) return;
|
||||||
|
|
||||||
|
if (!configResult.success) {
|
||||||
|
_feedbackService.trigger(FeedbackEvent.submitFailure);
|
||||||
|
_showStatusOverride(
|
||||||
|
configResult.errorMessage ?? '配置失败',
|
||||||
|
StatusDotColor.red,
|
||||||
|
const Duration(seconds: 2),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Submit attachment location for the given zongpai.
|
||||||
|
Future<bool> _submitAttachmentLocation(
|
||||||
|
String baseUrl,
|
||||||
|
String zongpaiNo,
|
||||||
|
int categoryId,
|
||||||
|
) async {
|
||||||
|
final result = await _apiService.registerAttachmentLocation(
|
||||||
|
baseUrl: baseUrl,
|
||||||
|
zongpaiNo: zongpaiNo,
|
||||||
|
categoryId: categoryId,
|
||||||
|
locationCode: _locationCode!,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!mounted) return false;
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
return true;
|
||||||
|
} else if (result.isDuplicate) {
|
||||||
|
_feedbackService.trigger(FeedbackEvent.duplicateError);
|
||||||
|
if (result.conflictInfo != null) {
|
||||||
|
final msg =
|
||||||
|
'附件 $zongpaiNo 已上架至 ${result.conflictInfo!['location_code']}';
|
||||||
|
_showStatusOverride(
|
||||||
|
msg,
|
||||||
|
StatusDotColor.red,
|
||||||
|
const Duration(seconds: 2),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else if (result.isAlreadyOffShelf) {
|
||||||
|
_feedbackService.trigger(FeedbackEvent.submitFailure);
|
||||||
|
_showStatusOverride(
|
||||||
|
result.errorMessage ?? '该附件已下架至转运区域,不可重新上架',
|
||||||
|
StatusDotColor.red,
|
||||||
|
const Duration(seconds: 2),
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
final isNetwork = result.errorMessage == '网络异常,请检查网络连接';
|
||||||
|
_feedbackService.trigger(
|
||||||
|
isNetwork ? FeedbackEvent.networkError : FeedbackEvent.submitFailure,
|
||||||
|
);
|
||||||
|
_showStatusOverride(
|
||||||
|
result.errorMessage ?? '提交失败',
|
||||||
|
isNetwork ? StatusDotColor.yellow : StatusDotColor.red,
|
||||||
|
const Duration(seconds: 2),
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,8 +45,9 @@ extension _RegistrationScanPart on _RegistrationPageState {
|
|||||||
final parsed = CodeParser.parse(result.barcode);
|
final parsed = CodeParser.parse(result.barcode);
|
||||||
switch (parsed.type) {
|
switch (parsed.type) {
|
||||||
case CodeType.zongpaiNo:
|
case CodeType.zongpaiNo:
|
||||||
case CodeType.attachmentCode:
|
|
||||||
_handleZongpaiScan(parsed.value);
|
_handleZongpaiScan(parsed.value);
|
||||||
|
case CodeType.attachmentCode:
|
||||||
|
_handleAttachmentScan(parsed.value);
|
||||||
case CodeType.locationNormal:
|
case CodeType.locationNormal:
|
||||||
case CodeType.locationTransit:
|
case CodeType.locationTransit:
|
||||||
case CodeType.locationTempStorage:
|
case CodeType.locationTempStorage:
|
||||||
@@ -116,6 +117,8 @@ extension _RegistrationScanPart on _RegistrationPageState {
|
|||||||
if (shouldRefresh) {
|
if (shouldRefresh) {
|
||||||
_loadOverview(zongpaiNo);
|
_loadOverview(zongpaiNo);
|
||||||
}
|
}
|
||||||
|
// Trigger attachment config check in background (modal dialog if needed)
|
||||||
|
unawaited(_checkAndConfigureAttachment(zongpaiNo));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _triggerDoubleVibration() {
|
void _triggerDoubleVibration() {
|
||||||
|
|||||||
@@ -110,6 +110,38 @@ extension _RegistrationSubmitPart on _RegistrationPageState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _submitOne(String baseUrl, String zongpaiNo) async {
|
Future<void> _submitOne(String baseUrl, String zongpaiNo) async {
|
||||||
|
// Attachment scan: submit via POST /attachment/location instead
|
||||||
|
final pendingCat = _pendingAttachmentCategory;
|
||||||
|
if (pendingCat != null) {
|
||||||
|
final ok = await _submitAttachmentLocation(
|
||||||
|
baseUrl,
|
||||||
|
zongpaiNo,
|
||||||
|
pendingCat,
|
||||||
|
);
|
||||||
|
if (!mounted) return;
|
||||||
|
setState(() {
|
||||||
|
_isSubmitting = false;
|
||||||
|
_pendingAttachmentCategory = null;
|
||||||
|
});
|
||||||
|
if (ok) {
|
||||||
|
_feedbackService.trigger(FeedbackEvent.submitSuccess);
|
||||||
|
setState(() {
|
||||||
|
_zongpaiNos.remove(zongpaiNo);
|
||||||
|
if (_mode == RegistrationMode.singleCode && !_isTempStorageTarget) {
|
||||||
|
_locationCode = null;
|
||||||
|
_locationType = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_showStatusOverride(
|
||||||
|
'附件上架成功',
|
||||||
|
StatusDotColor.green,
|
||||||
|
const Duration(milliseconds: 1500),
|
||||||
|
);
|
||||||
|
await _refreshCurrentOverview();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final result = await _apiService.registerLocation(
|
final result = await _apiService.registerLocation(
|
||||||
baseUrl: baseUrl,
|
baseUrl: baseUrl,
|
||||||
zongpaiNo: zongpaiNo,
|
zongpaiNo: zongpaiNo,
|
||||||
|
|||||||
@@ -14,11 +14,14 @@ import 'package:pad_scanner/widgets/status_bar.dart';
|
|||||||
import 'package:pad_scanner/pages/boxing/widgets/boxing_shared_widgets.dart';
|
import 'package:pad_scanner/pages/boxing/widgets/boxing_shared_widgets.dart';
|
||||||
import 'package:pad_scanner/pages/registration/registration_calculations.dart'
|
import 'package:pad_scanner/pages/registration/registration_calculations.dart'
|
||||||
as registration_calculations;
|
as registration_calculations;
|
||||||
|
import 'package:pad_scanner/pages/registration/dialogs/attachment_config_dialog.dart';
|
||||||
|
import 'package:pad_scanner/pages/registration/dialogs/attachment_category_picker.dart';
|
||||||
|
|
||||||
part 'registration/parts/registration_scan_part.dart';
|
part 'registration/parts/registration_scan_part.dart';
|
||||||
part 'registration/parts/registration_status_part.dart';
|
part 'registration/parts/registration_status_part.dart';
|
||||||
part 'registration/parts/registration_overview_part.dart';
|
part 'registration/parts/registration_overview_part.dart';
|
||||||
part 'registration/parts/registration_submit_part.dart';
|
part 'registration/parts/registration_submit_part.dart';
|
||||||
|
part 'registration/parts/registration_attachment_part.dart';
|
||||||
part 'registration/parts/registration_mode_part.dart';
|
part 'registration/parts/registration_mode_part.dart';
|
||||||
part 'registration/dialogs/registration_dialogs_part.dart';
|
part 'registration/dialogs/registration_dialogs_part.dart';
|
||||||
part 'registration/widgets/registration_widgets_part.dart';
|
part 'registration/widgets/registration_widgets_part.dart';
|
||||||
@@ -63,6 +66,11 @@ class _RegistrationPageState extends State<RegistrationPage> {
|
|||||||
/// Whether a cross-paicha warning dialog is currently showing.
|
/// Whether a cross-paicha warning dialog is currently showing.
|
||||||
bool _crossPaichaPending = false;
|
bool _crossPaichaPending = false;
|
||||||
|
|
||||||
|
/// Pending attachment category ID set by the FJ- scan branch.
|
||||||
|
/// Consumed by the submit path to call POST /attachment/location
|
||||||
|
/// instead of POST /location.
|
||||||
|
int? _pendingAttachmentCategory;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|||||||
Reference in New Issue
Block a user