refactor: extract boxing page into modular components

Split the monolithic boxing_page.dart into separate files:
- boxing_models.dart: data models (_ManyToOnePackedItem, _Phase)
- widgets/boxing_shared_widgets.dart: shared UI components
- widgets/single_code_body.dart: single-code boxing UI
- widgets/multi_code_body.dart: multi-code boxing UI
- widgets/multi_packed_row.dart: multi-code packed row widget
- widgets/single_assigned_row.dart: single-code assigned row widget

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Misaka_Company
2026-05-21 08:35:45 +08:00
parent 0ae4017eee
commit f2b2f41929
7 changed files with 1982 additions and 1293 deletions

View File

@@ -0,0 +1,231 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:pad_scanner/pages/boxing/widgets/boxing_shared_widgets.dart';
import 'package:pad_scanner/services/api_service.dart';
class SingleAssignedRow extends StatelessWidget {
final CurrentZongpaiBoxData item;
final String? workOrderNo;
final bool editing;
final bool deleting;
final bool isSubmitting;
final String editingQuantity;
final ValueChanged<String> onEditingQuantityChanged;
final VoidCallback onSave;
final VoidCallback onCancelEdit;
final VoidCallback onStartEdit;
final VoidCallback onStartDelete;
final VoidCallback onDelete;
final VoidCallback onCancelDelete;
const SingleAssignedRow({
super.key,
required this.item,
required this.workOrderNo,
required this.editing,
required this.deleting,
required this.isSubmitting,
required this.editingQuantity,
required this.onEditingQuantityChanged,
required this.onSave,
required this.onCancelEdit,
required this.onStartEdit,
required this.onStartDelete,
required this.onDelete,
required this.onCancelDelete,
});
@override
Widget build(BuildContext context) {
final barColor = editing
? Colors.amber
: (deleting ? Colors.red : Colors.green);
final Color bgColor;
if (editing) {
bgColor = Colors.yellow.shade50;
} else if (deleting) {
bgColor = Colors.red.shade50;
} else {
bgColor = Colors.transparent;
}
final rowStyle = TextStyle(
fontSize: 15,
fontWeight: FontWeight.w500,
color: Colors.black87,
);
return Column(
children: [
Container(
constraints: const BoxConstraints(minHeight: 36),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: bgColor,
border: Border(
left: BorderSide(color: barColor, width: 3),
bottom: BorderSide(color: Colors.grey.shade200),
),
),
child: Row(
children: [
Expanded(
flex: 22,
child: Text(
'${item.boxNo} 号箱',
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
style: rowStyle.copyWith(fontWeight: FontWeight.w700),
),
),
Expanded(
flex: 30,
child: Text(
workOrderNo ?? '--',
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
style: rowStyle,
),
),
Expanded(
flex: 23,
child: editing
? SizedBox(
width: 52,
height: 28,
child: TextField(
keyboardType: TextInputType.none,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
],
textAlign: TextAlign.center,
controller:
TextEditingController(text: editingQuantity)
..selection = TextSelection.collapsed(
offset: editingQuantity.length,
),
onChanged: onEditingQuantityChanged,
onSubmitted: (_) => onSave(),
decoration: InputDecoration(
contentPadding: const EdgeInsets.symmetric(
horizontal: 4,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: const BorderSide(
color: Colors.amber,
width: 1.5,
),
),
),
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w700,
),
),
)
: Text(
'${item.quantity}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
color: deleting ? Colors.red : Colors.black54,
),
),
),
SizedBox(
width: 54,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (editing) ...[
CompactIconButton(
icon: Icons.check,
color: Colors.green,
onTap: isSubmitting ? null : onSave,
),
CompactIconButton(
icon: Icons.close,
color: Colors.grey,
onTap: isSubmitting ? null : onCancelEdit,
),
] else ...[
CompactIconButton(
icon: Icons.edit,
color: Colors.grey.shade700,
onTap: isSubmitting ? null : onStartEdit,
),
CompactIconButton(
icon: Icons.delete_outline,
color: Colors.red,
onTap: isSubmitting ? null : onStartDelete,
),
],
],
),
),
],
),
),
if (deleting)
Container(
height: 28,
padding: const EdgeInsets.only(left: 15, right: 12),
decoration: BoxDecoration(
color: Colors.red.shade50,
border: Border(bottom: BorderSide(color: Colors.red.shade200)),
),
child: Row(
children: [
Expanded(
child: Text(
'确认删除 ${item.boxNo} 号箱记录?',
style: const TextStyle(fontSize: 12, color: Colors.red),
overflow: TextOverflow.ellipsis,
),
),
TextButton(
onPressed: isSubmitting ? null : onDelete,
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 2,
),
minimumSize: Size.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
backgroundColor: Colors.red,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
),
),
child: const Text(
'删除',
style: TextStyle(fontSize: 12, fontWeight: FontWeight.w700),
),
),
const SizedBox(width: 6),
TextButton(
onPressed: isSubmitting ? null : onCancelDelete,
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 2,
),
minimumSize: Size.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
child: const Text(
'取消',
style: TextStyle(fontSize: 12, fontWeight: FontWeight.w700),
),
),
],
),
),
],
);
}
}