diff --git a/docs/single-code-boxing-ui-states.html b/docs/single-code-boxing-ui-states.html
new file mode 100644
index 0000000..810ba4f
--- /dev/null
+++ b/docs/single-code-boxing-ui-states.html
@@ -0,0 +1,2104 @@
+
+
+
+
+
+单码装箱模式 - UI 状态全览
+
+
+
+
+单码装箱模式 — UI 状态全览
+
+ 源码:lib/pages/boxing_page.dart(_BoxingPageState)
+ 覆盖 BoxingMode.singleCode 下所有 UI 状态、状态机流转与交互细节
+
+
+
+
+
+
+
+
+
+
+
+
1. 状态机(_Phase 枚举)
+
+
+ waiting
等待扫码
+ → 扫码成功 →
+ scanned
已扫码,已自动填充
+ → 用户点击确认 →
+ submitting
正在提交…
+ →
+ 成功,尚有剩余 →
+ 回到 scanned(箱号+1,数量=剩余)
+ /
+ 回到 waiting(全部装箱完毕)
+ 失败 →
+ 停留在 scanned,显示错误覆盖
+
+
+
+
+
+ | _Phase |
+ 触发条件 |
+ 主要 UI 效果 |
+
+
+
+
+ waiting |
+ 初始化 / 重置 / 全部装箱完毕 |
+ 扫码区灰色占位;信息区灰色 "--";输入区禁用 |
+
+
+ scanned |
+ 扫码成功且 API 返回有效数据 |
+ 扫码区绿色边框+总排号;信息区展示数据;输入区可编辑,自动填充箱号/数量 |
+
+
+ | 没有 submitted |
+ — |
+ 单码模式中,提交成功后直接进入新的 scanned 或 resetting waiting,不经 submitted 阶段 |
+
+
+
+
+
+
+
+
+
+
2. UI 状态可视化
+
每个手机模型展示一个具体状态。底部状态栏颜色参考上方图例。
+
+
+
+
+
+
2.1 等待扫码 (waiting) 初始状态
+
+
+
+ 📷 请扫描执行卡二维码
+
+
+
+
+
+
+
+
+
+
+
+
+
+
2.2 已扫码-正常 (scanned, can submit) 最常见状态
+
+
+
+ ✅ ZP202605180001 已识别
+
+
+
+ PC-2605-A101
+ WO-2026-0882
+ 200件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
2.3 已扫码+已分配 (with assigned boxes)
+
+
+
+ ✅ ZP202605180001 已识别
+
+
+
+ PC-2605-A101
+ WO-2026-0882
+ 200件
+
+
+
+
+
+
已分配
+
+
+
3号箱
+
数量 50
+
+
+
+
+
+
+
+
+
7号箱
+
数量 100
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
2.4 已分配行 - 编辑中 (editing assigned) 行内编辑
+
+
+
+ ✅ ZP202605180001 已识别
+
+
+
+ PC-2605-A101
+ WO-2026-0882
+ 200件
+
+
+
+
+
+
已分配
+
+
+
3号箱
+
数量 50
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
2.5 已分配行 - 删除确认 (delete confirm) 行内确认
+
+
+
+ ✅ ZP202605180001 已识别
+
+
+
+ PC-2605-A101
+ WO-2026-0882
+ 200件
+
+
+
+
+
+
已分配
+
+
+
3号箱
+
数量 50
+
+
+
+
+
+
+
+
+
5号箱
+
数量 100
+
+
+
+
+
+
+ 确认删除此条记录?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
2.6 正在提交 (submitting) 按钮 loading
+
+
+
+ ✅ ZP202605180001 已识别
+
+
+
+ PC-2605-A101
+ WO-2026-0882
+ 200件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
2.7 箱号重复 (duplicate box no) 琥珀色警告
+
+
+
+
+ ⚠️ 箱号 5 已存在,请重新输入
+
+
+ ✅ ZP202605180001 已识别
+
+
+
+ PC-2605-A101
+ WO-2026-0882
+ 200件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
2.8 数量超限 (quantity too high) 红色警告
+
+
+
+ ✅ ZP202605180001 已识别
+
+
+
+ PC-2605-A101
+ WO-2026-0882
+ 200件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
2.9 已全部装箱完毕 (fully packed on scan) 红色覆盖
+
+
+
+ ✅ ZP202605180002 已识别
+
+
+
+ PC-2605-B202
+ WO-2026-0901
+ 100件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
2.10 无效码 (invalid code) 红色覆盖 2s
+
+
+
+ ❌ 无效码,请重新扫描
+
+
+ 📷 请扫描执行卡二维码
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
2.11 网络异常 (network error) 黄色覆盖 2s
+
+
+
+ ⚠️ 网络异常,请检查网络连接
+
+
+ 📷 请扫描执行卡二维码
+
+
+
+
+
+
+
+
+
+
+
+
+
+
2.12 提交失败 (submit failure) 红色覆盖 2s
+
+
+
+ ❌ 服务器响应异常,请稍后重试
+
+
+ ✅ ZP202605180001 已识别
+
+
+
+ PC-2605-A101
+ WO-2026-0882
+ 200件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
2.13 提交重复 (duplicate on submit) 琥珀覆盖 2s
+
+
+
+ ⚠️ 该总排号在箱号 5 已存在,请重新输入
+
+
+ ✅ ZP202605180001 已识别
+
+
+
+ PC-2605-A101
+ WO-2026-0882
+ 200件
+
+
+
+
+
+
+
+
+
+
+ 该总排号在箱号 5 已存在,请重新输入
+
+
+
+
+
+
+
2.14 未配置 API (no API configured) 红色覆盖 2s
+
+
+
+ ❌ 未配置 API 地址,请前往设置
+
+
+ 📷 请扫描执行卡二维码
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
2.15 同步转运数据中 (auto processing) 橙色横幅
+
+
+
+ 正在同步转运数据...
+
+
+ ✅ ZP202605180003 已识别
+
+
+
+ PC-2605-C303
+ WO-2026-0920
+ 300件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
2.16 自动装箱警告 (auto warnings) 琥珀横幅
+
+
+
+ ⚠️ 总排号 ZP-INVALID 未找到排产号信息,已忽略
+
+
+ ✅ ZP202605180004 已识别
+
+
+
+ PC-2605-D404
+ WO-2026-0931
+ 150件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
3. 提交按钮启用条件(_canSubmit)
+
+
+ 确认按钮的 enabled 状态由 _canSubmit 决定。当以下所有条件同时满足时,按钮启用:
+
+
+
+
+
+ | # |
+ 条件 |
+ 代码表达式 |
+ 不满足时效果 |
+
+
+
+
+ | 1 |
+ 未处于提交中 |
+ !_isSubmitting |
+ 按钮显示 loading 转圈 |
+
+
+ | 2 |
+ 阶段为 scanned |
+ _phase == _Phase.scanned |
+ 按钮灰色禁用 |
+
+
+ | 3 |
+ 已有总排号 |
+ _zongpaiNo != null |
+ 按钮灰色禁用 |
+
+
+ | 4 |
+ 箱号有效 |
+ boxNo != null && boxNo > 0 |
+ 按钮灰色禁用 |
+
+
+ | 5 |
+ 数量有效 |
+ qty != null && qty > 0 |
+ 按钮灰色禁用 |
+
+
+ | 6 |
+ 数量未超限 |
+ !_quantityTooHigh(qty ≤ remaining) |
+ 数量输入红色边框;状态栏红色 "超出可装数量上限" |
+
+
+ | 7 |
+ 箱号不重复 |
+ !_isDuplicateBoxNo |
+ 箱号输入琥珀边框;琥珀横幅;状态栏琥珀色 "箱号 X 已存在" |
+
+
+
+
+
+
+
+
+
+
4. 状态栏覆盖机制(_showStatusOverride)
+
+
+ 方法签名:void _showStatusOverride(String text, StatusDotColor dot, Duration duration)
+ 大多数反馈状态通过此方法展示。调用后立即替换底部状态栏的 文字和圆点颜色,并在 duration 到期后自动恢复为基础状态(由 _updateBaseStatus() 计算)。
+
+
+
+
+
+ | 场景 |
+ 文字 |
+ 颜色 |
+ 持续时间 |
+
+
+
+
+ | 无效码 |
+ 无效码,请重新扫描 |
+ 红色 |
+ 2s |
+
+
+ | 网络异常 |
+ 网络异常,请检查网络连接 |
+ 黄色 |
+ 2s |
+
+
+ | 查询失败 |
+ 查询失败(或具体消息) |
+ 红色 |
+ 2s |
+
+
+ | 提交重复 |
+ 该总排号在箱号 X 已存在,请重新输入 |
+ 琥珀 |
+ 2s |
+
+
+ | 提交失败 |
+ 提交失败(或具体消息) |
+ 红色 |
+ 2s |
+
+
+ | 未配置 API |
+ 未配置 API 地址,请前往设置 |
+ 红色 |
+ 2s |
+
+
+ | 装箱成功-继续 |
+ 请继续完成剩余数量装箱 |
+ 绿色 |
+ 1.5s |
+
+
+ | 装箱成功-全部 |
+ 装箱成功 |
+ 绿色 |
+ 1.5s |
+
+
+ | 全部装箱完毕 |
+ 该总排号已全部装箱完毕 |
+ 红色 |
+ 常驻(_statusOverride) |
+
+
+ | 删除成功 |
+ 删除成功 |
+ 绿色 |
+ 1.5s |
+
+
+ | 修改成功 |
+ 修改成功 |
+ 绿色 |
+ 1.5s |
+
+
+ | 保存编辑-数量无效 |
+ 请输入有效数量 |
+ 红色 |
+ 2s |
+
+
+ | 保存编辑-数量超限 |
+ 超出可装数量上限 |
+ 红色 |
+ 2s |
+
+
+ | 同步转运数据 |
+ 正在同步转运数据... |
+ 橙色 |
+ 常驻(直到处理结束) |
+
+
+
+
+
+
+
+
+
+
5. 自动填充逻辑(_applyAutoFill)
+
+
+ 扫码成功并获取 API 数据后自动触发。核心逻辑:填充箱号 = lastBoxNo+1 或 maxBoxNo+1;填充数量 = 剩余可装数量;数量输入框自动全选并聚焦。
+
+
+
+
+
+ | 情况 |
+ 箱号填充 |
+ 数量填充 |
+
+
+
+
+ | 首次扫码(无历史箱号) |
+ maxBoxNo + 1(通常为 1) |
+ erpQuantity - packedQuantity(全部剩余) |
+
+
+ | 上次装箱后有继续 |
+ lastBoxNo + 1 |
+ 剩余可装数量 |
+
+
+ | 已全部装箱完毕 |
+ 清空 |
+ 清空 |
+
+
+
+
+
+
+
+
+
+
6. 已分配行操作详解
+
+
+ 每个 CurrentZongpaiBoxData 渲染为一行 _buildAssignedBoxRow。操作按钮在 view/edit 模式 和 delete 确认模式 间切换。
+
+
+
+
+
+ | 操作 |
+ 入口 |
+ 交互过程 |
+ 成功后效果 |
+
+
+
+
+ | 修改 |
+ 点击 ✏️ |
+ 行变橙色背景;数量文字→文本输入;显示 ✅保存 / ❌取消 按钮 |
+ 调用 updateBoxRecord;状态栏绿 "修改成功" 1.5s;自动刷新输入区 |
+
+
+ | 删除 |
+ 点击 🗑️ |
+ 行下方出现红色确认条 "确认删除此条记录?" [是] [否] |
+ 调用 deleteBoxRecord;状态栏绿 "删除成功" 1.5s;行移除此数据 |
+
+
+ | 取消编辑 |
+ 点击 ❌ 或 "否" |
+ 恢复 view 模式,不做 API 调用 |
+ 无 |
+
+
+
+
+
+
+
+
+
+
7. 模式切换(_cycleMode)
+
+
+ 触发方式:点击 Pill 或 按下 P2 物理按键(Android KeyCode R1 / LogicalKey gameButtonRight1 / LogicalKey select)。
+ 切换时调用 _resetState() 清空所有状态,包括阶段、总排号、箱号输入等。
+
+
+
+
+
+ | 方向 |
+ Pill 背景色 |
+ 标签 |
+
+
+
+
+ | 单码 → 多码 |
+ 橙色 Colors.orange.shade700 |
+ 多码凑箱 |
+
+
+ | 多码 → 单码 |
+ 蓝色 Colors.blue.shade700 |
+ 单码装箱 |
+
+
+
+
+
+
+
+
+
+
8. 装箱详情页(BoxingDetailPage)
+
+
+ 源码:lib/pages/boxing_detail_page.dart
+ 通过点击主页面 "详情 →" 进入。传入 paichanNo 和 existingBoxes,按箱号分组展示每个箱内的总排号明细(总排号、工单号、数量/总量)。
+
+
+
+
+
装箱详情(导航页)
+
+
+
装箱详情 PC-2605-A101
+
+
+
+ 箱号 3
+ 共 50 件
+
+
+
+ ZP202605180001
+ WO-2026-0882
+ 50/--
+
+
+
+
+ 箱号 7
+ 共 100 件
+
+
+
+ ZP202605180001
+ WO-2026-0882
+ 100/--
+
+
+
+
+ 共 2 箱
+
+
+
+
+
+
+
+
+
+
+
9. 关键状态字段速查表
+
+
+
+
+ | 字段 |
+ 类型 |
+ 说明 |
+
+
+
+
+ _mode |
+ BoxingMode |
+ singleCode / multiCode |
+
+
+ _phase |
+ _Phase (enum) |
+ waiting / scanned(单码无 submitted) |
+
+
+ _zongpaiNo |
+ String? |
+ 当前总排号,null = 未扫码 |
+
+
+ _paichanNo |
+ String? |
+ 来自 API 的排产号 |
+
+
+ _workOrderNo |
+ String? |
+ 来自 API 的工单号 |
+
+
+ _erpQuantity |
+ int? |
+ 来自 API 的 ERP 总数量 |
+
+
+ _currentZongpaiBoxes |
+ List<CurrentZongpaiBoxData> |
+ 当前总排号已分配的箱号列表("已分配" 区数据源) |
+
+
+ _existingBoxes |
+ List<BoxDetailData> |
+ 该排产号所有已有箱号(详情页数据源) |
+
+
+ _maxBoxNo |
+ int |
+ 已有最大箱号,用于填充下一个箱号 |
+
+
+ _lastBoxNo |
+ int? |
+ 上次提交的箱号(用于 continue 时 boxNo+1) |
+
+
+ _editingBox |
+ CurrentZongpaiBoxData? |
+ 当前正在编辑的已分配行(null = 非编辑状态) |
+
+
+ _isSubmitting |
+ bool |
+ 正在提交 API 请求(禁用按钮、显示 loading 转圈) |
+
+
+ _isDuplicateBoxNo |
+ bool |
+ 当前箱号是否和已有箱号重复 |
+
+
+ _editingAssignedItemId |
+ int? |
+ 正在编辑的已分配行 ID |
+
+
+ _deletingAssignedItemId |
+ int? |
+ 待删除的已分配行 ID(显示确认条) |
+
+
+ _statusOverrideText |
+ String? |
+ 覆盖状态栏文字(null = 使用基础状态文字) |
+
+
+ _statusOverrideDot |
+ StatusDotColor? |
+ 覆盖状态栏圆点颜色 |
+
+
+ _isAutoProcessing |
+ bool |
+ 是否正在自动同步/装箱转运数据 |
+
+
+
+
+
+
+
+
+
+
10. API 数据依赖
+
+
+ 所有核心信息来自 BoxInfoResult(方法:fetchBoxInfo),装箱操作依赖 saveBoxRecord / updateBoxRecord / deleteBoxRecord。
+
+
+
+
+
+ | API |
+ 触发时机 |
+ 返回关键字段 |
+
+
+
+
+ fetchBoxInfo(zongpaiNo) |
+ 扫码时 |
+ paichanNo, workOrderNo, quantity, currentZongpaiBoxes, existingBoxes, maxBoxNo |
+
+
+ saveBoxRecord(zongpaiNo, boxNo, quantity) |
+ 首次添加装箱记录 |
+ success, isDuplicate, boxItemId |
+
+
+ updateBoxRecord(boxItemId, boxNo, quantity) |
+ 修改已分配行 / 保存编辑 |
+ success, isDuplicate |
+
+
+ deleteBoxRecord(boxItemId) |
+ 删除已分配行确认 |
+ success |
+
+
+
+
+
+
+ 生成时间:2026-05-18 · 源码:lib/pages/boxing_page.dart(2545行)
+ 相关模块:lib/pages/boxing_detail_page.dart · lib/widgets/status_bar.dart · lib/services/boxing_context.dart
+
+
+
+
diff --git a/docs/single-code-boxing-ui-v2.html b/docs/single-code-boxing-ui-v2.html
new file mode 100644
index 0000000..69ba195
--- /dev/null
+++ b/docs/single-code-boxing-ui-v2.html
@@ -0,0 +1,1488 @@
+
+
+
+
+
+单码装箱 UI v2 — 重构布局
+
+
+
+
+单码装箱 UI v2 — 重构布局
+参考多码凑箱设计语言 · 竖向空间最优 · 固定底栏 + 可滚动已分配区
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
场景1 · 等待扫码(初始状态)
+
+
+
+
+
+ 📷
+ 请扫描执行卡二维码
+
+
+
+
+
+ 排产号 —
+ 工单 —
+ — 件
+
+
+
+ 已有 — 箱 · 最大箱号 —
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
场景2 · 已扫码,自动填充箱号/数量(最常见)
+
+
+
+
+
+
✓
+
ZP202605180001
+
已识别
+
+
+
+
+
+ PC-2605-A101
+ WO-2026-0882
+ 200 件
+
+
+
+ 已有 1 箱 · 最大箱号 2 · 已装 50/200
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
场景3 · 已扫码 + 已有分配记录(可滚动)
+
+
+
+
+
✓
+
ZP202605180001
+
已识别
+
+
+
+
+ PC-2605-A101
+ WO-2026-0882
+ 200 件
+
+
+
+ 已有 3 箱 · 最大箱号 7 · 已装 150/200
+
+
+
+
+
+
+
+
+
+
1
+
+
+
50 件
+
+
+
+
+
+
2
+
+
+
100 件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
场景4 · 已分配行 — 行内编辑(琥珀色背景)
+
+
+
+
+
✓
+
ZP202605180001
+
已识别
+
+
+
+
+ PC-2605-A101
+ WO-2026-0882
+ 200 件
+
+
+
+ 已有 3 箱 · 最大箱号 7 · 已装 150/200
+
+
+
+
+
+
+
+
+
+
1
+
+
+
50 件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
场景5 · 已分配行 — 删除确认(行内展开)
+
+
+
+
+
✓
+
ZP202605180001
+
已识别
+
+
+
+
+ PC-2605-A101
+ WO-2026-0882
+ 200 件
+
+
+
+ 已有 3 箱 · 最大箱号 7
+
+
+
+
+
+
+
+
+
1
+
+
+
50 件
+
+
+
+
+
+
+
2
+
+
+
100 件
+
+
+
+
+
+ 确认删除 7 号箱记录?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
场景6 · 正在提交(按钮 loading,全局禁用)
+
+
+
+
+
✓
+
ZP202605180001
+
已识别
+
+
+
+
+ PC-2605-A101
+ WO-2026-0882
+ 200 件
+
+
+
+ 已有 1 箱 · 最大箱号 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
场景7 · 箱号重复(琥珀色通知 + 输入框高亮)
+
+
+
+
+
+ ⚠
+ 箱号 5 已存在,请重新输入
+
+
+
+
✓
+
ZP202605180001
+
已识别
+
+
+
+
+ PC-2605-A101
+ WO-2026-0882
+ 200 件
+
+
+
+ 已有 2 箱 · 最大箱号 5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
场景8 · 数量超限(红色通知 + 输入框高亮)
+
+
+
+
+
+ ✕
+ 超出可装数量上限(最多可装 150 件)
+
+
+
+
✓
+
ZP202605180001
+
已识别
+
+
+
+
+ PC-2605-A101
+ WO-2026-0882
+ 200 件
+
+
+
+ 已有 1 箱 · 最大箱号 2 · 剩余可装 150
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
场景9 · 已全部装完(保留明细,输入禁用)
+
+
+
+
+
+ ✓
+ ZP202605180002 已全部装箱完毕,无需操作
+
+
+
+
✓
+
ZP202605180002
+
已识别
+
+
+
+
+ PC-2605-B202
+ WO-2026-0901
+ 100 件
+
+
+
+ 已有 3 箱 · 最大箱号 3 · 100/100 已装完
+
+
+
+
+
+
+
+
+
1
+
+
+
30 件
+
+
+
+
+
+
2
+
+
+
30 件
+
+
+
+
+
+
3
+
+
+
40 件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
场景10 · 自动同步转运数据(processing)
+
+
+
+
+
+
+
+ ⚠
+ ZP202605180099 未找到排产号信息,已忽略
+
+
+
+
✓
+
ZP202605180001
+
已识别
+
+
+
+
+ PC-2605-A101
+ WO-2026-0882
+ 200 件
+
+
+
+ 已有 3 箱 · 最大箱号 7 · 已装 150/200
+
+
+
+
+
+
+
+
+
1
+
+
+
50 件
+
+
+
+
+
2
+
+
+
100 件
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
v2 布局优化要点(对比原版)
+
+ - AppBar 44px:标题 + 模式徽章一行,去掉原版独占区域;蓝色 Pill 明确区分单码/多码
+ - 扫码条 38px:从原版 ~52px 大卡片压缩为紧凑横条,等待/已识别两态颜色清晰
+ - 排产信息 header 约 52px:左侧三行合并(排产号+工单+ERP件数 / 进度条 / 已有箱数),右侧固定醒目的详情按钮;原版散落两块约 80px,节省 ~28px
+ - 已装入进度条:新增 3px 高度进度条直观显示已装/总量比例,不占额外空间
+ - 已分配列表每行 40px:与多码设计对齐(序号+彩色条+箱号/扫码标注+件数+操作),可滚动
+ - 全部装箱完毕仍保留明细:顶部绿色提示 + 进度条全绿 + 底栏禁用,列表继续展示已分配箱号,便于核对结果
+ - 删除确认行内 28px 条:不弹框,与多码保持一致
+ - 固定底栏:箱号输入 + 数量输入 + 确认按钮 横排一行(~50px),不参与滚动
+ - 通知条 ~30px:橙/琥珀/蓝/绿四色语义,替代原版内嵌 banner,可叠加
+ - 状态栏 28px:圆点 + 简短文字,去掉原版 ~38px 的高度
+
+
+
+
+
+
+
UI 结构(v2)
+
┌──────────────────────────────────────────┐ 44px
+│ "装箱编号" [⇄ 单码装箱 P2] │ AppBar
+├──────────────────────────────────────────┤
+│ [通知条] 可叠加显示,每条 ~30px │ 可选
+├──────────────────────────────────────────┤ 38px
+│ ✓ ZP202605180001 已识别 │ 扫码条
+├──────────────────────────────────────────┤ ~52px
+│ PC-2605-A101 WO-2026-0882 200件 [详情]│
+│ ▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ 进度条 │ info-bar
+│ 已有 2箱 · 最大箱号 5 · 已装50/200 │
+├──────────────────────────────────────────┤
+│ 此总排号已分配 2 条 │ list-header
+│ 1 ▌ 3号箱 本次扫码 50件 ✏🗑 │ 40px/行
+│ 2 ▌ 7号箱 本次扫码 100件 ✏🗑 │
+│ ... │ ← 可滚动区域
+├──────────────────────────────────────────┤
+│ 箱号[8] 数量[50 ] [确认] │ ~50px
+├──────────────────────────────────────────┤ 28px
+│ ● 数量已填入,请确认或修改 │ 状态栏
+└──────────────────────────────────────────┘
+
+
+
+
+
+
+
diff --git a/docs/单码装箱UI重构PRD.md b/docs/单码装箱UI重构PRD.md
new file mode 100644
index 0000000..4072de0
--- /dev/null
+++ b/docs/单码装箱UI重构PRD.md
@@ -0,0 +1,279 @@
+# 单码装箱页面 UI 重构 PRD
+
+**文档版本**:v2.0
+**更新日期**:2026-05-18
+**涉及页面**:`lib/pages/boxing_page.dart`(BoxingMode.singleCode)
+**参考设计**:多码凑箱 UI v2(`multi-code-boxing-ui-v2.html`)
+**产出物**:`single-code-boxing-ui-v2.html`
+
+---
+
+## 一、背景与目标
+
+原单码装箱页面各区块自然堆叠,当已分配记录增多或通知条出现时,下方输入区会被挤出屏幕可视范围,操作体验差。同时,原版与多码凑箱在视觉语言上存在差异,两种模式切换后用户需要重新适应布局。
+
+**重构目标:**
+
+1. 与多码凑箱采用统一的设计语言,降低双模式切换的认知成本
+2. 采用固定顶部 + 可滚动中间 + 固定底栏结构,无论已分配记录多少,输入区始终可见
+3. 在不损失信息量的前提下,压缩各区块高度,让屏幕展示更多有效内容
+4. 去掉返回按钮,简化底栏操作区
+
+---
+
+## 二、整体布局结构
+
+### v1(原版)布局
+
+```
+AppBar(~52px)
+扫码卡片(~52px)
+信息区 - 排产号+工单+件数(~30px)
+信息区 - 已有箱数+最大箱号+详情(~28px)
+分隔线
+已分配列表(自然高度,不可滚动)
+输入区 - 箱号+数量+确认(~48px)
+操作行 - 返回按钮(~48px)
+状态栏(~38px)
+```
+
+> 问题:各区全部占据固定高度,列表一旦有 3 条以上记录,输入区就会被推出屏幕,需要手动滚动才能操作。
+
+### v2(重构后)布局
+
+```
+AppBar(44px) ← 固定顶部
+[通知条 × N](每条 ~30px) ← 可选,固定
+扫码条(38px) ← 固定
+排产信息栏(~52px) ← 固定
+━━━━━━━━━━━━━━━━━━━━━━━━━
+已分配列表(弹性高度) ← 可滚动区域
+━━━━━━━━━━━━━━━━━━━━━━━━━
+输入行(~50px) ← 固定底栏
+状态栏(28px) ← 固定底栏
+```
+
+输入行与状态栏固定于底部,任何情况下都不会因列表增长而被遮挡。
+
+---
+
+## 三、各区块改动详情
+
+### 3.1 AppBar
+
+| 项目 | v1 | v2 |
+|---|---|---|
+| 高度 | ~52px | **44px** |
+| 标题 | `装箱编号`,大号字体 | `装箱编号`,15px/700 |
+| 模式标识 | 独占一行的大模式按钮区 | 右侧蓝色 Pill `⇄ 单码装箱 P2`,与标题同行 |
+| 模式颜色 | 蓝色 | **蓝色**(单码),橙色(多码),与多码对称 |
+
+Pill 点击或按 P2 物理键切换模式,行为不变。
+
+---
+
+### 3.2 通知条(Notice Banner)
+
+替代原版内嵌式 `banner` 组件,统一为横条形通知,可多条叠加显示。
+
+| 颜色 | 触发场景 |
+|---|---|
+| 🟠 橙色 | 正在同步转运数据 |
+| 🟡 琥珀色 | 箱号重复警告 / 忽略无效码 |
+| 🔵 蓝色 | 排产号切换提示 |
+| 🟢 绿色 | 全部装箱完毕提示 |
+| 🔴 红色 | 数量超限 / 提交失败 / 严重错误 |
+
+每条高度约 **30px**(含 6px 上下 padding),字号 12px,图标 + 文字,`border-bottom: 1px` 与下方区域隔开。
+
+---
+
+### 3.3 扫码条
+
+| 项目 | v1 | v2 |
+|---|---|---|
+| 高度 | ~52px 卡片 | **38px** 横条 |
+| 等待态 | 灰色圆角卡片,居中文字 | 灰底横条,📷 图标 + 文字 |
+| 已识别态 | 绿色边框卡片 + 大号总排号 | 绿底横条,✓ 绿圆 + 总排号 + `已识别` 徽章 |
+
+---
+
+### 3.4 排产信息栏(info-bar)
+
+原版将排产号/工单/件数与已有箱数分为两个分散区块,共约 80px。v2 合并为一个紧凑的 header-bar,高度约 **52px**。左侧包含三层信息,右侧固定放置醒目的详情按钮:
+
+```
+左侧第一层:[排产号] [工单号] [ERP总件数] 右侧:[📋 详情]
+左侧第二层:[进度条 ████████░░░░░░░░] ← 新增
+左侧第三层:[已有X箱 · 最大箱号Y · 已装A/B]
+```
+
+**新增:装箱进度条**
+
+- 高度 3px,不单独占行,嵌在第一层与第三层之间
+- 进度 = 已装件数 / ERP 总件数
+- 未完成时为蓝色(`#1565c0`),全部装完后变绿色(`#2e7d32`)
+
+**详情入口**
+
+- 放在排产信息栏最右侧,与三层信息垂直居中
+- 使用图标 + 文案的描边按钮样式,正常态为蓝色浅底,空状态置灰不可点击
+
+**空状态**(未扫码)时,所有字段显示为灰色占位符 `—`,详情按钮置灰不可点击。
+
+---
+
+### 3.5 已分配列表
+
+原版已分配记录直接堆叠在页面中间,无法滚动。v2 改为**弹性高度可滚动区域**,与多码凑箱的「已装入本箱」列表结构完全一致。
+
+**列表头(sticky,滚动时吸顶):**
+
+```
+已分配(此总排号) 2 条
+```
+
+**每行结构(高度 40px):**
+
+```
+[序号] [彩色竖条] [箱号 / 来源标注] [件数] [✏️] [🗑]
+```
+
+| 元素 | 说明 |
+|---|---|
+| 序号 | 10px 灰色,右对齐 |
+| 彩色竖条 | 宽 3px,高 22px;绿=正常,琥珀=编辑中,红=待删除 |
+| 箱号 | 13px/700,如「3 号箱」 |
+| 来源标注 | 10px 灰色,如「本次扫码」 |
+| 件数 | 13px/600,右对齐 |
+| 操作按钮 | ✏️ 编辑 / 🗑 删除,各 28×28px |
+
+**空状态**文案:`扫码后显示已分配箱号记录` / `本次扫码尚未分配箱号`
+
+**全部装箱完毕**时,顶部显示绿色通知 `已全部装箱完毕,无需操作`,进度条变为绿色满格,输入区禁用;已分配列表继续显示具体箱号和件数明细,避免用户只能看到完成提示却无法核对装箱结果。
+
+#### 行内编辑态
+
+点击 ✏️ 后该行变为编辑态(琥珀色背景 `#fff8e1`),件数文字变为输入框,操作按钮变为 ✓ 保存 / ✕ 取消。其他行保持正常可交互。
+
+#### 删除确认态
+
+点击 🗑 后该行背景变红(`#ffebee`),行下方展开一条 28px 确认条:
+
+```
+确认删除 X 号箱记录? [删除] [取消]
+```
+
+不弹出 Dialog,行内展开,减少视觉干扰。
+
+---
+
+### 3.6 固定底栏(输入区)
+
+原版输入区含三个独立行:箱号+数量+确认(~48px)、返回按钮(~48px)。
+
+**v2 改动:**
+
+- 箱号、数量、确认按钮**合并为单行**(高度 ~50px)
+- **移除返回按钮**
+- 正在提交时:两个输入框禁用,确认按钮替换为 loading 转圈
+
+**输入行布局:**
+
+```
+[箱号] [ 8 ] [数量] [ 50 ] [确认]
+```
+
+| 元素 | 规格 |
+|---|---|
+| 标签 | 11px/700,紧贴输入框左侧 |
+| 箱号输入 | 宽 52px,高 34px,居中,18px/800 |
+| 数量输入 | 宽 70px,高 34px,居中,16px/800 |
+| 确认按钮 | 高 34px,蓝底白字,14px/700 |
+
+**输入状态对应边框色:**
+
+| 状态 | 箱号输入框边框 | 数量输入框边框 | 确认按钮 |
+|---|---|---|---|
+| 正常可提交 | 蓝色 | 蓝色 | 可点击 |
+| 箱号重复 | **琥珀色** | 正常 | 禁用 |
+| 数量超限 | 正常 | **红色** | 禁用 |
+| 提交中 | 禁用灰 | 禁用灰 | loading 转圈 |
+| 等待扫码 | 禁用灰 | 禁用灰 | 禁用 |
+
+**边界规则:** 当提交后刚好装完(剩余数量变为 0)时,输入框中残留的上一次提交数量不应触发“数量超限”;此时按“全部装箱完毕”状态处理,确认按钮禁用。
+
+---
+
+### 3.7 状态栏
+
+| 项目 | v1 | v2 |
+|---|---|---|
+| 高度 | ~38px | **28px** |
+| 内容 | 状态圆点 + 文字 | 同,字号压缩至 11px |
+| 背景 | `#EEEEEE` | `#f5f5f5` |
+
+**圆点颜色语义(与多码统一):**
+
+| 颜色 | 状态 |
+|---|---|
+| 🔵 蓝 | 等待/空闲/数量已填入 |
+| 🟠 橙 | 提交中 / 同步中 |
+| 🟢 绿 | 操作成功 / 全部装完 |
+| 🔴 红 | 错误(无效码 / 超限 / 提交失败) |
+| 🟡 琥珀 | 警告(箱号重复 / 编辑中) |
+
+---
+
+## 四、场景状态清单
+
+| # | 场景 | 通知条 | 扫码条 | 列表 | 输入行 | 状态栏点 |
+|---|---|---|---|---|---|---|
+| 1 | 等待扫码 | 无 | 灰色等待 | 空 | 全禁用 | 🔵 |
+| 2 | 已扫码(无历史分配) | 无 | 绿色已识别 | 空 | 自动填充,可编辑 | 🔵 |
+| 3 | 已扫码 + 已有分配记录 | 无 | 绿色已识别 | 显示分配行 | 自动填充下一箱 | 🔵 |
+| 4 | 已分配行 — 编辑中 | 无 | 绿色已识别 | 目标行琥珀背景 + 输入 | 正常 | 🟡 |
+| 5 | 已分配行 — 删除确认 | 无 | 绿色已识别 | 目标行红背景 + 确认条 | 正常 | 🔴 |
+| 6 | 正在提交 | 无 | 绿色已识别 | 正常 | 全禁用 + loading | 🟠 |
+| 7 | 箱号重复 | 🟡 琥珀警告 | 绿色已识别 | 正常 | 箱号框红框,确认禁用 | 🟡 |
+| 8 | 数量超限 | 🔴 红色警告 | 绿色已识别 | 正常 | 数量框红框,确认禁用 | 🔴 |
+| 9 | 全部装箱完毕 | 🟢 绿色提示 | 绿色已识别 | 显示已分配明细 | 全禁用,进度条全绿 | 🟢 |
+| 10 | 自动同步中 | 🟠 同步 + 🟡 忽略 | 绿色已识别 | 正常,不可操作 | 全禁用 | 🟠 |
+
+---
+
+## 五、垂直空间节省汇总
+
+| 区块 | v1 高度 | v2 高度 | 节省 |
+|---|---|---|---|
+| AppBar | ~52px | 44px | **8px** |
+| 扫码区 | ~52px | 38px | **14px** |
+| 排产信息 | ~80px(两块) | ~52px(合并)| **28px** |
+| 已分配行/条 | ~52px/条 | 40px/条 | **12px/条** |
+| 通知条 | ~36px | ~30px | **6px/条** |
+| 操作行(返回) | ~48px | 0(已移除)| **48px** |
+| 状态栏 | ~38px | 28px | **10px** |
+
+> 固定区域合计节省约 **114px**,相当于屏幕高度约 1/7,可多展示约 **2~3 条**已分配记录。
+
+---
+
+## 六、与多码凑箱的设计统一点
+
+以下组件与多码凑箱在样式、尺寸、行为上完全一致,无差异:
+
+- AppBar 高度与 Pill 组件(颜色区分模式)
+- 通知条(Notice Banner)的结构与色彩语义
+- 已分配/已装入列表的行高、彩色竖条、序号、操作按钮
+- 行内编辑(输入框 + ✓/✕)与删除确认条
+- 状态栏高度、圆点颜色语义
+- 底栏的 loading 转圈形态
+
+---
+
+## 七、不在本次范围内的改动
+
+- 装箱详情页(`boxing_detail_page.dart`)布局不变
+- 状态机逻辑(`_Phase` 枚举、`_applyAutoFill`、API 调用时机)不变
+- 物理按键 P2 切换模式行为不变
+- 所有字段数据来源(`BoxInfoResult`、`saveBoxRecord` 等 API)不变