refine boxing UI: restructure info bar, scan bar, and mode switch

- Info bar: left-right layout with progress bar below, detail button on right
- Scan bar: remove '已识别' badge, show 工令号/总件数/已装X with larger font
- Mode switch: move to title right side, adopt rectangular style with 18px bold font

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Misaka_Company
2026-05-18 17:00:40 +08:00
parent 9e4667d68f
commit f60745607f
2 changed files with 215 additions and 219 deletions

View File

@@ -189,7 +189,7 @@ body {
flex-shrink: 0;
}
.scan-code {
font-size: 13px;
font-size: 20px;
font-weight: 700;
color: var(--text);
flex: 1;
@@ -197,6 +197,14 @@ body {
text-overflow: ellipsis;
white-space: nowrap;
}
.scan-zongpai-extra {
font-size: 11px;
color: var(--text-2);
font-weight: 500;
flex-shrink: 0;
white-space: nowrap;
margin-right: 4px;
}
.scan-badge {
font-size: 10px;
font-weight: 700;
@@ -216,7 +224,7 @@ body {
display: flex;
flex-direction: column;
position: relative;
padding: 8px 86px 8px 12px;
padding: 8px 12px 8px 12px;
border-bottom: 1px solid var(--border);
flex-shrink: 0;
background: #fafafa;
@@ -248,13 +256,19 @@ body {
white-space: nowrap;
}
/* 进度条+详情同行 */
.progress-with-detail {
display: flex;
align-items: center;
gap: 8px;
}
/* 进度条 */
.progress-wrap {
flex: 1;
height: 3px;
background: #e0e0e0;
border-radius: 2px;
overflow: hidden;
margin: 2px 0;
}
.progress-fill {
height: 100%;
@@ -264,29 +278,13 @@ body {
}
.progress-fill.full { background: var(--green); }
.info-row2 {
display: flex;
align-items: center;
gap: 4px;
}
.info-meta-text {
font-size: 11px;
color: var(--text-3);
flex: 1;
}
.info-meta-text .hl { color: var(--amber); font-weight: 700; }
.info-meta-text .packed { color: var(--blue); font-weight: 600; }
.detail-link {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
display: inline-flex;
align-items: center;
gap: 4px;
height: 34px;
font-size: 12px;
justify-content: center;
height: 28px;
min-width: 48px;
font-size: 11px;
font-weight: 700;
color: var(--blue);
background: var(--blue-lt);
@@ -309,10 +307,21 @@ body {
cursor: default;
}
.info-row2 {
display: flex;
align-items: center;
gap: 4px;
}
.info-meta-text {
font-size: 11px;
color: var(--text-3);
flex: 1;
}
.info-meta-text .hl { color: var(--amber); font-weight: 700; }
.info-meta-text .packed { color: var(--blue); font-weight: 600; }
/* 空状态的 info-bar */
.info-bar.empty .info-paichan,
.info-bar.empty .info-wo,
.info-bar.empty .info-erp,
.info-bar.empty .info-meta-text { color: #ccc; }
/* ── 已分配列表区 (可滚动) ── */
@@ -661,15 +670,15 @@ body {
<div class="info-bar empty">
<div class="info-row1">
<span class="info-paichan">排产号 —</span>
<span class="info-wo">工单 —</span>
<span class="info-erp">— 件</span>
</div>
<div class="progress-with-detail">
<div class="progress-wrap">
<div class="progress-fill" style="width:0%"></div>
</div>
<button class="detail-link disabled">详情</button>
</div>
<div class="info-row2">
<span class="info-meta-text">已有 — 箱 · 最大箱号 —</span>
<button class="detail-link disabled">详情</button>
</div>
</div>
@@ -718,6 +727,7 @@ body {
<div class="scan-bar scanned">
<div class="scan-check"></div>
<span class="scan-code">ZP202605180001</span>
<span class="scan-zongpai-extra">WO-2026-0882 / 200件</span>
<span class="scan-badge">已识别</span>
</div>
@@ -725,15 +735,15 @@ body {
<div class="info-bar">
<div class="info-row1">
<span class="info-paichan">PC-2605-A101</span>
<span class="info-wo">WO-2026-0882</span>
<span class="info-erp">200 件</span>
</div>
<div class="progress-with-detail">
<div class="progress-wrap">
<div class="progress-fill" style="width:25%"></div>
</div>
<button class="detail-link">详情</button>
</div>
<div class="info-row2">
<span class="info-meta-text">已有 <span class="packed">1 箱</span> · 最大箱号 <span class="hl">2</span> · 已装 50/200</span>
<button class="detail-link">详情</button>
</div>
</div>
@@ -781,21 +791,22 @@ body {
<div class="scan-bar scanned">
<div class="scan-check"></div>
<span class="scan-code">ZP202605180001</span>
<span class="scan-zongpai-extra">WO-2026-0882 / 200件</span>
<span class="scan-badge">已识别</span>
</div>
<div class="info-bar">
<div class="info-row1">
<span class="info-paichan">PC-2605-A101</span>
<span class="info-wo">WO-2026-0882</span>
<span class="info-erp">200 件</span>
</div>
<div class="progress-with-detail">
<div class="progress-wrap">
<div class="progress-fill" style="width:75%"></div>
</div>
<button class="detail-link">详情</button>
</div>
<div class="info-row2">
<span class="info-meta-text">已有 <span class="packed">3 箱</span> · 最大箱号 <span class="hl">7</span> · 已装 150/200</span>
<button class="detail-link">详情</button>
</div>
</div>
@@ -866,21 +877,22 @@ body {
<div class="scan-bar scanned">
<div class="scan-check"></div>
<span class="scan-code">ZP202605180001</span>
<span class="scan-zongpai-extra">WO-2026-0882 / 200件</span>
<span class="scan-badge">已识别</span>
</div>
<div class="info-bar">
<div class="info-row1">
<span class="info-paichan">PC-2605-A101</span>
<span class="info-wo">WO-2026-0882</span>
<span class="info-erp">200 件</span>
</div>
<div class="progress-with-detail">
<div class="progress-wrap">
<div class="progress-fill" style="width:75%"></div>
</div>
<button class="detail-link">详情</button>
</div>
<div class="info-row2">
<span class="info-meta-text">已有 <span class="packed">3 箱</span> · 最大箱号 <span class="hl">7</span> · 已装 150/200</span>
<button class="detail-link">详情</button>
</div>
</div>
@@ -951,21 +963,22 @@ body {
<div class="scan-bar scanned">
<div class="scan-check"></div>
<span class="scan-code">ZP202605180001</span>
<span class="scan-zongpai-extra">WO-2026-0882 / 200件</span>
<span class="scan-badge">已识别</span>
</div>
<div class="info-bar">
<div class="info-row1">
<span class="info-paichan">PC-2605-A101</span>
<span class="info-wo">WO-2026-0882</span>
<span class="info-erp">200 件</span>
</div>
<div class="progress-with-detail">
<div class="progress-wrap">
<div class="progress-fill" style="width:75%"></div>
</div>
<button class="detail-link">详情</button>
</div>
<div class="info-row2">
<span class="info-meta-text">已有 <span class="packed">3 箱</span> · 最大箱号 <span class="hl">7</span></span>
<button class="detail-link">详情</button>
</div>
</div>
@@ -1041,21 +1054,22 @@ body {
<div class="scan-bar scanned">
<div class="scan-check"></div>
<span class="scan-code">ZP202605180001</span>
<span class="scan-zongpai-extra">WO-2026-0882 / 200件</span>
<span class="scan-badge">已识别</span>
</div>
<div class="info-bar">
<div class="info-row1">
<span class="info-paichan">PC-2605-A101</span>
<span class="info-wo">WO-2026-0882</span>
<span class="info-erp">200 件</span>
</div>
<div class="progress-with-detail">
<div class="progress-wrap">
<div class="progress-fill" style="width:25%"></div>
</div>
<button class="detail-link">详情</button>
</div>
<div class="info-row2">
<span class="info-meta-text">已有 <span class="packed">1 箱</span> · 最大箱号 <span class="hl">2</span></span>
<button class="detail-link">详情</button>
</div>
</div>
@@ -1109,21 +1123,22 @@ body {
<div class="scan-bar scanned">
<div class="scan-check"></div>
<span class="scan-code">ZP202605180001</span>
<span class="scan-zongpai-extra">WO-2026-0882 / 200件</span>
<span class="scan-badge">已识别</span>
</div>
<div class="info-bar">
<div class="info-row1">
<span class="info-paichan">PC-2605-A101</span>
<span class="info-wo">WO-2026-0882</span>
<span class="info-erp">200 件</span>
</div>
<div class="progress-with-detail">
<div class="progress-wrap">
<div class="progress-fill" style="width:25%"></div>
</div>
<button class="detail-link">详情</button>
</div>
<div class="info-row2">
<span class="info-meta-text">已有 <span class="packed">2 箱</span> · 最大箱号 <span class="hl">5</span></span>
<button class="detail-link">详情</button>
</div>
</div>
@@ -1175,21 +1190,22 @@ body {
<div class="scan-bar scanned">
<div class="scan-check"></div>
<span class="scan-code">ZP202605180001</span>
<span class="scan-zongpai-extra">WO-2026-0882 / 200件</span>
<span class="scan-badge">已识别</span>
</div>
<div class="info-bar">
<div class="info-row1">
<span class="info-paichan">PC-2605-A101</span>
<span class="info-wo">WO-2026-0882</span>
<span class="info-erp">200 件</span>
</div>
<div class="progress-with-detail">
<div class="progress-wrap">
<div class="progress-fill" style="width:25%"></div>
</div>
<button class="detail-link">详情</button>
</div>
<div class="info-row2">
<span class="info-meta-text">已有 <span class="packed">1 箱</span> · 最大箱号 <span class="hl">2</span> · 剩余可装 150</span>
<button class="detail-link">详情</button>
</div>
</div>
@@ -1241,21 +1257,22 @@ body {
<div class="scan-bar scanned">
<div class="scan-check"></div>
<span class="scan-code">ZP202605180002</span>
<span class="scan-zongpai-extra">WO-2026-0901 / 100件</span>
<span class="scan-badge">已识别</span>
</div>
<div class="info-bar">
<div class="info-row1">
<span class="info-paichan">PC-2605-B202</span>
<span class="info-wo">WO-2026-0901</span>
<span class="info-erp">100 件</span>
</div>
<div class="progress-with-detail">
<div class="progress-wrap">
<div class="progress-fill full" style="width:100%"></div>
</div>
<button class="detail-link">详情</button>
</div>
<div class="info-row2">
<span class="info-meta-text">已有 <span class="packed">3 箱</span> · 最大箱号 <span class="hl">3</span> · <span style="color:var(--green);font-weight:700">100/100 已装完</span></span>
<button class="detail-link">详情</button>
</div>
</div>
@@ -1347,21 +1364,22 @@ body {
<div class="scan-bar scanned">
<div class="scan-check"></div>
<span class="scan-code">ZP202605180001</span>
<span class="scan-zongpai-extra">WO-2026-0882 / 200件</span>
<span class="scan-badge">已识别</span>
</div>
<div class="info-bar">
<div class="info-row1">
<span class="info-paichan">PC-2605-A101</span>
<span class="info-wo">WO-2026-0882</span>
<span class="info-erp">200 件</span>
</div>
<div class="progress-with-detail">
<div class="progress-wrap">
<div class="progress-fill" style="width:75%"></div>
</div>
<button class="detail-link">详情</button>
</div>
<div class="info-row2">
<span class="info-meta-text">已有 <span class="packed">3 箱</span> · 最大箱号 <span class="hl">7</span> · 已装 150/200</span>
<button class="detail-link">详情</button>
</div>
</div>
@@ -1456,10 +1474,10 @@ body {
│ "装箱编号" [⇄ 单码装箱 P2] │ AppBar
├──────────────────────────────────────────┤
│ [通知条] 可叠加显示,每条 ~30px │ 可选
├──────────────────────────────────────────┤ 38px
│ ✓ ZP202605180001 已识别 │ 扫码条
├──────────────────────────────────────────┤ ~52px
│ PC-2605-A101 WO-2026-0882 200件 [详情]│
├──────────────────────────────────────────┤ ~50px
│ ✓ ZP202605180001 WO-0882 / 200件 已识别 │ 扫码条
├──────────────────────────────────────────┤ ~45px
│ PC-2605-A101 [详情]
│ ▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ 进度条 │ info-bar
│ 已有 2箱 · 最大箱号 5 · 已装50/200 │
├──────────────────────────────────────────┤

View File

@@ -1305,10 +1305,15 @@ class _BoxingPageState extends State<BoxingPage> with WidgetsBindingObserver {
onKeyEvent: _onKeyEvent,
child: Scaffold(
appBar: AppBar(
title: const Text('装箱编号'),
title: Row(
children: [
const Text('装箱编号'),
const SizedBox(width: 8),
_buildModePill(),
],
),
toolbarHeight: 44,
titleSpacing: 12,
actions: [_buildModePill(), const SizedBox(width: 8)],
),
body: Column(
children: [
@@ -1446,27 +1451,10 @@ class _BoxingPageState extends State<BoxingPage> with WidgetsBindingObserver {
);
}
Widget _buildSingleCodeBody(ColorScheme colorScheme) {
final isWaiting = _phase == _Phase.waiting && _zongpaiNo == null;
final isFinished =
_phase == _Phase.scanned &&
_zongpaiNo != null &&
_remainingQuantity <= 0;
return Column(
children: [
_buildSingleScanBar(isWaiting),
_buildSingleInfoBar(isWaiting, colorScheme),
_buildSingleAssignedList(isWaiting, isFinished),
_buildSingleBottomArea(isWaiting || isFinished),
],
);
}
Widget _buildSingleScanBar(bool isWaiting) {
if (isWaiting) {
return Container(
height: 38,
height: 50,
padding: const EdgeInsets.symmetric(horizontal: 12),
decoration: BoxDecoration(
color: Colors.grey.shade100,
@@ -1486,7 +1474,7 @@ class _BoxingPageState extends State<BoxingPage> with WidgetsBindingObserver {
}
return Container(
height: 38,
height: 50,
padding: const EdgeInsets.symmetric(horizontal: 12),
decoration: BoxDecoration(
color: Colors.green.shade50,
@@ -1499,23 +1487,17 @@ class _BoxingPageState extends State<BoxingPage> with WidgetsBindingObserver {
Expanded(
child: Text(
_zongpaiNo ?? '',
style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w700),
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w700),
overflow: TextOverflow.ellipsis,
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 1),
decoration: BoxDecoration(
color: Colors.green.shade100,
borderRadius: BorderRadius.circular(8),
),
child: Text(
'已识别',
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w700,
color: Colors.green.shade700,
),
const SizedBox(width: 8),
Text(
'${_workOrderNo ?? "--"} / ${_erpQuantity ?? 0}件 / 已装$_packedQuantity',
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w500,
color: Colors.black54,
),
),
],
@@ -1523,6 +1505,23 @@ class _BoxingPageState extends State<BoxingPage> with WidgetsBindingObserver {
);
}
Widget _buildSingleCodeBody(ColorScheme colorScheme) {
final isWaiting = _phase == _Phase.waiting && _zongpaiNo == null;
final isFinished =
_phase == _Phase.scanned &&
_zongpaiNo != null &&
_remainingQuantity <= 0;
return Column(
children: [
_buildSingleScanBar(isWaiting),
_buildSingleInfoBar(isWaiting, colorScheme),
_buildSingleAssignedList(isWaiting, isFinished),
_buildSingleBottomArea(isWaiting || isFinished),
],
);
}
Widget _buildSingleInfoBar(bool isWaiting, ColorScheme colorScheme) {
final total = _erpQuantity ?? 0;
final packed = isWaiting ? 0 : _packedQuantity;
@@ -1531,57 +1530,50 @@ class _BoxingPageState extends State<BoxingPage> with WidgetsBindingObserver {
final detailEnabled = !isWaiting && _existingBoxes.isNotEmpty;
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: Colors.grey.shade50,
border: Border(bottom: BorderSide(color: Colors.grey.shade300)),
),
child: IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
Expanded(
child: Text(
Text(
isWaiting ? '排产号 --' : (_paichanNo ?? '--'),
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w700,
color: isWaiting
? Colors.grey.shade400
: Colors.black87,
color: isWaiting ? Colors.grey.shade400 : Colors.black87,
),
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(width: 8),
Text(
isWaiting ? '工单 --' : (_workOrderNo ?? '--'),
const SizedBox(width: 10),
Expanded(
child: Text(
isWaiting
? '已有 -- 箱 · 最大箱号 --'
: '已有 ${_existingBoxes.length} 箱 · 最大箱号 $_maxBoxNo',
style: TextStyle(
fontSize: 12,
fontSize: 10,
color: isWaiting
? Colors.grey.shade400
: Colors.black54,
: Colors.grey.shade600,
),
),
const SizedBox(width: 8),
Text(
isWaiting ? '-- 件' : '$total',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w700,
color: isWaiting
? Colors.grey.shade400
: Colors.black87,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.right,
),
),
],
),
const SizedBox(height: 5),
const SizedBox(height: 4),
ClipRRect(
borderRadius: BorderRadius.circular(2),
child: LinearProgressIndicator(
@@ -1593,22 +1585,6 @@ class _BoxingPageState extends State<BoxingPage> with WidgetsBindingObserver {
),
),
),
const SizedBox(height: 5),
Align(
alignment: Alignment.centerLeft,
child: Text(
isWaiting
? '已有 -- 箱 · 最大箱号 --'
: '已有 ${_existingBoxes.length} 箱 · 最大箱号 $_maxBoxNo · 已装 $packed/$total',
style: TextStyle(
fontSize: 11,
color: isWaiting
? Colors.grey.shade400
: Colors.grey.shade600,
),
overflow: TextOverflow.ellipsis,
),
),
],
),
),
@@ -1616,6 +1592,7 @@ class _BoxingPageState extends State<BoxingPage> with WidgetsBindingObserver {
_buildDetailButton(detailEnabled, colorScheme),
],
),
),
);
}
@@ -2064,46 +2041,47 @@ class _BoxingPageState extends State<BoxingPage> with WidgetsBindingObserver {
final isSingle = _mode == BoxingMode.singleCode;
final bgColor = isSingle ? Colors.blue.shade700 : Colors.orange.shade700;
return GestureDetector(
return Material(
borderRadius: BorderRadius.circular(8),
color: bgColor,
child: InkWell(
borderRadius: BorderRadius.circular(8),
onTap: _isAutoProcessing ? null : _cycleMode,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 9, vertical: 3),
decoration: BoxDecoration(
color: bgColor,
borderRadius: BorderRadius.circular(12),
),
height: 36,
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.swap_horiz, color: Colors.white, size: 14),
const SizedBox(width: 4),
Text(
const Icon(Icons.swap_horiz, color: Colors.white, size: 18),
const SizedBox(width: 6),
Flexible(
child: FittedBox(
fit: BoxFit.scaleDown,
child: Text(
_modeLabel,
maxLines: 1,
style: const TextStyle(
color: Colors.white,
fontSize: 11,
fontSize: 18,
fontWeight: FontWeight.w800,
),
),
),
),
const SizedBox(width: 8),
Text(
'P2',
style: TextStyle(
color: Colors.white.withValues(alpha: 0.88),
fontSize: 12,
fontWeight: FontWeight.w700,
),
),
const SizedBox(width: 4),
Container(
padding: const EdgeInsets.symmetric(horizontal: 4),
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.22),
borderRadius: BorderRadius.circular(4),
),
child: const Text(
'P2',
style: TextStyle(
color: Colors.white,
fontSize: 10,
fontWeight: FontWeight.w600,
),
),
),
],
),
),
),
);
}