454 lines
13 KiB
Dart
454 lines
13 KiB
Dart
// ignore_for_file: invalid_use_of_protected_member
|
|
|
|
part of '../../registration_page.dart';
|
|
|
|
extension _RegistrationWidgetsPart on _RegistrationPageState {
|
|
String _locationLabel(CodeType? type) {
|
|
if (type == CodeType.locationTransit) return '转运区域';
|
|
return '普通货架';
|
|
}
|
|
|
|
Color _locationLabelColor(CodeType? type) {
|
|
if (type == CodeType.locationTransit) return Colors.orange;
|
|
return Colors.blue;
|
|
}
|
|
|
|
Widget _buildModePill() {
|
|
return BoxingModePill(
|
|
isSingle: _mode == RegistrationMode.singleCode,
|
|
label: _mode == RegistrationMode.singleCode ? '单码上架' : '多码上架',
|
|
enabled: !_isSubmitting,
|
|
onTap: _cycleMode,
|
|
);
|
|
}
|
|
|
|
Widget _buildLocationChip() {
|
|
final color = _locationLabelColor(_locationType);
|
|
return Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
|
decoration: BoxDecoration(
|
|
color: color.withValues(alpha: 0.15),
|
|
borderRadius: BorderRadius.circular(4),
|
|
),
|
|
child: Text(
|
|
_locationLabel(_locationType),
|
|
style: TextStyle(
|
|
fontSize: 11,
|
|
color: color,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
// === Paicha Header ===
|
|
|
|
Widget _buildPaichaHeader() {
|
|
final overview = _overview;
|
|
final hasData = overview?.success == true;
|
|
final hasLoc = _locationCode != null;
|
|
final stats = registration_calculations.overviewStats(overview);
|
|
|
|
return Container(
|
|
padding: const EdgeInsets.fromLTRB(12, 8, 12, 6),
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey.shade50,
|
|
border: Border(bottom: BorderSide(color: Colors.grey.shade300)),
|
|
),
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
Text(
|
|
hasData ? (overview!.paichaNo ?? '--') : '--',
|
|
style: TextStyle(
|
|
fontSize: 24,
|
|
fontWeight: FontWeight.w800,
|
|
color: hasData ? Colors.black87 : Colors.grey.shade400,
|
|
),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.end,
|
|
children: [
|
|
if (hasLoc)
|
|
Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Text(
|
|
_locationCode!,
|
|
style: const TextStyle(
|
|
fontSize: 13,
|
|
fontWeight: FontWeight.w600,
|
|
color: Colors.black54,
|
|
),
|
|
),
|
|
const SizedBox(width: 5),
|
|
_buildLocationChip(),
|
|
],
|
|
),
|
|
Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
_buildStatTag(
|
|
'共 ${stats.totalCount}',
|
|
const Color(0xFFE3F2FD),
|
|
const Color(0xFF1565C0),
|
|
hasData,
|
|
),
|
|
_buildStatTag(
|
|
'上架 ${stats.shelvedCount}',
|
|
const Color(0xFFE8F5E9),
|
|
const Color(0xFF2E7D32),
|
|
hasData,
|
|
),
|
|
_buildStatTag(
|
|
'转运 ${stats.transferredCount}',
|
|
const Color(0xFFFFF3E0),
|
|
const Color(0xFFE65100),
|
|
hasData,
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildStatTag(String text, Color bg, Color fg, bool hasData) {
|
|
return Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 1),
|
|
margin: const EdgeInsets.only(left: 5),
|
|
decoration: BoxDecoration(
|
|
color: hasData ? bg : const Color(0xFFF5F5F5),
|
|
borderRadius: BorderRadius.circular(10),
|
|
),
|
|
child: Text(
|
|
text,
|
|
style: TextStyle(
|
|
fontSize: 10,
|
|
fontWeight: FontWeight.w700,
|
|
color: hasData ? fg : Colors.grey.shade400,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
// === Table Head ===
|
|
|
|
Widget _buildTableHead() {
|
|
return Container(
|
|
height: 28,
|
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey.shade200,
|
|
border: Border(bottom: BorderSide(color: Colors.grey.shade400)),
|
|
),
|
|
child: const Row(
|
|
children: [
|
|
Expanded(
|
|
flex: 22,
|
|
child: Text(
|
|
'总排号',
|
|
textAlign: TextAlign.center,
|
|
style: _headerStyle,
|
|
),
|
|
),
|
|
Expanded(
|
|
flex: 18,
|
|
child: Text(
|
|
'工令号',
|
|
textAlign: TextAlign.center,
|
|
style: _headerStyle,
|
|
),
|
|
),
|
|
Expanded(
|
|
flex: 12,
|
|
child: Text('数量', textAlign: TextAlign.center, style: _headerStyle),
|
|
),
|
|
Expanded(
|
|
flex: 28,
|
|
child: Text(
|
|
'货位号',
|
|
textAlign: TextAlign.center,
|
|
style: _headerStyle,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
// === List Body ===
|
|
|
|
Widget _buildListBody() {
|
|
if (_overviewZongpaiNo == null) {
|
|
return _buildListMessage('扫描总排号后自动显示排产号上架情况');
|
|
}
|
|
if (_overviewLoading && _overview == null) {
|
|
return _buildListMessage('正在加载排产号上架情况…');
|
|
}
|
|
if (_overviewNotFound) {
|
|
return _buildListMessage('暂无排产信息');
|
|
}
|
|
if (_overviewError != null && _overview == null) {
|
|
return _buildListError(_overviewError!);
|
|
}
|
|
final overview = _overview;
|
|
if (overview == null || !overview.success) {
|
|
return _buildListMessage('扫描总排号后自动显示排产号上架情况');
|
|
}
|
|
|
|
final sections = registration_calculations.splitOverviewItems(
|
|
overview: overview,
|
|
zongpaiNos: _zongpaiNos,
|
|
);
|
|
final scanned = sections.scanned;
|
|
final unscanned = sections.unscanned;
|
|
|
|
return Column(
|
|
children: [
|
|
if (_overviewError != null)
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
|
|
color: Colors.red.shade50,
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: Text(
|
|
_overviewError!,
|
|
style: const TextStyle(fontSize: 12, color: Colors.red),
|
|
),
|
|
),
|
|
TextButton(
|
|
onPressed: _overviewZongpaiNo == null
|
|
? null
|
|
: () => _loadOverview(_overviewZongpaiNo!, force: true),
|
|
child: const Text('重试'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Expanded(
|
|
child: ListView.builder(
|
|
itemCount:
|
|
scanned.length +
|
|
(sections.hasDivider ? 1 : 0) +
|
|
unscanned.length,
|
|
itemBuilder: (context, index) {
|
|
if (index < scanned.length) {
|
|
return _buildListRow(scanned[index], isScanned: true);
|
|
}
|
|
if (index == scanned.length && sections.hasDivider) {
|
|
return _buildSectionDivider(unscanned.length);
|
|
}
|
|
final unscannedIdx =
|
|
index - scanned.length - (sections.hasDivider ? 1 : 0);
|
|
return _buildListRow(unscanned[unscannedIdx], isScanned: false);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildSectionDivider(int count) {
|
|
return Container(
|
|
height: 24,
|
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
|
decoration: BoxDecoration(
|
|
border: Border(bottom: BorderSide(color: Colors.grey.shade200)),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
const Expanded(child: Divider(height: 0)),
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
child: Text(
|
|
'以下 $count 项未操作',
|
|
style: TextStyle(
|
|
fontSize: 10,
|
|
fontWeight: FontWeight.w600,
|
|
color: Colors.grey.shade500,
|
|
),
|
|
),
|
|
),
|
|
const Expanded(child: Divider(height: 0)),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildListRow(PaichaOverviewItem item, {required bool isScanned}) {
|
|
final rowStyle = TextStyle(
|
|
fontSize: 15,
|
|
fontWeight: isScanned ? FontWeight.w700 : FontWeight.w500,
|
|
color: Colors.black87,
|
|
);
|
|
|
|
final barColor = registration_calculations.registrationBarColor(
|
|
status: item.status,
|
|
isScanned: isScanned,
|
|
isTransitTarget: _isTransitTarget,
|
|
);
|
|
final bgColor = registration_calculations.registrationRowBgColor(
|
|
status: item.status,
|
|
isScanned: isScanned,
|
|
isTransitTarget: _isTransitTarget,
|
|
);
|
|
|
|
return 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.zongpaiNo,
|
|
textAlign: TextAlign.center,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: rowStyle,
|
|
),
|
|
),
|
|
Expanded(
|
|
flex: 18,
|
|
child: Text(
|
|
item.workOrderNo ?? '--',
|
|
textAlign: TextAlign.center,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: rowStyle,
|
|
),
|
|
),
|
|
Expanded(
|
|
flex: 12,
|
|
child: Text(
|
|
item.quantity.toString(),
|
|
textAlign: TextAlign.center,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: rowStyle,
|
|
),
|
|
),
|
|
Expanded(
|
|
flex: 28,
|
|
child: Text(
|
|
item.locationCode ?? '\u2014',
|
|
textAlign: TextAlign.center,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: rowStyle,
|
|
),
|
|
),
|
|
if (isScanned && _mode == RegistrationMode.multiCode) ...[
|
|
const SizedBox(width: 6),
|
|
SizedBox(
|
|
width: 28,
|
|
height: 28,
|
|
child: IconButton(
|
|
icon: Icon(Icons.delete_outline, size: 16),
|
|
color: Colors.red,
|
|
onPressed: () => _removeZongpai(item.zongpaiNo),
|
|
padding: EdgeInsets.zero,
|
|
constraints: const BoxConstraints(minWidth: 28, minHeight: 28),
|
|
),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildListMessage(String text) {
|
|
return Center(
|
|
child: Text(
|
|
text,
|
|
textAlign: TextAlign.center,
|
|
style: TextStyle(fontSize: 13, color: Colors.grey.shade600),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildListError(String text) {
|
|
return Center(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Text(
|
|
text,
|
|
textAlign: TextAlign.center,
|
|
style: const TextStyle(fontSize: 13, color: Colors.red),
|
|
),
|
|
const SizedBox(height: 6),
|
|
TextButton(
|
|
onPressed: _overviewZongpaiNo == null
|
|
? null
|
|
: () => _loadOverview(_overviewZongpaiNo!, force: true),
|
|
child: const Text('重试'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
// === Bottom Bar ===
|
|
|
|
Widget _buildBottomBar(ColorScheme colorScheme) {
|
|
return Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
border: Border(top: BorderSide(color: Colors.grey.shade300)),
|
|
),
|
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
|
child: SizedBox(
|
|
width: double.infinity,
|
|
height: 34,
|
|
child: ElevatedButton(
|
|
onPressed: _canSubmit ? _submit : null,
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: registrationSubmitColor(
|
|
canSubmit: _canSubmit,
|
|
isTransitTarget: _isTransitTarget,
|
|
primaryColor: colorScheme.primary,
|
|
),
|
|
foregroundColor: _canSubmit ? Colors.white : Colors.grey.shade600,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(6),
|
|
),
|
|
),
|
|
child: _isSubmitting
|
|
? const SizedBox(
|
|
width: 18,
|
|
height: 18,
|
|
child: CircularProgressIndicator(
|
|
strokeWidth: 2,
|
|
color: Colors.white,
|
|
),
|
|
)
|
|
: Text(
|
|
registrationSubmitLabel(
|
|
isTransitTarget: _isTransitTarget,
|
|
isMultiCode: _mode == RegistrationMode.multiCode,
|
|
zongpaiCount: _zongpaiNos.length,
|
|
),
|
|
style: const TextStyle(
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.w700,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
const _headerStyle = TextStyle(fontSize: 10, fontWeight: FontWeight.w700);
|